Merge tag '4.9/mtd-pairing-scheme' of github.com:linux-nand/linux
authorBrian Norris <computersforpeace@gmail.com>
Sat, 8 Oct 2016 19:23:37 +0000 (12:23 -0700)
committerBrian Norris <computersforpeace@gmail.com>
Sun, 9 Oct 2016 03:56:54 +0000 (20:56 -0700)
Introduction of the MTD pairing scheme concept.

28 files changed:
Documentation/devicetree/bindings/mtd/nand.txt
MAINTAINERS
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/brcmnand/brcmnand.h
drivers/mtd/nand/brcmnand/iproc_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/docg4.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/jz4780_nand.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_timings.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/qcom_nandc.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/nand/txx9ndfmc.c
drivers/of/Kconfig
include/linux/mtd/nand.h

index 3733300..b056016 100644 (file)
@@ -35,6 +35,15 @@ Optional NAND chip properties:
 - nand-ecc-step-size: integer representing the number of data bytes
                      that are covered by a single ECC step.
 
+- nand-ecc-maximize: boolean used to specify that you want to maximize ECC
+                    strength. The maximum ECC strength is both controller and
+                    chip dependent. The controller side has to select the ECC
+                    config providing the best strength and taking the OOB area
+                    size constraint into account.
+                    This is particularly useful when only the in-band area is
+                    used by the upper layers, and you want to make your NAND
+                    as reliable as possible.
+
 The ECC strength and ECC step size properties define the correction capability
 of a controller. Together, they say a controller can correct "{strength} bit
 errors per {size} bytes".
index 20bb1d0..fe3a3f8 100644 (file)
@@ -5976,6 +5976,12 @@ M:       Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
 S:     Maintained
 F:     drivers/dma/dma-jz4780.c
 
+INGENIC JZ4780 NAND DRIVER
+M:     Harvey Hunt <harveyhuntnexus@gmail.com>
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+F:     drivers/mtd/nand/jz4780_*
+
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
 M:     Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
index e32a0ac..c1f34f0 100644 (file)
@@ -317,6 +317,18 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
        return res;
 }
 
+static int part_get_device(struct mtd_info *mtd)
+{
+       struct mtd_part *part = mtd_to_part(mtd);
+       return part->master->_get_device(part->master);
+}
+
+static void part_put_device(struct mtd_info *mtd)
+{
+       struct mtd_part *part = mtd_to_part(mtd);
+       part->master->_put_device(part->master);
+}
+
 static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
                              struct mtd_oob_region *oobregion)
 {
@@ -464,6 +476,12 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
                slave->mtd._block_isbad = part_block_isbad;
        if (master->_block_markbad)
                slave->mtd._block_markbad = part_block_markbad;
+
+       if (master->_get_device)
+               slave->mtd._get_device = part_get_device;
+       if (master->_put_device)
+               slave->mtd._put_device = part_put_device;
+
        slave->mtd._erase = part_erase;
        slave->master = master;
        slave->offset = part->offset;
index 21ff580..7b7a887 100644 (file)
@@ -88,11 +88,11 @@ config MTD_NAND_AMS_DELTA
          Support for NAND flash on Amstrad E3 (Delta).
 
 config MTD_NAND_OMAP2
-       tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
-       depends on ARCH_OMAP2PLUS
+       tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
+       depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
        help
-          Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
-         platforms.
+          Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
+         and Keystone platforms.
 
 config MTD_NAND_OMAP_BCH
        depends on MTD_NAND_OMAP2
@@ -428,7 +428,7 @@ config MTD_NAND_ORION
 
 config MTD_NAND_FSL_ELBC
        tristate "NAND support for Freescale eLBC controllers"
-       depends on PPC
+       depends on FSL_SOC
        select FSL_LBC
        help
          Various Freescale chips, including the 8313, include a NAND Flash
@@ -438,7 +438,7 @@ config MTD_NAND_FSL_ELBC
 
 config MTD_NAND_FSL_IFC
        tristate "NAND support for Freescale IFC controller"
-       depends on MTD_NAND && (FSL_SOC || ARCH_LAYERSCAPE)
+       depends on FSL_SOC || ARCH_LAYERSCAPE
        select FSL_IFC
        select MEMORY
        help
index 37da423..3962f55 100644 (file)
@@ -761,8 +761,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, info);
 
-       spin_lock_init(&info->controller.lock);
-       init_waitqueue_head(&info->controller.wq);
+       nand_hw_control_init(&info->controller);
 
        info->device     = &pdev->dev;
        info->platform   = plat;
index 8eb2c64..9d2424b 100644 (file)
@@ -1336,7 +1336,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
                u32 *flash_cache = (u32 *)ctrl->flash_cache;
                int i;
 
-               brcmnand_soc_data_bus_prepare(ctrl->soc);
+               brcmnand_soc_data_bus_prepare(ctrl->soc, true);
 
                /*
                 * Must cache the FLASH_CACHE now, since changes in
@@ -1349,7 +1349,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
                         */
                        flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
 
-               brcmnand_soc_data_bus_unprepare(ctrl->soc);
+               brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
 
                /* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
                if (host->hwcfg.sector_size_1k)
@@ -1565,12 +1565,12 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
                brcmnand_waitfunc(mtd, chip);
 
                if (likely(buf)) {
-                       brcmnand_soc_data_bus_prepare(ctrl->soc);
+                       brcmnand_soc_data_bus_prepare(ctrl->soc, false);
 
                        for (j = 0; j < FC_WORDS; j++, buf++)
                                *buf = brcmnand_read_fc(ctrl, j);
 
-                       brcmnand_soc_data_bus_unprepare(ctrl->soc);
+                       brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
                }
 
                if (oob)
@@ -1815,12 +1815,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
                (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
 
                if (buf) {
-                       brcmnand_soc_data_bus_prepare(ctrl->soc);
+                       brcmnand_soc_data_bus_prepare(ctrl->soc, false);
 
                        for (j = 0; j < FC_WORDS; j++, buf++)
                                brcmnand_write_fc(ctrl, j, *buf);
 
-                       brcmnand_soc_data_bus_unprepare(ctrl->soc);
+                       brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
                } else if (oob) {
                        for (j = 0; j < FC_WORDS; j++)
                                brcmnand_write_fc(ctrl, j, 0xffffffff);
@@ -2370,8 +2370,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
 
        init_completion(&ctrl->done);
        init_completion(&ctrl->dma_done);
-       spin_lock_init(&ctrl->controller.lock);
-       init_waitqueue_head(&ctrl->controller.wq);
+       nand_hw_control_init(&ctrl->controller);
        INIT_LIST_HEAD(&ctrl->host_list);
 
        /* NAND register range */
index ef5eabb..5c44cd4 100644 (file)
@@ -23,19 +23,22 @@ struct dev_pm_ops;
 struct brcmnand_soc {
        bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
        void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
-       void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare);
+       void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
+                                bool is_param);
 };
 
-static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc)
+static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
+                                                bool is_param)
 {
        if (soc && soc->prepare_data_bus)
-               soc->prepare_data_bus(soc, true);
+               soc->prepare_data_bus(soc, true, is_param);
 }
 
-static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc)
+static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
+                                                  bool is_param)
 {
        if (soc && soc->prepare_data_bus)
-               soc->prepare_data_bus(soc, false);
+               soc->prepare_data_bus(soc, false, is_param);
 }
 
 static inline u32 brcmnand_readl(void __iomem *addr)
index 585596c..4c6ae11 100644 (file)
@@ -74,7 +74,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
        spin_unlock_irqrestore(&priv->idm_lock, flags);
 }
 
-static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
+static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
+                                 bool is_param)
 {
        struct iproc_nand_soc *priv =
                        container_of(soc, struct iproc_nand_soc, soc);
@@ -86,10 +87,19 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
 
        val = brcmnand_readl(mmio);
 
-       if (prepare)
-               val |= IPROC_NAND_APB_LE_MODE;
-       else
+       /*
+        * In the case of BE or when dealing with NAND data, alway configure
+        * the APB bus to LE mode before accessing the FIFO and back to BE mode
+        * after the access is done
+        */
+       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
+               if (prepare)
+                       val |= IPROC_NAND_APB_LE_MODE;
+               else
+                       val &= ~IPROC_NAND_APB_LE_MODE;
+       } else { /* when in LE accessing the parameter page, keep APB in BE */
                val &= ~IPROC_NAND_APB_LE_MODE;
+       }
 
        brcmnand_writel(val, mmio);
 
index cc07ba0..27fa8b8 100644 (file)
@@ -240,6 +240,9 @@ static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
        unsigned long flags;
        u32 val;
 
+       /* Reset ECC hardware */
+       davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
+
        spin_lock_irqsave(&davinci_nand_lock, flags);
 
        /* Start 4-bit ECC calculation for read/write */
index 4731699..7af2a3c 100644 (file)
@@ -1249,8 +1249,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
        nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
        nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
        nand->controller = &nand->hwcontrol;
