]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mtd/nand/nand_base.c
mtd: nand: Pass the CS line to ->setup_data_interface()
[karo-tx-linux.git] / drivers / mtd / nand / nand_base.c
index b0524f8accb6206f50e5b30d422b81ec311a40f3..3317acf0ce04d5575cbf755e01ffcf0c97d56052 100644 (file)
@@ -139,6 +139,74 @@ const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
 };
 EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
 
+/*
+ * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
+ * are placed at a fixed offset.
+ */
+static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
+                                        struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (section)
+               return -ERANGE;
+
+       switch (mtd->oobsize) {
+       case 64:
+               oobregion->offset = 40;
+               break;
+       case 128:
+               oobregion->offset = 80;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       oobregion->length = ecc->total;
+       if (oobregion->offset + oobregion->length > mtd->oobsize)
+               return -ERANGE;
+
+       return 0;
+}
+
+static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
+                                         struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int ecc_offset = 0;
+
+       if (section < 0 || section > 1)
+               return -ERANGE;
+
+       switch (mtd->oobsize) {
+       case 64:
+               ecc_offset = 40;
+               break;
+       case 128:
+               ecc_offset = 80;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (section == 0) {
+               oobregion->offset = 2;
+               oobregion->length = ecc_offset - 2;
+       } else {
+               oobregion->offset = ecc_offset + ecc->total;
+               oobregion->length = mtd->oobsize - oobregion->offset;
+       }
+
+       return 0;
+}
+
+const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
+       .ecc = nand_ooblayout_ecc_lp_hamming,
+       .free = nand_ooblayout_free_lp_hamming,
+};
+
 static int check_offs_len(struct mtd_info *mtd,
                                        loff_t ofs, uint64_t len)
 {
@@ -354,40 +422,32 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
  */
 static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
-       int page, res = 0, i = 0;
+       int page, page_end, res;
        struct nand_chip *chip = mtd_to_nand(mtd);
-       u16 bad;
+       u8 bad;
 
        if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
                ofs += mtd->erasesize - mtd->writesize;
 
        page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+       page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
 
-       do {
-               if (chip->options & NAND_BUSWIDTH_16) {
-                       chip->cmdfunc(mtd, NAND_CMD_READOOB,
-                                       chip->badblockpos & 0xFE, page);
-                       bad = cpu_to_le16(chip->read_word(mtd));
-                       if (chip->badblockpos & 0x1)
-                               bad >>= 8;
-                       else
-                               bad &= 0xFF;
-               } else {
-                       chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
-                                       page);
-                       bad = chip->read_byte(mtd);
-               }
+       for (; page < page_end; page++) {
+               res = chip->ecc.read_oob(mtd, chip, page);
+               if (res)
+                       return res;
+
+               bad = chip->oob_poi[chip->badblockpos];
 
                if (likely(chip->badblockbits == 8))
                        res = bad != 0xFF;
                else
                        res = hweight8(bad) < chip->badblockbits;
-               ofs += mtd->writesize;
-               page = (int)(ofs >> chip->page_shift) & chip->pagemask;
-               i++;
-       } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
+               if (res)
+                       return res;
+       }
 
-       return res;
+       return 0;
 }
 
 /**
@@ -676,6 +736,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:
@@ -794,6 +856,8 @@ static void nand_command_lp(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_RNDIN:
@@ -978,12 +1042,13 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 /**
  * nand_reset_data_interface - Reset data interface and timings
  * @chip: The NAND chip
+ * @chipnr: Internal die id
  *
  * 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)
+static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        const struct nand_data_interface *conf;
@@ -1007,7 +1072,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
         */
 
        conf = nand_get_default_data_interface();
-       ret = chip->setup_data_interface(mtd, conf, false);
+       ret = chip->setup_data_interface(mtd, chipnr, conf);
        if (ret)
                pr_err("Failed to configure data interface to SDR timing mode 0\n");
 
@@ -1017,6 +1082,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
 /**
  * nand_setup_data_interface - Setup the best data interface and timings
  * @chip: The NAND chip
+ * @chipnr: Internal die id
  *
  * Find and configure the best data interface and NAND timings supported by
  * the chip and the driver.
@@ -1026,7 +1092,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
  *
  * Returns 0 for success or negative error code otherwise.
  */
-static int nand_setup_data_interface(struct nand_chip *chip)
+static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
@@ -1050,7 +1116,7 @@ static int nand_setup_data_interface(struct nand_chip *chip)
                        goto err;
        }
 
-       ret = chip->setup_data_interface(mtd, chip->data_interface, false);
+       ret = chip->setup_data_interface(mtd, chipnr, chip->data_interface);
 err:
        return ret;
 }
@@ -1101,8 +1167,10 @@ static int nand_init_data_interface(struct nand_chip *chip)
                if (ret)
                        continue;
 
-               ret = chip->setup_data_interface(mtd, chip->data_interface,
-                                                true);
+               /* Pass -1 to only */
+               ret = chip->setup_data_interface(mtd,
+                                                NAND_DATA_IFACE_CHECK_ONLY,
+                                                chip->data_interface);
                if (!ret) {
                        chip->onfi_timing_mode_default = mode;
                        break;
@@ -1129,7 +1197,7 @@ 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);
+       ret = nand_reset_data_interface(chip, chipnr);
        if (ret)
                return ret;
 
@@ -1142,7 +1210,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
        chip->select_chip(mtd, -1);
 
        chip->select_chip(mtd, chipnr);
-       ret = nand_setup_data_interface(chip);
+       ret = nand_setup_data_interface(chip, chipnr);
        chip->select_chip(mtd, -1);
        if (ret)
                return ret;
@@ -1357,7 +1425,10 @@ static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
 
        for (; len >= sizeof(long);
             len -= sizeof(long), bitmap += sizeof(long)) {
-               weight = hweight_long(*((unsigned long *)bitmap));
+               unsigned long d = *((unsigned long *)bitmap);
+               if (d == ~0UL)
+                       continue;
+               weight = hweight_long(d);
                bitflips += BITS_PER_LONG - weight;
                if (unlikely(bitflips > bitflips_threshold))
                        return -EBADMSG;
@@ -1460,14 +1531,15 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
  *
  * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
-static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                             uint8_t *buf, int oob_required, int page)
+int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                      uint8_t *buf, int oob_required, int page)
 {
        chip->read_buf(mtd, buf, mtd->writesize);
        if (oob_required)
                chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
        return 0;
 }
+EXPORT_SYMBOL(nand_read_page_raw);
 
 /**
  * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
@@ -1958,7 +2030,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 = !virt_addr_valid(buf);
+                       use_bufpoi = !virt_addr_valid(buf) ||
+                                    !IS_ALIGNED((unsigned long)buf,
+                                                chip->buf_align);
                else
                        use_bufpoi = 0;
 
@@ -1997,8 +2071,6 @@ read_retry:
                                break;
                        }
 
-                       max_bitflips = max_t(unsigned int, max_bitflips, ret);
-
                        /* Transfer not aligned data */
                        if (use_bufpoi) {
                                if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
@@ -2049,6 +2121,7 @@ read_retry:
                        }
 
                        buf += bytes;
+                       max_bitflips = max_t(unsigned int, max_bitflips, ret);
                } else {
                        memcpy(buf, chip->buffers->databuf + col, bytes);
                        buf += bytes;
@@ -2404,8 +2477,8 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
  *
  * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
-static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                              const uint8_t *buf, int oob_required, int page)
+int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                       const uint8_t *buf, int oob_required, int page)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        if (oob_required)
@@ -2413,6 +2486,7 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
 
        return 0;
 }
+EXPORT_SYMBOL(nand_write_page_raw);
 
 /**
  * nand_write_page_raw_syndrome - [INTERN] raw page write function
@@ -2637,7 +2711,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
 }
 
 /**
- * nand_write_page - [REPLACEABLE] write one page
+ * nand_write_page - write one page
  * @mtd: MTD device structure
  * @chip: NAND chip descriptor
  * @offset: address offset within the page
@@ -2815,7 +2889,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                if (part_pagewr)
                        use_bufpoi = 1;
                else if (chip->options & NAND_USE_BOUNCE_BUFFER)
-                       use_bufpoi = !virt_addr_valid(buf);
+                       use_bufpoi = !virt_addr_valid(buf) ||
+                                    !IS_ALIGNED((unsigned long)buf,
+                                                chip->buf_align);
                else
                        use_bufpoi = 0;
 
@@ -2840,9 +2916,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                        /* We still need to erase leftover OOB data */
                        memset(chip->oob_poi, 0xff, mtd->oobsize);
                }
