]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/mtd/spi-nor/spi-nor.c
Merge tag 'spi-nor/for-4.11-v2' of git://github.com/spi-nor/linux
[karo-tx-linux.git] / drivers / mtd / spi-nor / spi-nor.c
index f6bde55784598af27a8ee65262bbaf754ea98dfe..1ae872bfc3ba5be342993f4d176b5a2d4390da57 100644 (file)
@@ -75,6 +75,16 @@ struct flash_info {
                                         * bit. Must be used with
                                         * SPI_NOR_HAS_LOCK.
                                         */
+#define        SPI_S3AN                BIT(10) /*
+                                        * Xilinx Spartan 3AN In-System Flash
+                                        * (MFR cannot be used for probing
+                                        * because it has the same value as
+                                        * ATMEL flashes)
+                                        */
+#define SPI_NOR_4B_OPCODES     BIT(11) /*
+                                        * Use dedicated 4byte address op codes
+                                        * to support memory size above 128Mib.
+                                        */
 };
 
 #define JEDEC_MFR(info)        ((info)->id[0])
@@ -188,6 +198,78 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
        return mtd->priv;
 }
 
+
+static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
+{
+       size_t i;
+
+       for (i = 0; i < size; i++)
+               if (table[i][0] == opcode)
+                       return table[i][1];
+
+       /* No conversion found, keep input op code. */
+       return opcode;
+}
+
+static inline u8 spi_nor_convert_3to4_read(u8 opcode)
+{
+       static const u8 spi_nor_3to4_read[][2] = {
+               { SPINOR_OP_READ,       SPINOR_OP_READ_4B },
+               { SPINOR_OP_READ_FAST,  SPINOR_OP_READ_FAST_4B },
+               { SPINOR_OP_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B },
+               { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B },
+               { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B },
+               { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B },
+       };
+
+       return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
+                                     ARRAY_SIZE(spi_nor_3to4_read));
+}
+
+static inline u8 spi_nor_convert_3to4_program(u8 opcode)
+{
+       static const u8 spi_nor_3to4_program[][2] = {
+               { SPINOR_OP_PP,         SPINOR_OP_PP_4B },
+               { SPINOR_OP_PP_1_1_4,   SPINOR_OP_PP_1_1_4_4B },
+               { SPINOR_OP_PP_1_4_4,   SPINOR_OP_PP_1_4_4_4B },
+       };
+
+       return spi_nor_convert_opcode(opcode, spi_nor_3to4_program,
+                                     ARRAY_SIZE(spi_nor_3to4_program));
+}
+
+static inline u8 spi_nor_convert_3to4_erase(u8 opcode)
+{
+       static const u8 spi_nor_3to4_erase[][2] = {
+               { SPINOR_OP_BE_4K,      SPINOR_OP_BE_4K_4B },
+               { SPINOR_OP_BE_32K,     SPINOR_OP_BE_32K_4B },
+               { SPINOR_OP_SE,         SPINOR_OP_SE_4B },
+       };
+
+       return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase,
+                                     ARRAY_SIZE(spi_nor_3to4_erase));
+}
+
+static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
+                                     const struct flash_info *info)
+{
+       /* Do some manufacturer fixups first */
+       switch (JEDEC_MFR(info)) {
+       case SNOR_MFR_SPANSION:
+               /* No small sector erase for 4-byte command set */
+               nor->erase_opcode = SPINOR_OP_SE;
+               nor->mtd.erasesize = info->sector_size;
+               break;
+
+       default:
+               break;
+       }
+
+       nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
+       nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
+       nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
+}
+
 /* Enable/disable 4-byte addressing mode. */
 static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
                            int enable)
@@ -217,6 +299,21 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
                return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
        }
 }