-       spin_lock_init(&nand->controller->lock);
-       init_waitqueue_head(&nand->controller->wq);
+       nand_hw_control_init(nand->controller);
 
        /* methods */
        nand->cmdfunc = docg4_command;
index 60a88f2..113f76e 100644 (file)
@@ -879,8 +879,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
                }
                elbc_fcm_ctrl->counter++;
 
-               spin_lock_init(&elbc_fcm_ctrl->controller.lock);
-               init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
+               nand_hw_control_init(&elbc_fcm_ctrl->controller);
                fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
        } else {
                elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
index 4e9e5fd..0a177b1 100644 (file)
@@ -987,8 +987,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
                ifc_nand_ctrl->addr = NULL;
                fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
 
-               spin_lock_init(&ifc_nand_ctrl->controller.lock);
-               init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
+               nand_hw_control_init(&ifc_nand_ctrl->controller);
        } else {
                ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
        }
index 6e46156..6c062b8 100644 (file)
@@ -318,7 +318,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
                return -EINVAL;
        }
 
-       geo->page_size = mtd->writesize + mtd->oobsize;
+       geo->page_size = mtd->writesize + geo->metadata_size +
+               (geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
        geo->payload_size = mtd->writesize;
 
        /*
index 175f67d..a39bb70 100644 (file)
@@ -368,9 +368,8 @@ static int jz4780_nand_probe(struct platform_device *pdev)
        nfc->dev = dev;
        nfc->num_banks = num_banks;
 
-       spin_lock_init(&nfc->controller.lock);
+       nand_hw_control_init(&nfc->controller);
        INIT_LIST_HEAD(&nfc->chips);
-       init_waitqueue_head(&nfc->controller.wq);
 
        ret = jz4780_nand_init_chips(nfc, pdev);
        if (ret) {
index 5173fad..d68314c 100644 (file)
@@ -152,6 +152,9 @@ struct mxc_nand_devtype_data {
        void (*select_chip)(struct mtd_info *mtd, int chip);
        int (*correct_data)(struct mtd_info *mtd, u_char *dat,
                        u_char *read_ecc, u_char *calc_ecc);
+       int (*setup_data_interface)(struct mtd_info *mtd,
+                                   const struct nand_data_interface *conf,
+                                   bool check_only);
 
        /*
         * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
@@ -1012,6 +1015,82 @@ static void preset_v1(struct mtd_info *mtd)
        writew(0x4, NFC_V1_V2_WRPROT);
 }
 
+static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
+                                       const struct nand_data_interface *conf,
+                                       bool check_only)
+{
+       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+       int tRC_min_ns, tRC_ps, ret;
+       unsigned long rate, rate_round;
+       const struct nand_sdr_timings *timings;
+       u16 config1;
+
+       timings = nand_get_sdr_timings(conf);
+       if (IS_ERR(timings))
+               return -ENOTSUPP;
+
+       config1 = readw(NFC_V1_V2_CONFIG1);
+
+       tRC_min_ns = timings->tRC_min / 1000;
+       rate = 1000000000 / tRC_min_ns;
+
+       /*
+        * For tRC < 30ns we have to use EDO mode. In this case the controller
+        * does one access per clock cycle. Otherwise the controller does one
+        * access in two clock cycles, thus we have to double the rate to the
+        * controller.
+        */
+       if (tRC_min_ns < 30) {
+               rate_round = clk_round_rate(host->clk, rate);
+               config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
+               tRC_ps = 1000000000 / (rate_round / 1000);
+       } else {
+               rate *= 2;
+               rate_round = clk_round_rate(host->clk, rate);
+               config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
+               tRC_ps = 1000000000 / (rate_round / 1000 / 2);
+       }
+
+       /*
+        * The timing values compared against are from the i.MX25 Automotive
+        * datasheet, Table 50. NFC Timing Parameters
+        */
+       if (timings->tCLS_min > tRC_ps - 1000 ||
+           timings->tCLH_min > tRC_ps - 2000 ||
+           timings->tCS_min > tRC_ps - 1000 ||
+           timings->tCH_min > tRC_ps - 2000 ||
+           timings->tWP_min > tRC_ps - 1500 ||
+           timings->tALS_min > tRC_ps ||
+           timings->tALH_min > tRC_ps - 3000 ||
+           timings->tDS_min > tRC_ps ||
+           timings->tDH_min > tRC_ps - 5000 ||
+           timings->tWC_min > 2 * tRC_ps ||
+           timings->tWH_min > tRC_ps - 2500 ||
+           timings->tRR_min > 6 * tRC_ps ||
+           timings->tRP_min > 3 * tRC_ps / 2 ||
+           timings->tRC_min > 2 * tRC_ps ||
+           timings->tREH_min > (tRC_ps / 2) - 2500) {
+               dev_dbg(host->dev, "Timing out of bounds\n");
+               return -EINVAL;
+       }
+
+       if (check_only)
+               return 0;
+
+       ret = clk_set_rate(host->clk, rate);
+       if (ret)
+               return ret;
+
+       writew(config1, NFC_V1_V2_CONFIG1);
+
+       dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
+               config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
+               "normal");
+
+       return 0;
+}
+
 static void preset_v2(struct mtd_info *mtd)
 {
        struct nand_chip *nand_chip = mtd_to_nand(mtd);
@@ -1239,6 +1318,57 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
        }
 }
 
+static int mxc_nand_onfi_set_features(struct mtd_info *mtd,
+                                     struct nand_chip *chip, int addr,
+                                     u8 *subfeature_param)
+{
+       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+       int i;
+
+       if (!chip->onfi_version ||
+           !(le16_to_cpu(chip->onfi_params.opt_cmd)
+             & ONFI_OPT_CMD_SET_GET_FEATURES))
+               return -EINVAL;
+
+       host->buf_start = 0;
+
+       for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+               chip->write_byte(mtd, subfeature_param[i]);
+
+       memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
+       host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
+       mxc_do_addr_cycle(mtd, addr, -1);
+       host->devtype_data->send_page(mtd, NFC_INPUT);
+
+       return 0;
+}
+
+static int mxc_nand_onfi_get_features(struct mtd_info *mtd,
+                                     struct nand_chip *chip, int addr,
+                                     u8 *subfeature_param)
+{
+       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+       int i;
+
+       if (!chip->onfi_version ||
+           !(le16_to_cpu(chip->onfi_params.opt_cmd)
+             & ONFI_OPT_CMD_SET_GET_FEATURES))
+               return -EINVAL;
+
+       host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
+       mxc_do_addr_cycle(mtd, addr, -1);
+       host->devtype_data->send_page(mtd, NFC_OUTPUT);
+       memcpy32_fromio(host->data_buf, host->main_area0, 512);
+       host->buf_start = 0;
+
+       for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+               *subfeature_param++ = chip->read_byte(mtd);
+
+       return 0;
+}
+
 /*
  * The generic flash bbt decriptors overlap with our ecc
  * hardware, so define some i.MX specific ones.
@@ -1327,6 +1457,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
        .ooblayout = &mxc_v2_ooblayout_ops,
        .select_chip = mxc_nand_select_chip_v2,
        .correct_data = mxc_nand_correct_data_v2_v3,
+       .setup_data_interface = mxc_nand_v2_setup_data_interface,
        .irqpending_quirk = 0,
        .needs_ip = 0,
        .regs_offset = 0x1e00,
@@ -1434,7 +1565,7 @@ static const struct platform_device_id mxcnd_devtype[] = {
 };
 MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
 
-#ifdef CONFIG_OF_MTD
+#ifdef CONFIG_OF
 static const struct of_device_id mxcnd_dt_ids[] = {
        {
                .compatible = "fsl,imx21-nand",
@@ -1513,6 +1644,8 @@ static int mxcnd_probe(struct platform_device *pdev)
        this->read_word = mxc_nand_read_word;
        this->write_buf = mxc_nand_write_buf;
        this->read_buf = mxc_nand_read_buf;
+       this->onfi_set_features = mxc_nand_onfi_set_features;
+       this->onfi_get_features = mxc_nand_onfi_get_features;
 
        host->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk))
@@ -1533,6 +1666,8 @@ static int mxcnd_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
+       this->setup_data_interface = host->devtype_data->setup_data_interface;
+
        if (host->devtype_data->needs_ip) {
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
index 77533f7..e5718e5 100644 (file)
@@ -745,7 +745,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
                                column >>= 1;
                        chip->cmd_ctrl(mtd, column, ctrl);
                        ctrl &= ~NAND_CTRL_CHANGE;
-                       chip->cmd_ctrl(mtd, column >> 8, ctrl);
+
+                       /* Only output a single addr cycle for 8bits opcodes. */
+                       if (!nand_opcode_8bits(command))
+                               chip->cmd_ctrl(mtd, column >> 8, ctrl);
                }
                if (page_addr != -1) {
                        chip->cmd_ctrl(mtd, page_addr, ctrl);
@@ -947,6 +950,172 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
        return status;
 }
 
