From: Ravikumar Kattekola <r...@ti.com> Some flash like S25fl256s supports quad read mode also. This patch enables the quad read support based on CONFIG_SF_QUAD_RD config.
Enabling quad read has the following components: 1. Enable the Quad mode bit in the flash device side. 2. Add a quad read mode read api. I have created a new api for quad mode as some flash has few more quad read command that can be supported. As of now, I have addded only QUAD OUTPUT READ command. 3. spi driver need to know that the read to be done is the quad read. Communicate this to the driver through a "SPI_QUAD" flag. This need to be done because quad read should only happen when quad command is sent. For reading status register and other configuration register normal transfers should happen. Signed-off-by: Ravikumar Kattekola <r...@ti.com> Signed-off-by: Sourav Poddar <sourav.pod...@ti.com> --- drivers/mtd/spi/spi_flash.c | 109 +++++++++++++++++++++++++++++++++- drivers/mtd/spi/spi_flash_internal.h | 2 + include/spi.h | 2 + 3 files changed, 112 insertions(+), 1 deletions(-) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 5d5055f..993a9d4 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -42,8 +42,13 @@ static int spi_flash_read_write(struct spi_slave *spi, debug("SF: Failed to send command (%zu bytes): %d\n", cmd_len, ret); } else if (data_len != 0) { + if (spi->quad_enable) + flags = SPI_QUAD; + else + flags = 0; + ret = spi_xfer(spi, data_len * 8, data_out, data_in, - SPI_XFER_END); + flags | SPI_XFER_END); if (ret) debug("SF: Failed to transfer %zu bytes of data: %d\n", data_len, ret); @@ -272,6 +277,58 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, return ret; } +int spi_flash_cmd_read_quad(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[5], bank_sel = 0; + u32 remain_len, read_len; + int ret = -1; + + /* Handle memory-mapped SPI */ + if (flash->memory_map) { + memcpy(data, flash->memory_map + offset, len); + return 0; + } + + spi->quad_enable = true; + cmd[0] = CMD_READ_ARRAY_QUAD; + cmd[4] = 0x00; + + while (len) { +#ifdef CONFIG_SPI_FLASH_BAR + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + + remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); + if (len < remain_len) + read_len = len; + else + read_len = remain_len; + + spi_flash_addr(offset, cmd); + + ret = spi_flash_read_common(flash, cmd, sizeof(cmd), + data, read_len); + if (ret < 0) { + debug("SF: read failed\n"); + break; + } + + offset += read_len; + len -= read_len; + data += read_len; + } + + return ret; +} + int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *data) { @@ -395,6 +452,48 @@ int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) } #endif +int spi_flash_en_quad_mode(struct spi_flash *flash) +{ + u8 stat, con, cd; + u16 cr; + int ret; + cd = CMD_WRITE_STATUS; + + ret = spi_flash_cmd_write_enable(flash); + if (ret < 0) { + debug("SF: enabling write failed\n"); + goto out; + } + ret = spi_flash_cmd(flash->spi, CMD_READ_STATUS, &stat, 1); + ret = spi_flash_cmd(flash->spi, CMD_READ_CONFIG, &con, 1); + if (ret < 0) { + debug("%s: SF: read CR failed\n", __func__); + goto out; + } + /* Byte 1 - status reg, Byte 2 - config reg */ + cr = ((con | (0x1 << 1)) << 8) | (stat << 0); + + ret = spi_flash_cmd_write(flash->spi, &cd, 1, &cr, 2); + if (ret) { + debug("SF: fail to write conf register\n"); + goto out; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret < 0) { + debug("SF: write conf register timed out\n"); + goto out; + } + + ret = spi_flash_cmd_write_disable(flash); + if (ret < 0) { + debug("SF: disabling write failed\n"); + goto out; + } +out: + return ret; +} + #ifdef CONFIG_OF_CONTROL int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) { @@ -549,6 +648,10 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, goto err_manufacturer_probe; #endif +#ifdef CONFIG_SF_QUAD_RD + spi_flash_en_quad_mode(flash); +#endif + #ifdef CONFIG_OF_CONTROL if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { debug("SF: FDT decode error\n"); @@ -601,7 +704,11 @@ void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, flash->name = name; flash->poll_cmd = CMD_READ_STATUS; +#ifdef CONFIG_SF_QUAD_RD + flash->read = spi_flash_cmd_read_quad; +#else flash->read = spi_flash_cmd_read_fast; +#endif flash->write = spi_flash_cmd_write_multi; flash->erase = spi_flash_cmd_erase; diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index af1afa9..b388837 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -17,11 +17,13 @@ #define CMD_READ_ARRAY_SLOW 0x03 #define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ARRAY_QUAD 0x6b #define CMD_WRITE_STATUS 0x01 #define CMD_PAGE_PROGRAM 0x02 #define CMD_WRITE_DISABLE 0x04 #define CMD_READ_STATUS 0x05 +#define CMD_READ_CONFIG 0x35 #define CMD_FLAG_STATUS 0x70 #define CMD_WRITE_ENABLE 0x06 #define CMD_ERASE_4K 0x20 diff --git a/include/spi.h b/include/spi.h index c0dab57..9d4b2dc 100644 --- a/include/spi.h +++ b/include/spi.h @@ -27,6 +27,7 @@ /* SPI transfer flags */ #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ +#define SPI_QUAD 0x04 /* Use QUAD read command */ /* Header byte that marks the start of the message */ #define SPI_PREAMBLE_END_BYTE 0xec @@ -45,6 +46,7 @@ struct spi_slave { unsigned int bus; unsigned int cs; unsigned int max_write_size; + bool quad_enable; }; /*----------------------------------------------------------------------- -- 1.7.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot