view loadtools/flashid.c @ 995:74024eb17e04

fc-loadtool help: improve language regarding 16 MiB flash chips In FC project history, 16 MiB flash originally meant Pirelli DP-L10. Then we got FCDEV3B with the same flash (our own design), but now we are discovering more Calypso devices that used such large flash, both late Calypso era (Sony Ericsson K2x0) as well as much earlier ones (FIC FLUID devices.txt file with 2004 dates, Leonardo+ rev 5). Hence we need to migrate to more generic or neutral language in associated documentation, without giving elevated status to specific examples that drove our early project history.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 03 Dec 2023 21:11:12 +0000
parents ff4ce8d5ece4
children
line wrap: on
line source

/*
 * Flash device detection code lives here
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "flash.h"

extern struct flash_device flashdev_28F160C3T;
extern struct flash_device flashdev_28F160C3B;
extern struct flash_device flashdev_28F320C3T;
extern struct flash_device flashdev_28F320C3B;
extern struct flash_device flashdev_28F640C3T;
extern struct flash_device flashdev_28F640C3B;
extern struct flash_device flashdev_28F320W30T;
extern struct flash_device flashdev_28F320W30B;
extern struct flash_device flashdev_28F640W30T;
extern struct flash_device flashdev_28F640W30B;

extern struct flash_device flashdev_Am29DL640G;
extern struct flash_device flashdev_PL032J;
extern struct flash_device flashdev_PL064J;
extern struct flash_device flashdev_PL129J;
extern struct flash_device flashdev_PL129N;
extern struct flash_device flashdev_K5A32xx_T;
extern struct flash_device flashdev_K5L33xx_A;
extern struct flash_device flashdev_K5L29xx_A;

extern int flash_global_config;
extern struct flash_bank_info flash_bank_info[2];

static
run_cfi_check(bi, table)
	struct flash_bank_info *bi;
	struct cfi_check *table;
{
	struct cfi_check *tp;
	uint16_t rdword;

	for (tp = table; tp->offset >= 0; tp++) {
		if (do_r16(bi->base_addr + (tp->offset << 1), &rdword) < 0)
			return(-1);
		if (rdword != tp->expect_val)
			return(0);
	}
	return(1);
}

static
try_device(bi, dev)
	struct flash_bank_info *bi;
	struct flash_device *dev;
{
	int rc;

	printf("Appears to be %s or compatible, checking CFI\n", dev->name);
	if (do_w16(bi->base_addr + 0xAA, 0x98)) {
		fprintf(stderr, "unexpected response to w16 - aborting\n");
		return(-1);
	}
	rc = run_cfi_check(bi, dev->cfi_table);
	if (rc < 0)
		return(rc);
	if (!rc) {
		fprintf(stderr, "Error: CFI mismatch, unsafe to continue\n");
		return(-1);
	}
	printf("Confirmed %s or compatible\n", dev->name);
	bi->device = dev;
	return(0);
}

static
try_device_amdreset(bi, dev)
	struct flash_bank_info *bi;
	struct flash_device *dev;
{
	int rc;

	printf("Appears to be %s or compatible, checking CFI\n", dev->name);
	/* need to go back to read array first, CFI cmd ignored otherwise */
	if (do_w16(bi->base_addr + 0xAAA, 0xF0)) {
bad_w16:	fprintf(stderr, "unexpected response to w16 - aborting\n");
		return(-1);
	}
	if (do_w16(bi->base_addr + 0xAA, 0x98))
		goto bad_w16;
	rc = run_cfi_check(bi, dev->cfi_table);
	if (rc < 0)
		return(rc);
	if (!rc) {
		fprintf(stderr, "Error: CFI mismatch, unsafe to continue\n");
		return(-1);
	}
	printf("Confirmed %s or compatible\n", dev->name);
	bi->device = dev;
	return(0);
}

static
spansion_pl129j_or_n(bi)
	struct flash_bank_info *bi;
{
	int rc;

