aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNico Huber <nico.h@gmx.de>2017-10-14 17:47:28 +0200
committerNico Huber <nico.h@gmx.de>2017-12-28 10:44:17 +0000
commitf43c654ad0dcb11b2738bbfac9246d09bb1949e5 (patch)
tree1d1f74d771dc2e8e8a67dab985945c00f68e0097
parent0ecbacbfca7f919f1780f5062c775d94c7869d81 (diff)
downloadflashrom-f43c654ad0dcb11b2738bbfac9246d09bb1949e5.tar.gz
flashrom-f43c654ad0dcb11b2738bbfac9246d09bb1949e5.tar.bz2
flashrom-f43c654ad0dcb11b2738bbfac9246d09bb1949e5.zip
spi25: Integrate 4BA support
Allow 4-byte addresses for instructions usually used with 3-byte addresses. Decide in which way the 4th byte will be communicated based on the state of the chip (i.e. have we enabled 4BA mode) and a new feature bit for an extended address register. If we are not in 4BA mode and no extended address register is available or the write to it fails, bail out. We cache the state of 4BA mode and the extended address register in the flashctx. Change-Id: I644600beaab9a571b97b67f7516abe571d3460c1 Signed-off-by: Nico Huber <nico.h@gmx.de> Reviewed-on: https://review.coreboot.org/22384 Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-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 b18d698d..5cb7040e 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 12d73901..8849f639 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 84de75e2..6940394c 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 a44e0674..902f0730 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 8a017924..a0316bc7 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__ */