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@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;