-               ret = chip->write_page(mtd, chip, column, bytes, wbuf,
-                                       oob_required, page, cached,
-                                       (ops->mode == MTD_OPS_RAW));
+
+               ret = nand_write_page(mtd, chip, column, bytes, wbuf,
+                                     oob_required, page, cached,
+                                     (ops->mode == MTD_OPS_RAW));
                if (ret)
                        break;
 
@@ -3350,6 +3427,25 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
        return 0;
 }
 
+/**
+ * nand_onfi_get_set_features_notsupp - set/get features stub returning
+ *                                     -ENOTSUPP
+ * @mtd: MTD device structure
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ *
+ * Should be used by NAND controller drivers that do not support the SET/GET
+ * FEATURES operations.
+ */
+int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
+                                      struct nand_chip *chip, int addr,
+                                      u8 *subfeature_param)
+{
+       return -ENOTSUPP;
+}
+EXPORT_SYMBOL(nand_onfi_get_set_features_notsupp);
+
 /**
  * nand_suspend - [MTD Interface] Suspend the NAND flash
  * @mtd: MTD device structure
@@ -3385,8 +3481,10 @@ static void nand_shutdown(struct mtd_info *mtd)
 }
 
 /* Set default functions */
-static void nand_set_defaults(struct nand_chip *chip, int busw)
+static void nand_set_defaults(struct nand_chip *chip)
 {
+       unsigned int busw = chip->options & NAND_BUSWIDTH_16;
+
        /* check for proper chip_delay setup, set 20us if not */
        if (!chip->chip_delay)
                chip->chip_delay = 20;
@@ -3431,6 +3529,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
                nand_hw_control_init(chip->controller);
        }
 
+       if (!chip->buf_align)
+               chip->buf_align = 1;
 }
 
 /* Sanitize ONFI strings so we can safely print them */
@@ -3464,9 +3564,10 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
 }
 
 /* Parse the Extended Parameter Page. */
-static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
-               struct nand_chip *chip, struct nand_onfi_params *p)
+static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
+                                           struct nand_onfi_params *p)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct onfi_ext_param_page *ep;
        struct onfi_ext_section *s;
        struct onfi_ext_ecc_info *ecc;
@@ -3534,36 +3635,12 @@ ext_out:
        return ret;
 }
 
-static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
-
-       return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
-                       feature);
-}
-
-/*
- * Configure chip properties from Micron vendor-specific ONFI table
- */
-static void nand_onfi_detect_micron(struct nand_chip *chip,
-               struct nand_onfi_params *p)
-{
-       struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
-
-       if (le16_to_cpu(p->vendor_revision) < 1)
-               return;
-
-       chip->read_retries = micron->read_retry_options;
-       chip->setup_read_retry = nand_setup_read_retry_micron;
-}
-
 /*
  * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
  */
-static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
-                                       int *busw)
+static int nand_flash_detect_onfi(struct nand_chip *chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_onfi_params *p = &chip->onfi_params;
        int i, j;
        int val;
@@ -3633,9 +3710,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
 
        if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
-               *busw = NAND_BUSWIDTH_16;
-       else
-               *busw = 0;
+               chip->options |= NAND_BUSWIDTH_16;
 
        if (p->ecc_bits != 0xff) {
                chip->ecc_strength_ds = p->ecc_bits;
@@ -3653,24 +3728,21 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
                        chip->cmdfunc = nand_command_lp;
 
                /* The Extended Parameter Page is supported since ONFI 2.1. */
-               if (nand_flash_detect_ext_param_page(mtd, chip, p))
+               if (nand_flash_detect_ext_param_page(chip, p))
                        pr_warn("Failed to detect ONFI extended param page\n");
        } else {
                pr_warn("Could not retrieve ONFI ECC requirements\n");
        }
 
-       if (p->jedec_id == NAND_MFR_MICRON)
-               nand_onfi_detect_micron(chip, p);
-
        return 1;
 }
 
 /*
  * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
  */
