changeset 506:0dd2c87c1b63

fc-loadtool flash support overhaul
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 28 May 2019 05:12:47 +0000
parents 7bf0d909c87e
children c942be3c7997
files loadtools/Makefile loadtools/flash.h loadtools/flashid.c loadtools/flashops.c loadtools/flashstubs.c loadtools/flcmplboot.c loadtools/flconf.c loadtools/fldevs.c loadtools/flmain.c loadtools/flmisc.c loadtools/flprogbin.c loadtools/flprogsrec.c loadtools/flutil.c loadtools/hwparam.c
diffstat 14 files changed, 721 insertions(+), 455 deletions(-) [+]
line wrap: on
line diff
--- a/loadtools/Makefile	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/Makefile	Tue May 28 05:12:47 2019 +0000
@@ -16,11 +16,11 @@
 		romload.o secondprog.o sertool.o srecreader.o ttypassthru.o \
 		${EXTRA_OBJ}
 
-LOADTOOL_OBJS=	crc32tab.o defpath.o flashops.o flcmplboot.o flmain.o flmisc.o \
-		flprogbin.o flprogsrec.o flutil.o hexdecode.o hwparam.o \
-		labaud.o ltdispatch.o ltdump.o ltexit.o lthelp.o ltmain.o \
-		ltmisc.o ltpassthru.o ltscript.o romload.o srecreader.o \
-		tpinterf.o tpinterf2.o tpinterf3.o ${EXTRA_OBJ}
+LOADTOOL_OBJS=	crc32tab.o defpath.o flashid.o flashops.o flcmplboot.o flconf.o\
+		fldevs.o flmain.o flmisc.o flprogbin.o flprogsrec.o flutil.o \
+		hexdecode.o hwparam.o labaud.o ltdispatch.o ltdump.o ltexit.o \
+		lthelp.o ltmain.o ltmisc.o ltpassthru.o ltscript.o romload.o \
+		srecreader.o tpinterf.o tpinterf2.o tpinterf3.o ${EXTRA_OBJ}
 
 XRAM_OBJS=	chainload.o clmain.o defexitstub.o defpath.o flashstubs.o \
 		hexdecode.o hwparam.o initscript.o labaud.o romload.o \
--- a/loadtools/flash.h	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/flash.h	Tue May 28 05:12:47 2019 +0000
@@ -1,5 +1,11 @@
 /* this header file contains definitions for fc-loadtool flash support */
 
+/* global configuration */
+#define	FLASH_GLOBAL_CFG_NONE		0
+#define	FLASH_GLOBAL_CFG_SINGLE_4M	1
+#define	FLASH_GLOBAL_CFG_SINGLE_8M	2
+#define	FLASH_GLOBAL_CFG_DUAL_8M	3
+
 /*
  * The following structures represent an "abstract"
  * description of flash devices.
@@ -25,22 +31,16 @@
 	unsigned			total_sectors;
 };
 
-struct flash_idcheck {
-	uint16_t	offset;
-	uint16_t	expect_val;
+struct cfi_check {
+	int	offset;
+	uint8_t	expect_val;
 };
 
-struct flash_bank_desc {
-	uint32_t		align_size;
-	struct flash_geom	*geom;
-	struct flash_idcheck	*idcheck_table;
-	unsigned		idcheck_num;
-};
-
-struct flash_device_desc {
+struct flash_device {
 	char			*name;
-	struct flash_bank_desc	*bank_desc;
-	unsigned		nbanks;
+	struct cfi_check	*cfi_table;
+	int			required_global_config;
+	struct flash_geom	*bank_geom[2];
 	struct flash_cmdset	*cmdset;
 };
 
@@ -65,9 +65,9 @@
 
 struct flash_bank_info {
 	uint32_t		base_addr;
-	struct flash_bank_desc	*bank_desc;
+	struct flash_device	*device;
 	struct flash_geom	*geom;
 	struct flash_cmdset	*ops;
 	struct sector_info	*sectors;
-	int			idcheck_done;
+	int			detect_done;
 };
--- /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);
+}
--- a/loadtools/flashops.c	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/flashops.c	Tue May 28 05:12:47 2019 +0000
@@ -19,10 +19,10 @@
 }
 
 static
-invalid()
+amd_invalid()
 {
 	fprintf(stderr,
-	      "This operation is not applicable to the selected flash type\n");
+		"This operation is not applicable to AMD-style flash\n");
 	return(-1);
 }
 
@@ -86,8 +86,8 @@
 struct flash_cmdset flash_cmdset_amd = {
 	.cmdset_name		= "AMD",
 	.reset_cmd		= amd_reset_cmd,
-	.status_cmd		= invalid,
-	.unlock_sector		= invalid,
+	.status_cmd		= amd_invalid,
+	.unlock_sector		= amd_invalid,
 	.erase_sector		= amd_sector_erase,
 	.prep_for_program	= noop,
 	.loadagent_setbase_cmd	= "AMFB",
--- a/loadtools/flashstubs.c	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/flashstubs.c	Tue May 28 05:12:47 2019 +0000
@@ -6,7 +6,7 @@
  */
 
 void
-set_flash_device()
+set_flash_config()
 {
 }
 
--- a/loadtools/flcmplboot.c	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/flcmplboot.c	Tue May 28 05:12:47 2019 +0000
@@ -140,7 +140,7 @@
 			argv[0], argv[1]);
 		return(-1);
 	}
-	if (flash_get_cfi(0) < 0)
+	if (flash_detect(0, 0) < 0)
 		return(-1);
 	if (flash_bank_info[0].geom->regions[0].sector_size
 			!= boot_sector_size) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loadtools/flconf.c	Tue May 28 05:12:47 2019 +0000
