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(-)
@@ -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 =
{
@@ -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,
@@ -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,
};
@@ -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