-static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
-                                       int *busw)
+static int nand_flash_detect_jedec(struct nand_chip *chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_jedec_params *p = &chip->jedec_params;
        struct jedec_ecc_info *ecc;
        int val;
@@ -3729,9 +3801,7 @@ static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
        chip->bits_per_cell = p->bits_per_cell;
 
        if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
-               *busw = NAND_BUSWIDTH_16;
-       else
-               *busw = 0;
+               chip->options |= NAND_BUSWIDTH_16;
 
        /* ECC info */
        ecc = &p->ecc_info[0];
@@ -3820,165 +3890,46 @@ static int nand_get_bits_per_cell(u8 cellinfo)
  * chip. The rest of the parameters must be decoded according to generic or
  * manufacturer-specific "extended ID" decoding patterns.
  */
-static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
-                               u8 id_data[8], int *busw)
+void nand_decode_ext_id(struct nand_chip *chip)
 {
-       int extid, id_len;
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int extid;
+       u8 *id_data = chip->id.data;
        /* The 3rd id byte holds MLC / multichip data */
        chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
        /* The 4th id byte is the important one */
        extid = id_data[3];
 
-       id_len = nand_id_len(id_data, 8);
-
-       /*
-        * Field definitions are in the following datasheets:
-        * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
-        * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
-        * Hynix MLC   (6 byte ID): Hynix H27UBG8T2B (p.22)
-        *
-        * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
-        * ID to decide what to do.
-        */
-       if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
-                       !nand_is_slc(chip) && id_data[5] != 0x00) {
-               /* Calc pagesize */
-               mtd->writesize = 2048 << (extid & 0x03);
-               extid >>= 2;
-               /* Calc oobsize */
-               switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
-               case 1:
-                       mtd->oobsize = 128;
-                       break;
-               case 2:
-                       mtd->oobsize = 218;
-                       break;
-               case 3:
-                       mtd->oobsize = 400;
-                       break;
-               case 4:
-                       mtd->oobsize = 436;
-                       break;
-               case 5:
-                       mtd->oobsize = 512;
-                       break;
-               case 6:
-                       mtd->oobsize = 640;
-                       break;
-               case 7:
-               default: /* Other cases are "reserved" (unknown) */
-                       mtd->oobsize = 1024;
-                       break;
-               }
-               extid >>= 2;
-               /* Calc blocksize */
-               mtd->erasesize = (128 * 1024) <<
-                       (((extid >> 1) & 0x04) | (extid & 0x03));
-               *busw = 0;
-       } else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
-                       !nand_is_slc(chip)) {
-               unsigned int tmp;
-
-               /* Calc pagesize */
-               mtd->writesize = 2048 << (extid & 0x03);
-               extid >>= 2;
-               /* Calc oobsize */
-               switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
-               case 0:
-                       mtd->oobsize = 128;
-                       break;
-               case 1:
-                       mtd->oobsize = 224;
-                       break;
-               case 2:
-                       mtd->oobsize = 448;
-                       break;
-               case 3:
-                       mtd->oobsize = 64;
-                       break;
-               case 4:
-                       mtd->oobsize = 32;
-                       break;
-               case 5:
-                       mtd->oobsize = 16;
-                       break;
-               default:
-                       mtd->oobsize = 640;
-                       break;
-               }
-               extid >>= 2;
-               /* Calc blocksize */
-               tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
-               if (tmp < 0x03)
-                       mtd->erasesize = (128 * 1024) << tmp;
-               else if (tmp == 0x03)
-                       mtd->erasesize = 768 * 1024;
-               else
-                       mtd->erasesize = (64 * 1024) << tmp;
-               *busw = 0;
-       } else {
-               /* Calc pagesize */
-               mtd->writesize = 1024 << (extid & 0x03);
-               extid >>= 2;
-               /* Calc oobsize */
-               mtd->oobsize = (8 << (extid & 0x01)) *
-                       (mtd->writesize >> 9);
-               extid >>= 2;
-               /* Calc blocksize. Blocksize is multiples of 64KiB */
-               mtd->erasesize = (64 * 1024) << (extid & 0x03);
-               extid >>= 2;
-               /* Get buswidth information */
-               *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
-
-               /*
-                * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
-                * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
-                * follows:
-                * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
-                *                         110b -> 24nm
-                * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
-                */
-               if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
-                               nand_is_slc(chip) &&
-                               (id_data[5] & 0x7) == 0x6 /* 24nm */ &&
-                               !(id_data[4] & 0x80) /* !BENAND */) {
-                       mtd->oobsize = 32 * mtd->writesize >> 9;
-               }
-
-       }
+       /* Calc pagesize */
+       mtd->writesize = 1024 << (extid & 0x03);
+       extid >>= 2;
+       /* Calc oobsize */
+       mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
+       extid >>= 2;
+       /* Calc blocksize. Blocksize is multiples of 64KiB */
+       mtd->erasesize = (64 * 1024) << (extid & 0x03);
+       extid >>= 2;
+       /* Get buswidth information */
+       if (extid & 0x1)
+               chip->options |= NAND_BUSWIDTH_16;
 }