+/**
+ * nand_reset_data_interface - Reset data interface and timings
+ * @chip: The NAND chip
+ *
+ * Reset the Data interface and timings to ONFI mode 0.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_reset_data_interface(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       const struct nand_data_interface *conf;
+       int ret;
+
+       if (!chip->setup_data_interface)
+               return 0;
+
+       /*
+        * The ONFI specification says:
+        * "
+        * To transition from NV-DDR or NV-DDR2 to the SDR data
+        * interface, the host shall use the Reset (FFh) command
+        * using SDR timing mode 0. A device in any timing mode is
+        * required to recognize Reset (FFh) command issued in SDR
+        * timing mode 0.
+        * "
+        *
+        * Configure the data interface in SDR mode and set the
+        * timings to timing mode 0.
+        */
+
+       conf = nand_get_default_data_interface();
+       ret = chip->setup_data_interface(mtd, conf, false);
+       if (ret)
+               pr_err("Failed to configure data interface to SDR timing mode 0\n");
+
+       return ret;
+}
+
+/**
+ * nand_setup_data_interface - Setup the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find and configure the best data interface and NAND timings supported by
+ * the chip and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_setup_data_interface(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int ret;
+
+       if (!chip->setup_data_interface || !chip->data_interface)
+               return 0;
+
+       /*
+        * Ensure the timing mode has been changed on the chip side
+        * before changing timings on the controller side.
+        */
+       if (chip->onfi_version) {
+               u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
+                       chip->onfi_timing_mode_default,
+               };
+
+               ret = chip->onfi_set_features(mtd, chip,
+                               ONFI_FEATURE_ADDR_TIMING_MODE,
+                               tmode_param);
+               if (ret)
+                       goto err;
+       }
+
+       ret = chip->setup_data_interface(mtd, chip->data_interface, false);
+err:
+       return ret;
+}
+
+/**
+ * nand_init_data_interface - find the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find the best data interface and NAND timings supported by the chip
+ * and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table. After this
+ * function nand_chip->data_interface is initialized with the best timing mode
+ * available.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_init_data_interface(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int modes, mode, ret;
+
+       if (!chip->setup_data_interface)
+               return 0;
+
+       /*
+        * First try to identify the best timings from ONFI parameters and
+        * if the NAND does not support ONFI, fallback to the default ONFI
+        * timing mode.
+        */
+       modes = onfi_get_async_timing_mode(chip);
+       if (modes == ONFI_TIMING_MODE_UNKNOWN) {
+               if (!chip->onfi_timing_mode_default)
+                       return 0;
+
+               modes = GENMASK(chip->onfi_timing_mode_default, 0);
+       }
+
+       chip->data_interface = kzalloc(sizeof(*chip->data_interface),
+                                      GFP_KERNEL);
+       if (!chip->data_interface)
+               return -ENOMEM;
+
+       for (mode = fls(modes) - 1; mode >= 0; mode--) {
+               ret = onfi_init_data_interface(chip, chip->data_interface,
+                                              NAND_SDR_IFACE, mode);
+               if (ret)
+                       continue;
+
+               ret = chip->setup_data_interface(mtd, chip->data_interface,
+                                                true);
+               if (!ret) {
+                       chip->onfi_timing_mode_default = mode;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static void nand_release_data_interface(struct nand_chip *chip)
+{
+       kfree(chip->data_interface);
+}
+
+/**
+ * nand_reset - Reset and initialize a NAND device
+ * @chip: The NAND chip
+ *
+ * Returns 0 for success or negative error code otherwise
+ */
+int nand_reset(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int ret;
+
+       ret = nand_reset_data_interface(chip);
+       if (ret)
+               return ret;
+
+       chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+       ret = nand_setup_data_interface(chip);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 /**
  * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks
  * @mtd: mtd info
@@ -1025,7 +1194,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
         * some operation can also clear the bit 7 of status register
         * eg. erase/program a locked block
         */
-       chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+       nand_reset(chip);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
@@ -1084,7 +1253,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
         * some operation can also clear the bit 7 of status register
         * eg. erase/program a locked block
         */
-       chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+       nand_reset(chip);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
@@ -2162,7 +2331,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 static int nand_read_oob(struct mtd_info *mtd, loff_t from,
                         struct mtd_oob_ops *ops)
 {
-       int ret = -ENOTSUPP;
+       int ret;
 
        ops->retlen = 0;
 
@@ -2173,24 +2342,18 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
                return -EINVAL;
        }
 
-       nand_get_device(mtd, FL_READING);
-
-       switch (ops->mode) {
-       case MTD_OPS_PLACE_OOB:
-       case MTD_OPS_AUTO_OOB:
-       case MTD_OPS_RAW:
-               break;
+       if (ops->mode != MTD_OPS_PLACE_OOB &&
+           ops->mode != MTD_OPS_AUTO_OOB &&
+           ops->mode != MTD_OPS_RAW)
+               return -ENOTSUPP;
 
-       default:
-               goto out;
-       }
+       nand_get_device(mtd, FL_READING);
 
        if (!ops->datbuf)
                ret = nand_do_read_oob(mtd, from, ops);
        else
                ret = nand_do_read_ops(mtd, from, ops);
 
-out:
        nand_release_device(mtd);
        return ret;
 }
@@ -2788,7 +2951,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
         * if we don't do this. I have no clue why, but I seem to have 'fixed'
         * it in the doc2000 driver in August 1999.  dwmw2.
         */
-       chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+       nand_reset(chip);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
@@ -3191,8 +3354,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 
        if (!chip->controller) {
                chip->controller = &chip->hwcontrol;
-               spin_lock_init(&chip->controller->lock);
-               init_waitqueue_head(&chip->controller->wq);
+               nand_hw_control_init(chip->controller);
        }
 
 }
@@ -3829,7 +3991,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
         * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
         * after power-up.
         */
-       chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+       nand_reset(chip);
 
        /* Send the command for reading device ID */
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
@@ -4113,6 +4275,9 @@ static int nand_dt_init(struct nand_chip *chip)
        if (ecc_step > 0)
                chip->ecc.size = ecc_step;
 
+       if (of_property_read_bool(dn, "nand-ecc-maximize"))
+               chip->ecc.options |= NAND_ECC_MAXIMIZE;
+
        return 0;
 }
 
@@ -4141,6 +4306,15 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        if (!mtd->name && mtd->dev.parent)
                mtd->name = dev_name(mtd->dev.parent);
 
+       if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
+               /*
+                * Default functions assigned for chip_select() and
+                * cmdfunc() both expect cmd_ctrl() to be populated,
+                * so we need to check that that's the case
+                */
+               pr_err("chip.cmd_ctrl() callback is not provided");
+               return -EINVAL;
+       }
        /* Set the default functions */
        nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
 
@@ -4155,13 +4329,17 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                return PTR_ERR(type);
        }
 
+       ret = nand_init_data_interface(chip);
+       if (ret)
+               return ret;
+
        chip->select_chip(mtd, -1);
 
        /* Check for a chip array */
        for (i = 1; i < maxchips; i++) {
                chip->select_chip(mtd, i);
                /* See comment in nand_get_flash_type for reset */
-               chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+               nand_reset(chip);
                /* Send the command for reading device ID */
                chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
                /* Read manufacturer and device IDs */
@@ -4221,6 +4399,7 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
                ecc->write_page_raw = nand_write_page_raw;
                ecc->read_oob = nand_read_oob_std;
                ecc->write_oob = nand_write_oob_std;
+
                /*
                * Board driver should supply ecc.size and ecc.strength
                * values to select how many bits are correctable.
@@ -4243,6 +4422,25 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
                        }
 
                        mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+
+               }
+
+               /*
+                * We can only maximize ECC config when the default layout is
+                * used, otherwise we don't know how many bytes can really be
+                * used.
+                */
+               if (mtd->ooblayout == &nand_ooblayout_lp_ops &&
+                   ecc->options & NAND_ECC_MAXIMIZE) {
+                       int steps, bytes;
+
+                       /* Always prefer 1k blocks over 512bytes ones */
+                       ecc->size = 1024;
+                       steps = mtd->writesize / ecc->size;
+
+                       /* Reserve 2 bytes for the BBM */
+                       bytes = (mtd->oobsize - 2) / steps;
+                       ecc->strength = bytes * 8 / fls(8 * ecc->size);
                }
 
                /* See nand_bch_init() for details. */
@@ -4601,18 +4799,16 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
 EXPORT_SYMBOL(nand_scan);
 
 /**
- * nand_release - [NAND Interface] Free resources held by the NAND device
- * @mtd: MTD device structure
+ * nand_cleanup - [NAND Interface] Free resources held by the NAND device
+ * @chip: NAND chip object
  */
-void nand_release(struct mtd_info *mtd)
+void nand_cleanup(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        if (chip->ecc.mode == NAND_ECC_SOFT &&
            chip->ecc.algo == NAND_ECC_BCH)
                nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
 
-       mtd_device_unregister(mtd);
+       nand_release_data_interface(chip);
 
        /* Free bad block table memory */
        kfree(chip->bbt);
@@ -4624,6 +4820,18 @@ void nand_release(struct mtd_info *mtd)
                        & NAND_BBT_DYNAMICSTRUCT)
                kfree(chip->badblock_pattern);
 }
