]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'l2-mtd/master'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 11 Feb 2016 01:07:33 +0000 (12:07 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 11 Feb 2016 01:07:33 +0000 (12:07 +1100)
27 files changed:
arch/arm/plat-samsung/devs.c
arch/mips/include/asm/mach-jz4740/jz4740_nand.h
drivers/memory/fsl_ifc.c
drivers/mtd/bcm47xxpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/nand/vf610_nfc.c
drivers/mtd/onenand/onenand_bbt.c
drivers/mtd/spi-nor/Kconfig
drivers/mtd/spi-nor/mtk-quadspi.c
drivers/staging/mt29f_spinand/mt29f_spinand.h
include/linux/mtd/bbm.h
include/linux/mtd/inftl.h
include/linux/mtd/nand.h
include/linux/mtd/nftl.h
include/linux/platform_data/mtd-nand-s3c2410.h

index b53d4ff3befb69a5e692640443674bca83129f83..84baa16f4c0b674dfe404b54bb9fe09b4fd682bf 100644 (file)
@@ -727,15 +727,6 @@ static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set)
                        return -ENOMEM;
        }
 
-       if (set->ecc_layout) {
-               ptr = kmemdup(set->ecc_layout,
-                             sizeof(struct nand_ecclayout), GFP_KERNEL);
-               set->ecc_layout = ptr;
-
-               if (!ptr)
-                       return -ENOMEM;
-       }
-
        return 0;
 }
 
index 79cff26d8b36f16cb333d9af2e56383db72b4222..398733e3e2cf65006541cf5c3eff6c68b06b0eb0 100644 (file)
@@ -25,8 +25,6 @@ struct jz_nand_platform_data {
        int                     num_partitions;
        struct mtd_partition    *partitions;
 
-       struct nand_ecclayout   *ecc_layout;
-
        unsigned char banks[JZ_NAND_NUM_BANKS];
 
        void (*ident_callback)(struct platform_device *, struct nand_chip *,
index acd1460cf7871c4ef4cffb0f0e196f41083aae36..2a691da8c1c7c0441c08d97a8d1e711099a32299 100644 (file)
@@ -260,7 +260,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
 
        /* get the Controller level irq */
        fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
-       if (fsl_ifc_ctrl_dev->irq == NO_IRQ) {
+       if (fsl_ifc_ctrl_dev->irq == 0) {
                dev_err(&dev->dev, "failed to get irq resource "
                                                        "for IFC\n");
                ret = -ENODEV;
index 8282f47bcf5d374e03d343453d62ee0bc4851785..845dd27d9f417a07cb6a55000f44504e55b3451c 100644 (file)
@@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
 {
        uint32_t buf;
        size_t bytes_read;
+       int err;
 
-       if (mtd_read(master, offset, sizeof(buf), &bytes_read,
-                    (uint8_t *)&buf) < 0) {
-               pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
-                       offset);
+       err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
+                       (uint8_t *)&buf);
+       if (err && !mtd_is_bitflip(err)) {
+               pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+                       offset, err);
                goto out_default;
        }
 
@@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_info *master,
        int trx_part = -1;
        int last_trx_part = -1;
        int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
+       int err;
 
        /*
         * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
@@ -118,8 +121,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
        /* Parse block by block looking for magics */
        for (offset = 0; offset <= master->size - blocksize;
             offset += blocksize) {
-               /* Nothing more in higher memory */
-               if (offset >= 0x2000000)
+               /* Nothing more in higher memory on BCM47XX (MIPS) */
+               if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
                        break;
 
                if (curr_part >= BCM47XXPART_MAX_PARTS) {
@@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                }
 
                /* Read beginning of the block */
-               if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
-                            &bytes_read, (uint8_t *)buf) < 0) {
-                       pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
-                              offset);
+               err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+                              &bytes_read, (uint8_t *)buf);
+               if (err && !mtd_is_bitflip(err)) {
+                       pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+                              offset, err);
                        continue;
                }
 
@@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                }
 
                /* Read middle of the block */
-               if (mtd_read(master, offset + 0x8000, 0x4,
-                            &bytes_read, (uint8_t *)buf) < 0) {
-                       pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
-                              offset);
+               err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
+                              (uint8_t *)buf);
+               if (err && !mtd_is_bitflip(err)) {
+                       pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
+                              offset, err);
                        continue;
                }
 
@@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                }
 
                offset = master->size - possible_nvram_sizes[i];