	printf("Spansion PL129J or PL129N, looking at CFI\n");
	/* need to go back to read array first, CFI cmd ignored otherwise */
	if (do_w16(bi->base_addr + 0xAAA, 0xF0)) {
bad_w16:	fprintf(stderr, "unexpected response to w16 - aborting\n");
		return(-1);
	}
	if (do_w16(bi->base_addr + 0xAAA, 0x98))
		goto bad_w16;
	rc = run_cfi_check(bi, flashdev_PL129N.cfi_table);
	if (rc < 0)
		return(rc);
	if (rc) {
		printf("Found PL129N\n");
		bi->device = &flashdev_PL129N;
		return(0);
	}
	rc = run_cfi_check(bi, flashdev_PL129J.cfi_table);
	if (rc < 0)
		return(rc);
	if (rc) {
		printf("Found PL129J\n");
		bi->device = &flashdev_PL129J;
		return(0);
	}
	fprintf(stderr, "Error: no matching CFI found\n");
	return(-1);
}

static
spansion_pl064j_or_oldamd(bi)
	struct flash_bank_info *bi;
{
	int rc;

	printf("Am29DL640G or PL064J, looking at CFI\n");
	if (do_w16(bi->base_addr + 0xAA, 0x98)) {
		fprintf(stderr, "unexpected response to w16 - aborting\n");
		return(-1);
	}
	rc = run_cfi_check(bi, flashdev_PL064J.cfi_table);
	if (rc < 0)
		return(rc);
	if (rc) {
		printf("Found PL064J\n");
		bi->device = &flashdev_PL064J;
		return(0);
	}
	rc = run_cfi_check(bi, flashdev_Am29DL640G.cfi_table);
	if (rc < 0)
		return(rc);
	if (rc) {
		printf("Found Am29DL640G\n");
		bi->device = &flashdev_Am29DL640G;
		return(0);
	}
	fprintf(stderr, "Error: no matching CFI found\n");
	return(-1);
}

static
amd_extended_id(bi)
	struct flash_bank_info *bi;
{
	uint16_t ext1, ext2;

	printf("AMD-style extended ID device, reading extended ID\n");
	if (do_r16(bi->base_addr + 0x1C, &ext1) < 0)
		return(-1);
	if (do_r16(bi->base_addr + 0x1E, &ext2) < 0)
		return(-1);
	printf("Extended ID: %04X %04X\n", ext1, ext2);
	if (ext1 == 0x2221 && ext2 == 0x2200)
		return spansion_pl129j_or_n(bi);
	if (ext1 == 0x2202 && ext2 == 0x2201)
		return spansion_pl064j_or_oldamd(bi);
	if (ext1 == 0x220A && ext2 == 0x2201)
		return try_device(bi, &flashdev_PL032J);
	fprintf(stderr, "Error: unknown device ID\n");
	return(-1);
}

static
samsung_extended_id(bi)
	struct flash_bank_info *bi;
{
	uint16_t ext1, ext2;

	printf("Samsung extended ID device, reading extended ID\n");
	if (do_r16(bi->base_addr + 0x1C, &ext1) < 0)
		return(-1);
	if (do_r16(bi->base_addr + 0x1E, &ext2) < 0)
		return(-1);
	printf("Extended ID: %04X %04X\n", ext1, ext2);
	if (ext1 == 0x2503 && ext2 == 0x2501)
		return try_device(bi, &flashdev_K5L33xx_A);
	if (ext1 == 0x2508 && ext2 == 0x2501)
		return try_device_amdreset(bi, &flashdev_K5L29xx_A);
	fprintf(stderr, "Error: unknown device ID\n");
	return(-1);
}