+EXPORT_SYMBOL_GPL(nand_cleanup);
+
+/**
+ * nand_release - [NAND Interface] Unregister the MTD device and free resources
+ *               held by the NAND device
+ * @mtd: MTD device structure
+ */
+void nand_release(struct mtd_info *mtd)
+{
+       mtd_device_unregister(mtd);
+       nand_cleanup(mtd_to_nand(mtd));
+}
 EXPORT_SYMBOL_GPL(nand_release);
 
 MODULE_LICENSE("GPL");
index 2fbb523..7695efe 100644 (file)
@@ -604,6 +604,100 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
                search_bbt(mtd, buf, md);
 }
 
+/**
+ * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
+ * @this: the NAND device
+ * @td: the BBT description
+ * @md: the mirror BBT descriptor
+ * @chip: the CHIP selector
+ *
+ * This functions returns a positive block number pointing a valid eraseblock
+ * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
+ * all blocks are already used of marked bad. If td->pages[chip] was already
+ * pointing to a valid block we re-use it, otherwise we search for the next
+ * valid one.
+ */
+static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
+                        struct nand_bbt_descr *md, int chip)
+{
+       int startblock, dir, page, numblocks, i;
+
+       /*
+        * There was already a version of the table, reuse the page. This
+        * applies for absolute placement too, as we have the page number in
+        * td->pages.
+        */
+       if (td->pages[chip] != -1)
+               return td->pages[chip] >>
+                               (this->bbt_erase_shift - this->page_shift);
+
+       numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+       if (!(td->options & NAND_BBT_PERCHIP))
+               numblocks *= this->numchips;
+
+       /*
+        * Automatic placement of the bad block table. Search direction
+        * top -> down?
+        */
+       if (td->options & NAND_BBT_LASTBLOCK) {
+               startblock = numblocks * (chip + 1) - 1;
+               dir = -1;
+       } else {
+               startblock = chip * numblocks;
+               dir = 1;
+       }
+
+       for (i = 0; i < td->maxblocks; i++) {
+               int block = startblock + dir * i;
+
+               /* Check, if the block is bad */
+               switch (bbt_get_entry(this, block)) {
+               case BBT_BLOCK_WORN:
+               case BBT_BLOCK_FACTORY_BAD:
+                       continue;
+               }
+
+               page = block << (this->bbt_erase_shift - this->page_shift);
+
+               /* Check, if the block is used by the mirror table */
+               if (!md || md->pages[chip] != page)
+                       return block;
+       }
+
+       return -ENOSPC;
+}
+
+/**
+ * mark_bbt_block_bad - Mark one of the block reserved for BBT bad
+ * @this: the NAND device
+ * @td: the BBT description
+ * @chip: the CHIP selector
+ * @block: the BBT block to mark
+ *
+ * Blocks reserved for BBT can become bad. This functions is an helper to mark
+ * such blocks as bad. It takes care of updating the in-memory BBT, marking the
+ * block as bad using a bad block marker and invalidating the associated
+ * td->pages[] entry.
+ */
+static void mark_bbt_block_bad(struct nand_chip *this,
+                              struct nand_bbt_descr *td,
+                              int chip, int block)
+{
+       struct mtd_info *mtd = nand_to_mtd(this);
+       loff_t to;
+       int res;
+
+       bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+       to = (loff_t)block << this->bbt_erase_shift;
+       res = this->block_markbad(mtd, to);
+       if (res)
+               pr_warn("nand_bbt: error %d while marking block %d bad\n",
+                       res, block);
+
+       td->pages[chip] = -1;
+}
+
 /**
  * write_bbt - [GENERIC] (Re)write the bad block table
  * @mtd: MTD device structure
@@ -621,7 +715,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
        struct nand_chip *this = mtd_to_nand(mtd);
        struct erase_info einfo;
        int i, res, chip = 0;
-       int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
+       int bits, page, offs, numblocks, sft, sftmsk;
        int nrchips, pageoffs, ooboffs;
        uint8_t msk[4];
        uint8_t rcode = td->reserved_block_code;
@@ -652,46 +746,21 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
        }
 
        /* Loop through the chips */
