OSDN Git Service

Merge MTD 4.3-rc updates into -next
authorBrian Norris <computersforpeace@gmail.com>
Wed, 30 Sep 2015 18:12:14 +0000 (11:12 -0700)
committerBrian Norris <computersforpeace@gmail.com>
Wed, 30 Sep 2015 18:12:14 +0000 (11:12 -0700)
35 files changed:
Documentation/devicetree/bindings/mtd/vf610-nfc.txt [new file with mode: 0644]
MAINTAINERS
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/m25p80.c
drivers/mtd/maps/pcmciamtd.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/nand/vf610_nfc.c [new file with mode: 0644]
drivers/mtd/spi-nor/fsl-quadspi.c
drivers/mtd/spi-nor/nxp-spifi.c
drivers/mtd/spi-nor/spi-nor.c
fs/jffs2/dir.c
fs/jffs2/malloc.c
fs/jffs2/wbuf.c
include/linux/blkpg.h [new file with mode: 0644]
include/linux/mtd/nand.h
include/linux/mtd/spi-nor.h
include/linux/platform_data/mtd-nand-pxa3xx.h
include/uapi/linux/blkpg.h

diff --git a/Documentation/devicetree/bindings/mtd/vf610-nfc.txt b/Documentation/devicetree/bindings/mtd/vf610-nfc.txt
new file mode 100644 (file)
index 0000000..c96eeb6
--- /dev/null
@@ -0,0 +1,59 @@
+Freescale's NAND flash controller (NFC)
+
+This variant of the Freescale NAND flash controller (NFC) can be found on
+Vybrid (vf610), MPC5125, MCF54418 and Kinetis K70.
+
+Required properties:
+- compatible: Should be set to "fsl,vf610-nfc".
+- reg: address range of the NFC.
+- interrupts: interrupt of the NFC.
+- #address-cells: shall be set to 1. Encode the nand CS.
+- #size-cells : shall be set to 0.
+- assigned-clocks: main clock from the SoC, for Vybrid <&clks VF610_CLK_NFC>;
+- assigned-clock-rates: The NAND bus timing is derived from this clock
+    rate and should not exceed maximum timing for any NAND memory chip
+    in a board stuffing. Typical NAND memory timings derived from this
+    clock are found in the SoC hardware reference manual. Furthermore,
+    there might be restrictions on maximum rates when using hardware ECC.
+
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+
+Required children nodes:
+Children nodes represent the available nand chips. Currently the driver can
+only handle one NAND chip.
+
+Required properties:
+- compatible: Should be set to "fsl,vf610-nfc-cs".
+- nand-bus-width: see nand.txt
+- nand-ecc-mode: see nand.txt
+
+Required properties for hardware ECC:
+- nand-ecc-strength: supported strengths are 24 and 32 bit (see nand.txt)
+- nand-ecc-step-size: step size equals page size, currently only 2k pages are
+    supported
+- nand-on-flash-bbt: see nand.txt
+
+Example:
+
+       nfc: nand@400e0000 {
+               compatible = "fsl,vf610-nfc";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x400e0000 0x4000>;
+               interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clks VF610_CLK_NFC>;
+               clock-names = "nfc";
+               assigned-clocks = <&clks VF610_CLK_NFC>;
+               assigned-clock-rates = <33000000>;
+
+               nand@0 {
+                       compatible = "fsl,vf610-nfc-nandcs";
+                       reg = <0>;
+                       nand-bus-width = <8>;
+                       nand-ecc-mode = "hw";
+                       nand-ecc-strength = <32>;
+                       nand-ecc-step-size = <2048>;
+                       nand-on-flash-bbt;
+               };
+       };
index 7ba7ab7..41e1e2b 100644 (file)
@@ -11056,6 +11056,12 @@ S:     Maintained
 F:     Documentation/fb/uvesafb.txt
 F:     drivers/video/fbdev/uvesafb.*
 
+VF610 NAND DRIVER
+M:     Stefan Agner <stefan@agner.ch>
+L:     linux-mtd@lists.infradead.org
+S:     Supported
+F:     drivers/mtd/nand/vf610_nfc.c
+
 VFAT/FAT/MSDOS FILESYSTEM
 M:     OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
 S:     Maintained
index c850300..08f6298 100644 (file)
@@ -48,6 +48,8 @@
  * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
  */
 
+#define pr_fmt(fmt)    "mtd: " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
@@ -55,9 +57,6 @@
 #include <linux/module.h>
 #include <linux/err.h>
 
-/* error message prefix */
-#define ERRP "mtd: "
-
 /* debug macro */
 #if 0
 #define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
