From 12bd794218573836302854675b25203d01f60bb1 Mon Sep 17 00:00:00 2001
From: Hatim Kanchwala <hatim@hatimak.me>
Date: Fri, 26 Aug 2016 12:38:34 +0530
Subject: [PATCH] Add support for W25Q128BV and W25Q128FV

Uses new status register, access protection and OTP infrastructure (WIP). Chip definition for "W25Q128.V" needed to be separated into 2 owing to different status register configurations of W25Q128BV and W25Q128FV.

Signed-off-by: Hatim Kanchwala <hatim@hatimak.me>
---
 flashchips.c           | 48 +++++++++++++++++++++++++++++++++++++++++++++---
 otp_layouts.c          |  2 +-
 statusreg_layouts.c    |  4 ++--
 writeprotect_layouts.c |  2 +-
 4 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/flashchips.c b/flashchips.c
index b946cb8..957d63c 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -14729,70 +14729,112 @@ const struct flashchip flashchips[] = {
 				.eraseblocks = { {8 * 1024 * 1024, 1} },
 				.block_erase = spi_block_erase_60,
 			}, {
 				.eraseblocks = { {8 * 1024 * 1024, 1} },
 				.block_erase = spi_block_erase_c7,
 			}
 		},
 		.status_register = &w25q40bl_64fv_sr,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
 		.wp		= &gd_w_wp,
 		.otp		= &gd_w256_3_otp,
 	},
 
 	{
 		.vendor		= "Winbond",
-		.name		= "W25Q128.V",
+		.name		= "W25Q128BF",
 		.bustype	= BUS_SPI,
 		.manufacture_id	= WINBOND_NEX_ID,
 		.model_id	= WINBOND_NEX_W25Q128_V,
 		.total_size	= 16384,
 		.page_size	= 256,
 		/* supports SFDP */
 		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_OK_PREW,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
 			{
 				.eraseblocks = { {4 * 1024, 4096} },
 				.block_erase = spi_block_erase_20,
 			}, {
 				.eraseblocks = { {32 * 1024, 512} },
 				.block_erase = spi_block_erase_52,
 			}, {
 				.eraseblocks = { {64 * 1024, 256} },
 				.block_erase = spi_block_erase_d8,
 			}, {
 				.eraseblocks = { {16 * 1024 * 1024, 1} },
 				.block_erase = spi_block_erase_60,
 			}, {
 				.eraseblocks = { {16 * 1024 * 1024, 1} },
 				.block_erase = spi_block_erase_c7,
 			}
 		},
