Sergii Dmytruk has uploaded this change for review.

View Change

[RFC][OTP] dummyflasher: add EN25QH128 chip with OTP mode

This chip demonstrates seecond kind of OTP: mode upon entering which
regular read/write/erase commands can be used to interact with OTP
content. It will also be used in tests.

Change-Id: Id5857db43ebf2613bdb5e99342d28d4e0981a6b8
Signed-off-by: Hatim Kanchwala <hatim at hatimak.me>
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
---
M dummyflasher.c
M flashrom.8.tmpl
2 files changed, 98 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/flashrom refs/changes/08/59708/1
diff --git a/dummyflasher.c b/dummyflasher.c
index 0aa10f3..e758075 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -14,6 +14,7 @@
* GNU General Public License for more details.
*/

+#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -36,6 +37,7 @@
EMULATE_MACRONIX_MX25L6436, /* SR1 */
EMULATE_WINBOND_W25Q128FV, /* SR1-2, OTP (sec. regs) */
EMULATE_VARIABLE_SIZE, /* SR1 */
+ EMULATE_EON_EN25QH128, /* SR1, OTP (mode) */
};

struct emu_data {
@@ -70,6 +72,10 @@
unsigned int spi_write_256_chunksize;
uint8_t *flashchip_contents;

+ /* For chips with OTP mode. */
+ bool otp_mode; /* in OTP mode */
+ bool otp_locked; /* OTP region is locked (there is only one) */
+
/* For all chips with OTP. */
uint8_t otp_region_count;
uint16_t otp_region_size; /* this assumes regions of equal size */
@@ -275,6 +281,24 @@
return 0;
}

+/* Checks if received offset is valid and that kind of requested operation is
+ * allowed in current state. Returns zero if everything is fine. */
+static int validate_otp_sector_op(struct emu_data *data, unsigned int offs, bool read_op)
+{
+ assert(data->emu_chip == EMULATE_EON_EN25QH128);
+
+ if (!read_op && data->otp_locked) {
+ msg_perr("OTP is locked, cannot change contents of OTP sector anymore\n");
+ return 1;
+ }
+ if ((offs & 0xfff) >= 0x200 && (offs >> 12) != 0xfff) {
+ msg_perr("OTP address out of range: 0x%jx\n", (uintmax_t)offs);
+ return 1;
+ }
+
+ return 0;
+}
+
static int emulate_spi_chip_response(unsigned int writecnt,
unsigned int readcnt,
const unsigned char *writearr,
@@ -289,6 +313,7 @@
const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a};
const unsigned char mx25l6436_rems_response[2] = {0xc2, 0x16};
const unsigned char w25q128fv_rems_response[2] = {0xef, 0x17};
+ const unsigned char en25qh128_rems_response[2] = {0x1c, 0x17};

if (writecnt == 0) {
msg_perr("No command sent to the chip!\n");
@@ -351,6 +376,10 @@
if (readcnt > 0)
memset(readarr, 0x17, readcnt);
break;
+ case EMULATE_EON_EN25QH128:
+ if (readcnt > 0)
+ memset(readarr, 0x17, readcnt);
+ break;
default: /* ignore */
break;
}
@@ -378,6 +407,10 @@
for (i = 0; i < readcnt; i++)
readarr[i] = w25q128fv_rems_response[(offs + i) % 2];
break;
+ case EMULATE_EON_EN25QH128:
+ for (i = 0; i < readcnt; i++)
+ readarr[i] = en25qh128_rems_response[(offs + i) % 2];
+ break;
default: /* ignore */
break;
}
@@ -418,11 +451,23 @@
if (readcnt > 3)
readarr[3] = PROGDEV_ID & 0xff;
break;
+ case EMULATE_EON_EN25QH128:
+ if (readcnt > 0)
+ readarr[0] = 0x1c;
+ if (readcnt > 1)
+ readarr[1] = 0x70;
+ if (readcnt > 2)
+ readarr[2] = 0x18;
+ break;
default: /* ignore */
break;
}
break;
case JEDEC_RDSR:
+ if (data->emu_chip == EMULATE_EON_EN25QH128 && data->otp_mode) {
+ memset(readarr, (data->emu_status & 0x7F) | (data->otp_locked << 7), readcnt);
+ break;
+ }
memset(readarr, data->emu_status, readcnt);
break;
case JEDEC_RDSR2:
@@ -440,6 +485,12 @@
break;
}

+ if (data->emu_chip == EMULATE_EON_EN25QH128 && data->otp_mode) {
+ data->otp_locked = true;
+ msg_pdbg("OTP bit set...\n");
+ break;
+ }
+
/* FIXME: add some reasonable simulation of the busy flag */
ro_bits = get_status_ro_bits(data, 1);
data->emu_status &= ro_bits;
@@ -474,6 +525,12 @@
break;
case JEDEC_READ:
offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ if (data->otp_mode) {
+ if (validate_otp_sector_op(data, offs, true))
+ break;
+ memcpy(readarr, data->otp_region[0] + (offs & 0xfff), readcnt);
+ break;
+ }
/* Truncate to emu_chip_size. */
offs %= data->emu_chip_size;
if (readcnt > 0)
@@ -488,6 +545,12 @@
break;
case JEDEC_BYTE_PROGRAM:
offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ if (data->otp_mode) {
+ if (validate_otp_sector_op(data, offs, false))
+ break;
+ memcpy(data->otp_region[0] + (offs & 0xfff), writearr + 4, writecnt - 4);
+ break;
+ }
/* Truncate to emu_chip_size. */
offs %= data->emu_chip_size;
if (writecnt < 5) {
@@ -565,6 +628,10 @@
case JEDEC_WRDI:
if (data->emu_max_aai_size)
data->emu_status &= ~SPI_SR_AAI;
+ if (data->emu_chip == EMULATE_EON_EN25QH128) {
+ data->otp_mode = false;
+ msg_pdbg("Left OTP mode...\n");
+ }
break;
case JEDEC_SE:
if (!data->emu_jedec_se_size)
@@ -578,6 +645,12 @@
return 1;
}
offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
+ if (data->otp_mode) {
+ if (validate_otp_sector_op(data, offs, false))
+ break;
+ memset(data->otp_region[0], 0xff, data->otp_region_size);
+ break;
+ }
if (offs & (data->emu_jedec_se_size - 1))
msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
offs &= ~(data->emu_jedec_se_size - 1);
@@ -773,6 +846,12 @@
memset(data->otp_region[region], 0xff, data->otp_region_size);
}
break;
+ case JEDEC_ENTER_OTP: /* enter OTP for Eon chips */
+ if (data->emu_chip != EMULATE_EON_EN25QH128)
+ break;
+ data->otp_mode = true;
+ msg_pdbg("Entered OTP mode...\n");
+ break;
default:
/* No special response. */
break;
@@ -809,6 +888,7 @@
case EMULATE_MACRONIX_MX25L6436:
case EMULATE_WINBOND_W25Q128FV:
case EMULATE_VARIABLE_SIZE:
+ case EMULATE_EON_EN25QH128:
if (emulate_spi_chip_response(writecnt, readcnt, writearr,
readarr, emu_data)) {
msg_pdbg("Invalid command sent to flash chip!\n");
@@ -1156,6 +1236,22 @@
msg_pdbg("Emulating Winbond W25Q128FV SPI flash chip (RDID, "
"OTP)\n");
}
+ if (!strcmp(tmp, "EN25QH128")) {
+ data->emu_chip = EMULATE_EON_EN25QH128;
+ data->emu_chip_size = 16 * 1024 * 1024;
+ data->emu_max_byteprogram_size = 256;
+ data->emu_max_aai_size = 0;
+ data->emu_status_len = 1;
+ data->emu_jedec_se_size = 4 * 1024;
+ data->emu_jedec_be_52_size = 32 * 1024;
+ data->emu_jedec_be_d8_size = 64 * 1024;
+ data->emu_jedec_ce_60_size = data->emu_chip_size;
+ data->emu_jedec_ce_c7_size = data->emu_chip_size;
+ data->otp_region_count = 1;
+ data->otp_region_size = 512;
+ msg_pdbg("Emulating Eon EN25QH128 SPI flash chip (RDID, "
+ "OTP)\n");
+ }

/* The name of variable-size virtual chip. A 4 MiB flash example:
* flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
index 3d9692f..7c77960 100644
--- a/flashrom.8.tmpl
+++ b/flashrom.8.tmpl
@@ -695,6 +695,8 @@
.sp
.RB "* Winbond " W25Q128FV " SPI flash chip (16384 kB, RDID, OTP)"
.sp
+.RB "* Eon " EN25QH128 " SPI flash chip (16384 kB, RDID, OTP)"
+.sp
.RB "* Dummy vendor " VARIABLE_SIZE " SPI flash chip (configurable size, page write)"
.sp
Example:

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

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: Id5857db43ebf2613bdb5e99342d28d4e0981a6b8
Gerrit-Change-Number: 59708
Gerrit-PatchSet: 1
Gerrit-Owner: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
Gerrit-MessageType: newchange