Sergii Dmytruk has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/59708 )
Change subject: [RFC][OTP] dummyflasher: add EN25QH128 chip with OTP mode ......................................................................
[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: