configs: Migrate CONFIG_SYS_MAX_FLASH_BANKS to Kconfig
[platform/kernel/u-boot.git] / drivers / mtd / spi / spi-nor-core.c
index 99e2f16..a70fbda 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <common.h>
+#include <flash.h>
 #include <log.h>
 #include <watchdog.h>
 #include <dm.h>
@@ -26,6 +27,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/spi-nor.h>
+#include <mtd/cfi_flash.h>
 #include <spi-mem.h>
 #include <spi.h>
 
@@ -906,30 +908,40 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
 static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
        struct spi_nor *nor = mtd_to_spi_nor(mtd);
+       bool addr_known = false;
        u32 addr, len, rem;
-       int ret;
+       int ret, err;
 
        dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
                (long long)instr->len);
 
-       if (!instr->len)
-               return 0;
-
        div_u64_rem(instr->len, mtd->erasesize, &rem);
-       if (rem)
-               return -EINVAL;
+       if (rem) {
+               ret = -EINVAL;
+               goto err;
+       }
 
        addr = instr->addr;
        len = instr->len;
 
+       instr->state = MTD_ERASING;
+       addr_known = true;
+
        while (len) {
                WATCHDOG_RESET();
+               if (ctrlc()) {
+                       addr_known = false;
+                       ret = -EINTR;
+                       goto erase_err;
+               }
 #ifdef CONFIG_SPI_FLASH_BAR
                ret = write_bar(nor, addr);
                if (ret < 0)
-                       return ret;
+                       goto erase_err;
 #endif
-               write_enable(nor);
+               ret = write_enable(nor);
+               if (ret < 0)
+                       goto erase_err;
 
                ret = spi_nor_erase_sector(nor, addr);
                if (ret < 0)
@@ -943,11 +955,24 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
                        goto erase_err;
        }
 
+       addr_known = false;
 erase_err:
 #ifdef CONFIG_SPI_FLASH_BAR
-       ret = clean_bar(nor);
+       err = clean_bar(nor);
+       if (!ret)
+               ret = err;
 #endif
-       write_disable(nor);
+       err = write_disable(nor);
+       if (!ret)
+               ret = err;
+
+err:
+       if (ret) {
+               instr->fail_addr = addr_known ? addr : MTD_FAIL_ADDR_UNKNOWN;
+               instr->state = MTD_ERASE_FAILED;
+       } else {
+               instr->state = MTD_ERASE_DONE;
+       }
 
        return ret;
 }
@@ -1663,9 +1688,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 
        dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
 
-       if (!len)
-               return 0;
-
        for (i = 0; i < len; ) {
                ssize_t written;
                loff_t addr = to + i;
@@ -2604,18 +2626,28 @@ static int spi_nor_init_params(struct spi_nor *nor,
        params->size = info->sector_size * info->n_sectors;
        params->page_size = info->page_size;
 
+       if (!(info->flags & SPI_NOR_NO_FR)) {
+               /* Default to Fast Read for DT and non-DT platform devices. */
+               params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
+
+               /* Mask out Fast Read if not requested at DT instantiation. */
+#if CONFIG_IS_ENABLED(DM_SPI)
+               if (!ofnode_read_bool(dev_ofnode(nor->spi->dev),
+                                     "m25p,fast-read"))
+                       params->hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
+#endif
+       }
+
        /* (Fast) Read settings. */
        params->hwcaps.mask |= SNOR_HWCAPS_READ;
        spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ],
                                  0, 0, SPINOR_OP_READ,
                                  SNOR_PROTO_1_1_1);
 
-       if (!(info->flags & SPI_NOR_NO_FR)) {
-               params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
+       if (params->hwcaps.mask & SNOR_HWCAPS_READ_FAST)
                spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_FAST],
                                          0, 8, SPINOR_OP_READ_FAST,
                                          SNOR_PROTO_1_1_1);
-       }
 
        if (info->flags & SPI_NOR_DUAL_READ) {
                params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
@@ -2858,10 +2890,11 @@ spi_nor_adjust_hwcaps(struct spi_nor *nor,
        unsigned int cap;
 
        /*
-        * Enable all caps by default. We will mask them after checking what's
-        * really supported using spi_mem_supports_op().
+        * Start by assuming the controller supports every capability.
+        * We will mask them after checking what's really supported
+        * using spi_mem_supports_op().
         */
-       *hwcaps = SNOR_HWCAPS_ALL;
+       *hwcaps = SNOR_HWCAPS_ALL & params->hwcaps.mask;
 
        /* X-X-X modes are not supported yet, mask them all. */
        *hwcaps &= ~SNOR_HWCAPS_X_X_X;
@@ -3211,6 +3244,21 @@ static struct spi_nor_fixups s25hx_t_fixups = {
        .post_bfpt = s25hx_t_post_bfpt_fixup,
        .post_sfdp = s25hx_t_post_sfdp_fixup,
 };
+
+static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info,
+                          const struct spi_nor_flash_parameter *params)
+{
+       return -ENOTSUPP; /* Bank Address Register is not supported */
+}
+
+static void s25fl256l_default_init(struct spi_nor *nor)
+{
+       nor->setup = s25fl256l_setup;
+}
+
+static struct spi_nor_fixups s25fl256l_fixups = {
+       .default_init = s25fl256l_default_init,
+};
 #endif
 
 #ifdef CONFIG_SPI_FLASH_S28HS512T
@@ -3633,6 +3681,10 @@ void spi_nor_set_fixups(struct spi_nor *nor)
                        break;
                }
        }
+
+       if (CONFIG_IS_ENABLED(SPI_FLASH_BAR) &&
+           !strcmp(nor->info->name, "s25fl256l"))
+               nor->fixups = &s25fl256l_fixups;
 #endif
 
 #ifdef CONFIG_SPI_FLASH_S28HS512T
@@ -3653,6 +3705,11 @@ int spi_nor_scan(struct spi_nor *nor)
        struct mtd_info *mtd = &nor->mtd;
        struct spi_slave *spi = nor->spi;
        int ret;
+       int cfi_mtd_nb = 0;
+
+#ifdef CONFIG_FLASH_CFI_MTD
+       cfi_mtd_nb = CFI_FLASH_BANKS;
+#endif
 
        /* Reset SPI protocol for all commands. */
        nor->reg_proto = SNOR_PROTO_1_1_1;
@@ -3704,8 +3761,12 @@ int spi_nor_scan(struct spi_nor *nor)
        if (ret)
                return ret;
 
-       if (!mtd->name)
-               mtd->name = info->name;
+       if (!mtd->name) {
+               sprintf(nor->mtd_name, "%s%d",
+                       MTD_DEV_TYPE(MTD_DEV_TYPE_NOR),
+                       cfi_mtd_nb + dev_seq(nor->dev));
+               mtd->name = nor->mtd_name;
+       }
        mtd->dev = nor->dev;
        mtd->priv = nor;
        mtd->type = MTD_NORFLASH;
@@ -3810,7 +3871,7 @@ int spi_nor_scan(struct spi_nor *nor)
 
        nor->rdsr_dummy = params.rdsr_dummy;
        nor->rdsr_addr_nbytes = params.rdsr_addr_nbytes;
-       nor->name = mtd->name;
+       nor->name = info->name;
        nor->size = mtd->size;
        nor->erase_size = mtd->erasesize;
        nor->sector_size = mtd->erasesize;