-               if (mtd_read(master, offset, 0x4, &bytes_read,
-                            (uint8_t *)buf) < 0) {
-                       pr_err("mtd_read error while reading at offset 0x%X!\n",
-                              offset);
+               err = mtd_read(master, offset, 0x4, &bytes_read,
+                              (uint8_t *)buf);
+               if (err && !mtd_is_bitflip(err)) {
+                       pr_err("mtd_read error while reading (offset 0x%X): %d\n",
+                              offset, err);
                        continue;
                }
 
index 20f01b3ec23d7dc29b5b4d4326cd4fc0d766d6be..b253654140d065405bf258ca339c80895b88e77c 100644 (file)
@@ -74,6 +74,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
 config MTD_NAND_GPIO
        tristate "GPIO assisted NAND Flash driver"
        depends on GPIOLIB || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          This enables a NAND flash driver where control signals are
          connected to GPIO pins, and commands and data are communicated
@@ -310,6 +311,7 @@ config MTD_NAND_CAFE
 config MTD_NAND_CS553X
        tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
        depends on X86_32
+       depends on !UML && HAS_IOMEM
        help
          The CS553x companion chips for the AMD Geode processor
          include NAND flash controllers with built-in hardware ECC
@@ -463,6 +465,7 @@ config MTD_NAND_MPC5121_NFC
 config MTD_NAND_VF610_NFC
        tristate "Support for Freescale NFC for VF610/MPC5125"
        depends on (SOC_VF610 || COMPILE_TEST)
+       depends on HAS_IOMEM
        help
          Enables support for NAND Flash Controller on some Freescale
          processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
index bddcf83d6859aecd689797c99d5745569f39b713..affe7a7e9ad7dcefa1e25366b5a21cf07454f3ad 100644 (file)
@@ -825,7 +825,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
                        *(buf + byte_pos) ^= (1 << bit_pos);
 
                        pos = sector_num * host->pmecc_sector_size + byte_pos;
-                       dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+                       dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
                                pos, bit_pos, err_byte, *(buf + byte_pos));
                } else {
                        /* Bit flip in OOB area */
@@ -835,7 +835,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
                        ecc[tmp] ^= (1 << bit_pos);
 
                        pos = tmp + nand_chip->ecc.layout->eccpos[0];
-                       dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+                       dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
                                pos, bit_pos, err_byte, ecc[tmp]);
                }
 
@@ -1486,8 +1486,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
                ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
 }
 
