Konstantin Grudnev has uploaded this change for review.

View Change

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)
{

To view, visit change 34496. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: Ic29cd9051c7eac4822d620c299834134f987f01b
Gerrit-Change-Number: 34496
Gerrit-PatchSet: 1
Gerrit-Owner: Konstantin Grudnev <grudnevkv@gmail.com>
Gerrit-MessageType: newchange