-       for (; chip < nrchips; chip++) {
-               /*
-                * There was already a version of the table, reuse the page
-                * This applies for absolute placement too, as we have the
-                * page nr. in td->pages.
-                */
-               if (td->pages[chip] != -1) {
-                       page = td->pages[chip];
-                       goto write;
+       while (chip < nrchips) {
+               int block;
+
+               block = get_bbt_block(this, td, md, chip);
+               if (block < 0) {
+                       pr_err("No space left to write bad block table\n");
+                       res = block;
+                       goto outerr;
                }
 
                /*
-                * Automatic placement of the bad block table. Search direction
-                * top -> down?
+                * get_bbt_block() returns a block number, shift the value to
+                * get a page number.
                 */
-               if (td->options & NAND_BBT_LASTBLOCK) {
-                       startblock = numblocks * (chip + 1) - 1;
-                       dir = -1;
-               } else {
-                       startblock = chip * numblocks;
-                       dir = 1;
-               }
-
-               for (i = 0; i < td->maxblocks; i++) {
-                       int block = startblock + dir * i;
-                       /* Check, if the block is bad */
-                       switch (bbt_get_entry(this, block)) {
-                       case BBT_BLOCK_WORN:
-                       case BBT_BLOCK_FACTORY_BAD:
-                               continue;
-                       }
-                       page = block <<
-                               (this->bbt_erase_shift - this->page_shift);
-                       /* Check, if the block is used by the mirror table */
-                       if (!md || md->pages[chip] != page)
-                               goto write;
-               }
-               pr_err("No space left to write bad block table\n");
-               return -ENOSPC;
-       write:
+               page = block << (this->bbt_erase_shift - this->page_shift);
 
                /* Set up shift count and masks for the flash table */
                bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -787,20 +856,28 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                einfo.addr = to;
                einfo.len = 1 << this->bbt_erase_shift;
                res = nand_erase_nand(mtd, &einfo, 1);
-               if (res < 0)
-                       goto outerr;
+               if (res < 0) {
+                       pr_warn("nand_bbt: error while erasing BBT block %d\n",
+                               res);
+                       mark_bbt_block_bad(this, td, chip, block);
+                       continue;
+               }
 
                res = scan_write_bbt(mtd, to, len, buf,
                                td->options & NAND_BBT_NO_OOB ? NULL :
                                &buf[len]);
-               if (res < 0)
-                       goto outerr;
+               if (res < 0) {
+                       pr_warn("nand_bbt: error while writing BBT block %d\n",
+                               res);
+                       mark_bbt_block_bad(this, td, chip, block);
+                       continue;
+               }
 
                pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
                         (unsigned long long)to, td->version[chip]);
 
                /* Mark it as used */
-               td->pages[chip] = page;
+               td->pages[chip++] = page;
        }
        return 0;
 
index e81470a..13a5874 100644 (file)
 #include <linux/export.h>
 #include <linux/mtd/nand.h>
 
-static const struct nand_sdr_timings onfi_sdr_timings[] = {
+static const struct nand_data_interface onfi_sdr_timings[] = {
        /* Mode 0 */
        {
-               .tADL_min = 200000,
-               .tALH_min = 20000,
-               .tALS_min = 50000,
-               .tAR_min = 25000,
-               .tCEA_max = 100000,
-               .tCEH_min = 20000,
-               .tCH_min = 20000,
-               .tCHZ_max = 100000,
-               .tCLH_min = 20000,
-               .tCLR_min = 20000,
-               .tCLS_min = 50000,
-               .tCOH_min = 0,
-               .tCS_min = 70000,
-               .tDH_min = 20000,
-               .tDS_min = 40000,
-               .tFEAT_max = 1000000,
-               .tIR_min = 10000,
-               .tITC_max = 1000000,
-               .tRC_min = 100000,
-               .tREA_max = 40000,
-               .tREH_min = 30000,
-               .tRHOH_min = 0,
-               .tRHW_min = 200000,
-               .tRHZ_max = 200000,
-               .tRLOH_min = 0,
-               .tRP_min = 50000,
-               .tRST_max = 250000000000ULL,
-               .tWB_max = 200000,
-               .tRR_min = 40000,
-               .tWC_min = 100000,
-               .tWH_min = 30000,
-               .tWHR_min = 120000,
-               .tWP_min = 50000,
-               .tWW_min = 100000,
+               .type = NAND_SDR_IFACE,
+               .timings.sdr = {
+                       .tADL_min = 400000,
+                       .tALH_min = 20000,
+                       .tALS_min = 50000,
+                       .tAR_min = 25000,
+                       .tCEA_max = 100000,
+                       .tCEH_min = 20000,
+                       .tCH_min = 20000,
+                       .tCHZ_max = 100000,
+                       .tCLH_min = 20000,
+                       .tCLR_min = 20000,
+                       .tCLS_min = 50000,
+                       .tCOH_min = 0,
+                       .tCS_min = 70000,
+                       .tDH_min = 20000,
+                       .tDS_min = 40000,
+                       .tFEAT_max = 1000000,
+                       .tIR_min = 10000,
+                       .tITC_max = 1000000,
+                       .tRC_min = 100000,
+                       .tREA_max = 40000,
+                       .tREH_min = 30000,
+                       .tRHOH_min = 0,
+                       .tRHW_min = 200000,
+                       .tRHZ_max = 200000,
+                       .tRLOH_min = 0,
+                       .tRP_min = 50000,
+                       .tRR_min = 40000,
+                       .tRST_max = 250000000000ULL,
+                       .tWB_max = 200000,
+                       .tWC_min = 100000,
+                       .tWH_min = 30000,
+                       .tWHR_min = 120000,
+                       .tWP_min = 50000,
+                       .tWW_min = 100000,
+               },
        },
        /* Mode 1 */
        {
-               .tADL_min = 100000,
-               .tALH_min = 10000,
-               .tALS_min = 25000,
-               .tAR_min = 10000,
-               .tCEA_max = 45000,
-               .tCEH_min = 20000,
-               .tCH_min = 10000,
-               .tCHZ_max = 50000,
-               .tCLH_min = 10000,
-               .tCLR_min = 10000,
-               .tCLS_min = 25000,
-               .tCOH_min = 15000,
-               .tCS_min = 35000,
-               .tDH_min = 10000,
-               .tDS_min = 20000,
-               .tFEAT_max = 1000000,
-               .tIR_min = 0,
-               .tITC_max = 1000000,
-               .tRC_min = 50000,
-               .tREA_max = 30000,
-               .tREH_min = 15000,
-               .tRHOH_min = 15000,
-               .tRHW_min = 100000,
-               .tRHZ_max = 100000,
-               .tRLOH_min = 0,
-               .tRP_min = 25000,
-               .tRR_min = 20000,
-               .tRST_max = 500000000,
-               .tWB_max = 100000,
-               .tWC_min = 45000,
-               .tWH_min = 15000,
-               .tWHR_min = 80000,
-               .tWP_min = 25000,
-               .tWW_min = 100000,
+               .type = NAND_SDR_IFACE,
+               .timings.sdr = {
+                       .tADL_min = 400000,
+                       .tALH_min = 10000,
+                       .tALS_min = 25000,
+                       .tAR_min = 10000,
+                       .tCEA_max = 45000,
+                       .tCEH_min = 20000,
+                       .tCH_min = 10000,
+                       .tCHZ_max = 50000,
+                       .tCLH_min = 10000,
+                       .tCLR_min = 10000,
+                       .tCLS_min = 25000,
+                       .tCOH_min = 15000,
+                       .tCS_min = 35000,
+                       .tDH_min = 10000,
+                       .tDS_min = 20000,
+                       .tFEAT_max = 1000000,
+                       .tIR_min = 0,
+                       .tITC_max = 1000000,
+                       .tRC_min = 50000,
+                       .tREA_max = 30000,
+                       .tREH_min = 15000,
+                       .tRHOH_min = 15000,
+                       .tRHW_min = 100000,
+                       .tRHZ_max = 100000,
+                       .tRLOH_min = 0,
+                       .tRP_min = 25000,
+                       .tRR_min = 20000,
+                       .tRST_max = 500000000,
+                       .tWB_max = 100000,
+                       .tWC_min = 45000,
+                       .tWH_min = 15000,
+                       .tWHR_min = 80000,
+                       .tWP_min = 25000,
+                       .tWW_min = 100000,
+               },
        },
        /* Mode 2 */
        {
-               .tADL_min = 100000,
-               .tALH_min = 10000,
-               .tALS_min = 15000,
-               .tAR_min = 10000,
-               .tCEA_max = 30000,
-               .tCEH_min = 20000,
-               .tCH_min = 10000,
-               .tCHZ_max = 50000,
-               .tCLH_min = 10000,
-               .tCLR_min = 10000,
-               .tCLS_min = 15000,
-               .tCOH_min = 15000,
-               .tCS_min = 25000,
-               .tDH_min = 5000,
-               .tDS_min = 15000,
-               .tFEAT_max = 1000000,
-               .tIR_min = 0,
-               .tITC_max = 1000000,
-               .tRC_min = 35000,
-               .tREA_max = 25000,
-               .tREH_min = 15000,
-               .tRHOH_min = 15000,
-               .tRHW_min = 100000,
-               .tRHZ_max = 100000,
-               .tRLOH_min = 0,
-               .tRR_min = 20000,
-               .tRST_max = 500000000,
-               .tWB_max = 100000,
-               .tRP_min = 17000,
-               .tWC_min = 35000,
-               .tWH_min = 15000,
-               .tWHR_min = 80000,
-               .tWP_min = 17000,
-               .tWW_min = 100000,
+               .type = NAND_SDR_IFACE,
+               .timings.sdr = {
+                       .tADL_min = 400000,
+                       .tALH_min = 10000,
+                       .tALS_min = 15000,
+                       .tAR_min = 10000,
+                       .tCEA_max = 30000,
+                       .tCEH_min = 20000,
+                       .tCH_min = 10000,
+                       .tCHZ_max = 50000,
+                       .tCLH_min = 10000,
+                       .tCLR_min = 10000,
+                       .tCLS_min = 15000,
+                       .tCOH_min = 15000,
+                       .tCS_min = 25000,
+                       .tDH_min = 5000,
+                       .tDS_min = 15000,
+                       .tFEAT_max = 1000000,
+                       .tIR_min = 0,
+                       .tITC_max = 1000000,
+                       .tRC_min = 35000,
+                       .tREA_max = 25000,
+                       .tREH_min = 15000,
+                       .tRHOH_min = 15000,
+                       .tRHW_min = 100000,
+                       .tRHZ_max = 100000,
+                       .tRLOH_min = 0,
+                       .tRR_min = 20000,
+                       .tRST_max = 500000000,
+                       .tWB_max = 100000,
+                       .tRP_min = 17000,
+                       .tWC_min = 35000,
+                       .tWH_min = 15000,
+                       .tWHR_min = 80000,
+                       .tWP_min = 17000,
+                       .tWW_min = 100000,
+               },
        },
        /* Mode 3 */
        {
-               .tADL_min = 100000,
-               .tALH_min = 5000,
-               .tALS_min = 10000,
-               .tAR_min = 10000,
-               .tCEA_max = 25000,
-               .tCEH_min = 20000,
-               .tCH_min = 5000,
-               .tCHZ_max = 50000,
-               .tCLH_min = 5000,
-               .tCLR_min = 10000,
-               .tCLS_min = 10000,
-               .tCOH_min = 15000,
-               .tCS_min = 25000,
-               .tDH_min = 5000,
-               .tDS_min = 10000,
-               .tFEAT_max = 1000000,
-               .tIR_min = 0,
-               .tITC_max = 1000000,
-               .tRC_min = 30000,
-               .tREA_max = 20000,
-               .tREH_min = 10000,
-               .tRHOH_min = 15000,
-               .tRHW_min = 100000,
-               .tRHZ_max = 100000,
-               .tRLOH_min = 0,
-               .tRP_min = 15000,
-               .tRR_min = 20000,
-               .tRST_max = 500000000,
-               .tWB_max = 100000,
-               .tWC_min = 30000,
-               .tWH_min = 10000,
-               .tWHR_min = 80000,
-               .tWP_min = 15000,
-               .tWW_min = 100000,
+               .type = NAND_SDR_IFACE,
+               .timings.sdr = {
+                       .tADL_min = 400000,
+                       .tALH_min = 5000,
+                       .tALS_min = 10000,
+                       .tAR_min = 10000,
+                       .tCEA_max = 25000,
+                       .tCEH_min = 20000,
+                       .tCH_min = 5000,
+                       .tCHZ_max = 50000,
+                       .tCLH_min = 5000,
+                       .tCLR_min = 10000,
+                       .tCLS_min = 10000,
+                       .tCOH_min = 15000,
+                       .tCS_min = 25000,
+                       .tDH_min = 5000,
+                       .tDS_min = 10000,
+                       .tFEAT_max = 1000000,
+                       .tIR_min = 0,
+                       .tITC_max = 1000000,
+                       .tRC_min = 30000,
+                       .tREA_max = 20000,
+                       .tREH_min = 10000,
+                       .tRHOH_min = 15000,
+                       .tRHW_min = 100000,
+                       .tRHZ_max = 100000,
+                       .tRLOH_min = 0,
+                       .tRP_min = 15000,
+                       .tRR_min = 20000,
+                       .tRST_max = 500000000,
+                       .tWB_max = 100000,
+                       .tWC_min = 30000,
+                       .tWH_min = 10000,
+                       .tWHR_min = 80000,
+                       .tWP_min = 15000,
+                       .tWW_min = 100000,
+               },
        },
        /* Mode 4 */
        {
-               .tADL_min = 70000,
-               .tALH_min = 5000,
-               .tALS_min = 10000,
-               .tAR_min = 10000,
-               .tCEA_max = 25000,
-               .tCEH_min = 20000,
-               .tCH_min = 5000,
-               .tCHZ_max = 30000,
-               .tCLH_min = 5000,
-               .tCLR_min = 10000,
-               .tCLS_min = 10000,
-               .tCOH_min = 15000,
-               .tCS_min = 20000,
-               .tDH_min = 5000,
-               .tDS_min = 10000,
-               .tFEAT_max = 1000000,
-               .tIR_min = 0,
-               .tITC_max = 1000000,
-               .tRC_min = 25000,
-               .tREA_max = 20000,
-               .tREH_min = 10000,
-               .tRHOH_min = 15000,
-               .tRHW_min = 100000,
-               .tRHZ_max = 100000,
-               .tRLOH_min = 5000,
-               .tRP_min = 12000,
-               .tRR_min = 20000,
-               .tRST_max = 500000000,
-               .tWB_max = 100000,
-               .tWC_min = 25000,
-               .tWH_min = 10000,
-               .tWHR_min = 80000,
-               .tWP_min = 12000,
-               .tWW_min = 100000,
+               .type = NAND_SDR_IFACE,
+               .timings.sdr = {
+                       .tADL_min = 400000,
+                       .tALH_min = 5000,
+                       .tALS_min = 10000,
+                       .tAR_min = 10000,
+                       .tCEA_max = 25000,
+                       .tCEH_min = 20000,
+                       .tCH_min = 5000,
+                       .tCHZ_max = 30000,
+                       .tCLH_min = 5000,
+                       .tCLR_min = 10000,
+                       .tCLS_min = 10000,
+                       .tCOH_min = 15000,
+                       .tCS_min = 20000,
+                       .tDH_min = 5000,
+                       .tDS_min = 10000,
+                       .tFEAT_max = 1000000,
+                       .tIR_min = 0,
+                       .tITC_max = 1000000,
+                       .tRC_min = 25000,
+                       .tREA_max = 20000,
+                       .tREH_min = 10000,
+                       .tRHOH_min = 15000,
+                       .tRHW_min = 100000,
+                       .tRHZ_max = 100000,
+                       .tRLOH_min = 5000,
+                       .tRP_min = 12000,
+                       .tRR_min = 20000,
+                       .tRST_max = 500000000,
+                       .tWB_max = 100000,
+                       .tWC_min = 25000,
+                       .tWH_min = 10000,
+                       .tWHR_min = 80000,
+                       .tWP_min = 12000,
+                       .tWW_min = 100000,
+               },
        },
        /* Mode 5 */
        {
-               .tADL_min = 70000,
-               .tALH_min = 5000,
-               .tALS_min = 10000,
-               .tAR_min = 10000,
-               .tCEA_max = 25000,
-               .tCEH_min = 20000,
-               .tCH_min = 5000,
-               .tCHZ_max = 30000,
-               .tCLH_min = 5000,
-               .tCLR_min = 10000,
-               .tCLS_min = 10000,
-               .tCOH_min = 15000,
-               .tCS_min = 15000,
-               .tDH_min = 5000,
-               .tDS_min = 7000,
-               .tFEAT_max = 1000000,
-               .tIR_min = 0,
-               .tITC_max = 1000000,
-               .tRC_min = 20000,
-               .tREA_max = 16000,
-               .tREH_min = 7000,
-               .tRHOH_min = 15000,
-               .tRHW_min = 100000,
-               .tRHZ_max = 100000,
-               .tRLOH_min = 5000,
-               .tRP_min = 10000,
-               .tRR_min = 20000,
-               .tRST_max = 500000000,
-               .tWB_max = 100000,
-               .tWC_min = 20000,
-               .tWH_min = 7000,
-               .tWHR_min = 80000,
-               .tWP_min = 10000,
-               .tWW_min = 100000,
+               .type = NAND_SDR_IFACE,
+               .timings.sdr = {
+                       .tADL_min = 400000,
+                       .tALH_min = 5000,
+                       .tALS_min = 10000,
+                       .tAR_min = 10000,
+                       .tCEA_max = 25000,
+                       .tCEH_min = 20000,
+                       .tCH_min = 5000,
+                       .tCHZ_max = 30000,
+                       .tCLH_min = 5000,
+                       .tCLR_min = 10000,
+                       .tCLS_min = 10000,
+                       .tCOH_min = 15000,
+                       .tCS_min = 15000,
+                       .tDH_min = 5000,
+                       .tDS_min = 7000,
+                       .tFEAT_max = 1000000,
+                       .tIR_min = 0,
+                       .tITC_max = 1000000,
+                       .tRC_min = 20000,
+                       .tREA_max = 16000,
+                       .tREH_min = 7000,
+                       .tRHOH_min = 15000,
+                       .tRHW_min = 100000,
+                       .tRHZ_max = 100000,
+                       .tRLOH_min = 5000,
+                       .tRP_min = 10000,
+                       .tRR_min = 20000,
+                       .tRST_max = 500000000,
+                       .tWB_max = 100000,
+                       .tWC_min = 20000,
+                       .tWH_min = 7000,
+                       .tWHR_min = 80000,
+                       .tWP_min = 10000,
+                       .tWW_min = 100000,
+               },
        },
 };
 
@@ -248,6 +266,46 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
        if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
                return ERR_PTR(-EINVAL);
 
-       return &onfi_sdr_timings[mode];
+       return &onfi_sdr_timings[mode].timings.sdr;
 }
 EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
+
+/**
+ * onfi_init_data_interface - [NAND Interface] Initialize a data interface from
+ * given ONFI mode
+ * @iface: The data interface to be initialized
+ * @mode: The ONFI timing mode
+ */
+int onfi_init_data_interface(struct nand_chip *chip,
+                            struct nand_data_interface *iface,
+                            enum nand_data_interface_type type,
+                            int timing_mode)
+{
+       if (type != NAND_SDR_IFACE)
+               return -EINVAL;
+
+       if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
+               return -EINVAL;
+
+       *iface = onfi_sdr_timings[timing_mode];
+
+       /*
+        * TODO: initialize timings that cannot be deduced from timing mode:
+        * tR, tPROG, tCCS, ...
+        * These information are part of the ONFI parameter page.
+        */
+
+       return 0;
+}
+EXPORT_SYMBOL(onfi_init_data_interface);
+
+/**
+ * nand_get_default_data_interface - [NAND Interface] Retrieve NAND
+ * data interface for mode 0. This is used as default timing after
+ * reset.
+ */
+const struct nand_data_interface *nand_get_default_data_interface(void)
+{
+       return &onfi_sdr_timings[0];
+}
+EXPORT_SYMBOL(nand_get_default_data_interface);
index 218c789..28e6118 100644 (file)
@@ -218,8 +218,7 @@ static int ndfc_probe(struct platform_device *ofdev)
        ndfc = &ndfc_ctrl[cs];
        ndfc->chip_select = cs;
 
-       spin_lock_init(&ndfc->ndfc_control.lock);
-       init_waitqueue_head(&ndfc->ndfc_control.wq);
+       nand_hw_control_init(&ndfc->ndfc_control);
        ndfc->ofdev = ofdev;
        dev_set_drvdata(&ofdev->dev, ndfc);
 
index a59361c..5513bfd 100644 (file)
@@ -2169,7 +2169,7 @@ scan_tail:
        return 0;
 
 return_error:
-       if (info->dma)
+       if (!IS_ERR_OR_NULL(info->dma))
                dma_release_channel(info->dma);
        if (nand_chip->ecc.priv) {
                nand_bch_free(nand_chip->ecc.priv);
index 436dd6d..b121bf4 100644 (file)
@@ -1810,8 +1810,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
                chip->cmdfunc           = nand_cmdfunc;
        }
 
-       spin_lock_init(&chip->controller->lock);
-       init_waitqueue_head(&chip->controller->wq);
+       nand_hw_control_init(chip->controller);
        info->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(info->clk)) {
                dev_err(&pdev->dev, "failed to get nand clock\n");
index de7d28e..57d483a 100644 (file)
@@ -1957,8 +1957,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
        INIT_LIST_HEAD(&nandc->desc_list);
        INIT_LIST_HEAD(&nandc->host_list);
 
-       spin_lock_init(&nandc->controller.lock);
-       init_waitqueue_head(&nandc->controller.wq);
+       nand_hw_control_init(&nandc->controller);
 
        return 0;
 }