-static const struct of_device_id atmel_nand_dt_ids[];
-
 static int atmel_of_init_port(struct atmel_nand_host *host,
                              struct device_node *np)
 {
@@ -1498,7 +1496,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
        enum of_gpio_flags flags = 0;
 
        host->caps = (struct atmel_nand_caps *)
-               of_match_device(atmel_nand_dt_ids, host->dev)->data;
+               of_device_get_match_data(host->dev);
 
        if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
                if (val >= 32) {
@@ -1550,7 +1548,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
                if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
                                (val != 24)) {
                        dev_err(host->dev,
-                               "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
+                               "Required ECC strength not supported: %u\n",
                                val);
                        return -EINVAL;
                }
@@ -1560,7 +1558,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
        if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) == 0) {
                if ((val != 512) && (val != 1024)) {
                        dev_err(host->dev,
-                               "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
+                               "Required ECC sector size not supported: %u\n",
                                val);
                        return -EINVAL;
                }
index 235ddcb58f39932fbd41aa949170000b9dee8891..8122c699ccf20895e400b8ae9246b39db00b1f00 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Freescale GPMI NAND Flash Driver
  *
- * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
  * Copyright (C) 2008 Embedded Alley Solutions, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -136,7 +136,7 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
  *
  * We may have available oob space in this case.
  */
-static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
+static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
 {
        struct bch_geometry *geo = &this->bch_geometry;
        struct nand_chip *chip = &this->nand;
@@ -145,7 +145,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
        unsigned int block_mark_bit_offset;
 
        if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
-               return false;
+               return -EINVAL;
 
        switch (chip->ecc_step_ds) {
        case SZ_512:
@@ -158,19 +158,19 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
                dev_err(this->dev,
                        "unsupported nand chip. ecc bits : %d, ecc size : %d\n",
                        chip->ecc_strength_ds, chip->ecc_step_ds);
-               return false;
+               return -EINVAL;
        }
        geo->ecc_chunk_size = chip->ecc_step_ds;
        geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
        if (!gpmi_check_ecc(this))
-               return false;
+               return -EINVAL;
 
        /* Keep the C >= O */
        if (geo->ecc_chunk_size < mtd->oobsize) {
                dev_err(this->dev,
                        "unsupported nand chip. ecc size: %d, oob size : %d\n",
                        chip->ecc_step_ds, mtd->oobsize);
-               return false;
+               return -EINVAL;
        }
 
        /* The default value, see comment in the legacy_set_geometry(). */
@@ -242,7 +242,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
                                + ALIGN(geo->ecc_chunk_count, 4);
 
        if (!this->swap_block_mark)
-               return true;
+               return 0;
 
        /* For bit swap. */
        block_mark_bit_offset = mtd->writesize * 8 -
@@ -251,7 +251,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
 
        geo->block_mark_byte_offset = block_mark_bit_offset / 8;
        geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
-       return true;
+       return 0;
 }
 
 static int legacy_set_geometry(struct gpmi_nand_data *this)
@@ -285,7 +285,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
        geo->ecc_strength = get_ecc_strength(this);
        if (!gpmi_check_ecc(this)) {
                dev_err(this->dev,
-                       "required ecc strength of the NAND chip: %d is not supported by the GPMI controller (%d)\n",
+                       "ecc strength: %d cannot be supported by the controller (%d)\n"
+                       "try to use minimum ecc strength that NAND chip required\n",
                        geo->ecc_strength,
                        this->devdata->bch_max_ecc_strength);
                return -EINVAL;
@@ -366,10 +367,11 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
 
 int common_nfc_set_geometry(struct gpmi_nand_data *this)
 {
-       if (of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc")
-               && set_geometry_by_ecc_info(this))
-               return 0;
-       return legacy_set_geometry(this);
+       if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
+                               || legacy_set_geometry(this))
+               return set_geometry_by_ecc_info(this);
+
+       return 0;
 }
 
 struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
@@ -2033,9 +2035,54 @@ static int gpmi_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int gpmi_pm_suspend(struct device *dev)
+{
+       struct gpmi_nand_data *this = dev_get_drvdata(dev);
+
+       release_dma_channels(this);
+       return 0;
+}
+
+static int gpmi_pm_resume(struct device *dev)
+{
+       struct gpmi_nand_data *this = dev_get_drvdata(dev);
+       int ret;
+
+       ret = acquire_dma_channels(this);
+       if (ret < 0)
+               return ret;
+
+       /* re-init the GPMI registers */
+       this->flags &= ~GPMI_TIMING_INIT_OK;
+       ret = gpmi_init(this);
+       if (ret) {
+               dev_err(this->dev, "Error setting GPMI : %d\n", ret);
+               return ret;
+       }
+
+       /* re-init the BCH registers */
+       ret = bch_set_geometry(this);
+       if (ret) {
+               dev_err(this->dev, "Error setting BCH : %d\n", ret);
+               return ret;
+       }
+
+       /* re-init others */
+       gpmi_extra_init(this);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops gpmi_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
+};
+
 static struct platform_driver gpmi_nand_driver = {
        .driver = {
                .name = "gpmi-nand",
+               .pm = &gpmi_pm_ops,
                .of_match_table = gpmi_nand_id_table,
        },
        .probe   = gpmi_nand_probe,
index b19d2a9a5eb97cb36ab64ca4108c5ff9fceb5ca2..673ceb2a0b44b677231e030aa8a0f23a5d412e3a 100644 (file)
@@ -427,9 +427,6 @@ static int jz_nand_probe(struct platform_device *pdev)
        chip->ecc.strength      = 4;
        chip->ecc.options       = NAND_ECC_GENERIC_ERASED_CHECK;
 
-       if (pdata)
-               chip->ecc.layout = pdata->ecc_layout;
-
        chip->chip_delay = 50;
        chip->cmd_ctrl = jz_nand_cmd_ctrl;
        chip->select_chip = jz_nand_select_chip;
index 9bc435d72a861b2a75d650f943a7522dd7e317ac..d8c3e7afcc0bfa74c5d0a87e580ca53a6b28e916 100644 (file)
@@ -750,7 +750,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
 
        nand_chip->ecc.mode = NAND_ECC_HW;
-       nand_chip->ecc.size = mtd->writesize;
+       nand_chip->ecc.size = 512;
        nand_chip->ecc.layout = &lpc32xx_nand_oob;
        host->mlcsubpages = mtd->writesize / 512;
 
index 6b93e899d4e95faf9372689bb290ec0d22b946e6..5d7843ffff6ac0c85c8a5cc9a11901eb603fdd1b 100644 (file)
@@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
 
 static int mpc5121_nfc_probe(struct platform_device *op)
 {
-       struct device_node *rootnode, *dn = op->dev.of_node;
+       struct device_node *dn = op->dev.of_node;
        struct clk *clk;
        struct device *dev = &op->dev;
        struct mpc5121_nfc_prv *prv;
@@ -712,18 +712,15 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        chip->ecc.mode = NAND_ECC_SOFT;
 
        /* Support external chip-select logic on ADS5121 board */
-       rootnode = of_find_node_by_path("/");
-       if (of_device_is_compatible(rootnode, "fsl,mpc5121ads")) {
+       if (of_machine_is_compatible("fsl,mpc5121ads")) {
                retval = ads5121_chipselect_init(mtd);
                if (retval) {
                        dev_err(dev, "Chipselect init error!\n");
-                       of_node_put(rootnode);
                        return retval;
                }
 
                chip->select_chip = ads5121_select_chip;
        }
-       of_node_put(rootnode);
 
        /* Enable NFC clock */
        clk = devm_clk_get(dev, "ipg");
index 4b6a7085b442deaf3a25216415f5a347ae232281..2fbb523df066840d0919ad9e918d02dbd19ac21c 100644 (file)
@@ -1373,5 +1373,3 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
 
        return ret;
 }
-
-EXPORT_SYMBOL(nand_scan_bbt);
index a8804a3da0760968db677406d30446c5ca3162ff..ccc05f5b2695f935aa374ce4f3bb7b50e07aa879 100644 (file)
@@ -50,8 +50,8 @@ struct nand_flash_dev nand_flash_ids[] = {
                  SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
        {"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
                { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
-                 SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
-                 4 },
+                 SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
+                 NAND_ECC_INFO(40, SZ_1K), 4 },
 
        LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
        LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
index 220ddfcf29f52535cd077f99ab5821a572962412..dbc5b571c2bbcca6a570e5855d2907009abd9b0f 100644 (file)
@@ -113,7 +113,7 @@ static int nuc900_check_rb(struct nuc900_nand *nand)
 {
        unsigned int val;
        spin_lock(&nand->lock);
-       val = __raw_readl(REG_SMISR);
+       val = __raw_readl(nand->reg + REG_SMISR);
        val &= READYBUSY;
        spin_unlock(&nand->lock);
 
index a0e26dea1424bb3ef0053836512a0a6a3c085265..e4e50da30444fc2dc2a4c6d936680f74525dac53 100644 (file)
@@ -73,7 +73,6 @@ static int plat_nand_probe(struct platform_device *pdev)
        data->chip.bbt_options |= pdata->chip.bbt_options;
 
        data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
-       data->chip.ecc.layout = pdata->chip.ecclayout;
        data->chip.ecc.mode = NAND_ECC_SOFT;
 
        platform_set_drvdata(pdev, data);
index 86fc245dc71a2395227a6b7283fa47ff1cc2fae1..e42496adda8dbf2a4a149f5197d42c1345ea3ac4 100644 (file)
 #define READ_ID_BYTES          7
 
 /* macros for registers read/write */
-#define nand_writel(info, off, val)    \
-       writel_relaxed((val), (info)->mmio_base + (off))
-
-#define nand_readl(info, off)          \
-       readl_relaxed((info)->mmio_base + (off))
+#define nand_writel(info, off, val)                                    \
+       do {                                                            \
+               dev_vdbg(&info->pdev->dev,                              \
+                        "%s():%d nand_writel(0x%x, 0x%04x)\n",         \
+                        __func__, __LINE__, (val), (off));             \
+               writel_relaxed((val), (info)->mmio_base + (off));       \
+       } while (0)
+
+#define nand_readl(info, off)                                          \
+       ({                                                              \
+               unsigned int _v;                                        \
+               _v = readl_relaxed((info)->mmio_base + (off));          \
+               dev_vdbg(&info->pdev->dev,                              \
+                        "%s():%d nand_readl(0x%04x) = 0x%x\n",         \
+                        __func__, __LINE__, (off), _v);                \
+               _v;                                                     \
+       })
 
 /* error code and state */
 enum {
index 01ac74fa3b95244d5c2bf455b664f0834c2940ae..9c9397b54b2ca9a826e27fc7625108100ae2fb87 100644 (file)
@@ -861,9 +861,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        chip->ecc.mode      = NAND_ECC_SOFT;
 #endif
 
-       if (set->ecc_layout != NULL)
-               chip->ecc.layout = set->ecc_layout;
-
        if (set->disable_ecc)
                chip->ecc.mode  = NAND_ECC_NONE;
 
index 51e10a35fe08c29d6a27ef94563b4a8036f7e41a..b5ea6b312df08b3467fcc85220a0f1e01cd263c2 100644 (file)
@@ -60,6 +60,7 @@
 #define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3)
 #define NFC_REG_USER_DATA(x)   (0x0050 + ((x) * 4))
 #define NFC_REG_SPARE_AREA     0x00A0
+#define NFC_REG_PAT_ID         0x00A4
 #define NFC_RAM0_BASE          0x0400
 #define NFC_RAM1_BASE          0x0800
 
@@ -538,6 +539,174 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
        sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
 }
 
+/* These seed values have been extracted from Allwinner's BSP */
+static const u16 sunxi_nfc_randomizer_page_seeds[] = {
+       0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
+       0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
+       0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
+       0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
+       0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
+       0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
+       0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
+       0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
+       0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
+       0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
+       0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
+       0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
+       0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
+       0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
+       0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
+       0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
+};
+
+/*
+ * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
+ * have been generated using
+ * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
+ * the randomizer engine does internally before de/scrambling OOB data.
+ *
+ * Those tables are statically defined to avoid calculating randomizer state
+ * at runtime.
+ */
+static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
+       0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
+       0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
+       0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
+       0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
+       0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
+       0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
+       0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
+       0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
+       0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
+       0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
+       0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
+       0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
+       0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
+       0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
+       0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
+       0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
+};
+
+static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
+       0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
+       0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
+       0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
+       0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
+       0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
+       0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
+       0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
+       0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
+       0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
+       0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
+       0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
+       0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
+       0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
+       0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
+       0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
+       0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
+};
+
+static u16 sunxi_nfc_randomizer_step(u16 state, int count)
+{
+       state &= 0x7fff;
+
+       /*
+        * This loop is just a simple implementation of a Fibonacci LFSR using
+        * the x16 + x15 + 1 polynomial.
+        */
+       while (count--)
+               state = ((state >> 1) |
+                        (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
+
+       return state;
+}
+
+static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
+{
+       const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
+       int mod = mtd_div_by_ws(mtd->erasesize, mtd);
+
+       if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
+               mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
+
+       if (ecc) {
+               if (mtd->ecc_step_size == 512)
+                       seeds = sunxi_nfc_randomizer_ecc512_seeds;
+               else
+                       seeds = sunxi_nfc_randomizer_ecc1024_seeds;
+       }
+
+       return seeds[page % mod];
+}
+
+static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
+                                       int page, bool ecc)
+{
+       struct nand_chip *nand = mtd->priv;
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+       u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+       u16 state;
+
+       if (!(nand->options & NAND_NEED_SCRAMBLING))
+               return;
+
+       ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
+       state = sunxi_nfc_randomizer_state(mtd, page, ecc);
+       ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
+       writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
+{
+       struct nand_chip *nand = mtd->priv;
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+       if (!(nand->options & NAND_NEED_SCRAMBLING))
+               return;
+
+       writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
+              nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
+{
+       struct nand_chip *nand = mtd->priv;
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+       if (!(nand->options & NAND_NEED_SCRAMBLING))
+               return;
+
+       writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
+              nfc->regs + NFC_REG_ECC_CTL);
+}
+
+static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
+{
+       u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
+
+       bbm[0] ^= state;
+       bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
+}
+
+static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
+                                          const uint8_t *buf, int len,
+                                          bool ecc, int page)
+{
+       sunxi_nfc_randomizer_config(mtd, page, ecc);
+       sunxi_nfc_randomizer_enable(mtd);
+       sunxi_nfc_write_buf(mtd, buf, len);
+       sunxi_nfc_randomizer_disable(mtd);
+}
+
+static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
+                                         int len, bool ecc, int page)
+{
+       sunxi_nfc_randomizer_config(mtd, page, ecc);
+       sunxi_nfc_randomizer_enable(mtd);
+       sunxi_nfc_read_buf(mtd, buf, len);
+       sunxi_nfc_randomizer_disable(mtd);
+}
+
 static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
@@ -574,18 +743,20 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
                                       u8 *data, int data_off,
                                       u8 *oob, int oob_off,
                                       int *cur_off,
-                                      unsigned int *max_bitflips)
+                                      unsigned int *max_bitflips,
+                                      bool bbm, int page)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
        struct nand_ecc_ctrl *ecc = &nand->ecc;
+       int raw_mode = 0;
        u32 status;
        int ret;
 
        if (*cur_off != data_off)
                nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
 
-       sunxi_nfc_read_buf(mtd, NULL, ecc->size);
+       sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
 
        if (data_off + ecc->size != oob_off)
                nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
@@ -594,25 +765,54 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
        if (ret)
                return ret;
 
+       sunxi_nfc_randomizer_enable(mtd);
        writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
               nfc->regs + NFC_REG_CMD);
 
        ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+       sunxi_nfc_randomizer_disable(mtd);
        if (ret)
                return ret;
 
