diff options
-rw-r--r-- | chipdrivers.h | 3 | ||||
-rw-r--r-- | flashchips.c | 263 | ||||
-rw-r--r-- | flashchips.h | 17 | ||||
-rw-r--r-- | spi.h | 5 | ||||
-rw-r--r-- | spi25.c | 45 | ||||
-rw-r--r-- | spi25_statusreg.c | 22 |
6 files changed, 339 insertions, 16 deletions
diff --git a/chipdrivers.h b/chipdrivers.h index 03abdd90..091d14c7 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -48,6 +48,7 @@ int spi_block_erase_52(struct flashctx *flash, unsigned int addr, unsigned int b int spi_block_erase_60(struct flashctx *flash, unsigned int addr, unsigned int blocklen); int spi_block_erase_62(struct flashctx *flash, unsigned int addr, unsigned int blocklen); int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen); int spi_block_erase_c7(struct flashctx *flash, unsigned int addr, unsigned int blocklen); int spi_block_erase_d7(struct flashctx *flash, unsigned int addr, unsigned int blocklen); int spi_block_erase_d8(struct flashctx *flash, unsigned int addr, unsigned int blocklen); @@ -91,6 +92,8 @@ int spi_disable_blockprotect_at25f512b(struct flashctx *flash); int spi_disable_blockprotect_at25fs010(struct flashctx *flash); int spi_disable_blockprotect_at25fs040(struct flashctx *flash); int spi_prettyprint_status_register_en25s_wp(struct flashctx *flash); +int spi_prettyprint_status_register_n25q(struct flashctx *flash); +int spi_disable_blockprotect_n25q(struct flashctx *flash); int spi_prettyprint_status_register_bp2_ep_srwd(struct flashctx *flash); int spi_disable_blockprotect_bp2_ep_srwd(struct flashctx *flash); int spi_prettyprint_status_register_sst25(struct flashctx *flash); diff --git a/flashchips.c b/flashchips.c index f50d1309..a3d4345b 100644 --- a/flashchips.c +++ b/flashchips.c @@ -7308,8 +7308,9 @@ const struct flashchip flashchips[] = { .block_erase = spi_block_erase_c7, } }, - .unlock = spi_disable_blockprotect, - .write = spi_chip_write_256, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ .voltage = {1700, 2000}, }, @@ -7341,8 +7342,9 @@ const struct flashchip flashchips[] = { .block_erase = spi_block_erase_c7, } }, - .unlock = spi_disable_blockprotect, - .write = spi_chip_write_256, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ .voltage = {1700, 2000}, }, @@ -7374,8 +7376,9 @@ const struct flashchip flashchips[] = { .block_erase = spi_block_erase_c7, } }, - .unlock = spi_disable_blockprotect, - .write = spi_chip_write_256, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ .voltage = {2700, 3600}, }, @@ -7407,8 +7410,9 @@ const struct flashchip flashchips[] = { .block_erase = spi_block_erase_c7, } }, - .unlock = spi_disable_blockprotect, - .write = spi_chip_write_256, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ .voltage = {1700, 2000}, }, @@ -7440,9 +7444,246 @@ const struct flashchip flashchips[] = { .block_erase = spi_block_erase_c7, } }, - .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */ - .unlock = spi_disable_blockprotect, - .write = spi_chip_write_256, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ + .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ + .voltage = {2700, 3600}, + }, + + { + .vendor = "Numonyx", + .name = "N25Q128..1E", /* ..1E = 1.8V, uniform 64KB/4KB blocks/sectors */ + .bustype = BUS_SPI, + .manufacture_id = ST_ID, + .model_id = ST_N25Q128__1E, + .total_size = 16384, + .page_size = 256, + /* supports SFDP */ + /* OTP: 64B total; read 0x4B, write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .block_erasers = { + { + .eraseblocks = { {4 * 1024, 4096 } }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 256} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {16384 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + } + }, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ + .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ + .voltage = {1700, 2000}, + }, + + { + .vendor = "Numonyx", + .name = "N25Q128..3E", /* ..3E = 3V, uniform 64KB/4KB blocks/sectors */ + .bustype = BUS_SPI, + .manufacture_id = ST_ID, + .model_id = ST_N25Q128__3E, + .total_size = 16384, + .page_size = 256, + /* supports SFDP */ + /* OTP: 64B total; read 0x4B, write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, + .tested = TEST_UNTESTED, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .block_erasers = { + { + .eraseblocks = { {4 * 1024, 4096 } }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 256} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {16384 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + } + }, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ + .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ + .voltage = {2700, 3600}, + }, + + { + .vendor = "Numonyx", + .name = "N25Q256..1E", /* ..1E = 1.8V, uniform 64KB/4KB blocks/sectors */ + .bustype = BUS_SPI, + .manufacture_id = ST_ID, + .model_id = ST_N25Q256__1E, + .total_size = 32768, + .page_size = 256, + /* supports SFDP */ + /* OTP: 64B total; read 0x4B, write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, + .tested = TEST_BAD_REW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .block_erasers = { + { + .eraseblocks = { {4 * 1024, 8192 } }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 512} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {32768 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + } + }, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ + .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ + .voltage = {1700, 2000}, + }, + + { + .vendor = "Numonyx", + .name = "N25Q256..3E", /* ..3E = 3V, uniform 64KB/4KB blocks/sectors */ + .bustype = BUS_SPI, + .manufacture_id = ST_ID, + .model_id = ST_N25Q256__3E, + .total_size = 32768, + .page_size = 256, + /* supports SFDP */ + /* OTP: 64B total; read 0x4B, write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, + .tested = TEST_BAD_REW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .block_erasers = { + { + .eraseblocks = { {4 * 1024, 8192 } }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 512} }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {32768 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + } + }, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ + .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ + .voltage = {2700, 3600}, + }, + + { + .vendor = "Numonyx", + .name = "N25Q512..1E", /* ..1E = 1.8V, uniform 64KB/4KB blocks/sectors */ + .bustype = BUS_SPI, + .manufacture_id = ST_ID, + .model_id = ST_N25Q512__1E, + .total_size = 65536, + .page_size = 256, + /* supports SFDP */ + /* OTP: 64B total; read 0x4B, write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, + .tested = TEST_BAD_REW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .block_erasers = { + { + .eraseblocks = { {4 * 1024, 16384 } }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 1024 } }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {32 * 1024 * 1024, 2 } }, + .block_erase = spi_block_erase_c4, + }, { /* Some models have a bulk erase command too. */ + .eraseblocks = { {64 * 1024 * 1024, 1 } }, + .block_erase = spi_block_erase_c7, + } + }, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ + .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ + .voltage = {1700, 2000}, + }, + + { + .vendor = "Numonyx", + .name = "N25Q512..3E", /* ..3E = 3V, uniform 64KB/4KB blocks/sectors */ + .bustype = BUS_SPI, + .manufacture_id = ST_ID, + .model_id = ST_N25Q512__3E, + .total_size = 65536, + .page_size = 256, + /* supports SFDP */ + /* OTP: 64B total; read 0x4B, write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, + .tested = TEST_BAD_REW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .block_erasers = { + { + .eraseblocks = { {4 * 1024, 16384 } }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 1024 } }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {32 * 1024 * 1024, 2 } }, + .block_erase = spi_block_erase_c4, + }, { /* Some models have a bulk erase command too. */ + .eraseblocks = { {64 * 1024 * 1024, 1} }, + .block_erase = spi_block_erase_c7, + } + }, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ + .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ + .voltage = {2700, 3600}, + }, + + { + .vendor = "Numonyx", + .name = "N25Q00A..3G", /* ..3G = 3V, uniform 64KB/4KB blocks/sectors */ + .bustype = BUS_SPI, + .manufacture_id = ST_ID, + .model_id = ST_N25Q00A__3E, + .total_size = 131072, + .page_size = 256, + /* supports SFDP */ + /* OTP: 64B total; read 0x4B, write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, + .tested = TEST_BAD_REW, + .probe = probe_spi_rdid, + .probe_timing = TIMING_ZERO, + .block_erasers = { + { + .eraseblocks = { {4 * 1024, 32768 } }, + .block_erase = spi_block_erase_20, + }, { + .eraseblocks = { {64 * 1024, 2048 } }, + .block_erase = spi_block_erase_d8, + }, { + .eraseblocks = { {32 * 1024 * 1024, 4 } }, + .block_erase = spi_block_erase_c4, + } + }, + .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */ + .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */ + .write = spi_chip_write_256, /* Multi I/O supported */ .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */ .voltage = {2700, 3600}, }, diff --git a/flashchips.h b/flashchips.h index cbeb2014..bf229861 100644 --- a/flashchips.h +++ b/flashchips.h @@ -663,11 +663,18 @@ #define ST_M29W010B 0x23 #define ST_M29W040B 0xE3 #define ST_M29W512B 0x27 -#define ST_N25Q016__1E 0xBB15 /* N25Q016, 1.8V, (uniform sectors expected) */ -#define ST_N25Q032__3E 0xBA16 /* N25Q032, 3.0V, (uniform sectors expected) */ -#define ST_N25Q032__1E 0xBB16 /* N25Q032, 1.8V, (uniform sectors expected) */ -#define ST_N25Q064__3E 0xBA17 /* N25Q064, 3.0V, (uniform sectors expected) */ -#define ST_N25Q064__1E 0xBB17 /* N25Q064, 1.8V, (uniform sectors expected) */ +#define ST_N25Q016__1E 0xBB15 /* N25Q016, 1.8V, (uniform sectors expected) */ +#define ST_N25Q032__3E 0xBA16 /* N25Q032, 3.0V, (uniform sectors expected) */ +#define ST_N25Q032__1E 0xBB16 /* N25Q032, 1.8V, (uniform sectors expected) */ +#define ST_N25Q064__3E 0xBA17 /* N25Q064, 3.0V, (uniform sectors expected) */ +#define ST_N25Q064__1E 0xBB17 /* N25Q064, 1.8V, (uniform sectors expected) */ +#define ST_N25Q128__3E 0xBA18 /* N25Q128, 3.0V, (uniform sectors expected) */ +#define ST_N25Q128__1E 0xBB18 /* N25Q128, 1.8V, (uniform sectors expected) */ +#define ST_N25Q256__3E 0xBA19 /* N25Q256, 3.0V, (uniform sectors expected) */ +#define ST_N25Q256__1E 0xBB19 /* N25Q256, 1.8V, (uniform sectors expected) */ +#define ST_N25Q512__3E 0xBA20 /* N25Q512, 3.0V, (uniform sectors expected) */ +#define ST_N25Q512__1E 0xBB20 /* N25Q512, 1.8V, (uniform sectors expected) */ +#define ST_N25Q00A__3E 0xBA21 /* N25Q00A, 3.0V, (uniform sectors expected) */ #define SYNCMOS_MVC_ID 0x40 /* SyncMOS (SM) and Mosel Vitelic Corporation (MVC) */ #define MVC_V29C51000T 0x00 @@ -91,6 +91,11 @@ #define JEDEC_BE_81_OUTSIZE 0x04 #define JEDEC_BE_81_INSIZE 0x00 +/* Block Erase 0xc4 is supported by Micron chips. */ +#define JEDEC_BE_C4 0xc4 +#define JEDEC_BE_C4_OUTSIZE 0x04 +#define JEDEC_BE_C4_INSIZE 0x00 + /* Block Erase 0xd8 is supported by EON/Macronix chips. */ #define JEDEC_BE_D8 0xd8 #define JEDEC_BE_D8_OUTSIZE 0x04 @@ -474,6 +474,49 @@ int spi_block_erase_52(struct flashctx *flash, unsigned int addr, } /* Block size is usually + * 32M (one die) for Micron + */ +int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen) +{ + int result; + struct spi_command cmds[] = { + { + .writecnt = JEDEC_WREN_OUTSIZE, + .writearr = (const unsigned char[]){ JEDEC_WREN }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = JEDEC_BE_C4_OUTSIZE, + .writearr = (const unsigned char[]){ + JEDEC_BE_C4, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + (addr & 0xff) + }, + .readcnt = 0, + .readarr = NULL, + }, { + .writecnt = 0, + .writearr = NULL, + .readcnt = 0, + .readarr = NULL, + }}; + + result = spi_send_multicommand(flash, cmds); + if (result) { + msg_cerr("%s failed during command execution at address 0x%x\n", __func__, addr); + return result; + } + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 240-480 s, so wait in 500 ms steps. + */ + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(500 * 1000 * 1000); + /* FIXME: Check the status register for errors. */ + return 0; +} + +/* Block size is usually * 64k for Macronix * 32k for SST * 4-32k non-uniform for EON @@ -780,6 +823,8 @@ erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode) return &spi_block_erase_62; case 0x81: return &spi_block_erase_81; + case 0xc4: + return &spi_block_erase_c4; case 0xc7: return &spi_block_erase_c7; case 0xd7: diff --git a/spi25_statusreg.c b/spi25_statusreg.c index 09fa0575..107bacd4 100644 --- a/spi25_statusreg.c +++ b/spi25_statusreg.c @@ -607,6 +607,28 @@ int spi_prettyprint_status_register_en25s_wp(struct flashctx *flash) /* === Intel/Numonyx/Micron - Spansion === */ +int spi_disable_blockprotect_n25q(struct flashctx *flash) +{ + return spi_disable_blockprotect_generic(flash, 0x5C, 1 << 7, 0, 0xFF); +} + +int spi_prettyprint_status_register_n25q(struct flashctx *flash) +{ + uint8_t status = spi_read_status_register(flash); + spi_prettyprint_status_register_hex(status); + + spi_prettyprint_status_register_srwd(status); + if (flash->chip->total_size <= 32 / 8 * 1024) /* N25Q16 and N25Q32: reserved */ + spi_prettyprint_status_register_bit(status, 6); + else + msg_cdbg("Chip status register: Block Protect 3 (BP3) is %sset\n", + (status & (1 << 6)) ? "" : "not "); + msg_cdbg("Chip status register: Top/Bottom (TB) is %s\n", (status & (1 << 5)) ? "bottom" : "top"); + spi_prettyprint_status_register_bp(status, 2); + spi_prettyprint_status_register_welwip(status); + return 0; +} + /* Used by Intel/Numonyx S33 and Spansion S25FL-S chips */ /* TODO: Clear P_FAIL and E_FAIL with Clear SR Fail Flags Command (30h) here? */ int spi_disable_blockprotect_bp2_ep_srwd(struct flashctx *flash) |