+EXPORT_SYMBOL_GPL(nand_decode_ext_id);
 
 /*
  * Old devices have chip data hardcoded in the device ID table. nand_decode_id
  * decodes a matching ID table entry and assigns the MTD size parameters for
  * the chip.
  */
-static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
-                               struct nand_flash_dev *type, u8 id_data[8],
-                               int *busw)
+static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
 {
-       int maf_id = id_data[0];
+       struct mtd_info *mtd = nand_to_mtd(chip);
 
        mtd->erasesize = type->erasesize;
        mtd->writesize = type->pagesize;
        mtd->oobsize = mtd->writesize / 32;
-       *busw = type->options & NAND_BUSWIDTH_16;
 
        /* All legacy ID NAND are small-page, SLC */
        chip->bits_per_cell = 1;
-
-       /*
-        * Check for Spansion/AMD ID + repeating 5th, 6th byte since
-        * some Spansion chips have erasesize that conflicts with size
-        * listed in nand_ids table.
-        * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
-        */
-       if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00
-                       && id_data[6] == 0x00 && id_data[7] == 0x00
-                       && mtd->writesize == 512) {
-               mtd->erasesize = 128 * 1024;
-               mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
-       }
 }
 
 /*
@@ -3986,36 +3937,15 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
  * heuristic patterns using various detected parameters (e.g., manufacturer,
  * page size, cell-type information).
  */
-static void nand_decode_bbm_options(struct mtd_info *mtd,
-                                   struct nand_chip *chip, u8 id_data[8])
+static void nand_decode_bbm_options(struct nand_chip *chip)
 {
-       int maf_id = id_data[0];
+       struct mtd_info *mtd = nand_to_mtd(chip);
 
        /* Set the bad block position */
        if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
                chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
        else
                chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
-
-       /*
-        * Bad block marker is stored in the last page of each block on Samsung
-        * and Hynix MLC devices; stored in first two pages of each block on
-        * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
-        * AMD/Spansion, and Macronix.  All others scan only the first page.
-        */
-       if (!nand_is_slc(chip) &&
-                       (maf_id == NAND_MFR_SAMSUNG ||
-                        maf_id == NAND_MFR_HYNIX))
-               chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
-       else if ((nand_is_slc(chip) &&
-                               (maf_id == NAND_MFR_SAMSUNG ||
-                                maf_id == NAND_MFR_HYNIX ||
-                                maf_id == NAND_MFR_TOSHIBA ||
-                                maf_id == NAND_MFR_AMD ||
-                                maf_id == NAND_MFR_MACRONIX)) ||
-                       (mtd->writesize == 2048 &&
-                        maf_id == NAND_MFR_MICRON))
-               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
 }
 
 static inline bool is_full_id_nand(struct nand_flash_dev *type)
@@ -4023,9 +3953,12 @@ static inline bool is_full_id_nand(struct nand_flash_dev *type)
        return type->id_len;
 }
 
-static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
-                  struct nand_flash_dev *type, u8 *id_data, int *busw)
+static bool find_full_id_nand(struct nand_chip *chip,
+                             struct nand_flash_dev *type)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       u8 *id_data = chip->id.data;
+
        if (!strncmp(type->id, id_data, type->id_len)) {
                mtd->writesize = type->pagesize;
                mtd->erasesize = type->erasesize;
@@ -4039,8 +3972,6 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
                chip->onfi_timing_mode_default =
                                        type->onfi_timing_mode_default;
 
-               *busw = type->options & NAND_BUSWIDTH_16;
-
                if (!mtd->name)
                        mtd->name = type->name;
 
@@ -4049,16 +3980,64 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
        return false;
 }
 