+       *cur_off = oob_off + ecc->bytes + 4;
+
        status = readl(nfc->regs + NFC_REG_ECC_ST);
+       if (status & NFC_ECC_PAT_FOUND(0)) {
+               u8 pattern = 0xff;
+
+               if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1)))
+                       pattern = 0x0;
+
+               memset(data, pattern, ecc->size);
+               memset(oob, pattern, ecc->bytes + 4);
+
+               return 1;
+       }
+
        ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0)));
 
        memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
 
        nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
-       sunxi_nfc_read_buf(mtd, oob, ecc->bytes + 4);
+       sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page);
 
        if (status & NFC_ECC_ERR(0)) {
+               /*
+                * Re-read the data with the randomizer disabled to identify
+                * bitflips in erased pages.
+                */
+               if (nand->options & NAND_NEED_SCRAMBLING) {
+                       nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
+                       nand->read_buf(mtd, data, ecc->size);
+                       nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+                       nand->read_buf(mtd, oob, ecc->bytes + 4);
+               }
+
                ret = nand_check_erased_ecc_chunk(data, ecc->size,
                                                  oob, ecc->bytes + 4,
                                                  NULL, 0, ecc->strength);
+               if (ret >= 0)
+                       raw_mode = 1;
        } else {
                /*
                 * The engine protects 4 bytes of OOB data per chunk.
@@ -620,6 +820,10 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
                 */
                sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(0)),
                                           oob);
