diff options
Diffstat (limited to 'src/drivers/spi/spi_flash.c')
-rw-r--r-- | src/drivers/spi/spi_flash.c | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c index b674749feb..f3cecd5fc6 100644 --- a/src/drivers/spi/spi_flash.c +++ b/src/drivers/spi/spi_flash.c @@ -20,7 +20,7 @@ static void spi_flash_addr(u32 addr, u8 *cmd) cmd[3] = addr >> 0; } -static int do_spi_flash_cmd(const struct spi_slave *spi, const void *dout, +static int do_spi_flash_cmd(const struct spi_slave *spi, const u8 *dout, size_t bytes_out, void *din, size_t bytes_in) { int ret; @@ -51,8 +51,8 @@ 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) +static int do_dual_output_cmd(const struct spi_slave *spi, const u8 *dout, + size_t bytes_out, void *din, size_t bytes_in) { int ret; @@ -79,6 +79,31 @@ static int do_dual_read_cmd(const struct spi_slave *spi, const void *dout, return ret; } +static int do_dual_io_cmd(const struct spi_slave *spi, const u8 *dout, + size_t bytes_out, void *din, size_t bytes_in) +{ + int ret; + + /* Only the very first byte (opcode) is transferred in "single" mode. */ + struct spi_op vector = { .dout = dout, .bytesout = 1, + .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, &dout[1], bytes_out - 1, NULL, 0); + + 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); @@ -119,18 +144,23 @@ int spi_flash_cmd_read(const struct spi_flash *flash, u32 offset, { u8 cmd[5]; int ret, cmd_len; - int (*do_cmd)(const struct spi_slave *spi, const void *din, + int (*do_cmd)(const struct spi_slave *spi, const u8 *din, size_t in_bytes, void *out, size_t out_bytes); if (CONFIG(SPI_FLASH_NO_FAST_READ)) { 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) { + } else if (flash->flags.dual_io && flash->spi.ctrlr->xfer_dual) { + cmd_len = 5; + cmd[0] = CMD_READ_FAST_DUAL_IO; + cmd[4] = 0; + do_cmd = do_dual_io_cmd; + } else if (flash->flags.dual_output && flash->spi.ctrlr->xfer_dual) { cmd_len = 5; cmd[0] = CMD_READ_FAST_DUAL_OUTPUT; cmd[4] = 0; - do_cmd = do_dual_read_cmd; + do_cmd = do_dual_output_cmd; } else { cmd_len = 5; cmd[0] = CMD_READ_ARRAY_FAST; @@ -352,7 +382,8 @@ static int fill_spi_flash(const struct spi_slave *spi, struct spi_flash *flash, flash->pp_cmd = vi->desc->pp_cmd; flash->wren_cmd = vi->desc->wren_cmd; - flash->flags.dual_spi = part->fast_read_dual_output_support; + flash->flags.dual_output = part->fast_read_dual_output_support; + flash->flags.dual_io = part->fast_read_dual_io_support; flash->ops = &vi->desc->ops; flash->prot_ops = vi->prot_ops; @@ -471,8 +502,10 @@ int spi_flash_probe(unsigned int bus, unsigned int cs, struct spi_flash *flash) } const char *mode_string = ""; - if (flash->flags.dual_spi && spi.ctrlr->xfer_dual) - mode_string = " (Dual SPI mode)"; + if (flash->flags.dual_io && spi.ctrlr->xfer_dual) + mode_string = " (Dual I/O mode)"; + else if (flash->flags.dual_output && spi.ctrlr->xfer_dual) + mode_string = " (Dual Output mode)"; printk(BIOS_INFO, "SF: Detected %02x %04x with sector size 0x%x, total 0x%x%s\n", flash->vendor, flash->model, flash->sector_size, flash->size, mode_string); |