[flashrom] [PATCH] Add support for a bunch of 29GL parallel flash chips.

Stefan Tauner stefan.tauner at alumni.tuwien.ac.at
Sat May 24 23:53:18 CEST 2014


They use a new 3-Byte device ID probing function (although the first one
seems to always be a continuation indicator) at addresses 0x01, 0x0E, 0x0F.

Supported families include...
 - EON EN29GL
 - Gigadevice GD29GL (if they really exist)
 - Macronix MX29GL (+MX68GL1G0F)
 - Spansion 29GL (+S70GL02G)
 - Winbond W29GL

Signed-off-by: Stefan Tauner <stefan.tauner at alumni.tuwien.ac.at>
---
Hello Gilbert,

I've tried to come up with a probing function that works on all 29GL chips.
Please apply the patch to r1796, recompile and post a verbose log,
e.g. by running './flashrom -p internal -o 29gl_probe.log and attaching
29gl_probe.log to the mail. Thanks!

I have very little experience with parallel flash chips so it might not
work at all. If it does detect the chip correctly, it will probably read
it correctly too, and maybe even erase it. I am not so sure about writing
though, so I would rather noth attempt writes or erases yet.

 chipdrivers.h |  1 +
 flashchips.c  | 27 ++++++++++++++++
 flashchips.h  | 66 ++++++++++++++++++++++++++++++++++++---
 jedec.c       | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 188 insertions(+), 5 deletions(-)

diff --git a/chipdrivers.h b/chipdrivers.h
index f270b55..1f6d57a 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -140,6 +140,7 @@ void data_polling_jedec(struct flashctx *flash, chipaddr dst, uint8_t data);
 int write_byte_program_jedec(struct flashctx *flash, chipaddr bios, uint8_t *src,
 			     chipaddr dst);
 int probe_jedec(struct flashctx *flash);
+int probe_jedec_29gl(struct flashctx *flash);
 int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
 int write_jedec_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
 int erase_sector_jedec(struct flashctx *flash, unsigned int page, unsigned int pagesize);
