- New infrastructure is used to read status register (for chips that have support for struct status_register) throughout spi25.c. - New infrastructure is used to prettyprint status register and write protection mode of status register (for chips that have support for struct status_register) in flashrom.c. - New disable from access protection infrastructure is used (for chips that have support for struct wp) in flashrom.c
Signed-off-by: Hatim Kanchwala hatim@hatimak.me --- flashrom.c | 17 +++++-- spi25.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 145 insertions(+), 36 deletions(-)
diff --git a/flashrom.c b/flashrom.c index 25e53f2..3e19cd6 100644 --- a/flashrom.c +++ b/flashrom.c @@ -26,26 +26,27 @@ #ifndef __LIBPAYLOAD__ #include <fcntl.h> #include <sys/stat.h> #endif #include <string.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <ctype.h> #include <getopt.h> #if HAVE_UTSNAME == 1 #include <sys/utsname.h> #endif +#include "chipdrivers.h" #include "flash.h" #include "flashchips.h" #include "programmer.h" #include "hwaccess.h"
const char flashrom_version[] = FLASHROM_VERSION; const char *chip_to_probe = NULL;
static enum programmer programmer = PROGRAMMER_INVALID; static const char *programmer_param = NULL;
/* * Programmers supporting multiple buses can have differing size limits on @@ -1250,29 +1251,37 @@ notfound: msg_cinfo("%s %s flash chip "%s" (%d kB, %s) ", force ? "Assuming" : "Found", flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp); free(tmp); #if CONFIG_INTERNAL == 1 if (programmer_table[programmer].map_flash_region == physmap) msg_cinfo("mapped at physical address 0x%0*" PRIxPTR ".\n", PRIxPTR_WIDTH, flash->physical_memory); else #endif msg_cinfo("on %s.\n", programmer_table[programmer].name);
/* Flash registers may more likely not be mapped if the chip was forced. * Lock info may be stored in registers, so avoid lock info printing. */ - if (!force) - if (flash->chip->printlock) + if (!force) { + if (flash->chip->status_register) { + for (enum status_register_num SRn = SR1; SRn <= top_status_register(flash); SRn++) + flash->chip->status_register->print(flash, SRn); + flash->chip->status_register->print_wp_mode(flash); + if (flash->chip->wp) + print_range_generic(flash); + } else if (flash->chip->printlock) { flash->chip->printlock(flash); + } + }
/* Get out of the way for later runs. */ unmap_flash(flash);
/* Return position of matching chip. */ return chip - flashchips; }
int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filename) { #ifdef __LIBPAYLOAD__ msg_gerr("Error: No file I/O support in libpayload\n"); @@ -1988,27 +1997,29 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, if (chip_safety_check(flash, force, read_it, write_it, erase_it, verify_it)) { msg_cerr("Aborting.\n"); return 1; }
if (normalize_romentries(flash)) { msg_cerr("Requested regions can not be handled. Aborting.\n"); return 1; }
/* Given the existence of read locks, we want to unlock for read, * erase and write. */ - if (flash->chip->unlock) + if (flash->chip->wp) + flash->chip->wp->disable(flash); + else if (flash->chip->unlock) flash->chip->unlock(flash);
if (read_it) { return read_flash_to_file(flash, filename); }
oldcontents = malloc(size); if (!oldcontents) { msg_gerr("Out of memory!\n"); exit(1); } /* Assume worst case: All bits are 0. */ memset(oldcontents, 0x00, size); diff --git a/spi25.c b/spi25.c index af4b6db..51db4c8 100644 --- a/spi25.c +++ b/spi25.c @@ -341,29 +341,35 @@ int spi_chip_erase_60(struct flashctx *flash) .readcnt = 0, .readarr = NULL, }}; result = spi_send_multicommand(flash, cmds); if (result) { msg_cerr("%s failed during command execution\n", __func__); return result; } /* Wait until the Write-In-Progress bit is cleared. * This usually takes 1-85 s, so wait in 1 s steps. */ - /* FIXME: We assume spi_read_status_register will never fail. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(1000 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(1000 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(1000 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
int spi_chip_erase_62(struct flashctx *flash) { int result; struct spi_command cmds[] = { { .writecnt = JEDEC_WREN_OUTSIZE, .writearr = (const unsigned char[]){ JEDEC_WREN }, .readcnt = 0, .readarr = NULL, @@ -378,29 +384,35 @@ int spi_chip_erase_62(struct flashctx *flash) .readcnt = 0, .readarr = NULL, }}; result = spi_send_multicommand(flash, cmds); if (result) { msg_cerr("%s failed during command execution\n", __func__); return result; } /* Wait until the Write-In-Progress bit is cleared. * This usually takes 2-5 s, so wait in 100 ms steps. */ - /* FIXME: We assume spi_read_status_register will never fail. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(100 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(100 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(100 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
int spi_chip_erase_c7(struct flashctx *flash) { int result; struct spi_command cmds[] = { { .writecnt = JEDEC_WREN_OUTSIZE, .writearr = (const unsigned char[]){ JEDEC_WREN }, .readcnt = 0, .readarr = NULL, @@ -414,29 +426,35 @@ int spi_chip_erase_c7(struct flashctx *flash) .writearr = NULL, .readcnt = 0, .readarr = NULL, }};
result = spi_send_multicommand(flash, cmds); if (result) { msg_cerr("%s failed during command execution\n", __func__); return result; } /* Wait until the Write-In-Progress bit is cleared. * This usually takes 1-85 s, so wait in 1 s steps. */ - /* FIXME: We assume spi_read_status_register will never fail. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(1000 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(1000 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(1000 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
int spi_block_erase_52(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, @@ -457,28 +475,35 @@ int spi_block_erase_52(struct flashctx *flash, unsigned int addr, .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 100-4000 ms, so wait in 100 ms steps. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(100 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(100 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(100 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
/* 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, @@ -500,28 +525,35 @@ int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int b .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: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(500 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(500 * 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 */ int spi_block_erase_d8(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { int result; @@ -547,28 +579,35 @@ int spi_block_erase_d8(struct flashctx *flash, unsigned int addr, .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 100-4000 ms, so wait in 100 ms steps. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(100 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(100 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(100 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
/* Block size is usually * 4k for PMC */ int spi_block_erase_d7(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { int result; struct spi_command cmds[] = { { @@ -592,28 +631,35 @@ int spi_block_erase_d7(struct flashctx *flash, unsigned int addr, .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 100-4000 ms, so wait in 100 ms steps. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(100 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(100 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(100 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
/* Page erase (usually 256B blocks) */ int spi_block_erase_db(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, @@ -633,28 +679,35 @@ int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int b .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 takes up to 20 ms usually (on worn out devices up to the 0.5s range), so wait in 1 ms steps. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(1 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(1 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(1 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
/* Sector size is usually 4k, though Macronix eliteflash has 64k */ int spi_block_erase_20(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 }, @@ -676,28 +729,35 @@ int spi_block_erase_20(struct flashctx *flash, unsigned int addr, .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 15-800 ms, so wait in 10 ms steps. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(10 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(10 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
int spi_block_erase_50(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, @@ -716,28 +776,35 @@ int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int b .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 10 ms, so wait in 1 ms steps. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(1 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(1 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(1 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
int spi_block_erase_81(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, @@ -756,28 +823,35 @@ int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int b .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 8 ms, so wait in 1 ms steps. */ - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(1 * 1000); + /* FIXME: We assume reading status register(s) will never fail. */ + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(1 * 1000); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(1 * 1000); + } /* FIXME: Check the status register for errors. */ return 0; }
int spi_block_erase_60(struct flashctx *flash, unsigned int addr, unsigned int blocklen) { if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) { msg_cerr("%s called with incorrect arguments\n", __func__); return -1; } return spi_chip_erase_60(flash); @@ -1004,54 +1078,66 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s * page as well, the loop condition uses <=. */ for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { /* Byte position of the first byte in the range in this page. */ /* starthere is an offset to the base address of the chip. */ starthere = max(start, i * page_size); /* Length of bytes in the range in this page. */ lenhere = min(start + len, (i + 1) * page_size) - starthere; for (j = 0; j < lenhere; j += chunksize) { towrite = min(chunksize, lenhere - j); rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite); if (rc) break; - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(10); + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(10); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10); + } } if (rc) break; }
return rc; }
/* * Program chip using byte programming. (SLOW!) * This is for chips which can only handle one byte writes * and for chips where memory mapped programming is impossible * (e.g. due to size constraints in IT87* for over 512 kB) */ /* real chunksize is 1, logical chunksize is 1 */ int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len) { unsigned int i; int result = 0;
for (i = start; i < start + len; i++) { result = spi_byte_program(flash, i, buf[i - start]); if (result) return 1; - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(10); + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(10); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10); + } }
return 0; }
int default_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len) { uint32_t pos = start; int result; unsigned char cmd[JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE] = { JEDEC_AAI_WORD_PROGRAM, }; struct spi_command cmds[] = { @@ -1120,43 +1206,55 @@ int default_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned i if (len % 2) { msg_cerr("%s: total write length not even! Please report a " "bug at flashrom@flashrom.org\n", __func__); /* Do not return an error for now. */ //return SPI_GENERIC_ERROR; }
result = spi_send_multicommand(flash, cmds); if (result != 0) { msg_cerr("%s failed during start command execution: %d\n", __func__, result); goto bailout; } - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(10); + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(10); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10); + }
/* We already wrote 2 bytes in the multicommand step. */ pos += 2;
/* Are there at least two more bytes to write? */ while (pos < start + len - 1) { cmd[1] = buf[pos++ - start]; cmd[2] = buf[pos++ - start]; result = spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL); if (result != 0) { msg_cerr("%s failed during followup AAI command execution: %d\n", __func__, result); goto bailout; } - while (spi_read_status_register(flash) & SPI_SR_WIP) - programmer_delay(10); + // TODO(hatim): Switch to newer infrastructure completely after integration + if (flash->chip->status_register) { + while (flash->chip->status_register->read(flash, SR1) & SPI_SR_WIP) + programmer_delay(10); + } else { + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10); + } }
/* Use WRDI to exit AAI mode. This needs to be done before issuing any other non-AAI command. */ result = spi_write_disable(flash); if (result != 0) { msg_cerr("%s failed to disable AAI mode.\n", __func__); return SPI_GENERIC_ERROR; }
/* Write remaining byte (if any). */ if (pos < start + len) { if (spi_chip_write_1(flash, buf + pos - start, pos, pos % 2)) return SPI_GENERIC_ERROR;