+/*
+ * Manufacturer detection. Only used when the NAND is not ONFI or JEDEC
+ * compliant and does not have a full-id or legacy-id entry in the nand_ids
+ * table.
+ */
+static void nand_manufacturer_detect(struct nand_chip *chip)
+{
+       /*
+        * Try manufacturer detection if available and use
+        * nand_decode_ext_id() otherwise.
+        */
+       if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+           chip->manufacturer.desc->ops->detect)
+               chip->manufacturer.desc->ops->detect(chip);
+       else
+               nand_decode_ext_id(chip);
+}
+
+/*
+ * Manufacturer initialization. This function is called for all NANDs including
+ * ONFI and JEDEC compliant ones.
+ * Manufacturer drivers should put all their specific initialization code in
+ * their ->init() hook.
+ */
+static int nand_manufacturer_init(struct nand_chip *chip)
+{
+       if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops ||
+           !chip->manufacturer.desc->ops->init)
+               return 0;
+
+       return chip->manufacturer.desc->ops->init(chip);
+}
+
+/*
+ * Manufacturer cleanup. This function is called for all NANDs including
+ * ONFI and JEDEC compliant ones.
+ * Manufacturer drivers should put all their specific cleanup code in their
+ * ->cleanup() hook.
+ */
+static void nand_manufacturer_cleanup(struct nand_chip *chip)
+{
+       /* Release manufacturer private data */
+       if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+           chip->manufacturer.desc->ops->cleanup)
+               chip->manufacturer.desc->ops->cleanup(chip);
+}
+
 /*
  * Get the flash and manufacturer id and lookup if the type is supported.
  */
-static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
-                              int *maf_id, int *dev_id,
-                              struct nand_flash_dev *type)
+static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
 {
+       const struct nand_manufacturer *manufacturer;
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int busw;
-       int i, maf_idx;
-       u8 id_data[8];
+       int i, ret;
+       u8 *id_data = chip->id.data;
+       u8 maf_id, dev_id;
 
        /*
         * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
@@ -4073,8 +4052,8 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
 
        /* Read manufacturer and device IDs */
-       *maf_id = chip->read_byte(mtd);
-       *dev_id = chip->read_byte(mtd);
+       maf_id = chip->read_byte(mtd);
+       dev_id = chip->read_byte(mtd);
 
        /*
         * Try again to make sure, as some systems the bus-hold or other
@@ -4089,20 +4068,41 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0; i < 8; i++)
                id_data[i] = chip->read_byte(mtd);
 
-       if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
+       if (id_data[0] != maf_id || id_data[1] != dev_id) {
                pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
-                       *maf_id, *dev_id, id_data[0], id_data[1]);
+                       maf_id, dev_id, id_data[0], id_data[1]);
                return -ENODEV;
        }
 
+       chip->id.len = nand_id_len(id_data, 8);
+
+       /* Try to identify manufacturer */
+       manufacturer = nand_get_manufacturer(maf_id);
+       chip->manufacturer.desc = manufacturer;
+
        if (!type)
                type = nand_flash_ids;
 
+       /*
+        * Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
+        * override it.
+        * This is required to make sure initial NAND bus width set by the
+        * NAND controller driver is coherent with the real NAND bus width
+        * (extracted by auto-detection code).
+        */
+       busw = chip->options & NAND_BUSWIDTH_16;
+
+       /*
+        * The flag is only set (never cleared), reset it to its default value
+        * before starting auto-detection.
+        */
+       chip->options &= ~NAND_BUSWIDTH_16;
+
        for (; type->name != NULL; type++) {
                if (is_full_id_nand(type)) {
-                       if (find_full_id_nand(mtd, chip, type, id_data, &busw))
+                       if (find_full_id_nand(chip, type))
                                goto ident_done;
-               } else if (*dev_id == type->dev_id) {
+               } else if (dev_id == type->dev_id) {
                        break;
                }
        }
@@ -4110,11 +4110,11 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
        chip->onfi_version = 0;
        if (!type->name || !type->pagesize) {
                /* Check if the chip is ONFI compliant */
-               if (nand_flash_detect_onfi(mtd, chip, &busw))
+               if (nand_flash_detect_onfi(chip))
                        goto ident_done;
 
                /* Check if the chip is JEDEC compliant */
-               if (nand_flash_detect_jedec(mtd, chip, &busw))
+               if (nand_flash_detect_jedec(chip))
                        goto ident_done;
        }
 
@@ -4126,48 +4126,34 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
 
        chip->chipsize = (uint64_t)type->chipsize << 20;
 
-       if (!type->pagesize) {
-               /* Decode parameters from extended ID */
-               nand_decode_ext_id(mtd, chip, id_data, &busw);
-       } else {
-               nand_decode_id(mtd, chip, type, id_data, &busw);
-       }
+       if (!type->pagesize)
+               nand_manufacturer_detect(chip);
+       else
+               nand_decode_id(chip, type);
+
        /* Get chip options */
        chip->options |= type->options;
 
-       /*
-        * Check if chip is not a Samsung device. Do not clear the
-        * options for chips which do not have an extended id.
-        */
-       if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
-               chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
 ident_done:
 
-       /* Try to identify manufacturer */
-       for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
-               if (nand_manuf_ids[maf_idx].id == *maf_id)
-                       break;
-       }
-
        if (chip->options & NAND_BUSWIDTH_AUTO) {
-               WARN_ON(chip->options & NAND_BUSWIDTH_16);
-               chip->options |= busw;
-               nand_set_defaults(chip, busw);
+               WARN_ON(busw & NAND_BUSWIDTH_16);
+               nand_set_defaults(chip);
        } else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
                /*
                 * Check, if buswidth is correct. Hardware drivers should set
                 * chip correct!
                 */
                pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