@@ -115,9 +114,8 @@ static struct mtd_partition * newpart(char *s,
                s++;
        } else {
                size = memparse(s, &s);
-               if (size < PAGE_SIZE) {
-                       printk(KERN_ERR ERRP "partition size too small (%llx)\n",
-                              size);
+               if (!size) {
+                       pr_err("partition has size 0\n");
                        return ERR_PTR(-EINVAL);
                }
        }
@@ -142,7 +140,7 @@ static struct mtd_partition * newpart(char *s,
                name = ++s;
                p = strchr(name, delim);
                if (!p) {
-                       printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
+                       pr_err("no closing %c found in partition name\n", delim);
                        return ERR_PTR(-EINVAL);
                }
                name_len = p - name;
@@ -170,7 +168,7 @@ static struct mtd_partition * newpart(char *s,
        /* test if more partitions are following */
        if (*s == ',') {
                if (size == SIZE_REMAINING) {
-                       printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
+                       pr_err("no partitions allowed after a fill-up partition\n");
                        return ERR_PTR(-EINVAL);
                }
                /* more partitions follow, parse them */
@@ -237,7 +235,7 @@ static int mtdpart_setup_real(char *s)
                /* fetch <mtd-id> */
                p = strchr(s, ':');
                if (!p) {
-                       printk(KERN_ERR ERRP "no mtd-id\n");
+                       pr_err("no mtd-id\n");
                        return -EINVAL;
                }
                mtd_id_len = p - mtd_id;
@@ -289,7 +287,7 @@ static int mtdpart_setup_real(char *s)
 
                /* does another spec follow? */
                if (*s != ';') {
-                       printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
+                       pr_err("bad character after partition (%c)\n", *s);
                        return -EINVAL;
                }
                s++;
@@ -343,17 +341,15 @@ static int parse_cmdline_partitions(struct mtd_info *master,
                        part->parts[i].size = master->size - offset;
 
                if (offset + part->parts[i].size > master->size) {
-                       printk(KERN_WARNING ERRP
-                              "%s: partitioning exceeds flash size, truncating\n",
-                              part->mtd_id);
+                       pr_warn("%s: partitioning exceeds flash size, truncating\n",
+                               part->mtd_id);
                        part->parts[i].size = master->size - offset;
                }
                offset += part->parts[i].size;
 
                if (part->parts[i].size == 0) {
-                       printk(KERN_WARNING ERRP
-                              "%s: skipping zero sized partition\n",
-                              part->mtd_id);
+                       pr_warn("%s: skipping zero sized partition\n",
+                               part->mtd_id);
                        part->num_parts--;
                        memmove(&part->parts[i], &part->parts[i + 1],
                                sizeof(*part->parts) * (part->num_parts - i));
index 9cd3631..4b5d7a4 100644 (file)
@@ -31,7 +31,6 @@
 struct m25p {
        struct spi_device       *spi;
        struct spi_nor          spi_nor;
-       struct mtd_info         mtd;
        u8                      command[MAX_CMD_SIZE];
 };
 
@@ -62,8 +61,7 @@ static int m25p_cmdsz(struct spi_nor *nor)
        return 1 + nor->addr_width;
 }
 
-static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
-                       int wr_en)
+static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
        struct m25p *flash = nor->priv;
        struct spi_device *spi = flash->spi;
@@ -159,7 +157,7 @@ static int m25p80_erase(struct spi_nor *nor, loff_t offset)
        struct m25p *flash = nor->priv;
 
        dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
-               flash->mtd.erasesize / 1024, (u32)offset);
+               flash->spi_nor.mtd.erasesize / 1024, (u32)offset);
 
        /* Set up command buffer. */
        flash->command[0] = nor->erase_opcode;
@@ -201,11 +199,10 @@ static int m25p_probe(struct spi_device *spi)
        nor->read_reg = m25p80_read_reg;
 
        nor->dev = &spi->dev;
-       nor->mtd = &flash->mtd;
+       nor->flash_node = spi->dev.of_node;
        nor->priv = flash;
 
        spi_set_drvdata(spi, flash);
-       flash->mtd.priv = nor;
        flash->spi = spi;
 
        if (spi->mode & SPI_RX_QUAD)
@@ -214,7 +211,7 @@ static int m25p_probe(struct spi_device *spi)
                mode = SPI_NOR_DUAL;
 
        if (data && data->name)
-               flash->mtd.name = data->name;
+               nor->mtd.name = data->name;
 
        /* For some (historical?) reason many platforms provide two different
         * names in flash_platform_data: "name" and "type". Quite often name is
@@ -232,7 +229,7 @@ static int m25p_probe(struct spi_device *spi)
 
        ppdata.of_node = spi->dev.of_node;
 
-       return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
+       return mtd_device_parse_register(&nor->mtd, NULL, &ppdata,
                        data ? data->parts : NULL,
                        data ? data->nr_parts : 0);
 }
@@ -243,7 +240,7 @@ static int m25p_remove(struct spi_device *spi)
        struct m25p     *flash = spi_get_drvdata(spi);
 
        /* Clean up MTD stuff. */
-       return mtd_device_unregister(&flash->mtd);
+       return mtd_device_unregister(&flash->spi_nor.mtd);
 }
 
 /*
index af747af..3dad211 100644 (file)
@@ -700,6 +700,7 @@ static const struct pcmcia_device_id pcmciamtd_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("Maxtor", "MAXFL MobileMax Flash Memory Card", 0xb68968c8, 0x2dfb47b0),
        PCMCIA_DEVICE_PROD_ID123("M-Systems", "M-SYS Flash Memory Card", "(c) M-Systems", 0x7ed2ad87, 0x675dc3fb, 0x7aef3965),
        PCMCIA_DEVICE_PROD_ID12("PRETEC", "  2MB SRAM CARD", 0xebf91155, 0x805360ca),
+       PCMCIA_DEVICE_PROD_ID12("PRETEC", "  4MB SRAM CARD", 0xebf91155, 0x20b6bf17),
        PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB101EN20", 0xf9876baf, 0xad0b207b),
        PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB513EN20", 0xf9876baf, 0xe8d884ad),
        PCMCIA_DEVICE_PROD_ID12("SMART Modular Technologies", " 4MB FLASH Card", 0x96fd8277, 0x737a5b05),
index 44dc965..cb47d79 100644 (file)
@@ -399,7 +399,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
                snprintf(gd->disk_name, sizeof(gd->disk_name),
                         "%s%d", tr->name, new->devnum);
 
-       set_capacity(gd, (new->size * tr->blksize) >> 9);
+       set_capacity(gd, ((u64)new->size * tr->blksize) >> 9);
 
        /* Create the request queue */
        spin_lock_init(&new->queue_lock);
index 55fa27e..6d19835 100644 (file)
@@ -498,21 +498,17 @@ static int shrink_ecclayout(const struct nand_ecclayout *from,
 }
 
 static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
-                          struct blkpg_ioctl_arg __user *arg)
+                              struct blkpg_ioctl_arg *arg)
 {
-       struct blkpg_ioctl_arg a;
        struct blkpg_partition p;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
+       if (copy_from_user(&p, arg->data, sizeof(p)))
                return -EFAULT;
 
-       if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
-               return -EFAULT;
-
-       switch (a.op) {
+       switch (arg->op) {
        case BLKPG_ADD_PARTITION:
 
                /* Only master mtd device must be used to add partitions */
@@ -966,8 +962,13 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
 
        case BLKPG:
        {
-               ret = mtdchar_blkpg_ioctl(mtd,
-                     (struct blkpg_ioctl_arg __user *)arg);
+               struct blkpg_ioctl_arg __user *blk_arg = argp;
+               struct blkpg_ioctl_arg a;
+
+               if (copy_from_user(&a, blk_arg, sizeof(a)))
+                       ret = -EFAULT;
+               else
+                       ret = mtdchar_blkpg_ioctl(mtd, &a);
                break;
        }
 
@@ -1046,6 +1047,29 @@ static long mtdchar_compat_ioctl(struct file *file, unsigned int cmd,
                                &buf_user->start);
                break;
        }
+
+       case BLKPG:
+       {
+               /* Convert from blkpg_compat_ioctl_arg to blkpg_ioctl_arg */
+               struct blkpg_compat_ioctl_arg __user *uarg = argp;
+               struct blkpg_compat_ioctl_arg compat_arg;
+               struct blkpg_ioctl_arg a;
+
+               if (copy_from_user(&compat_arg, uarg, sizeof(compat_arg))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               memset(&a, 0, sizeof(a));
+               a.op = compat_arg.op;
+               a.flags = compat_arg.flags;
+               a.datalen = compat_arg.datalen;
+               a.data = compat_ptr(compat_arg.data);
+
+               ret = mtdchar_blkpg_ioctl(mtd, &a);
+               break;
+       }
+
        default:
                ret = mtdchar_ioctl(file, cmd, (unsigned long)argp);
        }
index 8bbbb75..8598e3b 100644 (file)
@@ -1301,6 +1301,7 @@ static void __exit cleanup_mtd(void)
                remove_proc_entry("mtd", NULL);
        class_unregister(&mtd_class);
        bdi_destroy(&mtd_bdi);
+       idr_destroy(&mtd_idr);
 }
 
 module_init(init_mtd);
index cafdb88..919a936 100644 (file)
@@ -664,8 +664,10 @@ int add_mtd_partitions(struct mtd_info *master,
 
        for (i = 0; i < nbparts; i++) {
                slave = allocate_partition(master, parts + i, i, cur_offset);
-               if (IS_ERR(slave))
+               if (IS_ERR(slave)) {
+                       del_mtd_partitions(master);
                        return PTR_ERR(slave);
+               }
 
                mutex_lock(&mtd_partitions_mutex);
                list_add(&slave->list, &mtd_partitions);
index 3324281..ccd1158 100644 (file)
@@ -460,6 +460,17 @@ config MTD_NAND_MPC5121_NFC
          This enables the driver for the NAND flash controller on the
          MPC5121 SoC.
 
+config MTD_NAND_VF610_NFC
+       tristate "Support for Freescale NFC for VF610/MPC5125"
+       depends on (SOC_VF610 || COMPILE_TEST)
+       help
+         Enables support for NAND Flash Controller on some Freescale
+         processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
+         The driver supports a maximum 2k page size. With 2k pages and
+         64 bytes or more of OOB, hardware ECC with up to 32-bit error
+         correction is supported. Hardware ECC is only enabled through
+         device tree.
+
 config MTD_NAND_MXC
        tristate "MXC NAND support"
        depends on ARCH_MXC
index 075a027..2c7f014 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_MTD_NAND_SOCRATES)               += socrates_nand.o
 obj-$(CONFIG_MTD_NAND_TXX9NDFMC)       += txx9ndfmc.o
 obj-$(CONFIG_MTD_NAND_NUC900)          += nuc900_nand.o
 obj-$(CONFIG_MTD_NAND_MPC5121_NFC)     += mpc5121_nfc.o
+obj-$(CONFIG_MTD_NAND_VF610_NFC)       += vf610_nfc.o
 obj-$(CONFIG_MTD_NAND_RICOH)           += r852.o
 obj-$(CONFIG_MTD_NAND_JZ4740)          += jz4740_nand.o
 obj-$(CONFIG_MTD_NAND_GPMI_NAND)       += gpmi-nand/
index fddb795..048e4e0 100644 (file)
@@ -1792,7 +1792,8 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
 
        memset(cfg, 0, sizeof(*cfg));
 
-       ret = of_property_read_u32(chip->dn, "brcm,nand-oob-sector-size",
+       ret = of_property_read_u32(chip->flash_node,
+                                  "brcm,nand-oob-sector-size",
                                   &oob_sector);
        if (ret) {
                /* Use detected size */
@@ -1899,7 +1900,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host)
        mtd = &host->mtd;
        chip = &host->chip;
 
-       chip->dn = dn;
+       chip->flash_node = dn;
        chip->priv = host;
        mtd->priv = chip;
        mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
index 870c7fc..43c0771 100644 (file)
@@ -458,8 +458,17 @@ static void find_valid_banks(struct denali_nand_info *denali)
 static void detect_max_banks(struct denali_nand_info *denali)
 {
        uint32_t features = ioread32(denali->flash_reg + FEATURES);
+       /*
+        * Read the revision register, so we can calculate the max_banks
+        * properly: the encoding changed from rev 5.0 to 5.1
+        */
+       u32 revision = MAKE_COMPARABLE_REVISION(
+                               ioread32(denali->flash_reg + REVISION));
 
-       denali->max_banks = 2 << (features & FEATURES__N_BANKS);
+       if (revision < REVISION_5_1)
+               denali->max_banks = 2 << (features & FEATURES__N_BANKS);
+       else
+               denali->max_banks = 1 << (features & FEATURES__N_BANKS);
 }
 
 static void detect_partition_feature(struct denali_nand_info *denali)
@@ -1304,7 +1313,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
                 */
                addr = MODE_11 | BANK(denali->flash_bank);
                index_addr(denali, addr | 0, 0x90);
-               index_addr(denali, addr | 1, 0);
+               index_addr(denali, addr | 1, col);
                for (i = 0; i < 8; i++) {
                        index_addr_read_data(denali, addr | 2, &id);
                        write_byte_to_buf(denali, id);
index 145bf88..4b12cd3 100644 (file)
 
 #define REVISION                               0x370
 #define     REVISION__VALUE                            0xffff
+#define MAKE_COMPARABLE_REVISION(x)            swab16((x) & REVISION__VALUE)
+#define REVISION_5_1                           0x00000501
 
 #define ONFI_DEVICE_FEATURES                   0x380
 #define     ONFI_DEVICE_FEATURES__VALUE                        0x003f
index 04b22fd..b812074 100644 (file)
@@ -946,6 +946,7 @@ static const struct of_device_id fsl_elbc_nand_match[] = {
        { .compatible = "fsl,elbc-fcm-nand", },
        {}
 };
+MODULE_DEVICE_TABLE(of, fsl_elbc_nand_match);
 
 static struct platform_driver fsl_elbc_nand_driver = {
        .driver = {
index a4e27e8..429142e 100644 (file)
@@ -1163,6 +1163,7 @@ static const struct of_device_id fsl_ifc_nand_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, fsl_ifc_nand_match);
 
 static struct platform_driver fsl_ifc_nand_driver = {
        .driver = {
index 2a49b53..019fe0d 100644 (file)
@@ -841,6 +841,7 @@ static const struct of_device_id mpc5121_nfc_match[] = {
        { .compatible = "fsl,mpc5121-nfc", },
        {},
 };
+MODULE_DEVICE_TABLE(of, mpc5121_nfc_match);
 
 static struct platform_driver mpc5121_nfc_driver = {
        .probe          = mpc5121_nfc_probe,
index f04445b..6862eb3 100644 (file)
@@ -1458,6 +1458,7 @@ static const struct of_device_id mxcnd_dt_ids[] = {
        },
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
 
 static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
 {
index ceb68ca..37c0d9d 100644 (file)
@@ -1101,6 +1101,134 @@ out:
 EXPORT_SYMBOL(nand_lock);
 
 /**
+ * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
+ * @buf: buffer to test
+ * @len: buffer length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a buffer contains only 0xff, which means the underlying region
+ * has been erased and is ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region is not erased.
+ * Note: The logic of this function has been extracted from the memweight
+ * implementation, except that nand_check_erased_buf function exit before
+ * testing the whole buffer if the number of bitflips exceed the
+ * bitflips_threshold value.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold.
+ */
+static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
+{
+       const unsigned char *bitmap = buf;
+       int bitflips = 0;
+       int weight;
+
+       for (; len && ((uintptr_t)bitmap) % sizeof(long);
+            len--, bitmap++) {
+               weight = hweight8(*bitmap);
+               bitflips += BITS_PER_BYTE - weight;
+               if (unlikely(bitflips > bitflips_threshold))
+                       return -EBADMSG;
+       }
+
+       for (; len >= sizeof(long);
+            len -= sizeof(long), bitmap += sizeof(long)) {
+               weight = hweight_long(*((unsigned long *)bitmap));
+               bitflips += BITS_PER_LONG - weight;
+               if (unlikely(bitflips > bitflips_threshold))
+                       return -EBADMSG;
+       }
+
+       for (; len > 0; len--, bitmap++) {
+               weight = hweight8(*bitmap);
+               bitflips += BITS_PER_BYTE - weight;
+               if (unlikely(bitflips > bitflips_threshold))
+                       return -EBADMSG;
+       }
+
+       return bitflips;
+}
+
+/**
+ * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
+ *                              0xff data
+ * @data: data buffer to test
+ * @datalen: data length
+ * @ecc: ECC buffer
+ * @ecclen: ECC length
+ * @extraoob: extra OOB buffer
+ * @extraooblen: extra OOB length
+ * @bitflips_threshold: maximum number of bitflips
+ *
+ * Check if a data buffer and its associated ECC and OOB data contains only
+ * 0xff pattern, which means the underlying region has been erased and is
+ * ready to be programmed.
+ * The bitflips_threshold specify the maximum number of bitflips before
+ * considering the region as not erased.
+ *
+ * Note:
+ * 1/ ECC algorithms are working on pre-defined block sizes which are usually
+ *    different from the NAND page size. When fixing bitflips, ECC engines will
+ *    report the number of errors per chunk, and the NAND core infrastructure
+ *    expect you to return the maximum number of bitflips for the whole page.
+ *    This is why you should always use this function on a single chunk and
+ *    not on the whole page. After checking each chunk you should update your
+ *    max_bitflips value accordingly.
+ * 2/ When checking for bitflips in erased pages you should not only check
+ *    the payload data but also their associated ECC data, because a user might
+ *    have programmed almost all bits to 1 but a few. In this case, we
+ *    shouldn't consider the chunk as erased, and checking ECC bytes prevent
+ *    this case.
+ * 3/ The extraoob argument is optional, and should be used if some of your OOB
+ *    data are protected by the ECC engine.
+ *    It could also be used if you support subpages and want to attach some
+ *    extra OOB data to an ECC chunk.
+ *
+ * Returns a positive number of bitflips less than or equal to
+ * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
+ * threshold. In case of success, the passed buffers are filled with 0xff.
+ */
+int nand_check_erased_ecc_chunk(void *data, int datalen,
+                               void *ecc, int ecclen,
+                               void *extraoob, int extraooblen,
+                               int bitflips_threshold)
+{
+       int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
+
+       data_bitflips = nand_check_erased_buf(data, datalen,
+                                             bitflips_threshold);
+       if (data_bitflips < 0)
+               return data_bitflips;
+
+       bitflips_threshold -= data_bitflips;
+
+       ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
+       if (ecc_bitflips < 0)
+               return ecc_bitflips;
+
+       bitflips_threshold -= ecc_bitflips;
+
+       extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
+                                                 bitflips_threshold);
+       if (extraoob_bitflips < 0)
+               return extraoob_bitflips;
+
+       if (data_bitflips)
+               memset(data, 0xff, datalen);
+
+       if (ecc_bitflips)
+               memset(ecc, 0xff, ecclen);
+
+       if (extraoob_bitflips)
+               memset(extraoob, 0xff, extraooblen);
+
+       return data_bitflips + ecc_bitflips + extraoob_bitflips;
+}
+EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
+
+/**
  * nand_read_page_raw - [INTERN] read raw page data without ecc
  * @mtd: mtd info structure
  * @chip: nand chip info structure
@@ -3846,8 +3974,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        struct nand_flash_dev *type;
        int ret;
 
-       if (chip->dn) {
-               ret = nand_dt_init(mtd, chip, chip->dn);
+       if (chip->flash_node) {
+               ret = nand_dt_init(mtd, chip, chip->flash_node);
                if (ret)
                        return ret;
        }
index 95d0cc4..b16d70a 100644 (file)
@@ -649,8 +649,7 @@ static void free_device(struct nandsim *ns)
                                kmem_cache_free(ns->nand_pages_slab,
                                                ns->pages[i].byte);
                }
-               if (ns->nand_pages_slab)
-                       kmem_cache_destroy(ns->nand_pages_slab);
+               kmem_cache_destroy(ns->nand_pages_slab);
                vfree(ns->pages);
        }
 }
index c3c6d30..64785f4 100644 (file)
@@ -201,6 +201,7 @@ static const struct of_device_id orion_nand_of_match_table[] = {
        { .compatible = "marvell,orion-nand", },
        {},
 };
+MODULE_DEVICE_TABLE(of, orion_nand_of_match_table);
 #endif
 
 static struct platform_driver orion_nand_driver = {
index 740983a..232c707 100644 (file)
@@ -15,7 +15,9 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma/pxa-dma.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/mtd/mtd.h>
 #define ARCH_HAS_DMA
 #endif
 
-#ifdef ARCH_HAS_DMA
-#include <mach/dma.h>
-#endif
-
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
 
 #define        CHIP_DELAY_TIMEOUT      msecs_to_jiffies(200)
@@ -78,7 +76,8 @@
 #define NDCR_ND_MODE           (0x3 << 21)
 #define NDCR_NAND_MODE         (0x0)
 #define NDCR_CLR_PG_CNT                (0x1 << 20)
-#define NDCR_STOP_ON_UNCOR     (0x1 << 19)
+#define NFCV1_NDCR_ARB_CNTL    (0x1 << 19)
+#define NFCV2_NDCR_STOP_ON_UNCOR       (0x1 << 19)
 #define NDCR_RD_ID_CNT_MASK    (0x7 << 16)
 #define NDCR_RD_ID_CNT(x)      (((x) << 16) & NDCR_RD_ID_CNT_MASK)
 
@@ -201,6 +200,10 @@ struct pxa3xx_nand_info {
        unsigned int            oob_buff_pos;
 
        /* DMA information */
+       struct scatterlist      sg;
+       enum dma_data_direction dma_dir;
+       struct dma_chan         *dma_chan;
+       dma_cookie_t            dma_cookie;
        int                     drcmr_dat;
        int                     drcmr_cmd;
 
@@ -208,8 +211,6 @@ struct pxa3xx_nand_info {
        unsigned char           *oob_buff;
        dma_addr_t              data_buff_phys;
        int                     data_dma_ch;
-       struct pxa_dma_desc     *data_desc;
-       dma_addr_t              data_desc_addr;
 
        struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
        unsigned int            state;
@@ -252,6 +253,30 @@ static bool use_dma = 1;
 module_param(use_dma, bool, 0444);
 MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
 
+struct pxa3xx_nand_timing {
+       unsigned int    tCH;  /* Enable signal hold time */
+       unsigned int    tCS;  /* Enable signal setup time */
+       unsigned int    tWH;  /* ND_nWE high duration */
+       unsigned int    tWP;  /* ND_nWE pulse time */
+       unsigned int    tRH;  /* ND_nRE high duration */
+       unsigned int    tRP;  /* ND_nRE pulse width */
+       unsigned int    tR;   /* ND_nWE high to ND_nRE low for read */
+       unsigned int    tWHR; /* ND_nWE high to ND_nRE low for status read */
+       unsigned int    tAR;  /* ND_ALE low to ND_nRE low delay */
+};
+
+struct pxa3xx_nand_flash {
+       char            *name;
+       uint32_t        chip_id;
+       unsigned int    page_per_block; /* Pages per block (PG_PER_BLK) */
+       unsigned int    page_size;      /* Page size in bytes (PAGE_SZ) */
+       unsigned int    flash_width;    /* Width of Flash memory (DWIDTH_M) */
+       unsigned int    dfc_width;      /* Width of flash controller(DWIDTH_C) */
+       unsigned int    num_blocks;     /* Number of physical blocks in Flash */
+
+       struct pxa3xx_nand_timing *timing;      /* NAND Flash timing */
+};
+
 static struct pxa3xx_nand_timing timing[] = {
        { 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
        { 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
@@ -468,6 +493,9 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
                ndcr &= ~NDCR_ND_RUN;
                nand_writel(info, NDCR, ndcr);
        }
+       if (info->dma_chan)
+               dmaengine_terminate_all(info->dma_chan);
+
        /* clear status bits */
        nand_writel(info, NDSR, NDSR_MASK);
 }
@@ -559,57 +587,61 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
        info->data_size -= do_bytes;
 }
 
-#ifdef ARCH_HAS_DMA
-static void start_data_dma(struct pxa3xx_nand_info *info)
+static void pxa3xx_nand_data_dma_irq(void *data)
 {
-       struct pxa_dma_desc *desc = info->data_desc;
-       int dma_len = ALIGN(info->data_size + info->oob_size, 32);
+       struct pxa3xx_nand_info *info = data;
+       struct dma_tx_state state;
+       enum dma_status status;
 
-       desc->ddadr = DDADR_STOP;
-       desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len;
+       status = dmaengine_tx_status(info->dma_chan, info->dma_cookie, &state);
+       if (likely(status == DMA_COMPLETE)) {
+               info->state = STATE_DMA_DONE;
+       } else {
+               dev_err(&info->pdev->dev, "DMA error on data channel\n");
+               info->retcode = ERR_DMABUSERR;
+       }
+       dma_unmap_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
+
+       nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
+       enable_int(info, NDCR_INT_MASK);
+}
+
+static void start_data_dma(struct pxa3xx_nand_info *info)
+{
+       enum dma_transfer_direction direction;
+       struct dma_async_tx_descriptor *tx;
 
        switch (info->state) {
        case STATE_DMA_WRITING:
-               desc->dsadr = info->data_buff_phys;
-               desc->dtadr = info->mmio_phys + NDDB;
-               desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;
+               info->dma_dir = DMA_TO_DEVICE;
+               direction = DMA_MEM_TO_DEV;
                break;
        case STATE_DMA_READING:
-               desc->dtadr = info->data_buff_phys;
-               desc->dsadr = info->mmio_phys + NDDB;
-               desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
+               info->dma_dir = DMA_FROM_DEVICE;
+               direction = DMA_DEV_TO_MEM;
                break;
        default:
                dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
                                info->state);
                BUG();
        }
-
-       DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch;
-       DDADR(info->data_dma_ch) = info->data_desc_addr;
-       DCSR(info->data_dma_ch) |= DCSR_RUN;
-}
-
-static void pxa3xx_nand_data_dma_irq(int channel, void *data)
-{
-       struct pxa3xx_nand_info *info = data;
-       uint32_t dcsr;
-
-       dcsr = DCSR(channel);
-       DCSR(channel) = dcsr;
-
-       if (dcsr & DCSR_BUSERR) {
-               info->retcode = ERR_DMABUSERR;
+       info->sg.length = info->data_size +
+               (info->oob_size ? info->spare_size + info->ecc_size : 0);
+       dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
+
+       tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
+                                    DMA_PREP_INTERRUPT);
+       if (!tx) {
+               dev_err(&info->pdev->dev, "prep_slave_sg() failed\n");
+               return;
        }
-
-       info->state = STATE_DMA_DONE;
-       enable_int(info, NDCR_INT_MASK);
-       nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
+       tx->callback = pxa3xx_nand_data_dma_irq;
+       tx->callback_param = info;
+       info->dma_cookie = dmaengine_submit(tx);
+       dma_async_issue_pending(info->dma_chan);
+       dev_dbg(&info->pdev->dev, "%s(dir=%d cookie=%x size=%u)\n",
+               __func__, direction, info->dma_cookie, info->sg.length);
 }
-#else
-static void start_data_dma(struct pxa3xx_nand_info *info)
-{}
-#endif
 
 static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data)
 {
@@ -1289,42 +1321,57 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
 
        /* Set an initial chunk size */
        info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
-       info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
+       info->reg_ndcr = ndcr &
+               ~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
        info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
        info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
        return 0;
 }
 
-#ifdef ARCH_HAS_DMA
 static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 {
        struct platform_device *pdev = info->pdev;
-       int data_desc_offset = info->buf_size - sizeof(struct pxa_dma_desc);
+       struct dma_slave_config config;
+       dma_cap_mask_t mask;
+       struct pxad_param param;
+       int ret;
 
-       if (use_dma == 0) {
-               info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
-               if (info->data_buff == NULL)
-                       return -ENOMEM;
+       info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
+       if (info->data_buff == NULL)
+               return -ENOMEM;
+       if (use_dma == 0)
                return 0;
-       }
 
-       info->data_buff = dma_alloc_coherent(&pdev->dev, info->buf_size,
-                               &info->data_buff_phys, GFP_KERNEL);
-       if (info->data_buff == NULL) {
-               dev_err(&pdev->dev, "failed to allocate dma buffer\n");
-               return -ENOMEM;
-       }
+       ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
 
-       info->data_desc = (void *)info->data_buff + data_desc_offset;
-       info->data_desc_addr = info->data_buff_phys + data_desc_offset;
+       sg_init_one(&info->sg, info->data_buff, info->buf_size);
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       param.prio = PXAD_PRIO_LOWEST;
+       param.drcmr = info->drcmr_dat;
+       info->dma_chan = dma_request_slave_channel_compat(mask, pxad_filter_fn,
+                                                         &param, &pdev->dev,
+                                                         "data");
+       if (!info->dma_chan) {
+               dev_err(&pdev->dev, "unable to request data dma channel\n");
+               return -ENODEV;
+       }
 
-       info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW,
-                               pxa3xx_nand_data_dma_irq, info);
-       if (info->data_dma_ch < 0) {
-               dev_err(&pdev->dev, "failed to request data dma\n");
-               dma_free_coherent(&pdev->dev, info->buf_size,
-                               info->data_buff, info->data_buff_phys);
-               return info->data_dma_ch;
+       memset(&config, 0, sizeof(config));
+       config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       config.src_addr = info->mmio_phys + NDDB;
+       config.dst_addr = info->mmio_phys + NDDB;
+       config.src_maxburst = 32;
+       config.dst_maxburst = 32;
+       ret = dmaengine_slave_config(info->dma_chan, &config);
+       if (ret < 0) {
+               dev_err(&info->pdev->dev,
+                       "dma channel configuration failed: %d\n",
+                       ret);
+               return ret;
        }
 
        /*
@@ -1337,29 +1384,12 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 
 static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
 {
-       struct platform_device *pdev = info->pdev;
        if (info->use_dma) {
-               pxa_free_dma(info->data_dma_ch);
-               dma_free_coherent(&pdev->dev, info->buf_size,
-                                 info->data_buff, info->data_buff_phys);
-       } else {
-               kfree(info->data_buff);
+               dmaengine_terminate_all(info->dma_chan);
+               dma_release_channel(info->dma_chan);
        }
-}
-#else
-static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
-{
-       info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
-       if (info->data_buff == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
-{
        kfree(info->data_buff);
 }
-#endif
 
 static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
 {
@@ -1491,19 +1521,16 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
                return -EINVAL;
        }
 
-       num = ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1;
+       num = ARRAY_SIZE(builtin_flash_types) - 1;
        for (i = 0; i < num; i++) {
-               if (i < pdata->num_flash)
-                       f = pdata->flash + i;
-               else
-                       f = &builtin_flash_types[i - pdata->num_flash + 1];
+               f = &builtin_flash_types[i + 1];
 
                /* find the chip in default list */
                if (f->chip_id == id)
                        break;
        }
 
-       if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) {
+       if (i >= (ARRAY_SIZE(builtin_flash_types) - 1)) {
                dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
 
                return -EINVAL;
@@ -1528,6 +1555,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
        pxa3xx_flash_ids[1].name = NULL;
        def = pxa3xx_flash_ids;
 KEEP_CONFIG:
+       info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
        if (info->reg_ndcr & NDCR_DWIDTH_M)
                chip->options |= NAND_BUSWIDTH_16;
 
@@ -1662,34 +1690,23 @@ static int alloc_nand_resource(struct platform_device *pdev)
                return ret;
 
        if (use_dma) {
-               /*
-                * This is a dirty hack to make this driver work from
-                * devicetree bindings. It can be removed once we have
-                * a prober DMA controller framework for DT.
-                */
-               if (pdev->dev.of_node &&
-                   of_machine_is_compatible("marvell,pxa3xx")) {
-                       info->drcmr_dat = 97;
-                       info->drcmr_cmd = 99;
-               } else {
-                       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-                       if (r == NULL) {
-                               dev_err(&pdev->dev,
-                                       "no resource defined for data DMA\n");
-                               ret = -ENXIO;
-                               goto fail_disable_clk;
-                       }
-                       info->drcmr_dat = r->start;
-
-                       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-                       if (r == NULL) {
-                               dev_err(&pdev->dev,
-                                       "no resource defined for cmd DMA\n");
-                               ret = -ENXIO;
-                               goto fail_disable_clk;
-                       }
-                       info->drcmr_cmd = r->start;
+               r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+               if (r == NULL) {
+                       dev_err(&pdev->dev,
+                               "no resource defined for data DMA\n");
+                       ret = -ENXIO;
+                       goto fail_disable_clk;
                }
+               info->drcmr_dat = r->start;
+
+               r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (r == NULL) {
+                       dev_err(&pdev->dev,
+                               "no resource defined for cmd DMA\n");
+                       ret = -ENXIO;
+                       goto fail_disable_clk;
+               }
+               info->drcmr_cmd = r->start;
        }
 
        irq = platform_get_irq(pdev, 0);
@@ -1754,6 +1771,16 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
                free_irq(irq, info);
        pxa3xx_nand_free_buff(info);
 
+       /*
+        * In the pxa3xx case, the DFI bus is shared between the SMC and NFC.
+        * In order to prevent a lockup of the system bus, the DFI bus
+        * arbitration is granted to SMC upon driver removal. This is done by
+        * setting the x_ARB_CNTL bit, which also prevents the NAND to have
+        * access to the bus anymore.
+        */
+       nand_writel(info, NDCR,
+                   (nand_readl(info, NDCR) & ~NDCR_ND_ARB_EN) |
+                   NFCV1_NDCR_ARB_CNTL);
        clk_disable_unprepare(info->clk);
 
        for (cs = 0; cs < pdata->num_cs; cs++)
@@ -1800,15 +1827,16 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        struct pxa3xx_nand_platform_data *pdata;
        struct mtd_part_parser_data ppdata = {};
        struct pxa3xx_nand_info *info;
-       int ret, cs, probe_success;
+       int ret, cs, probe_success, dma_available;
 
-#ifndef ARCH_HAS_DMA
-       if (use_dma) {
+       dma_available = IS_ENABLED(CONFIG_ARM) &&
+               (IS_ENABLED(CONFIG_ARCH_PXA) || IS_ENABLED(CONFIG_ARCH_MMP));
+       if (use_dma && !dma_available) {
                use_dma = 0;
                dev_warn(&pdev->dev,
                         "This platform can't do DMA on this device\n");
        }
-#endif
+
        ret = pxa3xx_nand_probe_dt(pdev);
        if (ret)
                return ret;
index e7d333c..ef1fe61 100644 (file)
@@ -970,17 +970,23 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
                mode = chip->nand.onfi_timing_mode_default;
        } else {
                uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
+               int i;
 
                mode = fls(mode) - 1;
                if (mode < 0)
                        mode = 0;
 
                feature[0] = mode;
-               ret = chip->nand.onfi_set_features(&chip->mtd, &chip->nand,
+               for (i = 0; i < chip->nsels; i++) {
+                       chip->nand.select_chip(&chip->mtd, i);
+                       ret = chip->nand.onfi_set_features(&chip->mtd,
+                                               &chip->nand,
                                                ONFI_FEATURE_ADDR_TIMING_MODE,
                                                feature);
-               if (ret)
-                       return ret;
+                       chip->nand.select_chip(&chip->mtd, -1);
+                       if (ret)
+                               return ret;
+               }
        }
 
        timings = onfi_async_timing_mode_to_sdr_timings(mode);
@@ -1154,16 +1160,9 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
                               struct device_node *np)
 {
        struct nand_chip *nand = mtd->priv;
-       int strength;
-       int blk_size;
        int ret;
 
-       blk_size = of_get_nand_ecc_step_size(np);
-       strength = of_get_nand_ecc_strength(np);
-       if (blk_size > 0 && strength > 0) {
-               ecc->size = blk_size;
-               ecc->strength = strength;
-       } else {
+       if (!ecc->size) {
                ecc->size = nand->ecc_step_ds;
                ecc->strength = nand->ecc_strength_ds;
        }
@@ -1171,12 +1170,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
        if (!ecc->size || !ecc->strength)
                return -EINVAL;
 
-       ecc->mode = NAND_ECC_HW;
-
-       ret = of_get_nand_ecc_mode(np);
-       if (ret >= 0)
-               ecc->mode = ret;
-
        switch (ecc->mode) {
        case NAND_ECC_SOFT_BCH:
                break;
@@ -1302,15 +1295,18 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
        /* Default tR value specified in the ONFI spec (chapter 4.15.1) */
        nand->chip_delay = 200;
        nand->controller = &nfc->controller;
+       /*
+        * Set the ECC mode to the default value in case nothing is specified
+        * in the DT.
+        */
+       nand->ecc.mode = NAND_ECC_HW;
+       nand->flash_node = np;
        nand->select_chip = sunxi_nfc_select_chip;
        nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
        nand->read_buf = sunxi_nfc_read_buf;
        nand->write_buf = sunxi_nfc_write_buf;
        nand->read_byte = sunxi_nfc_read_byte;
 
-       if (of_get_nand_on_flash_bbt(np))
-               nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
-
        mtd = &chip->mtd;
        mtd->dev.parent = dev;
        mtd->priv = nand;
@@ -1320,6 +1316,9 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
        if (ret)
                return ret;
 
+       if (nand->bbt_options & NAND_BBT_USE_FLASH)
+               nand->bbt_options |= NAND_BBT_NO_OOB;
+
        ret = sunxi_nand_chip_init_timings(chip, np);
        if (ret) {
                dev_err(dev, "could not configure chip timings: %d\n", ret);
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
new file mode 100644 (file)
index 0000000..ae1f84e
--- /dev/null
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2009-2015 Freescale Semiconductor, Inc. and others
+ *
+ * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver.
+ * Jason ported to M54418TWR and MVFA5 (VF610).
+ * Authors: Stefan Agner <stefan.agner@toradex.com>
+ *          Bill Pringlemeir <bpringlemeir@nbsps.com>
+ *          Shaohui Xie <b21989@freescale.com>
+ *          Jason Jin <Jason.jin@freescale.com>
+ *
+ * Based on original driver mpc5121_nfc.c.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Limitations:
+ * - Untested on MPC5125 and M54418.
+ * - DMA and pipelining not used.
+ * - 2K pages or less.
+ * - HW ECC: Only 2K page with 64+ OOB.
+ * - HW ECC: Only 24 and 32-bit error correction implemented.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_mtd.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define        DRV_NAME                "vf610_nfc"
+
+/* Register Offsets */
+#define NFC_FLASH_CMD1                 0x3F00
+#define NFC_FLASH_CMD2                 0x3F04
+#define NFC_COL_ADDR                   0x3F08
+#define NFC_ROW_ADDR                   0x3F0c
+#define NFC_ROW_ADDR_INC               0x3F14
+#define NFC_FLASH_STATUS1              0x3F18
+#define NFC_FLASH_STATUS2              0x3F1c
+#define NFC_CACHE_SWAP                 0x3F28
+#define NFC_SECTOR_SIZE                        0x3F2c
+#define NFC_FLASH_CONFIG               0x3F30
+#define NFC_IRQ_STATUS                 0x3F38
+
+/* Addresses for NFC MAIN RAM BUFFER areas */
+#define NFC_MAIN_AREA(n)               ((n) *  0x1000)
+
+#define PAGE_2K                                0x0800
+#define OOB_64                         0x0040
+#define OOB_MAX                                0x0100
+
+/*
+ * NFC_CMD2[CODE] values. See section:
+ *  - 31.4.7 Flash Command Code Description, Vybrid manual
+ *  - 23.8.6 Flash Command Sequencer, MPC5125 manual
+ *
+ * Briefly these are bitmasks of controller cycles.
+ */
+#define READ_PAGE_CMD_CODE             0x7EE0
+#define READ_ONFI_PARAM_CMD_CODE       0x4860
+#define PROGRAM_PAGE_CMD_CODE          0x7FC0
+#define ERASE_CMD_CODE                 0x4EC0
+#define READ_ID_CMD_CODE               0x4804
+#define RESET_CMD_CODE                 0x4040
+#define STATUS_READ_CMD_CODE           0x4068
+
+/* NFC ECC mode define */
+#define ECC_BYPASS                     0
+#define ECC_45_BYTE                    6
+#define ECC_60_BYTE                    7
+
+/*** Register Mask and bit definitions */
+
+/* NFC_FLASH_CMD1 Field */
+#define CMD_BYTE2_MASK                         0xFF000000
+#define CMD_BYTE2_SHIFT                                24
+
+/* NFC_FLASH_CM2 Field */
+#define CMD_BYTE1_MASK                         0xFF000000
+#define CMD_BYTE1_SHIFT                                24
+#define CMD_CODE_MASK                          0x00FFFF00
+#define CMD_CODE_SHIFT                         8
+#define BUFNO_MASK                             0x00000006
+#define BUFNO_SHIFT                            1
+#define START_BIT                              BIT(0)
+
+/* NFC_COL_ADDR Field */
+#define COL_ADDR_MASK                          0x0000FFFF
+#define COL_ADDR_SHIFT                         0
+
+/* NFC_ROW_ADDR Field */
+#define ROW_ADDR_MASK                          0x00FFFFFF
+#define ROW_ADDR_SHIFT                         0
+#define ROW_ADDR_CHIP_SEL_RB_MASK              0xF0000000
+#define ROW_ADDR_CHIP_SEL_RB_SHIFT             28
+#define ROW_ADDR_CHIP_SEL_MASK                 0x0F000000
+#define ROW_ADDR_CHIP_SEL_SHIFT                        24
+
+/* NFC_FLASH_STATUS2 Field */
+#define STATUS_BYTE1_MASK                      0x000000FF
+
+/* NFC_FLASH_CONFIG Field */
+#define CONFIG_ECC_SRAM_ADDR_MASK              0x7FC00000
+#define CONFIG_ECC_SRAM_ADDR_SHIFT             22
+#define CONFIG_ECC_SRAM_REQ_BIT                        BIT(21)
+#define CONFIG_DMA_REQ_BIT                     BIT(20)
+#define CONFIG_ECC_MODE_MASK                   0x000E0000
+#define CONFIG_ECC_MODE_SHIFT                  17
+#define CONFIG_FAST_FLASH_BIT                  BIT(16)
+#define CONFIG_16BIT                           BIT(7)
+#define CONFIG_BOOT_MODE_BIT                   BIT(6)
+#define CONFIG_ADDR_AUTO_INCR_BIT              BIT(5)
+#define CONFIG_BUFNO_AUTO_INCR_BIT             BIT(4)
+#define CONFIG_PAGE_CNT_MASK                   0xF
+#define CONFIG_PAGE_CNT_SHIFT                  0
+
+/* NFC_IRQ_STATUS Field */
+#define IDLE_IRQ_BIT                           BIT(29)
+#define IDLE_EN_BIT                            BIT(20)
+#define CMD_DONE_CLEAR_BIT                     BIT(18)
+#define IDLE_CLEAR_BIT                         BIT(17)
+
+/*
+ * ECC status - seems to consume 8 bytes (double word). The documented
+ * status byte is located in the lowest byte of the second word (which is
+ * the 4th or 7th byte depending on endianness).
+ * Calculate an offset to store the ECC status at the end of the buffer.
+ */
+#define ECC_SRAM_ADDR          (PAGE_2K + OOB_MAX - 8)
+
+#define ECC_STATUS             0x4
+#define ECC_STATUS_MASK                0x80
+#define ECC_STATUS_ERR_COUNT   0x3F
+
+enum vf610_nfc_alt_buf {
+       ALT_BUF_DATA = 0,
+       ALT_BUF_ID = 1,
+       ALT_BUF_STAT = 2,
+       ALT_BUF_ONFI = 3,
+};
+
+enum vf610_nfc_variant {
+       NFC_VFC610 = 1,
+};
+
+struct vf610_nfc {
+       struct mtd_info mtd;
+       struct nand_chip chip;
+       struct device *dev;
+       void __iomem *regs;
+       struct completion cmd_done;
+       uint buf_offset;
+       int write_sz;
+       /* Status and ID are in alternate locations. */
+       enum vf610_nfc_alt_buf alt_buf;
+       enum vf610_nfc_variant variant;
+       struct clk *clk;
+       bool use_hw_ecc;
+       u32 ecc_mode;
+};
+
+#define mtd_to_nfc(_mtd) container_of(_mtd, struct vf610_nfc, mtd)
+
+static struct nand_ecclayout vf610_nfc_ecc45 = {
+       .eccbytes = 45,
+       .eccpos = {19, 20, 21, 22, 23,
+                  24, 25, 26, 27, 28, 29, 30, 31,
+                  32, 33, 34, 35, 36, 37, 38, 39,
+                  40, 41, 42, 43, 44, 45, 46, 47,
+                  48, 49, 50, 51, 52, 53, 54, 55,
+                  56, 57, 58, 59, 60, 61, 62, 63},
+       .oobfree = {
+               {.offset = 2,
+                .length = 17} }
+};
+
+static struct nand_ecclayout vf610_nfc_ecc60 = {
+       .eccbytes = 60,
+       .eccpos = { 4,  5,  6,  7,  8,  9, 10, 11,
+                  12, 13, 14, 15, 16, 17, 18, 19,
+                  20, 21, 22, 23, 24, 25, 26, 27,
+                  28, 29, 30, 31, 32, 33, 34, 35,
+                  36, 37, 38, 39, 40, 41, 42, 43,
+                  44, 45, 46, 47, 48, 49, 50, 51,
+                  52, 53, 54, 55, 56, 57, 58, 59,
+                  60, 61, 62, 63 },
+       .oobfree = {
+               {.offset = 2,
+                .length = 2} }
+};
+
+static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
+{
+       return readl(nfc->regs + reg);
+}
+
+static inline void vf610_nfc_write(struct vf610_nfc *nfc, uint reg, u32 val)
+{
+       writel(val, nfc->regs + reg);
+}
+
+static inline void vf610_nfc_set(struct vf610_nfc *nfc, uint reg, u32 bits)
+{
+       vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) | bits);
+}
+
+static inline void vf610_nfc_clear(struct vf610_nfc *nfc, uint reg, u32 bits)
+{
+       vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) & ~bits);
+}
+
+static inline void vf610_nfc_set_field(struct vf610_nfc *nfc, u32 reg,
+                                      u32 mask, u32 shift, u32 val)
+{
+       vf610_nfc_write(nfc, reg,
+                       (vf610_nfc_read(nfc, reg) & (~mask)) | val << shift);
+}
+
+static inline void vf610_nfc_memcpy(void *dst, const void __iomem *src,
+                                   size_t n)
+{
+       /*
+        * Use this accessor for the internal SRAM buffers. On the ARM
+        * Freescale Vybrid SoC it's known that the driver can treat
+        * the SRAM buffer as if it's memory. Other platform might need
+        * to treat the buffers differently.
+        *
+        * For the time being, use memcpy
+        */
+       memcpy(dst, src, n);
+}
+
+/* Clear flags for upcoming command */
+static inline void vf610_nfc_clear_status(struct vf610_nfc *nfc)
+{
+       u32 tmp = vf610_nfc_read(nfc, NFC_IRQ_STATUS);
+
+       tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT;
+       vf610_nfc_write(nfc, NFC_IRQ_STATUS, tmp);
+}
+
+static void vf610_nfc_done(struct vf610_nfc *nfc)
+{
+       unsigned long timeout = msecs_to_jiffies(100);
+
+       /*
+        * Barrier is needed after this write. This write need
+        * to be done before reading the next register the first
+        * time.
+        * vf610_nfc_set implicates such a barrier by using writel
+        * to write to the register.
+        */
+       vf610_nfc_set(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
+       vf610_nfc_set(nfc, NFC_FLASH_CMD2, START_BIT);
+
+       if (!wait_for_completion_timeout(&nfc->cmd_done, timeout))
+               dev_warn(nfc->dev, "Timeout while waiting for BUSY.\n");
+
+       vf610_nfc_clear_status(nfc);
+}
+
+static u8 vf610_nfc_get_id(struct vf610_nfc *nfc, int col)
+{
+       u32 flash_id;
+
+       if (col < 4) {
+               flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS1);
+               flash_id >>= (3 - col) * 8;
+       } else {
+               flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS2);
+               flash_id >>= 24;
+       }
+
+       return flash_id & 0xff;
+}
+
+static u8 vf610_nfc_get_status(struct vf610_nfc *nfc)
+{
+       return vf610_nfc_read(nfc, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK;
+}
+
+static void vf610_nfc_send_command(struct vf610_nfc *nfc, u32 cmd_byte1,
+                                  u32 cmd_code)
+{
+       u32 tmp;
+
+       vf610_nfc_clear_status(nfc);
+
+       tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD2);
+       tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK);
+       tmp |= cmd_byte1 << CMD_BYTE1_SHIFT;
+       tmp |= cmd_code << CMD_CODE_SHIFT;
+       vf610_nfc_write(nfc, NFC_FLASH_CMD2, tmp);
+}
+
+static void vf610_nfc_send_commands(struct vf610_nfc *nfc, u32 cmd_byte1,
+                                   u32 cmd_byte2, u32 cmd_code)
+{
+       u32 tmp;
+
+       vf610_nfc_send_command(nfc, cmd_byte1, cmd_code);
+
+       tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD1);
+       tmp &= ~CMD_BYTE2_MASK;
+       tmp |= cmd_byte2 << CMD_BYTE2_SHIFT;
+       vf610_nfc_write(nfc, NFC_FLASH_CMD1, tmp);
+}
+
+static irqreturn_t vf610_nfc_irq(int irq, void *data)
+{
+       struct mtd_info *mtd = data;
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
+       complete(&nfc->cmd_done);
+
+       return IRQ_HANDLED;
+}
+
+static void vf610_nfc_addr_cycle(struct vf610_nfc *nfc, int column, int page)
+{
+       if (column != -1) {
+               if (nfc->chip.options & NAND_BUSWIDTH_16)
+                       column = column / 2;
+               vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK,
+                                   COL_ADDR_SHIFT, column);
+       }
+       if (page != -1)
+               vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK,
+                                   ROW_ADDR_SHIFT, page);
+}
+
+static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode)
+{
+       vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+                           CONFIG_ECC_MODE_MASK,
+                           CONFIG_ECC_MODE_SHIFT, ecc_mode);
+}
+
+static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size)
+{
+       vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size);
+}
+
+static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
+                             int column, int page)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0;
+
+       nfc->buf_offset = max(column, 0);
+       nfc->alt_buf = ALT_BUF_DATA;
+
+       switch (command) {
+       case NAND_CMD_SEQIN:
+               /* Use valid column/page from preread... */
+               vf610_nfc_addr_cycle(nfc, column, page);
+               nfc->buf_offset = 0;
+
+               /*
+                * SEQIN => data => PAGEPROG sequence is done by the controller
+                * hence we do not need to issue the command here...
+                */
+               return;
+       case NAND_CMD_PAGEPROG:
+               trfr_sz += nfc->write_sz;
+               vf610_nfc_transfer_size(nfc, trfr_sz);
+               vf610_nfc_send_commands(nfc, NAND_CMD_SEQIN,
+                                       command, PROGRAM_PAGE_CMD_CODE);
+               if (nfc->use_hw_ecc)
+                       vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
+               else
+                       vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+               break;
+
+       case NAND_CMD_RESET:
+               vf610_nfc_transfer_size(nfc, 0);
+               vf610_nfc_send_command(nfc, command, RESET_CMD_CODE);
+               break;
+
+       case NAND_CMD_READOOB:
+               trfr_sz += mtd->oobsize;
+               column = mtd->writesize;
+               vf610_nfc_transfer_size(nfc, trfr_sz);
+               vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
+                                       NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, column, page);
+               vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+               break;
+
+       case NAND_CMD_READ0:
+               trfr_sz += mtd->writesize + mtd->oobsize;
+               vf610_nfc_transfer_size(nfc, trfr_sz);
+               vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
+                                       NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, column, page);
+               vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
+               break;
+
+       case NAND_CMD_PARAM:
+               nfc->alt_buf = ALT_BUF_ONFI;
+               trfr_sz = 3 * sizeof(struct nand_onfi_params);
+               vf610_nfc_transfer_size(nfc, trfr_sz);
+               vf610_nfc_send_command(nfc, command, READ_ONFI_PARAM_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, -1, column);
+               vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+               break;
+
+       case NAND_CMD_ERASE1:
+               vf610_nfc_transfer_size(nfc, 0);
+               vf610_nfc_send_commands(nfc, command,
+                                       NAND_CMD_ERASE2, ERASE_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, column, page);
+               break;
+
+       case NAND_CMD_READID:
+               nfc->alt_buf = ALT_BUF_ID;
+               nfc->buf_offset = 0;
+               vf610_nfc_transfer_size(nfc, 0);
+               vf610_nfc_send_command(nfc, command, READ_ID_CMD_CODE);
+               vf610_nfc_addr_cycle(nfc, -1, column);
+               break;
+
+       case NAND_CMD_STATUS:
+               nfc->alt_buf = ALT_BUF_STAT;
+               vf610_nfc_transfer_size(nfc, 0);
+               vf610_nfc_send_command(nfc, command, STATUS_READ_CMD_CODE);
+               break;
+       default:
+               return;
+       }
+
+       vf610_nfc_done(nfc);
+
+       nfc->use_hw_ecc = false;
+       nfc->write_sz = 0;
+}
+
+static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       uint c = nfc->buf_offset;
+
+       /* Alternate buffers are only supported through read_byte */
+       WARN_ON(nfc->alt_buf);
+
+       vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
+
+       nfc->buf_offset += len;
+}
+
+static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+                               int len)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       uint c = nfc->buf_offset;
+       uint l;
+
+       l = min_t(uint, len, mtd->writesize + mtd->oobsize - c);
+       vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l);
+
+       nfc->write_sz += l;
+       nfc->buf_offset += l;
+}
+
+static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       u8 tmp;
+       uint c = nfc->buf_offset;
+
+       switch (nfc->alt_buf) {
+       case ALT_BUF_ID:
+               tmp = vf610_nfc_get_id(nfc, c);
+               break;
+       case ALT_BUF_STAT:
+               tmp = vf610_nfc_get_status(nfc);
+               break;
+#ifdef __LITTLE_ENDIAN
+       case ALT_BUF_ONFI:
+               /* Reverse byte since the controller uses big endianness */
+               c = nfc->buf_offset ^ 0x3;
+               /* fall-through */
+#endif
+       default:
+               tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
+               break;
+       }
+       nfc->buf_offset++;
+       return tmp;
+}
+
+static u16 vf610_nfc_read_word(struct mtd_info *mtd)
+{
+       u16 tmp;
+
+       vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+       return tmp;
+}
+
+/* If not provided, upper layers apply a fixed delay. */
+static int vf610_nfc_dev_ready(struct mtd_info *mtd)
+{
+       /* NFC handles R/B internally; always ready.  */
+       return 1;
+}
+
+/*
+ * This function supports Vybrid only (MPC5125 would have full RB and four CS)
+ */
+static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
+
+       /* Vybrid only (MPC5125 would have full RB and four CS) */
+       if (nfc->variant != NFC_VFC610)
+               return;
+
+       tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
+
+       if (chip >= 0) {
+               tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
+               tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
+       }
+
+       vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
+}
+
+/* Count the number of 0's in buff up to max_bits */
+static inline int count_written_bits(uint8_t *buff, int size, int max_bits)
+{
+       uint32_t *buff32 = (uint32_t *)buff;
+       int k, written_bits = 0;
+
+       for (k = 0; k < (size / 4); k++) {
+               written_bits += hweight32(~buff32[k]);
+               if (unlikely(written_bits > max_bits))
+                       break;
+       }
+
+       return written_bits;
+}
+
+static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat,
+                                        uint8_t *oob, int page)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
+       u8 ecc_status;
+       u8 ecc_count;
+       int flips;
+       int flips_threshold = nfc->chip.ecc.strength / 2;
+
+       ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff;
+       ecc_count = ecc_status & ECC_STATUS_ERR_COUNT;
+
+       if (!(ecc_status & ECC_STATUS_MASK))
+               return ecc_count;
+
+       /* Read OOB without ECC unit enabled */
+       vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page);
+       vf610_nfc_read_buf(mtd, oob, mtd->oobsize);
+
+       /*
+        * On an erased page, bit count (including OOB) should be zero or
+        * at least less then half of the ECC strength.
+        */
+       flips = count_written_bits(dat, nfc->chip.ecc.size, flips_threshold);
+       flips += count_written_bits(oob, mtd->oobsize, flips_threshold);
+
+       if (unlikely(flips > flips_threshold))
+               return -EINVAL;
+
+       /* Erased page. */
+       memset(dat, 0xff, nfc->chip.ecc.size);
+       memset(oob, 0xff, mtd->oobsize);
+       return flips;
+}
+
+static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                               uint8_t *buf, int oob_required, int page)
+{
+       int eccsize = chip->ecc.size;
+       int stat;
+
+       vf610_nfc_read_buf(mtd, buf, eccsize);
+       if (oob_required)
+               vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page);
+
+       if (stat < 0) {
+               mtd->ecc_stats.failed++;
+               return 0;
+       } else {
+               mtd->ecc_stats.corrected += stat;
+               return stat;
+       }
+}
+
+static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                              const uint8_t *buf, int oob_required)
+{
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       vf610_nfc_write_buf(mtd, buf, mtd->writesize);
+       if (oob_required)
+               vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       /* Always write whole page including OOB due to HW ECC */
+       nfc->use_hw_ecc = true;
+       nfc->write_sz = mtd->writesize + mtd->oobsize;
+
+       return 0;
+}
+
+static const struct of_device_id vf610_nfc_dt_ids[] = {
+       { .compatible = "fsl,vf610-nfc", .data = (void *)NFC_VFC610 },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vf610_nfc_dt_ids);
+
+static void vf610_nfc_preinit_controller(struct vf610_nfc *nfc)
+{
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT);
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT);
+       vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT);
+       vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT);
+
+       /* Disable virtual pages, only one elementary transfer unit */
+       vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
+                           CONFIG_PAGE_CNT_SHIFT, 1);
+}
+
+static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
+{
+       if (nfc->chip.options & NAND_BUSWIDTH_16)
+               vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+       else
+               vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
+
+       if (nfc->chip.ecc.mode == NAND_ECC_HW) {
+               /* Set ECC status offset in SRAM */
+               vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+                                   CONFIG_ECC_SRAM_ADDR_MASK,
+                                   CONFIG_ECC_SRAM_ADDR_SHIFT,
+                                   ECC_SRAM_ADDR >> 3);
+
+               /* Enable ECC status in SRAM */
+               vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
+       }
+}
+
+static int vf610_nfc_probe(struct platform_device *pdev)
+{
+       struct vf610_nfc *nfc;
+       struct resource *res;
+       struct mtd_info *mtd;
+       struct nand_chip *chip;
+       struct device_node *child;
+       const struct of_device_id *of_id;
+       int err;
+       int irq;
+
+       nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+       if (!nfc)
+               return -ENOMEM;
+
+       nfc->dev = &pdev->dev;
+       mtd = &nfc->mtd;
+       chip = &nfc->chip;
+
+       mtd->priv = chip;
+       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = nfc->dev;
+       mtd->name = DRV_NAME;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       nfc->regs = devm_ioremap_resource(nfc->dev, res);
+       if (IS_ERR(nfc->regs))
+               return PTR_ERR(nfc->regs);
+
+       nfc->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(nfc->clk))
+               return PTR_ERR(nfc->clk);
+
+       err = clk_prepare_enable(nfc->clk);
+       if (err) {
+               dev_err(nfc->dev, "Unable to enable clock!\n");
+               return err;
+       }
+
+       of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
+       nfc->variant = (enum vf610_nfc_variant)of_id->data;
+
+       for_each_available_child_of_node(nfc->dev->of_node, child) {
+               if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
+
+                       if (chip->flash_node) {
+                               dev_err(nfc->dev,
+                                       "Only one NAND chip supported!\n");
+                               err = -EINVAL;
+                               goto error;
+                       }
+
+                       chip->flash_node = child;
+               }
+       }
+
+       if (!chip->flash_node) {
+               dev_err(nfc->dev, "NAND chip sub-node missing!\n");
+               err = -ENODEV;
+               goto err_clk;
+       }
+
+       chip->dev_ready = vf610_nfc_dev_ready;
+       chip->cmdfunc = vf610_nfc_command;
+       chip->read_byte = vf610_nfc_read_byte;
+       chip->read_word = vf610_nfc_read_word;
+       chip->read_buf = vf610_nfc_read_buf;
+       chip->write_buf = vf610_nfc_write_buf;
+       chip->select_chip = vf610_nfc_select_chip;
+
+       chip->options |= NAND_NO_SUBPAGE_WRITE;
+
+       init_completion(&nfc->cmd_done);
+
+       err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd);
+       if (err) {
+               dev_err(nfc->dev, "Error requesting IRQ!\n");
+               goto error;
+       }
+
+       vf610_nfc_preinit_controller(nfc);
+
+       /* first scan to find the device and get the page size */
+       if (nand_scan_ident(mtd, 1, NULL)) {
+               err = -ENXIO;
+               goto error;
+       }
+
+       vf610_nfc_init_controller(nfc);
+
+       /* Bad block options. */
+       if (chip->bbt_options & NAND_BBT_USE_FLASH)
+               chip->bbt_options |= NAND_BBT_NO_OOB;
+
+       /* Single buffer only, max 256 OOB minus ECC status */
+       if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
+               dev_err(nfc->dev, "Unsupported flash page size\n");
+               err = -ENXIO;
+               goto error;
+       }
+
+       if (chip->ecc.mode == NAND_ECC_HW) {
+               if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
+                       dev_err(nfc->dev, "Unsupported flash with hwecc\n");
+                       err = -ENXIO;
+                       goto error;
+               }
+
+               if (chip->ecc.size != mtd->writesize) {
+                       dev_err(nfc->dev, "Step size needs to be page size\n");
+                       err = -ENXIO;
+                       goto error;
+               }
+
+               /* Only 64 byte ECC layouts known */
+               if (mtd->oobsize > 64)
+                       mtd->oobsize = 64;
+
+               if (chip->ecc.strength == 32) {
+                       nfc->ecc_mode = ECC_60_BYTE;
+                       chip->ecc.bytes = 60;
+                       chip->ecc.layout = &vf610_nfc_ecc60;
+               } else if (chip->ecc.strength == 24) {
+                       nfc->ecc_mode = ECC_45_BYTE;
+                       chip->ecc.bytes = 45;
+                       chip->ecc.layout = &vf610_nfc_ecc45;
+               } else {
+                       dev_err(nfc->dev, "Unsupported ECC strength\n");
+                       err = -ENXIO;
+                       goto error;
+               }
+
+               /* propagate ecc.layout to mtd_info */
+               mtd->ecclayout = chip->ecc.layout;
+               chip->ecc.read_page = vf610_nfc_read_page;
+               chip->ecc.write_page = vf610_nfc_write_page;
+
+               chip->ecc.size = PAGE_2K;
+       }
+
+       /* second phase scan */
+       if (nand_scan_tail(mtd)) {
+               err = -ENXIO;
+               goto error;
+       }
+
+       platform_set_drvdata(pdev, mtd);
+
+       /* Register device in MTD */
+       return mtd_device_parse_register(mtd, NULL,
+               &(struct mtd_part_parser_data){
+                       .of_node = chip->flash_node,
+               },
+               NULL, 0);
+
+error:
+       of_node_put(chip->flash_node);
+err_clk:
+       clk_disable_unprepare(nfc->clk);
+       return err;
+}
+
+static int vf610_nfc_remove(struct platform_device *pdev)
+{
+       struct mtd_info *mtd = platform_get_drvdata(pdev);
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       nand_release(mtd);
+       clk_disable_unprepare(nfc->clk);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int vf610_nfc_suspend(struct device *dev)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       clk_disable_unprepare(nfc->clk);
+       return 0;
+}
+
+static int vf610_nfc_resume(struct device *dev)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+       pinctrl_pm_select_default_state(dev);
+
+       clk_prepare_enable(nfc->clk);
+
+       vf610_nfc_preinit_controller(nfc);
+       vf610_nfc_init_controller(nfc);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(vf610_nfc_pm_ops, vf610_nfc_suspend, vf610_nfc_resume);
+
+static struct platform_driver vf610_nfc_driver = {
+       .driver         = {
+               .name   = DRV_NAME,
+               .of_match_table = vf610_nfc_dt_ids,
+               .pm     = &vf610_nfc_pm_ops,
+       },
+       .probe          = vf610_nfc_probe,
+       .remove         = vf610_nfc_remove,
+};
+
+module_platform_driver(vf610_nfc_driver);
+
+MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
+MODULE_DESCRIPTION("Freescale VF610/MPC5125 NFC MTD NAND driver");
+MODULE_LICENSE("GPL");
index d32b7e0..2954f89 100644 (file)
@@ -259,7 +259,6 @@ static struct fsl_qspi_devtype_data imx6ul_data = {
 
 #define FSL_QSPI_MAX_CHIP      4
 struct fsl_qspi {
-       struct mtd_info mtd[FSL_QSPI_MAX_CHIP];
        struct spi_nor nor[FSL_QSPI_MAX_CHIP];
        void __iomem *iobase;
        void __iomem *ahb_addr;
@@ -798,8 +797,7 @@ static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
        return 0;
 }
 
-static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
-                       int write_enable)
+static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
        struct fsl_qspi *q = nor->priv;
        int ret;
