Merge tag 'mtd/fixes-for-5.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 24 Jun 2019 13:23:55 +0000 (21:23 +0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 24 Jun 2019 13:23:55 +0000 (21:23 +0800)
Pull mtd fixes from Miquel Raynal:

 - Set the raw NAND number of targets to the right value

 - Fix a bug uncovered by a recent patch on Spansion SPI-NOR flashes

* tag 'mtd/fixes-for-5.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux:
  mtd: spi-nor: use 16-bit WRR command when QE is set on spansion flashes
  mtd: rawnand: initialize ntargets with maxchips

drivers/mtd/nand/raw/nand_base.c
drivers/mtd/spi-nor/spi-nor.c
include/linux/mtd/spi-nor.h

index b5b68aa..6eb1312 100644 (file)
@@ -4662,7 +4662,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
        memorg = nanddev_get_memorg(&chip->base);
        memorg->planes_per_lun = 1;
        memorg->luns_per_target = 1;
-       memorg->ntargets = 1;
 
        /*
         * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
@@ -5027,6 +5026,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
        if (ret)
                return ret;
 
+       memorg->ntargets = maxchips;
+
        /* Read the flash type */
        ret = nand_detect(chip, table);
        if (ret) {
index 73172d7..0c2ec1c 100644 (file)
@@ -1636,6 +1636,95 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
        return 0;
 }
 
+/**
+ * spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits.
+ * @nor:        pointer to a 'struct spi_nor'
+ *
+ * Read-modify-write function that clears the Block Protection bits from the
+ * Status Register without affecting other bits.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_clear_sr_bp(struct spi_nor *nor)
+{
+       int ret;
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+       ret = read_sr(nor);
+       if (ret < 0) {
+               dev_err(nor->dev, "error while reading status register\n");
+               return ret;
+       }
+
+       write_enable(nor);
+
+       ret = write_sr(nor, ret & ~mask);
+       if (ret) {
+               dev_err(nor->dev, "write to status register failed\n");
+               return ret;
+       }
+
+       ret = spi_nor_wait_till_ready(nor);
+       if (ret)
+               dev_err(nor->dev, "timeout while writing status register\n");
+       return ret;
+}
+
+/**
+ * spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection
+ * bits on spansion flashes.
+ * @nor:        pointer to a 'struct spi_nor'
+ *
+ * Read-modify-write function that clears the Block Protection bits from the
+ * Status Register without affecting other bits. The function is tightly
+ * coupled with the spansion_quad_enable() function. Both assume that the Write
+ * Register with 16 bits, together with the Read Configuration Register (35h)
+ * instructions are supported.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor)
+{
+       int ret;
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+       u8 sr_cr[2] = {0};
+
+       /* Check current Quad Enable bit value. */
+       ret = read_cr(nor);
+       if (ret < 0) {
+               dev_err(nor->dev,
+                       "error while reading configuration register\n");
+               return ret;
+       }
+
+       /*
+        * When the configuration register Quad Enable bit is one, only the
+        * Write Status (01h) command with two data bytes may be used.
+        */
+       if (ret & CR_QUAD_EN_SPAN) {
+               sr_cr[1] = ret;
+
+               ret = read_sr(nor);
+               if (ret < 0) {
+                       dev_err(nor->dev,
+                               "error while reading status register\n");
+                       return ret;
+               }
+               sr_cr[0] = ret & ~mask;
+
+               ret = write_sr_cr(nor, sr_cr);
+               if (ret)
+                       dev_err(nor->dev, "16-bit write register failed\n");
+               return ret;
+       }
+
+       /*
+        * If the Quad Enable bit is zero, use the Write Status (01h) command
+        * with one data byte.
+        */
+       return spi_nor_clear_sr_bp(nor);
+}
+
 /* Used when the "_ext_id" is two bytes at most */
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
                .id = {                                                 \
@@ -3660,6 +3749,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
                default:
                        /* Kept only for backward compatibility purpose. */
                        params->quad_enable = spansion_quad_enable;
+                       if (nor->clear_sr_bp)
+                               nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp;
                        break;
                }
 
@@ -3912,17 +4003,13 @@ static int spi_nor_init(struct spi_nor *nor)
 {
        int err;
 
-       /*
-        * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
-        * with the software protection bits set
-        */
-       if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
-           JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
-           JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
-           nor->info->flags & SPI_NOR_HAS_LOCK) {
-               write_enable(nor);
-               write_sr(nor, 0);
-               spi_nor_wait_till_ready(nor);
+       if (nor->clear_sr_bp) {
+               err = nor->clear_sr_bp(nor);
+               if (err) {
+                       dev_err(nor->dev,
+                               "fail to clear block protection bits\n");
+                       return err;
+               }
        }
 
        if (nor->quad_enable) {
@@ -4047,6 +4134,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
        if (info->flags & SPI_S3AN)
                nor->flags |=  SNOR_F_READY_XSR_RDY;
 
+       /*
+        * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
+        * with the software protection bits set.
+        */
+       if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
+           JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
+           JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
+           nor->info->flags & SPI_NOR_HAS_LOCK)
+               nor->clear_sr_bp = spi_nor_clear_sr_bp;
+
        /* Parse the Serial Flash Discoverable Parameters table. */
        ret = spi_nor_init_params(nor, &params);
        if (ret)
index b3d360b..9f57cdf 100644 (file)
@@ -373,6 +373,8 @@ struct flash_info;
  * @flash_unlock:      [FLASH-SPECIFIC] unlock a region of the SPI NOR
  * @flash_is_locked:   [FLASH-SPECIFIC] check if a region of the SPI NOR is
  * @quad_enable:       [FLASH-SPECIFIC] enables SPI NOR quad mode
+ * @clear_sr_bp:       [FLASH-SPECIFIC] clears the Block Protection Bits from
+ *                     the SPI NOR Status Register.
  *                     completely locked
  * @priv:              the private data
  */
@@ -410,6 +412,7 @@ struct spi_nor {
        int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
        int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
        int (*quad_enable)(struct spi_nor *nor);
+       int (*clear_sr_bp)(struct spi_nor *nor);
 
        void *priv;
 };