index d9309cf..d459c19 100644 (file)
@@ -180,7 +180,7 @@ struct s3c2410_nand_info {
 
        enum s3c_cpu_type               cpu_type;
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
        struct notifier_block   freq_transition;
 #endif
 };
@@ -701,7 +701,7 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
 
 /* cpufreq driver support */
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
 
 static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
                                          unsigned long val, void *data)
@@ -977,8 +977,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, info);
 
-       spin_lock_init(&info->controller.lock);
-       init_waitqueue_head(&info->controller.wq);
+       nand_hw_control_init(&info->controller);
 
        /* get the clock source and enable it */
 
index 6fa3bcd..442ce61 100644 (file)
@@ -397,7 +397,7 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
        struct dma_chan *chan;
        enum dma_transfer_direction tr_dir;
        dma_addr_t dma_addr;
-       dma_cookie_t cookie = -EINVAL;
+       dma_cookie_t cookie;
        uint32_t reg;
        int ret;
 
@@ -423,6 +423,12 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
                desc->callback = flctl_dma_complete;
                desc->callback_param = flctl;
                cookie = dmaengine_submit(desc);
+               if (dma_submit_error(cookie)) {
+                       ret = dma_submit_error(cookie);
+                       dev_warn(&flctl->pdev->dev,
+                                "DMA submit failed, falling back to PIO\n");
+                       goto out;
+               }
 
                dma_async_issue_pending(chan);
        } else {
index e414b31..8b8470c 100644 (file)
@@ -1572,14 +1572,22 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
 #define sunxi_nand_lookup_timing(l, p, c) \
                        _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
 
-static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
-                                      const struct nand_sdr_timings *timings)
+static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
+                                       const struct nand_data_interface *conf,
+                                       bool check_only)
 {
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
        struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
+       const struct nand_sdr_timings *timings;
        u32 min_clk_period = 0;
        s32 tWB, tADL, tWHR, tRHW, tCAD;
        long real_clk_rate;
 
+       timings = nand_get_sdr_timings(conf);
+       if (IS_ERR(timings))
+               return -ENOTSUPP;
+
        /* T1 <=> tCLS */
        if (timings->tCLS_min > min_clk_period)
                min_clk_period = timings->tCLS_min;
@@ -1679,6 +1687,9 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
                return tRHW;
        }
 
+       if (check_only)
+               return 0;
+
        /*
         * TODO: according to ONFI specs this value only applies for DDR NAND,
         * but Allwinner seems to set this to 0x7. Mimic them for now.
@@ -1712,44 +1723,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
        return 0;
 }
 
-static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
-                                       struct device_node *np)
-{
-       struct mtd_info *mtd = nand_to_mtd(&chip->nand);
-       const struct nand_sdr_timings *timings;
-       int ret;
-       int mode;
-
-       mode = onfi_get_async_timing_mode(&chip->nand);
-       if (mode == ONFI_TIMING_MODE_UNKNOWN) {
-               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;
-               for (i = 0; i < chip->nsels; i++) {
-                       chip->nand.select_chip(mtd, i);
-                       ret = chip->nand.onfi_set_features(mtd, &chip->nand,
-                                               ONFI_FEATURE_ADDR_TIMING_MODE,
-                                               feature);
-                       chip->nand.select_chip(mtd, -1);
-                       if (ret)
-                               return ret;
-               }
-       }
-
-       timings = onfi_async_timing_mode_to_sdr_timings(mode);
-       if (IS_ERR(timings))
-               return PTR_ERR(timings);
-
-       return sunxi_nand_chip_set_timings(chip, timings);
-}
-
 static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
                                    struct mtd_oob_region *oobregion)
 {
@@ -1814,6 +1787,35 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
        int ret;
        int i;
 
+       if (ecc->options & NAND_ECC_MAXIMIZE) {
+               int bytes;
+
+               ecc->size = 1024;
+               nsectors = mtd->writesize / ecc->size;
+
+               /* Reserve 2 bytes for the BBM */
+               bytes = (mtd->oobsize - 2) / nsectors;
+
+               /* 4 non-ECC bytes are added before each ECC bytes section */
+               bytes -= 4;
+
+               /* and bytes has to be even. */
+               if (bytes % 2)
+                       bytes--;
+
+               ecc->strength = bytes * 8 / fls(8 * ecc->size);
+
+               for (i = 0; i < ARRAY_SIZE(strengths); i++) {
+                       if (strengths[i] > ecc->strength)
+                               break;
+               }
+
+               if (!i)
+                       ecc->strength = 0;
+               else
+                       ecc->strength = strengths[i - 1];
+       }
+
        if (ecc->size != 512 && ecc->size != 1024)
                return -EINVAL;
 
