When working with a lot of different flash chips it's sometimes useful to be able to print and update the status register directly as a separate operation.
Add --print-status and --write-status command line options to that maps to spi_read_status_register and spi_write_status_register.
The print operation reads the status register and prints it content to the user. While the write operation takes a parameter as a hex value (0x00 to 0xff) or a decimal value (0 to 255) and tries to write it to the status register.
This operation is limited to flash chips that have a SPI bustype.
Signed-off-by: Niklas Söderlund niklas.soderlund@ericsson.com --- cli_classic.c | 37 ++++++++++++++++++++++++++++++++----- flash.h | 2 +- flashrom.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 7 deletions(-)
diff --git a/cli_classic.c b/cli_classic.c index 972043b..87af1f3 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -144,11 +144,17 @@ static void cli_classic_usage(const char *name) "device\n");
list_programmers_linebreak(37, 80, 1); + + printf("\nAdvance options (use at your own risk)\n" + " -P | --print-status print status register\n" + " -W | --write-status <value> write <value> to status " + "register\n"); + printf("\nYou can specify one of -h, -R, -L, " #if CONFIG_PRINT_WIKI == 1 "-z, " #endif - "-E, -r, -w, -v or no operation.\n" + "-E, -r, -w, -v -P, -W or no operation.\n" "If no operation is specified, flashrom will only probe for " "flash chips.\n\n"); } @@ -173,15 +179,18 @@ int main(int argc, char *argv[]) int list_supported_wiki = 0; #endif int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0; + int statusreg_op = 0; int dont_verify_it = 0, list_supported = 0, operation_specified = 0; enum programmer prog = PROGRAMMER_INVALID; int ret = 0;
- static const char optstring[] = "r:Rw:v:nVEfc:l:i:p:Lzh"; + static const char optstring[] = "r:Rw:v:nVEfc:l:i:p:LzhPW:"; static const struct option long_options[] = { {"read", 1, NULL, 'r'}, {"write", 1, NULL, 'w'}, {"erase", 0, NULL, 'E'}, + {"print-status", 0, NULL, 'P'}, + {"write-status", 1, NULL, 'W'}, {"verify", 1, NULL, 'v'}, {"noverify", 0, NULL, 'n'}, {"chip", 1, NULL, 'c'}, @@ -201,6 +210,7 @@ int main(int argc, char *argv[]) char *layoutfile = NULL; char *tempstr = NULL; char *pparam = NULL; + char *statusreg_value = NULL;
print_version(); print_banner(); @@ -270,6 +280,23 @@ int main(int argc, char *argv[]) } erase_it = 1; break; + case 'P': + if (++operation_specified > 1) { + fprintf(stderr, "More than one operation " + "specified. Aborting.\n"); + cli_classic_abort_usage(); + } + statusreg_op = 1; + break; + case 'W': + if (++operation_specified > 1) { + fprintf(stderr, "More than one operation " + "specified. Aborting.\n"); + cli_classic_abort_usage(); + } + statusreg_op = 1; + statusreg_value = strdup(optarg); + break; case 'f': force = 1; break; @@ -511,12 +538,12 @@ int main(int argc, char *argv[]) goto out_shutdown; }
- if (!(read_it | write_it | verify_it | erase_it)) { + if (!(read_it | write_it | verify_it | erase_it | statusreg_op)) { printf("No operations were specified.\n"); goto out_shutdown; }
- if (!filename && !erase_it) { + if (!filename && !erase_it && !statusreg_op) { printf("Error: No filename specified.\n"); ret = 1; goto out_shutdown; @@ -531,7 +558,7 @@ int main(int argc, char *argv[]) * Give the chip time to settle. */ programmer_delay(100000); - return doit(fill_flash, force, filename, read_it, write_it, erase_it, verify_it); + return doit(fill_flash, force, filename, read_it, write_it, erase_it, verify_it, statusreg_op, statusreg_value);
out_shutdown: programmer_shutdown(); diff --git a/flash.h b/flash.h index 0dac13d..65ee0af 100644 --- a/flash.h +++ b/flash.h @@ -247,7 +247,7 @@ void print_version(void); void print_banner(void); void list_programmers_linebreak(int startcol, int cols, int paren); int selfcheck(void); -int doit(struct flashctx *flash, int force, const char *filename, int read_it, int write_it, int erase_it, int verify_it); +int doit(struct flashctx *flash, int force, const char *filename, int read_it, int write_it, int erase_it, int verify_it, int statureg_op, const char *statusreg_op); int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filename); int write_buf_to_file(unsigned char *buf, unsigned long size, const char *filename);
diff --git a/flashrom.c b/flashrom.c index cad043b..b3ba376 100644 --- a/flashrom.c +++ b/flashrom.c @@ -31,12 +31,14 @@ #include <stdlib.h> #include <ctype.h> #include <getopt.h> +#include <errno.h> #if HAVE_UTSNAME == 1 #include <sys/utsname.h> #endif #include "flash.h" #include "flashchips.h" #include "programmer.h" +#include "chipdrivers.h"
const char flashrom_version[] = FLASHROM_VERSION; char *chip_to_probe = NULL; @@ -1396,6 +1398,45 @@ int erase_and_write_flash(struct flashctx *flash, uint8_t *oldcontents, return ret; }
+int operate_on_statusregister(struct flashctx *flash, const char* value) { + long status; + char *endptr; + + if (flash->bustype != BUS_SPI) { + msg_cerr("Flash is not on SPI bus. Can't operate on status register\n"); + return 1; + } + + if (value) { + /* Try to parse as hex then dec */ + errno = 0; + status = strtol(value, &endptr, 0); + if (endptr == value || *endptr != '\0' || errno != 0) { + msg_cerr("Error parsing value %s for status register\n", + value); + return 1; + } + + if (status < 0 || status > 0xFF) { + msg_cerr("Invalid status register value: %s\n", value); + return 1; + } + + if (spi_write_status_register(flash, status)) { + msg_cerr("spi_write_status_register failed\n"); + return 1; + } + + msg_cinfo("Wrote 0x%02lx to status register\n", status); + } + + /* Read and print current value */ + status = spi_read_status_register(flash); + msg_cinfo("Status register: 0x%02lx\n", status); + + return 0; +} + void nonfatal_help_message(void) { msg_gerr("Writing to the flash chip apparently didn't do anything.\n" @@ -1705,7 +1746,8 @@ int chip_safety_check(struct flashctx *flash, int force, int read_it, * Besides that, the function itself is a textbook example of abysmal code flow. */ int doit(struct flashctx *flash, int force, const char *filename, int read_it, - int write_it, int erase_it, int verify_it) + int write_it, int erase_it, int verify_it, + int statusreg_op, const char *statusreg_value) { uint8_t *oldcontents; uint8_t *newcontents; @@ -1718,6 +1760,11 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, goto out_nofree; }
+ if (statusreg_op) { + ret = operate_on_statusregister(flash, statusreg_value); + goto out_nofree; + } + /* Given the existence of read locks, we want to unlock for read, * erase and write. */