@@ -888,7 +886,7 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
        int ret;
 
        dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
-               nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs);
+               nor->mtd.erasesize / 1024, q->chip_base_addr, (u32)offs);
 
        ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0);
        if (ret)
@@ -1006,19 +1004,16 @@ static int fsl_qspi_probe(struct platform_device *pdev)
 
        /* iterate the subnodes. */
        for_each_available_child_of_node(dev->of_node, np) {
-               char modalias[40];
-
                /* skip the holes */
                if (!q->has_second_chip)
                        i *= 2;
 
                nor = &q->nor[i];
-               mtd = &q->mtd[i];
+               mtd = &nor->mtd;
 
-               nor->mtd = mtd;
                nor->dev = dev;
+               nor->flash_node = np;
                nor->priv = q;
-               mtd->priv = nor;
 
                /* fill the hooks */
                nor->read_reg = fsl_qspi_read_reg;
@@ -1030,10 +1025,6 @@ static int fsl_qspi_probe(struct platform_device *pdev)
                nor->prepare = fsl_qspi_prep;
                nor->unprepare = fsl_qspi_unprep;
 
-               ret = of_modalias_node(np, modalias, sizeof(modalias));
-               if (ret < 0)
-                       goto mutex_failed;
-
                ret = of_property_read_u32(np, "spi-max-frequency",
                                &q->clk_rate);
                if (ret < 0)
@@ -1042,7 +1033,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
                /* set the chip address for READID */
                fsl_qspi_set_base_addr(q, nor);
 
-               ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD);
+               ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
                if (ret)
                        goto mutex_failed;
 
