]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/mtd/nand/nand_base.c
mtd: nand: allow drivers to request minimum alignment for passed buffer
[people/ms/u-boot.git] / drivers / mtd / nand / nand_base.c
index d1287bc3be9f880d4776683d8f4d267e3f34d643..f3c515b6df3ea7205986f8f5f443f16d62bcf774 100644 (file)
@@ -44,7 +44,7 @@
 #include <linux/mtd/partitions.h>
 #endif
 #include <asm/io.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 
 /* Define default oob placement schemes for large and small page devices */
 static struct nand_ecclayout nand_oob_8 = {
@@ -241,7 +241,6 @@ static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
        chip->write_buf(mtd, (uint8_t *)&word, 2);
 }
 
-#if !defined(CONFIG_BLACKFIN)
 static void iowrite8_rep(void *addr, const uint8_t *buf, int len)
 {
        int i;
@@ -274,7 +273,6 @@ static void iowrite16_rep(void *addr, void *buf, int len)
         for (i = 0; i < len; i++)
                 writew(p[i], addr);
 }
-#endif
 
 /**
  * nand_write_buf - [DEFAULT] write buffer to chip
@@ -653,6 +651,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
        case NAND_CMD_ERASE2:
        case NAND_CMD_SEQIN:
        case NAND_CMD_STATUS:
+       case NAND_CMD_READID:
+       case NAND_CMD_SET_FEATURES:
                return;
 
        case NAND_CMD_RESET:
@@ -750,6 +750,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
        case NAND_CMD_SEQIN:
        case NAND_CMD_RNDIN:
        case NAND_CMD_STATUS:
+       case NAND_CMD_READID:
+       case NAND_CMD_SET_FEATURES:
                return;
 
        case NAND_CMD_RESET:
@@ -899,7 +901,180 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
        return status;
 }
 
-#define BITS_PER_BYTE 8
+/**
+ * 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 __maybe_unused nand_release_data_interface(struct nand_chip *chip)
+{
+       kfree(chip->data_interface);
+}
+
+/**
+ * nand_reset - Reset and initialize a NAND device
+ * @chip: The NAND chip
+ * @chipnr: Internal die id
+ *
+ * Returns 0 for success or negative error code otherwise
+ */
+int nand_reset(struct nand_chip *chip, int chipnr)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int ret;
+
+       ret = nand_reset_data_interface(chip);
+       if (ret)
+               return ret;
+
+       /*
+        * The CS line has to be released before we can apply the new NAND
+        * interface settings, hence this weird ->select_chip() dance.
+        */
+       chip->select_chip(mtd, chipnr);
+       chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+       chip->select_chip(mtd, -1);
+
+       chip->select_chip(mtd, chipnr);
+       ret = nand_setup_data_interface(chip);
+       chip->select_chip(mtd, -1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
 
 /**
  * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
@@ -1545,6 +1720,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
                if (!aligned)
                        use_bufpoi = 1;
+               else if (chip->options & NAND_USE_BOUNCE_BUFFER)
+                       use_bufpoi = !IS_ALIGNED((unsigned long)buf,
+                                                chip->buf_align);
                else
                        use_bufpoi = 0;
 
@@ -1557,7 +1735,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                                 __func__, buf);
 
 read_retry:
-                       chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+                       if (nand_standard_page_accessors(&chip->ecc))
+                               chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
 
                        /*
                         * Now read the page into the buffer.  Absent an error,
@@ -2233,12 +2412,11 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
  * @buf: the data to write
  * @oob_required: must write chip->oob_poi to OOB
  * @page: page number to write
- * @cached: cached programming
  * @raw: use _raw version of write_page
  */
 static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                uint32_t offset, int data_len, const uint8_t *buf,
-               int oob_required, int page, int cached, int raw)
+               int oob_required, int page, int raw)
 {
        int status, subpage;
 
@@ -2248,7 +2426,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        else
                subpage = 0;
 
-       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+       if (nand_standard_page_accessors(&chip->ecc))
+               chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
        if (unlikely(raw))
                status = chip->ecc.write_page_raw(mtd, chip, buf,
@@ -2263,29 +2442,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        if (status < 0)
                return status;
 
-       /*
-        * Cached progamming disabled for now. Not sure if it's worth the
-        * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).
-        */
-       cached = 0;
-
-       if (!cached || !NAND_HAS_CACHEPROG(chip)) {
-
+       if (nand_standard_page_accessors(&chip->ecc)) {
                chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-               status = chip->waitfunc(mtd, chip);
-               /*
-                * See if operation failed and additional status checks are
-                * available.
-                */
-               if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-                       status = chip->errstat(mtd, chip, FL_WRITING, status,
-                                              page);
 
+               status = chip->waitfunc(mtd, chip);
                if (status & NAND_STATUS_FAIL)
                        return -EIO;
-       } else {
-               chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
-               status = chip->waitfunc(mtd, chip);
        }
 
        return 0;
@@ -2360,7 +2522,7 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
 static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                             struct mtd_oob_ops *ops)
 {
-       int chipnr, realpage, page, blockmask, column;
+       int chipnr, realpage, page, column;
        struct nand_chip *chip = mtd_to_nand(mtd);
        uint32_t writelen = ops->len;
 
@@ -2396,7 +2558,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 
        realpage = (int)(to >> chip->page_shift);
        page = realpage & chip->pagemask;
-       blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
 
        /* Invalidate the page cache, when we write to the cached page */
        if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
@@ -2411,13 +2572,15 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 
        while (1) {
                int bytes = mtd->writesize;
-               int cached = writelen > bytes && page != blockmask;
                uint8_t *wbuf = buf;
                int use_bufpoi;
                int part_pagewr = (column || writelen < mtd->writesize);
 
                if (part_pagewr)
                        use_bufpoi = 1;
+               else if (chip->options & NAND_USE_BOUNCE_BUFFER)
+                       use_bufpoi = !IS_ALIGNED((unsigned long)buf,
+                                                chip->buf_align);
                else
                        use_bufpoi = 0;
 
@@ -2426,7 +2589,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                if (use_bufpoi) {
                        pr_debug("%s: using write bounce buffer for buf@%p\n",
                                         __func__, buf);
-                       cached = 0;
                        if (part_pagewr)
                                bytes = min_t(int, bytes - column, writelen);
                        chip->pagebuf = -1;
@@ -2444,7 +2606,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                        memset(chip->oob_poi, 0xff, mtd->oobsize);
                }
                ret = chip->write_page(mtd, chip, column, bytes, wbuf,
-                                       oob_required, page, cached,
+                                       oob_required, page,
                                        (ops->mode == MTD_OPS_RAW));
                if (ret)
                        break;
@@ -2580,10 +2742,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        }
 
        chipnr = (int)(to >> chip->chip_shift);
-       chip->select_chip(mtd, chipnr);
-
-       /* Shift to get page */
-       page = (int)(to >> chip->page_shift);
 
        /*
         * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
@@ -2591,7 +2749,12 @@ 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, chipnr);
+
+       chip->select_chip(mtd, chipnr);
+
+       /* Shift to get page */
+       page = (int)(to >> chip->page_shift);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
@@ -2761,14 +2924,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
                status = chip->erase(mtd, page & chip->pagemask);
 
-               /*
-                * See if operation failed and additional status checks are
-                * available
-                */
-               if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-                       status = chip->errstat(mtd, chip, FL_ERASING,
-                                              status, page);
-
                /* See if block erase succeeded */
                if (status & NAND_STATUS_FAIL) {
                        pr_debug("%s: failed erase, page 0x%08x\n",
@@ -2970,6 +3125,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
                init_waitqueue_head(&chip->controller->wq);
        }
 
+       if (!chip->buf_align)
+               chip->buf_align = 1;
 }
 
 /* Sanitize ONFI strings so we can safely print them */
@@ -3605,14 +3762,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        int i, maf_idx;
        u8 id_data[8];
 
-       /* Select the device */
-       chip->select_chip(mtd, 0);
-
        /*
         * 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, 0);
+
+       /* Select the device */
+       chip->select_chip(mtd, 0);
 
        /* Send the command for reading device ID */
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
@@ -3817,6 +3974,9 @@ static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, int node)
        if (ecc_step > 0)
                chip->ecc.size = ecc_step;
 
+       if (fdt_getprop(blob, node, "nand-ecc-maximize", NULL))
+               chip->ecc.options |= NAND_ECC_MAXIMIZE;
+
        return 0;
 }
 #else
@@ -3864,13 +4024,31 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                return PTR_ERR(type);
        }
 
