sf: spi_flash: use dma to copy data from mmap region if platform supports
[oweals/u-boot.git] / drivers / mtd / spi / spi_flash.c
index 59e91ec071982b4b8c870cd45852b70b0aeebe7f..3c365d5e9ad8f94b11fd96388dbf934c58e7f5a6 100644 (file)
@@ -16,6 +16,7 @@
 #include <spi.h>
 #include <spi_flash.h>
 #include <linux/log2.h>
+#include <dma.h>
 
 #include "sf_internal.h"
 
@@ -29,16 +30,6 @@ static void spi_flash_addr(u32 addr, u8 *cmd)
        cmd[3] = addr >> 0;
 }
 
-/* Read commands array */
-static u8 spi_read_cmds_array[] = {
-       CMD_READ_ARRAY_SLOW,
-       CMD_READ_ARRAY_FAST,
-       CMD_READ_DUAL_OUTPUT_FAST,
-       CMD_READ_DUAL_IO_FAST,
-       CMD_READ_QUAD_OUTPUT_FAST,
-       CMD_READ_QUAD_IO_FAST,
-};
-
 static int read_sr(struct spi_flash *flash, u8 *rs)
 {
        int ret;
@@ -121,6 +112,37 @@ static int write_cr(struct spi_flash *flash, u8 wc)
 }
 #endif
 
+#ifdef CONFIG_SPI_FLASH_STMICRO
+static int read_evcr(struct spi_flash *flash, u8 *evcr)
+{
+       int ret;
+       const u8 cmd = CMD_READ_EVCR;
+
+       ret = spi_flash_read_common(flash, &cmd, 1, evcr, 1);
+       if (ret < 0) {
+               debug("SF: error reading EVCR\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int write_evcr(struct spi_flash *flash, u8 evcr)
+{
+       u8 cmd;
+       int ret;
+
+       cmd = CMD_WRITE_EVCR;
+       ret = spi_flash_write_common(flash, &cmd, 1, &evcr, 1);
+       if (ret < 0) {
+               debug("SF: error while writing EVCR register\n");
+               return ret;
+       }
+
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_SPI_FLASH_BAR
 static int spi_flash_write_bar(struct spi_flash *flash, u32 offset)
 {
@@ -149,7 +171,7 @@ static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0)
        int ret;
 
        if (flash->size <= SPI_FLASH_16MB_BOUN)
-               goto bank_end;
+               goto bar_end;
 
        switch (idcode0) {
        case SPI_FLASH_CFI_MFR_SPANSION:
@@ -168,7 +190,7 @@ static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0)
                return ret;
        }
 
-bank_end:
+bar_end:
        flash->bank_curr = curr_bank;
        return 0;
 }
@@ -433,8 +455,16 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
        return ret;
 }
 
+/*
+ * TODO: remove the weak after all the other spi_flash_copy_mmap
+ * implementations removed from drivers
+ */
 void __weak spi_flash_copy_mmap(void *data, void *offset, size_t len)
 {
+#ifdef CONFIG_DMA
+       if (!dma_memcpy(data, offset, len))
+               return;
+#endif
        memcpy(data, offset, len);
 }
 
@@ -810,7 +840,7 @@ int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len)
 
 
 #ifdef CONFIG_SPI_FLASH_MACRONIX