-		.printlock	= spi_prettyprint_status_register_plain, /* TODO: improve */
-		.unlock		= spi_disable_blockprotect,
+		.status_register = &w25q40bl_64fv_sr,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+		.voltage	= {2700, 3600},
+		.wp		= &gd_w_wp,
+		.otp		= &gd_w256_3_otp,
+	},
+
+	{
+		.vendor		= "Winbond",
+		.name		= "W25Q128FV",
+		.bustype	= BUS_SPI,
+		.manufacture_id	= WINBOND_NEX_ID,
+		.model_id	= WINBOND_NEX_W25Q128_V,
+		.total_size	= 16384,
+		.page_size	= 256,
+		/* supports SFDP */
+		/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
+		.tested		= TEST_OK_PREW,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 4096} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {32 * 1024, 512} },
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { {64 * 1024, 256} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {16 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {16 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			}
+		},
+		.status_register = &w25q128fw_sr,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
 		.voltage	= {2700, 3600},
+		.wp		= &gd_w_wp,
+		.otp		= &gd_w256_3_otp,
 	},
 
 	{
 		.vendor		= "Winbond",
 		.name		= "W25Q20.W",
 		.bustype	= BUS_SPI,
 		.manufacture_id	= WINBOND_NEX_ID,
 		.model_id	= WINBOND_NEX_W25Q20_W,
 		.total_size	= 256,
 		.page_size	= 256,
 		/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
 		.feature_bits	= FEATURE_WRSR_WREN | FEATURE_OTP,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
 		.block_erasers	=
 		{
diff --git a/otp_layouts.c b/otp_layouts.c
index e19516a..5860a4a 100644
--- a/otp_layouts.c
+++ b/otp_layouts.c
@@ -130,35 +130,35 @@ struct otp en512_16384otp = {
 	.region = {
 		{
 			.addr = 0xFFF000,
 			.size = 512,
 			.status_bit = SRP0,
 		},
 	},
 	.status = &eon_status_generic,
 	.print_status = &eon_print_status_generic,
 	.read = &eon_read_generic,
 	.write = &eon_write_generic,
 	.erase = &eon_erase_generic,
 	.lock = &eon_lock_generic,
 };
 
 /* === GigaDevice and Winbond === */
 // FIXME(hatim): Deal with chips with shared OTP modifier bit
-/* GD25LQ16, GD25LQ80, GD25LQ40, W25Q40BL, W25Q64FV
+/* GD25LQ16, GD25LQ80, GD25LQ40, W25Q40BL, W25Q64FV, W25Q128BV
  * (There is an additional 256 bytes security register
  * at 0x000000 which is reserved and can only be read.) */
 // FIXME(hatim): Add support to interact with the reserved security register
 struct otp gd_w256_3_otp = {
 	.region = {
 		{
 			.addr = 0x001000,
 			.size = 256,
 			.status_bit = LB1,
 		}, {
 			.addr = 0x002000,
 			.size = 256,
 			.status_bit = LB2,
 		}, {
 			.addr = 0x003000,
 			.size = 256,
 			.status_bit = LB3,
diff --git a/statusreg_layouts.c b/statusreg_layouts.c
index e83b1b4..cf963b9 100644
--- a/statusreg_layouts.c
+++ b/statusreg_layouts.c
@@ -267,35 +267,35 @@ struct status_register gd25q80b_128_sr = {
 };
 
 /* === Winbond === */
 /* W25Q80, W25Q16, W25Q32 */
 struct status_register w25q80_16_32_sr = {
 	.layout = {
 		{ WIP, WEL, BP0, BP1, BP2, TB, SEC, SRP0 },
 		{ SRP1, QE, RESV, RESV, RESV, RESV, RESV, RESV },
 	},
 	.read		= &spi_read_status_register_generic,
 	.write		= &spi_write_status_register_generic,
 	.print		= &spi_prettyprint_status_register_generic,
 	.print_wp_mode	= &spi_prettyprint_status_register_wp_generic,
 	.get_wp_mode	= &get_wp_mode_generic,
 	.set_wp_mode	= &set_wp_mode_generic,
 };
 
-/* W25Q40BL, W25Q64FV */
+/* W25Q40BL, W25Q64FV, W25Q128BV */
 struct status_register w25q40bl_64fv_sr = {
 	.layout = {
 		{ WIP, WEL, BP0, BP1, BP2, TB, SEC, SRP0 },
 		{ SRP1, QE, RESV, LB1, LB2, LB3, CMP, SUS },
 	},
 	.read		= &spi_read_status_register_generic,
 	.write		= &spi_write_status_register_generic,
 	.print		= &spi_prettyprint_status_register_generic,
 	.print_wp_mode	= &spi_prettyprint_status_register_wp_generic,
 	.get_wp_mode	= &get_wp_mode_generic,
 	.set_wp_mode	= &set_wp_mode_generic,
 };
 
 /* === Triple status registers === */
 /* === GigaDevice === */
 /* GD25LQ05B, GD25LQ10B, GD25LQ20B */
 struct status_register gd25lq05_10_20b_sr = {
@@ -344,31 +344,31 @@ struct status_register gd25q127c_sr = {
 
 /* GD25Q128C */
 struct status_register gd25q128c_sr = {
 	.layout = {
 		{ WIP, WEL, BP0, BP1, BP2, BP3, BP4, SRP0 },
 		{ SRP1, QE, SUS2, LB1, LB2, LB3, CMP, SUS1 },
 		{ RESV, RESV, WPS, RESV, RESV, DRV0, DRV1, RST },
 	},
 	.read		= &spi_read_status_register_generic,
 	.write		= &spi_write_status_register_generic,
 	.print		= &spi_prettyprint_status_register_generic,
 	.print_wp_mode	= &spi_prettyprint_status_register_wp_generic,
 	.get_wp_mode	= &get_wp_mode_generic,
 	.set_wp_mode	= &set_wp_mode_generic,
 };
 
 /* === Winbond === */
-/* W25Q128FW */
+/* W25Q128FW, W25Q128FV */
 struct status_register w25q128fw_sr = {
 	.layout = {
 		{ WIP, WEL, BP0, BP1, BP2, TB, SEC, SRP0 },
 		{ SRP1, QE, RESV, LB1, LB2, LB3, CMP, SUS },
 		{ RESV, RESV, WPS, RESV, RESV, DRV0, DRV1, RST },
 	},
 	.read		= &spi_read_status_register_generic,
 	.write		= &spi_write_status_register_generic,
 	.print		= &spi_prettyprint_status_register_generic,
 	.print_wp_mode	= &spi_prettyprint_status_register_wp_generic,
 	.get_wp_mode	= &get_wp_mode_generic,
 	.set_wp_mode	= &set_wp_mode_generic,
 };
diff --git a/writeprotect_layouts.c b/writeprotect_layouts.c
index 67e59c2..d216b91 100644
--- a/writeprotect_layouts.c
+++ b/writeprotect_layouts.c
@@ -30,35 +30,35 @@
  *	int (*set_range) (struct flashctx *flash, uint32_t start, uint32_t len);
  *	int (*disable) (struct flashctx *flash);
  *	int (*print_table) (struct flashctx *flash);
  * };
  */
 
 /* A25LQ032, A25LQ32A */
 struct wp a25l032_32a_wp = {
 	.range_table	= &a25l032_range_table,
 	.bp_bitmask	= &bp_bitmask_generic,
 	.print_table	= &print_table_generic,
 	.set_range	= &set_range_generic,
 	.disable	= &disable_generic,
 };
 
 /* A25L080, A25LQ16, GD25LQ40, GD25LQ80, GD25LQ16, GD25Q16, GD25Q16B GD25Q32(B),
  * GD25Q64(B), GD25Q128B, GD25Q128C, GD25VQ16C, GD25VQ21B, GD25VQ40C, GD25VQ41B,
- * GD25VQ80C, W25Q40BL, W25Q64FV */
+ * GD25VQ80C, W25Q40BL, W25Q64FV, W25Q128BV, W25Q128FV */
 struct wp gd_w_wp = {
 	.range_table	= &sec_block_range_pattern,
 	.bp_bitmask	= &bp_bitmask_generic,
 	.print_table	= &print_table_generic,
 	.set_range	= &set_range_generic,
 	.disable	= &disable_generic,
 };
 
 /* EN25QH128 */
 struct wp en25qh128_wp = {
 	.ranges = (struct range[]){
 		/* BP3 effectively acts as TB bit,
 		 * BP[0..2] function normally. */
 		{ 0x000000, 0 },
 		{ 0xff0000, 64 },
 		{ 0xfe0000, 128 },
 		{ 0xfc0000, 256 },
-- 
Hatim Kanchwala
hatim@hatimak.me