+       /* Initialize the ->data_interface field. */
+       ret = nand_init_data_interface(chip);
+       if (ret)
+               return ret;
+
+       /*
+        * Setup the data interface correctly on the chip and controller side.
+        * This explicit call to nand_setup_data_interface() is only required
+        * for the first die, because nand_reset() has been called before
+        * ->data_interface and ->default_onfi_timing_mode were set.
+        * For the other dies, nand_reset() will automatically switch to the
+        * best mode for us.
+        */
+       ret = nand_setup_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, i);
+
+               chip->select_chip(mtd, i);
                /* Send the command for reading device ID */
                chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
                /* Read manufacturer and device IDs */
@@ -3929,6 +4107,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
        return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
 }
 
+static bool invalid_ecc_page_accessors(struct nand_chip *chip)
+{
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (nand_standard_page_accessors(ecc))
+               return false;
+
+       /*
+        * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
+        * controller driver implements all the page accessors because
+        * default helpers are not suitable when the core does not
+        * send the READ0/PAGEPROG commands.
+        */
+       return (!ecc->read_page || !ecc->write_page ||
+               !ecc->read_page_raw || !ecc->write_page_raw ||
+               (NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) ||
+               (NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage &&
+                ecc->hwctl && ecc->calculate));
+}
+
 /**
  * nand_scan_tail - [NAND Interface] Scan for the NAND device
  * @mtd: MTD device structure
@@ -3948,6 +4146,11 @@ int nand_scan_tail(struct mtd_info *mtd)
        BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
                        !(chip->bbt_options & NAND_BBT_USE_FLASH));
 
+       if (invalid_ecc_page_accessors(chip)) {
+               pr_err("Invalid ECC page accessors setup\n");
+               return -EINVAL;
+       }
+
        if (!(chip->options & NAND_OWN_BUFFERS)) {
                nbuf = kzalloc(sizeof(struct nand_buffers), GFP_KERNEL);
                chip->buffers = nbuf;