From 519300cfe18ee8dcf0b1e7a38564b61b70e4ee86 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 7 Mar 2012 17:00:49 +0530 Subject: mtd: fsmc: Newly erased page read algorithm implemented A newly erased page contains ff in data as well as spare area. While reading an erased page, the read out ecc from spare area does not match the ecc generated by fsmc ecc hardware accelerator. This is because ecc of data ff ff is not ff ff. This leads to errors when file system erases and reads back the pages to ensure consistency. This patch adds a software workaround to ensure that the ecc check is not performed for erased pages. This problem is solved by checking the number of bits (in 512 byte data + 13 byte ecc) which are 0. If these number of bits are less than 8, the page is considered erased and correction algorithm is not tried on that page Signed-off-by: Vipin Kumar Acked-by: Linus Walleij Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 56 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index e53b76064133..9c7d9d85f756 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -391,6 +391,20 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, return 0; } +/* Count the number of 0's in buff upto a max of max_bits */ +static int count_written_bits(uint8_t *buff, int size, int max_bits) +{ + int k, written_bits = 0; + + for (k = 0; k < size; k++) { + written_bits += hweight8(~buff[k]); + if (written_bits > max_bits) + break; + } + + return written_bits; +} + /* * fsmc_read_page_hwecc * @mtd: mtd info structure @@ -426,7 +440,6 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *oob = (uint8_t *)&ecc_oob[0]; for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { - chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); chip->ecc.hwctl(mtd, NAND_ECC_READ); chip->read_buf(mtd, p, eccsize); @@ -447,7 +460,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, j += len; } - memcpy(&ecc_code[i], oob, 13); + memcpy(&ecc_code[i], oob, chip->ecc.bytes); chip->ecc.calculate(mtd, p, &ecc_calc[i]); stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); @@ -475,14 +488,49 @@ static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, { struct fsmc_nand_data *host = container_of(mtd, struct fsmc_nand_data, mtd); + struct nand_chip *chip = mtd->priv; struct fsmc_regs *regs = host->regs_va; unsigned int bank = host->bank; uint16_t err_idx[8]; uint64_t ecc_data[2]; uint32_t num_err, i; + num_err = (readl(®s->bank_regs[bank].sts) >> 10) & 0xF; + + /* no bit flipping */ + if (likely(num_err == 0)) + return 0; + + /* too many errors */ + if (unlikely(num_err > 8)) { + /* + * This is a temporary erase check. A newly erased page read + * would result in an ecc error because the oob data is also + * erased to FF and the calculated ecc for an FF data is not + * FF..FF. + * This is a workaround to skip performing correction in case + * data is FF..FF + * + * Logic: + * For every page, each bit written as 0 is counted until these + * number of bits are greater than 8 (the maximum correction + * capability of FSMC for each 512 + 13 bytes) + */ + + int bits_ecc = count_written_bits(read_ecc, chip->ecc.bytes, 8); + int bits_data = count_written_bits(dat, chip->ecc.size, 8); + + if ((bits_ecc + bits_data) <= 8) { + if (bits_data) + memset(dat, 0xff, chip->ecc.size); + return bits_data; + } + + return -EBADMSG; + } + /* The calculated ecc is actually the correction index in data */ - memcpy(ecc_data, calc_ecc, 13); + memcpy(ecc_data, calc_ecc, chip->ecc.bytes); /* * ------------------- calc_ecc[] bit wise -----------|--13 bits--| @@ -513,7 +561,7 @@ static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, change_bit(0, (unsigned long *)&err_idx[i]); change_bit(1, (unsigned long *)&err_idx[i]); - if (err_idx[i] <= 512 * 8) { + if (err_idx[i] <= chip->ecc.size * 8) { change_bit(err_idx[i], (unsigned long *)dat); i++; } -- cgit v1.2.3 From e29ee57b1d33abf119cb332a3d8fa69c9cd39096 Mon Sep 17 00:00:00 2001 From: Bhavna Yadav Date: Wed, 7 Mar 2012 17:00:50 +0530 Subject: mtd: fsmc_nand: ECC1 & ECC4 layout separated for different page sizes ECC1 & ECC4 layout for NAND of different pages sizes for e.g. 512bytes, 2KiB, 4KiB and 8KiB are separated. Previously there existed one ECC4 layout for 2KiB & 4KiB page size due to which oob test module available in drivers/mtd/nand/test was failing. Signed-off-by: Bhavna Yadav Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 176 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 159 insertions(+), 17 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 9c7d9d85f756..abbff77fd106 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -34,7 +34,7 @@ #include #include -static struct nand_ecclayout fsmc_ecc1_layout = { +static struct nand_ecclayout fsmc_ecc1_128_layout = { .eccbytes = 24, .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52, 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116}, @@ -50,7 +50,91 @@ static struct nand_ecclayout fsmc_ecc1_layout = { } }; -static struct nand_ecclayout fsmc_ecc4_lp_layout = { +static struct nand_ecclayout fsmc_ecc1_64_layout = { + .eccbytes = 12, + .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52}, + .oobfree = { + {.offset = 8, .length = 8}, + {.offset = 24, .length = 8}, + {.offset = 40, .length = 8}, + {.offset = 56, .length = 8}, + } +}; + +static struct nand_ecclayout fsmc_ecc1_16_layout = { + .eccbytes = 3, + .eccpos = {2, 3, 4}, + .oobfree = { + {.offset = 8, .length = 8}, + } +}; + +/* + * ECC4 layout for NAND of pagesize 8192 bytes & OOBsize 256 bytes. 13*16 bytes + * of OB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block and 46 + * bytes are free for use. + */ +static struct nand_ecclayout fsmc_ecc4_256_layout = { + .eccbytes = 208, + .eccpos = { 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, + 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, + 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, + 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, + 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, + 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, + 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, + 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, + 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, + 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, + 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, + 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, + 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, + 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254 + }, + .oobfree = { + {.offset = 15, .length = 3}, + {.offset = 31, .length = 3}, + {.offset = 47, .length = 3}, + {.offset = 63, .length = 3}, + {.offset = 79, .length = 3}, + {.offset = 95, .length = 3}, + {.offset = 111, .length = 3}, + {.offset = 127, .length = 3}, + {.offset = 143, .length = 3}, + {.offset = 159, .length = 3}, + {.offset = 175, .length = 3}, + {.offset = 191, .length = 3}, + {.offset = 207, .length = 3}, + {.offset = 223, .length = 3}, + {.offset = 239, .length = 3}, + {.offset = 255, .length = 1} + } +}; + +/* + * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 128 bytes. 13*8 bytes + * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 22 + * bytes are free for use. + */ +static struct nand_ecclayout fsmc_ecc4_128_layout = { .eccbytes = 104, .eccpos = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, @@ -81,6 +165,45 @@ static struct nand_ecclayout fsmc_ecc4_lp_layout = { } }; +/* + * ECC4 layout for NAND of pagesize 2048 bytes & OOBsize 64 bytes. 13*4 bytes of + * OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block and 10 + * bytes are free for use. + */ +static struct nand_ecclayout fsmc_ecc4_64_layout = { + .eccbytes = 52, + .eccpos = { 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, + 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, + 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, + }, + .oobfree = { + {.offset = 15, .length = 3}, + {.offset = 31, .length = 3}, + {.offset = 47, .length = 3}, + {.offset = 63, .length = 1}, + } +}; + +/* + * ECC4 layout for NAND of pagesize 512 bytes & OOBsize 16 bytes. 13 bytes of + * OOB size is reserved for ECC, Byte no. 4 & 5 reserved for bad block and One + * byte is free for use. + */ +static struct nand_ecclayout fsmc_ecc4_16_layout = { + .eccbytes = 13, + .eccpos = { 0, 1, 2, 3, 6, 7, 8, + 9, 10, 11, 12, 13, 14 + }, + .oobfree = { + {.offset = 15, .length = 1}, + } +}; + /* * ECC placement definitions in oobfree type format. * There are 13 bytes of ecc for every 512 byte block and it has to be read @@ -103,16 +226,6 @@ static struct fsmc_eccplace fsmc_ecc4_lp_place = { } }; -static struct nand_ecclayout fsmc_ecc4_sp_layout = { - .eccbytes = 13, - .eccpos = { 0, 1, 2, 3, 6, 7, 8, - 9, 10, 11, 12, 13, 14 - }, - .oobfree = { - {.offset = 15, .length = 1}, - } -}; - static struct fsmc_eccplace fsmc_ecc4_sp_place = { .eccplace = { {.offset = 0, .length = 4}, @@ -733,15 +846,44 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) } if (AMBA_REV_BITS(host->pid) >= 8) { - if (host->mtd.writesize == 512) { - nand->ecc.layout = &fsmc_ecc4_sp_layout; + switch (host->mtd.oobsize) { + case 16: + nand->ecc.layout = &fsmc_ecc4_16_layout; host->ecc_place = &fsmc_ecc4_sp_place; - } else { - nand->ecc.layout = &fsmc_ecc4_lp_layout; + break; + case 64: + nand->ecc.layout = &fsmc_ecc4_64_layout; + host->ecc_place = &fsmc_ecc4_lp_place; + break; + case 128: + nand->ecc.layout = &fsmc_ecc4_128_layout; + host->ecc_place = &fsmc_ecc4_lp_place; + break; + case 256: + nand->ecc.layout = &fsmc_ecc4_256_layout; host->ecc_place = &fsmc_ecc4_lp_place; + break; + default: + printk(KERN_WARNING "No oob scheme defined for " + "oobsize %d\n", mtd->oobsize); + BUG(); } } else { - nand->ecc.layout = &fsmc_ecc1_layout; + switch (host->mtd.oobsize) { + case 16: + nand->ecc.layout = &fsmc_ecc1_16_layout; + break; + case 64: + nand->ecc.layout = &fsmc_ecc1_64_layout; + break; + case 128: + nand->ecc.layout = &fsmc_ecc1_128_layout; + break; + default: + printk(KERN_WARNING "No oob scheme defined for " + "oobsize %d\n", mtd->oobsize); + BUG(); + } } /* Second stage of scan to fill MTD data-structures */ -- cgit v1.2.3 From b2acc92e144336dd29e30dc5d26439355be750b6 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Wed, 7 Mar 2012 17:00:51 +0530 Subject: mtd: fsmc: use ALE and CLE offsets from platform data ALE and CLE offsets can be different on different devices. Let devices pass these offsets to the fsmc driver through platform data. Signed-off-by: Shiraz Hashim Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 9 +++++---- include/linux/mtd/fsmc.h | 5 +++++ 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index abbff77fd106..4dda9bb38334 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -729,27 +729,28 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) goto err_probe1; } - host->resaddr = request_mem_region(res->start + PLAT_NAND_ALE, + host->resaddr = request_mem_region(res->start + pdata->ale_off, resource_size(res), pdev->name); if (!host->resaddr) { ret = -EIO; goto err_probe1; } - host->addr_va = ioremap(res->start + PLAT_NAND_ALE, resource_size(res)); + host->addr_va = ioremap(res->start + pdata->ale_off, + resource_size(res)); if (!host->addr_va) { ret = -EIO; goto err_probe1; } - host->rescmd = request_mem_region(res->start + PLAT_NAND_CLE, + host->rescmd = request_mem_region(res->start + pdata->cle_off, resource_size(res), pdev->name); if (!host->rescmd) { ret = -EIO; goto err_probe1; } - host->cmd_va = ioremap(res->start + PLAT_NAND_CLE, resource_size(res)); + host->cmd_va = ioremap(res->start + pdata->cle_off, resource_size(res)); if (!host->cmd_va) { ret = -EIO; goto err_probe1; diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h index 6987995ad3cf..2cd655f06e05 100644 --- a/include/linux/mtd/fsmc.h +++ b/include/linux/mtd/fsmc.h @@ -151,6 +151,11 @@ struct fsmc_nand_platform_data { unsigned int options; unsigned int width; unsigned int bank; + + /* CLE, ALE offsets */ + unsigned long cle_off; + unsigned long ale_off; + void (*select_bank)(uint32_t bank, uint32_t busw); }; -- cgit v1.2.3 From a612c2ae483ee7e4d40c31d5374edf8a8b025f2a Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 7 Mar 2012 17:00:53 +0530 Subject: mtd: fsmc: fixed data abort inside change_bit() Since change_bit() requires a (unsigned int *) as second arg, the correct definition of err_idx[] array declared as local variable of fsmc_correct_data() is the following: u32 err_idx[8]; Signed-off-by: Armando Visconti Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 4dda9bb38334..cfe15a6f29d0 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -604,7 +604,7 @@ static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, struct nand_chip *chip = mtd->priv; struct fsmc_regs *regs = host->regs_va; unsigned int bank = host->bank; - uint16_t err_idx[8]; + uint32_t err_idx[8]; uint64_t ecc_data[2]; uint32_t num_err, i; -- cgit v1.2.3 From 753e0139e5569946056a8d5960111665a7f8f6f1 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 7 Mar 2012 17:00:54 +0530 Subject: mtd: fsmc: Improve the fsmc_correct_data() routine This patch improves the error correction routine for bch8 - Loop only up to number of errors detected - Improve the error index calculation procedure Additionally, it also renames the "correct" routine to indicate that it is bch8 specific Signed-off-by: Armando Visconti Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index cfe15a6f29d0..5b217f2a31b7 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -587,7 +587,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /* - * fsmc_correct_data + * fsmc_bch8_correct_data * @mtd: mtd info structure * @dat: buffer of read data * @read_ecc: ecc read from device spare area @@ -596,7 +596,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * calc_ecc is a 104 bit information containing maximum of 8 error * offset informations of 13 bits each in 512 bytes of read data. */ -static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, +static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { struct fsmc_nand_data *host = container_of(mtd, @@ -605,8 +605,8 @@ static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, struct fsmc_regs *regs = host->regs_va; unsigned int bank = host->bank; uint32_t err_idx[8]; - uint64_t ecc_data[2]; uint32_t num_err, i; + uint32_t ecc1, ecc2, ecc3, ecc4; num_err = (readl(®s->bank_regs[bank].sts) >> 10) & 0xF; @@ -642,9 +642,6 @@ static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, return -EBADMSG; } - /* The calculated ecc is actually the correction index in data */ - memcpy(ecc_data, calc_ecc, chip->ecc.bytes); - /* * ------------------- calc_ecc[] bit wise -----------|--13 bits--| * |---idx[7]--|--.....-----|---idx[2]--||---idx[1]--||---idx[0]--| @@ -654,20 +651,19 @@ static int fsmc_correct_data(struct mtd_info *mtd, uint8_t *dat, * uint64_t array and error offset indexes are populated in err_idx * array */ - for (i = 0; i < 8; i++) { - if (i == 4) { - err_idx[4] = ((ecc_data[1] & 0x1) << 12) | ecc_data[0]; - ecc_data[1] >>= 1; - continue; - } - err_idx[i] = (ecc_data[i/4] & 0x1FFF); - ecc_data[i/4] >>= 13; - } - - num_err = (readl(®s->bank_regs[bank].sts) >> 10) & 0xF; - - if (num_err == 0xF) - return -EBADMSG; + ecc1 = readl(®s->bank_regs[bank].ecc1); + ecc2 = readl(®s->bank_regs[bank].ecc2); + ecc3 = readl(®s->bank_regs[bank].ecc3); + ecc4 = readl(®s->bank_regs[bank].sts); + + err_idx[0] = (ecc1 >> 0) & 0x1FFF; + err_idx[1] = (ecc1 >> 13) & 0x1FFF; + err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F); + err_idx[3] = (ecc2 >> 7) & 0x1FFF; + err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF); + err_idx[5] = (ecc3 >> 1) & 0x1FFF; + err_idx[6] = (ecc3 >> 14) & 0x1FFF; + err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F); i = 0; while (num_err--) { @@ -829,7 +825,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (AMBA_REV_BITS(host->pid) >= 8) { nand->ecc.read_page = fsmc_read_page_hwecc; nand->ecc.calculate = fsmc_read_hwecc_ecc4; - nand->ecc.correct = fsmc_correct_data; + nand->ecc.correct = fsmc_bch8_correct_data; nand->ecc.bytes = 13; } else { nand->ecc.calculate = fsmc_read_hwecc_ecc1; -- cgit v1.2.3 From 0c78e93b44f39d4e5dfd4ebfc529cd74ac2a9bbb Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 7 Mar 2012 17:00:55 +0530 Subject: mtd: fsmc: Support of 224-bytes OOB area length The current patch is required to support EVALSPEAR1340CPU Revision 2 where a new (ONFI compliant) MT29F16G08 NAND flash from Micron is present. This NAND flash device defines a OOB area which is 224 bytes long (oobsize). Signed-off-by: Armando Visconti Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 5b217f2a31b7..4a018d0b7034 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -129,6 +129,42 @@ static struct nand_ecclayout fsmc_ecc4_256_layout = { } }; +/* + * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 224 bytes. 13*8 bytes + * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 118 + * bytes are free for use. + */ +static struct nand_ecclayout fsmc_ecc4_224_layout = { + .eccbytes = 104, + .eccpos = { 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, + 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, + 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, + 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, + 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, + 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126 + }, + .oobfree = { + {.offset = 15, .length = 3}, + {.offset = 31, .length = 3}, + {.offset = 47, .length = 3}, + {.offset = 63, .length = 3}, + {.offset = 79, .length = 3}, + {.offset = 95, .length = 3}, + {.offset = 111, .length = 3}, + {.offset = 127, .length = 97} + } +}; + /* * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 128 bytes. 13*8 bytes * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 22 @@ -856,6 +892,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->ecc.layout = &fsmc_ecc4_128_layout; host->ecc_place = &fsmc_ecc4_lp_place; break; + case 224: + nand->ecc.layout = &fsmc_ecc4_224_layout; + host->ecc_place = &fsmc_ecc4_lp_place; + break; case 256: nand->ecc.layout = &fsmc_ecc4_256_layout; host->ecc_place = &fsmc_ecc4_lp_place; -- cgit v1.2.3 From 42d7fbe223ab878b23de9e3b0166f8cd665a2aa5 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 9 Mar 2012 19:24:26 +0200 Subject: mtd: do not use plain 0 as NULL The first 3 arguments of 'mtd_device_parse_register()' are pointers, but many callers pass '0' instead of 'NULL'. Fix this globally. Thanks to coccinelle for making it easy to do with the following semantic patch: @@ expression mtd, types, parser_data, parts, nr_parts; @@ ( -mtd_device_parse_register(mtd, 0, parser_data, parts, nr_parts) +mtd_device_parse_register(mtd, NULL, parser_data, parts, nr_parts) | -mtd_device_parse_register(mtd, types, 0, parts, nr_parts) +mtd_device_parse_register(mtd, types, NULL, parts, nr_parts) | -mtd_device_parse_register(mtd, types, parser_data, 0, nr_parts) +mtd_device_parse_register(mtd, types, parser_data, NULL, nr_parts) ) Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- arch/mips/cavium-octeon/flash_setup.c | 2 +- drivers/mtd/devices/spear_smi.c | 2 +- drivers/mtd/devices/sst25l.c | 6 +++--- drivers/mtd/maps/bfin-async-flash.c | 4 ++-- drivers/mtd/maps/dc21285.c | 2 +- drivers/mtd/maps/gpio-addr-flash.c | 4 ++-- drivers/mtd/maps/h720x-flash.c | 4 ++-- drivers/mtd/maps/impa7.c | 2 +- drivers/mtd/maps/intel_vr_nor.c | 2 +- drivers/mtd/maps/ixp2000.c | 2 +- drivers/mtd/maps/lantiq-flash.c | 5 +++-- drivers/mtd/maps/latch-addr-flash.c | 5 +++-- drivers/mtd/maps/physmap.c | 2 +- drivers/mtd/maps/plat-ram.c | 5 +++-- drivers/mtd/maps/pxa2xx-flash.c | 3 ++- drivers/mtd/maps/rbtx4939-flash.c | 4 ++-- drivers/mtd/maps/sa1100-flash.c | 4 ++-- drivers/mtd/maps/solutionengine.c | 4 ++-- drivers/mtd/maps/wr_sbc82xx_flash.c | 2 +- drivers/mtd/nand/atmel_nand.c | 4 ++-- drivers/mtd/nand/bcm_umi_nand.c | 2 +- drivers/mtd/nand/cafe_nand.c | 2 +- drivers/mtd/nand/cmx270_nand.c | 2 +- drivers/mtd/nand/cs553x_nand.c | 2 +- drivers/mtd/nand/davinci_nand.c | 4 ++-- drivers/mtd/nand/fsmc_nand.c | 14 +++++++------- drivers/mtd/nand/h1910.c | 4 ++-- drivers/mtd/nand/jz4740_nand.c | 6 +++--- drivers/mtd/nand/mxc_nand.c | 4 ++-- drivers/mtd/nand/omap2.c | 4 ++-- drivers/mtd/nand/orion_nand.c | 4 ++-- drivers/mtd/nand/plat_nand.c | 5 +++-- drivers/mtd/nand/ppchameleonevb.c | 18 ++++++++---------- drivers/mtd/nand/pxa3xx_nand.c | 5 +++-- drivers/mtd/nand/s3c2410.c | 4 ++-- drivers/mtd/nand/sharpsl.c | 4 ++-- drivers/mtd/nand/tmio_nand.c | 6 +++--- drivers/mtd/nand/txx9ndfmc.c | 2 +- drivers/mtd/onenand/generic.c | 6 +++--- drivers/mtd/onenand/omap2.c | 6 +++--- drivers/mtd/onenand/samsung.c | 2 +- 41 files changed, 89 insertions(+), 85 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/arch/mips/cavium-octeon/flash_setup.c b/arch/mips/cavium-octeon/flash_setup.c index 0a430e06f5e5..e44a55bc7f0d 100644 --- a/arch/mips/cavium-octeon/flash_setup.c +++ b/arch/mips/cavium-octeon/flash_setup.c @@ -60,7 +60,7 @@ static int __init flash_init(void) if (mymtd) { mymtd->owner = THIS_MODULE; mtd_device_parse_register(mymtd, part_probe_types, - 0, NULL, 0); + NULL, NULL, 0); } else { pr_err("Failed to register MTD device for flash\n"); } diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index f45dd37b771e..f2016b5f59b6 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -851,7 +851,7 @@ static int spear_smi_setup_banks(struct platform_device *pdev, u32 bank) goto err_map; } } - ret = mtd_device_parse_register(&flash->mtd, NULL, 0, parts, count); + ret = mtd_device_parse_register(&flash->mtd, NULL, NULL, parts, count); if (ret) dev_err(&dev->pdev->dev, "Err MTD partition=%d\n", ret); diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 51b2df33b8e9..ab8a2f4c8d60 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -399,9 +399,9 @@ static int __devinit sst25l_probe(struct spi_device *spi) flash->mtd.numeraseregions); - ret = mtd_device_parse_register(&flash->mtd, NULL, 0, - data ? data->parts : NULL, - data ? data->nr_parts : 0); + ret = mtd_device_parse_register(&flash->mtd, NULL, NULL, + data ? data->parts : NULL, + data ? data->nr_parts : 0); if (ret) { kfree(flash); dev_set_drvdata(&spi->dev, NULL); diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 650126c361f1..ef5cde84a8b3 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -164,8 +164,8 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev) return -ENXIO; } - mtd_device_parse_register(state->mtd, part_probe_types, 0, - pdata->parts, pdata->nr_parts); + mtd_device_parse_register(state->mtd, part_probe_types, NULL, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, state); diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index f43b365b848c..080f06053bd4 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -196,7 +196,7 @@ static int __init init_dc21285(void) dc21285_mtd->owner = THIS_MODULE; - mtd_device_parse_register(dc21285_mtd, probes, 0, NULL, 0); + mtd_device_parse_register(dc21285_mtd, probes, NULL, NULL, 0); if(machine_is_ebsa285()) { /* diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 33cce895859f..e4de96ba52b3 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -252,8 +252,8 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev) } - mtd_device_parse_register(state->mtd, part_probe_types, 0, - pdata->parts, pdata->nr_parts); + mtd_device_parse_register(state->mtd, part_probe_types, NULL, + pdata->parts, pdata->nr_parts); return 0; } diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 49c14187fc66..8ed6cb4529d8 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -85,8 +85,8 @@ static int __init h720x_mtd_init(void) if (mymtd) { mymtd->owner = THIS_MODULE; - mtd_device_parse_register(mymtd, NULL, 0, - h720x_partitions, NUM_PARTITIONS); + mtd_device_parse_register(mymtd, NULL, NULL, + h720x_partitions, NUM_PARTITIONS); return 0; } diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index f47aedb24366..834a06c56f56 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -91,7 +91,7 @@ static int __init init_impa7(void) if (impa7_mtd[i]) { impa7_mtd[i]->owner = THIS_MODULE; devicesfound++; - mtd_device_parse_register(impa7_mtd[i], NULL, 0, + mtd_device_parse_register(impa7_mtd[i], NULL, NULL, partitions, ARRAY_SIZE(partitions)); } diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index 08c239604ee4..92e1f41634c7 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -72,7 +72,7 @@ static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p) { /* register the flash bank */ /* partition the flash bank */ - return mtd_device_parse_register(p->info, NULL, 0, NULL, 0); + return mtd_device_parse_register(p->info, NULL, NULL, NULL, 0); } static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index fc7d4d0d9a4e..4a41ced0f710 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -226,7 +226,7 @@ static int ixp2000_flash_probe(struct platform_device *dev) } info->mtd->owner = THIS_MODULE; - err = mtd_device_parse_register(info->mtd, probes, 0, NULL, 0); + err = mtd_device_parse_register(info->mtd, probes, NULL, NULL, 0); if (err) goto Error; diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index cf7a3cddad35..b5401e355745 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -169,8 +169,9 @@ ltq_mtd_probe(struct platform_device *pdev) cfi->addr_unlock1 ^= 1; cfi->addr_unlock2 ^= 1; - err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, 0, - ltq_mtd_data->parts, ltq_mtd_data->nr_parts); + err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, NULL, + ltq_mtd_data->parts, + ltq_mtd_data->nr_parts); if (err) { dev_err(&pdev->dev, "failed to add partitions\n"); goto err_destroy; diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c index 8fed58e3a4a8..3c7ad17fca78 100644 --- a/drivers/mtd/maps/latch-addr-flash.c +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -199,8 +199,9 @@ static int __devinit latch_addr_flash_probe(struct platform_device *dev) } info->mtd->owner = THIS_MODULE; - mtd_device_parse_register(info->mtd, NULL, 0, - latch_addr_data->parts, latch_addr_data->nr_parts); + mtd_device_parse_register(info->mtd, NULL, NULL, + latch_addr_data->parts, + latch_addr_data->nr_parts); return 0; iounmap: diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 7e9233c503ab..21b0b713cacb 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -192,7 +192,7 @@ static int physmap_flash_probe(struct platform_device *dev) part_types = physmap_data->part_probe_types ? : part_probe_types; - mtd_device_parse_register(info->cmtd, part_types, 0, + mtd_device_parse_register(info->cmtd, part_types, NULL, physmap_data->parts, physmap_data->nr_parts); return 0; diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 45876d0e5b8e..891558de3ec1 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -222,8 +222,9 @@ static int platram_probe(struct platform_device *pdev) /* check to see if there are any available partitions, or wether * to add this device whole */ - err = mtd_device_parse_register(info->mtd, pdata->probes, 0, - pdata->partitions, pdata->nr_partitions); + err = mtd_device_parse_register(info->mtd, pdata->probes, NULL, + pdata->partitions, + pdata->nr_partitions); if (!err) dev_info(&pdev->dev, "registered mtd device\n"); diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 436d121185b1..81884c277405 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -98,7 +98,8 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) } info->mtd->owner = THIS_MODULE; - mtd_device_parse_register(info->mtd, probes, 0, flash->parts, flash->nr_parts); + mtd_device_parse_register(info->mtd, probes, NULL, flash->parts, + flash->nr_parts); platform_set_drvdata(pdev, info); return 0; diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c index 3da63fc6f16e..6f52e1f288b6 100644 --- a/drivers/mtd/maps/rbtx4939-flash.c +++ b/drivers/mtd/maps/rbtx4939-flash.c @@ -102,8 +102,8 @@ static int rbtx4939_flash_probe(struct platform_device *dev) info->mtd->owner = THIS_MODULE; if (err) goto err_out; - err = mtd_device_parse_register(info->mtd, NULL, 0, - pdata->parts, pdata->nr_parts); + err = mtd_device_parse_register(info->mtd, NULL, NULL, pdata->parts, + pdata->nr_parts); if (err) goto err_out; diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 1eaf7b6c35e5..a675bdbcb0fe 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -264,8 +264,8 @@ static int __devinit sa1100_mtd_probe(struct platform_device *pdev) /* * Partition selection stuff. */ - mtd_device_parse_register(info->mtd, part_probes, 0, - plat->parts, plat->nr_parts); + mtd_device_parse_register(info->mtd, part_probes, NULL, plat->parts, + plat->nr_parts); platform_set_drvdata(pdev, info); err = 0; diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index 496c40704aff..9d900ada6708 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -92,8 +92,8 @@ static int __init init_soleng_maps(void) mtd_device_register(eprom_mtd, NULL, 0); } - mtd_device_parse_register(flash_mtd, probes, 0, - superh_se_partitions, NUM_PARTITIONS); + mtd_device_parse_register(flash_mtd, probes, NULL, + superh_se_partitions, NUM_PARTITIONS); return 0; } diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index aa7e0cb2893c..71b0ba797912 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -142,7 +142,7 @@ static int __init init_sbc82xx_flash(void) nr_parts = ARRAY_SIZE(smallflash_parts); } - mtd_device_parse_register(sbcmtd[i], part_probes, 0, + mtd_device_parse_register(sbcmtd[i], part_probes, NULL, defparts, nr_parts); } return 0; diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 35b4fb55dbd6..7769519a54a7 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -650,8 +650,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev) } mtd->name = "atmel_nand"; - res = mtd_device_parse_register(mtd, NULL, 0, - host->board->parts, host->board->num_parts); + res = mtd_device_parse_register(mtd, NULL, NULL, host->board->parts, + host->board->num_parts); if (!res) return res; diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index 50387fd4009b..ee81b6333f6a 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -488,7 +488,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) /* Register the partitions */ board_mtd->name = "bcm_umi-nand"; - mtd_device_parse_register(board_mtd, NULL, 0, NULL, 0); + mtd_device_parse_register(board_mtd, NULL, NULL, NULL, 0); /* Return happy */ return 0; diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 72d3f23490c5..c23c07c5b391 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -799,7 +799,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, mtd); mtd->name = "cafe_nand"; - mtd_device_parse_register(mtd, part_probes, 0, NULL, 0); + mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0); goto out; diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 737ef9a04fdb..1024bfc05c86 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -219,7 +219,7 @@ static int __init cmx270_init(void) } /* Register the partitions */ - ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, 0, + ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL, partition_info, NUM_PARTITIONS); if (ret) goto err_scan; diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 414afa793563..e2b7c9e4c5c2 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -313,7 +313,7 @@ static int __init cs553x_init(void) for (i = 0; i < NR_CS553X_CONTROLLERS; i++) { if (cs553x_mtd[i]) { /* If any devices registered, return success. Else the last error. */ - mtd_device_parse_register(cs553x_mtd[i], NULL, 0, + mtd_device_parse_register(cs553x_mtd[i], NULL, NULL, NULL, 0); err = 0; } diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 6e566156956f..b81afc748fff 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -752,8 +752,8 @@ syndrome_done: if (ret < 0) goto err_scan; - ret = mtd_device_parse_register(&info->mtd, NULL, 0, - pdata->parts, pdata->nr_parts); + ret = mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts, + pdata->nr_parts); if (ret < 0) goto err_scan; diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 4a018d0b7034..341086c22e90 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -940,13 +940,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * Check for partition info passed */ host->mtd.name = "nand"; - ret = mtd_device_parse_register(&host->mtd, NULL, 0, - host->mtd.size <= 0x04000000 ? - partition_info_16KB_blk : - partition_info_128KB_blk, - host->mtd.size <= 0x04000000 ? - ARRAY_SIZE(partition_info_16KB_blk) : - ARRAY_SIZE(partition_info_128KB_blk)); + ret = mtd_device_parse_register(&host->mtd, NULL, NULL, + host->mtd.size <= 0x04000000 ? + partition_info_16KB_blk : + partition_info_128KB_blk, + host->mtd.size <= 0x04000000 ? + ARRAY_SIZE(partition_info_16KB_blk) : + ARRAY_SIZE(partition_info_128KB_blk)); if (ret) goto err_probe; diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 5dc6f0d92f1a..11e487813428 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -135,8 +135,8 @@ static int __init h1910_init(void) } /* Register the partitions */ - mtd_device_parse_register(h1910_nand_mtd, NULL, 0, - partition_info, NUM_PARTITIONS); + mtd_device_parse_register(h1910_nand_mtd, NULL, NULL, partition_info, + NUM_PARTITIONS); /* Return happy */ return 0; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index ac3b9f255e00..cc50e35cdc3d 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -367,9 +367,9 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) goto err_gpio_free; } - ret = mtd_device_parse_register(mtd, NULL, 0, - pdata ? pdata->partitions : NULL, - pdata ? pdata->num_partitions : 0); + ret = mtd_device_parse_register(mtd, NULL, NULL, + pdata ? pdata->partitions : NULL, + pdata ? pdata->num_partitions : 0); if (ret) { dev_err(&pdev->dev, "Failed to add mtd device\n"); diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 74a43b818d0e..3c4c0533191d 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1226,8 +1226,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) } /* Register the partitions */ - mtd_device_parse_register(mtd, part_probes, 0, - pdata->parts, pdata->nr_parts); + mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts, + pdata->nr_parts); platform_set_drvdata(pdev, host); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index b3a883e2a22f..d2e7a7da81f8 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1101,8 +1101,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) goto out_release_mem_region; } - mtd_device_parse_register(&info->mtd, NULL, 0, - pdata->parts, pdata->nr_parts); + mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts, + pdata->nr_parts); platform_set_drvdata(pdev, &info->mtd); diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 29f505adaf84..1d3bfb26080c 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -129,8 +129,8 @@ static int __init orion_nand_probe(struct platform_device *pdev) } mtd->name = "orion_nand"; - ret = mtd_device_parse_register(mtd, NULL, 0, - board->parts, board->nr_parts); + ret = mtd_device_parse_register(mtd, NULL, NULL, board->parts, + board->nr_parts); if (ret) { nand_release(mtd); goto no_dev; diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 7f2da6953357..6404e6e81b10 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -99,8 +99,9 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) } err = mtd_device_parse_register(&data->mtd, - pdata->chip.part_probe_types, 0, - pdata->chip.partitions, pdata->chip.nr_partitions); + pdata->chip.part_probe_types, NULL, + pdata->chip.partitions, + pdata->chip.nr_partitions); if (!err) return err; diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 7e52af51a198..0ddd90e5788f 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -275,11 +275,10 @@ static int __init ppchameleonevb_init(void) ppchameleon_mtd->name = "ppchameleon-nand"; /* Register the partitions */ - mtd_device_parse_register(ppchameleon_mtd, NULL, 0, - ppchameleon_mtd->size == NAND_SMALL_SIZE ? - partition_info_me : - partition_info_hi, - NUM_PARTITIONS); + mtd_device_parse_register(ppchameleon_mtd, NULL, NULL, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : partition_info_hi, + NUM_PARTITIONS); nand_evb_init: /**************************** @@ -365,11 +364,10 @@ static int __init ppchameleonevb_init(void) ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME; /* Register the partitions */ - mtd_device_parse_register(ppchameleonevb_mtd, NULL, 0, - ppchameleon_mtd->size == NAND_SMALL_SIZE ? - partition_info_me : - partition_info_hi, - NUM_PARTITIONS); + mtd_device_parse_register(ppchameleonevb_mtd, NULL, NULL, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : partition_info_hi, + NUM_PARTITIONS); /* Return happy */ return 0; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 5c3d719c37e6..d3bdc909c939 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1228,8 +1228,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) continue; } - ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0, - pdata->parts[cs], pdata->nr_parts[cs]); + ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, + NULL, pdata->parts[cs], + pdata->nr_parts[cs]); if (!ret) probe_success = 1; } diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 868685db6712..97623be04e0f 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -751,8 +751,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, if (set) mtd->mtd.name = set->name; - return mtd_device_parse_register(&mtd->mtd, NULL, 0, - set->partitions, set->nr_partitions); + return mtd_device_parse_register(&mtd->mtd, NULL, NULL, + set->partitions, set->nr_partitions); } /** diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index b175c0fd8b93..2d269a53f8bb 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -181,8 +181,8 @@ static int __devinit sharpsl_nand_probe(struct platform_device *pdev) /* Register the partitions */ sharpsl->mtd.name = "sharpsl-nand"; - err = mtd_device_parse_register(&sharpsl->mtd, NULL, 0, - data->partitions, data->nr_partitions); + err = mtd_device_parse_register(&sharpsl->mtd, NULL, NULL, + data->partitions, data->nr_partitions); if (err) goto err_add; diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 6caa0cd9d6a7..060848a91db7 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -456,9 +456,9 @@ static int tmio_probe(struct platform_device *dev) goto err_scan; } /* Register the partitions */ - retval = mtd_device_parse_register(mtd, NULL, 0, - data ? data->partition : NULL, - data ? data->num_partitions : 0); + retval = mtd_device_parse_register(mtd, NULL, NULL, + data ? data->partition : NULL, + data ? data->num_partitions : 0); if (!retval) return retval; diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index c7c4f1d11c77..8db0acbae6fa 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -386,7 +386,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) } mtd->name = txx9_priv->mtdname; - mtd_device_parse_register(mtd, NULL, 0, NULL, 0); + mtd_device_parse_register(mtd, NULL, NULL, NULL, 0); drvdata->mtds[i] = mtd; } diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 0ccd5bff2544..1c4f97c63e62 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -70,9 +70,9 @@ static int __devinit generic_onenand_probe(struct platform_device *pdev) goto out_iounmap; } - err = mtd_device_parse_register(&info->mtd, NULL, 0, - pdata ? pdata->parts : NULL, - pdata ? pdata->nr_parts : 0); + err = mtd_device_parse_register(&info->mtd, NULL, NULL, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); platform_set_drvdata(pdev, info); diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 7e9ea6852b67..398a82783848 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -751,9 +751,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) if ((r = onenand_scan(&c->mtd, 1)) < 0) goto err_release_regulator; - r = mtd_device_parse_register(&c->mtd, NULL, 0, - pdata ? pdata->parts : NULL, - pdata ? pdata->nr_parts : 0); + r = mtd_device_parse_register(&c->mtd, NULL, NULL, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); if (r) goto err_release_onenand; diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index deaf7628773f..8e4b3f2742ba 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -1014,7 +1014,7 @@ static int s3c_onenand_probe(struct platform_device *pdev) if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ) dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n"); - err = mtd_device_parse_register(mtd, NULL, 0, + err = mtd_device_parse_register(mtd, NULL, NULL, pdata ? pdata->parts : NULL, pdata ? pdata->nr_parts : 0); -- cgit v1.2.3 From 6a918bade9dab40aaef80559bd1169c69e8d69cb Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Sun, 11 Mar 2012 14:21:11 -0700 Subject: mtd: flash drivers set ecc strength Flash device drivers initialize 'ecc_strength' in struct mtd_info, which is the maximum number of bit errors that can be corrected in one writesize region. Drivers using the nand interface intitialize 'strength' in struct nand_ecc_ctrl, which is the maximum number of bit errors that can be corrected in one ecc step. Nand infrastructure code translates this to 'ecc_strength'. Also for nand drivers, the nand infrastructure code sets ecc.strength for ecc modes NAND_ECC_SOFT, NAND_ECC_SOFT_BCH, and NAND_ECC_NONE. It is set in the driver for all other modes. Signed-off-by: Mike Dunn Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/doc2000.c | 1 + drivers/mtd/devices/doc2001.c | 1 + drivers/mtd/devices/doc2001plus.c | 1 + drivers/mtd/devices/docg3.c | 1 + drivers/mtd/mtdpart.c | 1 + drivers/mtd/nand/alauda.c | 1 + drivers/mtd/nand/atmel_nand.c | 1 + drivers/mtd/nand/bcm_umi_nand.c | 8 ++++++++ drivers/mtd/nand/bf5xx_nand.c | 2 ++ drivers/mtd/nand/cafe_nand.c | 1 + drivers/mtd/nand/cs553x_nand.c | 2 ++ drivers/mtd/nand/davinci_nand.c | 1 + drivers/mtd/nand/denali.c | 3 +++ drivers/mtd/nand/diskonchip.c | 1 + drivers/mtd/nand/docg4.c | 1 + drivers/mtd/nand/fsl_elbc_nand.c | 6 ++++++ drivers/mtd/nand/fsmc_nand.c | 2 ++ drivers/mtd/nand/jz4740_nand.c | 5 +++++ drivers/mtd/nand/mxc_nand.c | 7 +++++++ drivers/mtd/nand/nand_base.c | 7 ++++++- drivers/mtd/nand/ndfc.c | 1 + drivers/mtd/nand/omap2.c | 1 + drivers/mtd/nand/pxa3xx_nand.c | 1 + drivers/mtd/nand/r852.c | 1 + drivers/mtd/nand/rtc_from4.c | 1 + drivers/mtd/nand/s3c2410.c | 1 + drivers/mtd/nand/sh_flctl.c | 1 + drivers/mtd/nand/sharpsl.c | 1 + drivers/mtd/nand/tmio_nand.c | 1 + drivers/mtd/nand/txx9ndfmc.c | 1 + drivers/mtd/onenand/onenand_base.c | 1 + 31 files changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 7ad7b054800c..a4eb8b5b85ec 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -564,6 +564,7 @@ void DoC2k_init(struct mtd_info *mtd) mtd->flags = MTD_CAP_NANDFLASH; mtd->writebufsize = mtd->writesize = 512; mtd->oobsize = 16; + mtd->ecc_strength = 2; mtd->owner = THIS_MODULE; mtd->_erase = doc_erase; mtd->_read = doc_read; diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 7bff54e62cd5..f6927955dab0 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -348,6 +348,7 @@ void DoCMil_init(struct mtd_info *mtd) mtd->erasesize = 0x2000; mtd->writebufsize = mtd->writesize = 512; mtd->oobsize = 16; + mtd->ecc_strength = 2; mtd->owner = THIS_MODULE; mtd->_erase = doc_erase; mtd->_read = doc_read; diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 4a03d869ad03..04eb2e4aa50f 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -469,6 +469,7 @@ void DoCMilPlus_init(struct mtd_info *mtd) mtd->flags = MTD_CAP_NANDFLASH; mtd->writebufsize = mtd->writesize = 512; mtd->oobsize = 16; + mtd->ecc_strength = 2; mtd->owner = THIS_MODULE; mtd->_erase = doc_erase; mtd->_read = doc_read; diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 2c1d0fca6757..349bbfa74d0d 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1832,6 +1832,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) mtd->_write_oob = doc_write_oob; mtd->_block_isbad = doc_block_isbad; mtd->ecclayout = &docg3_oobinfo; + mtd->ecc_strength = DOC_ECC_BCH_T; } /** diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 226d28a618d8..9651c06de0a9 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -516,6 +516,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, } slave->mtd.ecclayout = master->ecclayout; + slave->mtd.ecc_strength = master->ecc_strength; if (master->_block_isbad) { uint64_t offs = 0; diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c index ac38f73fde3b..4f20e1d8bef1 100644 --- a/drivers/mtd/nand/alauda.c +++ b/drivers/mtd/nand/alauda.c @@ -591,6 +591,7 @@ static int alauda_init_media(struct alauda *al) mtd->_block_isbad = alauda_isbad; mtd->priv = al; mtd->owner = THIS_MODULE; + mtd->ecc_strength = 1; err = mtd_device_register(mtd, NULL, 0); if (err) { diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 7769519a54a7..662abf08061a 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -554,6 +554,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->ecc.hwctl = atmel_nand_hwctl; nand_chip->ecc.read_page = atmel_nand_read_page; nand_chip->ecc.bytes = 4; + nand_chip->ecc.strength = 1; } nand_chip->chip_delay = 20; /* 20us command delay time */ diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index ee81b6333f6a..fc600431f519 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -476,6 +476,14 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) largepage_bbt.options = NAND_BBT_SCAN2NDPAGE; this->badblock_pattern = &largepage_bbt; } + + /* + * FIXME: ecc strength value of 6 bits per 512 bytes of data is a + * conservative guess, given 13 ecc bytes and using bch alg. + * (Assume Galois field order m=15 to allow a margin of error.) + */ + this->ecc.strength = 6; + #endif /* Now finish off the scan, now that ecc.layout has been initialized. */ diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index dd899cb5d366..d7b86b925de5 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -702,9 +702,11 @@ static int bf5xx_nand_scan(struct mtd_info *mtd) if (likely(mtd->writesize >= 512)) { chip->ecc.size = 512; chip->ecc.bytes = 6; + chip->ecc.strength = 2; } else { chip->ecc.size = 256; chip->ecc.bytes = 3; + chip->ecc.strength = 1; bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET)); SSYNC(); } diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index c23c07c5b391..2a96e1a12062 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -783,6 +783,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME; cafe->nand.ecc.size = mtd->writesize; cafe->nand.ecc.bytes = 14; + cafe->nand.ecc.strength = 4; cafe->nand.ecc.hwctl = (void *)cafe_nand_bug; cafe->nand.ecc.calculate = (void *)cafe_nand_bug; cafe->nand.ecc.correct = (void *)cafe_nand_bug; diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index e2b7c9e4c5c2..821c34c62500 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -248,6 +248,8 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) goto out_ior; } + this->ecc.strength = 1; + new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs); cs553x_mtd[cs] = new_mtd; diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index b81afc748fff..d94b03c207af 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -641,6 +641,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->chip.ecc.bytes = 3; } info->chip.ecc.size = 512; + info->chip.ecc.strength = pdata->ecc_bits; break; default: ret = -EINVAL; diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3984d488f9ab..a9e57d686297 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1590,6 +1590,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ECC_15BITS * (denali->mtd.writesize / ECC_SECTOR_SIZE)))) { /* if MLC OOB size is large enough, use 15bit ECC*/ + denali->nand.ecc.strength = 15; denali->nand.ecc.layout = &nand_15bit_oob; denali->nand.ecc.bytes = ECC_15BITS; iowrite32(15, denali->flash_reg + ECC_CORRECTION); @@ -1600,12 +1601,14 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) " contain 8bit ECC correction codes"); goto failed_req_irq; } else { + denali->nand.ecc.strength = 8; denali->nand.ecc.layout = &nand_8bit_oob; denali->nand.ecc.bytes = ECC_8BITS; iowrite32(8, denali->flash_reg + ECC_CORRECTION); } denali->nand.ecc.bytes *= denali->devnum; + denali->nand.ecc.strength *= denali->devnum; denali->nand.ecc.layout->eccbytes *= denali->mtd.writesize / ECC_SECTOR_SIZE; denali->nand.ecc.layout->oobfree[0].offset = diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index df921e7a496c..e2ca067631cf 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1653,6 +1653,7 @@ static int __init doc_probe(unsigned long physadr) nand->ecc.mode = NAND_ECC_HW_SYNDROME; nand->ecc.size = 512; nand->ecc.bytes = 6; + nand->ecc.strength = 2; nand->bbt_options = NAND_BBT_USE_FLASH; doc->physadr = physadr; diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 9b3a64904668..b08202664543 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -1191,6 +1191,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd) nand->ecc.size = DOCG4_PAGE_SIZE; nand->ecc.prepad = 8; nand->ecc.bytes = 8; + nand->ecc.strength = DOCG4_T; nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE | NAND_NO_AUTOINCR; nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA; diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 7195ee6efe12..80b5264f0a32 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -813,6 +813,12 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) &fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0; chip->ecc.size = 512; chip->ecc.bytes = 3; + chip->ecc.strength = 1; + /* + * FIXME: can hardware ecc correct 4 bitflips if page size is + * 2k? Then does hardware report number of corrections for this + * case? If so, ecc_stats reporting needs to be fixed as well. + */ } else { /* otherwise fall back to default software ECC */ chip->ecc.mode = NAND_ECC_SOFT; diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 341086c22e90..588e3733c3a4 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -863,10 +863,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->ecc.calculate = fsmc_read_hwecc_ecc4; nand->ecc.correct = fsmc_bch8_correct_data; nand->ecc.bytes = 13; + nand->ecc.strength = 8; } else { nand->ecc.calculate = fsmc_read_hwecc_ecc1; nand->ecc.correct = nand_correct_data; nand->ecc.bytes = 3; + nand->ecc.strength = 1; } /* diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index cc50e35cdc3d..e4147e8acb7c 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -332,6 +332,11 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; chip->ecc.size = 512; chip->ecc.bytes = 9; + chip->ecc.strength = 2; + /* + * FIXME: ecc_strength value of 2 bits per 512 bytes of data is a + * conservative guess, given 9 ecc bytes and reed-solomon alg. + */ if (pdata) chip->ecc.layout = pdata->ecc_layout; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 3c4c0533191d..cc0678a967c1 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1225,6 +1225,13 @@ static int __init mxcnd_probe(struct platform_device *pdev) goto escan; } + if (this->ecc.mode == NAND_ECC_HW) { + if (nfc_is_v1()) + this->ecc.strength = 1; + else + this->ecc.strength = (host->eccsize == 4) ? 4 : 8; + } + /* Register the partitions */ mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts, pdata->nr_parts); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1e907dc8638a..8008853756c9 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3350,6 +3350,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (!chip->ecc.size) chip->ecc.size = 256; chip->ecc.bytes = 3; + chip->ecc.strength = 1; break; case NAND_ECC_SOFT_BCH: @@ -3384,6 +3385,8 @@ int nand_scan_tail(struct mtd_info *mtd) pr_warn("BCH ECC initialization failed!\n"); BUG(); } + chip->ecc.strength = + chip->ecc.bytes*8 / fls(8*chip->ecc.size); break; case NAND_ECC_NONE: @@ -3397,6 +3400,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.write_oob = nand_write_oob_std; chip->ecc.size = mtd->writesize; chip->ecc.bytes = 0; + chip->ecc.strength = 0; break; default: @@ -3478,8 +3482,9 @@ int nand_scan_tail(struct mtd_info *mtd) mtd->_block_markbad = nand_block_markbad; mtd->writebufsize = mtd->writesize; - /* propagate ecc.layout to mtd_info */ + /* propagate ecc info to mtd_info */ mtd->ecclayout = chip->ecc.layout; + mtd->ecc_strength = chip->ecc.strength * chip->ecc.steps; /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index ec688548c880..2b6f632cf274 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -179,6 +179,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = 256; chip->ecc.bytes = 3; + chip->ecc.strength = 1; chip->priv = ndfc; ndfc->mtd.priv = chip; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index d2e7a7da81f8..c2b0bba9d8b3 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1058,6 +1058,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) { info->nand.ecc.bytes = 3; info->nand.ecc.size = 512; + info->nand.ecc.strength = 1; info->nand.ecc.calculate = omap_calculate_ecc; info->nand.ecc.hwctl = omap_enable_hwecc; info->nand.ecc.correct = omap_correct_data; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index d3bdc909c939..def50caa6f84 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1002,6 +1002,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) KEEP_CONFIG: chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = host->page_size; + chip->ecc.strength = 1; chip->options = NAND_NO_AUTOINCR; chip->options |= NAND_NO_READRDY; diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 769a4e096b3c..c2040187c813 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -891,6 +891,7 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) chip->ecc.mode = NAND_ECC_HW_SYNDROME; chip->ecc.size = R852_DMA_LEN; chip->ecc.bytes = SM_OOB_SIZE; + chip->ecc.strength = 2; chip->ecc.hwctl = r852_ecc_hwctl; chip->ecc.calculate = r852_ecc_calculate; chip->ecc.correct = r852_ecc_correct; diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index f309addc2fa0..e55b5cfbe145 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -527,6 +527,7 @@ static int __init rtc_from4_init(void) this->ecc.mode = NAND_ECC_HW_SYNDROME; this->ecc.size = 512; this->ecc.bytes = 8; + this->ecc.strength = 3; /* return the status of extra status and ECC checks */ this->errstat = rtc_from4_errstat; /* set the nand_oobinfo to support FPGA H/W error detection */ diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 97623be04e0f..91121f33f743 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -823,6 +823,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->ecc.calculate = s3c2410_nand_calculate_ecc; chip->ecc.correct = s3c2410_nand_correct_data; chip->ecc.mode = NAND_ECC_HW; + chip->ecc.strength = 1; switch (info->cpu_type) { case TYPE_S3C2410: diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 2ee9a1b50a22..e9b2b260de3a 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -825,6 +825,7 @@ static int flctl_chip_init_tail(struct mtd_info *mtd) chip->ecc.size = 512; chip->ecc.bytes = 10; + chip->ecc.strength = 4; chip->ecc.read_page = flctl_read_page_hwecc; chip->ecc.write_page = flctl_write_page_hwecc; chip->ecc.mode = NAND_ECC_HW; diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 2d269a53f8bb..3421e3762a5a 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -167,6 +167,7 @@ static int __devinit sharpsl_nand_probe(struct platform_device *pdev) this->ecc.mode = NAND_ECC_HW; this->ecc.size = 256; this->ecc.bytes = 3; + this->ecc.strength = 1; this->badblock_pattern = data->badblock_pattern; this->ecc.layout = data->ecc_layout; this->ecc.hwctl = sharpsl_nand_enable_hwecc; diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 060848a91db7..5aa518081c51 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -430,6 +430,7 @@ static int tmio_probe(struct platform_device *dev) nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; nand_chip->ecc.bytes = 6; + nand_chip->ecc.strength = 2; nand_chip->ecc.hwctl = tmio_nand_enable_hwecc; nand_chip->ecc.calculate = tmio_nand_calculate_ecc; nand_chip->ecc.correct = tmio_nand_correct_data; diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 8db0acbae6fa..26398dcf21cf 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -356,6 +356,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) /* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */ chip->ecc.size = 256; chip->ecc.bytes = 3; + chip->ecc.strength = 1; chip->chip_delay = 100; chip->controller = &drvdata->hw_control; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index a1592cf755f3..3d781b87b358 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -4080,6 +4080,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->oobavail = this->ecclayout->oobavail; mtd->ecclayout = this->ecclayout; + mtd->ecc_strength = 1; /* Fill in remaining MTD driver data */ mtd->type = ONENAND_IS_MLC(this) ? MTD_MLCNANDFLASH : MTD_NANDFLASH; -- cgit v1.2.3 From 7147032485293fc24751e4dede98ff29050fd3bd Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:07 +0530 Subject: mtd: nand/fsmc: Pass partition information through platform data This patch reimplements the passing of partition information through platform data. This was unintentionally deleted in commit 0d04eda1430e9a796214bee644b7e05d99cfe613 "mtd: fsmc_nand.c: use mtd_device_parse_register" Artem: fix gcc warning about passin 0 instead of NULL. Signed-off-by: Vipin Kumar Acked-by: Stefan Roese Signed-off-by: Linus Walleij Cc: stable@kernel.org [3.2+] Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 588e3733c3a4..7338d33fe1ed 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -333,6 +333,8 @@ static struct mtd_partition partition_info_128KB_blk[] = { * @pid: Part ID on the AMBA PrimeCell format * @mtd: MTD info for a NAND flash. * @nand: Chip related info for a NAND flash. + * @partitions: Partition info for a NAND Flash. + * @nr_partitions: Total number of partition of a NAND flash. * * @ecc_place: ECC placing locations in oobfree type format. * @bank: Bank number for probed device. @@ -347,6 +349,8 @@ struct fsmc_nand_data { u32 pid; struct mtd_info mtd; struct nand_chip nand; + struct mtd_partition *partitions; + unsigned int nr_partitions; struct fsmc_eccplace *ecc_place; unsigned int bank; @@ -833,6 +837,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->bank = pdata->bank; host->select_chip = pdata->select_bank; + host->partitions = pdata->partitions; + host->nr_partitions = pdata->nr_partitions; regs = host->regs_va; /* Link all private pointers */ @@ -943,12 +949,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) */ host->mtd.name = "nand"; ret = mtd_device_parse_register(&host->mtd, NULL, NULL, - host->mtd.size <= 0x04000000 ? - partition_info_16KB_blk : - partition_info_128KB_blk, - host->mtd.size <= 0x04000000 ? - ARRAY_SIZE(partition_info_16KB_blk) : - ARRAY_SIZE(partition_info_128KB_blk)); + host->partitions, host->nr_partitions); if (ret) goto err_probe; -- cgit v1.2.3 From 04f168524e4b13205404fb46337312c8023d934e Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 14 Mar 2012 11:47:08 +0530 Subject: mtd: nand/fsmc: Remove default partition information from driver Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 58 -------------------------------------------- 1 file changed, 58 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 7338d33fe1ed..21d8393d85c4 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -269,64 +269,6 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = { } }; -/* - * Default partition tables to be used if the partition information not - * provided through platform data. - * - * Default partition layout for small page(= 512 bytes) devices - * Size for "Root file system" is updated in driver based on actual device size - */ -static struct mtd_partition partition_info_16KB_blk[] = { - { - .name = "X-loader", - .offset = 0, - .size = 4*0x4000, - }, - { - .name = "U-Boot", - .offset = 0x10000, - .size = 20*0x4000, - }, - { - .name = "Kernel", - .offset = 0x60000, - .size = 256*0x4000, - }, - { - .name = "Root File System", - .offset = 0x460000, - .size = MTDPART_SIZ_FULL, - }, -}; - -/* - * Default partition layout for large page(> 512 bytes) devices - * Size for "Root file system" is updated in driver based on actual device size - */ -static struct mtd_partition partition_info_128KB_blk[] = { - { - .name = "X-loader", - .offset = 0, - .size = 4*0x20000, - }, - { - .name = "U-Boot", - .offset = 0x80000, - .size = 12*0x20000, - }, - { - .name = "Kernel", - .offset = 0x200000, - .size = 48*0x20000, - }, - { - .name = "Root File System", - .offset = 0x800000, - .size = MTDPART_SIZ_FULL, - }, -}; - - /** * struct fsmc_nand_data - structure for FSMC NAND device state * -- cgit v1.2.3 From 4cbe1bf07a4dfc3ec2d81c4e8aee832384997bc4 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:09 +0530 Subject: mtd: nand/fsmc: Correct the multiline comment format Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 21d8393d85c4..902ba0d9c32d 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -545,10 +545,10 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, group++; /* - * length is intentionally kept a higher multiple of 2 - * to read at least 13 bytes even in case of 16 bit NAND - * devices - */ + * length is intentionally kept a higher multiple of 2 + * to read at least 13 bytes even in case of 16 bit NAND + * devices + */ len = roundup(len, 2); chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); chip->read_buf(mtd, oob + j, len); -- cgit v1.2.3 From aea686b47c0cf97e0c6941799b523b6df87fc234 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:10 +0530 Subject: mtd: nand/fsmc: Read only 512 + 13 bytes for 8bit NAND devices The ECC logic of FSMC works on 512 bytes data + 13 bytes ECC to generate error indices of up to 8 incorrect bits. The FSMC driver reads 14 instead of 13 oob bytes to accommodate for 16 bit device as well. Unfortunately, the internal ecc state machine gets corrupted for 8 bit devices reading 512 + 14 bytes of data resulting in error indices not getting reported. Fix this by reading 14 bytes only for 16 bit devices Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 902ba0d9c32d..bd423390d330 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -549,7 +549,9 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * to read at least 13 bytes even in case of 16 bit NAND * devices */ - len = roundup(len, 2); + if (chip->options & NAND_BUSWIDTH_16) + len = roundup(len, 2); + chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); chip->read_buf(mtd, oob + j, len); j += len; -- cgit v1.2.3 From b533f8d84f4f0807bf1bcf52017c6a267c8c4405 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:11 +0530 Subject: mtd: nand/fsmc: Flip the bit only if the error index is < 4096 ECC can correct up to 8 bits in 512 bytes data + 13 bytes ecc. This means that the algorithm can correct a max of 8 bits in 4200 bits ie the error indices can be from 0 to 4199. Of these 0 to 4095 are for data and 4096 to 4199 for ecc. The driver flips the bit only if the index is <= 4096. This is a bug since the data bits are only from 0 to 4095. This patch modifies the check as < 4096 Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index bd423390d330..6a0bca17c223 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -654,7 +654,7 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, change_bit(0, (unsigned long *)&err_idx[i]); change_bit(1, (unsigned long *)&err_idx[i]); - if (err_idx[i] <= chip->ecc.size * 8) { + if (err_idx[i] < chip->ecc.size * 8) { change_bit(err_idx[i], (unsigned long *)dat); i++; } -- cgit v1.2.3 From 467e6e7be2e26fd5bbaabd849717d37de99df8f1 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:12 +0530 Subject: mtd: nand/fsmc: Initialize the badblockbits to 7 Ideally, the block should have 0xff written on the bad block position. Any value other than 0xff implies a bad block. In practical situations, there can be bit flips in the oob area as well which means that a block with 0x7f being read at bad block position may imply a bad block but it is infact only a bit flip in the bad block byte. To resolve this problem, the block is marked as good if number of high bits is greater than or equal to badblockbits (initialized to 7) Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 6a0bca17c223..91f5b3404c79 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -802,6 +802,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->ecc.size = 512; nand->options = pdata->options; nand->select_chip = fsmc_select_chip; + nand->badblockbits = 7; if (pdata->width == FSMC_NAND_BW16) nand->options |= NAND_BUSWIDTH_16; -- cgit v1.2.3 From f63acb75c5d8a9eb7cc5548e3e778d2a00bf3bae Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Wed, 14 Mar 2012 11:47:13 +0530 Subject: mtd: fsmc_nand: add pm callbacks to support hibernation Signed-off-by: Shiraz Hashim Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 91f5b3404c79..a5099607d203 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -382,7 +382,7 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) * This routine initializes timing parameters related to NAND memory access in * FSMC registers */ -static void __init fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, +static void fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, uint32_t busw) { uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; @@ -976,15 +976,15 @@ static int fsmc_nand_suspend(struct device *dev) static int fsmc_nand_resume(struct device *dev) { struct fsmc_nand_data *host = dev_get_drvdata(dev); - if (host) + if (host) { clk_enable(host->clk); + fsmc_nand_setup(host->regs_va, host->bank, + host->nand.options & NAND_BUSWIDTH_16); + } return 0; } -static const struct dev_pm_ops fsmc_nand_pm_ops = { - .suspend = fsmc_nand_suspend, - .resume = fsmc_nand_resume, -}; +static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume); #endif static struct platform_driver fsmc_nand_driver = { -- cgit v1.2.3 From e2f6bce8d94d2c82d4f7ae9d94743963a3b10136 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:14 +0530 Subject: mtd: nand/fsmc: Modify fsmc driver to accept nand timing parameters via platform FSMC controllers provide registers to program the required timing values for attached NAND device. The timing values used until now are relaxed and should work for all devices. Although, for read/write performance improvements, the fsmc nand driver should accept nand timings as a platform data and program the timing parameters into fsmc registers accordingly. This patch implements this modification. Additionally, it programs the default timing parameters if these are not passed via platform data. Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 41 +++++++++++++++++++++++++++++++++-------- include/linux/mtd/fsmc.h | 34 ++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 14 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index a5099607d203..e7ae63ab59c6 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -303,6 +303,8 @@ struct fsmc_nand_data { struct resource *resaddr; struct resource *resdata; + struct fsmc_nand_timings *dev_timings; + void __iomem *data_va; void __iomem *cmd_va; void __iomem *addr_va; @@ -383,21 +385,41 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) * FSMC registers */ static void fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, - uint32_t busw) + uint32_t busw, struct fsmc_nand_timings *timings) { uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; + uint32_t tclr, tar, thiz, thold, twait, tset; + struct fsmc_nand_timings *tims; + struct fsmc_nand_timings default_timings = { + .tclr = FSMC_TCLR_1, + .tar = FSMC_TAR_1, + .thiz = FSMC_THIZ_1, + .thold = FSMC_THOLD_4, + .twait = FSMC_TWAIT_6, + .tset = FSMC_TSET_0, + }; + + if (timings) + tims = timings; + else + tims = &default_timings; + + tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT; + tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT; + thiz = (tims->thiz & FSMC_THIZ_MASK) << FSMC_THIZ_SHIFT; + thold = (tims->thold & FSMC_THOLD_MASK) << FSMC_THOLD_SHIFT; + twait = (tims->twait & FSMC_TWAIT_MASK) << FSMC_TWAIT_SHIFT; + tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT; if (busw) writel(value | FSMC_DEVWID_16, ®s->bank_regs[bank].pc); else writel(value | FSMC_DEVWID_8, ®s->bank_regs[bank].pc); - writel(readl(®s->bank_regs[bank].pc) | FSMC_TCLR_1 | FSMC_TAR_1, + writel(readl(®s->bank_regs[bank].pc) | tclr | tar, ®s->bank_regs[bank].pc); - writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, - ®s->bank_regs[bank].comm); - writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, - ®s->bank_regs[bank].attrib); + writel(thiz | thold | twait | tset, ®s->bank_regs[bank].comm); + writel(thiz | thold | twait | tset, ®s->bank_regs[bank].attrib); } /* @@ -783,6 +805,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->select_chip = pdata->select_bank; host->partitions = pdata->partitions; host->nr_partitions = pdata->nr_partitions; + host->dev_timings = pdata->nand_timings; regs = host->regs_va; /* Link all private pointers */ @@ -807,7 +830,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (pdata->width == FSMC_NAND_BW16) nand->options |= NAND_BUSWIDTH_16; - fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); + fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16, + host->dev_timings); if (AMBA_REV_BITS(host->pid) >= 8) { nand->ecc.read_page = fsmc_read_page_hwecc; @@ -979,7 +1003,8 @@ static int fsmc_nand_resume(struct device *dev) if (host) { clk_enable(host->clk); fsmc_nand_setup(host->regs_va, host->bank, - host->nand.options & NAND_BUSWIDTH_16); + host->nand.options & NAND_BUSWIDTH_16, + host->dev_timings); } return 0; } diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h index e877325d9c51..c4ac07a19691 100644 --- a/include/linux/mtd/fsmc.h +++ b/include/linux/mtd/fsmc.h @@ -90,17 +90,29 @@ struct fsmc_regs { #define FSMC_ECCEN (1 << 6) #define FSMC_ECCPLEN_512 (0 << 7) #define FSMC_ECCPLEN_256 (1 << 7) -#define FSMC_TCLR_1 (1 << 9) -#define FSMC_TAR_1 (1 << 13) +#define FSMC_TCLR_1 (1) +#define FSMC_TCLR_SHIFT (9) +#define FSMC_TCLR_MASK (0xF) +#define FSMC_TAR_1 (1) +#define FSMC_TAR_SHIFT (13) +#define FSMC_TAR_MASK (0xF) /* sts register definitions */ #define FSMC_CODE_RDY (1 << 15) /* comm register definitions */ -#define FSMC_TSET_0 (0 << 0) -#define FSMC_TWAIT_6 (6 << 8) -#define FSMC_THOLD_4 (4 << 16) -#define FSMC_THIZ_1 (1 << 24) +#define FSMC_TSET_0 0 +#define FSMC_TSET_SHIFT 0 +#define FSMC_TSET_MASK 0xFF +#define FSMC_TWAIT_6 6 +#define FSMC_TWAIT_SHIFT 8 +#define FSMC_TWAIT_MASK 0xFF +#define FSMC_THOLD_4 4 +#define FSMC_THOLD_SHIFT 16 +#define FSMC_THOLD_MASK 0xFF +#define FSMC_THIZ_1 1 +#define FSMC_THIZ_SHIFT 24 +#define FSMC_THIZ_MASK 0xFF /* * There are 13 bytes of ecc for every 512 byte block in FSMC version 8 @@ -120,6 +132,15 @@ struct fsmc_eccplace { struct fsmc_nand_eccplace eccplace[MAX_ECCPLACE_ENTRIES]; }; +struct fsmc_nand_timings { + uint8_t tclr; + uint8_t tar; + uint8_t thiz; + uint8_t thold; + uint8_t twait; + uint8_t tset; +}; + /** * fsmc_nand_platform_data - platform specific NAND controller config * @partitions: partition table for the platform, use a default fallback @@ -133,6 +154,7 @@ struct fsmc_eccplace { * this may be set to NULL */ struct fsmc_nand_platform_data { + struct fsmc_nand_timings *nand_timings; struct mtd_partition *partitions; unsigned int nr_partitions; unsigned int options; -- cgit v1.2.3 From 82b9dbe2e0f6870bf385b759b91e403b62a60c5e Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:15 +0530 Subject: mtd: nand/fsmc: Use devm routines fsmc_nand driver currently uses normal kzalloc, request_mem etc routines. This patch replaces these routines with devm_kzalloc and devm_request_mem_region etc. Consequently, the error and driver removal scenarios are curtailed. Signed-off-by: Vipin Kumar Reviewed-by: Viresh Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 134 ++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 91 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index e7ae63ab59c6..56b661972122 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -298,11 +298,6 @@ struct fsmc_nand_data { unsigned int bank; struct clk *clk; - struct resource *resregs; - struct resource *rescmd; - struct resource *resaddr; - struct resource *resdata; - struct fsmc_nand_timings *dev_timings; void __iomem *data_va; @@ -706,88 +701,81 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) } /* Allocate memory for the device structure (and zero it) */ - host = kzalloc(sizeof(*host), GFP_KERNEL); + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); if (!host) { dev_err(&pdev->dev, "failed to allocate device structure\n"); return -ENOMEM; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); - if (!res) { - ret = -EIO; - goto err_probe1; - } + if (!res) + return -EINVAL; - host->resdata = request_mem_region(res->start, resource_size(res), - pdev->name); - if (!host->resdata) { - ret = -EIO; - goto err_probe1; + if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), + pdev->name)) { + dev_err(&pdev->dev, "Failed to get memory data resourse\n"); + return -ENOENT; } - host->data_va = ioremap(res->start, resource_size(res)); + host->data_va = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); if (!host->data_va) { - ret = -EIO; - goto err_probe1; + dev_err(&pdev->dev, "data ioremap failed\n"); + return -ENOMEM; } - host->resaddr = request_mem_region(res->start + pdata->ale_off, - resource_size(res), pdev->name); - if (!host->resaddr) { - ret = -EIO; - goto err_probe1; + if (!devm_request_mem_region(&pdev->dev, res->start + pdata->ale_off, + resource_size(res), pdev->name)) { + dev_err(&pdev->dev, "Failed to get memory ale resourse\n"); + return -ENOENT; } - host->addr_va = ioremap(res->start + pdata->ale_off, + host->addr_va = devm_ioremap(&pdev->dev, res->start + pdata->ale_off, resource_size(res)); if (!host->addr_va) { - ret = -EIO; - goto err_probe1; + dev_err(&pdev->dev, "ale ioremap failed\n"); + return -ENOMEM; } - host->rescmd = request_mem_region(res->start + pdata->cle_off, - resource_size(res), pdev->name); - if (!host->rescmd) { - ret = -EIO; - goto err_probe1; + if (!devm_request_mem_region(&pdev->dev, res->start + pdata->cle_off, + resource_size(res), pdev->name)) { + dev_err(&pdev->dev, "Failed to get memory cle resourse\n"); + return -ENOENT; } - host->cmd_va = ioremap(res->start + pdata->cle_off, resource_size(res)); + host->cmd_va = devm_ioremap(&pdev->dev, res->start + pdata->cle_off, + resource_size(res)); if (!host->cmd_va) { - ret = -EIO; - goto err_probe1; + dev_err(&pdev->dev, "ale ioremap failed\n"); + return -ENOMEM; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs"); - if (!res) { - ret = -EIO; - goto err_probe1; - } + if (!res) + return -EINVAL; - host->resregs = request_mem_region(res->start, resource_size(res), - pdev->name); - if (!host->resregs) { - ret = -EIO; - goto err_probe1; + if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), + pdev->name)) { + dev_err(&pdev->dev, "Failed to get memory regs resourse\n"); + return -ENOENT; } - host->regs_va = ioremap(res->start, resource_size(res)); + host->regs_va = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); if (!host->regs_va) { - ret = -EIO; - goto err_probe1; + dev_err(&pdev->dev, "regs ioremap failed\n"); + return -ENOMEM; } host->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) { dev_err(&pdev->dev, "failed to fetch block clock\n"); - ret = PTR_ERR(host->clk); - host->clk = NULL; - goto err_probe1; + return PTR_ERR(host->clk); } ret = clk_enable(host->clk); if (ret) - goto err_probe1; + goto err_clk_enable; /* * This device ID is actually a common AMBA ID as used on the @@ -852,7 +840,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (nand_scan_ident(&host->mtd, 1, NULL)) { ret = -ENXIO; dev_err(&pdev->dev, "No NAND Device found!\n"); - goto err_probe; + goto err_scan_ident; } if (AMBA_REV_BITS(host->pid) >= 8) { @@ -927,32 +915,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) return 0; err_probe: +err_scan_ident: clk_disable(host->clk); -err_probe1: - if (host->clk) - clk_put(host->clk); - if (host->regs_va) - iounmap(host->regs_va); - if (host->resregs) - release_mem_region(host->resregs->start, - resource_size(host->resregs)); - if (host->cmd_va) - iounmap(host->cmd_va); - if (host->rescmd) - release_mem_region(host->rescmd->start, - resource_size(host->rescmd)); - if (host->addr_va) - iounmap(host->addr_va); - if (host->resaddr) - release_mem_region(host->resaddr->start, - resource_size(host->resaddr)); - if (host->data_va) - iounmap(host->data_va); - if (host->resdata) - release_mem_region(host->resdata->start, - resource_size(host->resdata)); - - kfree(host); +err_clk_enable: + clk_put(host->clk); return ret; } @@ -969,22 +935,8 @@ static int fsmc_nand_remove(struct platform_device *pdev) nand_release(&host->mtd); clk_disable(host->clk); clk_put(host->clk); - - iounmap(host->regs_va); - release_mem_region(host->resregs->start, - resource_size(host->resregs)); - iounmap(host->cmd_va); - release_mem_region(host->rescmd->start, - resource_size(host->rescmd)); - iounmap(host->addr_va); - release_mem_region(host->resaddr->start, - resource_size(host->resaddr)); - iounmap(host->data_va); - release_mem_region(host->resdata->start, - resource_size(host->resdata)); - - kfree(host); } + return 0; } -- cgit v1.2.3 From 712c4add03277197168210bb628b8273e36adf76 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:16 +0530 Subject: mtd: nand/fsmc: Use dev_err to report error scenario fsmc controller takes time to calculate the bch8 codes and the error offsets. The calculate logic checks for completion upto a timeout. This patch adds a error print when this timer expires and the ecc or error offsets are not yet calculated. Signed-off-by: Vipin Kumar Reviewed-by: Viresh Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 56b661972122..c41f45faa09e 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -296,6 +296,7 @@ struct fsmc_nand_data { struct fsmc_eccplace *ecc_place; unsigned int bank; + struct device *dev; struct clk *clk; struct fsmc_nand_timings *dev_timings; @@ -457,6 +458,11 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, cond_resched(); } while (!time_after_eq(jiffies, deadline)); + if (time_after_eq(jiffies, deadline)) { + dev_err(host->dev, "calculate ecc timed out\n"); + return -ETIMEDOUT; + } + ecc_tmp = readl(®s->bank_regs[bank].ecc1); ecc[0] = (uint8_t) (ecc_tmp >> 0); ecc[1] = (uint8_t) (ecc_tmp >> 8); @@ -793,6 +799,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->select_chip = pdata->select_bank; host->partitions = pdata->partitions; host->nr_partitions = pdata->nr_partitions; + host->dev = &pdev->dev; host->dev_timings = pdata->nand_timings; regs = host->regs_va; -- cgit v1.2.3 From 604e75444fa82cfdcba339e3bd4da1dfd6947539 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:17 +0530 Subject: mtd: nand/fsmc: Access the NAND device word by word whenever possible The default way of accessing nand device is using the nand width. This means that 8bit devices are using u8 * and 16bit devices are accessed using u16 *. This results in a non-optimal performance since the FSMC is designed to translate the normal word accesses into device width based accesses. This patch implements read_buf and write_buf callbacks using word by word accesses. Signed-off-by: Vipin Kumar Reviewed-by: Viresh Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/fsmc.h | 6 +++++ 2 files changed, 61 insertions(+) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index c41f45faa09e..81fc8e6b8cb8 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -523,6 +523,52 @@ static int count_written_bits(uint8_t *buff, int size, int max_bits) return written_bits; } +/* + * fsmc_write_buf - write buffer to chip + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + */ +static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + + if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) && + IS_ALIGNED(len, sizeof(uint32_t))) { + uint32_t *p = (uint32_t *)buf; + len = len >> 2; + for (i = 0; i < len; i++) + writel(p[i], chip->IO_ADDR_W); + } else { + for (i = 0; i < len; i++) + writeb(buf[i], chip->IO_ADDR_W); + } +} + +/* + * fsmc_read_buf - read chip data into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + */ +static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + + if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) && + IS_ALIGNED(len, sizeof(uint32_t))) { + uint32_t *p = (uint32_t *)buf; + len = len >> 2; + for (i = 0; i < len; i++) + p[i] = readl(chip->IO_ADDR_R); + } else { + for (i = 0; i < len; i++) + buf[i] = readb(chip->IO_ADDR_R); + } +} + /* * fsmc_read_page_hwecc * @mtd: mtd info structure @@ -825,6 +871,15 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (pdata->width == FSMC_NAND_BW16) nand->options |= NAND_BUSWIDTH_16; + /* + * use customized (word by word) version of read_buf, write_buf if + * access_with_dev_width is reset supported + */ + if (pdata->mode == USE_WORD_ACCESS) { + nand->read_buf = fsmc_read_buf; + nand->write_buf = fsmc_write_buf; + } + fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16, host->dev_timings); diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h index c4ac07a19691..1edd2b3ac38e 100644 --- a/include/linux/mtd/fsmc.h +++ b/include/linux/mtd/fsmc.h @@ -141,6 +141,11 @@ struct fsmc_nand_timings { uint8_t tset; }; +enum access_mode { + USE_DMA_ACCESS = 1, + USE_WORD_ACCESS, +}; + /** * fsmc_nand_platform_data - platform specific NAND controller config * @partitions: partition table for the platform, use a default fallback @@ -164,6 +169,7 @@ struct fsmc_nand_platform_data { /* CLE, ALE offsets */ unsigned long cle_off; unsigned long ale_off; + enum access_mode mode; void (*select_bank)(uint32_t bank, uint32_t busw); }; -- cgit v1.2.3 From 4774fb0a48aacfec206e6d54ecf58706f6a5320a Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:18 +0530 Subject: mtd: nand/fsmc: Add DMA support The fsmc_nand driver uses cpu to read/write onto the device. This is inefficient because of two reasons - the cpu gets locked on AHB bus while reading from NAND - the cpu is unnecessarily used when dma can do the job This patch adds the support for accessing the device through DMA Signed-off-by: Vipin Kumar Reviewed-by: Viresh Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 168 +++++++++++++++++++++++++++++++++++++++++-- include/linux/mtd/fsmc.h | 4 ++ 2 files changed, 167 insertions(+), 5 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 81fc8e6b8cb8..d20a0c63251e 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -17,6 +17,10 @@ */ #include +#include +#include +#include +#include #include #include #include @@ -282,6 +286,11 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = { * @bank: Bank number for probed device. * @clk: Clock structure for FSMC. * + * @read_dma_chan: DMA channel for read access + * @write_dma_chan: DMA channel for write access to NAND + * @dma_access_complete: Completion structure + * + * @data_pa: NAND Physical port for Data. * @data_va: NAND port for Data. * @cmd_va: NAND port for Command. * @addr_va: NAND port for Address. @@ -297,10 +306,17 @@ struct fsmc_nand_data { struct fsmc_eccplace *ecc_place; unsigned int bank; struct device *dev; + enum access_mode mode; struct clk *clk; + /* DMA related objects */ + struct dma_chan *read_dma_chan; + struct dma_chan *write_dma_chan; + struct completion dma_access_complete; + struct fsmc_nand_timings *dev_timings; + dma_addr_t data_pa; void __iomem *data_va; void __iomem *cmd_va; void __iomem *addr_va; @@ -523,6 +539,77 @@ static int count_written_bits(uint8_t *buff, int size, int max_bits) return written_bits; } +static void dma_complete(void *param) +{ + struct fsmc_nand_data *host = param; + + complete(&host->dma_access_complete); +} + +static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len, + enum dma_data_direction direction) +{ + struct dma_chan *chan; + struct dma_device *dma_dev; + struct dma_async_tx_descriptor *tx; + dma_addr_t dma_dst, dma_src, dma_addr; + dma_cookie_t cookie; + unsigned long flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + int ret; + + if (direction == DMA_TO_DEVICE) + chan = host->write_dma_chan; + else if (direction == DMA_FROM_DEVICE) + chan = host->read_dma_chan; + else + return -EINVAL; + + dma_dev = chan->device; + dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction); + + if (direction == DMA_TO_DEVICE) { + dma_src = dma_addr; + dma_dst = host->data_pa; + flags |= DMA_COMPL_SRC_UNMAP_SINGLE | DMA_COMPL_SKIP_DEST_UNMAP; + } else { + dma_src = host->data_pa; + dma_dst = dma_addr; + flags |= DMA_COMPL_DEST_UNMAP_SINGLE | DMA_COMPL_SKIP_SRC_UNMAP; + } + + tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, + len, flags); + + if (!tx) { + dev_err(host->dev, "device_prep_dma_memcpy error\n"); + dma_unmap_single(dma_dev->dev, dma_addr, len, direction); + return -EIO; + } + + tx->callback = dma_complete; + tx->callback_param = host; + cookie = tx->tx_submit(tx); + + ret = dma_submit_error(cookie); + if (ret) { + dev_err(host->dev, "dma_submit_error %d\n", cookie); + return ret; + } + + dma_async_issue_pending(chan); + + ret = + wait_for_completion_interruptible_timeout(&host->dma_access_complete, + msecs_to_jiffies(3000)); + if (ret <= 0) { + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dev_err(host->dev, "wait_for_completion_timeout\n"); + return ret ? ret : -ETIMEDOUT; + } + + return 0; +} + /* * fsmc_write_buf - write buffer to chip * @mtd: MTD device structure @@ -569,6 +656,35 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) } } +/* + * fsmc_read_buf_dma - read chip data into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + */ +static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct fsmc_nand_data *host; + + host = container_of(mtd, struct fsmc_nand_data, mtd); + dma_xfer(host, buf, len, DMA_FROM_DEVICE); +} + +/* + * fsmc_write_buf_dma - write buffer to chip + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + */ +static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct fsmc_nand_data *host; + + host = container_of(mtd, struct fsmc_nand_data, mtd); + dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE); +} + /* * fsmc_read_page_hwecc * @mtd: mtd info structure @@ -731,6 +847,12 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, return i; } +static bool filter(struct dma_chan *chan, void *slave) +{ + chan->private = slave; + return true; +} + /* * fsmc_nand_probe - Probe function * @pdev: platform device structure @@ -743,6 +865,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) struct nand_chip *nand; struct fsmc_regs *regs; struct resource *res; + dma_cap_mask_t mask; int ret = 0; u32 pid; int i; @@ -769,6 +892,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) return -ENOENT; } + host->data_pa = (dma_addr_t)res->start; host->data_va = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!host->data_va) { @@ -847,6 +971,11 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->nr_partitions = pdata->nr_partitions; host->dev = &pdev->dev; host->dev_timings = pdata->nand_timings; + host->mode = pdata->mode; + + if (host->mode == USE_DMA_ACCESS) + init_completion(&host->dma_access_complete); + regs = host->regs_va; /* Link all private pointers */ @@ -871,13 +1000,31 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (pdata->width == FSMC_NAND_BW16) nand->options |= NAND_BUSWIDTH_16; - /* - * use customized (word by word) version of read_buf, write_buf if - * access_with_dev_width is reset supported - */ - if (pdata->mode == USE_WORD_ACCESS) { + switch (host->mode) { + case USE_DMA_ACCESS: + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + host->read_dma_chan = dma_request_channel(mask, filter, + pdata->read_dma_priv); + if (!host->read_dma_chan) { + dev_err(&pdev->dev, "Unable to get read dma channel\n"); + goto err_req_read_chnl; + } + host->write_dma_chan = dma_request_channel(mask, filter, + pdata->write_dma_priv); + if (!host->write_dma_chan) { + dev_err(&pdev->dev, "Unable to get write dma channel\n"); + goto err_req_write_chnl; + } + nand->read_buf = fsmc_read_buf_dma; + nand->write_buf = fsmc_write_buf_dma; + break; + + default: + case USE_WORD_ACCESS: nand->read_buf = fsmc_read_buf; nand->write_buf = fsmc_write_buf; + break; } fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16, @@ -978,6 +1125,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) err_probe: err_scan_ident: + if (host->mode == USE_DMA_ACCESS) + dma_release_channel(host->write_dma_chan); +err_req_write_chnl: + if (host->mode == USE_DMA_ACCESS) + dma_release_channel(host->read_dma_chan); +err_req_read_chnl: clk_disable(host->clk); err_clk_enable: clk_put(host->clk); @@ -995,6 +1148,11 @@ static int fsmc_nand_remove(struct platform_device *pdev) if (host) { nand_release(&host->mtd); + + if (host->mode == USE_DMA_ACCESS) { + dma_release_channel(host->write_dma_chan); + dma_release_channel(host->read_dma_chan); + } clk_disable(host->clk); clk_put(host->clk); } diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h index 1edd2b3ac38e..18f9127a6631 100644 --- a/include/linux/mtd/fsmc.h +++ b/include/linux/mtd/fsmc.h @@ -172,6 +172,10 @@ struct fsmc_nand_platform_data { enum access_mode mode; void (*select_bank)(uint32_t bank, uint32_t busw); + + /* priv structures for dma accesses */ + void *read_dma_priv; + void *write_dma_priv; }; extern int __init fsmc_nor_init(struct platform_device *pdev, -- cgit v1.2.3 From 2a5dbead29a7c081a47133eb428440147a6d8d5a Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Wed, 14 Mar 2012 11:47:19 +0530 Subject: mtd: nand/fsmc: Remove sparse warnings and errors This patch removes the sparse below warnings and errors for nand/fsmc driver /root/vipin/spear/kernel/3.3/linux-3.3/drivers/mtd/nand/fsmc_nand.c:363:31: warning: incorrect type in initializer (different address spaces) /root/vipin/spear/kernel/3.3/linux-3.3/drivers/mtd/nand/fsmc_nand.c:363:31: expected struct fsmc_regs *regs /root/vipin/spear/kernel/3.3/linux-3.3/drivers/mtd/nand/fsmc_nand.c:363:31: got void [noderef] *regs_va [...] Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 91 ++++++++++++++------------- include/linux/mtd/fsmc.h | 143 ++++++++++++++++++++----------------------- 2 files changed, 111 insertions(+), 123 deletions(-) (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index d20a0c63251e..049018213090 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -360,28 +360,29 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) struct nand_chip *this = mtd->priv; struct fsmc_nand_data *host = container_of(mtd, struct fsmc_nand_data, mtd); - struct fsmc_regs *regs = host->regs_va; + void *__iomem *regs = host->regs_va; unsigned int bank = host->bank; if (ctrl & NAND_CTRL_CHANGE) { + u32 pc; + if (ctrl & NAND_CLE) { - this->IO_ADDR_R = (void __iomem *)host->cmd_va; - this->IO_ADDR_W = (void __iomem *)host->cmd_va; + this->IO_ADDR_R = host->cmd_va; + this->IO_ADDR_W = host->cmd_va; } else if (ctrl & NAND_ALE) { - this->IO_ADDR_R = (void __iomem *)host->addr_va; - this->IO_ADDR_W = (void __iomem *)host->addr_va; + this->IO_ADDR_R = host->addr_va; + this->IO_ADDR_W = host->addr_va; } else { - this->IO_ADDR_R = (void __iomem *)host->data_va; - this->IO_ADDR_W = (void __iomem *)host->data_va; + this->IO_ADDR_R = host->data_va; + this->IO_ADDR_W = host->data_va; } - if (ctrl & NAND_NCE) { - writel(readl(®s->bank_regs[bank].pc) | FSMC_ENABLE, - ®s->bank_regs[bank].pc); - } else { - writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ENABLE, - ®s->bank_regs[bank].pc); - } + pc = readl(FSMC_NAND_REG(regs, bank, PC)); + if (ctrl & NAND_NCE) + pc |= FSMC_ENABLE; + else + pc &= ~FSMC_ENABLE; + writel(pc, FSMC_NAND_REG(regs, bank, PC)); } mb(); @@ -396,7 +397,7 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) * This routine initializes timing parameters related to NAND memory access in * FSMC registers */ -static void fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, +static void fsmc_nand_setup(void __iomem *regs, uint32_t bank, uint32_t busw, struct fsmc_nand_timings *timings) { uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON; @@ -424,14 +425,14 @@ static void fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT; if (busw) - writel(value | FSMC_DEVWID_16, ®s->bank_regs[bank].pc); + writel(value | FSMC_DEVWID_16, FSMC_NAND_REG(regs, bank, PC)); else - writel(value | FSMC_DEVWID_8, ®s->bank_regs[bank].pc); + writel(value | FSMC_DEVWID_8, FSMC_NAND_REG(regs, bank, PC)); - writel(readl(®s->bank_regs[bank].pc) | tclr | tar, - ®s->bank_regs[bank].pc); - writel(thiz | thold | twait | tset, ®s->bank_regs[bank].comm); - writel(thiz | thold | twait | tset, ®s->bank_regs[bank].attrib); + writel(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar, + FSMC_NAND_REG(regs, bank, PC)); + writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, COMM)); + writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, ATTRIB)); } /* @@ -441,15 +442,15 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) { struct fsmc_nand_data *host = container_of(mtd, struct fsmc_nand_data, mtd); - struct fsmc_regs *regs = host->regs_va; + void __iomem *regs = host->regs_va; uint32_t bank = host->bank; - writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ECCPLEN_256, - ®s->bank_regs[bank].pc); - writel(readl(®s->bank_regs[bank].pc) & ~FSMC_ECCEN, - ®s->bank_regs[bank].pc); - writel(readl(®s->bank_regs[bank].pc) | FSMC_ECCEN, - ®s->bank_regs[bank].pc); + writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256, + FSMC_NAND_REG(regs, bank, PC)); + writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN, + FSMC_NAND_REG(regs, bank, PC)); + writel(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN, + FSMC_NAND_REG(regs, bank, PC)); } /* @@ -462,13 +463,13 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, { struct fsmc_nand_data *host = container_of(mtd, struct fsmc_nand_data, mtd); - struct fsmc_regs *regs = host->regs_va; + void __iomem *regs = host->regs_va; uint32_t bank = host->bank; uint32_t ecc_tmp; unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; do { - if (readl(®s->bank_regs[bank].sts) & FSMC_CODE_RDY) + if (readl(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY) break; else cond_resched(); @@ -479,25 +480,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, return -ETIMEDOUT; } - ecc_tmp = readl(®s->bank_regs[bank].ecc1); + ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1)); ecc[0] = (uint8_t) (ecc_tmp >> 0); ecc[1] = (uint8_t) (ecc_tmp >> 8); ecc[2] = (uint8_t) (ecc_tmp >> 16); ecc[3] = (uint8_t) (ecc_tmp >> 24); - ecc_tmp = readl(®s->bank_regs[bank].ecc2); + ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC2)); ecc[4] = (uint8_t) (ecc_tmp >> 0); ecc[5] = (uint8_t) (ecc_tmp >> 8); ecc[6] = (uint8_t) (ecc_tmp >> 16); ecc[7] = (uint8_t) (ecc_tmp >> 24); - ecc_tmp = readl(®s->bank_regs[bank].ecc3); + ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC3)); ecc[8] = (uint8_t) (ecc_tmp >> 0); ecc[9] = (uint8_t) (ecc_tmp >> 8); ecc[10] = (uint8_t) (ecc_tmp >> 16); ecc[11] = (uint8_t) (ecc_tmp >> 24); - ecc_tmp = readl(®s->bank_regs[bank].sts); + ecc_tmp = readl(FSMC_NAND_REG(regs, bank, STS)); ecc[12] = (uint8_t) (ecc_tmp >> 16); return 0; @@ -513,11 +514,11 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, { struct fsmc_nand_data *host = container_of(mtd, struct fsmc_nand_data, mtd); - struct fsmc_regs *regs = host->regs_va; + void __iomem *regs = host->regs_va; uint32_t bank = host->bank; uint32_t ecc_tmp; - ecc_tmp = readl(®s->bank_regs[bank].ecc1); + ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1)); ecc[0] = (uint8_t) (ecc_tmp >> 0); ecc[1] = (uint8_t) (ecc_tmp >> 8); ecc[2] = (uint8_t) (ecc_tmp >> 16); @@ -771,13 +772,13 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, struct fsmc_nand_data *host = container_of(mtd, struct fsmc_nand_data, mtd); struct nand_chip *chip = mtd->priv; - struct fsmc_regs *regs = host->regs_va; + void __iomem *regs = host->regs_va; unsigned int bank = host->bank; uint32_t err_idx[8]; uint32_t num_err, i; uint32_t ecc1, ecc2, ecc3, ecc4; - num_err = (readl(®s->bank_regs[bank].sts) >> 10) & 0xF; + num_err = (readl(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF; /* no bit flipping */ if (likely(num_err == 0)) @@ -820,10 +821,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, * uint64_t array and error offset indexes are populated in err_idx * array */ - ecc1 = readl(®s->bank_regs[bank].ecc1); - ecc2 = readl(®s->bank_regs[bank].ecc2); - ecc3 = readl(®s->bank_regs[bank].ecc3); - ecc4 = readl(®s->bank_regs[bank].sts); + ecc1 = readl(FSMC_NAND_REG(regs, bank, ECC1)); + ecc2 = readl(FSMC_NAND_REG(regs, bank, ECC2)); + ecc3 = readl(FSMC_NAND_REG(regs, bank, ECC3)); + ecc4 = readl(FSMC_NAND_REG(regs, bank, STS)); err_idx[0] = (ecc1 >> 0) & 0x1FFF; err_idx[1] = (ecc1 >> 13) & 0x1FFF; @@ -863,7 +864,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) struct fsmc_nand_data *host; struct mtd_info *mtd; struct nand_chip *nand; - struct fsmc_regs *regs; struct resource *res; dma_cap_mask_t mask; int ret = 0; @@ -976,8 +976,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (host->mode == USE_DMA_ACCESS) init_completion(&host->dma_access_complete); - regs = host->regs_va; - /* Link all private pointers */ mtd = &host->mtd; nand = &host->nand; @@ -1027,7 +1025,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) break; } - fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16, + fsmc_nand_setup(host->regs_va, host->bank, + nand->options & NAND_BUSWIDTH_16, host->dev_timings); if (AMBA_REV_BITS(host->pid) >= 8) { diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h index 18f9127a6631..823359c0f5a1 100644 --- a/include/linux/mtd/fsmc.h +++ b/include/linux/mtd/fsmc.h @@ -32,88 +32,77 @@ #define FSMC_FLASH_WIDTH8 1 #define FSMC_FLASH_WIDTH16 2 -struct fsmc_nor_bank_regs { - uint32_t ctrl; - uint32_t ctrl_tim; -}; - -/* ctrl register definitions */ -#define BANK_ENABLE (1 << 0) -#define MUXED (1 << 1) -#define NOR_DEV (2 << 2) -#define WIDTH_8 (0 << 4) -#define WIDTH_16 (1 << 4) -#define RSTPWRDWN (1 << 6) -#define WPROT (1 << 7) -#define WRT_ENABLE (1 << 12) -#define WAIT_ENB (1 << 13) - -/* ctrl_tim register definitions */ - -struct fsmc_nand_bank_regs { - uint32_t pc; - uint32_t sts; - uint32_t comm; - uint32_t attrib; - uint32_t ioata; - uint32_t ecc1; - uint32_t ecc2; - uint32_t ecc3; -}; - +/* fsmc controller registers for NOR flash */ +#define CTRL 0x0 + /* ctrl register definitions */ + #define BANK_ENABLE (1 << 0) + #define MUXED (1 << 1) + #define NOR_DEV (2 << 2) + #define WIDTH_8 (0 << 4) + #define WIDTH_16 (1 << 4) + #define RSTPWRDWN (1 << 6) + #define WPROT (1 << 7) + #define WRT_ENABLE (1 << 12) + #define WAIT_ENB (1 << 13) + +#define CTRL_TIM 0x4 + /* ctrl_tim register definitions */ + +#define FSMC_NOR_BANK_SZ 0x8 #define FSMC_NOR_REG_SIZE 0x40 -struct fsmc_regs { - struct fsmc_nor_bank_regs nor_bank_regs[FSMC_MAX_NOR_BANKS]; - uint8_t reserved_1[0x40 - 0x20]; - struct fsmc_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS]; - uint8_t reserved_2[0xfe0 - 0xc0]; - uint32_t peripid0; /* 0xfe0 */ - uint32_t peripid1; /* 0xfe4 */ - uint32_t peripid2; /* 0xfe8 */ - uint32_t peripid3; /* 0xfec */ - uint32_t pcellid0; /* 0xff0 */ - uint32_t pcellid1; /* 0xff4 */ - uint32_t pcellid2; /* 0xff8 */ - uint32_t pcellid3; /* 0xffc */ -}; +#define FSMC_NOR_REG(base, bank, reg) (base + \ + FSMC_NOR_BANK_SZ * (bank) + \ + reg) + +/* fsmc controller registers for NAND flash */ +#define PC 0x00 + /* pc register definitions */ + #define FSMC_RESET (1 << 0) + #define FSMC_WAITON (1 << 1) + #define FSMC_ENABLE (1 << 2) + #define FSMC_DEVTYPE_NAND (1 << 3) + #define FSMC_DEVWID_8 (0 << 4) + #define FSMC_DEVWID_16 (1 << 4) + #define FSMC_ECCEN (1 << 6) + #define FSMC_ECCPLEN_512 (0 << 7) + #define FSMC_ECCPLEN_256 (1 << 7) + #define FSMC_TCLR_1 (1) + #define FSMC_TCLR_SHIFT (9) + #define FSMC_TCLR_MASK (0xF) + #define FSMC_TAR_1 (1) + #define FSMC_TAR_SHIFT (13) + #define FSMC_TAR_MASK (0xF) +#define STS 0x04 + /* sts register definitions */ + #define FSMC_CODE_RDY (1 << 15) +#define COMM 0x08 + /* comm register definitions */ + #define FSMC_TSET_0 0 + #define FSMC_TSET_SHIFT 0 + #define FSMC_TSET_MASK 0xFF + #define FSMC_TWAIT_6 6 + #define FSMC_TWAIT_SHIFT 8 + #define FSMC_TWAIT_MASK 0xFF + #define FSMC_THOLD_4 4 + #define FSMC_THOLD_SHIFT 16 + #define FSMC_THOLD_MASK 0xFF + #define FSMC_THIZ_1 1 + #define FSMC_THIZ_SHIFT 24 + #define FSMC_THIZ_MASK 0xFF +#define ATTRIB 0x0C +#define IOATA 0x10 +#define ECC1 0x14 +#define ECC2 0x18 +#define ECC3 0x1C +#define FSMC_NAND_BANK_SZ 0x20 + +#define FSMC_NAND_REG(base, bank, reg) (base + FSMC_NOR_REG_SIZE + \ + (FSMC_NAND_BANK_SZ * (bank)) + \ + reg) #define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ) -/* pc register definitions */ -#define FSMC_RESET (1 << 0) -#define FSMC_WAITON (1 << 1) -#define FSMC_ENABLE (1 << 2) -#define FSMC_DEVTYPE_NAND (1 << 3) -#define FSMC_DEVWID_8 (0 << 4) -#define FSMC_DEVWID_16 (1 << 4) -#define FSMC_ECCEN (1 << 6) -#define FSMC_ECCPLEN_512 (0 << 7) -#define FSMC_ECCPLEN_256 (1 << 7) -#define FSMC_TCLR_1 (1) -#define FSMC_TCLR_SHIFT (9) -#define FSMC_TCLR_MASK (0xF) -#define FSMC_TAR_1 (1) -#define FSMC_TAR_SHIFT (13) -#define FSMC_TAR_MASK (0xF) - -/* sts register definitions */ -#define FSMC_CODE_RDY (1 << 15) - -/* comm register definitions */ -#define FSMC_TSET_0 0 -#define FSMC_TSET_SHIFT 0 -#define FSMC_TSET_MASK 0xFF -#define FSMC_TWAIT_6 6 -#define FSMC_TWAIT_SHIFT 8 -#define FSMC_TWAIT_MASK 0xFF -#define FSMC_THOLD_4 4 -#define FSMC_THOLD_SHIFT 16 -#define FSMC_THOLD_MASK 0xFF -#define FSMC_THIZ_1 1 -#define FSMC_THIZ_SHIFT 24 -#define FSMC_THIZ_MASK 0xFF - /* * There are 13 bytes of ecc for every 512 byte block in FSMC version 8 * and it has to be read consecutively and immediately after the 512 -- cgit v1.2.3 From eea628199d5b12429c47db17035a954b0062e554 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 16 Mar 2012 10:19:31 +0100 Subject: mtd: Add device-tree support to fsmc_nand This patch adds support to configure the FSMC NAND driver (used amongst others on SPEAr platforms) via device-tree instead of platform_data. Signed-off-by: Stefan Roese Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- .../devicetree/bindings/mtd/fsmc-nand.txt | 33 +++++++++++++ drivers/mtd/nand/fsmc_nand.c | 57 +++++++++++++++++++++- include/linux/mtd/fsmc.h | 4 +- 3 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/fsmc-nand.txt (limited to 'drivers/mtd/nand/fsmc_nand.c') diff --git a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt new file mode 100644 index 000000000000..e2c663b354d2 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt @@ -0,0 +1,33 @@ +* FSMC NAND + +Required properties: +- compatible : "st,spear600-fsmc-nand" +- reg : Address range of the mtd chip +- reg-names: Should contain the reg names "fsmc_regs" and "nand_data" +- st,ale-off : Chip specific offset to ALE +- st,cle-off : Chip specific offset to CLE + +Optional properties: +- bank-width : Width (in bytes) of the device. If not present, the width + defaults to 1 byte +- nand-skip-bbtscan: Indicates the the BBT scanning should be skipped + +Example: + + fsmc: flash@d1800000 { + compatible = "st,spear600-fsmc-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xd1800000 0x1000 /* FSMC Register */ + 0xd2000000 0x4000>; /* NAND Base */ + reg-names = "fsmc_regs", "nand_data"; + st,ale-off = <0x20000>; + st,cle-off = <0x10000>; + + bank-width = <1>; + nand-skip-bbtscan; + + partition@0 { + ... + }; + }; diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 049018213090..1b8330e1155a 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -854,6 +855,38 @@ static bool filter(struct dma_chan *chan, void *slave) return true; } +#ifdef CONFIG_OF +static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, + struct device_node *np) +{ + struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); + u32 val; + + /* Set default NAND width to 8 bits */ + pdata->width = 8; + if (!of_property_read_u32(np, "bank-width", &val)) { + if (val == 2) { + pdata->width = 16; + } else if (val != 1) { + dev_err(&pdev->dev, "invalid bank-width %u\n", val); + return -EINVAL; + } + } + of_property_read_u32(np, "st,ale-off", &pdata->ale_off); + of_property_read_u32(np, "st,cle-off", &pdata->cle_off); + if (of_get_property(np, "nand-skip-bbtscan", NULL)) + pdata->options = NAND_SKIP_BBTSCAN; + + return 0; +} +#else +static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, + struct device_node *np) +{ + return -ENOSYS; +} +#endif + /* * fsmc_nand_probe - Probe function * @pdev: platform device structure @@ -861,6 +894,8 @@ static bool filter(struct dma_chan *chan, void *slave) static int __init fsmc_nand_probe(struct platform_device *pdev) { struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct device_node __maybe_unused *np = pdev->dev.of_node; + struct mtd_part_parser_data ppdata = {}; struct fsmc_nand_data *host; struct mtd_info *mtd; struct nand_chip *nand; @@ -870,6 +905,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) u32 pid; int i; + if (np) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdev->dev.platform_data = pdata; + ret = fsmc_nand_probe_config_dt(pdev, np); + if (ret) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENODEV; + } + } + if (!pdata) { dev_err(&pdev->dev, "platform data is NULL\n"); return -EINVAL; @@ -1113,7 +1158,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * Check for partition info passed */ host->mtd.name = "nand"; - ret = mtd_device_parse_register(&host->mtd, NULL, NULL, + ppdata.of_node = np; + ret = mtd_device_parse_register(&host->mtd, NULL, &ppdata, host->partitions, host->nr_partitions); if (ret) goto err_probe; @@ -1183,11 +1229,20 @@ static int fsmc_nand_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume); #endif +#ifdef CONFIG_OF +static const struct of_device_id fsmc_nand_id_table[] = { + { .compatible = "st,spear600-fsmc-nand" }, + {} +}; +MODULE_DEVICE_TABLE(of, fsmc_nand_id_table); +#endif + static struct platform_driver fsmc_nand_driver = { .remove = fsmc_nand_remove, .driver = { .owner = THIS_MODULE, .name = "fsmc-nand", + .of_match_table = of_match_ptr(fsmc_nand_id_table), #ifdef CONFIG_PM .pm = &fsmc_nand_pm_ops, #endif diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h index 823359c0f5a1..b20029221fb1 100644 --- a/include/linux/mtd/fsmc.h +++ b/include/linux/mtd/fsmc.h @@ -156,8 +156,8 @@ struct fsmc_nand_platform_data { unsigned int bank; /* CLE, ALE offsets */ - unsigned long cle_off; - unsigned long ale_off; + unsigned int cle_off; + unsigned int ale_off; enum access_mode mode; void (*select_bank)(uint32_t bank, uint32_t busw); -- cgit v1.2.3