-static int spi_flash_set_qeb_mxic(struct spi_flash *flash)
+static int macronix_quad_enable(struct spi_flash *flash)
 {
        u8 qeb_status;
        int ret;
@@ -819,12 +849,18 @@ static int spi_flash_set_qeb_mxic(struct spi_flash *flash)
        if (ret < 0)
                return ret;
 
-       if (qeb_status & STATUS_QEB_MXIC) {
-               debug("SF: mxic: QEB is already set\n");
-       } else {
-               ret = write_sr(flash, STATUS_QEB_MXIC);
-               if (ret < 0)
-                       return ret;
+       if (qeb_status & STATUS_QEB_MXIC)
+               return 0;
+
+       ret = write_sr(flash, qeb_status | STATUS_QEB_MXIC);
+       if (ret < 0)
+               return ret;
+
+       /* read SR and check it */
+       ret = read_sr(flash, &qeb_status);
+       if (!(ret >= 0 && (qeb_status & STATUS_QEB_MXIC))) {
+               printf("SF: Macronix SR Quad bit not clear\n");
+               return -EINVAL;
        }
 
        return ret;
@@ -832,7 +868,7 @@ static int spi_flash_set_qeb_mxic(struct spi_flash *flash)
 #endif
 
 #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
-static int spi_flash_set_qeb_winspan(struct spi_flash *flash)
+static int spansion_quad_enable(struct spi_flash *flash)
 {
        u8 qeb_status;
        int ret;
@@ -841,34 +877,67 @@ static int spi_flash_set_qeb_winspan(struct spi_flash *flash)
        if (ret < 0)
                return ret;
 
-       if (qeb_status & STATUS_QEB_WINSPAN) {
-               debug("SF: winspan: QEB is already set\n");
-       } else {
-               ret = write_cr(flash, STATUS_QEB_WINSPAN);
-               if (ret < 0)
-                       return ret;
+       if (qeb_status & STATUS_QEB_WINSPAN)
+               return 0;
+
+       ret = write_cr(flash, qeb_status | STATUS_QEB_WINSPAN);
+       if (ret < 0)
+               return ret;
+
+       /* read CR and check it */
+       ret = read_cr(flash, &qeb_status);
+       if (!(ret >= 0 && (qeb_status & STATUS_QEB_WINSPAN))) {
+               printf("SF: Spansion CR Quad bit not clear\n");
+               return -EINVAL;
        }
 
        return ret;
 }
 #endif
 
-static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0)
+#ifdef CONFIG_SPI_FLASH_STMICRO
+static int micron_quad_enable(struct spi_flash *flash)
+{
+       u8 qeb_status;
+       int ret;
+
+       ret = read_evcr(flash, &qeb_status);
+       if (ret < 0)
+               return ret;
+
+       if (!(qeb_status & STATUS_QEB_MICRON))
+               return 0;
+
+       ret = write_evcr(flash, qeb_status & ~STATUS_QEB_MICRON);
+       if (ret < 0)
+               return ret;
+
+       /* read EVCR and check it */
+       ret = read_evcr(flash, &qeb_status);
+       if (!(ret >= 0 && !(qeb_status & STATUS_QEB_MICRON))) {
+               printf("SF: Micron EVCR Quad bit not clear\n");
+               return -EINVAL;
+       }
+
+       return ret;
+}
+#endif
+
+static int set_quad_mode(struct spi_flash *flash, u8 idcode0)
 {
        switch (idcode0) {
 #ifdef CONFIG_SPI_FLASH_MACRONIX
        case SPI_FLASH_CFI_MFR_MACRONIX:
-               return spi_flash_set_qeb_mxic(flash);
+               return macronix_quad_enable(flash);
 #endif
 #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
        case SPI_FLASH_CFI_MFR_SPANSION:
        case SPI_FLASH_CFI_MFR_WINBOND:
-               return spi_flash_set_qeb_winspan(flash);
+               return spansion_quad_enable(flash);
 #endif
 #ifdef CONFIG_SPI_FLASH_STMICRO
        case SPI_FLASH_CFI_MFR_STMICRO:
-               debug("SF: QEB is volatile for %02x flash\n", idcode0);
-               return 0;
+               return micron_quad_enable(flash);
 #endif
        default:
                printf("SF: Need set QEB func for %02x flash\n", idcode0);
@@ -879,14 +948,10 @@ static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0)
 #if CONFIG_IS_ENABLED(OF_CONTROL)
 int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
 {
+#ifdef CONFIG_DM_SPI_FLASH
        fdt_addr_t addr;
        fdt_size_t size;
-       int node;
-
-       /* If there is no node, do nothing */
-       node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
-       if (node < 0)
-               return 0;
+       int node = flash->dev->of_offset;
 
        addr = fdtdec_get_addr_size(blob, node, "memory-map", &size);
        if (addr == FDT_ADDR_T_NONE) {
@@ -899,6 +964,7 @@ int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
                return -1;
        }
        flash->memory_map = map_sysmem(addr, size);
+#endif
 
        return 0;
 }
@@ -909,9 +975,15 @@ int spi_flash_scan(struct spi_flash *flash)
        struct spi_slave *spi = flash->spi;
        const struct spi_flash_params *params;
        u16 jedec, ext_jedec;
-       u8 idcode[5];
-       u8 cmd;
+       u8 cmd, idcode[5];
        int ret;
+       static u8 spi_read_cmds_array[] = {
+               CMD_READ_ARRAY_SLOW,
+               CMD_READ_ARRAY_FAST,
+               CMD_READ_DUAL_OUTPUT_FAST,
+               CMD_READ_QUAD_OUTPUT_FAST,
+               CMD_READ_DUAL_IO_FAST,
+               CMD_READ_QUAD_IO_FAST };
 
        /* Read the ID codes */
        ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
@@ -968,7 +1040,7 @@ int spi_flash_scan(struct spi_flash *flash)
        flash->write = spi_flash_cmd_write_ops;
 #if defined(CONFIG_SPI_FLASH_SST)
        if (flash->flags & SNOR_F_SST_WR) {
-               if (spi->mode & SPI_TX_BP)
+               if (spi->mode & SPI_TX_BYTE)
                        flash->write = sst_write_bp;
                else
                        flash->write = sst_write_wp;
@@ -1032,7 +1104,7 @@ int spi_flash_scan(struct spi_flash *flash)
        flash->sector_size = flash->erase_size;
 
        /* Look for the fastest read cmd */
-       cmd = fls(params->e_rd_cmd & spi->op_mode_rx);
+       cmd = fls(params->e_rd_cmd & spi->mode_rx);
        if (cmd) {
                cmd = spi_read_cmds_array[cmd - 1];
                flash->read_cmd = cmd;
@@ -1042,7 +1114,7 @@ int spi_flash_scan(struct spi_flash *flash)
        }
 
        /* Not require to look for fastest only two write cmds yet */
-       if (params->flags & WR_QPP && spi->mode & SPI_TX_QPP)
+       if (params->flags & WR_QPP && spi->mode & SPI_TX_QUAD)
                flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
        else
                /* Go for default supported write cmd */
@@ -1052,7 +1124,7 @@ int spi_flash_scan(struct spi_flash *flash)
        if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
            (flash->read_cmd == CMD_READ_QUAD_IO_FAST) ||
            (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
-               ret = spi_flash_set_qeb(flash, idcode[0]);
+               ret = set_quad_mode(flash, idcode[0]);
                if (ret) {
                        debug("SF: Fail to set QEB for %02x\n", idcode[0]);
                        return -EINVAL;