+
+               /* De-randomize the Bad Block Marker. */
+               if (bbm && nand->options & NAND_NEED_SCRAMBLING)
+                       sunxi_nfc_randomize_bbm(mtd, page, oob);
        }
 
        if (ret < 0) {
@@ -629,13 +833,12 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
                *max_bitflips = max_t(unsigned int, *max_bitflips, ret);
        }
 
-       *cur_off = oob_off + ecc->bytes + 4;
-
-       return 0;
+       return raw_mode;
 }
 
 static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
-                                           u8 *oob, int *cur_off)
+                                           u8 *oob, int *cur_off,
+                                           bool randomize, int page)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct nand_ecc_ctrl *ecc = &nand->ecc;
@@ -649,7 +852,11 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
                nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
                              offset + mtd->writesize, -1);
 
-       sunxi_nfc_read_buf(mtd, oob + offset, len);
+       if (!randomize)
+               sunxi_nfc_read_buf(mtd, oob + offset, len);
+       else
+               sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
+                                             false, page);
 
        *cur_off = mtd->oobsize + mtd->writesize;
 }
@@ -662,7 +869,8 @@ static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
 static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
                                        const u8 *data, int data_off,
                                        const u8 *oob, int oob_off,
-                                       int *cur_off)
+                                       int *cur_off, bool bbm,
+                                       int page)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
@@ -672,11 +880,20 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
        if (data_off != *cur_off)
                nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1);
 
