aboutsummaryrefslogtreecommitdiff
path: root/src/drivers/spi/spi_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/spi/spi_flash.c')
-rw-r--r--src/drivers/spi/spi_flash.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c
index 5e42a375f6..a81306e386 100644
--- a/src/drivers/spi/spi_flash.c
+++ b/src/drivers/spi/spi_flash.c
@@ -59,6 +59,34 @@ static int do_spi_flash_cmd(const struct spi_slave *spi, const void *dout,
return ret;
}
+static int do_dual_read_cmd(const struct spi_slave *spi, const void *dout,
+ size_t bytes_out, void *din, size_t bytes_in)
+{
+ int ret;
+
+ /*
+ * spi_xfer_vector() will automatically fall back to .xfer() if
+ * .xfer_vector() is unimplemented. So using vector API here is more
+ * flexible, even though a controller that implements .xfer_vector()
+ * and (the non-vector based) .xfer_dual() but not .xfer() would be
+ * pretty odd.
+ */
+ struct spi_op vector = { .dout = dout, .bytesout = bytes_out,
+ .din = NULL, .bytesin = 0 };
+
+ ret = spi_claim_bus(spi);
+ if (ret)
+ return ret;
+
+ ret = spi_xfer_vector(spi, &vector, 1);
+
+ if (!ret)
+ ret = spi->ctrlr->xfer_dual(spi, NULL, 0, din, bytes_in);
+
+ spi_release_bus(spi);
+ return ret;
+}
+
int spi_flash_cmd(const struct spi_slave *spi, u8 cmd, void *response, size_t len)
{
int ret = do_spi_flash_cmd(spi, &cmd, sizeof(cmd), response, len);
@@ -105,6 +133,11 @@ static int spi_flash_read_chunked(const struct spi_flash *flash, u32 offset,
cmd_len = 4;
cmd[0] = CMD_READ_ARRAY_SLOW;
do_cmd = do_spi_flash_cmd;
+ } else if (flash->flags.dual_spi && flash->spi.ctrlr->xfer_dual) {
+ cmd_len = 5;
+ cmd[0] = CMD_READ_FAST_DUAL_OUTPUT;
+ cmd[4] = 0;
+ do_cmd = do_dual_read_cmd;
} else {
cmd_len = 5;
cmd[0] = CMD_READ_ARRAY_FAST;
@@ -347,8 +380,12 @@ int spi_flash_probe(unsigned int bus, unsigned int cs, struct spi_flash *flash)
return -1;
}
- printk(BIOS_INFO, "SF: Detected %s with sector size 0x%x, total 0x%x\n",
- flash->name, flash->sector_size, flash->size);
+ const char *mode_string = "";
+ if (flash->flags.dual_spi && spi.ctrlr->xfer_dual)
+ mode_string = " (Dual SPI mode)";
+ printk(BIOS_INFO,
+ "SF: Detected %s with sector size 0x%x, total 0x%x%s\n",
+ flash->name, flash->sector_size, flash->size, mode_string);
if (bus == CONFIG_BOOT_DEVICE_SPI_FLASH_BUS
&& flash->size != CONFIG_ROM_SIZE) {
printk(BIOS_ERR, "SF size 0x%x does not correspond to"