mtd: nand: add common DT init code
[firefly-linux-kernel-4.4.55.git] / drivers / mtd / nand / nand_base.c
index d4cec2f8a0162a7e5bad7c9deb5cd699c9cbcdb7..c4619e3ac4ab2194947c253de81f5a054401857e 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/leds.h>
 #include <linux/io.h>
 #include <linux/mtd/partitions.h>
+#include <linux/of_mtd.h>
 
 /* Define default oob placement schemes for large and small page devices */
 static struct nand_ecclayout nand_oob_8 = {
@@ -565,6 +566,25 @@ void nand_wait_ready(struct mtd_info *mtd)
 }
 EXPORT_SYMBOL_GPL(nand_wait_ready);
 
+/**
+ * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
+ * @mtd: MTD device structure
+ * @timeo: Timeout in ms
+ *
+ * Wait for status ready (i.e. command done) or timeout.
+ */
+static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
+{
+       register struct nand_chip *chip = mtd->priv;
+
+       timeo = jiffies + msecs_to_jiffies(timeo);
+       do {
+               if ((chip->read_byte(mtd) & NAND_STATUS_READY))
+                       break;
+               touch_softlockup_watchdog();
+       } while (time_before(jiffies, timeo));
+};
+
 /**
  * nand_command - [DEFAULT] Send command to NAND device
  * @mtd: MTD device structure
@@ -643,8 +663,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
                               NAND_CTRL_CLE | NAND_CTRL_CHANGE);
                chip->cmd_ctrl(mtd,
                               NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-               while (!(chip->read_byte(mtd) & NAND_STATUS_READY))
-                               ;
+               /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+               nand_wait_status_ready(mtd, 250);
                return;
 
                /* This applies to read commands */
@@ -740,8 +760,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
                               NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
                chip->cmd_ctrl(mtd, NAND_CMD_NONE,
                               NAND_NCE | NAND_CTRL_CHANGE);
-               while (!(chip->read_byte(mtd) & NAND_STATUS_READY))
-                               ;
+               /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+               nand_wait_status_ready(mtd, 250);
                return;
 
        case NAND_CMD_RNDOUT:
@@ -2124,7 +2144,7 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 
 
 /**
- * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write
+ * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @offset:    column address of subpage within the page
@@ -2909,9 +2929,6 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
              & ONFI_OPT_CMD_SET_GET_FEATURES))
                return -EINVAL;
 
-       /* clear the sub feature parameters */
-       memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
-
        chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
        for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
                *subfeature_param++ = chip->read_byte(mtd);
@@ -3779,6 +3796,39 @@ ident_done:
        return type;
 }
 
+static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip,
+                       struct device_node *dn)
+{
+       int ecc_mode, ecc_strength, ecc_step;
+
+       if (of_get_nand_bus_width(dn) == 16)
+               chip->options |= NAND_BUSWIDTH_16;
+
+       if (of_get_nand_on_flash_bbt(dn))
+               chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+       ecc_mode = of_get_nand_ecc_mode(dn);
+       ecc_strength = of_get_nand_ecc_strength(dn);
+       ecc_step = of_get_nand_ecc_step_size(dn);
+
+       if ((ecc_step >= 0 && !(ecc_strength >= 0)) ||
+           (!(ecc_step >= 0) && ecc_strength >= 0)) {
+               pr_err("must set both strength and step size in DT\n");
+               return -EINVAL;
+       }
+
+       if (ecc_mode >= 0)
+               chip->ecc.mode = ecc_mode;
+
+       if (ecc_strength >= 0)
+               chip->ecc.strength = ecc_strength;
+
+       if (ecc_step > 0)
+               chip->ecc.size = ecc_step;
+
+       return 0;
+}
+
 /**
  * nand_scan_ident - [NAND Interface] Scan for the NAND device
  * @mtd: MTD device structure
@@ -3796,6 +3846,13 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        int i, nand_maf_id, nand_dev_id;
        struct nand_chip *chip = mtd->priv;
        struct nand_flash_dev *type;
+       int ret;
+
+       if (chip->dn) {
+               ret = nand_dt_init(mtd, chip, chip->dn);
+               if (ret)
+                       return ret;
+       }
 
        /* Set the default functions */
        nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);