summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Wu <josh.wu@atmel.com>2013-03-22 17:07:39 +0800
committerJosh Wu <josh.wu@atmel.com>2013-03-22 17:12:52 +0800
commit5a631ad95526c7ea7440581631f5f3dc8a4a2ab8 (patch)
tree70b4fe2c7fee2f6196e1efa075013e71b9caf5e6
parentb887fcac6a9665ebcd3a755f29ed06e13fcf76a7 (diff)
ARM: at91: atmel_nand: add code to check the ONFI parameter ECC requirement
1. if CONFIG_SYS_NAND_ONFI_DETECTION is defined, driver will check NAND flash's ecc minimum requirement in ONFI parameter. a) if CONFIG_PMECC_CAP, CONFIG_PMECC_SECTOR_SIZE are defined. then use it. Driver will display a WARNING if the values are different from ONFI parameters. b) if CONFIG_PMECC_CAP, CONFIG_PMECC_SECTOR_SIZE are not defined, then use the value from ONFI parameters. * If ONFI ECC parameters are in ONFI extended parameter page, since we are not support it, so assume the minimum ecc requirement is 2 bits in 512 bytes. * For non-ONFI support nand flash, also assume the minimum ecc requirement is 2 bits in 512 bytes. 2. if CONFIG_SYS_NAND_ONFI_DETECTION is not defined, just use CONFIG_PMECC_CAP and CONFIG_PMECC_SECTOR_SIZE. Signed-off-by: Josh Wu <josh.wu@atmel.com>
-rw-r--r--drivers/mtd/nand/atmel_nand.c131
1 files changed, 97 insertions, 34 deletions
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index f7e61998bd..edb107760e 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -676,42 +676,84 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
}
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
-static int pmecc_choose_ecc_bits(int pre_ecc_bits, struct nand_chip *nand_chip)
+/*
+ * Get ECC requirement in ONFI parameters, returns -1 if ONFI
+ * parameters is not supported.
+ * return 0 if success to get the ECC requirement.
+ */
+static int get_onfi_ecc_param(struct nand_chip *chip,
+ int *ecc_bits, int *sector_size)
{
- int ecc_bits = pre_ecc_bits;
+ *ecc_bits = *sector_size = 0;
- if (nand_chip->onfi_version) {
- printk(KERN_WARNING "ONFI params, minimum required ECC: %d\n",
- nand_chip->onfi_params.ecc_bits);
- if (nand_chip->onfi_params.ecc_bits < ecc_bits)
- ecc_bits = nand_chip->onfi_params.ecc_bits;
- } else {
- /* For non-ONFI support nand flash, we assume the software
- * ecc can work. That means the ecc_bits = 1.
+ if (chip->onfi_params.ecc_bits == 0xff)
+ /* TODO: the sector_size and ecc_bits need to be find in
+ * extended ecc parameter, currently we don't support it.
*/
- ecc_bits = 1;
- printk(KERN_WARNING "non-ONFI supported nand flash, assume minimum required ECC: 1\n");
+ return -1;
+
+ *ecc_bits = chip->onfi_params.ecc_bits;
+
+ /* The default sector size (ecc codeword size) is 512 */
+ *sector_size = 512;
+
+ return 0;
+}
+
+/*
+ * Get ecc requirement from ONFI parameters ecc requirement.
+ * If pmecc-cap, pmecc-sector-size are not specified in board head file, this
+ * function will set them according to ONFI ecc requirement. Otherwise, use the
+ * value defined in head file.
+ * return 0 if success. otherwise return error code.
+ */
+static int pmecc_choose_ecc(struct atmel_nand_host *host,
+ struct nand_chip *chip,
+ int *cap, int *sector_size)
+{
+ /* Get ECC requirement from ONFI parameters */
+ *cap = *sector_size = 0;
+ if (chip->onfi_version) {
+ if (!get_onfi_ecc_param(chip, cap, sector_size))
+ MTDDEBUG(MTD_DEBUG_LEVEL1, "ONFI params, minimum required ECC: %d bits in %d bytes\n",
+ *cap, *sector_size);
+ else
+ printk(KERN_WARNING "NAND chip ECC reqirement is in Extended ONFI parameter, we don't support yet.\n");
+ } else {
+ printk(KERN_WARNING "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes");
+ }
+ if (*cap == 0 && *sector_size == 0) {
+ /* Non-ONFI compliant or use extended ONFI parameters */
+ *cap = 2;
+ *sector_size = 512;
}
- if ((ecc_bits != 2) && (ecc_bits != 4) && (ecc_bits != 8) && (ecc_bits != 12) &&
- (ecc_bits != 24)) {
+ /* If head file doesn't specify then use the one in ONFI parameters */
+ if (host->pmecc_corr_cap == 0) {
/* use the most fitable ecc bits (the near bigger one ) */
- if (ecc_bits < 2)
- return 2;
- else if (ecc_bits < 4)
- return 4;
- else if (ecc_bits < 8)
- return 8;
- else if (ecc_bits < 12)
- return 12;
- else if (ecc_bits < 24)
- return 24;
+ if (*cap <= 2)
+ host->pmecc_corr_cap = 2;
+ else if (*cap <= 4)
+ host->pmecc_corr_cap = 4;
+ else if (*cap < 8)
+ host->pmecc_corr_cap = 8;
+ else if (*cap < 12)
+ host->pmecc_corr_cap = 12;
+ else if (*cap < 24)
+ host->pmecc_corr_cap = 24;
else
- /* not support by our pmecc hw */
- return pre_ecc_bits;
- } else {
- return ecc_bits;
+ return -EINVAL;
}
+ if (host->pmecc_sector_size == 0) {
+ /* use the most fitable sector size (the near smaller one ) */
+ if (*sector_size >= 1024)
+ host->pmecc_sector_size = 1024;
+ else if (*sector_size >= 512)
+ host->pmecc_sector_size = 512;
+ else
+ return -EINVAL;
+ }
+ return 0;
}
#endif
@@ -729,14 +771,35 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
nand->ecc.hwctl = NULL;
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
- /* Choose PMECC ecc bits according to ONFI parameters */
- host->pmecc_corr_cap = pmecc_choose_ecc_bits(CONFIG_PMECC_CAP, nand);
- cap = host->pmecc_corr_cap;
-#else
- cap = host->pmecc_corr_cap = CONFIG_PMECC_CAP;
+ host->pmecc_corr_cap = host->pmecc_sector_size = 0;
+
+#ifdef CONFIG_PMECC_CAP
+ host->pmecc_corr_cap = CONFIG_PMECC_CAP;
+#endif
+#ifdef CONFIG_PMECC_SECTOR_SIZE
+ host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE;
#endif
+ /* Display the ONFI parameters. And if not define CONFIG_PMECC_CAP or
+ * CONFIG_PMECC_SECTOR_SIZE, then use if from ONFI.
+ */
+ if (pmecc_choose_ecc(host, nand, &cap, &sector_size)) {
+ printk(KERN_WARNING "The NAND flash's ECC requirement are not support!");
+ return -EINVAL;
+ }
+
+ if (cap != host->pmecc_corr_cap ||
+ sector_size != host->pmecc_sector_size)
+ printk(KERN_WARNING "WARNING: Be Caution! Using different PMECC parameters from Nand ONFI ECC reqirement.\n");
+#else /* CONFIG_SYS_NAND_ONFI_DETECTION */
+ host->pmecc_corr_cap = CONFIG_PMECC_CAP;
+ host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE;
+#endif
+
+ cap = host->pmecc_corr_cap;
+ sector_size = host->pmecc_sector_size;
+
+ /* TODO: need check whether cap & sector_size is validate */
- sector_size = host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE;
if (host->pmecc_sector_size == 512)
host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_512;
else