@@ -42,7 +42,12 @@ 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) {
- ret = spi_xfer(spi, data_len * 8, data_out, data_in, SPI_XFER_END);
+ if (spi->quad_enable)
+ flags = SPI_6WIRE;
+ else
+ flags = 0;
+
+ ret = spi_xfer(spi, data_len * 8, data_out, data_in, flags | SPI_XFER_END);
if (ret)
debug("SF: Failed to transfer %zu bytes of data: %d\n",
data_len, ret);
@@ -198,6 +203,51 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
#endif
}
+int spi_flash_cmd_read_quad(struct spi_flash *flash, u32 offset,
+ size_t len, void *data)
+{
+ struct spi_slave *spi = flash->spi;
+
+ unsigned long page_addr, byte_addr, page_size;
+ size_t chunk_len, actual;
+ int ret = 0;
+ u8 cmd[5];
+
+ spi->quad_enable = 1;
+ /* Handle memory-mapped SPI */
+ if (flash->memory_map)
+ memcpy(data, flash->memory_map + offset, len);
+
+ page_size = flash->page_size;
+ page_addr = offset / page_size;
+ byte_addr = offset % page_size;
+
+ cmd[0] = CMD_READ_ARRAY_QUAD;
+ for (actual = 0; actual < len; actual += chunk_len) {
+ chunk_len = min(len - actual, page_size - byte_addr);
+
+ cmd[1] = page_addr >> 8;
+ cmd[2] = page_addr;
+ cmd[3] = byte_addr;
+ cmd[4] = 0x0;
+
+ ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
+ data + actual, chunk_len);
+ if (ret < 0) {
+ debug("SF: read failed");
+ break;
+ }
+
+ byte_addr += chunk_len;
+ if (byte_addr == page_size) {
+ page_addr++;
+ byte_addr = 0;
+ }
+ }
+
+ return ret;
+}
+
int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout,
u8 cmd, u8 poll_bit)
{
@@ -320,6 +370,56 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)
return 0;
}
+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(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;
+ }
+ debug("%s: *** CR = %x\n", __func__, con);
+
+ 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)
{
@@ -464,6 +564,10 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
goto err_manufacturer_probe;
}
+#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");
@@ -507,7 +611,11 @@ void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi,
flash->spi = spi;
flash->name = name;
+#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;
@@ -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_WRITE_ENABLE 0x06
#define CMD_ERASE_4K 0x20
#define CMD_ERASE_32K 0x52
@@ -72,6 +72,7 @@ static struct qspi_regs *qspi = (struct qspi_regs *)QSPI_BASE;
#define QSPI_RD_SNGL (1 << 16)
#define QSPI_WR_SNGL (2 << 16)
#define QSPI_INVAL (4 << 16)
+#define QSPI_RD_QUAD (7 << 16)
/* Device Control */
#define QSPI_DD(m, n) (m << (3 + n*8))
@@ -235,10 +236,17 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
debug("tx done, status %08x\n", status);
}
if (rxp) {
- debug("rx cmd %08x dc %08x\n",
- qslave->cmd | QSPI_RD_SNGL, qslave->dc);
- writel(qslave->dc, &qspi->spi_dc);
- writel(qslave->cmd | QSPI_RD_SNGL, &qspi->spi_cmd);
+ if (flags & SPI_6WIRE) {
+ debug("rx cmd %08x dc %08x\n",
+ qslave->cmd | QSPI_RD_QUAD, qslave->dc);
+ writel(qslave->cmd | QSPI_RD_QUAD,
+ &qspi->spi_cmd);
+ } else {
+ debug("rx cmd %08x dc %08x\n",
+ qslave->cmd | QSPI_RD_SNGL, qslave->dc);
+ writel(qslave->cmd | QSPI_RD_SNGL,
+ &qspi->spi_cmd);
+ }
status = readl(&qspi->spi_status);
timeout = QSPI_TIMEOUT;
while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) {
@@ -250,7 +258,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
}
*rxp++ = readl(&qspi->spi_data);
debug("rx done, status %08x, read %02x\n",
- status, *(rxp-1));
+ status, *(rxp-1));
}
}
@@ -57,6 +57,7 @@
#define CONFIG_SPI_FLASH_SPANSION
#define CONFIG_CMD_SF
#define CONFIG_CMD_SPI
+#define CONFIG_SF_QUAD_RD
#define CONFIG_SF_DEFAULT_SPEED 12000000
#define CONFIG_DEFAULT_SPI_MODE SPI_MODE_3
@@ -37,6 +37,7 @@
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
#define SPI_3WIRE 0x10 /* SI/SO signals shared */
#define SPI_LOOP 0x20 /* loopback mode */
+#define SPI_6WIRE 0x10 /* SI/SO signals shared */
/* SPI transfer flags */
#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */
@@ -56,6 +57,7 @@ struct spi_slave {
unsigned int bus;
unsigned int cs;
unsigned int max_write_size;
+ bool quad_enable;
};
/*-----------------------------------------------------------------------