@@ -1975,7 +1977,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
 static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
                                struct device_node *np)
 {
-       const struct nand_sdr_timings *timings;
        struct sunxi_nand_chip *chip;
        struct mtd_info *mtd;
        struct nand_chip *nand;
@@ -2065,25 +2066,11 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
        nand->read_buf = sunxi_nfc_read_buf;
        nand->write_buf = sunxi_nfc_write_buf;
        nand->read_byte = sunxi_nfc_read_byte;
+       nand->setup_data_interface = sunxi_nfc_setup_data_interface;
 
        mtd = nand_to_mtd(nand);
        mtd->dev.parent = dev;
 
-       timings = onfi_async_timing_mode_to_sdr_timings(0);
-       if (IS_ERR(timings)) {
-               ret = PTR_ERR(timings);
-               dev_err(dev,
-                       "could not retrieve timings for ONFI mode 0: %d\n",
-                       ret);
-               return ret;
-       }
-
-       ret = sunxi_nand_chip_set_timings(chip, timings);
-       if (ret) {
-               dev_err(dev, "could not configure chip timings: %d\n", ret);
-               return ret;
-       }
-
        ret = nand_scan_ident(mtd, nsels, NULL);
        if (ret)
                return ret;
@@ -2096,12 +2083,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 
        nand->options |= NAND_SUBPAGE_READ;
 
-       ret = sunxi_nand_chip_init_timings(chip, np);
-       if (ret) {
-               dev_err(dev, "could not configure chip timings: %d\n", ret);
-               return ret;
-       }
-
        ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
        if (ret) {
                dev_err(dev, "ECC init failed: %d\n", ret);
@@ -2175,8 +2156,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        nfc->dev = dev;
-       spin_lock_init(&nfc->controller.lock);
-       init_waitqueue_head(&nfc->controller.wq);
+       nand_hw_control_init(&nfc->controller);
        INIT_LIST_HEAD(&nfc->chips);
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 04d63f5..0a14fda 100644 (file)
@@ -303,8 +303,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
        dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
                 (gbusclk + 500000) / 1000000, hold, spw);
 
-       spin_lock_init(&drvdata->hw_control.lock);
-       init_waitqueue_head(&drvdata->hw_control.wq);
+       nand_hw_control_init(&drvdata->hw_control);
 
        platform_set_drvdata(dev, drvdata);
        txx9ndfmc_initialize(dev);
index bc07ad3..ba7b034 100644 (file)
@@ -90,10 +90,6 @@ config OF_PCI_IRQ
        help
          OpenFirmware PCI IRQ routing helpers
 
-config OF_MTD
-       depends on MTD
-       def_bool y
-
 config OF_RESERVED_MEM
        depends on OF_EARLY_FLATTREE
        bool
index 8dd6e01..c5d3d50 100644 (file)
@@ -29,26 +29,26 @@ struct nand_flash_dev;
 struct device_node;
 
 /* Scan and identify a NAND device */
-extern int nand_scan(struct mtd_info *mtd, int max_chips);
+int nand_scan(struct mtd_info *mtd, int max_chips);
 /*
  * Separate phases of nand_scan(), allowing board driver to intervene
  * and override command or ECC setup according to flash type.
  */
-extern int nand_scan_ident(struct mtd_info *mtd, int max_chips,
+int nand_scan_ident(struct mtd_info *mtd, int max_chips,
                           struct nand_flash_dev *table);
-extern int nand_scan_tail(struct mtd_info *mtd);
+int nand_scan_tail(struct mtd_info *mtd);
 
-/* Free resources held by the NAND device */
-extern void nand_release(struct mtd_info *mtd);
+/* Unregister the MTD device and free resources held by the NAND device */
+void nand_release(struct mtd_info *mtd);
 
 /* Internal helper for board drivers which need to override command function */
-extern void nand_wait_ready(struct mtd_info *mtd);
+void nand_wait_ready(struct mtd_info *mtd);
 
 /* locks all blocks present in the device */
-extern int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 
 /* unlocks specified locked blocks */
-extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 
 /* The maximum number of NAND chips in an array */
 #define NAND_MAX_CHIPS         8
@@ -141,6 +141,7 @@ enum nand_ecc_algo {
  * pages and you want to rely on the default implementation.
  */
 #define NAND_ECC_GENERIC_ERASED_CHECK  BIT(0)
+#define NAND_ECC_MAXIMIZE              BIT(1)
 
 /* Bit mask for flags passed to do_nand_read_ecc */
 #define NAND_GET_DEVICE                0x80
@@ -460,6 +461,13 @@ struct nand_hw_control {
        wait_queue_head_t wq;
 };
 
+static inline void nand_hw_control_init(struct nand_hw_control *nfc)
+{
+       nfc->active = NULL;
+       spin_lock_init(&nfc->lock);
+       init_waitqueue_head(&nfc->wq);
+}
+
 /**
  * struct nand_ecc_ctrl - Control structure for ECC
  * @mode:      ECC mode
@@ -565,6 +573,123 @@ struct nand_buffers {
        uint8_t *databuf;
 };
 
+/**
+ * struct nand_sdr_timings - SDR NAND chip timings
+ *
+ * This struct defines the timing requirements of a SDR NAND chip.
+ * These information can be found in every NAND datasheets and the timings
+ * meaning are described in the ONFI specifications:
+ * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
+ * Parameters)
+ *
+ * All these timings are expressed in picoseconds.
+ *
+ * @tALH_min: ALE hold time
+ * @tADL_min: ALE to data loading time
+ * @tALS_min: ALE setup time
+ * @tAR_min: ALE to RE# delay
+ * @tCEA_max: CE# access time
+ * @tCEH_min:
+ * @tCH_min:  CE# hold time
+ * @tCHZ_max: CE# high to output hi-Z
+ * @tCLH_min: CLE hold time
+ * @tCLR_min: CLE to RE# delay
+ * @tCLS_min: CLE setup time
+ * @tCOH_min: CE# high to output hold
+ * @tCS_min: CE# setup time
+ * @tDH_min: Data hold time
+ * @tDS_min: Data setup time
+ * @tFEAT_max: Busy time for Set Features and Get Features
+ * @tIR_min: Output hi-Z to RE# low
+ * @tITC_max: Interface and Timing Mode Change time
+ * @tRC_min: RE# cycle time
+ * @tREA_max: RE# access time
+ * @tREH_min: RE# high hold time
+ * @tRHOH_min: RE# high to output hold
+ * @tRHW_min: RE# high to WE# low
+ * @tRHZ_max: RE# high to output hi-Z
+ * @tRLOH_min: RE# low to output hold
+ * @tRP_min: RE# pulse width
+ * @tRR_min: Ready to RE# low (data only)
+ * @tRST_max: Device reset time, measured from the falling edge of R/B# to the
+ *           rising edge of R/B#.
+ * @tWB_max: WE# high to SR[6] low
+ * @tWC_min: WE# cycle time
+ * @tWH_min: WE# high hold time
+ * @tWHR_min: WE# high to RE# low
+ * @tWP_min: WE# pulse width
+ * @tWW_min: WP# transition to WE# low
+ */
+struct nand_sdr_timings {
+       u32 tALH_min;
+       u32 tADL_min;
+       u32 tALS_min;
+       u32 tAR_min;
+       u32 tCEA_max;
+       u32 tCEH_min;
+       u32 tCH_min;
+       u32 tCHZ_max;
+       u32 tCLH_min;
+       u32 tCLR_min;
+       u32 tCLS_min;
+       u32 tCOH_min;
+       u32 tCS_min;
+       u32 tDH_min;
+       u32 tDS_min;
+       u32 tFEAT_max;
+       u32 tIR_min;
+       u32 tITC_max;
+       u32 tRC_min;
+       u32 tREA_max;
+       u32 tREH_min;
+       u32 tRHOH_min;
+       u32 tRHW_min;
+       u32 tRHZ_max;
+       u32 tRLOH_min;
+       u32 tRP_min;
+       u32 tRR_min;
+       u64 tRST_max;
+       u32 tWB_max;
+       u32 tWC_min;
+       u32 tWH_min;
+       u32 tWHR_min;
+       u32 tWP_min;
+       u32 tWW_min;
+};
+
+/**
+ * enum nand_data_interface_type - NAND interface timing type
+ * @NAND_SDR_IFACE:    Single Data Rate interface
+ */
+enum nand_data_interface_type {
+       NAND_SDR_IFACE,
+};
+
+/**
+ * struct nand_data_interface - NAND interface timing
+ * @type:      type of the timing
+ * @timings:   The timing, type according to @type
+ */
+struct nand_data_interface {
+       enum nand_data_interface_type type;
+       union {
+               struct nand_sdr_timings sdr;
+       } timings;
+};
+
+/**
+ * nand_get_sdr_timings - get SDR timing from data interface
+ * @conf:      The data interface
+ */
+static inline const struct nand_sdr_timings *
+nand_get_sdr_timings(const struct nand_data_interface *conf)
+{
+       if (conf->type != NAND_SDR_IFACE)
+               return ERR_PTR(-EINVAL);
+
+       return &conf->timings.sdr;
+}
+
 /**
  * struct nand_chip - NAND Private Flash Chip Data
  * @mtd:               MTD device registered to the MTD framework
@@ -627,10 +752,9 @@ struct nand_buffers {
  *                      also from the datasheet. It is the recommended ECC step
  *                     size, if known; if unknown, set to zero.
  * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
- *                           either deduced from the datasheet if the NAND
- *                           chip is not ONFI compliant or set to 0 if it is
- *                           (an ONFI chip is always configured in mode 0
- *                           after a NAND reset)
+ *                           set to the actually used ONFI mode if the chip is
+ *                           ONFI compliant or deduced from the datasheet if
+ *                           the NAND chip is not ONFI compliant.
  * @numchips:          [INTERN] number of physical chips
  * @chipsize:          [INTERN] the size of one chip for multichip arrays
  * @pagemask:          [INTERN] page number mask = number of (pages / chip) - 1
@@ -650,6 +774,7 @@ struct nand_buffers {
  * @read_retries:      [INTERN] the number of read retry modes supported
  * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
  * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
+ * @setup_data_interface: [OPTIONAL] setup the data interface and timing
  * @bbt:               [INTERN] bad block table pointer
  * @bbt_td:            [REPLACEABLE] bad block table descriptor for flash
  *                     lookup.
@@ -696,6 +821,10 @@ struct nand_chip {
        int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
                        int feature_addr, uint8_t *subfeature_para);
        int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
+       int (*setup_data_interface)(struct mtd_info *mtd,
+                                   const struct nand_data_interface *conf,
+                                   bool check_only);
+
 
        int chip_delay;
        unsigned int options;
@@ -725,6 +854,8 @@ struct nand_chip {
                struct nand_jedec_params jedec_params;
        };
 
+       struct nand_data_interface *data_interface;
+
        int read_retries;
 
        flstate_t state;
@@ -893,14 +1024,14 @@ struct nand_manufacturers {
 extern struct nand_flash_dev nand_flash_ids[];
 extern struct nand_manufacturers nand_manuf_ids[];
 
-extern int nand_default_bbt(struct mtd_info *mtd);
-extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
-extern int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
-extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
-extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
-                          int allowbbt);
-extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, uint8_t *buf);
+int nand_default_bbt(struct mtd_info *mtd);
+int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
+int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
+int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
+int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+                   int allowbbt);
+int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
+                size_t *retlen, uint8_t *buf);
 
 /**
  * struct platform_nand_chip - chip level device structure
@@ -988,6 +1119,11 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
        return le16_to_cpu(chip->onfi_params.src_sync_timing_mode);
 }
 
+int onfi_init_data_interface(struct nand_chip *chip,
+                            struct nand_data_interface *iface,
+                            enum nand_data_interface_type type,
+                            int timing_mode);
+
 /*
  * Check if it is a SLC nand.
  * The !nand_is_slc() can be used to check the MLC/TLC nand chips.
@@ -1023,57 +1159,10 @@ static inline int jedec_feature(struct nand_chip *chip)
                : 0;
 }
 
-/*
- * struct nand_sdr_timings - SDR NAND chip timings
- *
- * This struct defines the timing requirements of a SDR NAND chip.
- * These informations can be found in every NAND datasheets and the timings
- * meaning are described in the ONFI specifications:
- * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
- * Parameters)
- *
- * All these timings are expressed in picoseconds.
- */
-
-struct nand_sdr_timings {
-       u32 tALH_min;
-       u32 tADL_min;
-       u32 tALS_min;
-       u32 tAR_min;
-       u32 tCEA_max;
-       u32 tCEH_min;
-       u32 tCH_min;
-       u32 tCHZ_max;
-       u32 tCLH_min;
-       u32 tCLR_min;
-       u32 tCLS_min;
-       u32 tCOH_min;
-       u32 tCS_min;
-       u32 tDH_min;
-       u32 tDS_min;
-       u32 tFEAT_max;
-       u32 tIR_min;
-       u32 tITC_max;
-       u32 tRC_min;
-       u32 tREA_max;
-       u32 tREH_min;
-       u32 tRHOH_min;
-       u32 tRHW_min;
-       u32 tRHZ_max;
-       u32 tRLOH_min;
-       u32 tRP_min;
-       u32 tRR_min;
-       u64 tRST_max;
-       u32 tWB_max;
-       u32 tWC_min;
-       u32 tWH_min;
-       u32 tWHR_min;
-       u32 tWP_min;
-       u32 tWW_min;
-};
-
 /* get timing characteristics from ONFI timing mode. */
 const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
+/* get data interface from ONFI timing mode 0, used after reset. */
+const struct nand_data_interface *nand_get_default_data_interface(void);
 
 int nand_check_erased_ecc_chunk(void *data, int datalen,
                                void *ecc, int ecclen,
@@ -1093,4 +1182,11 @@ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
 /* Default read_oob syndrome implementation */
 int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
                           int page);
+
+/* Reset and initialize a NAND device */
+int nand_reset(struct nand_chip *chip);
+
+/* Free resources held by the NAND device */
+void nand_cleanup(struct nand_chip *chip);
+
 #endif /* __LINUX_MTD_NAND_H */