summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--flash.h8
-rw-r--r--flashrom.c3
-rw-r--r--spi25.c33
-rw-r--r--spi4ba.c21
-rw-r--r--spi4ba.h1
5 files changed, 57 insertions, 9 deletions
diff --git a/flash.h b/flash.h
index b18d698d8..5cb7040e9 100644
--- a/flash.h
+++ b/flash.h
@@ -120,6 +120,8 @@ enum write_granularity {
#define FEATURE_OTP (1 << 8)
#define FEATURE_QPI (1 << 9)
#define FEATURE_4BA_SUPPORT (1 << 10)
+#define FEATURE_4BA_EXT_ADDR (1 << 11) /**< Regular 3-byte operations can be used by writing the most
+ significant address byte into an extended address register. */
enum test_state {
OK = 0,
@@ -236,6 +238,12 @@ struct flashrom_flashctx {
bool verify_after_write;
bool verify_whole_chip;
} flags;
+ /* We cache the state of the extended address register (highest byte
+ of a 4BA for 3BA instructions) and the state of the 4BA mode here.
+ If possible, we enter 4BA mode early. If that fails, we make use
+ of the extended address register. */
+ int address_high_byte;
+ bool in_4ba_mode;
};
/* Timing used in probe routines. ZERO is -2 to differentiate between an unset
diff --git a/flashrom.c b/flashrom.c
index 12d739014..8849f6396 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -2215,6 +2215,9 @@ int prepare_flash_access(struct flashctx *const flash,
if (flash->chip->unlock)
flash->chip->unlock(flash);
+ flash->address_high_byte = -1;
+ flash->in_4ba_mode = false;
+
/* Enable/disable 4-byte addressing mode if flash chip supports it */
if ((flash->chip->feature_bits & FEATURE_4BA_SUPPORT) &&
flash->chip->four_bytes_addr_funcs.set_4ba) {
diff --git a/spi25.c b/spi25.c
index 84de75e2f..6940394c7 100644
--- a/spi25.c
+++ b/spi25.c
@@ -363,14 +363,37 @@ static int spi_simple_write_cmd(struct flashctx *const flash, const uint8_t op,
return result ? result : status;
}
+static int spi_set_extended_address(struct flashctx *const flash, const uint8_t addr_high)
+{
+ if (flash->address_high_byte != addr_high &&
+ spi_write_extended_address_register(flash, addr_high))
+ return -1;
+ flash->address_high_byte = addr_high;
+ return 0;
+}
+
static int spi_prepare_address(struct flashctx *const flash,
uint8_t cmd_buf[], const unsigned int addr)
{
- /* TODO: extend for 4BA */
- cmd_buf[1] = (addr >> 16) & 0xff;
- cmd_buf[2] = (addr >> 8) & 0xff;
- cmd_buf[3] = (addr >> 0) & 0xff;
- return 3;
+ if (flash->in_4ba_mode) {
+ cmd_buf[1] = (addr >> 24) & 0xff;
+ cmd_buf[2] = (addr >> 16) & 0xff;
+ cmd_buf[3] = (addr >> 8) & 0xff;
+ cmd_buf[4] = (addr >> 0) & 0xff;
+ return 4;
+ } else {
+ if (flash->chip->feature_bits & FEATURE_4BA_EXT_ADDR) {
+ if (spi_set_extended_address(flash, addr >> 24))
+ return -1;
+ } else {
+ if (addr >> 24)
+ return -1;
+ }
+ cmd_buf[1] = (addr >> 16) & 0xff;
+ cmd_buf[2] = (addr >> 8) & 0xff;
+ cmd_buf[3] = (addr >> 0) & 0xff;
+ return 3;
+ }
}
/**
diff --git a/spi4ba.c b/spi4ba.c
index a44e0674d..902f07309 100644
--- a/spi4ba.c
+++ b/spi4ba.c
@@ -39,12 +39,17 @@
/* Enter 4-bytes addressing mode (without sending WREN before) */
int spi_enter_4ba_b7(struct flashctx *flash)
{
+ int result;
const unsigned char cmd[JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE] = { JEDEC_ENTER_4_BYTE_ADDR_MODE };
msg_trace("-> %s\n", __func__);
/* Switch to 4-bytes addressing mode */
- return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
+ result = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
+ if (!result)
+ flash->in_4ba_mode = true;
+
+ return result;
}
/* Enter 4-bytes addressing mode with sending WREN before */
@@ -75,18 +80,25 @@ int spi_enter_4ba_b7_we(struct flashctx *flash)
result = spi_send_multicommand(flash, cmds);
if (result)
msg_cerr("%s failed during command execution\n", __func__);
+ else
+ flash->in_4ba_mode = true;
return result;
}
/* Exit 4-bytes addressing mode (without sending WREN before) */
int spi_exit_4ba_e9(struct flashctx *flash)
{
+ int result;
const unsigned char cmd[JEDEC_EXIT_4_BYTE_ADDR_MODE_OUTSIZE] = { JEDEC_EXIT_4_BYTE_ADDR_MODE };
msg_trace("-> %s\n", __func__);
/* Switch to 3-bytes addressing mode */
- return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
+ result = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
+ if (!result)
+ flash->in_4ba_mode = false;
+
+ return result;
}
/* Exit 4-bytes addressing mode with sending WREN before */
@@ -115,9 +127,10 @@ int spi_exit_4ba_e9_we(struct flashctx *flash)
/* Switch to 3-bytes addressing mode */
result = spi_send_multicommand(flash, cmds);
- if (result) {
+ if (result)
msg_cerr("%s failed during command execution\n", __func__);
- }
+ else
+ flash->in_4ba_mode = false;
return result;
}
diff --git a/spi4ba.h b/spi4ba.h
index 8a0179243..a0316bc7c 100644
--- a/spi4ba.h
+++ b/spi4ba.h
@@ -114,5 +114,6 @@ int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr, uns
int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_write_extended_address_register(struct flashctx *flash, uint8_t regdata);
#endif /* __SPI_4BA_H__ */