static struct idmap {
	uint16_t	manuf_id;
	uint16_t	dev_id;
	int		(*handler)();
	void		*extra_arg;
} device_id_table[] = {
	/* AMD/Spansion devices */
	{0x0001, 0x227E, amd_extended_id, 0},
	/* 28F160C3T and 28F320C3T equivalents found in some Mot C1xx phones */
	{0x0020, 0x88BA, try_device, &flashdev_28F320C3T},
	{0x0020, 0x88CE, try_device, &flashdev_28F160C3T},
	/* Intel W30 flash family */
	{0x0089, 0x8852, try_device, &flashdev_28F320W30T},
	{0x0089, 0x8853, try_device, &flashdev_28F320W30B},
	{0x0089, 0x8854, try_device, &flashdev_28F640W30T},
	{0x0089, 0x8855, try_device, &flashdev_28F640W30B},
	/* Intel W18 flash family: same as W30, but different ID codes */
	{0x0089, 0x8862, try_device, &flashdev_28F320W30T},
	{0x0089, 0x8863, try_device, &flashdev_28F320W30B},
	{0x0089, 0x8864, try_device, &flashdev_28F640W30T},
	{0x0089, 0x8865, try_device, &flashdev_28F640W30B},
	/* Intel C3 flash family */
	{0x0089, 0x88C2, try_device, &flashdev_28F160C3T},
	{0x0089, 0x88C3, try_device, &flashdev_28F160C3B},
	{0x0089, 0x88C4, try_device, &flashdev_28F320C3T},
	{0x0089, 0x88C5, try_device, &flashdev_28F320C3B},
	{0x0089, 0x88CC, try_device, &flashdev_28F640C3T},
	{0x0089, 0x88CD, try_device, &flashdev_28F640C3B},
	/* Samsung flash */
	{0x00EC, 0x22A0, try_device, &flashdev_K5A32xx_T},
	{0x00EC, 0x257E, samsung_extended_id, 0},
	/* table search terminator */
	{0,      0,      0,          0}
};

flash_detect(bank, repeat)
{
	struct flash_bank_info *bi;
	uint16_t manuf_id, dev_id;
	struct idmap *tp;
	int rc;

	bi = flash_bank_info + bank;
	if (bi->detect_done && !repeat)
		return(0);
	printf("Autodetecting flash chip type\n");
	if (do_w16(bi->base_addr + 0xAAA, 0xAA)) {
bad_w16:	fprintf(stderr,
	"unexpected response to w16 in read ID cmd sequence - aborting\n");
		return(-1);
	}
	if (do_w16(bi->base_addr + 0x554, 0x55))
		goto bad_w16;
	if (do_w16(bi->base_addr + 0xAAA, 0x90))
		goto bad_w16;
	if (do_r16(bi->base_addr, &manuf_id) < 0)
		return(-1);
	if (do_r16(bi->base_addr + 2, &dev_id) < 0)
		return(-1);
	printf("Basic device ID: %04X %04X\n", manuf_id, dev_id);
	for (tp = device_id_table; tp->handler; tp++)
		if (tp->manuf_id == manuf_id && tp->dev_id == dev_id)
			break;
	if (!tp->handler) {
		fprintf(stderr, "Error: unknown device ID\n");
		return(-1);
	}
	rc = tp->handler(bi, tp->extra_arg);
	if (rc < 0)
		return(rc);
	/* got the device, see if it is compatible with global config */
	if (bi->device->required_global_config > flash_global_config) {
		fprintf(stderr,
"Error: detected flash device is not compatible with the configured mapping\n");
		return(-1);
	}
	/* good to go */
	if (bi->device->bank_geom[1] && bank) {
		bi->geom = bi->device->bank_geom[1];
		bi->amd_lock = bi->device->lock_info[1];
	} else {
		bi->geom = bi->device->bank_geom[0];
		bi->amd_lock = bi->device->lock_info[0];
	}
	bi->ops = bi->device->cmdset;
	bi->detect_done = 1;
	/* return device to read array mode */
	return bi->ops->reset_cmd(bi);
}