Add support for a bunch of 29GL parallel flash chips

29GL chips use a new 3-Byte device ID probing function at addresses
0x01, 0x0E, 0x0F.

Flash chip families supported by this method include...
 - EON EN29GL
 - Gigadevice GD29GL (if they really exist)
 - ISSI (PMC) IS29GL
 - Macronix MX29GL (+MX68GL1G0F)
 - Spansion S29GL (+S70GL02G)
 - Winbond W29GL

This patch adds respective flash chip definitions for chips up to 16 MB from
Eon, ISSI, Macronix and Winbond. Bigger chips as well as those from
Gigadevice and Spansion are left out.

Corresponding to flashrom svn r1835.

Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
diff --git a/chipdrivers.h b/chipdrivers.h
index 57b1340..4ece42e 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -139,6 +139,7 @@
 void toggle_ready_jedec(const struct flashctx *flash, chipaddr dst);
 void data_polling_jedec(const struct flashctx *flash, chipaddr dst, uint8_t data);
 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 e8ac789..a1166e0 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -4892,6 +4892,120 @@
 	},
 
 	{
+		.vendor		= "Eon",
+		.name		= "EN29GL064(A)B",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= EON_ID,
+		.model_id	= EON_EN29GL064B,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{8 * 1024, 8},
+					{64 * 1024, 127},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN29GL064(A)T",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= EON_ID,
+		.model_id	= EON_EN29GL064T,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{64 * 1024, 127},
+					{8 * 1024, 8},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN29GL064H/L",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= EON_ID,
+		.model_id	= EON_EN29GL064HL,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {64 * 1024, 128} },
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN29GL128",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= EON_ID,
+		.model_id	= EON_EN29GL128HL,
+		.total_size	= 16384,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.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		= "Fujitsu",
 		.name		= "MBM29F004BC",
 		.bustype	= BUS_PARALLEL,
@@ -6093,6 +6207,120 @@
 	},
 
 	{
+		.vendor		= "ISSI",
+		.name		= "IS29GL064B",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= ISSI_ID,
+		.model_id	= ISSI_PMC_IS29GL064B,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{8 * 1024, 8},
+					{64 * 1024, 127},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "ISSI",
+		.name		= "IS29GL064T",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= ISSI_ID,
+		.model_id	= ISSI_PMC_IS29GL064T,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{64 * 1024, 127},
+					{8 * 1024, 8},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "ISSI",
+		.name		= "IS29GL064H/L",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= ISSI_ID,
+		.model_id	= ISSI_PMC_IS29GL064HL,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {64 * 1024, 128} },
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "ISSI",
+		.name		= "IS29GL128H/L",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= ISSI_ID,
+		.model_id	= ISSI_PMC_IS29GL128HL,
+		.total_size	= 16384,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.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		= "MX23L3254",
 		.bustype	= BUS_SPI,