@@ -1087,7 +1078,7 @@ last_init_failed:
                /* skip the holes */
                if (!q->has_second_chip)
                        i *= 2;
-               mtd_device_unregister(&q->mtd[i]);
+               mtd_device_unregister(&q->nor[i].mtd);
        }
 mutex_failed:
        mutex_destroy(&q->lock);
@@ -1107,7 +1098,7 @@ static int fsl_qspi_remove(struct platform_device *pdev)
                /* skip the holes */
                if (!q->has_second_chip)
                        i *= 2;
-               mtd_device_unregister(&q->mtd[i]);
+               mtd_device_unregister(&q->nor[i].mtd);
        }
 
        /* disable the hardware */
index 9ad1dd0..9e82098 100644 (file)
@@ -60,7 +60,6 @@ struct nxp_spifi {
        struct clk *clk_reg;
        void __iomem *io_base;
        void __iomem *flash_base;
-       struct mtd_info mtd;
        struct spi_nor nor;
        bool memory_mode;
        u32 mcmd;
@@ -150,8 +149,7 @@ static int nxp_spifi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
        return nxp_spifi_wait_for_cmd(spifi);
 }
 
-static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
-                              int len, int write_enable)
+static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 {
        struct nxp_spifi *spifi = nor->priv;
        u32 cmd;
@@ -331,9 +329,8 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
 
        writel(ctrl, spifi->io_base + SPIFI_CTRL);
 
-       spifi->mtd.priv  = &spifi->nor;
-       spifi->nor.mtd   = &spifi->mtd;
        spifi->nor.dev   = spifi->dev;
+       spifi->nor.flash_node = np;
        spifi->nor.priv  = spifi;
        spifi->nor.read  = nxp_spifi_read;
        spifi->nor.write = nxp_spifi_write;
@@ -365,7 +362,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
        }
 
        ppdata.of_node = np;