-       sunxi_nfc_write_buf(mtd, data, ecc->size);
+       sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
 
        /* Fill OOB data in */
-       writel(sunxi_nfc_buf_to_user_data(oob),
-              nfc->regs + NFC_REG_USER_DATA(0));
+       if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) {
+               u8 user_data[4];
+
+               memcpy(user_data, oob, 4);
+               sunxi_nfc_randomize_bbm(mtd, page, user_data);
+               writel(sunxi_nfc_buf_to_user_data(user_data),
+                      nfc->regs + NFC_REG_USER_DATA(0));
+       } else {
+               writel(sunxi_nfc_buf_to_user_data(oob),
+                      nfc->regs + NFC_REG_USER_DATA(0));
+       }
 
        if (data_off + ecc->size != oob_off)
                nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1);
@@ -685,11 +902,13 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
        if (ret)
                return ret;
 
+       sunxi_nfc_randomizer_enable(mtd);
        writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
               NFC_ACCESS_DIR | NFC_ECC_OP,
               nfc->regs + NFC_REG_CMD);
 
        ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
+       sunxi_nfc_randomizer_disable(mtd);
        if (ret)
                return ret;
 
@@ -699,7 +918,8 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
 }
 
 static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
-                                            u8 *oob, int *cur_off)
+                                            u8 *oob, int *cur_off,
+                                            int page)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct nand_ecc_ctrl *ecc = &nand->ecc;
@@ -713,7 +933,7 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
                nand->cmdfunc(mtd, NAND_CMD_RNDIN,
                              offset + mtd->writesize, -1);
 
