diff loadtools/flashid.c @ 506:0dd2c87c1b63

fc-loadtool flash support overhaul
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 28 May 2019 05:12:47 +0000
parents
children c942be3c7997
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loadtools/flashid.c	Tue May 28 05:12:47 2019 +0000
@@ -0,0 +1,188 @@
+/*
+ * 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_28F320C3T;
+extern struct flash_device flashdev_28F640C3T;
+extern struct flash_device flashdev_28F640C3B;
+extern struct flash_device flashdev_28F640W30T;
+extern struct flash_device flashdev_28F640W30B;
+extern struct flash_device flashdev_PL129J;
+extern struct flash_device flashdev_PL129N;
+extern struct flash_device flashdev_K5A32xx_T;
+
+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
+spansion_pl129j_or_n(bi)
+	struct flash_bank_info *bi;
+{
+	int rc;
+
+	printf("Spansion PL129J or PL129N, 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_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
+amd_extended_id(bi)
+	struct flash_bank_info *bi;
+{
+	uint16_t ext1, ext2;
+
+	printf("AMD-style extended ID device, reading\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);
+	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 equivalent found in a C11x phone in the wild */
+	{0x0020, 0x88CE, try_device, &flashdev_28F160C3T},
+	/* Intel flash chips */
+	{0x0089, 0x8854, try_device, &flashdev_28F640W30T},
+	{0x0089, 0x8855, try_device, &flashdev_28F640W30B},
+	{0x0089, 0x8864, try_device, &flashdev_28F640W30T},
+	{0x0089, 0x88C2, try_device, &flashdev_28F160C3T},
+	{0x0089, 0x88C4, try_device, &flashdev_28F320C3T},
+	{0x0089, 0x88CC, try_device, &flashdev_28F640C3T},
+	{0x0089, 0x88CD, try_device, &flashdev_28F640C3B},
+	/* Samsung flash */
+	{0x00EC, 0x22A0, try_device, &flashdev_K5A32xx_T},
+	/* 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];
+	else
+		bi->geom = bi->device->bank_geom[0];
+	bi->ops = bi->device->cmdset;
+	bi->detect_done = 1;
+	/* return device to read array mode */
+	return bi->ops->reset_cmd(bi);
+}