-       ret = mtd_device_parse_register(&spifi->mtd, NULL, &ppdata, NULL, 0);
+       ret = mtd_device_parse_register(&spifi->nor.mtd, NULL, &ppdata, NULL, 0);
        if (ret) {
                dev_err(spifi->dev, "mtd device parse failed\n");
                return ret;
@@ -454,7 +451,7 @@ static int nxp_spifi_remove(struct platform_device *pdev)
 {
        struct nxp_spifi *spifi = platform_get_drvdata(pdev);
 
-       mtd_device_unregister(&spifi->mtd);
+       mtd_device_unregister(&spifi->nor.mtd);
        clk_disable_unprepare(spifi->clk_spifi);
        clk_disable_unprepare(spifi->clk_reg);
 
index f59aedf..4be41fb 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/math64.h>
+#include <linux/sizes.h>
 
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/spi-nor.h>
 
 /* Define max times to check status register before we give up. */
-#define        MAX_READY_WAIT_JIFFIES  (40 * HZ) /* M25P16 specs 40s max chip erase */
+
+/*
+ * For everything but full-chip erase; probably could be much smaller, but kept
+ * around for safety for now
+ */
+#define DEFAULT_READY_WAIT_JIFFIES             (40UL * HZ)
+
+/*
+ * For full-chip erase, calibrated to a 2MB flash (M25P16); should be scaled up
+ * for larger flash
+ */
+#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES      (40UL * HZ)
 
 #define SPI_NOR_MAX_ID_LEN     6
 
@@ -145,7 +157,7 @@ static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
 static inline int write_sr(struct spi_nor *nor, u8 val)
 {
        nor->cmd_buf[0] = val;
-       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
+       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
 }
 
 /*
@@ -154,7 +166,7 @@ static inline int write_sr(struct spi_nor *nor, u8 val)
  */
 static inline int write_enable(struct spi_nor *nor)
 {
-       return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
+       return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
 }
 
 /*
@@ -162,7 +174,7 @@ static inline int write_enable(struct spi_nor *nor)
  */
 static inline int write_disable(struct spi_nor *nor)
 {
-       return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0, 0);
+       return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
 }
 
 static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
@@ -188,7 +200,7 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
                        write_enable(nor);
 
                cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
-               status = nor->write_reg(nor, cmd, NULL, 0, 0);
+               status = nor->write_reg(nor, cmd, NULL, 0);
                if (need_wren)
                        write_disable(nor);
 
@@ -196,7 +208,7 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
        default:
                /* Spansion style */
                nor->cmd_buf[0] = enable << 7;
-               return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1, 0);
+               return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
        }
 }
 static inline int spi_nor_sr_ready(struct spi_nor *nor)