-       sunxi_nfc_write_buf(mtd, oob + offset, len);
+       sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
 
        *cur_off = mtd->oobsize + mtd->writesize;
 }
@@ -725,6 +945,7 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        unsigned int max_bitflips = 0;
        int ret, i, cur_off = 0;
+       bool raw_mode = false;
 
        sunxi_nfc_hw_ecc_enable(mtd);
 
@@ -736,13 +957,17 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
 
                ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
                                                  oob_off + mtd->writesize,
-                                                 &cur_off, &max_bitflips);
-               if (ret)
+                                                 &cur_off, &max_bitflips,
+                                                 !i, page);
+               if (ret < 0)
                        return ret;
+               else if (ret)
+                       raw_mode = true;
        }
 
        if (oob_required)
-               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off);
+               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+                                               !raw_mode, page);
 
        sunxi_nfc_hw_ecc_disable(mtd);
 
@@ -767,13 +992,14 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
 
                ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
                                                   oob_off + mtd->writesize,
-                                                  &cur_off);
+                                                  &cur_off, !i, page);
                if (ret)
                        return ret;
        }
 
-       if (oob_required)
-               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off);
+       if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+                                                &cur_off, page);
 
        sunxi_nfc_hw_ecc_disable(mtd);
 
@@ -788,6 +1014,7 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        unsigned int max_bitflips = 0;
        int ret, i, cur_off = 0;
+       bool raw_mode = false;
 
        sunxi_nfc_hw_ecc_enable(mtd);
 
@@ -799,13 +1026,16 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
 
                ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
                                                  oob_off, &cur_off,
-                                                 &max_bitflips);
-               if (ret)
+                                                 &max_bitflips, !i, page);
+               if (ret < 0)
                        return ret;
+               else if (ret)
+                       raw_mode = true;
        }
 
        if (oob_required)
-               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off);
+               sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
+                                               !raw_mode, page);
 
        sunxi_nfc_hw_ecc_disable(mtd);
 
@@ -829,13 +1059,15 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
                const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
 
                ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off,
-                                                  oob, oob_off, &cur_off);
+                                                  oob, oob_off, &cur_off,
+                                                  false, page);
                if (ret)
                        return ret;
        }
 
-       if (oob_required)
-               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off);
+       if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+                                                &cur_off, page);
 
        sunxi_nfc_hw_ecc_disable(mtd);
 
@@ -1345,6 +1577,9 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
        if (nand->bbt_options & NAND_BBT_USE_FLASH)
                nand->bbt_options |= NAND_BBT_NO_OOB;
 
+       if (nand->options & NAND_NEED_SCRAMBLING)
+               nand->options |= NAND_NO_SUBPAGE_WRITE;
+
        ret = sunxi_nand_chip_init_timings(chip, np);
        if (ret) {
                dev_err(dev, "could not configure chip timings: %d\n", ret);
index 034420f313d500634e4ad66e46129535fac619d7..293feb19b0b149c7add9d4e2bf7dc0f2a8313275 100644 (file)
@@ -795,8 +795,6 @@ static int vf610_nfc_probe(struct platform_device *pdev)
                        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;
 
index 08d0085f3e939fb277cc9c21b3b3004eab662206..680188a881301ee195af0320694324da9ca2caeb 100644 (file)
@@ -179,7 +179,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
  * by the onenand_release function.
  *
  */
-int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 {
        struct onenand_chip *this = mtd->priv;
        struct bbm_info *bbm = this->bbm;
@@ -247,6 +247,3 @@ int onenand_default_bbt(struct mtd_info *mtd)
 
        return onenand_scan_bbt(mtd, bbm->badblock_pattern);
 }
-
-EXPORT_SYMBOL(onenand_scan_bbt);
-EXPORT_SYMBOL(onenand_default_bbt);
index 0dc927540b3d1627fbe77fce5e3bff09414fe4fb..83befab4b5b4a13121b2dc1b4c816baaca6e238a 100644 (file)
@@ -9,6 +9,7 @@ if MTD_SPI_NOR
 
 config MTD_MT81xx_NOR
        tristate "Mediatek MT81xx SPI NOR flash controller"
+       depends on HAS_IOMEM
        help
          This enables access to SPI NOR flash, using MT81xx SPI NOR flash
          controller. This controller does not support generic SPI BUS, it only
index d5f850d035bb93fb3a7c6547901ddfe84c3c6f04..8bed1a4cb79ce585d88623dc7d6784efaf58ccb7 100644 (file)
@@ -371,8 +371,8 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
        return ret;
 }
 
