]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/mtd/nand/nand_base.c
Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-opp'
[linux.git] / drivers / mtd / nand / nand_base.c
index 3bde96a3f7bfd5b8f066fc56af91fb1983279cdf..1492c12906f6bd3f83bedc05c14f8b7ee7d80963 100644 (file)
@@ -709,6 +709,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
        nand_wait_ready(mtd);
 }
 
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+       /*
+        * The controller already takes care of waiting for tCCS when the RNDIN
+        * or RNDOUT command is sent, return directly.
+        */
+       if (!(chip->options & NAND_WAIT_TCCS))
+               return;
+
+       /*
+        * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+        * (which should be safe for all NANDs).
+        */
+       if (chip->data_interface && chip->data_interface->timings.sdr.tCCS_min)
+               ndelay(chip->data_interface->timings.sdr.tCCS_min / 1000);
+       else
+               ndelay(500);
+}
+
 /**
  * nand_command_lp - [DEFAULT] Send command to NAND large page device
  * @mtd: MTD device structure
@@ -773,10 +792,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
        case NAND_CMD_ERASE1:
        case NAND_CMD_ERASE2:
        case NAND_CMD_SEQIN:
-       case NAND_CMD_RNDIN:
        case NAND_CMD_STATUS:
                return;
 
+       case NAND_CMD_RNDIN:
+               nand_ccs_delay(chip);
+               return;
+
        case NAND_CMD_RESET:
                if (chip->dev_ready)
                        break;
@@ -795,6 +817,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);
+
+               nand_ccs_delay(chip);
                return;
 
        case NAND_CMD_READ0:
@@ -1946,7 +1970,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,
@@ -2634,7 +2659,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,
@@ -2657,7 +2683,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        if (!cached || !NAND_HAS_CACHEPROG(chip)) {
 
-               chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+               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
@@ -3235,6 +3262,42 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
        return nand_block_markbad_lowlevel(mtd, ofs);
 }
 
+/**
+ * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ * @len: length of mtd
+ */
+static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       u32 part_start_block;
+       u32 part_end_block;
+       u32 part_start_die;
+       u32 part_end_die;
+
+       /*
+        * max_bb_per_die and blocks_per_die used to determine
+        * the maximum bad block count.
+        */
+       if (!chip->max_bb_per_die || !chip->blocks_per_die)
+               return -ENOTSUPP;
+
+       /* Get the start and end of the partition in erase blocks. */
+       part_start_block = mtd_div_by_eb(ofs, mtd);
+       part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1;
+
+       /* Get the start and end LUNs of the partition. */
+       part_start_die = part_start_block / chip->blocks_per_die;
+       part_end_die = part_end_block / chip->blocks_per_die;
+
+       /*
+        * Look up the bad blocks per unit and multiply by the number of units
+        * that the partition spans.
+        */
+       return chip->max_bb_per_die * (part_end_die - part_start_die + 1);
+}
+
 /**
  * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
  * @mtd: MTD device structure
@@ -3565,6 +3628,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
        chip->bits_per_cell = p->bits_per_cell;
 
+       chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
+       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
@@ -3985,10 +4051,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
 /*
  * Get the flash and manufacturer id and lookup if the type is supported.
  */
-static struct nand_flash_dev *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_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
+                              int *maf_id, int *dev_id,
+                              struct nand_flash_dev *type)
 {
        int busw;
        int i, maf_idx;
@@ -4026,7 +4091,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        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]);
-               return ERR_PTR(-ENODEV);
+               return -ENODEV;
        }
 
        if (!type)
@@ -4053,7 +4118,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        }
 
        if (!type->name)
-               return ERR_PTR(-ENODEV);
+               return -ENODEV;
 
        if (!mtd->name)
                mtd->name = type->name;
@@ -4098,7 +4163,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                pr_warn("bus width %d instead %d bit\n",
                           (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
                           busw ? 16 : 8);
-               return ERR_PTR(-EINVAL);
+               return -EINVAL;
        }
 
        nand_decode_bbm_options(mtd, chip, id_data);
@@ -4140,7 +4205,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        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",
                mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
-       return type;
+       return 0;
 }
 
 static const char * const nand_ecc_modes[] = {
@@ -4306,7 +4371,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 {
        int i, nand_maf_id, nand_dev_id;
        struct nand_chip *chip = mtd_to_nand(mtd);
-       struct nand_flash_dev *type;
        int ret;
 
        ret = nand_dt_init(chip);
@@ -4329,14 +4393,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
 
        /* Read the flash type */
-       type = nand_get_flash_type(mtd, chip, &nand_maf_id,
-                                  &nand_dev_id, table);
-
-       if (IS_ERR(type)) {
+       ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table);
+       if (ret) {
                if (!(chip->options & NAND_SCAN_SILENT_NODEV))
                        pr_warn("No NAND device found\n");
                chip->select_chip(mtd, -1);
-               return PTR_ERR(type);
+               return ret;
        }
 
        /* Initialize the ->data_interface field. */
@@ -4515,6 +4577,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
@@ -4535,6 +4617,11 @@ int nand_scan_tail(struct mtd_info *mtd)
                   !(chip->bbt_options & NAND_BBT_USE_FLASH)))
                return -EINVAL;
 
+       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(*nbuf) + mtd->writesize
                                + mtd->oobsize * 3, GFP_KERNEL);
@@ -4767,6 +4854,7 @@ int nand_scan_tail(struct mtd_info *mtd)
        mtd->_block_isreserved = nand_block_isreserved;
        mtd->_block_isbad = nand_block_isbad;
        mtd->_block_markbad = nand_block_markbad;
+       mtd->_max_bad_blocks = nand_max_bad_blocks;
        mtd->writebufsize = mtd->writesize;
 
        /*