@@ -233,12 +245,13 @@ static int spi_nor_ready(struct spi_nor *nor)
  * Service routine to read status register until ready, or timeout occurs.
  * Returns non-zero if error.
  */
-static int spi_nor_wait_till_ready(struct spi_nor *nor)
+static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
+                                               unsigned long timeout_jiffies)
 {
        unsigned long deadline;
        int timeout = 0, ret;
 
-       deadline = jiffies + MAX_READY_WAIT_JIFFIES;
+       deadline = jiffies + timeout_jiffies;
 
        while (!timeout) {
                if (time_after_eq(jiffies, deadline))
@@ -258,6 +271,12 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor)
        return -ETIMEDOUT;
 }
 
+static int spi_nor_wait_till_ready(struct spi_nor *nor)
+{
+       return spi_nor_wait_till_ready_with_timeout(nor,
+                                                   DEFAULT_READY_WAIT_JIFFIES);
+}
+
 /*
  * Erase the whole flash memory
  *
@@ -265,9 +284,9 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor)
  */
 static int erase_chip(struct spi_nor *nor)
 {
-       dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd->size >> 10));
+       dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
 
-       return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0, 0);
+       return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
 }
 
 static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
@@ -321,6 +340,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 
        /* whole-chip erase? */
        if (len == mtd->size) {
+               unsigned long timeout;
+
                write_enable(nor);
 
                if (erase_chip(nor)) {
@@ -328,7 +349,16 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
                        goto erase_err;
                }
 
-               ret = spi_nor_wait_till_ready(nor);
+               /*
+                * Scale the timeout linearly with the size of the flash, with
+                * a minimum calibrated to an old 2MB flash. We could try to
+                * pull these from CFI/SFDP, but these values should be good
+                * enough for now.
+                */
+               timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
+                             CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
+                             (unsigned long)(mtd->size / SZ_2M));
+               ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
                if (ret)
                        goto erase_err;
 