-                       *maf_id, *dev_id);
-               pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
-               pr_warn("bus width %d instead %d bit\n",
-                          (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
-                          busw ? 16 : 8);
+                       maf_id, dev_id);
+               pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+                       mtd->name);
+               pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
+                       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
                return -EINVAL;
        }
 
-       nand_decode_bbm_options(mtd, chip, id_data);
+       nand_decode_bbm_options(chip);
 
        /* Calculate the address shift from the page size */
        chip->page_shift = ffs(mtd->writesize) - 1;
@@ -4190,18 +4176,22 @@ ident_done:
        if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
                chip->cmdfunc = nand_command_lp;
 
+       ret = nand_manufacturer_init(chip);
+       if (ret)
+               return ret;
+
        pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
-               *maf_id, *dev_id);
+               maf_id, dev_id);
 
        if (chip->onfi_version)
-               pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
-                               chip->onfi_params.model);
+               pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+                       chip->onfi_params.model);
        else if (chip->jedec_version)
-               pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
-                               chip->jedec_params.model);
+               pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+                       chip->jedec_params.model);
        else
-               pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
-                               type->name);
+               pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
+                       type->name);
 
        pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
                (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
@@ -4215,6 +4205,7 @@ static const char * const nand_ecc_modes[] = {
        [NAND_ECC_HW]           = "hw",
        [NAND_ECC_HW_SYNDROME]  = "hw_syndrome",
        [NAND_ECC_HW_OOB_FIRST] = "hw_oob_first",
+       [NAND_ECC_ON_DIE]       = "on-die",
 };
 
 static int of_get_nand_ecc_mode(struct device_node *np)
@@ -4333,12 +4324,6 @@ static int nand_dt_init(struct nand_chip *chip)
        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;
 
@@ -4391,10 +4376,10 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                return -EINVAL;
        }
        /* Set the default functions */
-       nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
+       nand_set_defaults(chip);
 
        /* Read the flash type */
