spi25_statusreg: inline spi_write_register_flag()
Creating the entire SPI command that should be sent to the chip in
spi_write_register() is simpler than splitting it across two functions
that have to pass multiple parameters between them.
Additionally, having separate spi_write_register_flag() function
provided little benefit, as it was only ever called from
spi_write_register().
Tested: flashrom -{r,w,E}
Tested: Tested with a W25Q128.W flash on a kasumi (AMD) dut.
Read SR1/SR2 with --wp-status and activated various WP ranges
that toggled bits in both SR1 and SR2.
Change-Id: I4996b0848d0ed09032bad2ab13ab1f40bbfc0304
Signed-off-by: Nikolai Artemiev <nartemiev@google.com>
Original-Reviewed-on: https://review.coreboot.org/c/flashrom/+/59528
Original-Reviewed-by: Anastasia Klimchuk <aklm@chromium.org>
Original-Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
Reviewed-on: https://review.coreboot.org/c/flashrom-stable/+/70974
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/spi25_statusreg.c b/spi25_statusreg.c
index 31d6c76..249ab9a 100644
--- a/spi25_statusreg.c
+++ b/spi25_statusreg.c
@@ -22,68 +22,6 @@
#include "spi.h"
/* === Generic functions === */
-static int spi_write_register_flag(const struct flashctx *flash, uint8_t enable_opcode, uint8_t *write_cmd, size_t write_cmd_len, enum flash_reg reg)
-{
- /*
- * Enabling register writes requires either EWSR or WREN depending on
- * chip type. The code below relies on the fact hat EWSR and WREN have
- * the same INSIZE and OUTSIZE.
- */
-
- struct spi_command cmds[] = {
- {
- .writecnt = JEDEC_WREN_OUTSIZE,
- .writearr = &enable_opcode,
- .readcnt = 0,
- .readarr = NULL,
- }, {
- .writecnt = write_cmd_len,
- .writearr = write_cmd,
- .readcnt = 0,
- .readarr = NULL,
- }, {
- .writecnt = 0,
- .writearr = NULL,
- .readcnt = 0,
- .readarr = NULL,
- }};
-
- int result = spi_send_multicommand(flash, cmds);
- if (result) {
- msg_cerr("%s failed during command execution\n", __func__);
- /*
- * No point in waiting for the command to complete if execution
- * failed.
- */
- return result;
- }
-
- /*
- * WRSR performs a self-timed erase before the changes take effect.
- * This may take 50-85 ms in most cases, and some chips apparently
- * allow running RDSR only once. Therefore pick an initial delay of
- * 100 ms, then wait in 10 ms steps until a total of 5 s have elapsed.
- *
- * Newer chips with multiple status registers (SR2 etc.) are unlikely
- * to have problems with multiple RDSR commands, so only wait for the
- * initial 100 ms if the register we wrote to was SR1.
- */
- int delay_ms = 5000;
- if (reg == STATUS1) {
- programmer_delay(100 * 1000);
- delay_ms -= 100;
- }
-
- for (; delay_ms > 0; delay_ms -= 10) {
- if ((spi_read_status_register(flash) & SPI_SR_WIP) == 0)
- return 0;
- programmer_delay(10 * 1000);
- }
-
- msg_cerr("Error: WIP bit after WRSR never cleared\n");
- return TIMEOUT_ERROR;
-}
-
int spi_write_register(const struct flashctx *flash, enum flash_reg reg, uint8_t value)
{
int feature_bits = flash->chip->feature_bits;
@@ -133,18 +71,66 @@
return 1;
}
- if (!(feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
+ uint8_t enable_cmd;
+ if (feature_bits & FEATURE_WRSR_WREN) {
+ enable_cmd = JEDEC_WREN;
+ } else if (feature_bits & FEATURE_WRSR_EWSR) {
+ enable_cmd = JEDEC_EWSR;
+ } else {
msg_cdbg("Missing status register write definition, assuming "
"EWSR is needed\n");
- feature_bits |= FEATURE_WRSR_EWSR;
+ enable_cmd = JEDEC_EWSR;
}
- int ret = 1;
- if (feature_bits & FEATURE_WRSR_WREN)
- ret = spi_write_register_flag(flash, JEDEC_WREN, write_cmd, write_cmd_len, reg);
- if (ret && (feature_bits & FEATURE_WRSR_EWSR))
- ret = spi_write_register_flag(flash, JEDEC_EWSR, write_cmd, write_cmd_len, reg);
- return ret;
+ struct spi_command cmds[] = {
+ {
+ .writecnt = JEDEC_WREN_OUTSIZE,
+ .writearr = &enable_cmd,
+ .readcnt = 0,
+ .readarr = NULL,
+ }, {
+ .writecnt = write_cmd_len,
+ .writearr = write_cmd,
+ .readcnt = 0,
+ .readarr = NULL,
+ }, {
+ .writecnt = 0,
+ .writearr = NULL,
+ .readcnt = 0,
+ .readarr = NULL,
+ }};
+
+ int result = spi_send_multicommand(flash, cmds);
+ if (result) {
+ msg_cerr("%s failed during command execution\n", __func__);
+ return result;
+ }
+
+ /*
+ * WRSR performs a self-timed erase before the changes take effect.
+ * This may take 50-85 ms in most cases, and some chips apparently
+ * allow running RDSR only once. Therefore pick an initial delay of
+ * 100 ms, then wait in 10 ms steps until a total of 5 s have elapsed.
+ *
+ * Newer chips with multiple status registers (SR2 etc.) are unlikely
+ * to have problems with multiple RDSR commands, so only wait for the
+ * initial 100 ms if the register we wrote to was SR1.
+ */
+ int delay_ms = 5000;
+ if (reg == STATUS1) {
+ programmer_delay(100 * 1000);
+ delay_ms -= 100;
+ }
+
+ for (; delay_ms > 0; delay_ms -= 10) {
+ if ((spi_read_status_register(flash) & SPI_SR_WIP) == 0)
+ return 0;
+ programmer_delay(10 * 1000);
+ }
+
+
+ msg_cerr("Error: WIP bit after WRSR never cleared\n");
+ return TIMEOUT_ERROR;
}
int spi_read_register(const struct flashctx *flash, enum flash_reg reg, uint8_t *value)