diff --git a/flashchips.c b/flashchips.c
index dee7d9e..40f79b3 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -6910,6 +6910,33 @@ const struct flashchip flashchips[] = {
 
 	{
 		.vendor		= "Macronix",
+		.name		= "MX29GL128F",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= MACRONIX_ID,
+		.model_id	= MACRONIX_MX29GL128F,
+		.total_size	= 16384,
+		.page_size	= 128 * 1024,
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {128 * 1024, 128}, },
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {16 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Macronix",
 		.name		= "MX29LV040",
 		.bustype	= BUS_PARALLEL,
 		.manufacture_id	= MACRONIX_ID,
diff --git a/flashchips.h b/flashchips.h
index 234e58c..7eea262 100644
--- a/flashchips.h
+++ b/flashchips.h
@@ -287,6 +287,11 @@
 #define EON_EN29LV640B		0xCB
 #define EON_EN29F002T		0x7F92	/* Same as EN29F002A */
 #define EON_EN29F002B		0x7F97	/* Same as EN29F002AN */
+#define EON_EN29GL064HL		0x7F0C01
+#define EON_EN29GL064T		0x7F1001	/* Same ID as EN29GL064AT */
+#define EON_EN29GL064B		0x7F1001	/* Same ID as EN29GL064AB */
+#define EON_EN29GL128HL		0x7F2101	/* Uniform Sectors, WP protects Top OR Bottom sector */
+#define EON_EN29GL256HL		0x7F2201	/* Uniform Sectors, WP protects Top OR Bottom sector */
 
 #define EXCEL_ID		0x7F7F7F7F4A	/* Excel Semiconductor Inc. (ESI) resides in bank 5 */
 #define EXCEL_ID_NOPREFIX	0x4A	/* ESI, missing 0x7F prefix */
@@ -353,6 +358,7 @@
 #define GIGADEVICE_GD25LQ32	0x6016
 #define GIGADEVICE_GD25LQ64	0x6017	/* Same as GD25LQ64B (which is faster) */
 #define GIGADEVICE_GD25LQ128	0x6018
+#define GIGADEVICE_GD29GL064CAB	0x7E0601
 
 #define HYUNDAI_ID		0xAD	/* Hyundai */
 #define HYUNDAI_HY29F400T	0x23	/* Same as HY29F400AT */
@@ -464,6 +470,16 @@
 #define MACRONIX_MX29F400T	0x23	/* Same as MX29F400CT */
 #define MACRONIX_MX29F800B	0x58
 #define MACRONIX_MX29F800T	0xD6
+#define MACRONIX_MX29GL320EB	0x7E1A00
+#define MACRONIX_MX29GL320ET	0x7E1A01
+#define MACRONIX_MX29GL320EHL	0x7E1D00
+#define MACRONIX_MX29GL640EB	0x7E1000
+#define MACRONIX_MX29GL640ET	0x7E1001
+#define MACRONIX_MX29GL640EHL	0x7E0C01
+#define MACRONIX_MX29GL128F	0x7E2101
+#define MACRONIX_MX29GL256F	0x7E2201
+#define MACRONIX_MX29GL512F	0x7E2301
+#define MACRONIX_MX68GL1G0F	0x7E2801
 #define MACRONIX_MX29LV002CB	0x5A
 #define MACRONIX_MX29LV002CT	0x59
 #define MACRONIX_MX29LV004B	0xB6	/* Same as MX29LV004CB */
@@ -551,12 +567,10 @@
 #define SHARP_LHF00L02		0xC9	/* Same as LHF00L06/LHF00L07 */
 #define SHARP_LHF00L04		0xCF	/* Same as LHF00L03/LHF00L05 */
 
-/*
- * Spansion was previously a joint venture of AMD and Fujitsu.
- * S25 chips are SPI. The first device ID byte is memory type and
- * the second device ID byte is memory capacity.
- */
+/* Spansion was previously a joint venture of AMD and Fujitsu. */
 #define SPANSION_ID		0x01	/* Spansion, same ID as AMD */
+/* S25 chips are SPI. The first device ID byte is memory type and
+ * the second device ID byte is memory capacity. */
 #define SPANSION_S25FL004A	0x0212
 #define SPANSION_S25FL008A	0x0213
 #define SPANSION_S25FL016A	0x0214
@@ -571,6 +585,40 @@
 #define SPANSION_S25FL132K	0x4016
 #define SPANSION_S25FL164K	0x4017
 
+/* Spansion 29GL families got a suffix indicating the process technology but share the same 3-Byte IDs. They can
+ * however be differentiated by CFI byte 45h. Some versions exist which have special top or bottom boot sectors
+ * and various WP configurations (not heeded in the table below).
+ *
+ * Suf.  Process Sector Sz  Rd Page  Wr Page  Data Width  OTP Sz   Min Size     Max Size
+ *  A     200 nm    64 kB      8 B     32 B     x8/x16     256 B   16Mb/ 2MB   64Mb/  8MB
+ *  M     230 nm    64 kB      8 B     32 B     x8/x16     256 B   32Mb/ 4MB  256Mb/ 32MB
+ *  N*    110 nm    64 kB     16 B     32 B     x8/x16     256 B   32Mb/ 4MB   64Mb/  8MB
+ *  N*    110 nm   128 kB     16 B     32 B     x8/x16     256 B  128Mb/16MB  256Mb/ 64MB
+ *  P      90 nm   128 kB     16 B     64 B     x8/x16     256 B  128Mb/16MB    2Gb/256MB
+ *  S      65 nm   128 kB     32 B    512 B     x8 only    512 B  128Mb/16MB    2Gb/256MB
+ *
+ * For the N series there are two subgroups: the 4 and 8MB devices (S29GL032N, S29GL064N) have 64 kB erase
+ * sectors while the bigger chips got 128 kB sectors.
+ * Each series includes multiple models varying in speedgrade, boot block configurations etc.
+ */
+#define SPANSION_S29GL016_1	0xC4	/* Top Boot Sector, WP protects Top 2 sectors */
+#define SPANSION_S29GL016_2	0x49	/* Bottom Boot Sector, WP protects Bottom 2 sectors */
+/* Same IDs for S29GL032A, S29GL032M, S29GL032N (variations) */
+#define SPANSION_S29GL032_1289	0x7E1D00	/* Uniform Sectors, WP protects Top OR Bottom sector */
+#define SPANSION_S29GL032_3	0x7E1A01	/* Top Boot Sector, WP protects Top 2 sectors */
+#define SPANSION_S29GL032_4	0x7E1A00	/* Bottom Boot Sector, WP protects Bottom 2 sectors */
+/* Same IDs for S29GL064A, S29GL064M, S29GL064N, S29GL064S (variations) */
+#define SPANSION_S29GL064_1289	0x7E0C01	/* Uniform Sectors, WP protects Top OR Bottom sector */
+#define SPANSION_S29GL064_3	0x7E1001	/* Top Boot Sector, WP protects Top 2 sectors */
+#define SPANSION_S29GL064_4	0x7E1000	/* Bottom Boot Sector, WP protects Bottom 2 sectors */
+#define SPANSION_S29GL064_567	0x7E1301	/* x16 only, Uniform Sectors */
+
+#define SPANSION_S29GL128	0x7E2101	/* Same ID for S29GL128M, S29GL128N, S29GL128P, S29GL128S */
+#define SPANSION_S29GL256	0x7E2201	/* Same ID for S29GL256M, S29GL256N, S29GL256P, S29GL256S */
+#define SPANSION_S29GL512	0x7E2301	/* Same ID for S29GL512P, S29GL512S */
+#define SPANSION_S29GL01G	0x7E2801	/* Same ID for S29GL01GP, S29GL01GS */
+#define SPANSION_S70GL02G	0x7E4801	/* Same ID for S70GL02GP, S70GL02GS; based on two S29GL01G dies respectively */
+
 /*
  * SST25 chips are SPI, first byte of device ID is memory type, second
  * byte of device ID is related to log(bitsize) at least for some chips.
@@ -770,6 +818,14 @@
 #define WINBOND_W29C020		0x45    /* Same as W29C020C, W29C022 and ASD AE29F2008 */
 #define WINBOND_W29C040		0x46    /* Same as W29C040P */
 #define WINBOND_W29C512A	0xC8    /* Same as W29EE512 */
+#define WINBOND_W29GL032CHL	0x7E1D01	/* Uniform Sectors, WP protects Top OR Bottom sector */
+#define WINBOND_W29GL032CB	0x7E1A00	/* Top Boot Sector, WP protects Top 2 sectors */
+#define WINBOND_W29GL032CT	0x7E1A01	/* Bottom Boot Sector, WP protects Bottom 2 sectors */
+#define WINBOND_W29GL064CHL	0x7E0C01	/* Uniform Sectors, WP protects Top OR Bottom sector */
+#define WINBOND_W29GL064CB	0x7E1000	/* Top Boot Sector, WP protects Top 2 sectors */
+#define WINBOND_W29GL064CT	0x7E1001	/* Bottom Boot Sector, WP protects Bottom 2 sectors */
+#define WINBOND_W29GL0128CHL	0x7E2101	/* Uniform Sectors, WP protects Top OR Bottom sector */
+#define WINBOND_W29GL0256HL	0x7E2201	/* Same ID for W29GL0256P and W29GL0256S; uniform Sectors, WP protects Top OR Bottom sector */
 #define WINBOND_W39F010		0xA1
 #define WINBOND_W39L010		0x31
 #define WINBOND_W39L020		0xB5
diff --git a/jedec.c b/jedec.c
index be4782a..2569729 100644
--- a/jedec.c
+++ b/jedec.c
@@ -120,6 +120,105 @@ static void start_program_jedec_common(struct flashctx *flash,
 	chip_writeb(flash, 0xA0, bios + (0x5555 & mask));
 }
 
+int probe_jedec_29gl(struct flashctx *flash)
+{
+	unsigned int mask = getaddrmask(flash->chip);
+	chipaddr bios = flash->virtual_memory;
+	const struct flashchip *chip = flash->chip;
+
+	//unsigned int probe_timing_enter, probe_timing_exit;
+	//if (chip->probe_timing > 0)
+		//probe_timing_enter = probe_timing_exit = chip->probe_timing;
+	//else if (chip->probe_timing == TIMING_ZERO) { /* No delay. */
+		//probe_timing_enter = probe_timing_exit = 0;
+	//} else if (chip->probe_timing == TIMING_FIXME) { /* == _IGNORED */
+		//msg_cdbg("Chip lacks correct probe timing information, "
+			     //"using default 10mS/40uS. ");
+		//probe_timing_enter = 10000;
+		//probe_timing_exit = 40;
+	//} else {
+		//msg_cerr("Chip has negative value in probe_timing, failing "
+		       //"without chip access\n");
+		//return 0;
+	//}
+
+	/* Earlier probes might have been too fast for the chip to enter ID
+	 * mode completely. Allow the chip to finish this before seeing a
+	 * reset command.
+	 */
+	//if (probe_timing_enter)
+		//programmer_delay(probe_timing_enter);
+
+	/* Reset chip to a clean slate */
+	if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
+	{
+		chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+		//if (probe_timing_exit)
+			//programmer_delay(10);
+		chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+		//if (probe_timing_exit)
+			//programmer_delay(10);
+	}
+	chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
+	//if (probe_timing_exit)
+		//programmer_delay(probe_timing_exit);
+
+	/* Issue JEDEC Product ID Entry command */
+	chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+	//if (probe_timing_enter)
+		//programmer_delay(10);
+	chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+	//if (probe_timing_enter)
+		//programmer_delay(10);
+	chip_writeb(flash, 0x90, bios + (0x5555 & mask));
+	//if (probe_timing_enter)
+		//programmer_delay(probe_timing_enter);
+
+	/* Read product ID */
+	uint32_t man_id = chip_readb(flash, bios + 0x00); // FIXME: Continuation loop
+	uint32_t dev_id = (chip_readb(flash, bios + 0x01) << 16) |
+			  (chip_readb(flash, bios + 0x0E) <<  8) |
+			  (chip_readb(flash, bios + 0x0F) <<  0);
+
+	/* Issue JEDEC Product ID Exit command */
+	if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
+	{
+		chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+		//if (probe_timing_exit)
+			//programmer_delay(10);
+		chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+		//if (probe_timing_exit)
+			//programmer_delay(10);
+	}
+	chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
+	//if (probe_timing_exit)
+		//programmer_delay(probe_timing_exit);
+
+	msg_cdbg("%s: man_id 0x%02x, dev_id 0x%06x", __func__, man_id, dev_id);
+	if (!oddparity(man_id))
+		msg_cdbg(", man_id parity violation");
+
+	/* Read the product ID location again. We should now see normal flash contents. */
+	uint32_t flashcontent1 = chip_readb(flash, bios + 0x00); // FIXME: Continuation loop
+	uint32_t flashcontent2 = (chip_readb(flash, bios + 0x01) << 16) |
+				 (chip_readb(flash, bios + 0x0E) <<  8) |
+				 (chip_readb(flash, bios + 0x0F) <<  0);
+
+	if (man_id == flashcontent1)
+		msg_cdbg(", man_id seems to be normal flash content");
+	if (dev_id == flashcontent2)
+		msg_cdbg(", dev_id seems to be normal flash content");
+
+	msg_cdbg("\n");
+	if (man_id != chip->manufacture_id || dev_id != chip->model_id)
+		return 0;
+
+	if (chip->feature_bits & FEATURE_REGISTERMAP)
+		map_flash_registers(flash);
+
+	return 1;
+}
+
 static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
 {
 	chipaddr bios = flash->virtual_memory;
-- 
Kind regards, Stefan Tauner





More information about the flashrom mailing list