-static int __init mtk_nor_init(struct mt8173_nor *mt8173_nor,
-                              struct device_node *flash_node)
+static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
+                       struct device_node *flash_node)
 {
        int ret;
        struct spi_nor *nor;
index ae62975cf44a7bb4fa37ba008191c6e6968666b2..457dc7ffdaf1b5f19de7303bfe92cbb307da22fa 100644 (file)
@@ -78,7 +78,6 @@
 #define BL_ALL_UNLOCKED    0
 
 struct spinand_info {
-       struct nand_ecclayout *ecclayout;
        struct spi_device *spi;
        void *priv;
 };
index 36bb6a503f196ea04e4184c1445aa142db906607..3bf8f954b642581c271a7236e8e1b46f6820b015 100644 (file)
@@ -166,7 +166,6 @@ struct bbm_info {
 };
 
 /* OneNAND BBT interface */
-extern int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
 extern int onenand_default_bbt(struct mtd_info *mtd);
 
 #endif /* __LINUX_MTD_BBM_H */
index 02cd5f9b79b875ed03e5b9042df1cf98eff60709..8255118be0f0a508fdee0b6a83ba148e0d837bb9 100644 (file)
@@ -44,7 +44,6 @@ struct INFTLrecord {
        unsigned int nb_blocks;         /* number of physical blocks */
        unsigned int nb_boot_blocks;    /* number of blocks used by the bios */
        struct erase_info instr;
-       struct nand_ecclayout oobinfo;
 };
 
 int INFTL_mount(struct INFTLrecord *s);
index bdd68e22b5a59d891765d2b5f852a7fabb57d141..7604f4be33865deeee79c50251a2a71e4aebfe38 100644 (file)
@@ -168,6 +168,12 @@ typedef enum {
 /* Device supports subpage reads */
 #define NAND_SUBPAGE_READ      0x00001000
 
+/*
+ * Some MLC NANDs need data scrambling to limit bitflips caused by repeated
+ * patterns.
+ */
+#define NAND_NEED_SCRAMBLING   0x00002000
+
 /* Options valid for Samsung large page devices */
 #define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
 
@@ -896,7 +902,6 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
  * @chip_delay:                R/B delay value in us
  * @options:           Option flags, e.g. 16bit buswidth
  * @bbt_options:       BBT option flags, e.g. NAND_BBT_USE_FLASH
- * @ecclayout:         ECC layout info structure
  * @part_probe_types:  NULL-terminated array of probe types
  */
 struct platform_nand_chip {
@@ -904,7 +909,6 @@ struct platform_nand_chip {
        int chip_offset;
        int nr_partitions;
        struct mtd_partition *partitions;
-       struct nand_ecclayout *ecclayout;
        int chip_delay;
        unsigned int options;
        unsigned int bbt_options;
index b059629e22bc6901f9f17007672b0ee2f24191ec..044daa02b8ff94fde7531d4e9c4ebe548d5d49ef 100644 (file)
@@ -50,7 +50,6 @@ struct NFTLrecord {
         unsigned int nb_blocks;                /* number of physical blocks */
         unsigned int nb_boot_blocks;   /* number of blocks used by the bios */
         struct erase_info instr;
-       struct nand_ecclayout oobinfo;
 };
 
 int NFTL_mount(struct NFTLrecord *s);
index 36bb92172f4795ff806275f8777d5ecf0bd93b1a..c55e42ee57fa0c9ba3083d6bf03b04fae275d13c 100644 (file)
@@ -40,7 +40,6 @@ struct s3c2410_nand_set {
        char                    *name;
        int                     *nr_map;
        struct mtd_partition    *partitions;
-       struct nand_ecclayout   *ecc_layout;
 };
 
 struct s3c2410_platform_nand {