-       ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table);
+       ret = nand_detect(chip, table);
        if (ret) {
                if (!(chip->options & NAND_SCAN_SILENT_NODEV))
                        pr_warn("No NAND device found\n");
@@ -4415,10 +4400,13 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
         * For the other dies, nand_reset() will automatically switch to the
         * best mode for us.
         */
-       ret = nand_setup_data_interface(chip);
+       ret = nand_setup_data_interface(chip, 0);
        if (ret)
                return ret;
 
+       nand_maf_id = chip->id.data[0];
+       nand_dev_id = chip->id.data[1];
+
        chip->select_chip(mtd, -1);
 
        /* Check for a chip array */
@@ -4610,7 +4598,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
-       struct nand_buffers *nbuf;
+       struct nand_buffers *nbuf = NULL;
        int ret;
 
        /* New bad blocks should be marked in OOB, flash-based BBT, or both */
@@ -4624,13 +4612,28 @@ int nand_scan_tail(struct mtd_info *mtd)
        }
 
        if (!(chip->options & NAND_OWN_BUFFERS)) {
-               nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
-                               + mtd->oobsize * 3, GFP_KERNEL);
+               nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL);
                if (!nbuf)
                        return -ENOMEM;
-               nbuf->ecccalc = (uint8_t *)(nbuf + 1);
-               nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
-               nbuf->databuf = nbuf->ecccode + mtd->oobsize;
+
+               nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL);
+               if (!nbuf->ecccalc) {
+                       ret = -ENOMEM;
+                       goto err_free;
+               }
+
+               nbuf->ecccode = kmalloc(mtd->oobsize, GFP_KERNEL);
+               if (!nbuf->ecccode) {
+                       ret = -ENOMEM;
+                       goto err_free;
+               }
+
+               nbuf->databuf = kmalloc(mtd->writesize + mtd->oobsize,
+                                       GFP_KERNEL);
+               if (!nbuf->databuf) {
+                       ret = -ENOMEM;
+                       goto err_free;
+               }
 
                chip->buffers = nbuf;
        } else {
@@ -4653,7 +4656,7 @@ int nand_scan_tail(struct mtd_info *mtd)
                        break;
                case 64:
                case 128:
-                       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+                       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops);
                        break;
                default:
                        WARN(1, "No oob scheme defined for oobsize %d\n",
@@ -4663,9 +4666,6 @@ int nand_scan_tail(struct mtd_info *mtd)
                }
        }
 
-       if (!chip->write_page)
-               chip->write_page = nand_write_page;
-
        /*
         * Check ECC mode, default to software if 3byte/512byte hardware ECC is
         * selected and we have 256 byte pagesize fallback to software ECC
@@ -4746,6 +4746,18 @@ int nand_scan_tail(struct mtd_info *mtd)
                }
                break;
 
+       case NAND_ECC_ON_DIE:
+               if (!ecc->read_page || !ecc->write_page) {
+                       WARN(1, "No ECC functions supplied; on-die ECC not possible\n");
+                       ret = -EINVAL;
+                       goto err_free;
+               }
+               if (!ecc->read_oob)
+                       ecc->read_oob = nand_read_oob_std;
+               if (!ecc->write_oob)
+                       ecc->write_oob = nand_write_oob_std;
+               break;
+
        case NAND_ECC_NONE:
                pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
                ecc->read_page = nand_read_page_raw;
@@ -4873,8 +4885,12 @@ int nand_scan_tail(struct mtd_info *mtd)
        /* Build bad block table */
        return chip->scan_bbt(mtd);
 err_free:
-       if (!(chip->options & NAND_OWN_BUFFERS))
-               kfree(chip->buffers);
+       if (nbuf) {
+               kfree(nbuf->databuf);
+               kfree(nbuf->ecccode);
+               kfree(nbuf->ecccalc);
+               kfree(nbuf);
+       }
        return ret;
 }
 EXPORT_SYMBOL(nand_scan_tail);
@@ -4925,13 +4941,20 @@ void nand_cleanup(struct nand_chip *chip)
 
        /* Free bad block table memory */
        kfree(chip->bbt);
-       if (!(chip->options & NAND_OWN_BUFFERS))
+       if (!(chip->options & NAND_OWN_BUFFERS) && chip->buffers) {
+               kfree(chip->buffers->databuf);
+               kfree(chip->buffers->ecccode);
+               kfree(chip->buffers->ecccalc);
                kfree(chip->buffers);
+       }
 
        /* Free bad block descriptor memory */
        if (chip->badblock_pattern && chip->badblock_pattern->options
                        & NAND_BBT_DYNAMICSTRUCT)
                kfree(chip->badblock_pattern);
+
+       /* Free manufacturer priv data. */
+       nand_manufacturer_cleanup(chip);
 }
 EXPORT_SYMBOL_GPL(nand_cleanup);