Konstantin Grudnev has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/34496 )
Change subject: Add support for M95M02-A125 ......................................................................
Add support for M95M02-A125
Automotive 2 Mbit (256KiB) serial SPI bus EEPROM PREW tested successfully with use of ch341a programmer on Linux host 5.2.0-1-MANJARO x86_64
Signed-off-by: Konstantin Grudnev grudnevkv@gmail.com Change-Id: Ic29cd9051c7eac4822d620c299834134f987f01b --- M chipdrivers.h M flashchips.c M flashchips.h M spi.h M spi25.c 5 files changed, 102 insertions(+), 7 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/96/34496/1
diff --git a/chipdrivers.h b/chipdrivers.h index e380878..0b4435c 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -34,6 +34,7 @@ int probe_spi_res1(struct flashctx *flash); int probe_spi_res2(struct flashctx *flash); int probe_spi_res3(struct flashctx *flash); +int probe_spi_st95(struct flashctx *flash); int probe_spi_at25f(struct flashctx *flash); int spi_write_enable(struct flashctx *flash); int spi_write_disable(struct flashctx *flash); @@ -51,6 +52,7 @@ int spi_block_erase_d8(struct flashctx *flash, unsigned int addr, unsigned int blocklen); int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int blocklen); int spi_block_erase_dc(struct flashctx *flash, unsigned int addr, unsigned int blocklen); +int spi_block_erase_emulation(struct flashctx *flash, unsigned int addr, unsigned int blocklen); erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode); int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len); int spi_nbyte_read(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len); diff --git a/flashchips.c b/flashchips.c index 166af6a..44875c6 100644 --- a/flashchips.c +++ b/flashchips.c @@ -14104,6 +14104,33 @@ },
{ + .vendor = "ST", + .name = "M95M02", + .bustype = BUS_SPI, + .manufacture_id = ST_ID, + .model_id = ST_M95M02, + .total_size = 256, + .page_size = 256, + .feature_bits = FEATURE_WRSR_WREN, + .tested = TEST_OK_PREW, + .probe = probe_spi_st95, + .probe_timing = TIMING_ZERO, + .block_erasers = + { + { + .eraseblocks = { { 256 * 1024, 1 } }, + .block_erase = spi_block_erase_emulation, + } + }, + + .printlock = spi_prettyprint_status_register_bp1_srwd, + .unlock = spi_disable_blockprotect_bp1_srwd, + .write = spi_chip_write_256, + .read = spi_chip_read, + .voltage = {2500, 5500}, + }, + + { .vendor = "Sanyo", .name = "LE25FU106B", .bustype = BUS_SPI, diff --git a/flashchips.h b/flashchips.h index 006b95e..d1eed91 100644 --- a/flashchips.h +++ b/flashchips.h @@ -851,6 +851,12 @@ #define ST_M58WR032KT 0x8814 #define ST_M58WR064KB 0x8811 #define ST_M58WR064KT 0x8810 + +/* 00h ST Manufacturer code ST_ID*/ +/* 01h SPI Family code 0x00*/ +/* 02h Memory Density code ST_M95XXX */ +#define ST_M95M02 0x0012 /* ST M95XXX 2Mbit (256KiB) */ + #define ST_MT28GU01G___1 0x88B0 #define ST_MT28GU01G___2 0x88B1 #define ST_MT28GU256___1 0x8901 diff --git a/spi.h b/spi.h index 0073c71..9f199f3 100644 --- a/spi.h +++ b/spi.h @@ -28,6 +28,12 @@ /* INSIZE may be 0x04 for some chips*/ #define JEDEC_RDID_INSIZE 0x03
+/* Some ST M95X model */ +#define ST_M95_RDID 0x83 +#define ST_M95_RDID_OUTSIZE 0x04 /* 8b op, 24bit addr where size >64KiB */ +#define ST_M95_RDID_INSIZE 0x03 + + /* Some Atmel AT25F* models have bit 3 as don't care bit in commands */ #define AT25F_RDID 0x15 /* 0x15 or 0x1d */ #define AT25F_RDID_OUTSIZE 0x01 diff --git a/spi25.c b/spi25.c index 2a1d492..ec35585 100644 --- a/spi25.c +++ b/spi25.c @@ -21,6 +21,7 @@ #include <stddef.h> #include <string.h> #include <stdbool.h> +#include <stdlib.h> #include "flash.h" #include "flashchips.h" #include "chipdrivers.h" @@ -262,6 +263,32 @@ return 1; }
+/* Only used for some stm95080 and higher chip. */ +int probe_spi_st95(struct flashctx *flash) +{ + /* ST_M95_RDID_OUTSIZE depends on size of the flash and + * not all ST_M95XXX have RDID + */ + static const unsigned char cmd[ST_M95_RDID_OUTSIZE] = {ST_M95_RDID}; + unsigned char readarr[ST_M95_RDID_INSIZE]; + uint32_t id1, id2; + + spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr); + + id1 = readarr[0]; // manufacture id + id2 = readarr[2]; // model id + + msg_ginfo("RDID[%s: id1 0x%02x, id2 0x%02x, " + "L 0x%02x, M 0x%02x, H 0x%02x]\n", + __func__, flash->chip->manufacture_id, flash->chip->model_id, + readarr[0], readarr[1], readarr[2]); + + if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id) + return 1; + + return 0; +} + /* Only used for some Atmel chips. */ int probe_spi_at25f(struct flashctx *flash) { @@ -440,6 +467,13 @@ return result ? result : status; }
+static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len) +{ + const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_WRITE && spi_master_4ba(flash); + const uint8_t op = native_4ba ? JEDEC_BYTE_PROGRAM_4BA : JEDEC_BYTE_PROGRAM; + return spi_write_cmd(flash, op, native_4ba, addr, bytes, len, 10); +} + static int spi_chip_erase_60(struct flashctx *flash) { /* This usually takes 1-85s, so wait in 1s steps. */ @@ -577,6 +611,33 @@ return spi_write_cmd(flash, 0xdc, true, addr, NULL, 0, 100 * 1000); }
+/* some chips don't have erase function */ +int spi_block_erase_emulation(struct flashctx *flash, unsigned int addr, unsigned int blocklen) +{ + unsigned int i; + const unsigned int erase_len = flash->chip->page_size; + uint8_t *erased_contents = NULL; + int result = 0; + + erased_contents = (uint8_t*) malloc(erase_len * sizeof(uint8_t)); + if (!erased_contents) { + msg_cerr("Out of memory!\n"); + return 1; + } + + memset(erased_contents, ERASED_VALUE(flash), erase_len * sizeof(uint8_t)); + msg_cinfo("\n"); + for (i = addr; i < blocklen; i+=erase_len) { + if (spi_nbyte_program(flash, i, erased_contents, erase_len)) { + result = 1; + break; + } + } + + free(erased_contents); + return result; +} + erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode) { switch(opcode){ @@ -619,13 +680,6 @@ } }
-static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len) -{ - const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_WRITE && spi_master_4ba(flash); - const uint8_t op = native_4ba ? JEDEC_BYTE_PROGRAM_4BA : JEDEC_BYTE_PROGRAM; - return spi_write_cmd(flash, op, native_4ba, addr, bytes, len, 10); -} - int spi_nbyte_read(struct flashctx *flash, unsigned int address, uint8_t *bytes, unsigned int len) {