[PATCH 10/11] fsmc/nand: Add sw bch support for ecc calculation/correction
Jean-Christophe PLAGNIOL-VILLARD
plagnioj at jcrosoft.com
Tue Oct 9 07:50:23 EDT 2012
On 16:14 Tue 09 Oct , Vipin Kumar wrote:
> Signed-off-by: Vipin Kumar <vipin.kumar at st.com>
> ---
> .../devicetree/bindings/mtd/fsmc-nand.txt | 2 +
> drivers/mtd/nand/fsmc_nand.c | 156 +++++++++++++--------
> include/linux/mtd/fsmc.h | 3 +
> 3 files changed, 106 insertions(+), 55 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
> index 598bca2..dcf513b 100644
> --- a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
> +++ b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
> @@ -30,6 +30,8 @@ Optional properties:
> - st,rb-gpios: When the st,ready-busy is defined as "rb-gpio", a gpio
> pin number is defined in this property
>
> +- nand-sw-ecc: boolean indicating whether s/w ecc is supported
> +
please use the generic binding
- nand-ecc-mode = xx
> Example:
>
> fsmc: flash at d1800000 {
> diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
> index 762cf83..ff84468 100644
> --- a/drivers/mtd/nand/fsmc_nand.c
> +++ b/drivers/mtd/nand/fsmc_nand.c
> @@ -946,6 +946,9 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
> } else
> pdata->rbpin.use_pin = FSMC_RB_WAIT;
>
> + if (of_property_read_bool(np, "nand-sw-ecc"))
> + pdata->sw_ecc = true;
> +
of_get_nand_ecc_mode
> return 0;
> }
> #else
> @@ -972,6 +975,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
> dma_cap_mask_t mask;
> int ret = 0;
> u32 pid, bank;
> + uint oobeccsize, m;
> int i;
>
> if (np) {
> @@ -1104,9 +1108,24 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
> nand->cmd_ctrl = fsmc_cmd_ctrl;
> nand->chip_delay = 30;
>
> - nand->ecc.mode = NAND_ECC_HW;
> - nand->ecc.hwctl = fsmc_enable_hwecc;
> - nand->ecc.size = 512;
> + if (pdata->sw_ecc) {
> + nand->ecc.mode = NAND_ECC_SOFT_BCH;
> + /*
> + * The recent devices require n-bit correctibility in x bytes.
> + * The values of n and x varies as below
> + * n - 1 to 100
> + * x - 512 to 1K
> + * TODO: For now, take x = 1K for all sw bch mathematics. Think
> + * of a better way to handle other device dependent
> + * requirements. May be it should come from board dts files
> + */
> + nand->ecc.size = 1024;
> + } else {
> + nand->ecc.mode = NAND_ECC_HW;
> + nand->ecc.hwctl = fsmc_enable_hwecc;
> + nand->ecc.size = 512;
> + }
> +
> nand->options = pdata->options;
> nand->select_chip = fsmc_select_chip;
> nand->badblockbits = 7;
> @@ -1165,17 +1184,19 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
> nand->options & NAND_BUSWIDTH_16,
> host->dev_timings, host->rbpin);
>
> - 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_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;
> + if (nand->ecc.mode != NAND_ECC_SOFT_BCH) {
> + 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_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;
> + }
> }
>
> /*
> @@ -1187,48 +1208,73 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
> goto err_scan_ident;
> }
>
> - if (AMBA_REV_BITS(host->pid) >= 8) {
> - switch (host->mtd.oobsize) {
> - case 16:
> - nand->ecc.layout = &fsmc_ecc4_16_layout;
> - host->ecc_place = &fsmc_ecc4_sp_place;
> - 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 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;
> - break;
> - default:
> - printk(KERN_WARNING "No oob scheme defined for "
> - "oobsize %d\n", mtd->oobsize);
> - BUG();
> - }
> + if (nand->ecc.mode == NAND_ECC_SOFT_BCH) {
> + /*
> + * Initialize the ecc bytes and strength dynamically based on eccsize
> + * and writesize.
> + *
> + * Parameters @eccsize and @eccbytes are used to compute BCH parameters
> + * m (Galois field order) and t (error correction capability). @eccbytes
> + * should be equal to the number of bytes required to store m*t bits,
> + * where m is such that 2^m-1 > @eccsize*8.
> + *
> + * Example: to configure 4 bit correction per 512 bytes, you should pass
> + * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 >
> + * 512*8) @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52
> + * bits)
> + *
> + * Note: 2 bytes of oob are considered reserved for bad block marking
> + */
> + m = fls(1 + 8 * nand->ecc.size);
> + oobeccsize = ((host->mtd.oobsize - 2) * \
> + nand->ecc.size) / host->mtd.writesize;
> + nand->ecc.bytes = (oobeccsize / m) * m;
> + nand->ecc.strength = (nand->ecc.bytes * 8) / m;
> + nand->ecc.layout = NULL;
> } else {
> - 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();
> + if (AMBA_REV_BITS(host->pid) >= 8) {
> + switch (host->mtd.oobsize) {
> + case 16:
> + nand->ecc.layout = &fsmc_ecc4_16_layout;
> + host->ecc_place = &fsmc_ecc4_sp_place;
> + 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 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;
> + break;
> + default:
> + printk(KERN_WARNING "No oob scheme defined for "
> + "oobsize %d\n", mtd->oobsize);
> + BUG();
> + }
> + } else {
> + 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();
> + }
> }
> }
>
> diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h
> index eed22a1..07eee6e 100644
> --- a/include/linux/mtd/fsmc.h
> +++ b/include/linux/mtd/fsmc.h
> @@ -176,6 +176,9 @@ struct fsmc_nand_platform_data {
> /* priv structures for dma accesses */
> void *read_dma_priv;
> void *write_dma_priv;
> +
> + /* whether s/w ecc is supported */
> + bool sw_ecc;
> };
>
> extern int __init fsmc_nor_init(struct platform_device *pdev,
> --
> 1.7.11.4
>
More information about the linux-arm-kernel
mailing list