+
+static int s3an_sr_ready(struct spi_nor *nor)
+{
+       int ret;
+       u8 val;
+
+       ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1);
+       if (ret < 0) {
+               dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret);
+               return ret;
+       }
+
+       return !!(val & XSR_RDY);
+}
+
 static inline int spi_nor_sr_ready(struct spi_nor *nor)
 {
        int sr = read_sr(nor);
@@ -238,7 +335,11 @@ static inline int spi_nor_fsr_ready(struct spi_nor *nor)
 static int spi_nor_ready(struct spi_nor *nor)
 {
        int sr, fsr;
-       sr = spi_nor_sr_ready(nor);
+
+       if (nor->flags & SNOR_F_READY_XSR_RDY)
+               sr = s3an_sr_ready(nor);
+       else
+               sr = spi_nor_sr_ready(nor);
        if (sr < 0)
                return sr;
        fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1;
@@ -319,6 +420,27 @@ static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
        mutex_unlock(&nor->lock);
 }
 
+/*
+ * This code converts an address to the Default Address Mode, that has non
+ * power of two page sizes. We must support this mode because it is the default
+ * mode supported by Xilinx tools, it can access the whole flash area and
+ * changing over to the Power-of-two mode is irreversible and corrupts the
+ * original data.
+ * Addr can safely be unsigned int, the biggest S3AN device is smaller than
+ * 4 MiB.
+ */
+static loff_t spi_nor_s3an_addr_convert(struct spi_nor *nor, unsigned int addr)
+{
+       unsigned int offset;
+       unsigned int page;
+
+       offset = addr % nor->page_size;
+       page = addr / nor->page_size;
+       page <<= (nor->page_size > 512) ? 10 : 9;
+
+       return page | offset;
+}
+
 /*
  * Initiate the erasure of a single sector
  */
@@ -327,6 +449,9 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
        u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
        int i;
 
+       if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
+               addr = spi_nor_s3an_addr_convert(nor, addr);
+
        if (nor->erase)
                return nor->erase(nor, addr);
 
@@ -368,7 +493,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
                return ret;
 
        /* whole-chip erase? */
-       if (len == mtd->size) {
+       if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
                unsigned long timeout;
 
                write_enable(nor);
@@ -782,6 +907,19 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
                .addr_width = (_addr_width),                            \
                .flags = (_flags),
 
+#define S3AN_INFO(_jedec_id, _n_sectors, _page_size)                   \
+               .id = {                                                 \
+                       ((_jedec_id) >> 16) & 0xff,                     \
+                       ((_jedec_id) >> 8) & 0xff,                      \
+                       (_jedec_id) & 0xff                              \
+                       },                                              \
+               .id_len = 3,                                            \
+               .sector_size = (8*_page_size),                          \
+               .n_sectors = (_n_sectors),                              \
+               .page_size = _page_size,                                \
+               .addr_width = 3,                                        \
+               .flags = SPI_NOR_NO_FR | SPI_S3AN,
+
 /* NOTE: double check command sets and memory organization when you add
  * more nor chips.  This current list focusses on newer chips, which
  * have been converging on command sets which including JEDEC ID.
@@ -821,7 +959,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "en25s64",    INFO(0x1c3817, 0, 64 * 1024,  128, SECT_4K) },
 
        /* ESMT */
-       { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
+       { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) },
 
        /* Everspin */
        { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
@@ -832,6 +970,11 @@ static const struct flash_info spi_nor_ids[] = {
        { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
 
        /* GigaDevice */
+       {
+               "gd25q16", INFO(0xc84015, 0, 64 * 1024,  32,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
        {
                "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64,
                        SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
@@ -1014,6 +1157,13 @@ static const struct flash_info spi_nor_ids[] = {
        { "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
        { "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
        { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+
+       /* Xilinx S3AN Internal Flash */
+       { "3S50AN", S3AN_INFO(0x1f2200, 64, 264) },
+       { "3S200AN", S3AN_INFO(0x1f2400, 256, 264) },
+       { "3S400AN", S3AN_INFO(0x1f2400, 256, 264) },
+       { "3S700AN", S3AN_INFO(0x1f2500, 512, 264) },
+       { "3S1400AN", S3AN_INFO(0x1f2600, 512, 528) },
        { },
 };
 
@@ -1054,7 +1204,12 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
                return ret;
 
        while (len) {
-               ret = nor->read(nor, from, len, buf);
+               loff_t addr = from;
+
+               if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
+                       addr = spi_nor_s3an_addr_convert(nor, addr);
+
+               ret = nor->read(nor, addr, len, buf);
                if (ret == 0) {
                        /* We shouldn't see 0-length reads */
                        ret = -EIO;
@@ -1175,17 +1330,32 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 
        for (i = 0; i < len; ) {
                ssize_t written;
+               loff_t addr = to + i;
+
+               /*
+                * If page_size is a power of two, the offset can be quickly
+                * calculated with an AND operation. On the other cases we
+                * need to do a modulus operation (more expensive).
+                * Power of two numbers have only one bit set and we can use
+                * the instruction hweight32 to detect if we need to do a
+                * modulus (do_div()) or not.
+                */
+               if (hweight32(nor->page_size) == 1) {
+                       page_offset = addr & (nor->page_size - 1);
+               } else {
+                       uint64_t aux = addr;
 
-               page_offset = (to + i) & (nor->page_size - 1);
-               WARN_ONCE(page_offset,
-                         "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.",
-                         page_offset);
+                       page_offset = do_div(aux, nor->page_size);
+               }
                /* the size of data remaining on the first page */
                page_remain = min_t(size_t,
                                    nor->page_size - page_offset, len - i);
 
+               if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
+                       addr = spi_nor_s3an_addr_convert(nor, addr);
+
                write_enable(nor);
-               ret = nor->write(nor, to + i, page_remain, buf + i);
+               ret = nor->write(nor, addr, page_remain, buf + i);
                if (ret < 0)
                        goto write_err;
                written = ret;
@@ -1216,6 +1386,9 @@ static int macronix_quad_enable(struct spi_nor *nor)
        val = read_sr(nor);
        if (val < 0)
                return val;
+       if (val & SR_QUAD_EN_MX)
+               return 0;
+
        write_enable(nor);
 
        write_sr(nor, val | SR_QUAD_EN_MX);
@@ -1312,6 +1485,47 @@ static int spi_nor_check(struct spi_nor *nor)
        return 0;
 }
 
+static int s3an_nor_scan(const struct flash_info *info, struct spi_nor *nor)
+{
+       int ret;
+       u8 val;
+
+       ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1);
+       if (ret < 0) {
+               dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret);
+               return ret;
+       }
+
+       nor->erase_opcode = SPINOR_OP_XSE;
+       nor->program_opcode = SPINOR_OP_XPP;
+       nor->read_opcode = SPINOR_OP_READ;
+       nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
+
+       /*
+        * This flashes have a page size of 264 or 528 bytes (known as
+        * Default addressing mode). It can be changed to a more standard
+        * Power of two mode where the page size is 256/512. This comes
+        * with a price: there is 3% less of space, the data is corrupted
+        * and the page size cannot be changed back to default addressing
+        * mode.
+        *
+        * The current addressing mode can be read from the XRDSR register
+        * and should not be changed, because is a destructive operation.
+        */
+       if (val & XSR_PAGESIZE) {
+               /* Flash in Power of 2 mode */
+               nor->page_size = (nor->page_size == 264) ? 256 : 512;
+               nor->mtd.writebufsize = nor->page_size;
+               nor->mtd.size = 8 * nor->page_size * info->n_sectors;
+               nor->mtd.erasesize = 8 * nor->page_size;
+       } else {
+               /* Flash in Default addressing mode */
+               nor->flags |= SNOR_F_S3AN_ADDR_DEFAULT;
+       }
+
+       return 0;
+}
+
 int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 {
        const struct flash_info *info = NULL;
@@ -1359,6 +1573,14 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
        mutex_init(&nor->lock);
 
+       /*
+        * Make sure the XSR_RDY flag is set before calling
+        * spi_nor_wait_till_ready(). Xilinx S3AN share MFR
+        * with Atmel spi-nor
+        */
+       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
@@ -1483,27 +1705,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        else if (mtd->size > 0x1000000) {
                /* enable 4-byte addressing if the device exceeds 16MiB */
                nor->addr_width = 4;
-               if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
-                       /* Dedicated 4-byte command set */
-                       switch (nor->flash_read) {
-                       case SPI_NOR_QUAD:
-                               nor->read_opcode = SPINOR_OP_READ4_1_1_4;
-                               break;
-                       case SPI_NOR_DUAL:
-                               nor->read_opcode = SPINOR_OP_READ4_1_1_2;
-                               break;
-                       case SPI_NOR_FAST:
-                               nor->read_opcode = SPINOR_OP_READ4_FAST;
-                               break;
-                       case SPI_NOR_NORMAL:
-                               nor->read_opcode = SPINOR_OP_READ4;
-                               break;
-                       }
-                       nor->program_opcode = SPINOR_OP_PP_4B;
-                       /* No small sector erase for 4-byte command set */
-                       nor->erase_opcode = SPINOR_OP_SE_4B;
-                       mtd->erasesize = info->sector_size;
-               } else
+               if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
+                   info->flags & SPI_NOR_4B_OPCODES)
+                       spi_nor_set_4byte_opcodes(nor, info);
+               else
                        set_4byte(nor, info, 1);
        } else {
                nor->addr_width = 3;
@@ -1517,6 +1722,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
        nor->read_dummy = spi_nor_read_dummy_cycles(nor);
 
+       if (info->flags & SPI_S3AN) {
+               ret = s3an_nor_scan(info, nor);
+               if (ret)
+                       return ret;
+       }
+
        dev_info(dev, "%s (%lld Kbytes)\n", info->name,
                        (long long)mtd->size >> 10);