@@ -0,0 +1,131 @@
+/*
+ * This module handles flash configuration for fc-loadtool
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include "flash.h"
+
+/* the following variables describe our selected flash config */
+
+int flash_global_config;
+struct flash_bank_info flash_bank_info[2];
+
+/* global configurations selected via hw parameter files */
+
+static struct global_cfg_kw {
+	char *kw;
+	int code;
+} global_cfg_keywords[] = {
+	{"single-4M", FLASH_GLOBAL_CFG_SINGLE_4M},
+	{"single-8M", FLASH_GLOBAL_CFG_SINGLE_8M},
+	{"dual-8M", FLASH_GLOBAL_CFG_DUAL_8M},
+	/* backward compatibility with old hw param files */
+	{"cfi-4M", FLASH_GLOBAL_CFG_SINGLE_4M},
+	{"cfi-8M", FLASH_GLOBAL_CFG_SINGLE_8M},
+	{"k5a32xx_t", FLASH_GLOBAL_CFG_SINGLE_4M},
+	{"pl129n", FLASH_GLOBAL_CFG_DUAL_8M},
+	{"28f640w30b", FLASH_GLOBAL_CFG_SINGLE_8M},
+	{0, 0}		/* array terminator */
+};
+
+/* called from hwparam.c config file parser */
+void
+set_flash_config(arg, filename_for_errs, lineno_for_errs)
+	char *arg;
+	char *filename_for_errs;
+	int lineno_for_errs;
+{
+	char *cp, *np, *ep;
+	struct global_cfg_kw *tp;
+	int bank, nbanks;
+	struct flash_bank_info *bi;
+	uint32_t align_size;
+
+	if (flash_global_config) {
+		fprintf(stderr, "%s line %d: duplicate flash setting\n",
+			filename_for_errs, lineno_for_errs);
+		exit(1);
+	}
+	for (cp = arg; isspace(*cp); cp++)
+		;
+	if (!*cp || *cp == '#') {
+too_few_arg:	fprintf(stderr,
+			"%s line %d: flash setting: too few arguments\n",
+			filename_for_errs, lineno_for_errs);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	for (tp = global_cfg_keywords; tp->kw; tp++)
+		if (!strcmp(tp->kw, np))
+			break;
+	if (!tp->kw) {
+		fprintf(stderr,
+			"%s line %d: unknown flash config \"%s\"\n",
+			filename_for_errs, lineno_for_errs, np);
+		exit(1);
+	}
+	flash_global_config = tp->code;
+
+	/* now initialize flash_bank_info (base addresses) */
+	switch (flash_global_config) {
+	case FLASH_GLOBAL_CFG_SINGLE_4M:
+		nbanks = 1;
+		align_size = 0x400000;
+		break;
+	case FLASH_GLOBAL_CFG_SINGLE_8M:
+		nbanks = 1;
+		align_size = 0x800000;
+		break;
+	case FLASH_GLOBAL_CFG_DUAL_8M:
+		nbanks = 2;
+		align_size = 0x800000;
+		break;
+	default:
+		fprintf(stderr,
+			"BUG in set_flash_config(): invalid global config\n");
+		abort();
+	}
+	for (bank = 0; bank < nbanks; bank++) {
+		while (isspace(*cp))
+			cp++;
+		if (!*cp || *cp == '#')
+			goto too_few_arg;
+		for (np = cp; *cp && !isspace(*cp); cp++)
+			;
+		if (*cp)
+			*cp++ = '\0';
+		bi = flash_bank_info + bank;
+		bi->base_addr = strtoul(np, &ep, 16);
+		if (*ep) {
+			fprintf(stderr,
+"%s line %d: syntax error (base addr expected after flash config name)\n",
+				filename_for_errs, lineno_for_errs);
+			exit(1);
+		}
+		/* check alignment */
+		if (bi->base_addr & (align_size - 1)) {
+			fprintf(stderr,
+"%s line %d: flash bank %d base addr is not aligned to the bank size (0x%lx)\n",
+				filename_for_errs, lineno_for_errs, bank,
+				(u_long) align_size);
+			exit(1);
+		}
+	}
+	while (isspace(*cp))
+		cp++;
+	if (*cp && *cp != '#') {
+		fprintf(stderr,
+			"%s line %d: flash setting: too many arguments\n",
+			filename_for_errs, lineno_for_errs);
+		exit(1);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loadtools/fldevs.c	Tue May 28 05:12:47 2019 +0000
@@ -0,0 +1,302 @@
+/*
+ * This module holds the tables of supported flash devices
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include "flash.h"
+
+extern struct flash_cmdset flash_cmdset_amd;
+extern struct flash_cmdset flash_cmdset_intel;
+extern struct flash_cmdset flash_cmdset_intel_w30;
+
+/* flash bank geometries */
+
+static struct flash_geom geom_2M_topboot = {
+	.total_size	= 0x200000,
+	.nregions	= 2,
+	.regions	= {0x10000, 31, 0x2000, 8},
+	.total_sectors	= 39,
+};
+
+static struct flash_geom geom_4M_topboot = {
+	.total_size	= 0x400000,
+	.nregions	= 2,
+	.regions	= {0x10000, 63, 0x2000, 8},
+	.total_sectors	= 71,
+};
+
+static struct flash_geom geom_8M_topboot = {
+	.total_size	= 0x800000,
+	.nregions	= 2,
+	.regions	= {0x10000, 127, 0x2000, 8},
+	.total_sectors	= 135,
+};
+
+static struct flash_geom geom_8M_bottomboot = {
+	.total_size	= 0x800000,
+	.nregions	= 2,
+	.regions	= {0x2000, 8, 0x10000, 127},
+	.total_sectors	= 135,
+};
+
+static struct flash_geom geom_8M_topboot_big = {
+	.total_size	= 0x800000,
+	.nregions	= 2,
+	.regions	= {0x40000, 31, 0x10000, 4},
+	.total_sectors	= 35,
+};
+
+static struct flash_geom geom_8M_bottomboot_big = {
+	.total_size	= 0x800000,
+	.nregions	= 2,
+	.regions	= {0x10000, 4, 0x40000, 31},
+	.total_sectors	= 35,
+};
+
+/* Intel and compatible flash chips */
+
+static struct cfi_check intel_2M_topboot_cfi[] = {
+	{0x10, 'Q'},
+	{0x11, 'R'},
+	{0x12, 'Y'},
+	{0x13, 0x03},
+	{0x14, 0x00},
+	{0x27, 0x15},
+	{0x2C, 0x02},
+	{0x2D, 0x1E},
+	{0x2E, 0x00},
+	{0x2F, 0x00},
+	{0x30, 0x01},
+	{0x31, 0x07},
+	{0x32, 0x00},
+	{0x33, 0x20},
+	{0x34, 0x00},
+	{-1,   0}
+};
+
+static struct cfi_check intel_4M_topboot_cfi[] = {
+	{0x10, 'Q'},
+	{0x11, 'R'},
+	{0x12, 'Y'},
+	{0x13, 0x03},
+	{0x14, 0x00},
+	{0x27, 0x16},
+	{0x2C, 0x02},
+	{0x2D, 0x3E},
+	{0x2E, 0x00},
+	{0x2F, 0x00},
+	{0x30, 0x01},
+	{0x31, 0x07},
+	{0x32, 0x00},
+	{0x33, 0x20},
+	{0x34, 0x00},
+	{-1,   0}
+};
+
+static struct cfi_check intel_8M_topboot_cfi[] = {
+	{0x10, 'Q'},
+	{0x11, 'R'},
+	{0x12, 'Y'},
+	{0x13, 0x03},
+	{0x14, 0x00},
+	{0x27, 0x17},
+	{0x2C, 0x02},
+	{0x2D, 0x7E},
+	{0x2E, 0x00},
+	{0x2F, 0x00},
+	{0x30, 0x01},
+	{0x31, 0x07},
+	{0x32, 0x00},
+	{0x33, 0x20},
+	{0x34, 0x00},
+	{-1,   0}
+};
+
+static struct cfi_check intel_8M_bottomboot_cfi[] = {
+	{0x10, 'Q'},
+	{0x11, 'R'},
+	{0x12, 'Y'},
+	{0x13, 0x03},
+	{0x14, 0x00},
+	{0x27, 0x17},
+	{0x2C, 0x02},
+	{0x2D, 0x07},
+	{0x2E, 0x00},
+	{0x2F, 0x20},
+	{0x30, 0x00},
+	{0x31, 0x7E},
+	{0x32, 0x00},
+	{0x33, 0x00},
+	{0x34, 0x01},
+	{-1,   0}
+};
+
+struct flash_device flashdev_28F160C3T = {
+	.name			= "Intel 28F160C3T",
+	.cfi_table		= intel_2M_topboot_cfi,
+	.required_global_config	= FLASH_GLOBAL_CFG_SINGLE_4M,
+	.bank_geom		= {&geom_2M_topboot, 0},
+	.cmdset			= &flash_cmdset_intel,
+};
+
+struct flash_device flashdev_28F320C3T = {
+	.name			= "Intel 28F320C3T",
+	.cfi_table		= intel_4M_topboot_cfi,
+	.required_global_config	= FLASH_GLOBAL_CFG_SINGLE_4M,
+	.bank_geom		= {&geom_4M_topboot, 0},
+	.cmdset			= &flash_cmdset_intel,
+};
+
+struct flash_device flashdev_28F640C3T = {
+	.name			= "Intel 28F640C3T",
+	.cfi_table		= intel_8M_topboot_cfi,
+	.required_global_config	= FLASH_GLOBAL_CFG_SINGLE_8M,
+	.bank_geom		= {&geom_8M_topboot, 0},
+	.cmdset			= &flash_cmdset_intel,
+};
+
+struct flash_device flashdev_28F640C3B = {
+	.name			= "Intel 28F640C3B",
+	.cfi_table		= intel_8M_bottomboot_cfi,
+	.required_global_config	= FLASH_GLOBAL_CFG_SINGLE_8M,
+	.bank_geom		= {&geom_8M_bottomboot, 0},
+	.cmdset			= &flash_cmdset_intel,
+};
+
+struct flash_device flashdev_28F640W30T = {
+	.name			= "Intel 28F640W30T",
+	.cfi_table		= intel_8M_topboot_cfi,
+	.required_global_config	= FLASH_GLOBAL_CFG_SINGLE_8M,
+	.bank_geom		= {&geom_8M_topboot, 0},
+	.cmdset			= &flash_cmdset_intel_w30,
+};
+
+struct flash_device flashdev_28F640W30B = {
+	.name			= "Intel 28F640W30B",
+	.cfi_table		= intel_8M_bottomboot_cfi,
+	.required_global_config	= FLASH_GLOBAL_CFG_SINGLE_8M,
+	.bank_geom		= {&geom_8M_bottomboot, 0},
+	.cmdset			= &flash_cmdset_intel_w30,
+};
+
+/* Spansion S71PL-J and S71PL-N flash */
+
+static struct cfi_check spansion_PL129J_cfi[] = {
+	{0x10, 'Q'},
+	{0x11, 'R'},
+	{0x12, 'Y'},
+	{0x13, 0x02},
+	{0x14, 0x00},
+	{0x15, 0x40},
+	{0x16, 0x00},
+	{0x27, 0x18},
+	{0x2C, 0x03},
+	{0x2D, 0x07},
+	{0x2E, 0x00},
+	{0x2F, 0x20},
+	{0x30, 0x00},
+	{0x31, 0xFD},
+	{0x32, 0x00},
+	{0x33, 0x00},
+	{0x34, 0x01},
+	{0x35, 0x07},
+	{0x36, 0x00},
+	{0x37, 0x20},
+	{0x38, 0x00},
+	{0x40, 'P'},
+	{0x41, 'R'},
+	{0x42, 'I'},
+	{0x43, '1'},
+	{0x44, '3'},
+	{-1,   0}
+};
+
+struct flash_device flashdev_PL129J = {
+	.name			= "Spansion S29PL129J",
+	.cfi_table		= spansion_PL129J_cfi,
+	.required_global_config	= FLASH_GLOBAL_CFG_DUAL_8M,
+	.bank_geom		= {&geom_8M_bottomboot, &geom_8M_topboot},
+	.cmdset			= &flash_cmdset_amd,
+};
+
+static struct cfi_check spansion_PL129N_cfi[] = {
+	{0x10, 'Q'},
+	{0x11, 'R'},
+	{0x12, 'Y'},
+	{0x13, 0x02},
+	{0x14, 0x00},
+	{0x15, 0x40},
+	{0x16, 0x00},
+	{0x27, 0x18},
+	{0x2C, 0x03},
+	{0x2D, 0x03},
+	{0x2E, 0x00},
+	{0x2F, 0x00},
+	{0x30, 0x01},
+	{0x31, 0x3D},
+	{0x32, 0x00},
+	{0x33, 0x00},
+	{0x34, 0x04},
+	{0x35, 0x03},
+	{0x36, 0x00},
+	{0x37, 0x00},
+	{0x38, 0x01},
+	{0x40, 'P'},
+	{0x41, 'R'},
+	{0x42, 'I'},
+	{0x43, '1'},
+	{0x44, '4'},
+	{-1,   0}
+};
+
+struct flash_device flashdev_PL129N = {
+	.name			= "Spansion S29PL129N",
+	.cfi_table		= spansion_PL129N_cfi,
+	.required_global_config	= FLASH_GLOBAL_CFG_DUAL_8M,
+	.bank_geom		= {&geom_8M_bottomboot_big,
+				   &geom_8M_topboot_big},
+	.cmdset			= &flash_cmdset_amd,
+};
+
+/* Samsung K5A32xxCTM introduced onto the scene by Openmoko */
+
+static struct cfi_check samsung_4M_topboot_cfi[] = {
+	{0x10, 'Q'},
+	{0x11, 'R'},
+	{0x12, 'Y'},
+	{0x13, 0x02},
+	{0x14, 0x00},
+	{0x15, 0x40},
+	{0x16, 0x00},
+	{0x27, 0x16},
+	{0x2C, 0x02},
+	{0x2D, 0x07},
+	{0x2E, 0x00},
+	{0x2F, 0x20},
+	{0x30, 0x00},
+	{0x31, 0x3E},
+	{0x32, 0x00},
+	{0x33, 0x00},
+	{0x34, 0x01},
+	{0x40, 'P'},
+	{0x41, 'R'},
+	{0x42, 'I'},
+	{0x43, '3'},
+	{0x44, '3'},
+	{0x4F, 0x03},
+	{-1,   0}
+};
+
+struct flash_device flashdev_K5A32xx_T = {
+	.name			= "Samsung K5A32xx_T",
+	.cfi_table		= samsung_4M_topboot_cfi,
+	.required_global_config	= FLASH_GLOBAL_CFG_SINGLE_4M,
+	.bank_geom		= {&geom_4M_topboot, 0},
+	.cmdset			= &flash_cmdset_amd,
+};
--- a/loadtools/flmain.c	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/flmain.c	Tue May 28 05:12:47 2019 +0000
@@ -11,185 +11,10 @@
 #include <stdlib.h>
 #include "flash.h"
 
-/* K5A32xx device description */
-
-static struct flash_geom k5a32xx_topboot_geom = {
-	.total_size	= 0x400000,
-	.nregions	= 2,
-	.regions	= {0x10000, 63, 0x2000, 8},
-	.total_sectors	= 71,
-};
-
-static struct flash_idcheck k5a32xx_topboot_idcheck[2] = {
-	{0x00, 0x00EC},
-	{0x02, 0x22A0}
-};
-
-static struct flash_bank_desc k5a32xx_topboot_bankdesc = {
-	0x400000, &k5a32xx_topboot_geom, k5a32xx_topboot_idcheck, 2
-};
-
-/* S{29,71}PL129N device description */
-
-static struct flash_geom pl129n_ce1_geom = {
-	.total_size	= 0x800000,
-	.nregions	= 2,
-	.regions	= {0x10000, 4, 0x40000, 31},
-	.total_sectors	= 35,
-};
-
-static struct flash_geom pl129n_ce2_geom = {
-	.total_size	= 0x800000,
-	.nregions	= 2,
-	.regions	= {0x40000, 31, 0x10000, 4},
-	.total_sectors	= 35,
-};
-
-static struct flash_idcheck pl129n_idcheck[4] = {
-	{0x00, 0x0001},
-	{0x02, 0x227E},
-	{0x1C, 0x2221},
-	{0x1E, 0x2200}
-};
-
-static struct flash_bank_desc pl129n_banks[2] = {
-	{0x800000, &pl129n_ce1_geom, pl129n_idcheck, 4},
-	{0x800000, &pl129n_ce2_geom, pl129n_idcheck, 4}
-};
-
-/* 28F640W30B device description */
-
-static struct flash_geom f640w30b_geom = {
-	.total_size	= 0x800000,
-	.nregions	= 2,
-	.regions	= {0x2000, 8, 0x10000, 127},
-	.total_sectors	= 135,
-};
-
-static struct flash_idcheck f640w30b_idcheck[2] = {
-	{0x00, 0x0089},
-	{0x02, 0x8855}
-};
-
-static struct flash_bank_desc f640w30b_bankdesc = {
-	0x800000, &f640w30b_geom, f640w30b_idcheck, 2
-};
-
-/* bank configurations for CFI */
-
-static struct flash_bank_desc cfi_4M_bankdesc = {
-	0x400000, 0, 0, 0
-};
-
-static struct flash_bank_desc cfi_8M_bankdesc = {
-	0x800000, 0, 0, 0
-};
-
-/* list of supported flash devices */
-
-extern struct flash_cmdset flash_cmdset_amd;
-extern struct flash_cmdset flash_cmdset_intel_w30;
-
-struct flash_device_desc flash_device_list[] = {
-	{"cfi-4M", &cfi_4M_bankdesc, 1, 0},
-	{"cfi-8M", &cfi_8M_bankdesc, 1, 0},
-	{"k5a32xx_t", &k5a32xx_topboot_bankdesc, 1, &flash_cmdset_amd},
-	{"pl129n", pl129n_banks, 2, &flash_cmdset_amd},
-	{"28f640w30b", &f640w30b_bankdesc, 1, &flash_cmdset_intel_w30},
-	{0, 0, 0, 0}	/* array terminator */
-};
-
-/* the following variables describe our selected flash device */
+extern int flash_global_config;
+extern struct flash_bank_info flash_bank_info[2];
 
-struct flash_device_desc *selected_flash_device;
-struct flash_bank_info flash_bank_info[2];
-
-/* called from hwparam.c config file parser */
-void
-set_flash_device(arg, filename_for_errs, lineno_for_errs)
-	char *arg;
-	char *filename_for_errs;
-	int lineno_for_errs;
-{
-	char *cp, *np, *ep;
-	struct flash_device_desc *tp;
-	int bank;
-	struct flash_bank_info *bi;
-
-	if (selected_flash_device) {
-		fprintf(stderr, "%s line %d: duplicate flash setting\n",
-			filename_for_errs, lineno_for_errs);
-		exit(1);
-	}
-	for (cp = arg; isspace(*cp); cp++)
-		;
-	if (!*cp || *cp == '#') {
-too_few_arg:	fprintf(stderr,
-			"%s line %d: flash setting: too few arguments\n",
-			filename_for_errs, lineno_for_errs);
-		exit(1);
-	}
-	for (np = cp; *cp && !isspace(*cp); cp++)
-		;
-	if (*cp)
-		*cp++ = '\0';
-	for (tp = flash_device_list; tp->name; tp++)
-		if (!strcmp(tp->name, np))
-			break;
-	if (!tp->name) {
-		fprintf(stderr,
-			"%s line %d: unknown flash device \"%s\"\n",
-			filename_for_errs, lineno_for_errs, np);
-		exit(1);
-	}
-	selected_flash_device = tp;
-
-	/* now initialize flash_bank_info */
-	for (bank = 0; bank < selected_flash_device->nbanks; bank++) {
-		while (isspace(*cp))
-			cp++;
-		if (!*cp || *cp == '#')
-			goto too_few_arg;
-		for (np = cp; *cp && !isspace(*cp); cp++)
-			;
-		if (*cp)
-			*cp++ = '\0';
-		bi = flash_bank_info + bank;
-		bi->base_addr = strtoul(np, &ep, 16);
-		if (*ep) {
-			fprintf(stderr,
-"%s line %d: syntax error (base addr expected after flash device type)\n",
-				filename_for_errs, lineno_for_errs);
-			exit(1);
-		}
-		/* the rest comes from the flash device type */
-		bi->bank_desc = selected_flash_device->bank_desc + bank;
-		if (bi->base_addr & (bi->bank_desc->align_size - 1)) {
-			fprintf(stderr,
-"%s line %d: flash bank %d base addr is not aligned to the bank size (0x%lx)\n",
-				filename_for_errs, lineno_for_errs, bank,
-				(u_long) bi->bank_desc->align_size);
-			exit(1);
-		}
-		bi->geom = bi->bank_desc->geom;
-		bi->ops = selected_flash_device->cmdset;
-	}
-	while (isspace(*cp))
-		cp++;
-	if (*cp && *cp != '#') {
-		fprintf(stderr,
-			"%s line %d: flash setting: too many arguments\n",
-			filename_for_errs, lineno_for_errs);
-		exit(1);
-	}
-}
-
-flashcmd_help()
-{
-	return loadtool_help("flash");
-}
-
-flashcmd_info(argc, argv, bank)
+flashcmd_geom(argc, argv, bank)
 	char **argv;
 {
 	struct flash_bank_info *bi;
@@ -198,19 +23,65 @@
 		fprintf(stderr, "error: too many arguments\n");
 		return(-1);
 	}
+	if (flash_detect(bank, 0) < 0)
+		return(-1);
 	bi = flash_bank_info + bank;
-	printf("Flash device type: %s\n", selected_flash_device->name);
-	printf("Bank %d base address: %08lX\n", bank, (u_long) bi->base_addr);
-	if (flash_get_cfi(bank) < 0)
-		return(-1);
+	if (bi->device->bank_geom[1])
+		printf("Device has two banks, looking at bank %d\n", bank);
+	else
+		printf("Single-bank flash device\n");
 	printf("Bank %d total size: %lx\n", bank,
 		(u_long) bi->geom->total_size);
 	printf("Sectors in bank %d: %u (%u regions)\n", bank,
 		bi->geom->total_sectors, bi->geom->nregions);
 	printf("Command set style: %s\n", bi->ops->cmdset_name);
-	flash_id_check(bank, 1);
-	if (selected_flash_device->nbanks == 2 && !bank)
-	    printf("\nFlash device has 2 banks; flash2 command available\n");
+	return(0);
+}
+
+flashcmd_help()
+{
+	return loadtool_help("flash");
+}
+
+flashcmd_id(argc, argv, bank)
+	char **argv;
+{
+	if (argc > 2) {
+		fprintf(stderr, "error: too many arguments\n");
+		return(-1);
+	}
+	return flash_detect(bank, 1);
+}
+
+flashcmd_info(argc, argv)
+	char **argv;
+{
+	int bank, nbanks;
+
+	if (argc > 2) {
+		fprintf(stderr, "error: too many arguments\n");
+		return(-1);
+	}
+	switch (flash_global_config) {
+	case FLASH_GLOBAL_CFG_SINGLE_4M:
+		printf("Configured for a single flash bank of up to 4 MiB\n");
+		nbanks = 1;
+		break;
+	case FLASH_GLOBAL_CFG_SINGLE_8M:
+		printf("Configured for a single flash bank of up to 8 MiB\n");
+		nbanks = 1;
+		break;
+	case FLASH_GLOBAL_CFG_DUAL_8M:
+		printf("Configured for two flash banks of up to 8 MiB each\n");
+		nbanks = 2;
+		break;
+	default:
+		fprintf(stderr, "error: invalid global config\n");
+		return(-1);
+	}
+	for (bank = 0; bank < nbanks; bank++)
+		printf("Bank %d base address: %08lX\n", bank,
+			(u_long) flash_bank_info[bank].base_addr);
 	return(0);
 }
 
@@ -236,7 +107,9 @@
 	{"dump2srec", flashcmd_dump2file},
 	{"erase", flashcmd_erase},
 	{"erase-program-boot", flashcmd_erase_program_boot},
+	{"geom", flashcmd_geom},
 	{"help", flashcmd_help},
+	{"id", flashcmd_id},
 	{"info", flashcmd_info},
 	{"program-bin", flashcmd_progbin},
 	{"program-m0", flashcmd_program_m0},
@@ -255,14 +128,13 @@
 	int bank;
 	struct cmdtab *tp;
 
-	if (!selected_flash_device) {
+	if (!flash_global_config) {
 		fprintf(stderr, "No flash configuration defined\n");
 		return(-1);
 	}
 	if (argv[0][5] == '2') {
-		if (selected_flash_device->nbanks < 2) {
-			fprintf(stderr, "Flash device %s has only one bank\n",
-				selected_flash_device->name);
+		if (flash_global_config != FLASH_GLOBAL_CFG_DUAL_8M) {
+			fprintf(stderr, "No second flash bank configured\n");
 			return(-1);
 		}
 		bank = 1;
--- a/loadtools/flmisc.c	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/flmisc.c	Tue May 28 05:12:47 2019 +0000
@@ -28,7 +28,7 @@
 	offset = strtoul(argv[2], &strtoul_endp, 16);
 	if (*strtoul_endp)
 		goto inv;
-	if (flash_get_cfi(bank) < 0)
+	if (flash_detect(bank, 0) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
 	if (offset >= bi->geom->total_size) {
@@ -74,7 +74,7 @@
 			argv[0], argv[1]);
 		return(-1);
 	}
-	if (flash_get_cfi(bank) < 0)
+	if (flash_detect(bank, 0) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
 	if (argc >= 4) {
@@ -138,7 +138,7 @@
 	offset = strtoul(argv[2], &strtoul_endp, 16);
 	if (*strtoul_endp)
 		goto inv;
-	if (flash_get_cfi(bank) < 0)
+	if (flash_detect(bank, 0) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
 	if (offset >= bi->geom->total_size) {
@@ -165,9 +165,6 @@
 		return(-1);
 	if (get_flash_sector_range(bi, offset, len, &startsec, &endsec) < 0)
 		return(-1);
-	stat = flash_id_check(bank, 0);
-	if (stat)
-		return(stat);
 	printf("Erasing %d sector(s)\n", endsec - startsec);
 	for (sp = startsec; sp < endsec; sp++) {
 		stat = bi->ops->erase_sector(bi, sp);
@@ -192,7 +189,7 @@
 			argv[0], argv[1]);
 		return(-1);
 	}
-	if (flash_get_cfi(bank) < 0)
+	if (flash_detect(bank, 0) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
 	sprintf(targ_base, "%lx", (u_long) bi->base_addr);
@@ -228,7 +225,7 @@
 		fprintf(stderr, "error: too many arguments\n");
 		return(-1);
 	}
-	if (flash_get_cfi(bank) < 0)
+	if (flash_detect(bank, 0) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
 	return bi->ops->reset_cmd(bi);
@@ -243,7 +240,7 @@
 		fprintf(stderr, "error: too many arguments\n");
 		return(-1);
 	}
-	if (flash_get_cfi(bank) < 0)
+	if (flash_detect(bank, 0) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
 	return bi->ops->status_cmd(bi);
@@ -258,12 +255,12 @@
 	struct sector_info *startsec, *endsec, *sp;
 	int stat;
 
-	if (flash_get_cfi(bank) < 0)
+	if (flash_detect(bank, 0) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
 	if (!bi->ops->needs_unlock) {
 		fprintf(stderr,
-	    "This operation is not applicable to the selected flash type\n");
+		      "This operation is not applicable to AMD-style flash\n");
 		return(-1);
 	}
 	if (argc != 4) {
--- a/loadtools/flprogbin.c	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/flprogbin.c	Tue May 28 05:12:47 2019 +0000
@@ -38,7 +38,7 @@
 	flashoff = strtoul(argv[2], &strtoul_endp, 16);
 	if (*strtoul_endp)
 		goto inv;
-	if (flash_get_cfi(bank) < 0)
+	if (flash_detect(bank, 0) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
 	if (flashoff >= bi->geom->total_size) {
@@ -109,10 +109,6 @@
 	}
 
 	/* finally done with the arg parsing etc, can get to work now */
-	if (flash_id_check(bank, 0) < 0) {
-		fclose(binf);
-		return(-1);
-	}
 	crc_base_addr = bi->base_addr + flashoff;
 	sprintf(shortarg, "%lx", (u_long) bi->base_addr);
 	targv[0] = bi->ops->loadagent_setbase_cmd;
--- a/loadtools/flprogsrec.c	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/flprogsrec.c	Tue May 28 05:12:47 2019 +0000
@@ -21,18 +21,13 @@
 	int resp;
 	unsigned long rec_count;
 
-	if (flash_get_cfi(bank) < 0)
+	if (flash_detect(bank, 0) < 0)
 		return(-1);
 	bi = flash_bank_info + bank;
 	srr.filename = imgfile;
 	resp = open_srec_file(&srr);
 	if (resp < 0)
 		return(resp);
-	resp = flash_id_check(bank, 0);
-	if (resp) {
-		fclose(srr.openfile);
-		return(resp);
-	}
 	sprintf(shortarg, "%lx", (u_long) bi->base_addr);
 	targv[0] = bi->ops->loadagent_setbase_cmd;
 	targv[1] = shortarg;
--- a/loadtools/flutil.c	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/flutil.c	Tue May 28 05:12:47 2019 +0000
@@ -9,167 +9,6 @@
 #include "flash.h"
 
 extern struct flash_bank_info flash_bank_info[2];
-extern struct flash_cmdset flash_cmdset_amd;
-extern struct flash_cmdset flash_cmdset_intel;
-
-static int
-cfi_read_byte(bi, off, ret16p)
-	struct flash_bank_info *bi;
-	int off;
-	uint16_t *ret16p;
-{
-	return do_r16(bi->base_addr + (off << 1), ret16p);
-}
-
-static int
-cfi_read_twobyte(bi, off, retptr)
-	struct flash_bank_info *bi;
-	int off;
-	uint16_t *retptr;
-{
-	uint16_t lo, hi;
-
-	if (cfi_read_byte(bi, off, &lo) < 0)
-		return(-1);
-	lo &= 0xFF;
-	if (cfi_read_byte(bi, off + 1, &hi) < 0)
-		return(-1);
-	hi &= 0xFF;
-	*retptr = (hi << 8) | lo;
-	return(0);
-}
-
-flash_get_cfi(bank)
-{
-	struct flash_bank_info *bi;
-	struct flash_geom *geom;
-	struct flash_region_desc *reg;
-	int nr;
-	uint16_t rdval, cmdset_id;
-	uint32_t size_check;
-
-	bi = flash_bank_info + bank;
-	if (bi->geom)
-		return(0);
-	printf("Performing CFI query\n");
-	if (do_w16(bi->base_addr + 0xAA, 0x98)) {
-		fprintf(stderr, "unexpected response to w16 - aborting\n");
-		return(-1);
-	}
-	/* if do_r16() returns -1, error msg has already been printed */
-	if (cfi_read_byte(bi, 0x10, &rdval) < 0)
-		return(-1);
-	if (rdval != 'Q') {
-noqry:		fprintf(stderr, "error: no QRY response from flash\n");
-		amd_reset_cmd(bi);
-		return(-1);
-	}
-	if (cfi_read_byte(bi, 0x11, &rdval) < 0)
-		return(-1);
-	if (rdval != 'R')
-		goto noqry;
-	if (cfi_read_byte(bi, 0x12, &rdval) < 0)
-		return(-1);
-	if (rdval != 'Y')
-		goto noqry;
-	if (cfi_read_twobyte(bi, 0x13, &cmdset_id) < 0)
-		return(-1);
-	if (!bi->ops) {
-		switch (cmdset_id) {
-		case 2:
-			bi->ops = &flash_cmdset_amd;
-			break;
-		case 3:
-			bi->ops = &flash_cmdset_intel;
-			break;
-		default:
-			fprintf(stderr, "error: command set %04X unsupported\n",
-				cmdset_id);
-			amd_reset_cmd(bi);
-			return(-1);
-		}
-	}
-	geom = malloc(sizeof(struct flash_geom));
-	if (!geom) {
-		fprintf(stderr,
-	"unable to malloc buffer for flash bank %d CFI geometry structure\n",
-			bank);
-		bi->ops->reset_cmd(bi);
-		return(-1);
-	}
-	/* total device size */
-	if (cfi_read_byte(bi, 0x27, &rdval) < 0) {
-free_and_immed_out:
-		free(geom);
-		return(-1);
-	}
-	if (rdval < 20 || rdval > 24) {
-		fprintf(stderr,
-			"error: CFI reports unreasonable device size\n");
-free_and_clean_out:
-		free(geom);
-		bi->ops->reset_cmd(bi);
-		return(-1);
-	}
-	geom->total_size = 1 << rdval;
-	if (geom->total_size > bi->bank_desc->align_size) {
-		fprintf(stderr,
-	"error: CFI device size 0x%lx exceeds configured maximum 0x%lx\n",
-			(u_long) geom->total_size, bi->bank_desc->align_size);
-		goto free_and_clean_out;
-	}
-	if (cfi_read_byte(bi, 0x2C, &rdval) < 0)
-		goto free_and_immed_out;
-	if (rdval < 1 || rdval > CFI_MAX_REGIONS) {
-		fprintf(stderr,
-			"error: CFI reports unreasonable # of erase regions\n");
-		goto free_and_clean_out;
-	}
-	geom->nregions = rdval;
-	geom->total_sectors = 0;
-	size_check = 0;
-	for (nr = 0; nr < geom->nregions; nr++) {
-		reg = geom->regions + nr;
-		if (cfi_read_twobyte(bi, 0x2D + nr*4, &rdval) < 0)
-			goto free_and_immed_out;
-		if (rdval > 255) {
-			fprintf(stderr,
-		"error: CFI reports unreasonable # of sectors in region %d\n",
-				nr);
-			goto free_and_clean_out;
-		}
-		reg->nsectors = rdval + 1;
-		geom->total_sectors += reg->nsectors;
-		if (cfi_read_twobyte(bi, 0x2F + nr*4, &rdval) < 0)
-			goto free_and_immed_out;
-		if (rdval < 0x20 || rdval > 0x400) {
-			fprintf(stderr,
-		"error: CFI reports unreasonable sector size in region %d\n",
-				nr);
-			goto free_and_clean_out;
-		}
-		reg->sector_size = rdval << 8;
-		size_check += reg->sector_size * reg->nsectors;
-	}
-	if (bi->ops->reset_cmd(bi) < 0) {
-		/* error msg already printed */
-		free(geom);
-		return(-1);
-	}
-	if (size_check != geom->total_size) {
-		fprintf(stderr,
-"CFI error: added size of erase regions (%lx) != reported device size (%lx)\n",
-			(u_long) size_check, (u_long) geom->total_size);
-		free(geom);
-		return(-1);
-	}
-	/* all checks passed */
-	bi->geom = geom;
-	printf(
-"CFI query successful: total size %lx, %u sectors, command set style %04X\n",
-		(u_long) geom->total_size, geom->total_sectors, cmdset_id);
-	return(1);
-}
 
 get_flash_sector_table(bank)
 {
@@ -183,7 +22,7 @@
 	bi = flash_bank_info + bank;
 	if (bi->sectors)
 		return(0);
-	i = flash_get_cfi(bank);
+	i = flash_detect(bank, 0);
 	if (i < 0)
 		return(i);
 	geom = bi->geom;
@@ -291,57 +130,3 @@
 	}
 	*s = '\0';
 }
-
-flash_id_check(bank, repeat)
-{
-	struct flash_bank_info *bi;
-	struct flash_bank_desc *bd;
-	struct flash_idcheck *id;
-	int stat, fail;
-	uint16_t rdval;
-	unsigned cnt;
-
-	bi = flash_bank_info + bank;
-	if (bi->idcheck_done && !repeat)
-		return(0);
-	bd = bi->bank_desc;
-	if (!bd->idcheck_table || !bd->idcheck_num)
-		return(0);
-	printf("Performing flash ID check\n");
-	stat = do_w16(bi->base_addr + 0xAAA, 0xAA);
-	if (stat) {
-bad_w16:	fprintf(stderr,
-	"unexpected response to w16 in read ID cmd sequence - aborting\n");
-		return(-1);
-	}
-	stat = do_w16(bi->base_addr + 0x554, 0x55);
-	if (stat)
-		goto bad_w16;
-	stat = do_w16(bi->base_addr + 0xAAA, 0x90);
-	if (stat)
-		goto bad_w16;
-	id = bd->idcheck_table;
-	fail = 0;
-	for (cnt = 0; cnt < bd->idcheck_num; cnt++) {
-		stat = do_r16(bi->base_addr + id->offset, &rdval);
-		if (stat)
-			return(stat);	/* error msg already printed */
-		printf("offset %02X: %04X -- ", (int)id->offset, (int)rdval);
-		if (rdval == id->expect_val)
-			printf("PASS\n");
-		else {
-			printf("FAIL: expected %04X\n", (int)id->expect_val);
-			fail = 1;
-			break;
-		}
-		id++;
-	}
-	if (fail)
-		return(-1);
-	if (bi->ops->reset_cmd(bi) < 0) {
-		/* error msg already printed */
-		return(-1);
-	}
-	bi->idcheck_done = 1;
-	return(0);
-}
--- a/loadtools/hwparam.c	Mon May 27 19:58:01 2019 +0000
+++ b/loadtools/hwparam.c	Tue May 28 05:12:47 2019 +0000
@@ -14,7 +14,7 @@
 
 extern void set_boot_reflash_hack();
 extern void set_default_exit_mode();
-extern void set_flash_device();
+extern void set_flash_config();
 
 char hw_init_script[128];
 
@@ -133,7 +133,7 @@
 	{"boot-reflash-hack", set_boot_reflash_hack},
 	{"compal-stage", handle_compal_stage},
 	{"exit-mode", set_default_exit_mode},
-	{"flash", set_flash_device},
+	{"flash", set_flash_config},
 	{"init-script", handle_init_script},
 	{"pll-config", handle_pll_config},
 	{"rhea-cntl", handle_rhea_cntl},