@@ -7199,6 +7427,207 @@
 
 	{
 		.vendor		= "Macronix",
+		.name		= "MX29GL320EB",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= MACRONIX_ID,
+		.model_id	= MACRONIX_MX29GL320EB,
+		.total_size	= 4096,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{8 * 1024, 8},
+					{64 * 1024, 63},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {4 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29GL320ET",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= MACRONIX_ID,
+		.model_id	= MACRONIX_MX29GL320ET,
+		.total_size	= 4096,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{64 * 1024, 63},
+					{8 * 1024, 8},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {4 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29GL320EH/L",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= MACRONIX_ID,
+		.model_id	= MACRONIX_MX29GL320EHL,
+		.total_size	= 4096,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {64 * 1024, 64} },
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {4 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29GL640EB",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= MACRONIX_ID,
+		.model_id	= MACRONIX_MX29GL640EB,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{8 * 1024, 8},
+					{64 * 1024, 127},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29GL640ET",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= MACRONIX_ID,
+		.model_id	= MACRONIX_MX29GL640ET,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{64 * 1024, 127},
+					{8 * 1024, 8},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29GL640EH/L",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= MACRONIX_ID,
+		.model_id	= MACRONIX_MX29GL640EHL,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {64 * 1024, 128} },
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Macronix",
+		.name		= "MX29GL128F",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= MACRONIX_ID,
+		.model_id	= MACRONIX_MX29GL128F,
+		.total_size	= 16384,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.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,
@@ -13055,6 +13484,207 @@
 
 	{
 		.vendor		= "Winbond",
+		.name		= "W29GL032CB",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= AMD_ID, /* WTF: "Industry Standard compatible Manufacturer ID code of 01h" */
+		.model_id	= WINBOND_W29GL032CB,
+		.total_size	= 4096,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{8 * 1024, 8},
+					{64 * 1024, 63},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {4 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29GL032CT",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= AMD_ID, /* WTF: "Industry Standard compatible Manufacturer ID code of 01h" */
+		.model_id	= WINBOND_W29GL032CT,
+		.total_size	= 4096,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{64 * 1024, 63},
+					{8 * 1024, 8},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {4 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29GL032CH/L",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= AMD_ID, /* WTF: "Industry Standard compatible Manufacturer ID code of 01h" */
+		.model_id	= WINBOND_W29GL032CHL,
+		.total_size	= 4096,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {64 * 1024, 64} },
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {4 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29GL064CB",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= AMD_ID, /* WTF: "Industry Standard compatible Manufacturer ID code of 01h" */
+		.model_id	= WINBOND_W29GL064CB,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{8 * 1024, 8},
+					{64 * 1024, 127},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29GL064CT",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= AMD_ID, /* WTF: "Industry Standard compatible Manufacturer ID code of 01h" */
+		.model_id	= WINBOND_W29GL064CT,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = {
+					{64 * 1024, 127},
+					{8 * 1024, 8},
+				},
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29GL064CH/L",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= AMD_ID, /* WTF: "Industry Standard compatible Manufacturer ID code of 01h" */
+		.model_id	= WINBOND_W29GL064CHL,
+		.total_size	= 8192,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.feature_bits	= FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_jedec_29gl,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {64 * 1024, 128} },
+				.block_erase = erase_sector_jedec,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = erase_chip_block_jedec,
+			},
+		},
+		.write		= write_jedec_1,
+		.read		= read_memmapped,
+		.voltage	= {2700, 3600},
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W29GL128C",
+		.bustype	= BUS_PARALLEL,
+		.manufacture_id	= AMD_ID, /* WTF: "Industry Standard compatible Manufacturer ID code of 01h" */
+		.model_id	= WINBOND_W29GL128CHL,
+		.total_size	= 16384,
+		.page_size	= 128 * 1024, /* actual page size is 16 */
+		.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		= "Winbond",
 		.name		= "W39F010",
 		.bustype	= BUS_PARALLEL,
 		.manufacture_id	= WINBOND_ID,
diff --git a/flashchips.h b/flashchips.h
index 5589714..029bae8 100644
--- a/flashchips.h
+++ b/flashchips.h
@@ -29,9 +29,9 @@
  * entry of each section should be the manufacturer ID, followed by the
  * list of devices from that manufacturer (sorted by device IDs).
  *
- * All LPC/FWH parts (parallel flash) have 8-bit device IDs if there is no
+ * Most LPC/FWH parts (parallel flash) have 8-bit device IDs if there is no
  * continuation code.
- * SPI parts have 16-bit device IDs if they support RDID.
+ * SPI parts have at least 16-bit device IDs if they support RDID.
  */
 
 #define GENERIC_MANUF_ID	0xFFFF	/* Check if there is a vendor ID */
@@ -290,6 +290,11 @@
 #define EON_EN29LV640B		0xCB
 #define EON_EN29F002T		0x7F92	/* Same as EN29F002A */
 #define EON_EN29F002B		0x7F97	/* Same as EN29F002AN */
+#define EON_EN29GL064HL		0x7E0C01	/* Uniform Sectors, WP protects Top OR Bottom sector */
+#define EON_EN29GL064T		0x7E1001	/* Same ID as EN29GL064AT */
+#define EON_EN29GL064B		0x7E1000	/* 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 */
@@ -356,6 +361,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 */
@@ -424,7 +430,14 @@
 #define SHARP_LH28F008SA	0xA2	/* Sharp chip, Intel Vendor ID */
 #define SHARP_LH28F008SC	0xA6	/* Sharp chip, Intel Vendor ID */
 
-#define ISSI_ID			0xD5	/* ISSI Integrated Silicon Solutions */
+#define ISSI_ID			0xD5	/* ISSI Integrated Silicon Solutions, see also PMC. */
+#define ISSI_PMC_IS29GL032B	0xF9
+#define ISSI_PMC_IS29GL032T	0xF6
+#define ISSI_PMC_IS29GL064B	0x7E1000
+#define ISSI_PMC_IS29GL064T	0x7E1001
+#define ISSI_PMC_IS29GL064HL	0x7E0C01
+#define ISSI_PMC_IS29GL128HL	0x7E2101
+#define ISSI_PMC_IS29GL256HL	0x7E2201
 
 #define MACRONIX_ID		0xC2	/* Macronix (MX) */
 /* Mask ROMs */
@@ -468,6 +481,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 /* Same as MX29GL128E */
+#define MACRONIX_MX29GL256F	0x7E2201 /* Same as MX29GL256E */
+#define MACRONIX_MX29GL512F	0x7E2301
+#define MACRONIX_MX68GL1G0F	0x7E2801
 #define MACRONIX_MX29LV002CB	0x5A
 #define MACRONIX_MX29LV002CT	0x59
 #define MACRONIX_MX29LV004B	0xB6	/* Same as MX29LV004CB */
@@ -506,8 +529,9 @@
 /*
  * Programmable Micro Corp is listed in JEP106W in bank 2, so it should
  * have a 0x7F continuation code prefix.
- * Apparently this name is owned by "Chingis Technology Corporation" http://www.chingistek.com which is now a
- * subsidiary of ISSI. They continue to use the PMC manufacturer ID nevertheless.
+ * Apparently PMC was renamed to "Chingis Technology Corporation" http://www.chingistek.com which is now a
+ * subsidiary of ISSI. They continue to use the PMC manufacturer ID (instead of ISSI's) nevertheless, even for
+ * new chips with IS* model numbers.
  */
 #define PMC_ID			0x7F9D	/* PMC */
 #define PMC_ID_NOPREFIX		0x9D	/* PMC, missing 0x7F prefix */
@@ -557,12 +581,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
@@ -577,6 +599,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.
@@ -776,6 +832,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_W29GL128CHL	0x7E2101	/* Uniform Sectors, WP protects Top OR Bottom sector */
+#define WINBOND_W29GL256HL	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 29fdae8..59bec6f 100644
--- a/jedec.c
+++ b/jedec.c
@@ -121,6 +121,55 @@
 	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;
+
+	/* Reset chip to a clean slate */
+	chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
+
+	/* Issue JEDEC Product ID Entry command */
+	chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
+	chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
+	chip_writeb(flash, 0x90, bios + (0x5555 & mask));
+
+	/* Read product ID */
+	// FIXME: Continuation loop, second byte is at word 0x100/byte 0x200
+	uint32_t man_id = chip_readb(flash, bios + 0x00);
+	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 */
+	chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
+
+	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;