@@ -373,7 +403,7 @@ erase_err:
 
 static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
-       struct mtd_info *mtd = nor->mtd;
+       struct mtd_info *mtd = &nor->mtd;
        uint32_t offset = ofs;
        uint8_t status_old, status_new;
        int ret = 0;
@@ -407,7 +437,7 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 
 static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
-       struct mtd_info *mtd = nor->mtd;
+       struct mtd_info *mtd = &nor->mtd;
        uint32_t offset = ofs;
        uint8_t status_old, status_new;
        int ret = 0;
@@ -618,8 +648,8 @@ static const struct flash_info spi_nor_ids[] = {
        { "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
        { "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
        { "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
-       { "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
-       { "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
+       { "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
        { "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, SECT_4K) },
        { "s25fl164k",  INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
@@ -635,6 +665,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
        { "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
        { "sst25wf020a", INFO(0x621612, 0, 64 * 1024,  4, SECT_4K) },
+       { "sst25wf040b", INFO(0x621613, 0, 64 * 1024,  8, SECT_4K) },
        { "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
        { "sst25wf080",  INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
 
@@ -687,6 +718,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K) },
+       { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
        { "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
@@ -868,8 +900,7 @@ static int macronix_quad_enable(struct spi_nor *nor)
        val = read_sr(nor);
        write_enable(nor);
 
-       nor->cmd_buf[0] = val | SR_QUAD_EN_MX;
-       nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
+       write_sr(nor, val | SR_QUAD_EN_MX);
 
        if (spi_nor_wait_till_ready(nor))
                return 1;
@@ -894,7 +925,7 @@ static int write_sr_cr(struct spi_nor *nor, u16 val)
        nor->cmd_buf[0] = val & 0xff;
        nor->cmd_buf[1] = (val >> 8);
 
-       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2, 0);
+       return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
 }
 
 static int spansion_quad_enable(struct spi_nor *nor)
@@ -936,7 +967,7 @@ static int micron_quad_enable(struct spi_nor *nor)
 
        /* set EVCR, enable quad I/O */
        nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
-       ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0);
+       ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
        if (ret < 0) {
                dev_err(nor->dev, "error while writing EVCR register\n");
                return ret;
@@ -1004,8 +1035,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 {
        const struct flash_info *info = NULL;
        struct device *dev = nor->dev;
-       struct mtd_info *mtd = nor->mtd;
-       struct device_node *np = dev->of_node;
+       struct mtd_info *mtd = &nor->mtd;
+       struct device_node *np = nor->flash_node;
        int ret;
        int i;
 
@@ -1061,6 +1092,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
        if (!mtd->name)
                mtd->name = dev_name(dev);
+       mtd->priv = nor;
        mtd->type = MTD_NORFLASH;
        mtd->writesize = 1;
        mtd->flags = MTD_CAP_NORFLASH;
index 8118002..d211b8e 100644 (file)
@@ -621,9 +621,6 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode
        uint32_t alloclen;
        int ret;
 
-       if (!new_valid_dev(rdev))
-               return -EINVAL;
-
        ri = jffs2_alloc_raw_inode();
        if (!ri)
                return -ENOMEM;
index b8fd651..ce11897 100644 (file)
@@ -97,25 +97,16 @@ int __init jffs2_create_slab_caches(void)
 
 void jffs2_destroy_slab_caches(void)
 {
-       if(full_dnode_slab)
-               kmem_cache_destroy(full_dnode_slab);
-       if(raw_dirent_slab)
-               kmem_cache_destroy(raw_dirent_slab);
-       if(raw_inode_slab)
-               kmem_cache_destroy(raw_inode_slab);
-       if(tmp_dnode_info_slab)
-               kmem_cache_destroy(tmp_dnode_info_slab);
-       if(raw_node_ref_slab)
-               kmem_cache_destroy(raw_node_ref_slab);
-       if(node_frag_slab)
-               kmem_cache_destroy(node_frag_slab);
-       if(inode_cache_slab)
-               kmem_cache_destroy(inode_cache_slab);
+       kmem_cache_destroy(full_dnode_slab);
+       kmem_cache_destroy(raw_dirent_slab);
+       kmem_cache_destroy(raw_inode_slab);
+       kmem_cache_destroy(tmp_dnode_info_slab);
+       kmem_cache_destroy(raw_node_ref_slab);
+       kmem_cache_destroy(node_frag_slab);
+       kmem_cache_destroy(inode_cache_slab);
 #ifdef CONFIG_JFFS2_FS_XATTR
-       if (xattr_datum_cache)
-               kmem_cache_destroy(xattr_datum_cache);
-       if (xattr_ref_cache)
-               kmem_cache_destroy(xattr_ref_cache);
+       kmem_cache_destroy(xattr_datum_cache);
+       kmem_cache_destroy(xattr_ref_cache);
 #endif
 }
 
index 09ed551..63f31c0 100644 (file)
@@ -1274,7 +1274,6 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
 #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
        c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
        if (!c->wbuf_verify) {
-               kfree(c->oobbuf);
                kfree(c->wbuf);
                return -ENOMEM;
        }
diff --git a/include/linux/blkpg.h b/include/linux/blkpg.h
new file mode 100644 (file)
index 0000000..bef124f
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _LINUX_BLKPG_H
+#define _LINUX_BLKPG_H
+
+/*
+ * Partition table and disk geometry handling
+ */
+
+#include <linux/compat.h>
+#include <uapi/linux/blkpg.h>
+
+#ifdef CONFIG_COMPAT
+/* For 32-bit/64-bit compatibility of struct blkpg_ioctl_arg */
+struct blkpg_compat_ioctl_arg {
+       compat_int_t op;
+       compat_int_t flags;
+       compat_int_t datalen;
+       compat_uptr_t data;
+};
+#endif
+
+#endif /* _LINUX_BLKPG_H */
index 272f429..c4d8e30 100644 (file)
@@ -544,7 +544,7 @@ struct nand_buffers {
  *                     flash device
  * @IO_ADDR_W:         [BOARDSPECIFIC] address to write the 8 I/O lines of the
  *                     flash device.
- * @dn:                        [BOARDSPECIFIC] device node describing this instance
+ * @flash_node:                [BOARDSPECIFIC] device node describing this instance
  * @read_byte:         [REPLACEABLE] read one byte from the chip
  * @read_word:         [REPLACEABLE] read one word from the chip
  * @write_byte:                [REPLACEABLE] write a single byte to the chip on the
@@ -647,7 +647,7 @@ struct nand_chip {
        void __iomem *IO_ADDR_R;
        void __iomem *IO_ADDR_W;
 
-       struct device_node *dn;
+       struct device_node *flash_node;
 
        uint8_t (*read_byte)(struct mtd_info *mtd);
        u16 (*read_word)(struct mtd_info *mtd);
@@ -1030,4 +1030,9 @@ struct nand_sdr_timings {
 
 /* get timing characteristics from ONFI timing mode. */
 const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
+
+int nand_check_erased_ecc_chunk(void *data, int datalen,
+                               void *ecc, int ecclen,
+                               void *extraoob, int extraooblen,
+                               int threshold);
 #endif /* __LINUX_MTD_NAND_H */
index e540952..672595a 100644 (file)
@@ -87,33 +87,6 @@ enum read_mode {
        SPI_NOR_QUAD,
 };
 
-/**
- * struct spi_nor_xfer_cfg - Structure for defining a Serial Flash transfer
- * @wren:              command for "Write Enable", or 0x00 for not required
- * @cmd:               command for operation
- * @cmd_pins:          number of pins to send @cmd (1, 2, 4)
- * @addr:              address for operation
- * @addr_pins:         number of pins to send @addr (1, 2, 4)
- * @addr_width:                number of address bytes
- *                     (3,4, or 0 for address not required)
- * @mode:              mode data
- * @mode_pins:         number of pins to send @mode (1, 2, 4)
- * @mode_cycles:       number of mode cycles (0 for mode not required)
- * @dummy_cycles:      number of dummy cycles (0 for dummy not required)
- */
-struct spi_nor_xfer_cfg {
-       u8              wren;
-       u8              cmd;
-       u8              cmd_pins;
-       u32             addr;
-       u8              addr_pins;
-       u8              addr_width;
-       u8              mode;
-       u8              mode_pins;
-       u8              mode_cycles;
-       u8              dummy_cycles;
-};
-
 #define SPI_NOR_MAX_CMD_SIZE   8
 enum spi_nor_ops {
        SPI_NOR_OPS_READ = 0,
@@ -127,11 +100,14 @@ enum spi_nor_option_flags {
        SNOR_F_USE_FSR          = BIT(0),
 };
 
+struct mtd_info;
+
 /**
  * struct spi_nor - Structure for defining a the SPI NOR layer
  * @mtd:               point to a mtd_info structure
  * @lock:              the lock for the read/write/erase/lock/unlock operations
  * @dev:               point to a spi device, or a spi nor controller device.
+ * @flash_node:                point to a device node describing this flash instance.
  * @page_size:         the page size of the SPI NOR
  * @addr_width:                number of address bytes
  * @erase_opcode:      the opcode for erasing a sector
@@ -141,14 +117,11 @@ enum spi_nor_option_flags {
  * @flash_read:                the mode of the read
  * @sst_write_second:  used by the SST write operation
  * @flags:             flag options for the current SPI-NOR (SNOR_F_*)
- * @cfg:               used by the read_xfer/write_xfer
  * @cmd_buf:           used by the write_reg
  * @prepare:           [OPTIONAL] do some preparations for the
  *                     read/write/erase/lock/unlock operations
  * @unprepare:         [OPTIONAL] do some post work after the
  *                     read/write/erase/lock/unlock operations
- * @read_xfer:         [OPTIONAL] the read fundamental primitive
- * @write_xfer:                [OPTIONAL] the writefundamental primitive
  * @read_reg:          [DRIVER-SPECIFIC] read out the register
  * @write_reg:         [DRIVER-SPECIFIC] write data to the register
  * @read:              [DRIVER-SPECIFIC] read data from the SPI NOR
@@ -160,9 +133,10 @@ enum spi_nor_option_flags {
  * @priv:              the private data
  */
 struct spi_nor {
-       struct mtd_info         *mtd;
+       struct mtd_info         mtd;
        struct mutex            lock;
        struct device           *dev;
+       struct device_node      *flash_node;
        u32                     page_size;
        u8                      addr_width;
        u8                      erase_opcode;
@@ -172,18 +146,12 @@ struct spi_nor {
        enum read_mode          flash_read;
        bool                    sst_write_second;
        u32                     flags;
-       struct spi_nor_xfer_cfg cfg;
        u8                      cmd_buf[SPI_NOR_MAX_CMD_SIZE];
 
        int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
        void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
-       int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
-                        u8 *buf, size_t len);
-       int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
-                         u8 *buf, size_t len);
        int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
-       int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
-                       int write_enable);
+       int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
 
        int (*read)(struct spi_nor *nor, loff_t from,
                        size_t len, size_t *retlen, u_char *read_buf);
index ac4ea2e..394d155 100644 (file)
@@ -4,30 +4,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-struct pxa3xx_nand_timing {
-       unsigned int    tCH;  /* Enable signal hold time */
-       unsigned int    tCS;  /* Enable signal setup time */
-       unsigned int    tWH;  /* ND_nWE high duration */
-       unsigned int    tWP;  /* ND_nWE pulse time */
-       unsigned int    tRH;  /* ND_nRE high duration */
-       unsigned int    tRP;  /* ND_nRE pulse width */
-       unsigned int    tR;   /* ND_nWE high to ND_nRE low for read */
-       unsigned int    tWHR; /* ND_nWE high to ND_nRE low for status read */
-       unsigned int    tAR;  /* ND_ALE low to ND_nRE low delay */
-};
-
-struct pxa3xx_nand_flash {
-       char            *name;
-       uint32_t        chip_id;
-       unsigned int    page_per_block; /* Pages per block (PG_PER_BLK) */
-       unsigned int    page_size;      /* Page size in bytes (PAGE_SZ) */
-       unsigned int    flash_width;    /* Width of Flash memory (DWIDTH_M) */
-       unsigned int    dfc_width;      /* Width of flash controller(DWIDTH_C) */
-       unsigned int    num_blocks;     /* Number of physical blocks in Flash */
-
-       struct pxa3xx_nand_timing *timing;      /* NAND Flash timing */
-};
-
 /*
  * Current pxa3xx_nand controller has two chip select which
  * both be workable.
@@ -63,9 +39,6 @@ struct pxa3xx_nand_platform_data {
 
        const struct mtd_partition              *parts[NUM_CHIP_SELECT];
        unsigned int                            nr_parts[NUM_CHIP_SELECT];
-
-       const struct pxa3xx_nand_flash *        flash;
-       size_t                                  num_flash;
 };
 
 extern void pxa3xx_set_nand_info(struct pxa3xx_nand_platform_data *info);
index a851944..63739a0 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _LINUX_BLKPG_H
-#define _LINUX_BLKPG_H
+#ifndef _UAPI__LINUX_BLKPG_H
+#define _UAPI__LINUX_BLKPG_H
 
 /*
  * Partition table and disk geometry handling
@@ -56,4 +56,4 @@ struct blkpg_partition {
        char volname[BLKPG_VOLNAMELTH]; /* volume label */
 };
 
-#endif /* _LINUX_BLKPG_H */
+#endif /* _UAPI__LINUX_BLKPG_H */