Merge tag 'spi-nor/for-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd...
authorRichard Weinberger <richard@nod.at>
Sun, 11 Oct 2020 20:07:52 +0000 (22:07 +0200)
committerRichard Weinberger <richard@nod.at>
Sun, 11 Oct 2020 20:07:52 +0000 (22:07 +0200)
SPI NOR core changes:
- Support for Winbond w25q64jwm flash
- Enable 4K sector support for mx25l12805d

SPI NOR controller drivers changes:
- intel-spi:
   - Add Alder Lake-S PCI ID

114 files changed:
Documentation/devicetree/bindings/mtd/nand-controller.yaml
arch/arm/mach-davinci/board-da830-evm.c
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-davinci/board-dm355-evm.c
arch/arm/mach-davinci/board-dm355-leopard.c
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-davinci/board-dm644x-evm.c
arch/arm/mach-davinci/board-dm646x-evm.c
arch/arm/mach-davinci/board-mityomapl138.c
arch/arm/mach-davinci/board-neuros-osd2.c
arch/arm/mach-davinci/board-omapl138-hawk.c
arch/arm/mach-s3c24xx/common-smdk.c
arch/arm/mach-s3c24xx/mach-anubis.c
arch/arm/mach-s3c24xx/mach-at2440evb.c
arch/arm/mach-s3c24xx/mach-bast.c
arch/arm/mach-s3c24xx/mach-gta02.c
arch/arm/mach-s3c24xx/mach-jive.c
arch/arm/mach-s3c24xx/mach-mini2440.c
arch/arm/mach-s3c24xx/mach-osiris.c
arch/arm/mach-s3c24xx/mach-qt2410.c
arch/arm/mach-s3c24xx/mach-rx1950.c
arch/arm/mach-s3c24xx/mach-rx3715.c
arch/arm/mach-s3c24xx/mach-vstms.c
arch/arm/mach-s3c64xx/mach-hmt.c
arch/arm/mach-s3c64xx/mach-mini6410.c
arch/arm/mach-s3c64xx/mach-real6410.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/lart.c
drivers/mtd/devices/spear_smi.c
drivers/mtd/lpddr/lpddr2_nvm.c
drivers/mtd/lpddr/lpddr_cmds.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/physmap-bt1-rom.c [new file with mode: 0644]
drivers/mtd/maps/physmap-bt1-rom.h [new file with mode: 0644]
drivers/mtd/maps/physmap-core.c
drivers/mtd/maps/vmu-flash.c
drivers/mtd/mtdconcat.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdoops.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/ecc.c [new file with mode: 0644]
drivers/mtd/nand/onenand/onenand_base.c
drivers/mtd/nand/onenand/onenand_omap2.c
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/ams-delta.c
drivers/mtd/nand/raw/arasan-nand-controller.c
drivers/mtd/nand/raw/atmel/nand-controller.c
drivers/mtd/nand/raw/au1550nd.c
drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
drivers/mtd/nand/raw/brcmnand/brcmnand.c
drivers/mtd/nand/raw/cadence-nand-controller.c
drivers/mtd/nand/raw/cafe_nand.c
drivers/mtd/nand/raw/cs553x_nand.c
drivers/mtd/nand/raw/davinci_nand.c
drivers/mtd/nand/raw/denali.c
drivers/mtd/nand/raw/denali_pci.c
drivers/mtd/nand/raw/diskonchip.c
drivers/mtd/nand/raw/fsl_elbc_nand.c
drivers/mtd/nand/raw/fsl_ifc_nand.c
drivers/mtd/nand/raw/fsl_upm.c
drivers/mtd/nand/raw/fsmc_nand.c
drivers/mtd/nand/raw/gpio.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/raw/hisi504_nand.c
drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c
drivers/mtd/nand/raw/lpc32xx_mlc.c
drivers/mtd/nand/raw/lpc32xx_slc.c
drivers/mtd/nand/raw/marvell_nand.c
drivers/mtd/nand/raw/meson_nand.c
drivers/mtd/nand/raw/mpc5121_nfc.c
drivers/mtd/nand/raw/mtk_nand.c
drivers/mtd/nand/raw/mxc_nand.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/nand_bch.c
drivers/mtd/nand/raw/nand_esmt.c
drivers/mtd/nand/raw/nand_hynix.c
drivers/mtd/nand/raw/nand_jedec.c
drivers/mtd/nand/raw/nand_micron.c
drivers/mtd/nand/raw/nand_onfi.c
drivers/mtd/nand/raw/nand_samsung.c
drivers/mtd/nand/raw/nand_toshiba.c
drivers/mtd/nand/raw/nandsim.c
drivers/mtd/nand/raw/ndfc.c
drivers/mtd/nand/raw/omap2.c
drivers/mtd/nand/raw/orion_nand.c
drivers/mtd/nand/raw/oxnas_nand.c
drivers/mtd/nand/raw/pasemi_nand.c
drivers/mtd/nand/raw/plat_nand.c
drivers/mtd/nand/raw/qcom_nandc.c
drivers/mtd/nand/raw/r852.c
drivers/mtd/nand/raw/s3c2410.c
drivers/mtd/nand/raw/sh_flctl.c
drivers/mtd/nand/raw/sharpsl.c
drivers/mtd/nand/raw/socrates_nand.c
drivers/mtd/nand/raw/stm32_fmc2_nand.c
drivers/mtd/nand/raw/sunxi_nand.c
drivers/mtd/nand/raw/tango_nand.c
drivers/mtd/nand/raw/tegra_nand.c
drivers/mtd/nand/raw/tmio_nand.c
drivers/mtd/nand/raw/txx9ndfmc.c
drivers/mtd/nand/raw/vf610_nfc.c
drivers/mtd/nand/raw/xway_nand.c
drivers/mtd/nand/spi/core.c
drivers/mtd/nand/spi/gigadevice.c
drivers/mtd/nand/spi/macronix.c
drivers/mtd/nand/spi/toshiba.c
drivers/mtd/parsers/Kconfig
include/linux/mtd/nand.h
include/linux/mtd/pfow.h
include/linux/mtd/rawnand.h
include/linux/platform_data/mtd-davinci.h
include/linux/platform_data/mtd-nand-s3c2410.h

index 40fc5b0..e79bb6d 100644 (file)
@@ -55,6 +55,37 @@ patternProperties:
         $ref: /schemas/types.yaml#/definitions/string
         enum: [none, soft, hw, hw_syndrome, hw_oob_first, on-die]
 
+      nand-ecc-engine:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/phandle
+        description: |
+          A phandle on the hardware ECC engine if any. There are
+          basically three possibilities:
+          1/ The ECC engine is part of the NAND controller, in this
+          case the phandle should reference the parent node.
+          2/ The ECC engine is part of the NAND part (on-die), in this
+          case the phandle should reference the node itself.
+          3/ The ECC engine is external, in this case the phandle should
+          reference the specific ECC engine node.
+
+      nand-use-soft-ecc-engine:
+        type: boolean
+        description: Use a software ECC engine.
+
+      nand-no-ecc-engine:
+        type: boolean
+        description: Do not use any ECC correction.
+
+      nand-ecc-placement:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/string
+          - enum: [ oob, interleaved ]
+        description:
+          Location of the ECC bytes. This location is unknown by default
+          but can be explicitly set to "oob", if all ECC bytes are
+          known to be stored in the OOB area, or "interleaved" if ECC
+          bytes will be interleaved with regular data in the main area.
+
       nand-ecc-algo:
         description:
           Desired ECC algorithm.
index 1076886..a20ba12 100644 (file)
@@ -306,7 +306,7 @@ static struct davinci_nand_pdata da830_evm_nand_pdata = {
        .core_chipsel   = 1,
        .parts          = da830_evm_nand_partitions,
        .nr_parts       = ARRAY_SIZE(da830_evm_nand_partitions),
-       .ecc_mode       = NAND_ECC_HW,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_ON_HOST,
        .ecc_bits       = 4,
        .bbt_options    = NAND_BBT_USE_FLASH,
        .bbt_td         = &da830_evm_nand_bbt_main_descr,
index 6751292..4280126 100644 (file)
@@ -239,7 +239,7 @@ static struct davinci_nand_pdata da850_evm_nandflash_data = {
        .core_chipsel   = 1,
        .parts          = da850_evm_nandflash_partition,
        .nr_parts       = ARRAY_SIZE(da850_evm_nandflash_partition),
-       .ecc_mode       = NAND_ECC_HW,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_ON_HOST,
        .ecc_bits       = 4,
        .bbt_options    = NAND_BBT_USE_FLASH,
        .timing         = &da850_evm_nandflash_timing,
index 5113273..3c5a9e3 100644 (file)
@@ -82,7 +82,7 @@ static struct davinci_nand_pdata davinci_nand_data = {
        .mask_chipsel           = BIT(14),
        .parts                  = davinci_nand_partitions,
        .nr_parts               = ARRAY_SIZE(davinci_nand_partitions),
-       .ecc_mode               = NAND_ECC_HW,
+       .engine_type            = NAND_ECC_ENGINE_TYPE_ON_HOST,
        .bbt_options            = NAND_BBT_USE_FLASH,
        .ecc_bits               = 4,
 };
index b9e9950..e475b21 100644 (file)
@@ -76,7 +76,8 @@ static struct davinci_nand_pdata davinci_nand_data = {
        .mask_chipsel           = BIT(14),
        .parts                  = davinci_nand_partitions,
        .nr_parts               = ARRAY_SIZE(davinci_nand_partitions),
-       .ecc_mode               = NAND_ECC_HW_SYNDROME,
+       .engine_type            = NAND_ECC_ENGINE_TYPE_ON_HOST,
+       .ecc_placement          = NAND_ECC_PLACEMENT_INTERLEAVED,
        .ecc_bits               = 4,
        .bbt_options            = NAND_BBT_USE_FLASH,
 };
index 2328b15..bdf31eb 100644 (file)
@@ -146,7 +146,7 @@ static struct davinci_nand_pdata davinci_nand_data = {
        .mask_chipsel           = BIT(14),
        .parts                  = davinci_nand_partitions,
        .nr_parts               = ARRAY_SIZE(davinci_nand_partitions),
-       .ecc_mode               = NAND_ECC_HW,
+       .engine_type            = NAND_ECC_ENGINE_TYPE_ON_HOST,
        .bbt_options            = NAND_BBT_USE_FLASH,
        .ecc_bits               = 4,
 };
index a5d3708..bcb3c40 100644 (file)
@@ -162,7 +162,7 @@ static struct davinci_nand_pdata davinci_evm_nandflash_data = {
        .core_chipsel   = 0,
        .parts          = davinci_evm_nandflash_partition,
        .nr_parts       = ARRAY_SIZE(davinci_evm_nandflash_partition),
-       .ecc_mode       = NAND_ECC_HW,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_ON_HOST,
        .ecc_bits       = 1,
        .bbt_options    = NAND_BBT_USE_FLASH,
        .timing         = &davinci_evm_nandflash_timing,
index dd7d60f..8319a60 100644 (file)
@@ -91,7 +91,7 @@ static struct davinci_nand_pdata davinci_nand_data = {
        .mask_ale               = 0x40000,
        .parts                  = davinci_nand_partitions,
        .nr_parts               = ARRAY_SIZE(davinci_nand_partitions),
-       .ecc_mode               = NAND_ECC_HW,
+       .engine_type            = NAND_ECC_ENGINE_TYPE_ON_HOST,
        .ecc_bits               = 1,
        .options                = 0,
 };
index 3382b93..5205008 100644 (file)
@@ -432,7 +432,7 @@ static struct davinci_nand_pdata mityomapl138_nandflash_data = {
        .core_chipsel   = 1,
        .parts          = mityomapl138_nandflash_partition,
        .nr_parts       = ARRAY_SIZE(mityomapl138_nandflash_partition),
-       .ecc_mode       = NAND_ECC_HW,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_ON_HOST,
        .bbt_options    = NAND_BBT_USE_FLASH,
        .options        = NAND_BUSWIDTH_16,
        .ecc_bits       = 1, /* 4 bit mode is not supported with 16 bit NAND */
index 6cf46bb..b4843f6 100644 (file)
@@ -90,7 +90,7 @@ static struct davinci_nand_pdata davinci_ntosd2_nandflash_data = {
        .core_chipsel   = 0,
        .parts          = davinci_ntosd2_nandflash_partition,
        .nr_parts       = ARRAY_SIZE(davinci_ntosd2_nandflash_partition),
-       .ecc_mode       = NAND_ECC_HW,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_ON_HOST,
        .ecc_bits       = 1,
        .bbt_options    = NAND_BBT_USE_FLASH,
 };
index 6c79039..88df801 100644 (file)
@@ -206,7 +206,7 @@ static struct davinci_nand_pdata omapl138_hawk_nandflash_data = {
        .core_chipsel   = 1,
        .parts          = omapl138_hawk_nandflash_partition,
        .nr_parts       = ARRAY_SIZE(omapl138_hawk_nandflash_partition),
-       .ecc_mode       = NAND_ECC_HW,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_ON_HOST,
        .ecc_bits       = 4,
        .bbt_options    = NAND_BBT_USE_FLASH,
        .options        = NAND_BUSWIDTH_16,
index 75064df..121646a 100644 (file)
@@ -191,7 +191,7 @@ static struct s3c2410_platform_nand smdk_nand_info = {
        .twrph1         = 20,
        .nr_sets        = ARRAY_SIZE(smdk_nand_sets),
        .sets           = smdk_nand_sets,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 /* devices we initialise */
index 072966d..2832624 100644 (file)
@@ -218,7 +218,7 @@ static struct s3c2410_platform_nand __initdata anubis_nand_info = {
        .nr_sets        = ARRAY_SIZE(anubis_nand_sets),
        .sets           = anubis_nand_sets,
        .select_chip    = anubis_nand_select,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 /* IDE channels */
index 58c5ef3..04dedeb 100644 (file)
@@ -109,7 +109,7 @@ static struct s3c2410_platform_nand __initdata at2440evb_nand_info = {
        .twrph1         = 40,
        .nr_sets        = ARRAY_SIZE(at2440evb_nand_sets),
        .sets           = at2440evb_nand_sets,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
index a7c3955..6465eab 100644 (file)
@@ -294,7 +294,7 @@ static struct s3c2410_platform_nand __initdata bast_nand_info = {
        .nr_sets        = ARRAY_SIZE(bast_nand_sets),
        .sets           = bast_nand_sets,
        .select_chip    = bast_nand_select,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 /* DM9000 */
index 594901f..db1b64f 100644 (file)
@@ -416,7 +416,7 @@ static struct s3c2410_platform_nand __initdata gta02_nand_info = {
        .twrph1         = 15,
        .nr_sets        = ARRAY_SIZE(gta02_nand_sets),
        .sets           = gta02_nand_sets,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 
index 885e8f1..8233dcf 100644 (file)
@@ -228,7 +228,7 @@ static struct s3c2410_platform_nand __initdata jive_nand_info = {
        .twrph1         = 40,
        .sets           = jive_nand_sets,
        .nr_sets        = ARRAY_SIZE(jive_nand_sets),
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 static int __init jive_mtdset(char *options)
index 2357494..057dcba 100644 (file)
@@ -296,7 +296,7 @@ static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
        .nr_sets        = ARRAY_SIZE(mini2440_nand_sets),
        .sets           = mini2440_nand_sets,
        .ignore_unset_ecc = 1,
-       .ecc_mode       = NAND_ECC_HW,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_ON_HOST,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
index ee3630c..1574488 100644 (file)
@@ -234,7 +234,7 @@ static struct s3c2410_platform_nand __initdata osiris_nand_info = {
        .nr_sets        = ARRAY_SIZE(osiris_nand_sets),
        .sets           = osiris_nand_sets,
        .select_chip    = osiris_nand_select,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 /* PCMCIA control and configuration */
index ff9e319..f3131d9 100644 (file)
@@ -287,7 +287,7 @@ static struct s3c2410_platform_nand __initdata qt2410_nand_info = {
        .twrph1         = 20,
        .nr_sets        = ARRAY_SIZE(qt2410_nand_sets),
        .sets           = qt2410_nand_sets,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 /* UDC */
index fde98b1..5ecb42e 100644 (file)
@@ -620,7 +620,7 @@ static struct s3c2410_platform_nand rx1950_nand_info = {
        .twrph1 = 15,
        .nr_sets = ARRAY_SIZE(rx1950_nand_sets),
        .sets = rx1950_nand_sets,
-       .ecc_mode = NAND_ECC_SOFT,
+       .engine_type = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
index 995f1ff..017010d 100644 (file)
@@ -158,7 +158,7 @@ static struct s3c2410_platform_nand __initdata rx3715_nand_info = {
        .twrph1         = 15,
        .nr_sets        = ARRAY_SIZE(rx3715_nand_sets),
        .sets           = rx3715_nand_sets,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 static struct platform_device *rx3715_devices[] __initdata = {
index d76b28b..c5fa215 100644 (file)
@@ -112,7 +112,7 @@ static struct s3c2410_platform_nand __initdata vstms_nand_info = {
        .twrph1         = 20,
        .nr_sets        = ARRAY_SIZE(vstms_nand_sets),
        .sets           = vstms_nand_sets,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 static struct platform_device *vstms_devices[] __initdata = {
index e708021..0d9acaf 100644 (file)
@@ -199,7 +199,7 @@ static struct s3c2410_platform_nand hmt_nand_info = {
        .twrph1         = 40,
        .nr_sets        = ARRAY_SIZE(hmt_nand_sets),
        .sets           = hmt_nand_sets,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 static struct gpio_led hmt_leds[] = {
index 0dd36ae..6fbb578 100644 (file)
@@ -136,7 +136,7 @@ static struct s3c2410_platform_nand mini6410_nand_info = {
        .twrph1         = 40,
        .nr_sets        = ARRAY_SIZE(mini6410_nand_sets),
        .sets           = mini6410_nand_sets,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
index 0ff88b6..1e98e53 100644 (file)
@@ -188,7 +188,7 @@ static struct s3c2410_platform_nand real6410_nand_info = {
        .twrph1         = 40,
        .nr_sets        = ARRAY_SIZE(real6410_nand_sets),
        .sets           = real6410_nand_sets,
-       .ecc_mode       = NAND_ECC_SOFT,
+       .engine_type    = NAND_ECC_ENGINE_TYPE_SOFT,
 };
 
 static struct platform_device *real6410_devices[] __initdata = {
index f96287c..0f4c2d8 100644 (file)
@@ -91,7 +91,7 @@ config MTD_MCHP23K256
 
 config MTD_SPEAR_SMI
        tristate "SPEAR MTD NOR Support through SMI controller"
-       depends on PLAT_SPEAR
+       depends on PLAT_SPEAR || COMPILE_TEST
        default y
        help
          This enable SNOR support on SPEAR platforms using SMI controller
index 56f50d2..aecd441 100644 (file)
@@ -436,7 +436,10 @@ static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retle
         {
                int gap = BUSWIDTH - (from & (BUSWIDTH - 1));
 
-               while (len && gap--) *buf++ = read8 (from++), len--;
+               while (len && gap--) {
+                       *buf++ = read8 (from++);
+                       len--;
+               }
         }
 
    /* now we read dwords until we reach a non-dword boundary */
@@ -518,7 +521,10 @@ static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen
                i = n = 0;
 
                while (gap--) tmp[i++] = 0xFF;
-               while (len && i < BUSWIDTH) tmp[i++] = buf[n++], len--;
+               while (len && i < BUSWIDTH) {
+                       tmp[i++] = buf[n++];
+                       len--;
+               }
                while (i < BUSWIDTH) tmp[i++] = 0xFF;
 
                if (!write_dword (aligned,*((__u32 *) tmp))) return (-EIO);
index 79dcca1..2e00862 100644 (file)
@@ -793,7 +793,7 @@ static int spear_smi_probe_config_dt(struct platform_device *pdev,
                                     struct device_node *np)
 {
        struct spear_smi_plat_data *pdata = dev_get_platdata(&pdev->dev);
-       struct device_node *pp = NULL;
+       struct device_node *pp;
        const __be32 *addr;
        u32 val;
        int len;
@@ -812,7 +812,7 @@ static int spear_smi_probe_config_dt(struct platform_device *pdev,
                return -ENOMEM;
 
        /* Fill structs for each subnode (flash device) */
-       while ((pp = of_get_next_child(np, pp))) {
+       for_each_child_of_node(np, pp) {
                pdata->np[i] = pp;
 
                /* Read base-addr and size from DT */
index 0f1547f..72f5c7b 100644 (file)
@@ -393,6 +393,17 @@ static int lpddr2_nvm_lock(struct mtd_info *mtd, loff_t start_add,
        return lpddr2_nvm_do_block_op(mtd, start_add, len, LPDDR2_NVM_LOCK);
 }
 
+static const struct mtd_info lpddr2_nvm_mtd_info = {
+       .type           = MTD_RAM,
+       .writesize      = 1,
+       .flags          = (MTD_CAP_NVRAM | MTD_POWERUP_LOCK),
+       ._read          = lpddr2_nvm_read,
+       ._write         = lpddr2_nvm_write,
+       ._erase         = lpddr2_nvm_erase,
+       ._unlock        = lpddr2_nvm_unlock,
+       ._lock          = lpddr2_nvm_lock,
+};
+
 /*
  * lpddr2_nvm driver probe method
  */
@@ -433,6 +444,7 @@ static int lpddr2_nvm_probe(struct platform_device *pdev)
                .pfow_base      = OW_BASE_ADDRESS,
                .fldrv_priv     = pcm_data,
        };
+
        if (IS_ERR(map->virt))
                return PTR_ERR(map->virt);
 
@@ -444,22 +456,13 @@ static int lpddr2_nvm_probe(struct platform_device *pdev)
                return PTR_ERR(pcm_data->ctl_regs);
 
        /* Populate mtd_info data structure */
-       *mtd = (struct mtd_info) {
-               .dev            = { .parent = &pdev->dev },
-               .name           = pdev->dev.init_name,
-               .type           = MTD_RAM,
-               .priv           = map,
-               .size           = resource_size(add_range),
-               .erasesize      = ERASE_BLOCKSIZE * pcm_data->bus_width,
-               .writesize      = 1,
-               .writebufsize   = WRITE_BUFFSIZE * pcm_data->bus_width,
-               .flags          = (MTD_CAP_NVRAM | MTD_POWERUP_LOCK),
-               ._read          = lpddr2_nvm_read,
-               ._write         = lpddr2_nvm_write,
-               ._erase         = lpddr2_nvm_erase,
-               ._unlock        = lpddr2_nvm_unlock,
-               ._lock          = lpddr2_nvm_lock,
-       };
+       *mtd = lpddr2_nvm_mtd_info;
+       mtd->dev.parent         = &pdev->dev;
+       mtd->name               = pdev->dev.init_name;
+       mtd->priv               = map;
+       mtd->size               = resource_size(add_range);
+       mtd->erasesize          = ERASE_BLOCKSIZE * pcm_data->bus_width;
+       mtd->writebufsize       = WRITE_BUFFSIZE * pcm_data->bus_width;
 
        /* Verify the presence of the device looking for PFOW string */
        if (!lpddr2_nvm_pfow_present(map)) {
index fb1cbc9..ee063ba 100644 (file)
@@ -94,6 +94,34 @@ struct mtd_info *lpddr_cmdset(struct map_info *map)
 }
 EXPORT_SYMBOL(lpddr_cmdset);
 
+static void print_drs_error(unsigned int dsr)
+{
+       int prog_status = (dsr & DSR_RPS) >> 8;
+
+       if (!(dsr & DSR_AVAILABLE))
+               pr_notice("DSR.15: (0) Device not Available\n");
+       if ((prog_status & 0x03) == 0x03)
+               pr_notice("DSR.9,8: (11) Attempt to program invalid half with 41h command\n");
+       else if (prog_status & 0x02)
+               pr_notice("DSR.9,8: (10) Object Mode Program attempt in region with Control Mode data\n");
+       else if (prog_status &  0x01)
+               pr_notice("DSR.9,8: (01) Program attempt in region with Object Mode data\n");
+       if (!(dsr & DSR_READY_STATUS))
+               pr_notice("DSR.7: (0) Device is Busy\n");
+       if (dsr & DSR_ESS)
+               pr_notice("DSR.6: (1) Erase Suspended\n");
+       if (dsr & DSR_ERASE_STATUS)
+               pr_notice("DSR.5: (1) Erase/Blank check error\n");
+       if (dsr & DSR_PROGRAM_STATUS)
+               pr_notice("DSR.4: (1) Program Error\n");
+       if (dsr & DSR_VPPS)
+               pr_notice("DSR.3: (1) Vpp low detect, operation aborted\n");
+       if (dsr & DSR_PSS)
+               pr_notice("DSR.2: (1) Program suspended\n");
+       if (dsr & DSR_DPS)
+               pr_notice("DSR.1: (1) Aborted Erase/Program attempt on locked block\n");
+}
+
 static int wait_for_ready(struct map_info *map, struct flchip *chip,
                unsigned int chip_op_time)
 {
index fd37553..6650acb 100644 (file)
@@ -75,6 +75,17 @@ config MTD_PHYSMAP_OF
          physically into the CPU's memory. The mapping description here is
          taken from OF device tree.
 
+config MTD_PHYSMAP_BT1_ROM
+       bool "Baikal-T1 Boot ROMs OF-based physical memory map handling"
+       depends on MTD_PHYSMAP_OF
+       depends on MIPS_BAIKAL_T1 || COMPILE_TEST
+       select MTD_COMPLEX_MAPPINGS
+       select MULTIPLEXER
+       select MUX_MMIO
+       help
+         This provides some extra DT physmap parsing for the Baikal-T1
+         platforms, some detection and setting up ROMs-specific accessors.
+
 config MTD_PHYSMAP_VERSATILE
        bool "ARM Versatile OF-based physical memory map handling"
        depends on MTD_PHYSMAP_OF
index c0da86a..79f018c 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_MTD_CK804XROM)   += ck804xrom.o
 obj-$(CONFIG_MTD_TSUNAMI)      += tsunami_flash.o
 obj-$(CONFIG_MTD_PXA2XX)       += pxa2xx-flash.o
 physmap-objs-y                 += physmap-core.o
+physmap-objs-$(CONFIG_MTD_PHYSMAP_BT1_ROM) += physmap-bt1-rom.o
 physmap-objs-$(CONFIG_MTD_PHYSMAP_VERSATILE) += physmap-versatile.o
 physmap-objs-$(CONFIG_MTD_PHYSMAP_GEMINI) += physmap-gemini.o
 physmap-objs-$(CONFIG_MTD_PHYSMAP_IXP4XX) += physmap-ixp4xx.o
diff --git a/drivers/mtd/maps/physmap-bt1-rom.c b/drivers/mtd/maps/physmap-bt1-rom.c
new file mode 100644 (file)
index 0000000..27cfe1c
--- /dev/null
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
+ *
+ * Authors:
+ *   Serge Semin <Sergey.Semin@baikalelectronics.ru>
+ *
+ * Baikal-T1 Physically Mapped Internal ROM driver
+ */
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/xip.h>
+#include <linux/mux/consumer.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "physmap-bt1-rom.h"
+
+/*
+ * Baikal-T1 SoC ROMs are only accessible by the dword-aligned instructions.
+ * We have to take this into account when implementing the data read-methods.
+ * Note there is no need in bothering with endianness, since both Baikal-T1
+ * CPU and MMIO are LE.
+ */
+static map_word __xipram bt1_rom_map_read(struct map_info *map,
+                                         unsigned long ofs)
+{
+       void __iomem *src = map->virt + ofs;
+       unsigned long shift;
+       map_word ret;
+       u32 data;
+
+       /* Read data within offset dword. */
+       shift = (unsigned long)src & 0x3;
+       data = readl_relaxed(src - shift);
+       if (!shift) {
+               ret.x[0] = data;
+               return ret;
+       }
+       ret.x[0] = data >> (shift * BITS_PER_BYTE);
+
+       /* Read data from the next dword. */
+       shift = 4 - shift;
+       if (ofs + shift >= map->size)
+               return ret;
+
+       data = readl_relaxed(src + shift);
+       ret.x[0] |= data << (shift * BITS_PER_BYTE);
+
+       return ret;
+}
+
+static void __xipram bt1_rom_map_copy_from(struct map_info *map,
+                                          void *to, unsigned long from,
+                                          ssize_t len)
+{
+       void __iomem *src = map->virt + from;
+       ssize_t shift, chunk;
+       u32 data;
+
+       if (len <= 0 || from >= map->size)
+               return;
+
+       /* Make sure we don't go over the map limit. */
+       len = min_t(ssize_t, map->size - from, len);
+
+       /*
+        * Since requested data size can be pretty big we have to implement
+        * the copy procedure as optimal as possible. That's why it's split
+        * up into the next three stages: unaligned head, aligned body,
+        * unaligned tail.
+        */
+       shift = (ssize_t)src & 0x3;
+       if (shift) {
+               chunk = min_t(ssize_t, 4 - shift, len);
+               data = readl_relaxed(src - shift);
+               memcpy(to, &data + shift, chunk);
+               src += chunk;
+               to += chunk;
+               len -= chunk;
+       }
+
+       while (len >= 4) {
+               data = readl_relaxed(src);
+               memcpy(to, &data, 4);
+               src += 4;
+               to += 4;
+               len -= 4;
+       }
+
+       if (len) {
+               data = readl_relaxed(src);
+               memcpy(to, &data, len);
+       }
+}
+
+int of_flash_probe_bt1_rom(struct platform_device *pdev,
+                          struct device_node *np,
+                          struct map_info *map)
+{
+       struct device *dev = &pdev->dev;
+
+       /* It's supposed to be read-only MTD. */
+       if (!of_device_is_compatible(np, "mtd-rom")) {
+               dev_info(dev, "No mtd-rom compatible string\n");
+               return 0;
+       }
+
+       /* Multiplatform guard. */
+       if (!of_device_is_compatible(np, "baikal,bt1-int-rom"))
+               return 0;
+
+       /* Sanity check the device parameters retrieved from DTB. */
+       if (map->bankwidth != 4)
+               dev_warn(dev, "Bank width is supposed to be 32 bits wide\n");
+
+       map->read = bt1_rom_map_read;
+       map->copy_from = bt1_rom_map_copy_from;
+
+       return 0;
+}
diff --git a/drivers/mtd/maps/physmap-bt1-rom.h b/drivers/mtd/maps/physmap-bt1-rom.h
new file mode 100644 (file)
index 0000000..6782899
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <linux/mtd/map.h>
+#include <linux/of.h>
+
+#ifdef CONFIG_MTD_PHYSMAP_BT1_ROM
+int of_flash_probe_bt1_rom(struct platform_device *pdev,
+                          struct device_node *np,
+                          struct map_info *map);
+#else
+static inline
+int of_flash_probe_bt1_rom(struct platform_device *pdev,
+                          struct device_node *np,
+                          struct map_info *map)
+{
+       return 0;
+}
+#endif
index 8f7f966..001ed5d 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/gpio/consumer.h>
 
+#include "physmap-bt1-rom.h"
 #include "physmap-gemini.h"
 #include "physmap-ixp4xx.h"
 #include "physmap-versatile.h"
@@ -371,6 +372,10 @@ static int physmap_flash_of_init(struct platform_device *dev)
                info->maps[i].bankwidth = bankwidth;
                info->maps[i].device_node = dp;
 
+               err = of_flash_probe_bt1_rom(dev, dp, &info->maps[i]);
+               if (err)
+                       return err;
+
                err = of_flash_probe_gemini(dev, dp, &info->maps[i]);
                if (err)
                        return err;
@@ -515,7 +520,8 @@ static int physmap_flash_probe(struct platform_device *dev)
                dev_notice(&dev->dev, "physmap platform flash device: %pR\n",
                           res);
 
-               info->maps[i].name = dev_name(&dev->dev);
+               if (!info->maps[i].name)
+                       info->maps[i].name = dev_name(&dev->dev);
 
                if (!info->maps[i].phys)
                        info->maps[i].phys = res->start;
index 177bf13..a7ec947 100644 (file)
@@ -40,7 +40,7 @@ struct memcard {
        u32 blocklen;
        u32 writecnt;
        u32 readcnt;
-       u32 removeable;
+       u32 removable;
        int partition;
        int read;
        unsigned char *blockread;
@@ -619,7 +619,7 @@ static int vmu_connect(struct maple_device *mdev)
        card->blocklen = ((basic_flash_data >> 16 & 0xFF) + 1) << 5;
        card->writecnt = basic_flash_data >> 12 & 0xF;
        card->readcnt = basic_flash_data >> 8 & 0xF;
-       card->removeable = basic_flash_data >> 7 & 1;
+       card->removable = basic_flash_data >> 7 & 1;
 
        card->partition = 0;
 
@@ -772,7 +772,6 @@ static void vmu_file_error(struct maple_device *mdev, void *recvbuf)
 
 static int probe_maple_vmu(struct device *dev)
 {
-       int error;
        struct maple_device *mdev = to_maple_dev(dev);
        struct maple_driver *mdrv = to_maple_driver(dev->driver);
 
@@ -780,11 +779,7 @@ static int probe_maple_vmu(struct device *dev)
        mdev->fileerr_handler = vmu_file_error;
        mdev->driver = mdrv;
 
-       error = vmu_connect(mdev);
-       if (error)
-               return error;
-
-       return 0;
+       return vmu_connect(mdev);
 }
 
 static int remove_maple_vmu(struct device *dev)
index 1d6c9e7..6e4d001 100644 (file)
@@ -102,6 +102,47 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
        return -EINVAL;
 }
 
+static int
+concat_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
+            size_t * retlen, const u_char * buf)
+{
+       struct mtd_concat *concat = CONCAT(mtd);
+       int err = -EINVAL;
+       int i;
+       for (i = 0; i < concat->num_subdev; i++) {
+               struct mtd_info *subdev = concat->subdev[i];
+               size_t size, retsize;
+
+               if (to >= subdev->size) {
+                       to -= subdev->size;
+                       continue;
+               }
+               if (to + len > subdev->size)
+                       size = subdev->size - to;
+               else
+                       size = len;
+
+               err = mtd_panic_write(subdev, to, size, &retsize, buf);
+               if (err == -EOPNOTSUPP) {
+                       printk(KERN_ERR "mtdconcat: Cannot write from panic without panic_write\n");
+                       return err;
+               }
+               if (err)
+                       break;
+
+               *retlen += retsize;
+               len -= size;
+               if (len == 0)
+                       break;
+
+               err = -EINVAL;
+               buf += size;
+               to = 0;
+       }
+       return err;
+}
+
+
 static int
 concat_write(struct mtd_info *mtd, loff_t to, size_t len,
             size_t * retlen, const u_char * buf)
@@ -648,6 +689,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],       /* subdevices to c
                concat->mtd._block_isbad = concat_block_isbad;
        if (subdev[0]->_block_markbad)
                concat->mtd._block_markbad = concat_block_markbad;
+       if (subdev[0]->_panic_write)
+               concat->mtd._panic_write = concat_panic_write;
 
        concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
 
index 7d93056..a88fe9f 100644 (file)
@@ -335,7 +335,7 @@ static const struct device_type mtd_devtype = {
        .release        = mtd_release,
 };
 
-static int mtd_partid_show(struct seq_file *s, void *p)
+static int mtd_partid_debug_show(struct seq_file *s, void *p)
 {
        struct mtd_info *mtd = s->private;
 
@@ -344,19 +344,9 @@ static int mtd_partid_show(struct seq_file *s, void *p)
        return 0;
 }
 
-static int mtd_partid_debugfs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, mtd_partid_show, inode->i_private);
-}
-
-static const struct file_operations mtd_partid_debug_fops = {
-       .open           = mtd_partid_debugfs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mtd_partid_debug);
 
-static int mtd_partname_show(struct seq_file *s, void *p)
+static int mtd_partname_debug_show(struct seq_file *s, void *p)
 {
        struct mtd_info *mtd = s->private;
 
@@ -365,17 +355,7 @@ static int mtd_partname_show(struct seq_file *s, void *p)
        return 0;
 }
 
-static int mtd_partname_debugfs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, mtd_partname_show, inode->i_private);
-}
-
-static const struct file_operations mtd_partname_debug_fops = {
-       .open           = mtd_partname_debugfs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mtd_partname_debug);
 
 static struct dentry *dfs_dir_mtd;
 
index 4ced68b..774970b 100644 (file)
@@ -279,12 +279,13 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper,
        kmsg_dump_get_buffer(dumper, true, cxt->oops_buf + MTDOOPS_HEADER_SIZE,
                             record_size - MTDOOPS_HEADER_SIZE, NULL);
 
-       /* Panics must be written immediately */
-       if (reason != KMSG_DUMP_OOPS)
+       if (reason != KMSG_DUMP_OOPS) {
+               /* Panics must be written immediately */
                mtdoops_write(cxt, 1);
-
-       /* For other cases, schedule work to write it "nicely" */
-       schedule_work(&cxt->work_write);
+       } else {
+               /* For other cases, schedule work to write it "nicely" */
+               schedule_work(&cxt->work_write);
+       }
 }
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
index c1a45b0..4a9aed4 100644 (file)
@@ -9,4 +9,12 @@ source "drivers/mtd/nand/onenand/Kconfig"
 source "drivers/mtd/nand/raw/Kconfig"
 source "drivers/mtd/nand/spi/Kconfig"
 
+menu "ECC engine support"
+
+config MTD_NAND_ECC
+       bool
+       depends on MTD_NAND_CORE
+
+endmenu
+
 endmenu
index 7ecd80c..9813729 100644 (file)
@@ -6,3 +6,5 @@ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
 obj-y  += onenand/
 obj-y  += raw/
 obj-y  += spi/
+
+nandcore-$(CONFIG_MTD_NAND_ECC) += ecc.o
diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
new file mode 100644 (file)
index 0000000..4a56e6c
--- /dev/null
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Generic Error-Correcting Code (ECC) engine
+ *
+ * Copyright (C) 2019 Macronix
+ * Author:
+ *     Miquèl RAYNAL <miquel.raynal@bootlin.com>
+ *
+ *
+ * This file describes the abstraction of any NAND ECC engine. It has been
+ * designed to fit most cases, including parallel NANDs and SPI-NANDs.
+ *
+ * There are three main situations where instantiating this ECC engine makes
+ * sense:
+ *   - external: The ECC engine is outside the NAND pipeline, typically this
+ *               is a software ECC engine, or an hardware engine that is
+ *               outside the NAND controller pipeline.
+ *   - pipelined: The ECC engine is inside the NAND pipeline, ie. on the
+ *                controller's side. This is the case of most of the raw NAND
+ *                controllers. In the pipeline case, the ECC bytes are
+ *                generated/data corrected on the fly when a page is
+ *                written/read.
+ *   - ondie: The ECC engine is inside the NAND pipeline, on the chip's side.
+ *            Some NAND chips can correct themselves the data.
+ *
+ * Besides the initial setup and final cleanups, the interfaces are rather
+ * simple:
+ *   - prepare: Prepare an I/O request. Enable/disable the ECC engine based on
+ *              the I/O request type. In case of software correction or external
+ *              engine, this step may involve to derive the ECC bytes and place
+ *              them in the OOB area before a write.
+ *   - finish: Finish an I/O request. Correct the data in case of a read
+ *             request and report the number of corrected bits/uncorrectable
+ *             errors. Most likely empty for write operations, unless you have
+ *             hardware specific stuff to do, like shutting down the engine to
+ *             save power.
+ *
+ * The I/O request should be enclosed in a prepare()/finish() pair of calls
+ * and will behave differently depending on the requested I/O type:
+ *   - raw: Correction disabled
+ *   - ecc: Correction enabled
+ *
+ * The request direction is impacting the logic as well:
+ *   - read: Load data from the NAND chip
+ *   - write: Store data in the NAND chip
+ *
+ * Mixing all this combinations together gives the following behavior.
+ * Those are just examples, drivers are free to add custom steps in their
+ * prepare/finish hook.
+ *
+ * [external ECC engine]
+ *   - external + prepare + raw + read: do nothing
+ *   - external + finish  + raw + read: do nothing
+ *   - external + prepare + raw + write: do nothing
+ *   - external + finish  + raw + write: do nothing
+ *   - external + prepare + ecc + read: do nothing
+ *   - external + finish  + ecc + read: calculate expected ECC bytes, extract
+ *                                      ECC bytes from OOB buffer, correct
+ *                                      and report any bitflip/error
+ *   - external + prepare + ecc + write: calculate ECC bytes and store them at
+ *                                       the right place in the OOB buffer based
+ *                                       on the OOB layout
+ *   - external + finish  + ecc + write: do nothing
+ *
+ * [pipelined ECC engine]
+ *   - pipelined + prepare + raw + read: disable the controller's ECC engine if
+ *                                       activated
+ *   - pipelined + finish  + raw + read: do nothing
+ *   - pipelined + prepare + raw + write: disable the controller's ECC engine if
+ *                                        activated
+ *   - pipelined + finish  + raw + write: do nothing
+ *   - pipelined + prepare + ecc + read: enable the controller's ECC engine if
+ *                                       deactivated
+ *   - pipelined + finish  + ecc + read: check the status, report any
+ *                                       error/bitflip
+ *   - pipelined + prepare + ecc + write: enable the controller's ECC engine if
+ *                                        deactivated
+ *   - pipelined + finish  + ecc + write: do nothing
+ *
+ * [ondie ECC engine]
+ *   - ondie + prepare + raw + read: send commands to disable the on-chip ECC
+ *                                   engine if activated
+ *   - ondie + finish  + raw + read: do nothing
+ *   - ondie + prepare + raw + write: send commands to disable the on-chip ECC
+ *                                    engine if activated
+ *   - ondie + finish  + raw + write: do nothing
+ *   - ondie + prepare + ecc + read: send commands to enable the on-chip ECC
+ *                                   engine if deactivated
+ *   - ondie + finish  + ecc + read: send commands to check the status, report
+ *                                   any error/bitflip
+ *   - ondie + prepare + ecc + write: send commands to enable the on-chip ECC
+ *                                    engine if deactivated
+ *   - ondie + finish  + ecc + write: do nothing
+ */
+
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+
+/**
+ * nand_ecc_init_ctx - Init the ECC engine context
+ * @nand: the NAND device
+ *
+ * On success, the caller is responsible of calling @nand_ecc_cleanup_ctx().
+ */
+int nand_ecc_init_ctx(struct nand_device *nand)
+{
+       if (!nand->ecc.engine->ops->init_ctx)
+               return 0;
+
+       return nand->ecc.engine->ops->init_ctx(nand);
+}
+EXPORT_SYMBOL(nand_ecc_init_ctx);
+
+/**
+ * nand_ecc_cleanup_ctx - Cleanup the ECC engine context
+ * @nand: the NAND device
+ */
+void nand_ecc_cleanup_ctx(struct nand_device *nand)
+{
+       if (nand->ecc.engine->ops->cleanup_ctx)
+               nand->ecc.engine->ops->cleanup_ctx(nand);
+}
+EXPORT_SYMBOL(nand_ecc_cleanup_ctx);
+
+/**
+ * nand_ecc_prepare_io_req - Prepare an I/O request
+ * @nand: the NAND device
+ * @req: the I/O request
+ */
+int nand_ecc_prepare_io_req(struct nand_device *nand,
+                           struct nand_page_io_req *req)
+{
+       if (!nand->ecc.engine->ops->prepare_io_req)
+               return 0;
+
+       return nand->ecc.engine->ops->prepare_io_req(nand, req);
+}
+EXPORT_SYMBOL(nand_ecc_prepare_io_req);
+
+/**
+ * nand_ecc_finish_io_req - Finish an I/O request
+ * @nand: the NAND device
+ * @req: the I/O request
+ */
+int nand_ecc_finish_io_req(struct nand_device *nand,
+                          struct nand_page_io_req *req)
+{
+       if (!nand->ecc.engine->ops->finish_io_req)
+               return 0;
+
+       return nand->ecc.engine->ops->finish_io_req(nand, req);
+}
+EXPORT_SYMBOL(nand_ecc_finish_io_req);
+
+/* Define default OOB placement schemes for large and small page devices */
+static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
+                                struct mtd_oob_region *oobregion)
+{
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+       unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+
+       if (section > 1)
+               return -ERANGE;
+
+       if (!section) {
+               oobregion->offset = 0;
+               if (mtd->oobsize == 16)
+                       oobregion->length = 4;
+               else
+                       oobregion->length = 3;
+       } else {
+               if (mtd->oobsize == 8)
+                       return -ERANGE;
+
+               oobregion->offset = 6;
+               oobregion->length = total_ecc_bytes - 4;
+       }
+
+       return 0;
+}
+
+static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *oobregion)
+{
+       if (section > 1)
+               return -ERANGE;
+
+       if (mtd->oobsize == 16) {
+               if (section)
+                       return -ERANGE;
+
+               oobregion->length = 8;
+               oobregion->offset = 8;
+       } else {
+               oobregion->length = 2;
+               if (!section)
+                       oobregion->offset = 3;
+               else
+                       oobregion->offset = 6;
+       }
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
+       .ecc = nand_ooblayout_ecc_sp,
+       .free = nand_ooblayout_free_sp,
+};
+
+const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void)
+{
+       return &nand_ooblayout_sp_ops;
+}
+EXPORT_SYMBOL_GPL(nand_get_small_page_ooblayout);
+
+static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
+                                struct mtd_oob_region *oobregion)
+{
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+       unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+
+       if (section || !total_ecc_bytes)
+               return -ERANGE;
+
+       oobregion->length = total_ecc_bytes;
+       oobregion->offset = mtd->oobsize - oobregion->length;
+
+       return 0;
+}
+
+static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *oobregion)
+{
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+       unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+
+       if (section)
+               return -ERANGE;
+
+       oobregion->length = mtd->oobsize - total_ecc_bytes - 2;
+       oobregion->offset = 2;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
+       .ecc = nand_ooblayout_ecc_lp,
+       .free = nand_ooblayout_free_lp,
+};
+
+const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void)
+{
+       return &nand_ooblayout_lp_ops;
+}
+EXPORT_SYMBOL_GPL(nand_get_large_page_ooblayout);
+
+/*
+ * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
+ * are placed at a fixed offset.
+ */
+static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
+                                        struct mtd_oob_region *oobregion)
+{
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+       unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+
+       if (section)
+               return -ERANGE;
+
+       switch (mtd->oobsize) {
+       case 64:
+               oobregion->offset = 40;
+               break;
+       case 128:
+               oobregion->offset = 80;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       oobregion->length = total_ecc_bytes;
+       if (oobregion->offset + oobregion->length > mtd->oobsize)
+               return -ERANGE;
+
+       return 0;
+}
+
+static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
+                                         struct mtd_oob_region *oobregion)
+{
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+       unsigned int total_ecc_bytes = nand->ecc.ctx.total;
+       int ecc_offset = 0;
+
+       if (section < 0 || section > 1)
+               return -ERANGE;
+
+       switch (mtd->oobsize) {
+       case 64:
+               ecc_offset = 40;
+               break;
+       case 128:
+               ecc_offset = 80;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (section == 0) {
+               oobregion->offset = 2;
+               oobregion->length = ecc_offset - 2;
+       } else {
+               oobregion->offset = ecc_offset + total_ecc_bytes;
+               oobregion->length = mtd->oobsize - oobregion->offset;
+       }
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
+       .ecc = nand_ooblayout_ecc_lp_hamming,
+       .free = nand_ooblayout_free_lp_hamming,
+};
+
+const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void)
+{
+       return &nand_ooblayout_lp_hamming_ops;
+}
+EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_ooblayout);
+
+static enum nand_ecc_engine_type
+of_get_nand_ecc_engine_type(struct device_node *np)
+{
+       struct device_node *eng_np;
+
+       if (of_property_read_bool(np, "nand-no-ecc-engine"))
+               return NAND_ECC_ENGINE_TYPE_NONE;
+
+       if (of_property_read_bool(np, "nand-use-soft-ecc-engine"))
+               return NAND_ECC_ENGINE_TYPE_SOFT;
+
+       eng_np = of_parse_phandle(np, "nand-ecc-engine", 0);
+       of_node_put(eng_np);
+
+       if (eng_np) {
+               if (eng_np == np)
+                       return NAND_ECC_ENGINE_TYPE_ON_DIE;
+               else
+                       return NAND_ECC_ENGINE_TYPE_ON_HOST;
+       }
+
+       return NAND_ECC_ENGINE_TYPE_INVALID;
+}
+
+static const char * const nand_ecc_placement[] = {
+       [NAND_ECC_PLACEMENT_OOB] = "oob",
+       [NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
+};
+
+static enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
+{
+       enum nand_ecc_placement placement;
+       const char *pm;
+       int err;
+
+       err = of_property_read_string(np, "nand-ecc-placement", &pm);
+       if (!err) {
+               for (placement = NAND_ECC_PLACEMENT_OOB;
+                    placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
+                       if (!strcasecmp(pm, nand_ecc_placement[placement]))
+                               return placement;
+               }
+       }
+
+       return NAND_ECC_PLACEMENT_UNKNOWN;
+}
+
+static const char * const nand_ecc_algos[] = {
+       [NAND_ECC_ALGO_HAMMING] = "hamming",
+       [NAND_ECC_ALGO_BCH] = "bch",
+       [NAND_ECC_ALGO_RS] = "rs",
+};
+
+static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
+{
+       enum nand_ecc_algo ecc_algo;
+       const char *pm;
+       int err;
+
+       err = of_property_read_string(np, "nand-ecc-algo", &pm);
+       if (!err) {
+               for (ecc_algo = NAND_ECC_ALGO_HAMMING;
+                    ecc_algo < ARRAY_SIZE(nand_ecc_algos);
+                    ecc_algo++) {
+                       if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
+                               return ecc_algo;
+               }
+       }
+
+       return NAND_ECC_ALGO_UNKNOWN;
+}
+
+static int of_get_nand_ecc_step_size(struct device_node *np)
+{
+       int ret;
+       u32 val;
+
+       ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
+       return ret ? ret : val;
+}
+
+static int of_get_nand_ecc_strength(struct device_node *np)
+{
+       int ret;
+       u32 val;
+
+       ret = of_property_read_u32(np, "nand-ecc-strength", &val);
+       return ret ? ret : val;
+}
+
+void of_get_nand_ecc_user_config(struct nand_device *nand)
+{
+       struct device_node *dn = nanddev_get_of_node(nand);
+       int strength, size;
+
+       nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
+       nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
+       nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
+
+       strength = of_get_nand_ecc_strength(dn);
+       if (strength >= 0)
+               nand->ecc.user_conf.strength = strength;
+
+       size = of_get_nand_ecc_step_size(dn);
+       if (size >= 0)
+               nand->ecc.user_conf.step_size = size;
+
+       if (of_property_read_bool(dn, "nand-ecc-maximize"))
+               nand->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE_STRENGTH;
+}
+EXPORT_SYMBOL(of_get_nand_ecc_user_config);
+
+/**
+ * nand_ecc_is_strong_enough - Check if the chip configuration meets the
+ *                             datasheet requirements.
+ *
+ * @nand: Device to check
+ *
+ * If our configuration corrects A bits per B bytes and the minimum
+ * required correction level is X bits per Y bytes, then we must ensure
+ * both of the following are true:
+ *
+ * (1) A / B >= X / Y
+ * (2) A >= X
+ *
+ * Requirement (1) ensures we can correct for the required bitflip density.
+ * Requirement (2) ensures we can correct even when all bitflips are clumped
+ * in the same sector.
+ */
+bool nand_ecc_is_strong_enough(struct nand_device *nand)
+{
+       const struct nand_ecc_props *reqs = nanddev_get_ecc_requirements(nand);
+       const struct nand_ecc_props *conf = nanddev_get_ecc_conf(nand);
+       struct mtd_info *mtd = nanddev_to_mtd(nand);
+       int corr, ds_corr;
+
+       if (conf->step_size == 0 || reqs->step_size == 0)
+               /* Not enough information */
+               return true;
+
+       /*
+        * We get the number of corrected bits per page to compare
+        * the correction density.
+        */
+       corr = (mtd->writesize * conf->strength) / conf->step_size;
+       ds_corr = (mtd->writesize * reqs->strength) / reqs->step_size;
+
+       return corr >= ds_corr && conf->strength >= reqs->strength;
+}
+EXPORT_SYMBOL(nand_ecc_is_strong_enough);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
+MODULE_DESCRIPTION("Generic ECC engine");
index ec18ade..188b806 100644 (file)
@@ -1052,16 +1052,11 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
                                int thislen)
 {
        struct onenand_chip *this = mtd->priv;
-       int ret;
 
        this->read_bufferram(mtd, ONENAND_SPARERAM, this->oob_buf, 0,
                             mtd->oobsize);
-       ret = mtd_ooblayout_get_databytes(mtd, buf, this->oob_buf,
-                                         column, thislen);
-       if (ret)
-               return ret;
-
-       return 0;
+       return mtd_ooblayout_get_databytes(mtd, buf, this->oob_buf,
+                                          column, thislen);
 }
 
 /**
index aa9368b..d8c0bd0 100644 (file)
@@ -494,11 +494,8 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 
        c->int_gpiod = devm_gpiod_get_optional(dev, "int", GPIOD_IN);
        if (IS_ERR(c->int_gpiod)) {
-               r = PTR_ERR(c->int_gpiod);
                /* Just try again if this happens */
-               if (r != -EPROBE_DEFER)
-                       dev_err(dev, "error getting gpio: %d\n", r);
-               return r;
+               return dev_err_probe(dev, PTR_ERR(c->int_gpiod), "error getting gpio\n");
        }
 
        if (c->int_gpiod) {
index 1203775..6c46f25 100644 (file)
@@ -13,6 +13,7 @@ config MTD_NAND_ECC_SW_HAMMING_SMC
 menuconfig MTD_RAW_NAND
        tristate "Raw/Parallel NAND Device Support"
        select MTD_NAND_CORE
+       select MTD_NAND_ECC
        select MTD_NAND_ECC_SW_HAMMING
        help
          This enables support for accessing all type of raw/parallel
index fdba155..d3c5cc5 100644 (file)
@@ -260,8 +260,8 @@ static int gpio_nand_probe(struct platform_device *pdev)
                return err;
        }
 
-       this->ecc.mode = NAND_ECC_SOFT;
-       this->ecc.algo = NAND_ECC_HAMMING;
+       this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       this->ecc.algo = NAND_ECC_ALGO_HAMMING;
 
        platform_set_drvdata(pdev, priv);
 
@@ -400,12 +400,14 @@ static int gpio_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id gpio_nand_of_id_table[] = {
        {
                /* sentinel */
        },
 };
 MODULE_DEVICE_TABLE(of, gpio_nand_of_id_table);
+#endif
 
 static const struct platform_device_id gpio_nand_plat_id_table[] = {
        {
index 12c643e..fbb4ea7 100644 (file)
@@ -980,10 +980,10 @@ static int anfc_init_hw_ecc_controller(struct arasan_nfc *nfc,
                return -EINVAL;
        }
 
-       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+       mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
 
        ecc->steps = mtd->writesize / ecc->size;
-       ecc->algo = NAND_ECC_BCH;
+       ecc->algo = NAND_ECC_ALGO_BCH;
        anand->ecc_bits = bch_gf_mag * ecc->strength;
        ecc->bytes = DIV_ROUND_UP(anand->ecc_bits, 8);
        anand->ecc_total = DIV_ROUND_UP(anand->ecc_bits * ecc->steps, 8);
@@ -1056,17 +1056,17 @@ static int anfc_attach_chip(struct nand_chip *chip)
        chip->ecc.read_page_raw = nand_monolithic_read_page_raw;
        chip->ecc.write_page_raw = nand_monolithic_write_page_raw;
 
-       switch (chip->ecc.mode) {
-       case NAND_ECC_NONE:
-       case NAND_ECC_SOFT:
-       case NAND_ECC_ON_DIE:
+       switch (chip->ecc.engine_type) {
+       case NAND_ECC_ENGINE_TYPE_NONE:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
+       case NAND_ECC_ENGINE_TYPE_ON_DIE:
                break;
-       case NAND_ECC_HW:
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                ret = anfc_init_hw_ecc_controller(nfc, chip);
                break;
        default:
                dev_err(nfc->dev, "Unsupported ECC mode: %d\n",
-                       chip->ecc.mode);
+                       chip->ecc.engine_type);
                return -EINVAL;
        }
 
index c9818f5..e6ceec8 100644 (file)
@@ -202,6 +202,8 @@ struct atmel_nand_controller_ops {
        int (*ecc_init)(struct nand_chip *chip);
        int (*setup_interface)(struct atmel_nand *nand, int csline,
                               const struct nand_interface_config *conf);
+       int (*exec_op)(struct atmel_nand *nand,
+                      const struct nand_operation *op, bool check_only);
 };
 
 struct atmel_nand_controller_caps {
@@ -259,6 +261,7 @@ struct atmel_hsmc_nand_controller {
        struct regmap *io;
        struct atmel_nfc_op op;
        struct completion complete;
+       u32 cfg;
        int irq;
 
        /* Only used when instantiating from legacy DT bindings. */
@@ -414,29 +417,62 @@ err:
        return -EIO;
 }
 
-static u8 atmel_nand_read_byte(struct nand_chip *chip)
+static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
 {
-       struct atmel_nand *nand = to_atmel_nand(chip);
+       u8 *addrs = nc->op.addrs;
+       unsigned int op = 0;
+       u32 addr, val;
+       int i, ret;
 
-       return ioread8(nand->activecs->io.virt);
-}
+       nc->op.wait = ATMEL_HSMC_NFC_SR_CMDDONE;
 
-static void atmel_nand_write_byte(struct nand_chip *chip, u8 byte)
-{
-       struct atmel_nand *nand = to_atmel_nand(chip);
+       for (i = 0; i < nc->op.ncmds; i++)
+               op |= ATMEL_NFC_CMD(i, nc->op.cmds[i]);
 
-       if (chip->options & NAND_BUSWIDTH_16)
-               iowrite16(byte | (byte << 8), nand->activecs->io.virt);
-       else
-               iowrite8(byte, nand->activecs->io.virt);
+       if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
+               regmap_write(nc->base.smc, ATMEL_HSMC_NFC_ADDR, *addrs++);
+
+       op |= ATMEL_NFC_CSID(nc->op.cs) |
+             ATMEL_NFC_ACYCLE(nc->op.naddrs);
+
+       if (nc->op.ncmds > 1)
+               op |= ATMEL_NFC_VCMD2;
+
+       addr = addrs[0] | (addrs[1] << 8) | (addrs[2] << 16) |
+              (addrs[3] << 24);
+
+       if (nc->op.data != ATMEL_NFC_NO_DATA) {
+               op |= ATMEL_NFC_DATAEN;
+               nc->op.wait |= ATMEL_HSMC_NFC_SR_XFRDONE;
+
+               if (nc->op.data == ATMEL_NFC_WRITE_DATA)
+                       op |= ATMEL_NFC_NFCWR;
+       }
+
+       /* Clear all flags. */
+       regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &val);
+
+       /* Send the command. */
+       regmap_write(nc->io, op, addr);
+
+       ret = atmel_nfc_wait(nc, poll, 0);
+       if (ret)
+               dev_err(nc->base.dev,
+                       "Failed to send NAND command (err = %d)!",
+                       ret);
+
+       /* Reset the op state. */
+       memset(&nc->op, 0, sizeof(nc->op));
+
+       return ret;
 }
 
-static void atmel_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
+static void atmel_nand_data_in(struct atmel_nand *nand, void *buf,
+                              unsigned int len, bool force_8bit)
 {
-       struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_nand_controller *nc;
 
-       nc = to_nand_controller(chip->controller);
+       nc = to_nand_controller(nand->base.controller);
 
        /*
         * If the controller supports DMA, the buffer address is DMA-able and
@@ -444,23 +480,23 @@ static void atmel_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
         * a DMA transfer. If it fails, fallback to PIO mode.
         */
        if (nc->dmac && virt_addr_valid(buf) &&
-           len >= MIN_DMA_LEN &&
+           len >= MIN_DMA_LEN && !force_8bit &&
            !atmel_nand_dma_transfer(nc, buf, nand->activecs->io.dma, len,
                                     DMA_FROM_DEVICE))
                return;
 
-       if (chip->options & NAND_BUSWIDTH_16)
+       if ((nand->base.options & NAND_BUSWIDTH_16) && !force_8bit)
                ioread16_rep(nand->activecs->io.virt, buf, len / 2);
        else
                ioread8_rep(nand->activecs->io.virt, buf, len);
 }
 
-static void atmel_nand_write_buf(struct nand_chip *chip, const u8 *buf, int len)
+static void atmel_nand_data_out(struct atmel_nand *nand, const void *buf,
+                               unsigned int len, bool force_8bit)
 {
-       struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_nand_controller *nc;
 
-       nc = to_nand_controller(chip->controller);
+       nc = to_nand_controller(nand->base.controller);
 
        /*
         * If the controller supports DMA, the buffer address is DMA-able and
@@ -468,179 +504,213 @@ static void atmel_nand_write_buf(struct nand_chip *chip, const u8 *buf, int len)
         * a DMA transfer. If it fails, fallback to PIO mode.
         */
        if (nc->dmac && virt_addr_valid(buf) &&
-           len >= MIN_DMA_LEN &&
+           len >= MIN_DMA_LEN && !force_8bit &&
            !atmel_nand_dma_transfer(nc, (void *)buf, nand->activecs->io.dma,
                                     len, DMA_TO_DEVICE))
                return;
 
-       if (chip->options & NAND_BUSWIDTH_16)
+       if ((nand->base.options & NAND_BUSWIDTH_16) && !force_8bit)
                iowrite16_rep(nand->activecs->io.virt, buf, len / 2);
        else
                iowrite8_rep(nand->activecs->io.virt, buf, len);
 }
 
-static int atmel_nand_dev_ready(struct nand_chip *chip)
+static int atmel_nand_waitrdy(struct atmel_nand *nand, unsigned int timeout_ms)
 {
-       struct atmel_nand *nand = to_atmel_nand(chip);
+       if (nand->activecs->rb.type == ATMEL_NAND_NO_RB)
+               return nand_soft_waitrdy(&nand->base, timeout_ms);
 
-       return gpiod_get_value(nand->activecs->rb.gpio);
+       return nand_gpio_waitrdy(&nand->base, nand->activecs->rb.gpio,
+                                timeout_ms);
 }
 
-static void atmel_nand_select_chip(struct nand_chip *chip, int cs)
+static int atmel_hsmc_nand_waitrdy(struct atmel_nand *nand,
+                                  unsigned int timeout_ms)
 {
-       struct atmel_nand *nand = to_atmel_nand(chip);
-
-       if (cs < 0 || cs >= nand->numcs) {
-               nand->activecs = NULL;
-               chip->legacy.dev_ready = NULL;
-               return;
-       }
+       struct atmel_hsmc_nand_controller *nc;
+       u32 status, mask;
 
-       nand->activecs = &nand->cs[cs];
+       if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB)
+               return atmel_nand_waitrdy(nand, timeout_ms);
 
-       if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
-               chip->legacy.dev_ready = atmel_nand_dev_ready;
+       nc = to_hsmc_nand_controller(nand->base.controller);
+       mask = ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
+       return regmap_read_poll_timeout_atomic(nc->base.smc, ATMEL_HSMC_NFC_SR,
+                                              status, status & mask,
+                                              10, timeout_ms * 1000);
 }
 
-static int atmel_hsmc_nand_dev_ready(struct nand_chip *chip)
+static void atmel_nand_select_target(struct atmel_nand *nand,
+                                    unsigned int cs)
 {
-       struct atmel_nand *nand = to_atmel_nand(chip);
-       struct atmel_hsmc_nand_controller *nc;
-       u32 status;
-
-       nc = to_hsmc_nand_controller(chip->controller);
-
-       regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &status);
-
-       return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
+       nand->activecs = &nand->cs[cs];
 }
 
-static void atmel_hsmc_nand_select_chip(struct nand_chip *chip, int cs)
+static void atmel_hsmc_nand_select_target(struct atmel_nand *nand,
+                                         unsigned int cs)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct atmel_nand *nand = to_atmel_nand(chip);
+       struct mtd_info *mtd = nand_to_mtd(&nand->base);
        struct atmel_hsmc_nand_controller *nc;
+       u32 cfg = ATMEL_HSMC_NFC_CFG_PAGESIZE(mtd->writesize) |
+                 ATMEL_HSMC_NFC_CFG_SPARESIZE(mtd->oobsize) |
+                 ATMEL_HSMC_NFC_CFG_RSPARE;
 
-       nc = to_hsmc_nand_controller(chip->controller);
-
-       atmel_nand_select_chip(chip, cs);
-
-       if (!nand->activecs) {
-               regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
-                            ATMEL_HSMC_NFC_CTRL_DIS);
+       nand->activecs = &nand->cs[cs];
+       nc = to_hsmc_nand_controller(nand->base.controller);
+       if (nc->cfg == cfg)
                return;
-       }
-
-       if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
-               chip->legacy.dev_ready = atmel_hsmc_nand_dev_ready;
 
        regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
                           ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
                           ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK |
                           ATMEL_HSMC_NFC_CFG_RSPARE |
                           ATMEL_HSMC_NFC_CFG_WSPARE,
-                          ATMEL_HSMC_NFC_CFG_PAGESIZE(mtd->writesize) |
-                          ATMEL_HSMC_NFC_CFG_SPARESIZE(mtd->oobsize) |
-                          ATMEL_HSMC_NFC_CFG_RSPARE);
-       regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
-                    ATMEL_HSMC_NFC_CTRL_EN);
+                          cfg);
+       nc->cfg = cfg;
 }
 
-static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
+static int atmel_smc_nand_exec_instr(struct atmel_nand *nand,
+                                    const struct nand_op_instr *instr)
 {
-       u8 *addrs = nc->op.addrs;
-       unsigned int op = 0;
-       u32 addr, val;
-       int i, ret;
-
-       nc->op.wait = ATMEL_HSMC_NFC_SR_CMDDONE;
-
-       for (i = 0; i < nc->op.ncmds; i++)
-               op |= ATMEL_NFC_CMD(i, nc->op.cmds[i]);
-
-       if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
-               regmap_write(nc->base.smc, ATMEL_HSMC_NFC_ADDR, *addrs++);
-
-       op |= ATMEL_NFC_CSID(nc->op.cs) |
-             ATMEL_NFC_ACYCLE(nc->op.naddrs);
-
-       if (nc->op.ncmds > 1)
-               op |= ATMEL_NFC_VCMD2;
-
-       addr = addrs[0] | (addrs[1] << 8) | (addrs[2] << 16) |
-              (addrs[3] << 24);
-
-       if (nc->op.data != ATMEL_NFC_NO_DATA) {
-               op |= ATMEL_NFC_DATAEN;
-               nc->op.wait |= ATMEL_HSMC_NFC_SR_XFRDONE;
+       struct atmel_nand_controller *nc;
+       unsigned int i;
 
-               if (nc->op.data == ATMEL_NFC_WRITE_DATA)
-                       op |= ATMEL_NFC_NFCWR;
+       nc = to_nand_controller(nand->base.controller);
+       switch (instr->type) {
+       case NAND_OP_CMD_INSTR:
+               writeb(instr->ctx.cmd.opcode,
+                      nand->activecs->io.virt + nc->caps->cle_offs);
+               return 0;
+       case NAND_OP_ADDR_INSTR:
+               for (i = 0; i < instr->ctx.addr.naddrs; i++)
+                       writeb(instr->ctx.addr.addrs[i],
+                              nand->activecs->io.virt + nc->caps->ale_offs);
+               return 0;
+       case NAND_OP_DATA_IN_INSTR:
+               atmel_nand_data_in(nand, instr->ctx.data.buf.in,
+                                  instr->ctx.data.len,
+                                  instr->ctx.data.force_8bit);
+               return 0;
+       case NAND_OP_DATA_OUT_INSTR:
+               atmel_nand_data_out(nand, instr->ctx.data.buf.out,
+                                   instr->ctx.data.len,
+                                   instr->ctx.data.force_8bit);
+               return 0;
+       case NAND_OP_WAITRDY_INSTR:
+               return atmel_nand_waitrdy(nand,
+                                         instr->ctx.waitrdy.timeout_ms);
+       default:
+               break;
        }
 
-       /* Clear all flags. */
-       regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &val);
+       return -EINVAL;
+}
 
-       /* Send the command. */
-       regmap_write(nc->io, op, addr);
+static int atmel_smc_nand_exec_op(struct atmel_nand *nand,
+                                 const struct nand_operation *op,
+                                 bool check_only)
+{
+       unsigned int i;
+       int ret = 0;
 
-       ret = atmel_nfc_wait(nc, poll, 0);
-       if (ret)
-               dev_err(nc->base.dev,
-                       "Failed to send NAND command (err = %d)!",
-                       ret);
+       if (check_only)
+               return 0;
 
-       /* Reset the op state. */
-       memset(&nc->op, 0, sizeof(nc->op));
+       atmel_nand_select_target(nand, op->cs);
+       gpiod_set_value(nand->activecs->csgpio, 0);
+       for (i = 0; i < op->ninstrs; i++) {
+               ret = atmel_smc_nand_exec_instr(nand, &op->instrs[i]);
+               if (ret)
+                       break;
+       }
+       gpiod_set_value(nand->activecs->csgpio, 1);
 
        return ret;
 }
 
-static void atmel_hsmc_nand_cmd_ctrl(struct nand_chip *chip, int dat,
-                                    unsigned int ctrl)
+static int atmel_hsmc_exec_cmd_addr(struct nand_chip *chip,
+                                   const struct nand_subop *subop)
 {
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_hsmc_nand_controller *nc;
+       unsigned int i, j;
 
        nc = to_hsmc_nand_controller(chip->controller);
 
-       if (ctrl & NAND_ALE) {
-               if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
-                       return;
+       nc->op.cs = nand->activecs->id;
+       for (i = 0; i < subop->ninstrs; i++) {
+               const struct nand_op_instr *instr = &subop->instrs[i];
 
-               nc->op.addrs[nc->op.naddrs++] = dat;
-       } else if (ctrl & NAND_CLE) {
-               if (nc->op.ncmds > 1)
-                       return;
+               if (instr->type == NAND_OP_CMD_INSTR) {
+                       nc->op.cmds[nc->op.ncmds++] = instr->ctx.cmd.opcode;
+                       continue;
+               }
 
-               nc->op.cmds[nc->op.ncmds++] = dat;
+               for (j = nand_subop_get_addr_start_off(subop, i);
+                    j < nand_subop_get_num_addr_cyc(subop, i); j++) {
+                       nc->op.addrs[nc->op.naddrs] = instr->ctx.addr.addrs[j];
+                       nc->op.naddrs++;
+               }
        }
 
-       if (dat == NAND_CMD_NONE) {
-               nc->op.cs = nand->activecs->id;
-               atmel_nfc_exec_op(nc, true);
-       }
+       return atmel_nfc_exec_op(nc, true);
 }
 
-static void atmel_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
-                               unsigned int ctrl)
+static int atmel_hsmc_exec_rw(struct nand_chip *chip,
+                             const struct nand_subop *subop)
 {
+       const struct nand_op_instr *instr = subop->instrs;
        struct atmel_nand *nand = to_atmel_nand(chip);
-       struct atmel_nand_controller *nc;
 
-       nc = to_nand_controller(chip->controller);
+       if (instr->type == NAND_OP_DATA_IN_INSTR)
+               atmel_nand_data_in(nand, instr->ctx.data.buf.in,
+                                  instr->ctx.data.len,
+                                  instr->ctx.data.force_8bit);
+       else
+               atmel_nand_data_out(nand, instr->ctx.data.buf.out,
+                                   instr->ctx.data.len,
+                                   instr->ctx.data.force_8bit);
 
-       if ((ctrl & NAND_CTRL_CHANGE) && nand->activecs->csgpio) {
-               if (ctrl & NAND_NCE)
-                       gpiod_set_value(nand->activecs->csgpio, 0);
-               else
-                       gpiod_set_value(nand->activecs->csgpio, 1);
-       }
+       return 0;
+}
+
+static int atmel_hsmc_exec_waitrdy(struct nand_chip *chip,
+                                  const struct nand_subop *subop)
+{
+       const struct nand_op_instr *instr = subop->instrs;
+       struct atmel_nand *nand = to_atmel_nand(chip);
 
-       if (ctrl & NAND_ALE)
-               writeb(cmd, nand->activecs->io.virt + nc->caps->ale_offs);
-       else if (ctrl & NAND_CLE)
-               writeb(cmd, nand->activecs->io.virt + nc->caps->cle_offs);
+       return atmel_hsmc_nand_waitrdy(nand, instr->ctx.waitrdy.timeout_ms);
+}
+
+static const struct nand_op_parser atmel_hsmc_op_parser = NAND_OP_PARSER(
+       NAND_OP_PARSER_PATTERN(atmel_hsmc_exec_cmd_addr,
+               NAND_OP_PARSER_PAT_CMD_ELEM(true),
+               NAND_OP_PARSER_PAT_ADDR_ELEM(true, 5),
+               NAND_OP_PARSER_PAT_CMD_ELEM(true)),
+       NAND_OP_PARSER_PATTERN(atmel_hsmc_exec_rw,
+               NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 0)),
+       NAND_OP_PARSER_PATTERN(atmel_hsmc_exec_rw,
+               NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 0)),
+       NAND_OP_PARSER_PATTERN(atmel_hsmc_exec_waitrdy,
+               NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
+);
+
+static int atmel_hsmc_nand_exec_op(struct atmel_nand *nand,
+                                  const struct nand_operation *op,
+                                  bool check_only)
+{
+       int ret;
+
+       if (check_only)
+               return nand_op_parser_exec_op(&nand->base,
+                                             &atmel_hsmc_op_parser, op, true);
+
+       atmel_hsmc_nand_select_target(nand, op->cs);
+       ret = nand_op_parser_exec_op(&nand->base, &atmel_hsmc_op_parser, op,
+                                    false);
+
+       return ret;
 }
 
 static void atmel_nfc_copy_to_sram(struct nand_chip *chip, const u8 *buf,
@@ -838,7 +908,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
        if (ret)
                return ret;
 
-       atmel_nand_write_buf(chip, buf, mtd->writesize);
+       nand_write_data_op(chip, buf, mtd->writesize, false);
 
        ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
        if (ret) {
@@ -848,7 +918,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
 
        atmel_nand_pmecc_disable(chip, raw);
 
-       atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
+       nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
 
        return nand_prog_page_end_op(chip);
 }
@@ -878,11 +948,17 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
        if (ret)
                return ret;
 
-       atmel_nand_read_buf(chip, buf, mtd->writesize);
-       atmel_nand_read_buf(chip, chip->oob_poi, mtd->oobsize);
+       ret = nand_read_data_op(chip, buf, mtd->writesize, false, false);
+       if (ret)
+               goto out_disable;
+
+       ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false, false);
+       if (ret)
+               goto out_disable;
 
        ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
 
+out_disable:
        atmel_nand_pmecc_disable(chip, raw);
 
        return ret;
@@ -907,8 +983,9 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_hsmc_nand_controller *nc;
-       int ret, status;
+       int ret;
 
+       atmel_hsmc_nand_select_target(nand, chip->cur_cs);
        nc = to_hsmc_nand_controller(chip->controller);
 
        atmel_nfc_copy_to_sram(chip, buf, false);
@@ -939,21 +1016,9 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
        if (ret)
                return ret;
 
-       atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
-
-       nc->op.cmds[0] = NAND_CMD_PAGEPROG;
-       nc->op.ncmds = 1;
-       nc->op.cs = nand->activecs->id;
-       ret = atmel_nfc_exec_op(nc, false);
-       if (ret)
-               dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
-                       ret);
-
-       status = chip->legacy.waitfunc(chip);
-       if (status & NAND_STATUS_FAIL)
-               return -EIO;
+       nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false);
 
-       return ret;
+       return nand_prog_page_end_op(chip);
 }
 
 static int atmel_hsmc_nand_pmecc_write_page(struct nand_chip *chip,
@@ -981,6 +1046,7 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
        struct atmel_hsmc_nand_controller *nc;
        int ret;
 
+       atmel_hsmc_nand_select_target(nand, chip->cur_cs);
        nc = to_hsmc_nand_controller(chip->controller);
 
        /*
@@ -988,12 +1054,9 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
         * connected to a native SoC R/B pin. If that's not the case, fallback
         * to the non-optimized one.
         */
-       if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) {
-               nand_read_page_op(chip, page, 0, NULL, 0);
-
+       if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB)
                return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page,
                                                raw);
-       }
 
        nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READ0;
 
@@ -1043,7 +1106,10 @@ static int atmel_hsmc_nand_pmecc_read_page_raw(struct nand_chip *chip,
 
 static int atmel_nand_pmecc_init(struct nand_chip *chip)
 {
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(&chip->base);
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_device *nanddev = mtd_to_nanddev(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_nand_controller *nc;
        struct atmel_pmecc_user_req req;
@@ -1068,19 +1134,19 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
                        chip->ecc.size = val;
        }
 
-       if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+       if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH)
                req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
        else if (chip->ecc.strength)
                req.ecc.strength = chip->ecc.strength;
-       else if (chip->base.eccreq.strength)
-               req.ecc.strength = chip->base.eccreq.strength;
+       else if (requirements->strength)
+               req.ecc.strength = requirements->strength;
        else
                req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
 
        if (chip->ecc.size)
                req.ecc.sectorsize = chip->ecc.size;
-       else if (chip->base.eccreq.step_size)
-               req.ecc.sectorsize = chip->base.eccreq.step_size;
+       else if (requirements->step_size)
+               req.ecc.sectorsize = requirements->step_size;
        else
                req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
 
@@ -1099,14 +1165,14 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
        if (IS_ERR(nand->pmecc))
                return PTR_ERR(nand->pmecc);
 
-       chip->ecc.algo = NAND_ECC_BCH;
+       chip->ecc.algo = NAND_ECC_ALGO_BCH;
        chip->ecc.size = req.ecc.sectorsize;
        chip->ecc.bytes = req.ecc.bytes / req.ecc.nsectors;
        chip->ecc.strength = req.ecc.strength;
 
        chip->options |= NAND_NO_SUBPAGE_WRITE;
 
-       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+       mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
 
        return 0;
 }
@@ -1118,15 +1184,15 @@ static int atmel_nand_ecc_init(struct nand_chip *chip)
 
        nc = to_nand_controller(chip->controller);
 
-       switch (chip->ecc.mode) {
-       case NAND_ECC_NONE:
-       case NAND_ECC_SOFT:
+       switch (chip->ecc.engine_type) {
+       case NAND_ECC_ENGINE_TYPE_NONE:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
                /*
                 * Nothing to do, the core will initialize everything for us.
                 */
                break;
 
-       case NAND_ECC_HW:
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                ret = atmel_nand_pmecc_init(chip);
                if (ret)
                        return ret;
@@ -1140,7 +1206,7 @@ static int atmel_nand_ecc_init(struct nand_chip *chip)
        default:
                /* Other modes are not supported. */
                dev_err(nc->dev, "Unsupported ECC mode: %d\n",
-                       chip->ecc.mode);
+                       chip->ecc.engine_type);
                return -ENOTSUPP;
        }
 
@@ -1155,7 +1221,7 @@ static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip)
        if (ret)
                return ret;
 
-       if (chip->ecc.mode != NAND_ECC_HW)
+       if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
                return 0;
 
        /* Adjust the ECC operations for the HSMC IP. */
@@ -1467,6 +1533,18 @@ static int atmel_nand_setup_interface(struct nand_chip *chip, int csline,
        return nc->caps->ops->setup_interface(nand, csline, conf);
 }
 
+static int atmel_nand_exec_op(struct nand_chip *chip,
+                             const struct nand_operation *op,
+                             bool check_only)
+{
+       struct atmel_nand *nand = to_atmel_nand(chip);
+       struct atmel_nand_controller *nc;
+
+       nc = to_nand_controller(nand->base.controller);
+
+       return nc->caps->ops->exec_op(nand, op, check_only);
+}
+
 static void atmel_nand_init(struct atmel_nand_controller *nc,
                            struct atmel_nand *nand)
 {
@@ -1476,19 +1554,9 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
        mtd->dev.parent = nc->dev;
        nand->base.controller = &nc->base;
 
-       chip->legacy.cmd_ctrl = atmel_nand_cmd_ctrl;
-       chip->legacy.read_byte = atmel_nand_read_byte;
-       chip->legacy.write_byte = atmel_nand_write_byte;
-       chip->legacy.read_buf = atmel_nand_read_buf;
-       chip->legacy.write_buf = atmel_nand_write_buf;
-       chip->legacy.select_chip = atmel_nand_select_chip;
-
        if (!nc->mck || !nc->caps->ops->setup_interface)
                chip->options |= NAND_KEEP_TIMINGS;
 
-       /* Some NANDs require a longer delay than the default one (20us). */
-       chip->legacy.chip_delay = 40;
-
        /*
         * Use a bounce buffer when the buffer passed by the MTD user is not
         * suitable for DMA.
@@ -1498,7 +1566,7 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
 
        /* Default to HW ECC if pmecc is available. */
        if (nc->pmecc)
-               chip->ecc.mode = NAND_ECC_HW;
+               chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
 }
 
 static void atmel_smc_nand_init(struct atmel_nand_controller *nc,
@@ -1527,18 +1595,6 @@ static void atmel_smc_nand_init(struct atmel_nand_controller *nc,
                                   smc_nc->ebi_csa->nfd0_on_d16);
 }
 
-static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
-                                struct atmel_nand *nand)
-{
-       struct nand_chip *chip = &nand->base;
-
-       atmel_nand_init(nc, nand);
-
-       /* Overload some methods for the HSMC controller. */
-       chip->legacy.cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
-       chip->legacy.select_chip = atmel_hsmc_nand_select_chip;
-}
-
 static int atmel_nand_controller_remove_nand(struct atmel_nand *nand)
 {
        struct nand_chip *chip = &nand->base;
@@ -1957,6 +2013,7 @@ static int atmel_nand_attach_chip(struct nand_chip *chip)
 static const struct nand_controller_ops atmel_nand_controller_ops = {
        .attach_chip = atmel_nand_attach_chip,
        .setup_interface = atmel_nand_setup_interface,
+       .exec_op = atmel_nand_exec_op,
 };
 
 static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
@@ -1976,13 +2033,9 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
        platform_set_drvdata(pdev, nc);
 
        nc->pmecc = devm_atmel_pmecc_get(dev);
-       if (IS_ERR(nc->pmecc)) {
-               ret = PTR_ERR(nc->pmecc);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "Could not get PMECC object (err = %d)\n",
-                               ret);
-               return ret;
-       }
+       if (IS_ERR(nc->pmecc))
+               return dev_err_probe(dev, PTR_ERR(nc->pmecc),
+                                    "Could not get PMECC object\n");
 
        if (nc->caps->has_dma && !atmel_nand_avoid_dma) {
                dma_cap_mask_t mask;
@@ -2248,6 +2301,9 @@ atmel_hsmc_nand_controller_remove(struct atmel_nand_controller *nc)
                return ret;
 
        hsmc_nc = container_of(nc, struct atmel_hsmc_nand_controller, base);
+       regmap_write(hsmc_nc->base.smc, ATMEL_HSMC_NFC_CTRL,
+                    ATMEL_HSMC_NFC_CTRL_DIS);
+
        if (hsmc_nc->sram.pool)
                gen_pool_free(hsmc_nc->sram.pool,
                              (unsigned long)hsmc_nc->sram.virt,
@@ -2300,6 +2356,8 @@ static int atmel_hsmc_nand_controller_probe(struct platform_device *pdev,
        /* Initial NFC configuration. */
        regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CFG,
                     ATMEL_HSMC_NFC_CFG_DTO_MAX);
+       regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
+                    ATMEL_HSMC_NFC_CTRL_EN);
 
        ret = atmel_nand_controller_add_nands(&nc->base);
        if (ret)
@@ -2317,8 +2375,9 @@ static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
        .probe = atmel_hsmc_nand_controller_probe,
        .remove = atmel_hsmc_nand_controller_remove,
        .ecc_init = atmel_hsmc_nand_ecc_init,
-       .nand_init = atmel_hsmc_nand_init,
+       .nand_init = atmel_nand_init,
        .setup_interface = atmel_hsmc_nand_setup_interface,
+       .exec_op = atmel_hsmc_nand_exec_op,
 };
 
 static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
@@ -2385,6 +2444,7 @@ static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
        .remove = atmel_smc_nand_controller_remove,
        .ecc_init = atmel_nand_ecc_init,
        .nand_init = atmel_smc_nand_init,
+       .exec_op = atmel_smc_nand_exec_op,
 };
 
 static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = {
@@ -2400,6 +2460,7 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
        .ecc_init = atmel_nand_ecc_init,
        .nand_init = atmel_smc_nand_init,
        .setup_interface = atmel_smc_nand_setup_interface,
+       .exec_op = atmel_smc_nand_exec_op,
 };
 
 static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {
index d865200..79b0574 100644 (file)
@@ -294,8 +294,8 @@ static int au1550nd_probe(struct platform_device *pdev)
        nand_controller_init(&ctx->controller);
        ctx->controller.ops = &au1550nd_ops;
        this->controller = &ctx->controller;
-       this->ecc.mode = NAND_ECC_SOFT;
-       this->ecc.algo = NAND_ECC_HAMMING;
+       this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       this->ecc.algo = NAND_ECC_ALGO_HAMMING;
 
        if (pd->devwidth)
                this->options |= NAND_BUSWIDTH_16;
index 5917751..8bb17c5 100644 (file)
@@ -391,7 +391,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
 
        nand_chip->legacy.chip_delay = 50;
        b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
-       b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
+       /* TODO: implement ECC */
+       b47n->nand_chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_NONE;
 
        /* Enable NAND flash access */
        bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
index a4033d3..2da39ab 100644 (file)
@@ -2532,6 +2532,8 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
 {
        struct mtd_info *mtd = nand_to_mtd(&host->chip);
        struct nand_chip *chip = &host->chip;
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(&chip->base);
        struct brcmnand_controller *ctrl = host->ctrl;
        struct brcmnand_cfg *cfg = &host->hwcfg;
        char msg[128];
@@ -2565,34 +2567,34 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
        cfg->col_adr_bytes = 2;
        cfg->blk_adr_bytes = get_blk_adr_bytes(mtd->size, mtd->writesize);
 
-       if (chip->ecc.mode != NAND_ECC_HW) {
+       if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) {
                dev_err(ctrl->dev, "only HW ECC supported; selected: %d\n",
-                       chip->ecc.mode);
+                       chip->ecc.engine_type);
                return -EINVAL;
        }
 
-       if (chip->ecc.algo == NAND_ECC_UNKNOWN) {
+       if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN) {
                if (chip->ecc.strength == 1 && chip->ecc.size == 512)
                        /* Default to Hamming for 1-bit ECC, if unspecified */
-                       chip->ecc.algo = NAND_ECC_HAMMING;
+                       chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
                else
                        /* Otherwise, BCH */
-                       chip->ecc.algo = NAND_ECC_BCH;
+                       chip->ecc.algo = NAND_ECC_ALGO_BCH;
        }
 
-       if (chip->ecc.algo == NAND_ECC_HAMMING && (chip->ecc.strength != 1 ||
-                                                  chip->ecc.size != 512)) {
+       if (chip->ecc.algo == NAND_ECC_ALGO_HAMMING &&
+           (chip->ecc.strength != 1 || chip->ecc.size != 512)) {
                dev_err(ctrl->dev, "invalid Hamming params: %d bits per %d bytes\n",
                        chip->ecc.strength, chip->ecc.size);
                return -EINVAL;
        }
 
-       if (chip->ecc.mode != NAND_ECC_NONE &&
+       if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
            (!chip->ecc.size || !chip->ecc.strength)) {
-               if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
+               if (requirements->step_size && requirements->strength) {
                        /* use detected ECC parameters */
-                       chip->ecc.size = chip->base.eccreq.step_size;
-                       chip->ecc.strength = chip->base.eccreq.strength;
+                       chip->ecc.size = requirements->step_size;
+                       chip->ecc.strength = requirements->strength;
                        dev_info(ctrl->dev, "Using ECC step-size %d, strength %d\n",
                                chip->ecc.size, chip->ecc.strength);
                }
@@ -2600,7 +2602,7 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
 
        switch (chip->ecc.size) {
        case 512:
-               if (chip->ecc.algo == NAND_ECC_HAMMING)
+               if (chip->ecc.algo == NAND_ECC_ALGO_HAMMING)
                        cfg->ecc_level = 15;
                else
                        cfg->ecc_level = chip->ecc.strength;
@@ -2728,7 +2730,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
        chip->legacy.read_buf = brcmnand_read_buf;
        chip->legacy.write_buf = brcmnand_write_buf;
 
-       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        chip->ecc.read_page = brcmnand_read_page;
        chip->ecc.write_page = brcmnand_write_page;
        chip->ecc.read_page_raw = brcmnand_read_page_raw;
index 71516af..b46786c 100644 (file)
@@ -2611,7 +2611,7 @@ static int cadence_nand_attach_chip(struct nand_chip *chip)
 
        chip->bbt_options |= NAND_BBT_USE_FLASH;
        chip->bbt_options |= NAND_BBT_NO_OOB;
-       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
 
        chip->options |= NAND_NO_SUBPAGE_WRITE;
 
@@ -2757,7 +2757,7 @@ static int cadence_nand_chip_init(struct cdns_nand_ctrl *cdns_ctrl,
         * Default to HW ECC engine mode. If the nand-ecc-mode property is given
         * in the DT node, this entry will be overwritten in nand_scan_ident().
         */
-       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
 
        ret = nand_scan(chip, cdns_chip->nsels);
        if (ret) {
@@ -2980,18 +2980,14 @@ static int cadence_nand_dt_probe(struct platform_device *ofdev)
        dev_info(cdns_ctrl->dev, "IRQ: nr %d\n", cdns_ctrl->irq);
 
        cdns_ctrl->reg = devm_platform_ioremap_resource(ofdev, 0);
-       if (IS_ERR(cdns_ctrl->reg)) {
-               dev_err(&ofdev->dev, "devm_ioremap_resource res 0 failed\n");
+       if (IS_ERR(cdns_ctrl->reg))
                return PTR_ERR(cdns_ctrl->reg);
-       }
 
        res = platform_get_resource(ofdev, IORESOURCE_MEM, 1);
        cdns_ctrl->io.dma = res->start;
        cdns_ctrl->io.virt = devm_ioremap_resource(&ofdev->dev, res);
-       if (IS_ERR(cdns_ctrl->io.virt)) {
-               dev_err(cdns_ctrl->dev, "devm_ioremap_resource res 1 failed\n");
+       if (IS_ERR(cdns_ctrl->io.virt))
                return PTR_ERR(cdns_ctrl->io.virt);
-       }
 
        dt->clk = devm_clk_get(cdns_ctrl->dev, "nf_clk");
        if (IS_ERR(dt->clk))
index 9217379..2b94f38 100644 (file)
@@ -629,7 +629,8 @@ static int cafe_nand_attach_chip(struct nand_chip *chip)
                goto out_free_dma;
        }
 
-       cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+       cafe->nand.ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
+       cafe->nand.ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
        cafe->nand.ecc.size = mtd->writesize;
        cafe->nand.ecc.bytes = 14;
        cafe->nand.ecc.strength = 4;
index 9472bf7..b7f3f63 100644 (file)
@@ -286,7 +286,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
                goto out_mtd;
        }
 
-       this->ecc.mode = NAND_ECC_HW;
+       this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        this->ecc.size = 256;
        this->ecc.bytes = 3;
        this->ecc.hwctl  = cs_enable_hwecc;
index d975a62..427f320 100644 (file)
@@ -168,7 +168,7 @@ static int nand_davinci_correct_1bit(struct nand_chip *chip, u_char *dat,
 /*
  * 4-bit hardware ECC ... context maintained over entire AEMIF
  *
- * This is a syndrome engine, but we avoid NAND_ECC_HW_SYNDROME
+ * This is a syndrome engine, but we avoid NAND_ECC_PLACEMENT_INTERLEAVED
  * since that forces use of a problematic "infix OOB" layout.
  * Among other things, it trashes manufacturer bad block markers.
  * Also, and specific to this hardware, it ECC-protects the "prepad"
@@ -530,11 +530,11 @@ static struct davinci_nand_pdata
                if (!of_property_read_string(pdev->dev.of_node,
                        "ti,davinci-ecc-mode", &mode)) {
                        if (!strncmp("none", mode, 4))
-                               pdata->ecc_mode = NAND_ECC_NONE;
+                               pdata->engine_type = NAND_ECC_ENGINE_TYPE_NONE;
                        if (!strncmp("soft", mode, 4))
-                               pdata->ecc_mode = NAND_ECC_SOFT;
+                               pdata->engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
                        if (!strncmp("hw", mode, 2))
-                               pdata->ecc_mode = NAND_ECC_HW;
+                               pdata->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
                }
                if (!of_property_read_u32(pdev->dev.of_node,
                        "ti,davinci-ecc-bits", &prop))
@@ -585,21 +585,21 @@ static int davinci_nand_attach_chip(struct nand_chip *chip)
        if (IS_ERR(pdata))
                return PTR_ERR(pdata);
 
-       switch (info->chip.ecc.mode) {
-       case NAND_ECC_NONE:
+       switch (info->chip.ecc.engine_type) {
+       case NAND_ECC_ENGINE_TYPE_NONE:
                pdata->ecc_bits = 0;
                break;
-       case NAND_ECC_SOFT:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
                pdata->ecc_bits = 0;
                /*
-                * This driver expects Hamming based ECC when ecc_mode is set
-                * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
-                * avoid adding an extra ->ecc_algo field to
-                * davinci_nand_pdata.
+                * This driver expects Hamming based ECC when engine_type is set
+                * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to
+                * NAND_ECC_ALGO_HAMMING to avoid adding an extra ->ecc_algo
+                * field to davinci_nand_pdata.
                 */
-               info->chip.ecc.algo = NAND_ECC_HAMMING;
+               info->chip.ecc.algo = NAND_ECC_ALGO_HAMMING;
                break;
-       case NAND_ECC_HW:
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                if (pdata->ecc_bits == 4) {
                        int chunks = mtd->writesize / 512;
 
@@ -629,7 +629,7 @@ static int davinci_nand_attach_chip(struct nand_chip *chip)
                        info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
                        info->chip.ecc.bytes = 10;
                        info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
-                       info->chip.ecc.algo = NAND_ECC_BCH;
+                       info->chip.ecc.algo = NAND_ECC_ALGO_BCH;
 
                        /*
                         * Update ECC layout if needed ... for 1-bit HW ECC, the
@@ -645,7 +645,8 @@ static int davinci_nand_attach_chip(struct nand_chip *chip)
                                mtd_set_ooblayout(mtd,
                                                  &hwecc4_small_ooblayout_ops);
                        } else if (chunks == 4 || chunks == 8) {
-                               mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+                               mtd_set_ooblayout(mtd,
+                                                 nand_get_large_page_ooblayout());
                                info->chip.ecc.read_page = nand_davinci_read_page_hwecc_oob_first;
                        } else {
                                return -EIO;
@@ -656,7 +657,7 @@ static int davinci_nand_attach_chip(struct nand_chip *chip)
                        info->chip.ecc.correct = nand_davinci_correct_1bit;
                        info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
                        info->chip.ecc.bytes = 3;
-                       info->chip.ecc.algo = NAND_ECC_HAMMING;
+                       info->chip.ecc.algo = NAND_ECC_ALGO_HAMMING;
                }
                info->chip.ecc.size = 512;
                info->chip.ecc.strength = pdata->ecc_bits;
@@ -850,7 +851,8 @@ static int nand_davinci_probe(struct platform_device *pdev)
        info->mask_cle          = pdata->mask_cle ? : MASK_CLE;
 
        /* Use board-specific ECC config */
-       info->chip.ecc.mode     = pdata->ecc_mode;
+       info->chip.ecc.engine_type = pdata->engine_type;
+       info->chip.ecc.placement = pdata->ecc_placement;
 
        spin_lock_irq(&davinci_nand_lock);
 
@@ -897,7 +899,7 @@ static int nand_davinci_remove(struct platform_device *pdev)
        int ret;
 
        spin_lock_irq(&davinci_nand_lock);
-       if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
+       if (info->chip.ecc.placement == NAND_ECC_PLACEMENT_INTERLEAVED)
                ecc4_busy = false;
        spin_unlock_irq(&davinci_nand_lock);
 
index 9d99dad..fa2439c 100644 (file)
@@ -1237,7 +1237,8 @@ int denali_chip_init(struct denali_controller *denali,
        chip->bbt_options |= NAND_BBT_USE_FLASH;
        chip->bbt_options |= NAND_BBT_NO_OOB;
        chip->options |= NAND_NO_SUBPAGE_WRITE;
-       chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
+       chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
        chip->ecc.read_page = denali_read_page;
        chip->ecc.write_page = denali_write_page;
        chip->ecc.read_page_raw = denali_read_page_raw;
index 2f77ee5..20c085a 100644 (file)
@@ -100,7 +100,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                goto out_remove_denali;
        }
 
-       dchip->chip.ecc.options |= NAND_ECC_MAXIMIZE;
+       dchip->chip.base.ecc.user_conf.flags |= NAND_ECC_MAXIMIZE_STRENGTH;
 
        dchip->nsels = nsels;
 
index 4372186..94432a4 100644 (file)
@@ -1456,7 +1456,8 @@ static int __init doc_probe(unsigned long physadr)
        nand->ecc.calculate     = doc200x_calculate_ecc;
        nand->ecc.correct       = doc200x_correct_data;
 
-       nand->ecc.mode          = NAND_ECC_HW_SYNDROME;
+       nand->ecc.engine_type   = NAND_ECC_ENGINE_TYPE_ON_HOST;
+       nand->ecc.placement     = NAND_ECC_PLACEMENT_INTERLEAVED;
        nand->ecc.size          = 512;
        nand->ecc.bytes         = 6;
        nand->ecc.strength      = 2;
index 088692b..b2af7f8 100644 (file)
@@ -244,7 +244,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
                return -EIO;
        }
 
-       if (chip->ecc.mode != NAND_ECC_HW)
+       if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
                return 0;
 
        elbc_fcm_ctrl->max_bitflips = 0;
@@ -727,12 +727,12 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
        struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
        unsigned int al;
 
-       switch (chip->ecc.mode) {
+       switch (chip->ecc.engine_type) {
        /*
         * if ECC was not chosen in DT, decide whether to use HW or SW ECC from
         * CS Base Register
         */
-       case NAND_ECC_NONE:
+       case NAND_ECC_ENGINE_TYPE_NONE:
                /* If CS Base Register selects full hardware ECC then use it */
                if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
                    BR_DECC_CHK_GEN) {
@@ -740,23 +740,23 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
                        chip->ecc.write_page = fsl_elbc_write_page;
                        chip->ecc.write_subpage = fsl_elbc_write_subpage;
 
-                       chip->ecc.mode = NAND_ECC_HW;
+                       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
                        mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
                        chip->ecc.size = 512;
                        chip->ecc.bytes = 3;
                        chip->ecc.strength = 1;
                } else {
                        /* otherwise fall back to default software ECC */
-                       chip->ecc.mode = NAND_ECC_SOFT;
-                       chip->ecc.algo = NAND_ECC_HAMMING;
+                       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+                       chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
                }
                break;
 
        /* if SW ECC was chosen in DT, we do not need to set anything here */
-       case NAND_ECC_SOFT:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
                break;
 
-       /* should we also implement NAND_ECC_HW to do as the code above? */
+       /* should we also implement *_ECC_ENGINE_CONTROLLER to do as above? */
        default:
                return -EINVAL;
        }
@@ -786,8 +786,8 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
                chip->page_shift);
        dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
                chip->phys_erase_shift);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
-               chip->ecc.mode);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.engine_type = %d\n",
+               chip->ecc.engine_type);
        dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
                chip->ecc.steps);
        dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
index 00ae7a9..0e7a9b6 100644 (file)
@@ -309,7 +309,7 @@ static void fsl_ifc_cmdfunc(struct nand_chip *chip, unsigned int command,
                ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
                ifc_nand_ctrl->index += column;
 
-               if (chip->ecc.mode == NAND_ECC_HW)
+               if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
                        ifc_nand_ctrl->eccread = 1;
 
                fsl_ifc_do_read(chip, 0, mtd);
@@ -724,8 +724,8 @@ static int fsl_ifc_attach_chip(struct nand_chip *chip)
                                                        chip->page_shift);
        dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
                                                        chip->phys_erase_shift);
-       dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
-                                                       chip->ecc.mode);
+       dev_dbg(priv->dev, "%s: nand->ecc.engine_type = %d\n", __func__,
+                                                       chip->ecc.engine_type);
        dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
                                                        chip->ecc.steps);
        dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__,
@@ -912,7 +912,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
        /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
        if (csor & CSOR_NAND_ECC_DEC_EN) {
-               chip->ecc.mode = NAND_ECC_HW;
+               chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
                mtd_set_ooblayout(mtd, &fsl_ifc_ooblayout_ops);
 
                /* Hardware generates ECC per 512 Bytes */
@@ -925,8 +925,8 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
                        chip->ecc.strength = 8;
                }
        } else {
-               chip->ecc.mode = NAND_ECC_SOFT;
-               chip->ecc.algo = NAND_ECC_HAMMING;
+               chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+               chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
        }
 
        ret = fsl_ifc_sram_init(priv);
index 197850a..d5813b9 100644 (file)
@@ -47,8 +47,8 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
        int ret;
        struct device_node *flash_np;
 
-       fun->chip.ecc.mode = NAND_ECC_SOFT;
-       fun->chip.ecc.algo = NAND_ECC_HAMMING;
+       fun->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       fun->chip.ecc.algo = NAND_ECC_ALGO_HAMMING;
        fun->chip.controller = &fun->base;
        mtd->dev.parent = fun->dev;
 
index 92ddc41..4191831 100644 (file)
@@ -900,8 +900,8 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
                return 0;
        }
 
-       switch (nand->ecc.mode) {
-       case NAND_ECC_HW:
+       switch (nand->ecc.engine_type) {
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                dev_info(host->dev, "Using 1-bit HW ECC scheme\n");
                nand->ecc.calculate = fsmc_read_hwecc_ecc1;
                nand->ecc.correct = nand_correct_data;
@@ -910,14 +910,14 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
                nand->ecc.options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
                break;
 
-       case NAND_ECC_SOFT:
-               if (nand->ecc.algo == NAND_ECC_BCH) {
+       case NAND_ECC_ENGINE_TYPE_SOFT:
+               if (nand->ecc.algo == NAND_ECC_ALGO_BCH) {
                        dev_info(host->dev,
                                 "Using 4-bit SW BCH ECC scheme\n");
                        break;
                }
 
-       case NAND_ECC_ON_DIE:
+       case NAND_ECC_ENGINE_TYPE_ON_DIE:
                break;
 
        default:
@@ -929,7 +929,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
         * Don't set layout for BCH4 SW ECC. This will be
         * generated later in nand_bch_init() later.
         */
-       if (nand->ecc.mode == NAND_ECC_HW) {
+       if (nand->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) {
                switch (mtd->oobsize) {
                case 16:
                case 64:
@@ -1059,7 +1059,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
         * Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
         * can overwrite this value if the DT provides a different value.
         */
-       nand->ecc.mode = NAND_ECC_HW;
+       nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        nand->ecc.hwctl = fsmc_enable_hwecc;
        nand->ecc.size = 512;
        nand->badblockbits = 7;
index 3bd847c..4ec0a1e 100644 (file)
@@ -342,8 +342,8 @@ static int gpio_nand_probe(struct platform_device *pdev)
        gpiomtd->base.ops = &gpio_nand_ops;
 
        nand_set_flash_node(chip, pdev->dev.of_node);
-       chip->ecc.mode          = NAND_ECC_SOFT;
-       chip->ecc.algo          = NAND_ECC_HAMMING;
+       chip->ecc.engine_type   = NAND_ECC_ENGINE_TYPE_SOFT;
+       chip->ecc.algo          = NAND_ECC_ALGO_HAMMING;
        chip->options           = gpiomtd->plat.options;
        chip->controller        = &gpiomtd->base;
 
index 5d4aee4..dc8104e 100644 (file)
@@ -272,8 +272,8 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this,
        default:
                dev_err(this->dev,
                        "unsupported nand chip. ecc bits : %d, ecc size : %d\n",
-                       chip->base.eccreq.strength,
-                       chip->base.eccreq.step_size);
+                       nanddev_get_ecc_requirements(&chip->base)->strength,
+                       nanddev_get_ecc_requirements(&chip->base)->step_size);
                return -EINVAL;
        }
        geo->ecc_chunk_size = ecc_step;
@@ -510,6 +510,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
 static int common_nfc_set_geometry(struct gpmi_nand_data *this)
 {
        struct nand_chip *chip = &this->nand;
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(&chip->base);
 
        if (chip->ecc.strength > 0 && chip->ecc.size > 0)
                return set_geometry_by_ecc_info(this, chip->ecc.strength,
@@ -517,13 +519,12 @@ static int common_nfc_set_geometry(struct gpmi_nand_data *this)
 
        if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
                                || legacy_set_geometry(this)) {
-               if (!(chip->base.eccreq.strength > 0 &&
-                     chip->base.eccreq.step_size > 0))
+               if (!(requirements->strength > 0 && requirements->step_size > 0))
                        return -EINVAL;
 
                return set_geometry_by_ecc_info(this,
-                                               chip->base.eccreq.strength,
-                                               chip->base.eccreq.step_size);
+                                               requirements->strength,
+                                               requirements->step_size);
        }
 
        return 0;
@@ -1003,10 +1004,8 @@ static int acquire_dma_channels(struct gpmi_nand_data *this)
        /* request dma channel */
        dma_chan = dma_request_chan(&pdev->dev, "rx-tx");
        if (IS_ERR(dma_chan)) {
-               ret = PTR_ERR(dma_chan);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(this->dev, "DMA channel request failed: %d\n",
-                               ret);
+               ret = dev_err_probe(this->dev, PTR_ERR(dma_chan),
+                                   "DMA channel request failed\n");
                release_dma_channels(this);
        } else {
                this->dma_chans[0] = dma_chan;
@@ -2032,7 +2031,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
        ecc->write_page_raw = gpmi_ecc_write_page_raw;
        ecc->read_oob_raw = gpmi_ecc_read_oob_raw;
        ecc->write_oob_raw = gpmi_ecc_write_oob_raw;
-       ecc->mode       = NAND_ECC_HW;
+       ecc->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        ecc->size       = bch_geo->ecc_chunk_size;
        ecc->strength   = bch_geo->ecc_strength;
        mtd_set_ooblayout(mtd, &gpmi_ooblayout_ops);
index b84238e..8b2122c 100644 (file)
@@ -186,7 +186,7 @@ static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev)
        hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA);
        hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB);
 
-       if (chip->ecc.mode == NAND_ECC_NONE) {
+       if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_NONE) {
                hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK)
                        << HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN);
 
@@ -468,7 +468,7 @@ static void hisi_nfc_cmdfunc(struct nand_chip *chip, unsigned command,
 
        case NAND_CMD_STATUS:
                flag = hinfc_read(host, HINFC504_CON);
-               if (chip->ecc.mode == NAND_ECC_HW)
+               if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
                        hinfc_write(host,
                                    flag & ~(HINFC504_CON_ECCTYPE_MASK <<
                                    HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON);
@@ -721,7 +721,7 @@ static int hisi_nfc_attach_chip(struct nand_chip *chip)
        }
        hinfc_write(host, flag, HINFC504_CON);
 
-       if (chip->ecc.mode == NAND_ECC_HW)
+       if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
                hisi_nfc_ecc_probe(host);
 
        return 0;
index 69423bb..0e9d426 100644 (file)
@@ -194,8 +194,8 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip)
                                  (chip->ecc.strength / 8);
        }
 
-       switch (chip->ecc.mode) {
-       case NAND_ECC_HW:
+       switch (chip->ecc.engine_type) {
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                if (!nfc->ecc) {
                        dev_err(nfc->dev, "HW ECC selected, but ECC controller not found\n");
                        return -ENODEV;
@@ -205,22 +205,22 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip)
                chip->ecc.calculate = ingenic_nand_ecc_calculate;
                chip->ecc.correct = ingenic_nand_ecc_correct;
                fallthrough;
-       case NAND_ECC_SOFT:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
                dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n",
                         (nfc->ecc) ? "hardware ECC" : "software ECC",
                         chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
                break;
-       case NAND_ECC_NONE:
+       case NAND_ECC_ENGINE_TYPE_NONE:
                dev_info(nfc->dev, "not using ECC\n");
                break;
        default:
                dev_err(nfc->dev, "ECC mode %d not supported\n",
-                       chip->ecc.mode);
+                       chip->ecc.engine_type);
                return -EINVAL;
        }
 
        /* The NAND core will generate the ECC layout for SW ECC */
-       if (chip->ecc.mode != NAND_ECC_HW)
+       if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
                return 0;
 
        /* Generate ECC layout. ECC codes are right aligned in the OOB area. */
@@ -243,8 +243,10 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip)
        /* For legacy reasons we use a different layout on the qi,lb60 board. */
        if (of_machine_is_compatible("qi,lb60"))
                mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops);
-       else
+       else if (nfc->soc_info->oob_layout)
                mtd_set_ooblayout(mtd, nfc->soc_info->oob_layout);
+       else
+               mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
 
        return 0;
 }
@@ -404,7 +406,7 @@ static int ingenic_nand_init_chip(struct platform_device *pdev,
        mtd->dev.parent = dev;
 
        chip->options = NAND_NO_SUBPAGE_WRITE;
-       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        chip->controller = &nfc->controller;
        nand_set_flash_node(chip, np);
 
@@ -532,7 +534,6 @@ static const struct jz_soc_info jz4740_soc_info = {
        .data_offset = 0x00000000,
        .cmd_offset = 0x00008000,
        .addr_offset = 0x00010000,
-       .oob_layout = &nand_ooblayout_lp_ops,
 };
 
 static const struct jz_soc_info jz4725b_soc_info = {
@@ -546,7 +547,6 @@ static const struct jz_soc_info jz4780_soc_info = {
        .data_offset = 0x00000000,
        .cmd_offset = 0x00400000,
        .addr_offset = 0x00800000,
-       .oob_layout = &nand_ooblayout_lp_ops,
 };
 
 static const struct of_device_id ingenic_nand_dt_match[] = {
index 7521038..4940bb2 100644 (file)
@@ -656,7 +656,7 @@ static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
        if (!host->dummy_buf)
                return -ENOMEM;
 
-       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        chip->ecc.size = 512;
        mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
        host->mlcsubpages = mtd->writesize / 512;
index b151fd0..6db9d2e 100644 (file)
@@ -881,7 +881,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, host);
 
        /* NAND callbacks for LPC32xx SLC hardware */
-       chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
+       chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
        chip->legacy.read_byte = lpc32xx_nand_read_byte;
        chip->legacy.read_buf = lpc32xx_nand_read_buf;
        chip->legacy.write_buf = lpc32xx_nand_write_buf;
index 8482d3b..f5ca200 100644 (file)
 #define XTYPE_MASK             7
 
 /**
+ * struct marvell_hw_ecc_layout - layout of Marvell ECC
+ *
  * Marvell ECC engine works differently than the others, in order to limit the
  * size of the IP, hardware engineers chose to set a fixed strength at 16 bits
  * per subpage, and depending on a the desired strength needed by the NAND chip,
@@ -292,6 +294,8 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
 };
 
 /**
+ * struct marvell_nand_chip_sel - CS line description
+ *
  * The Nand Flash Controller has up to 4 CE and 2 RB pins. The CE selection
  * is made by a field in NDCB0 register, and in another field in NDCB2 register.
  * The datasheet describes the logic with an error: ADDR5 field is once
@@ -312,14 +316,15 @@ struct marvell_nand_chip_sel {
 };
 
 /**
- * NAND chip structure: stores NAND chip device related information
+ * struct marvell_nand_chip - stores NAND chip device related information
  *
  * @chip:              Base NAND chip structure
  * @node:              Used to store NAND chips into a list
- * @layout             NAND layout when using hardware ECC
+ * @layout:            NAND layout when using hardware ECC
  * @ndcr:              Controller register value for this NAND chip
  * @ndtr0:             Timing registers 0 value for this NAND chip
  * @ndtr1:             Timing registers 1 value for this NAND chip
+ * @addr_cyc:          Amount of cycles needed to pass column address
  * @selected_die:      Current active CS
  * @nsels:             Number of CS lines required by the NAND chip
  * @sels:              Array of CS lines descriptions
@@ -349,7 +354,8 @@ static inline struct marvell_nand_chip_sel *to_nand_sel(struct marvell_nand_chip
 }
 
 /**
- * NAND controller capabilities for distinction between compatible strings
+ * struct marvell_nfc_caps - NAND controller capabilities for distinction
+ *                           between compatible strings
  *
  * @max_cs_nb:         Number of Chip Select lines available
  * @max_rb_nb:         Number of Ready/Busy lines available
@@ -372,7 +378,7 @@ struct marvell_nfc_caps {
 };
 
 /**
- * NAND controller structure: stores Marvell NAND controller information
+ * struct marvell_nfc - stores Marvell NAND controller information
  *
  * @controller:                Base controller structure
  * @dev:               Parent device (used to print error messages)
@@ -383,7 +389,9 @@ struct marvell_nfc_caps {
  * @assigned_cs:       Bitmask describing already assigned CS lines
  * @chips:             List containing all the NAND chips attached to
  *                     this NAND controller
+ * @selected_chip:     Currently selected target chip
  * @caps:              NAND controller capabilities for each compatible string
+ * @use_dma:           Whetner DMA is used
  * @dma_chan:          DMA channel (NFCv1 only)
  * @dma_buf:           32-bit aligned buffer for DMA transfers (NFCv1 only)
  */
@@ -411,7 +419,8 @@ static inline struct marvell_nfc *to_marvell_nfc(struct nand_controller *ctrl)
 }
 
 /**
- * NAND controller timings expressed in NAND Controller clock cycles
+ * struct marvell_nfc_timings - NAND controller timings expressed in NAND
+ *                              Controller clock cycles
  *
  * @tRP:               ND_nRE pulse width
  * @tRH:               ND_nRE high duration
@@ -455,8 +464,8 @@ struct marvell_nfc_timings {
                                                     period_ns))
 
 /**
- * NAND driver structure filled during the parsing of the ->exec_op() subop
- * subset of instructions.
+ * struct marvell_nfc_op - filled during the parsing of the ->exec_op()
+ *                         subop subset of instructions.
  *
  * @ndcb:              Array of values written to NDCBx registers
  * @cle_ale_delay_ns:  Optional delay after the last CMD or ADDR cycle
@@ -685,9 +694,31 @@ static int marvell_nfc_wait_cmdd(struct nand_chip *chip)
        return marvell_nfc_end_cmd(chip, cs_flag, "CMDD");
 }
 
+static int marvell_nfc_poll_status(struct marvell_nfc *nfc, u32 mask,
+                                  u32 expected_val, unsigned long timeout_ms)
+{
+       unsigned long limit;
+       u32 st;
+
+       limit = jiffies + msecs_to_jiffies(timeout_ms);
+       do {
+               st = readl_relaxed(nfc->regs + NDSR);
+               if (st & NDSR_RDY(1))
+                       st |= NDSR_RDY(0);
+
+               if ((st & mask) == expected_val)
+                       return 0;
+
+               cpu_relax();
+       } while (time_after(limit, jiffies));
+
+       return -ETIMEDOUT;
+}
+
 static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
 {
        struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        u32 pending;
        int ret;
 
@@ -695,12 +726,18 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
        if (!timeout_ms)
                timeout_ms = IRQ_TIMEOUT;
 
-       init_completion(&nfc->complete);
+       if (mtd->oops_panic_write) {
+               ret = marvell_nfc_poll_status(nfc, NDSR_RDY(0),
+                                             NDSR_RDY(0),
+                                             timeout_ms);
+       } else {
+               init_completion(&nfc->complete);
 
-       marvell_nfc_enable_int(nfc, NDCR_RDYM);
-       ret = wait_for_completion_timeout(&nfc->complete,
-                                         msecs_to_jiffies(timeout_ms));
-       marvell_nfc_disable_int(nfc, NDCR_RDYM);
+               marvell_nfc_enable_int(nfc, NDCR_RDYM);
+               ret = wait_for_completion_timeout(&nfc->complete,
+                                                 msecs_to_jiffies(timeout_ms));
+               marvell_nfc_disable_int(nfc, NDCR_RDYM);
+       }
        pending = marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1));
 
        /*
@@ -780,7 +817,7 @@ static void marvell_nfc_enable_hw_ecc(struct nand_chip *chip)
                 * When enabling BCH, set threshold to 0 to always know the
                 * number of corrected bitflips.
                 */
-               if (chip->ecc.algo == NAND_ECC_BCH)
+               if (chip->ecc.algo == NAND_ECC_ALGO_BCH)
                        writel_relaxed(NDECCCTRL_BCH_EN, nfc->regs + NDECCCTRL);
        }
 }
@@ -792,7 +829,7 @@ static void marvell_nfc_disable_hw_ecc(struct nand_chip *chip)
 
        if (ndcr & NDCR_ECC_EN) {
                writel_relaxed(ndcr & ~NDCR_ECC_EN, nfc->regs + NDCR);
-               if (chip->ecc.algo == NAND_ECC_BCH)
+               if (chip->ecc.algo == NAND_ECC_ALGO_BCH)
                        writel_relaxed(0, nfc->regs + NDECCCTRL);
        }
 }
@@ -966,7 +1003,7 @@ static int marvell_nfc_hw_ecc_check_bitflips(struct nand_chip *chip,
        if (ndsr & NDSR_CORERR) {
                writel_relaxed(ndsr, nfc->regs + NDSR);
 
-               if (chip->ecc.algo == NAND_ECC_BCH)
+               if (chip->ecc.algo == NAND_ECC_ALGO_BCH)
                        bf = NDSR_ERRCNT(ndsr);
                else
                        bf = 1;
@@ -2218,7 +2255,7 @@ static int marvell_nand_hw_ecc_controller_init(struct mtd_info *mtd,
        ecc->size = l->data_bytes;
 
        if (ecc->strength == 1) {
-               chip->ecc.algo = NAND_ECC_HAMMING;
+               chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
                ecc->read_page_raw = marvell_nfc_hw_ecc_hmg_read_page_raw;
                ecc->read_page = marvell_nfc_hw_ecc_hmg_read_page;
                ecc->read_oob_raw = marvell_nfc_hw_ecc_hmg_read_oob_raw;
@@ -2228,7 +2265,7 @@ static int marvell_nand_hw_ecc_controller_init(struct mtd_info *mtd,
                ecc->write_oob_raw = marvell_nfc_hw_ecc_hmg_write_oob_raw;
                ecc->write_oob = ecc->write_oob_raw;
        } else {
-               chip->ecc.algo = NAND_ECC_BCH;
+               chip->ecc.algo = NAND_ECC_ALGO_BCH;
                ecc->strength = 16;
                ecc->read_page_raw = marvell_nfc_hw_ecc_bch_read_page_raw;
                ecc->read_page = marvell_nfc_hw_ecc_bch_read_page;
@@ -2247,13 +2284,16 @@ static int marvell_nand_ecc_init(struct mtd_info *mtd,
                                 struct nand_ecc_ctrl *ecc)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(&chip->base);
        struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
        int ret;
 
-       if (ecc->mode != NAND_ECC_NONE && (!ecc->size || !ecc->strength)) {
-               if (chip->base.eccreq.step_size && chip->base.eccreq.strength) {
-                       ecc->size = chip->base.eccreq.step_size;
-                       ecc->strength = chip->base.eccreq.strength;
+       if (ecc->engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
+           (!ecc->size || !ecc->strength)) {
+               if (requirements->step_size && requirements->strength) {
+                       ecc->size = requirements->step_size;
+                       ecc->strength = requirements->strength;
                } else {
                        dev_info(nfc->dev,
                                 "No minimum ECC strength, using 1b/512B\n");
@@ -2262,15 +2302,15 @@ static int marvell_nand_ecc_init(struct mtd_info *mtd,
                }
        }
 
-       switch (ecc->mode) {
-       case NAND_ECC_HW:
+       switch (ecc->engine_type) {
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                ret = marvell_nand_hw_ecc_controller_init(mtd, ecc);
                if (ret)
                        return ret;
                break;
-       case NAND_ECC_NONE:
-       case NAND_ECC_SOFT:
-       case NAND_ECC_ON_DIE:
+       case NAND_ECC_ENGINE_TYPE_NONE:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
+       case NAND_ECC_ENGINE_TYPE_ON_DIE:
                if (!nfc->caps->is_nfcv2 && mtd->writesize != SZ_512 &&
                    mtd->writesize != SZ_2K) {
                        dev_err(nfc->dev, "NFCv1 cannot write %d bytes pages\n",
@@ -2467,7 +2507,7 @@ static int marvell_nand_attach_chip(struct nand_chip *chip)
                return ret;
        }
 
-       if (chip->ecc.mode == NAND_ECC_HW) {
+       if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) {
                /*
                 * Subpage write not available with hardware ECC, prohibit also
                 * subpage read as in userspace subpage access would still be
@@ -2642,7 +2682,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
         * Default to HW ECC engine mode. If the nand-ecc-mode property is given
         * in the DT node, this entry will be overwritten in nand_scan_ident().
         */
-       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
 
        /*
         * Save a reference value for timing registers before
@@ -2759,10 +2799,7 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
        if (IS_ERR(nfc->dma_chan)) {
                ret = PTR_ERR(nfc->dma_chan);
                nfc->dma_chan = NULL;
-               if (ret != -EPROBE_DEFER)
-                       dev_err(nfc->dev, "DMA channel request failed: %d\n",
-                               ret);
-               return ret;
+               return dev_err_probe(nfc->dev, ret, "DMA channel request failed\n");
        }
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 0e5829a..48e6dac 100644 (file)
@@ -1197,7 +1197,7 @@ static int meson_nand_attach_chip(struct nand_chip *nand)
        if (ret)
                return -EINVAL;
 
-       nand->ecc.mode = NAND_ECC_HW;
+       nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        nand->ecc.write_page_raw = meson_nfc_write_page_raw;
        nand->ecc.write_page = meson_nfc_write_page_hwecc;
        nand->ecc.write_oob_raw = nand_write_oob_std;
index 18ecb09..dfd0d3e 100644 (file)
@@ -688,8 +688,8 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        chip->legacy.set_features = nand_get_set_features_notsupp;
        chip->legacy.get_features = nand_get_set_features_notsupp;
        chip->bbt_options = NAND_BBT_USE_FLASH;
-       chip->ecc.mode = NAND_ECC_SOFT;
-       chip->ecc.algo = NAND_ECC_HAMMING;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
 
        /* Support external chip-select logic on ADS5121 board */
        if (of_machine_is_compatible("fsl,mpc5121ads")) {
index ad1b55d..57f1f17 100644 (file)
@@ -1253,21 +1253,23 @@ static int mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
 static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(&nand->base);
        struct mtk_nfc *nfc = nand_get_controller_data(nand);
        u32 spare;
        int free, ret;
 
        /* support only ecc hw mode */
-       if (nand->ecc.mode != NAND_ECC_HW) {
-               dev_err(dev, "ecc.mode not supported\n");
+       if (nand->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) {
+               dev_err(dev, "ecc.engine_type not supported\n");
                return -EINVAL;
        }
 
        /* if optional dt settings not present */
        if (!nand->ecc.size || !nand->ecc.strength) {
                /* use datasheet requirements */
-               nand->ecc.strength = nand->base.eccreq.strength;
-               nand->ecc.size = nand->base.eccreq.step_size;
+               nand->ecc.strength = requirements->strength;
+               nand->ecc.size = requirements->step_size;
 
                /*
                 * align eccstrength and eccsize
@@ -1416,7 +1418,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
        nand->options |= NAND_USES_DMA | NAND_SUBPAGE_READ;
 
        /* set default mode in case dt entry is missing */
-       nand->ecc.mode = NAND_ECC_HW;
+       nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
 
        nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
        nand->ecc.write_page_raw = mtk_nfc_write_page_raw;
index a043d76..d4200eb 100644 (file)
@@ -669,7 +669,7 @@ static void mxc_nand_enable_hwecc_v1_v2(struct nand_chip *chip, bool enable)
        struct mxc_nand_host *host = nand_get_controller_data(chip);
        uint16_t config1;
 
-       if (chip->ecc.mode != NAND_ECC_HW)
+       if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
                return;
 
        config1 = readw(NFC_V1_V2_CONFIG1);
@@ -687,7 +687,7 @@ static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable)
        struct mxc_nand_host *host = nand_get_controller_data(chip);
        uint32_t config2;
 
-       if (chip->ecc.mode != NAND_ECC_HW)
+       if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
                return;
 
        config2 = readl(NFC_V3_CONFIG2);
@@ -1117,7 +1117,8 @@ static void preset_v1(struct mtd_info *mtd)
        struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
        uint16_t config1 = 0;
 
-       if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize)
+       if (nand_chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST &&
+           mtd->writesize)
                config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
 
        if (!host->devtype_data->irqpending_quirk)
@@ -1227,7 +1228,7 @@ static void preset_v2(struct mtd_info *mtd)
        if (mtd->writesize) {
                uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
 
-               if (nand_chip->ecc.mode == NAND_ECC_HW)
+               if (nand_chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
                        config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
 
                host->eccsize = get_eccsize(mtd);
@@ -1303,7 +1304,7 @@ static void preset_v3(struct mtd_info *mtd)
        }
 
        if (mtd->writesize) {
-               if (chip->ecc.mode == NAND_ECC_HW)
+               if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
                        config2 |= NFC_V3_CONFIG2_ECC_EN;
 
                config2 |= NFC_V3_CONFIG2_PPB(
@@ -1680,8 +1681,8 @@ static int mxcnd_attach_chip(struct nand_chip *chip)
        struct mxc_nand_host *host = nand_get_controller_data(chip);
        struct device *dev = mtd->dev.parent;
 
-       switch (chip->ecc.mode) {
-       case NAND_ECC_HW:
+       switch (chip->ecc.engine_type) {
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                chip->ecc.read_page = mxc_nand_read_page;
                chip->ecc.read_page_raw = mxc_nand_read_page_raw;
                chip->ecc.read_oob = mxc_nand_read_oob;
@@ -1690,7 +1691,7 @@ static int mxcnd_attach_chip(struct nand_chip *chip)
                chip->ecc.write_oob = mxc_nand_write_oob;
                break;
 
-       case NAND_ECC_SOFT:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
                break;
 
        default:
@@ -1728,7 +1729,7 @@ static int mxcnd_attach_chip(struct nand_chip *chip)
         */
        host->used_oobsize = min(mtd->oobsize, 218U);
 
-       if (chip->ecc.mode == NAND_ECC_HW) {
+       if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) {
                if (is_imx21_nfc(host) || is_imx27_nfc(host))
                        chip->ecc.strength = 1;
                else
@@ -1843,10 +1844,10 @@ static int mxcnd_probe(struct platform_device *pdev)
        mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
 
        if (host->pdata.hw_ecc) {
-               this->ecc.mode = NAND_ECC_HW;
+               this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        } else {
-               this->ecc.mode = NAND_ECC_SOFT;
-               this->ecc.algo = NAND_ECC_HAMMING;
+               this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+               this->ecc.algo = NAND_ECC_ALGO_HAMMING;
        }
 
        /* NAND bus width determines access functions used by upper layer */
index 0c768cb..1f0d542 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/mm.h>
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/nand_bch.h>
 #include <linux/interrupt.h>
 
 #include "internals.h"
 
-/* Define default oob placement schemes for large and small page devices */
-static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
-                                struct mtd_oob_region *oobregion)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-       if (section > 1)
-               return -ERANGE;
-
-       if (!section) {
-               oobregion->offset = 0;
-               if (mtd->oobsize == 16)
-                       oobregion->length = 4;
-               else
-                       oobregion->length = 3;
-       } else {
-               if (mtd->oobsize == 8)
-                       return -ERANGE;
-
-               oobregion->offset = 6;
-               oobregion->length = ecc->total - 4;
-       }
-
-       return 0;
-}
-
-static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
-                                 struct mtd_oob_region *oobregion)
-{
-       if (section > 1)
-               return -ERANGE;
-
-       if (mtd->oobsize == 16) {
-               if (section)
-                       return -ERANGE;
-
-               oobregion->length = 8;
-               oobregion->offset = 8;
-       } else {
-               oobregion->length = 2;
-               if (!section)
-                       oobregion->offset = 3;
-               else
-                       oobregion->offset = 6;
-       }
-
-       return 0;
-}
-
-const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
-       .ecc = nand_ooblayout_ecc_sp,
-       .free = nand_ooblayout_free_sp,
-};
-EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops);
-
-static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
-                                struct mtd_oob_region *oobregion)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-       if (section || !ecc->total)
-               return -ERANGE;
-
-       oobregion->length = ecc->total;
-       oobregion->offset = mtd->oobsize - oobregion->length;
-
-       return 0;
-}
-
-static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
-                                 struct mtd_oob_region *oobregion)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-       if (section)
-               return -ERANGE;
-
-       oobregion->length = mtd->oobsize - ecc->total - 2;
-       oobregion->offset = 2;
-
-       return 0;
-}
-
-const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
-       .ecc = nand_ooblayout_ecc_lp,
-       .free = nand_ooblayout_free_lp,
-};
-EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
-
-/*
- * Support the old "large page" layout used for 1-bit Hamming ECC where ECC
- * are placed at a fixed offset.
- */
-static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
-                                        struct mtd_oob_region *oobregion)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct nand_ecc_ctrl *ecc = &chip->ecc;
-
-       if (section)
-               return -ERANGE;
-
-       switch (mtd->oobsize) {
-       case 64:
-               oobregion->offset = 40;
-               break;
-       case 128:
-               oobregion->offset = 80;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       oobregion->length = ecc->total;
-       if (oobregion->offset + oobregion->length > mtd->oobsize)
-               return -ERANGE;
-
-       return 0;
-}
-
-static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
-                                         struct mtd_oob_region *oobregion)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct nand_ecc_ctrl *ecc = &chip->ecc;
-       int ecc_offset = 0;
-
-       if (section < 0 || section > 1)
-               return -ERANGE;
-
-       switch (mtd->oobsize) {
-       case 64:
-               ecc_offset = 40;
-               break;
-       case 128:
-               ecc_offset = 80;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (section == 0) {
-               oobregion->offset = 2;
-               oobregion->length = ecc_offset - 2;
-       } else {
-               oobregion->offset = ecc_offset + ecc->total;
-               oobregion->length = mtd->oobsize - oobregion->offset;
-       }
-
-       return 0;
-}
-
-static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
-       .ecc = nand_ooblayout_ecc_lp_hamming,
-       .free = nand_ooblayout_free_lp_hamming,
-};
-
 static int nand_pairing_dist3_get_info(struct mtd_info *mtd, int page,
                                       struct mtd_pairing_info *info)
 {
@@ -4750,6 +4591,8 @@ static inline bool is_full_id_nand(struct nand_flash_dev *type)
 static bool find_full_id_nand(struct nand_chip *chip,
                              struct nand_flash_dev *type)
 {
+       struct nand_device *base = &chip->base;
+       struct nand_ecc_props requirements;
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_memory_organization *memorg;
        u8 *id_data = chip->id.data;
@@ -4771,8 +4614,9 @@ static bool find_full_id_nand(struct nand_chip *chip,
                                           memorg->pagesize *
                                           memorg->pages_per_eraseblock);
                chip->options |= type->options;
-               chip->base.eccreq.strength = NAND_ECC_STRENGTH(type);
-               chip->base.eccreq.step_size = NAND_ECC_STEP(type);
+               requirements.strength = NAND_ECC_STRENGTH(type);
+               requirements.step_size = NAND_ECC_STEP(type);
+               nanddev_set_ecc_requirements(base, &requirements);
 
                chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
                if (!chip->parameters.model)
@@ -5033,91 +4877,101 @@ free_detect_allocation:
        return ret;
 }
 
-static const char * const nand_ecc_modes[] = {
-       [NAND_ECC_NONE]         = "none",
-       [NAND_ECC_SOFT]         = "soft",
-       [NAND_ECC_HW]           = "hw",
-       [NAND_ECC_HW_SYNDROME]  = "hw_syndrome",
-       [NAND_ECC_ON_DIE]       = "on-die",
-};
-
-static int of_get_nand_ecc_mode(struct device_node *np)
+static enum nand_ecc_engine_type
+of_get_rawnand_ecc_engine_type_legacy(struct device_node *np)
 {
+       enum nand_ecc_legacy_mode {
+               NAND_ECC_INVALID,
+               NAND_ECC_NONE,
+               NAND_ECC_SOFT,
+               NAND_ECC_SOFT_BCH,
+               NAND_ECC_HW,
+               NAND_ECC_HW_SYNDROME,
+               NAND_ECC_ON_DIE,
+       };
+       const char * const nand_ecc_legacy_modes[] = {
+               [NAND_ECC_NONE]         = "none",
+               [NAND_ECC_SOFT]         = "soft",
+               [NAND_ECC_SOFT_BCH]     = "soft_bch",
+               [NAND_ECC_HW]           = "hw",
+               [NAND_ECC_HW_SYNDROME]  = "hw_syndrome",
+               [NAND_ECC_ON_DIE]       = "on-die",
+       };
+       enum nand_ecc_legacy_mode eng_type;
        const char *pm;
-       int err, i;
+       int err;
 
        err = of_property_read_string(np, "nand-ecc-mode", &pm);
-       if (err < 0)
-               return err;
-
-       for (i = NAND_ECC_NONE; i < ARRAY_SIZE(nand_ecc_modes); i++)
-               if (!strcasecmp(pm, nand_ecc_modes[i]))
-                       return i;
-
-       /*
-        * For backward compatibility we support few obsoleted values that don't
-        * have their mappings into the nand_ecc_mode enum anymore (they were
-        * merged with other enums).
-        */
-       if (!strcasecmp(pm, "soft_bch"))
-               return NAND_ECC_SOFT;
+       if (err)
+               return NAND_ECC_ENGINE_TYPE_INVALID;
+
+       for (eng_type = NAND_ECC_NONE;
+            eng_type < ARRAY_SIZE(nand_ecc_legacy_modes); eng_type++) {
+               if (!strcasecmp(pm, nand_ecc_legacy_modes[eng_type])) {
+                       switch (eng_type) {
+                       case NAND_ECC_NONE:
+                               return NAND_ECC_ENGINE_TYPE_NONE;
+                       case NAND_ECC_SOFT:
+                       case NAND_ECC_SOFT_BCH:
+                               return NAND_ECC_ENGINE_TYPE_SOFT;
+                       case NAND_ECC_HW:
+                       case NAND_ECC_HW_SYNDROME:
+                               return NAND_ECC_ENGINE_TYPE_ON_HOST;
+                       case NAND_ECC_ON_DIE:
+                               return NAND_ECC_ENGINE_TYPE_ON_DIE;
+                       default:
+                               break;
+                       }
+               }
+       }
 
-       return -ENODEV;
+       return NAND_ECC_ENGINE_TYPE_INVALID;
 }
 
-static const char * const nand_ecc_algos[] = {
-       [NAND_ECC_HAMMING]      = "hamming",
-       [NAND_ECC_BCH]          = "bch",
-       [NAND_ECC_RS]           = "rs",
-};
-
-static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
+static enum nand_ecc_placement
+of_get_rawnand_ecc_placement_legacy(struct device_node *np)
 {
-       enum nand_ecc_algo ecc_algo;
        const char *pm;
        int err;
 
-       err = of_property_read_string(np, "nand-ecc-algo", &pm);
+       err = of_property_read_string(np, "nand-ecc-mode", &pm);
        if (!err) {
-               for (ecc_algo = NAND_ECC_HAMMING;
-                    ecc_algo < ARRAY_SIZE(nand_ecc_algos);
-                    ecc_algo++) {
-                       if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
-                               return ecc_algo;
-               }
+               if (!strcasecmp(pm, "hw_syndrome"))
+                       return NAND_ECC_PLACEMENT_INTERLEAVED;
        }
 
-       /*
-        * For backward compatibility we also read "nand-ecc-mode" checking
-        * for some obsoleted values that were specifying ECC algorithm.
-        */
+       return NAND_ECC_PLACEMENT_UNKNOWN;
+}
+
+static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np)
+{
+       const char *pm;
+       int err;
+
        err = of_property_read_string(np, "nand-ecc-mode", &pm);
        if (!err) {
                if (!strcasecmp(pm, "soft"))
-                       return NAND_ECC_HAMMING;
+                       return NAND_ECC_ALGO_HAMMING;
                else if (!strcasecmp(pm, "soft_bch"))
-                       return NAND_ECC_BCH;
+                       return NAND_ECC_ALGO_BCH;
        }
 
-       return NAND_ECC_UNKNOWN;
+       return NAND_ECC_ALGO_UNKNOWN;
 }
 
-static int of_get_nand_ecc_step_size(struct device_node *np)
+static void of_get_nand_ecc_legacy_user_config(struct nand_chip *chip)
 {
-       int ret;
-       u32 val;
+       struct device_node *dn = nand_get_flash_node(chip);
+       struct nand_ecc_props *user_conf = &chip->base.ecc.user_conf;
 
-       ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
-       return ret ? ret : val;
-}
+       if (user_conf->engine_type == NAND_ECC_ENGINE_TYPE_INVALID)
+               user_conf->engine_type = of_get_rawnand_ecc_engine_type_legacy(dn);
 
-static int of_get_nand_ecc_strength(struct device_node *np)
-{
-       int ret;
-       u32 val;
+       if (user_conf->algo == NAND_ECC_ALGO_UNKNOWN)
+               user_conf->algo = of_get_rawnand_ecc_algo_legacy(dn);
 
-       ret = of_property_read_u32(np, "nand-ecc-strength", &val);
-       return ret ? ret : val;
+       if (user_conf->placement == NAND_ECC_PLACEMENT_UNKNOWN)
+               user_conf->placement = of_get_rawnand_ecc_placement_legacy(dn);
 }
 
 static int of_get_nand_bus_width(struct device_node *np)
@@ -5141,11 +4995,10 @@ static bool of_get_nand_on_flash_bbt(struct device_node *np)
        return of_property_read_bool(np, "nand-on-flash-bbt");
 }
 
-static int nand_dt_init(struct nand_chip *chip)
+static int rawnand_dt_init(struct nand_chip *chip)
 {
+       struct nand_device *nand = mtd_to_nanddev(nand_to_mtd(chip));
        struct device_node *dn = nand_get_flash_node(chip);
-       enum nand_ecc_algo ecc_algo;
-       int ecc_mode, ecc_strength, ecc_step;
 
        if (!dn)
                return 0;
@@ -5159,25 +5012,29 @@ static int nand_dt_init(struct nand_chip *chip)
        if (of_get_nand_on_flash_bbt(dn))
                chip->bbt_options |= NAND_BBT_USE_FLASH;
 
-       ecc_mode = of_get_nand_ecc_mode(dn);
-       ecc_algo = of_get_nand_ecc_algo(dn);
-       ecc_strength = of_get_nand_ecc_strength(dn);
-       ecc_step = of_get_nand_ecc_step_size(dn);
-
-       if (ecc_mode >= 0)
-               chip->ecc.mode = ecc_mode;
+       of_get_nand_ecc_user_config(nand);
+       of_get_nand_ecc_legacy_user_config(chip);
 
-       if (ecc_algo != NAND_ECC_UNKNOWN)
-               chip->ecc.algo = ecc_algo;
-
-       if (ecc_strength >= 0)
-               chip->ecc.strength = ecc_strength;
+       /*
+        * If neither the user nor the NAND controller have requested a specific
+        * ECC engine type, we will default to NAND_ECC_ENGINE_TYPE_ON_HOST.
+        */
+       nand->ecc.defaults.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
 
-       if (ecc_step > 0)
-               chip->ecc.size = ecc_step;
+       /*
+        * Use the user requested engine type, unless there is none, in this
+        * case default to the NAND controller choice, otherwise fallback to
+        * the raw NAND default one.
+        */
+       if (nand->ecc.user_conf.engine_type != NAND_ECC_ENGINE_TYPE_INVALID)
+               chip->ecc.engine_type = nand->ecc.user_conf.engine_type;
+       if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_INVALID)
+               chip->ecc.engine_type = nand->ecc.defaults.engine_type;
 
-       if (of_property_read_bool(dn, "nand-ecc-maximize"))
-               chip->ecc.options |= NAND_ECC_MAXIMIZE;
+       chip->ecc.placement = nand->ecc.user_conf.placement;
+       chip->ecc.algo = nand->ecc.user_conf.algo;
+       chip->ecc.strength = nand->ecc.user_conf.strength;
+       chip->ecc.size = nand->ecc.user_conf.step_size;
 
        return 0;
 }
@@ -5215,7 +5072,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
        /* Enforce the right timings for reset/detection */
        chip->current_interface_config = nand_get_reset_interface_config();
 
-       ret = nand_dt_init(chip);
+       ret = rawnand_dt_init(chip);
        if (ret)
                return ret;
 
@@ -5282,16 +5139,76 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip)
        kfree(chip->parameters.onfi);
 }
 
+static int nand_set_ecc_on_host_ops(struct nand_chip *chip)
+{
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       switch (ecc->placement) {
+       case NAND_ECC_PLACEMENT_UNKNOWN:
+       case NAND_ECC_PLACEMENT_OOB:
+               /* Use standard hwecc read page function? */
+               if (!ecc->read_page)
+                       ecc->read_page = nand_read_page_hwecc;
+               if (!ecc->write_page)
+                       ecc->write_page = nand_write_page_hwecc;
+               if (!ecc->read_page_raw)
+                       ecc->read_page_raw = nand_read_page_raw;
+               if (!ecc->write_page_raw)
+                       ecc->write_page_raw = nand_write_page_raw;
+               if (!ecc->read_oob)
+                       ecc->read_oob = nand_read_oob_std;
+               if (!ecc->write_oob)
+                       ecc->write_oob = nand_write_oob_std;
+               if (!ecc->read_subpage)
+                       ecc->read_subpage = nand_read_subpage;
+               if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
+                       ecc->write_subpage = nand_write_subpage_hwecc;
+               fallthrough;
+
+       case NAND_ECC_PLACEMENT_INTERLEAVED:
+               if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
+                   (!ecc->read_page ||
+                    ecc->read_page == nand_read_page_hwecc ||
+                    !ecc->write_page ||
+                    ecc->write_page == nand_write_page_hwecc)) {
+                       WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
+                       return -EINVAL;
+               }
+               /* Use standard syndrome read/write page function? */
+               if (!ecc->read_page)
+                       ecc->read_page = nand_read_page_syndrome;
+               if (!ecc->write_page)
+                       ecc->write_page = nand_write_page_syndrome;
+               if (!ecc->read_page_raw)
+                       ecc->read_page_raw = nand_read_page_raw_syndrome;
+               if (!ecc->write_page_raw)
+                       ecc->write_page_raw = nand_write_page_raw_syndrome;
+               if (!ecc->read_oob)
+                       ecc->read_oob = nand_read_oob_syndrome;
+               if (!ecc->write_oob)
+                       ecc->write_oob = nand_write_oob_syndrome;
+               break;
+
+       default:
+               pr_warn("Invalid NAND_ECC_PLACEMENT %d\n",
+                       ecc->placement);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int nand_set_ecc_soft_ops(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_device *nanddev = mtd_to_nanddev(mtd);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
 
-       if (WARN_ON(ecc->mode != NAND_ECC_SOFT))
+       if (WARN_ON(ecc->engine_type != NAND_ECC_ENGINE_TYPE_SOFT))
                return -EINVAL;
 
        switch (ecc->algo) {
-       case NAND_ECC_HAMMING:
+       case NAND_ECC_ALGO_HAMMING:
                ecc->calculate = nand_calculate_ecc;
                ecc->correct = nand_correct_data;
                ecc->read_page = nand_read_page_swecc;
@@ -5312,7 +5229,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
                        ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
 
                return 0;
-       case NAND_ECC_BCH:
+       case NAND_ECC_ALGO_BCH:
                if (!mtd_nand_has_bch()) {
                        WARN(1, "CONFIG_MTD_NAND_ECC_SW_BCH not enabled\n");
                        return -EINVAL;
@@ -5350,7 +5267,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
                                return -EINVAL;
                        }
 
-                       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+                       mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
 
                }
 
@@ -5359,8 +5276,8 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
                 * used, otherwise we don't know how many bytes can really be
                 * used.
                 */
-               if (mtd->ooblayout == &nand_ooblayout_lp_ops &&
-                   ecc->options & NAND_ECC_MAXIMIZE) {
+               if (mtd->ooblayout == nand_get_large_page_ooblayout() &&
+                   nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) {
                        int steps, bytes;
 
                        /* Always prefer 1k blocks over 512bytes ones */
@@ -5454,10 +5371,12 @@ static int
 nand_match_ecc_req(struct nand_chip *chip,
                   const struct nand_ecc_caps *caps, int oobavail)
 {
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(&chip->base);
        struct mtd_info *mtd = nand_to_mtd(chip);
        const struct nand_ecc_step_info *stepinfo;
-       int req_step = chip->base.eccreq.step_size;
-       int req_strength = chip->base.eccreq.strength;
+       int req_step = requirements->step_size;
+       int req_strength = requirements->strength;
        int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
        int best_step, best_strength, best_ecc_bytes;
        int best_ecc_bytes_total = INT_MAX;
@@ -5598,11 +5517,12 @@ nand_maximize_ecc(struct nand_chip *chip,
  * @caps: ECC engine caps info structure
  * @oobavail: OOB size that the ECC engine can use
  *
- * Choose the ECC configuration according to following logic
+ * Choose the ECC configuration according to following logic.
  *
  * 1. If both ECC step size and ECC strength are already set (usually by DT)
  *    then check if it is supported by this controller.
- * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
+ * 2. If the user provided the nand-ecc-maximize property, then select maximum
+ *    ECC strength.
  * 3. Otherwise, try to match the ECC step size and ECC strength closest
  *    to the chip's requirement. If available OOB size can't fit the chip
  *    requirement then fallback to the maximum ECC step size and ECC strength.
@@ -5613,6 +5533,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
                         const struct nand_ecc_caps *caps, int oobavail)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_device *nanddev = mtd_to_nanddev(mtd);
 
        if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize))
                return -EINVAL;
@@ -5620,7 +5541,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
        if (chip->ecc.size && chip->ecc.strength)
                return nand_check_ecc_caps(chip, caps, oobavail);
 
-       if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+       if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH)
                return nand_maximize_ecc(chip, caps, oobavail);
 
        if (!nand_match_ecc_req(chip, caps, oobavail))
@@ -5630,41 +5551,6 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
 }
 EXPORT_SYMBOL_GPL(nand_ecc_choose_conf);
 
-/*
- * Check if the chip configuration meet the datasheet requirements.
-
- * If our configuration corrects A bits per B bytes and the minimum
- * required correction level is X bits per Y bytes, then we must ensure
- * both of the following are true:
- *
- * (1) A / B >= X / Y
- * (2) A >= X
- *
- * Requirement (1) ensures we can correct for the required bitflip density.
- * Requirement (2) ensures we can correct even when all bitflips are clumped
- * in the same sector.
- */
-static bool nand_ecc_strength_good(struct nand_chip *chip)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct nand_ecc_ctrl *ecc = &chip->ecc;
-       int corr, ds_corr;
-
-       if (ecc->size == 0 || chip->base.eccreq.step_size == 0)
-               /* Not enough information */
-               return true;
-
-       /*
-        * We get the number of corrected bits per page to compare
-        * the correction density.
-        */
-       corr = (mtd->writesize * ecc->strength) / ecc->size;
-       ds_corr = (mtd->writesize * chip->base.eccreq.strength) /
-                 chip->base.eccreq.step_size;
-
-       return corr >= ds_corr && ecc->strength >= chip->base.eccreq.strength;
-}
-
 static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos)
 {
        struct nand_chip *chip = container_of(nand, struct nand_chip,
@@ -5752,15 +5638,17 @@ static int nand_scan_tail(struct nand_chip *chip)
         * If no default placement scheme is given, select an appropriate one.
         */
        if (!mtd->ooblayout &&
-           !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_BCH)) {
+           !(ecc->engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
+             ecc->algo == NAND_ECC_ALGO_BCH)) {
                switch (mtd->oobsize) {
                case 8:
                case 16:
-                       mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
+                       mtd_set_ooblayout(mtd, nand_get_small_page_ooblayout());
                        break;
                case 64:
                case 128:
-                       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops);
+                       mtd_set_ooblayout(mtd,
+                                         nand_get_large_page_hamming_ooblayout());
                        break;
                default:
                        /*
@@ -5770,9 +5658,9 @@ static int nand_scan_tail(struct nand_chip *chip)
                         * page with ECC layout when ->oobsize <= 128 for
                         * compatibility reasons.
                         */
-                       if (ecc->mode == NAND_ECC_NONE) {
+                       if (ecc->engine_type == NAND_ECC_ENGINE_TYPE_NONE) {
                                mtd_set_ooblayout(mtd,
-                                               &nand_ooblayout_lp_ops);
+                                                 nand_get_large_page_ooblayout());
                                break;
                        }
 
@@ -5788,49 +5676,11 @@ static int nand_scan_tail(struct nand_chip *chip)
         * selected and we have 256 byte pagesize fallback to software ECC
         */
 
-       switch (ecc->mode) {
-       case NAND_ECC_HW:
-               /* Use standard hwecc read page function? */
-               if (!ecc->read_page)
-                       ecc->read_page = nand_read_page_hwecc;
-               if (!ecc->write_page)
-                       ecc->write_page = nand_write_page_hwecc;
-               if (!ecc->read_page_raw)
-                       ecc->read_page_raw = nand_read_page_raw;
-               if (!ecc->write_page_raw)
-                       ecc->write_page_raw = nand_write_page_raw;
-               if (!ecc->read_oob)
-                       ecc->read_oob = nand_read_oob_std;
-               if (!ecc->write_oob)
-                       ecc->write_oob = nand_write_oob_std;
-               if (!ecc->read_subpage)
-                       ecc->read_subpage = nand_read_subpage;
-               if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
-                       ecc->write_subpage = nand_write_subpage_hwecc;
-               fallthrough;
-       case NAND_ECC_HW_SYNDROME:
-               if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
-                   (!ecc->read_page ||
-                    ecc->read_page == nand_read_page_hwecc ||
-                    !ecc->write_page ||
-                    ecc->write_page == nand_write_page_hwecc)) {
-                       WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
-                       ret = -EINVAL;
+       switch (ecc->engine_type) {
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
+               ret = nand_set_ecc_on_host_ops(chip);
+               if (ret)
                        goto err_nand_manuf_cleanup;
-               }
-               /* Use standard syndrome read/write page function? */
-               if (!ecc->read_page)
-                       ecc->read_page = nand_read_page_syndrome;
-               if (!ecc->write_page)
-                       ecc->write_page = nand_write_page_syndrome;
-               if (!ecc->read_page_raw)
-                       ecc->read_page_raw = nand_read_page_raw_syndrome;
-               if (!ecc->write_page_raw)
-                       ecc->write_page_raw = nand_write_page_raw_syndrome;
-               if (!ecc->read_oob)
-                       ecc->read_oob = nand_read_oob_syndrome;
-               if (!ecc->write_oob)
-                       ecc->write_oob = nand_write_oob_syndrome;
 
                if (mtd->writesize >= ecc->size) {
                        if (!ecc->strength) {
@@ -5842,18 +5692,17 @@ static int nand_scan_tail(struct nand_chip *chip)
                }
                pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
                        ecc->size, mtd->writesize);
-               ecc->mode = NAND_ECC_SOFT;
-               ecc->algo = NAND_ECC_HAMMING;
+               ecc->engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+               ecc->algo = NAND_ECC_ALGO_HAMMING;
                fallthrough;
-       case NAND_ECC_SOFT:
+
+       case NAND_ECC_ENGINE_TYPE_SOFT:
                ret = nand_set_ecc_soft_ops(chip);
-               if (ret) {
-                       ret = -EINVAL;
+               if (ret)
                        goto err_nand_manuf_cleanup;
-               }
                break;
 
-       case NAND_ECC_ON_DIE:
+       case NAND_ECC_ENGINE_TYPE_ON_DIE:
                if (!ecc->read_page || !ecc->write_page) {
                        WARN(1, "No ECC functions supplied; on-die ECC not possible\n");
                        ret = -EINVAL;
@@ -5865,8 +5714,8 @@ static int nand_scan_tail(struct nand_chip *chip)
                        ecc->write_oob = nand_write_oob_std;
                break;
 
-       case NAND_ECC_NONE:
-               pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n");
+       case NAND_ECC_ENGINE_TYPE_NONE:
+               pr_warn("NAND_ECC_ENGINE_TYPE_NONE selected by board driver. This is not recommended!\n");
                ecc->read_page = nand_read_page_raw;
                ecc->write_page = nand_write_page_raw;
                ecc->read_oob = nand_read_oob_std;
@@ -5879,7 +5728,7 @@ static int nand_scan_tail(struct nand_chip *chip)
                break;
 
        default:
-               WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->mode);
+               WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->engine_type);
                ret = -EINVAL;
                goto err_nand_manuf_cleanup;
        }
@@ -5913,7 +5762,10 @@ static int nand_scan_tail(struct nand_chip *chip)
                ret = -EINVAL;
                goto err_nand_manuf_cleanup;
        }
+
        ecc->total = ecc->steps * ecc->bytes;
+       chip->base.ecc.ctx.total = ecc->total;
+
        if (ecc->total > mtd->oobsize) {
                WARN(1, "Total number of ECC bytes exceeded oobsize\n");
                ret = -EINVAL;
@@ -5931,11 +5783,11 @@ static int nand_scan_tail(struct nand_chip *chip)
        mtd->oobavail = ret;
 
        /* ECC sanity check: warn if it's too weak */
-       if (!nand_ecc_strength_good(chip))
+       if (!nand_ecc_is_strong_enough(&chip->base))
                pr_warn("WARNING: %s: the ECC used on your system (%db/%dB) is too weak compared to the one required by the NAND chip (%db/%dB)\n",
                        mtd->name, chip->ecc.strength, chip->ecc.size,
-                       chip->base.eccreq.strength,
-                       chip->base.eccreq.step_size);
+                       nanddev_get_ecc_requirements(&chip->base)->strength,
+                       nanddev_get_ecc_requirements(&chip->base)->step_size);
 
        /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
        if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
@@ -5956,8 +5808,8 @@ static int nand_scan_tail(struct nand_chip *chip)
        chip->pagecache.page = -1;
 
        /* Large page NAND with SOFT_ECC should support subpage reads */
-       switch (ecc->mode) {
-       case NAND_ECC_SOFT:
+       switch (ecc->engine_type) {
+       case NAND_ECC_ENGINE_TYPE_SOFT:
                if (chip->page_shift > 9)
                        chip->options |= NAND_SUBPAGE_READ;
                break;
@@ -6101,8 +5953,8 @@ EXPORT_SYMBOL(nand_scan_with_ids);
  */
 void nand_cleanup(struct nand_chip *chip)
 {
-       if (chip->ecc.mode == NAND_ECC_SOFT &&
-           chip->ecc.algo == NAND_ECC_BCH)
+       if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&
+           chip->ecc.algo == NAND_ECC_ALGO_BCH)
                nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
 
        nanddev_cleanup(&chip->base);
index d5af8c5..9d19ac1 100644 (file)
@@ -165,6 +165,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
         */
        nand->ecc.steps = eccsteps;
        nand->ecc.total = eccsteps * eccbytes;
+       nand->base.ecc.ctx.total = nand->ecc.total;
        if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
                pr_warn("invalid ecc layout\n");
                goto fail;
index 3338c68..4412c40 100644 (file)
 
 static void esmt_nand_decode_id(struct nand_chip *chip)
 {
+       struct nand_device *base = &chip->base;
+       struct nand_ecc_props requirements = {};
+
        nand_decode_ext_id(chip);
 
        /* Extract ECC requirements from 5th id byte. */
        if (chip->id.len >= 5 && nand_is_slc(chip)) {
-               chip->base.eccreq.step_size = 512;
+               requirements.step_size = 512;
                switch (chip->id.data[4] & 0x3) {
                case 0x0:
-                       chip->base.eccreq.strength = 4;
+                       requirements.strength = 4;
                        break;
                case 0x1:
-                       chip->base.eccreq.strength = 2;
+                       requirements.strength = 2;
                        break;
                case 0x2:
-                       chip->base.eccreq.strength = 1;
+                       requirements.strength = 1;
                        break;
                default:
                        WARN(1, "Could not get ECC info");
-                       chip->base.eccreq.step_size = 0;
+                       requirements.step_size = 0;
                        break;
                }
        }
+
+       nanddev_set_ecc_requirements(base, &requirements);
 }
 
 static int esmt_nand_init(struct nand_chip *chip)
index 6d08eb8..a9f50c9 100644 (file)
@@ -495,34 +495,36 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
 static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
                                                bool valid_jedecid)
 {
+       struct nand_device *base = &chip->base;
+       struct nand_ecc_props requirements = {};
        u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
 
        if (valid_jedecid) {
                /* Reference: H27UCG8T2E datasheet */
-               chip->base.eccreq.step_size = 1024;
+               requirements.step_size = 1024;
 
                switch (ecc_level) {
                case 0:
-                       chip->base.eccreq.step_size = 0;
-                       chip->base.eccreq.strength = 0;
+                       requirements.step_size = 0;
+                       requirements.strength = 0;
                        break;
                case 1:
-                       chip->base.eccreq.strength = 4;
+                       requirements.strength = 4;
                        break;
                case 2:
-                       chip->base.eccreq.strength = 24;
+                       requirements.strength = 24;
                        break;
                case 3:
-                       chip->base.eccreq.strength = 32;
+                       requirements.strength = 32;
                        break;
                case 4:
-                       chip->base.eccreq.strength = 40;
+                       requirements.strength = 40;
                        break;
                case 5:
-                       chip->base.eccreq.strength = 50;
+                       requirements.strength = 50;
                        break;
                case 6:
-                       chip->base.eccreq.strength = 60;
+                       requirements.strength = 60;
                        break;
                default:
                        /*
@@ -543,14 +545,14 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
                if (nand_tech < 3) {
                        /* > 26nm, reference: H27UBG8T2A datasheet */
                        if (ecc_level < 5) {
-                               chip->base.eccreq.step_size = 512;
-                               chip->base.eccreq.strength = 1 << ecc_level;
+                               requirements.step_size = 512;
+                               requirements.strength = 1 << ecc_level;
                        } else if (ecc_level < 7) {
                                if (ecc_level == 5)
-                                       chip->base.eccreq.step_size = 2048;
+                                       requirements.step_size = 2048;
                                else
-                                       chip->base.eccreq.step_size = 1024;
-                               chip->base.eccreq.strength = 24;
+                                       requirements.step_size = 1024;
+                               requirements.strength = 24;
                        } else {
                                /*
                                 * We should never reach this case, but if that
@@ -563,18 +565,20 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
                } else {
                        /* <= 26nm, reference: H27UBG8T2B datasheet */
                        if (!ecc_level) {
-                               chip->base.eccreq.step_size = 0;
-                               chip->base.eccreq.strength = 0;
+                               requirements.step_size = 0;
+                               requirements.strength = 0;
                        } else if (ecc_level < 5) {
-                               chip->base.eccreq.step_size = 512;
-                               chip->base.eccreq.strength = 1 << (ecc_level - 1);
+                               requirements.step_size = 512;
+                               requirements.strength = 1 << (ecc_level - 1);
                        } else {
-                               chip->base.eccreq.step_size = 1024;
-                               chip->base.eccreq.strength = 24 +
+                               requirements.step_size = 1024;
+                               requirements.strength = 24 +
                                                        (8 * (ecc_level - 5));
                        }
                }
        }
+
+       nanddev_set_ecc_requirements(base, &requirements);
 }
 
 static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
index b15c42f..85b6d93 100644 (file)
@@ -23,6 +23,7 @@
  */
 int nand_jedec_detect(struct nand_chip *chip)
 {
+       struct nand_device *base = &chip->base;
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_memory_organization *memorg;
        struct nand_jedec_params *p;
@@ -120,8 +121,12 @@ int nand_jedec_detect(struct nand_chip *chip)
        ecc = &p->ecc_info[0];
 
        if (ecc->codeword_size >= 9) {
-               chip->base.eccreq.strength = ecc->ecc_bits;
-               chip->base.eccreq.step_size = 1 << ecc->codeword_size;
+               struct nand_ecc_props requirements = {
+                       .strength = ecc->ecc_bits,
+                       .step_size = 1 << ecc->codeword_size,
+               };
+
+               nanddev_set_ecc_requirements(base, &requirements);
        } else {
                pr_warn("Invalid codeword size\n");
        }
index 4385092..c019288 100644 (file)
@@ -413,6 +413,8 @@ enum {
  */
 static int micron_supports_on_die_ecc(struct nand_chip *chip)
 {
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(&chip->base);
        u8 id[5];
        int ret;
 
@@ -425,7 +427,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
        /*
         * We only support on-die ECC of 4/512 or 8/512
         */
-       if  (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8)
+       if  (requirements->strength != 4 && requirements->strength != 8)
                return MICRON_ON_DIE_UNSUPPORTED;
 
        /* 0x2 means on-die ECC is available. */
@@ -466,7 +468,7 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
        /*
         * We only support on-die ECC of 4/512 or 8/512
         */
-       if  (chip->base.eccreq.strength != 4 && chip->base.eccreq.strength != 8)
+       if  (requirements->strength != 4 && requirements->strength != 8)
                return MICRON_ON_DIE_UNSUPPORTED;
 
        return MICRON_ON_DIE_SUPPORTED;
@@ -474,6 +476,9 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
 
 static int micron_nand_init(struct nand_chip *chip)
 {
+       struct nand_device *base = &chip->base;
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(base);
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct micron_nand *micron;
        int ondie;
@@ -497,13 +502,13 @@ static int micron_nand_init(struct nand_chip *chip)
        ondie = micron_supports_on_die_ecc(chip);
 
        if (ondie == MICRON_ON_DIE_MANDATORY &&
-           chip->ecc.mode != NAND_ECC_ON_DIE) {
+           chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_DIE) {
                pr_err("On-die ECC forcefully enabled, not supported\n");
                ret = -EINVAL;
                goto err_free_manuf_data;
        }
 
-       if (chip->ecc.mode == NAND_ECC_ON_DIE) {
+       if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE) {
                if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
                        pr_err("On-die ECC selected but not supported\n");
                        ret = -EINVAL;
@@ -523,7 +528,7 @@ static int micron_nand_init(struct nand_chip *chip)
                 * That's not needed for 8-bit ECC, because the status expose
                 * a better approximation of the number of bitflips in a page.
                 */
-               if (chip->base.eccreq.strength == 4) {
+               if (requirements->strength == 4) {
                        micron->ecc.rawbuf = kmalloc(mtd->writesize +
                                                     mtd->oobsize,
                                                     GFP_KERNEL);
@@ -533,17 +538,17 @@ static int micron_nand_init(struct nand_chip *chip)
                        }
                }
 
-               if (chip->base.eccreq.strength == 4)
+               if (requirements->strength == 4)
                        mtd_set_ooblayout(mtd,
                                          &micron_nand_on_die_4_ooblayout_ops);
                else
                        mtd_set_ooblayout(mtd,
                                          &micron_nand_on_die_8_ooblayout_ops);
 
-               chip->ecc.bytes = chip->base.eccreq.strength * 2;
+               chip->ecc.bytes = requirements->strength * 2;
                chip->ecc.size = 512;
-               chip->ecc.strength = chip->base.eccreq.strength;
-               chip->ecc.algo = NAND_ECC_BCH;
+               chip->ecc.strength = requirements->strength;
+               chip->ecc.algo = NAND_ECC_ALGO_BCH;
                chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
                chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
 
index be34566..45649e0 100644 (file)
@@ -34,6 +34,8 @@ u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
 static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
                                            struct nand_onfi_params *p)
 {
+       struct nand_device *base = &chip->base;
+       struct nand_ecc_props requirements;
        struct onfi_ext_param_page *ep;
        struct onfi_ext_section *s;
        struct onfi_ext_ecc_info *ecc;
@@ -94,8 +96,10 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
                goto ext_out;
        }
 
-       chip->base.eccreq.strength = ecc->ecc_bits;
-       chip->base.eccreq.step_size = 1 << ecc->codeword_size;
+       requirements.strength = ecc->ecc_bits;
+       requirements.step_size = 1 << ecc->codeword_size;
+       nanddev_set_ecc_requirements(base, &requirements);
+
        ret = 0;
 
 ext_out:
@@ -139,6 +143,7 @@ static void nand_bit_wise_majority(const void **srcbufs,
  */
 int nand_onfi_detect(struct nand_chip *chip)
 {
+       struct nand_device *base = &chip->base;
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_memory_organization *memorg;
        struct nand_onfi_params *p = NULL, *pbuf;
@@ -265,8 +270,12 @@ int nand_onfi_detect(struct nand_chip *chip)
                chip->options |= NAND_BUSWIDTH_16;
 
        if (p->ecc_bits != 0xff) {
-               chip->base.eccreq.strength = p->ecc_bits;
-               chip->base.eccreq.step_size = 512;
+               struct nand_ecc_props requirements = {
+                       .strength = p->ecc_bits,
+                       .step_size = 512,
+               };
+
+               nanddev_set_ecc_requirements(base, &requirements);
        } else if (onfi_version >= 21 &&
                (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
 
index 3a4a19e..0be6b75 100644 (file)
@@ -10,6 +10,8 @@
 
 static void samsung_nand_decode_id(struct nand_chip *chip)
 {
+       struct nand_device *base = &chip->base;
+       struct nand_ecc_props requirements = {};
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_memory_organization *memorg;
 
@@ -71,23 +73,23 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
                /* Extract ECC requirements from 5th id byte*/
                extid = (chip->id.data[4] >> 4) & 0x07;
                if (extid < 5) {
-                       chip->base.eccreq.step_size = 512;
-                       chip->base.eccreq.strength = 1 << extid;
+                       requirements.step_size = 512;
+                       requirements.strength = 1 << extid;
                } else {
-                       chip->base.eccreq.step_size = 1024;
+                       requirements.step_size = 1024;
                        switch (extid) {
                        case 5:
-                               chip->base.eccreq.strength = 24;
+                               requirements.strength = 24;
                                break;
                        case 6:
-                               chip->base.eccreq.strength = 40;
+                               requirements.strength = 40;
                                break;
                        case 7:
-                               chip->base.eccreq.strength = 60;
+                               requirements.strength = 60;
                                break;
                        default:
                                WARN(1, "Could not decode ECC info");
-                               chip->base.eccreq.step_size = 0;
+                               requirements.step_size = 0;
                        }
                }
        } else {
@@ -97,8 +99,8 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
                        switch (chip->id.data[1]) {
                        /* K9F4G08U0D-S[I|C]B0(T00) */
                        case 0xDC:
-                               chip->base.eccreq.step_size = 512;
-                               chip->base.eccreq.strength = 1;
+                               requirements.step_size = 512;
+                               requirements.strength = 1;
                                break;
 
                        /* K9F1G08U0E 21nm chips do not support subpage write */
@@ -112,6 +114,8 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
                        }
                }
        }
+
+       nanddev_set_ecc_requirements(base, &requirements);
 }
 
 static int samsung_nand_init(struct nand_chip *chip)
index f746c19..cf4f379 100644 (file)
@@ -140,11 +140,13 @@ static void toshiba_nand_benand_init(struct nand_chip *chip)
 
        chip->options |= NAND_SUBPAGE_READ;
 
-       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+       mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
 }
 
 static void toshiba_nand_decode_id(struct nand_chip *chip)
 {
+       struct nand_device *base = &chip->base;
+       struct nand_ecc_props requirements = {};
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_memory_organization *memorg;
 
@@ -175,23 +177,25 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
         *  - 24nm: 8 bit ECC for each 512Byte is required.
         */
        if (chip->id.len >= 6 && nand_is_slc(chip)) {
-               chip->base.eccreq.step_size = 512;
+               requirements.step_size = 512;
                switch (chip->id.data[5] & 0x7) {
                case 0x4:
-                       chip->base.eccreq.strength = 1;
+                       requirements.strength = 1;
                        break;
                case 0x5:
-                       chip->base.eccreq.strength = 4;
+                       requirements.strength = 4;
                        break;
                case 0x6:
-                       chip->base.eccreq.strength = 8;
+                       requirements.strength = 8;
                        break;
                default:
                        WARN(1, "Could not get ECC info");
-                       chip->base.eccreq.step_size = 0;
+                       requirements.step_size = 0;
                        break;
                }
        }
+
+       nanddev_set_ecc_requirements(base, &requirements);
 }
 
 static int
@@ -273,7 +277,8 @@ static int toshiba_nand_init(struct nand_chip *chip)
                chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
 
        /* Check that chip is BENAND and ECC mode is on-die */
-       if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE &&
+       if (nand_is_slc(chip) &&
+           chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE &&
            chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND)
                toshiba_nand_benand_init(chip);
 
index f5a53aa..a8048cb 100644 (file)
@@ -2234,8 +2234,8 @@ static int ns_attach_chip(struct nand_chip *chip)
                return -EINVAL;
        }
 
-       chip->ecc.mode = NAND_ECC_SOFT;
-       chip->ecc.algo = NAND_ECC_BCH;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       chip->ecc.algo = NAND_ECC_ALGO_BCH;
        chip->ecc.size = 512;
        chip->ecc.strength = bch;
        chip->ecc.bytes = eccbytes;
@@ -2274,8 +2274,8 @@ static int __init ns_init_module(void)
        nsmtd       = nand_to_mtd(chip);
        nand_set_controller_data(chip, (void *)ns);
 
-       chip->ecc.mode   = NAND_ECC_SOFT;
-       chip->ecc.algo   = NAND_ECC_HAMMING;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       chip->ecc.algo   = NAND_ECC_ALGO_HAMMING;
        /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
        /* and 'badblocks' parameters to work */
        chip->options   |= NAND_SKIP_BBTSCAN;
index ed38338..0fb4ba9 100644 (file)
@@ -149,7 +149,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
        chip->ecc.correct = nand_correct_data;
        chip->ecc.hwctl = ndfc_enable_hwecc;
        chip->ecc.calculate = ndfc_calculate_ecc;
-       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        chip->ecc.size = 256;
        chip->ecc.bytes = 3;
        chip->ecc.strength = 1;
index eb7fcfd..512f607 100644 (file)
@@ -884,8 +884,8 @@ static int omap_correct_data(struct nand_chip *chip, u_char *dat,
        int stat = 0;
 
        /* Ex NAND_ECC_HW12_2048 */
-       if ((info->nand.ecc.mode == NAND_ECC_HW) &&
-                       (info->nand.ecc.size  == 2048))
+       if (info->nand.ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST &&
+           info->nand.ecc.size == 2048)
                blockCnt = 4;
        else
                blockCnt = 1;
@@ -2006,12 +2006,12 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
                return -EINVAL;
 
        /*
-        * Bail out earlier to let NAND_ECC_SOFT code create its own
+        * Bail out earlier to let NAND_ECC_ENGINE_TYPE_SOFT code create its own
         * ooblayout instead of using ours.
         */
        if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
-               chip->ecc.mode = NAND_ECC_SOFT;
-               chip->ecc.algo = NAND_ECC_HAMMING;
+               chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+               chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
                return 0;
        }
 
@@ -2019,7 +2019,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
        switch (info->ecc_opt) {
        case OMAP_ECC_HAM1_CODE_HW:
                dev_info(dev, "nand: using OMAP_ECC_HAM1_CODE_HW\n");
-               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.engine_type   = NAND_ECC_ENGINE_TYPE_ON_HOST;
                chip->ecc.bytes         = 3;
                chip->ecc.size          = 512;
                chip->ecc.strength      = 1;
@@ -2036,7 +2036,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
 
        case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
                pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
-               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.engine_type   = NAND_ECC_ENGINE_TYPE_ON_HOST;
                chip->ecc.size          = 512;
                chip->ecc.bytes         = 7;
                chip->ecc.strength      = 4;
@@ -2056,7 +2056,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
 
        case OMAP_ECC_BCH4_CODE_HW:
                pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
-               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.engine_type   = NAND_ECC_ENGINE_TYPE_ON_HOST;
                chip->ecc.size          = 512;
                /* 14th bit is kept reserved for ROM-code compatibility */
                chip->ecc.bytes         = 7 + 1;
@@ -2078,7 +2078,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
 
        case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
                pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
-               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.engine_type   = NAND_ECC_ENGINE_TYPE_ON_HOST;
                chip->ecc.size          = 512;
                chip->ecc.bytes         = 13;
                chip->ecc.strength      = 8;
@@ -2098,7 +2098,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
 
        case OMAP_ECC_BCH8_CODE_HW:
                pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
-               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.engine_type   = NAND_ECC_ENGINE_TYPE_ON_HOST;
                chip->ecc.size          = 512;
                /* 14th bit is kept reserved for ROM-code compatibility */
                chip->ecc.bytes         = 13 + 1;
@@ -2121,7 +2121,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
 
        case OMAP_ECC_BCH16_CODE_HW:
                pr_info("Using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
-               chip->ecc.mode          = NAND_ECC_HW;
+               chip->ecc.engine_type   = NAND_ECC_ENGINE_TYPE_ON_HOST;
                chip->ecc.size          = 512;
                chip->ecc.bytes         = 26;
                chip->ecc.strength      = 16;
index 880b54c..df9c0f8 100644 (file)
@@ -139,8 +139,8 @@ static int __init orion_nand_probe(struct platform_device *pdev)
        nc->legacy.IO_ADDR_R = nc->legacy.IO_ADDR_W = io_base;
        nc->legacy.cmd_ctrl = orion_nand_cmd_ctrl;
        nc->legacy.read_buf = orion_nand_read_buf;
-       nc->ecc.mode = NAND_ECC_SOFT;
-       nc->ecc.algo = NAND_ECC_HAMMING;
+       nc->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       nc->ecc.algo = NAND_ECC_ALGO_HAMMING;
 
        if (board->chip_delay)
                nc->legacy.chip_delay = board->chip_delay;
index 8d0d76a..f449470 100644 (file)
@@ -144,8 +144,7 @@ static int oxnas_nand_probe(struct platform_device *pdev)
                if (err)
                        goto err_cleanup_nand;
 
-               oxnas->chips[oxnas->nchips] = chip;
-               ++oxnas->nchips;
+               oxnas->chips[oxnas->nchips++] = chip;
        }
 
        /* Exit if no chips found */
index d8eca8c..2b8f155 100644 (file)
@@ -68,7 +68,7 @@ static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
        inl(lpcctl);
 }
 
-int pasemi_device_ready(struct nand_chip *chip)
+static int pasemi_device_ready(struct nand_chip *chip)
 {
        return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
 }
@@ -132,8 +132,8 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
        chip->legacy.read_buf = pasemi_read_buf;
        chip->legacy.write_buf = pasemi_write_buf;
        chip->legacy.chip_delay = 0;
-       chip->ecc.mode = NAND_ECC_SOFT;
-       chip->ecc.algo = NAND_ECC_HAMMING;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
 
        /* Enable the following for a flash based bad block table */
        chip->bbt_options = NAND_BBT_USE_FLASH;
index 556182f..b98c0d5 100644 (file)
@@ -66,8 +66,8 @@ static int plat_nand_probe(struct platform_device *pdev)
        data->chip.options |= pdata->chip.options;
        data->chip.bbt_options |= pdata->chip.bbt_options;
 
-       data->chip.ecc.mode = NAND_ECC_SOFT;
-       data->chip.ecc.algo = NAND_ECC_HAMMING;
+       data->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       data->chip.ecc.algo = NAND_ECC_ALGO_HAMMING;
 
        platform_set_drvdata(pdev, data);
 
index bd7a725..777fb0d 100644 (file)
@@ -2550,7 +2550,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
        ecc->write_page_raw     = qcom_nandc_write_page_raw;
        ecc->write_oob          = qcom_nandc_write_oob;
 
-       ecc->mode = NAND_ECC_HW;
+       ecc->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
 
        mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
 
@@ -2702,10 +2702,8 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
                if (IS_ERR(nandc->tx_chan)) {
                        ret = PTR_ERR(nandc->tx_chan);
                        nandc->tx_chan = NULL;
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(nandc->dev,
-                                       "tx DMA channel request failed: %d\n",
-                                       ret);
+                       dev_err_probe(nandc->dev, ret,
+                                     "tx DMA channel request failed\n");
                        goto unalloc;
                }
 
@@ -2713,10 +2711,8 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
                if (IS_ERR(nandc->rx_chan)) {
                        ret = PTR_ERR(nandc->rx_chan);
                        nandc->rx_chan = NULL;
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(nandc->dev,
-                                       "rx DMA channel request failed: %d\n",
-                                       ret);
+                       dev_err_probe(nandc->dev, ret,
+                                     "rx DMA channel request failed\n");
                        goto unalloc;
                }
 
@@ -2724,10 +2720,8 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
                if (IS_ERR(nandc->cmd_chan)) {
                        ret = PTR_ERR(nandc->cmd_chan);
                        nandc->cmd_chan = NULL;
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(nandc->dev,
-                                       "cmd DMA channel request failed: %d\n",
-                                       ret);
+                       dev_err_probe(nandc->dev, ret,
+                                     "cmd DMA channel request failed\n");
                        goto unalloc;
                }
 
@@ -2750,10 +2744,8 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
                if (IS_ERR(nandc->chan)) {
                        ret = PTR_ERR(nandc->chan);
                        nandc->chan = NULL;
-                       if (ret != -EPROBE_DEFER)
-                               dev_err(nandc->dev,
-                                       "rxtx DMA channel request failed: %d\n",
-                                       ret);
+                       dev_err_probe(nandc->dev, ret,
+                                     "rxtx DMA channel request failed\n");
                        return ret;
                }
        }
index f865e3a..6b7addd 100644 (file)
@@ -859,7 +859,8 @@ static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
        chip->legacy.write_buf = r852_write_buf;
 
        /* ecc */
-       chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
+       chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
        chip->ecc.size = R852_DMA_LEN;
        chip->ecc.bytes = SM_OOB_SIZE;
        chip->ecc.strength = 2;
index 1055222..fbd0fa4 100644 (file)
@@ -904,7 +904,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        nmtd->info         = info;
        nmtd->set          = set;
 
-       chip->ecc.mode = info->platform->ecc_mode;
+       chip->ecc.engine_type = info->platform->engine_type;
 
        /*
         * If you use u-boot BBT creation code, specifying this flag will
@@ -929,24 +929,24 @@ static int s3c2410_nand_attach_chip(struct nand_chip *chip)
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
 
-       switch (chip->ecc.mode) {
+       switch (chip->ecc.engine_type) {
 
-       case NAND_ECC_NONE:
+       case NAND_ECC_ENGINE_TYPE_NONE:
                dev_info(info->device, "ECC disabled\n");
                break;
 
-       case NAND_ECC_SOFT:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
                /*
-                * This driver expects Hamming based ECC when ecc_mode is set
-                * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
-                * avoid adding an extra ecc_algo field to
-                * s3c2410_platform_nand.
+                * This driver expects Hamming based ECC when engine_type is set
+                * to NAND_ECC_ENGINE_TYPE_SOFT. Force ecc.algo to
+                * NAND_ECC_ALGO_HAMMING to avoid adding an extra ecc_algo field
+                * to s3c2410_platform_nand.
                 */
-               chip->ecc.algo = NAND_ECC_HAMMING;
+               chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
                dev_info(info->device, "soft ECC\n");
                break;
 
-       case NAND_ECC_HW:
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                chip->ecc.calculate = s3c2410_nand_calculate_ecc;
                chip->ecc.correct   = s3c2410_nand_correct_data;
                chip->ecc.strength  = 1;
index a661b8b..13df4bd 100644 (file)
@@ -1039,13 +1039,13 @@ static int flctl_chip_attach_chip(struct nand_chip *chip)
                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;
+               chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
 
                /* 4 symbols ECC enabled */
                flctl->flcmncr_base |= _4ECCEN;
        } else {
-               chip->ecc.mode = NAND_ECC_SOFT;
-               chip->ecc.algo = NAND_ECC_HAMMING;
+               chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+               chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
        }
 
        return 0;
index 51286f7..1327bfb 100644 (file)
@@ -157,7 +157,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
        /* 15 us command delay time */
        this->legacy.chip_delay = 15;
        /* set eccmode using hardware ECC */
-       this->ecc.mode = NAND_ECC_HW;
+       this->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        this->ecc.size = 256;
        this->ecc.bytes = 3;
        this->ecc.strength = 1;
index 243b34c..0f63ff6 100644 (file)
@@ -153,8 +153,9 @@ static int socrates_nand_probe(struct platform_device *ofdev)
        nand_chip->legacy.read_buf = socrates_nand_read_buf;
        nand_chip->legacy.dev_ready = socrates_nand_device_ready;
 
-       nand_chip->ecc.mode = NAND_ECC_SOFT;    /* enable ECC */
-       nand_chip->ecc.algo = NAND_ECC_HAMMING;
+       /* enable ECC */
+       nand_chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       nand_chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
 
        /* TODO: I have no idea what real delay is. */
        nand_chip->legacy.chip_delay = 20;      /* 20us command delay time */
index 7f4546a..b31a581 100644 (file)
@@ -1696,14 +1696,15 @@ static int stm32_fmc2_nfc_attach_chip(struct nand_chip *chip)
        int ret;
 
        /*
-        * Only NAND_ECC_HW mode is actually supported
+        * Only NAND_ECC_ENGINE_TYPE_ON_HOST mode is actually supported
         * Hamming => ecc.strength = 1
         * BCH4 => ecc.strength = 4
         * BCH8 => ecc.strength = 8
         * ECC sector size = 512
         */
-       if (chip->ecc.mode != NAND_ECC_HW) {
-               dev_err(nfc->dev, "nand_ecc_mode is not well defined in the DT\n");
+       if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) {
+               dev_err(nfc->dev,
+                       "nand_ecc_engine_type is not well defined in the DT\n");
                return -EINVAL;
        }
 
@@ -1762,7 +1763,7 @@ static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc,
                        return ret;
                }
 
-               if (cs > FMC2_MAX_CE) {
+               if (cs >= FMC2_MAX_CE) {
                        dev_err(nfc->dev, "invalid reg value: %d\n", cs);
                        return -EINVAL;
                }
@@ -1952,7 +1953,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
                         NAND_USES_DMA;
 
        /* Default ECC settings */
-       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        chip->ecc.size = FMC2_ECC_STEP_SIZE;
        chip->ecc.strength = FMC2_ECC_BCH8;
 
index 9c50c2b..2a7ca30 100644 (file)
@@ -1575,7 +1575,7 @@ static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
         * only have 2 bytes available in the first user data
         * section.
         */
-       if (!section && ecc->mode == NAND_ECC_HW) {
+       if (!section && ecc->engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) {
                oobregion->offset = 2;
                oobregion->length = 2;
 
@@ -1609,12 +1609,13 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
        static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
        struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
        struct mtd_info *mtd = nand_to_mtd(nand);
+       struct nand_device *nanddev = mtd_to_nanddev(mtd);
        struct sunxi_nand_hw_ecc *data;
        int nsectors;
        int ret;
        int i;
 
-       if (ecc->options & NAND_ECC_MAXIMIZE) {
+       if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) {
                int bytes;
 
                ecc->size = 1024;
@@ -1720,11 +1721,11 @@ err:
 
 static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
 {
-       switch (ecc->mode) {
-       case NAND_ECC_HW:
+       switch (ecc->engine_type) {
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                sunxi_nand_hw_ecc_ctrl_cleanup(ecc);
                break;
-       case NAND_ECC_NONE:
+       case NAND_ECC_ENGINE_TYPE_NONE:
        default:
                break;
        }
@@ -1732,6 +1733,8 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
 
 static int sunxi_nand_attach_chip(struct nand_chip *nand)
 {
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(&nand->base);
        struct nand_ecc_ctrl *ecc = &nand->ecc;
        struct device_node *np = nand_get_flash_node(nand);
        int ret;
@@ -1745,21 +1748,21 @@ static int sunxi_nand_attach_chip(struct nand_chip *nand)
        nand->options |= NAND_SUBPAGE_READ;
 
        if (!ecc->size) {
-               ecc->size = nand->base.eccreq.step_size;
-               ecc->strength = nand->base.eccreq.strength;
+               ecc->size = requirements->step_size;
+               ecc->strength = requirements->strength;
        }
 
        if (!ecc->size || !ecc->strength)
                return -EINVAL;
 
-       switch (ecc->mode) {
-       case NAND_ECC_HW:
+       switch (ecc->engine_type) {
+       case NAND_ECC_ENGINE_TYPE_ON_HOST:
                ret = sunxi_nand_hw_ecc_ctrl_init(nand, ecc, np);
                if (ret)
                        return ret;
                break;
-       case NAND_ECC_NONE:
-       case NAND_ECC_SOFT:
+       case NAND_ECC_ENGINE_TYPE_NONE:
+       case NAND_ECC_ENGINE_TYPE_SOFT:
                break;
        default:
                return -EINVAL;
@@ -1991,7 +1994,7 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
         * Set the ECC mode to the default value in case nothing is specified
         * in the DT.
         */
-       nand->ecc.mode = NAND_ECC_HW;
+       nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        nand_set_flash_node(nand, np);
 
        mtd = nand_to_mtd(nand);
index bdb965a..359187b 100644 (file)
@@ -549,8 +549,8 @@ static int tango_attach_chip(struct nand_chip *chip)
 {
        struct nand_ecc_ctrl *ecc = &chip->ecc;
 
-       ecc->mode = NAND_ECC_HW;
-       ecc->algo = NAND_ECC_BCH;
+       ecc->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
+       ecc->algo = NAND_ECC_ALGO_BCH;
        ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
 
        ecc->read_page_raw = tango_read_page_raw;
index 6b6212f..fbf6772 100644 (file)
@@ -479,7 +479,7 @@ static void tegra_nand_hw_ecc(struct tegra_nand_controller *ctrl,
 {
        struct tegra_nand_chip *nand = to_tegra_chip(chip);
 
-       if (chip->ecc.algo == NAND_ECC_BCH && enable)
+       if (chip->ecc.algo == NAND_ECC_ALGO_BCH && enable)
                writel_relaxed(nand->bch_config, ctrl->regs + BCH_CONFIG);
        else
                writel_relaxed(0, ctrl->regs + BCH_CONFIG);
@@ -840,7 +840,10 @@ static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength,
                                   int strength_len, int bits_per_step,
                                   int oobsize)
 {
-       bool maximize = chip->ecc.options & NAND_ECC_MAXIMIZE;
+       struct nand_device *base = mtd_to_nanddev(nand_to_mtd(chip));
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(base);
+       bool maximize = base->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH;
        int i;
 
        /*
@@ -855,7 +858,7 @@ static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength,
                } else {
                        strength_sel = strength[i];
 
-                       if (strength_sel < chip->base.eccreq.strength)
+                       if (strength_sel < requirements->strength)
                                continue;
                }
 
@@ -877,7 +880,7 @@ static int tegra_nand_select_strength(struct nand_chip *chip, int oobsize)
        int strength_len, bits_per_step;
 
        switch (chip->ecc.algo) {
-       case NAND_ECC_RS:
+       case NAND_ECC_ALGO_RS:
                bits_per_step = BITS_PER_STEP_RS;
                if (chip->options & NAND_IS_BOOT_MEDIUM) {
                        strength = rs_strength_bootable;
@@ -887,7 +890,7 @@ static int tegra_nand_select_strength(struct nand_chip *chip, int oobsize)
                        strength_len = ARRAY_SIZE(rs_strength);
                }
                break;
-       case NAND_ECC_BCH:
+       case NAND_ECC_ALGO_BCH:
                bits_per_step = BITS_PER_STEP_BCH;
                if (chip->options & NAND_IS_BOOT_MEDIUM) {
                        strength = bch_strength_bootable;
@@ -908,6 +911,8 @@ static int tegra_nand_select_strength(struct nand_chip *chip, int oobsize)
 static int tegra_nand_attach_chip(struct nand_chip *chip)
 {
        struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
+       const struct nand_ecc_props *requirements =
+               nanddev_get_ecc_requirements(&chip->base);
        struct tegra_nand_chip *nand = to_tegra_chip(chip);
        struct mtd_info *mtd = nand_to_mtd(chip);
        int bits_per_step;
@@ -916,12 +921,12 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
        if (chip->bbt_options & NAND_BBT_USE_FLASH)
                chip->bbt_options |= NAND_BBT_NO_OOB;
 
-       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        chip->ecc.size = 512;
        chip->ecc.steps = mtd->writesize / chip->ecc.size;
-       if (chip->base.eccreq.step_size != 512) {
+       if (requirements->step_size != 512) {
                dev_err(ctrl->dev, "Unsupported step size %d\n",
-                       chip->base.eccreq.step_size);
+                       requirements->step_size);
                return -EINVAL;
        }
 
@@ -935,14 +940,14 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
        if (chip->options & NAND_BUSWIDTH_16)
                nand->config |= CONFIG_BUS_WIDTH_16;
 
-       if (chip->ecc.algo == NAND_ECC_UNKNOWN) {
+       if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN) {
                if (mtd->writesize < 2048)
-                       chip->ecc.algo = NAND_ECC_RS;
+                       chip->ecc.algo = NAND_ECC_ALGO_RS;
                else
-                       chip->ecc.algo = NAND_ECC_BCH;
+                       chip->ecc.algo = NAND_ECC_ALGO_BCH;
        }
 
-       if (chip->ecc.algo == NAND_ECC_BCH && mtd->writesize < 2048) {
+       if (chip->ecc.algo == NAND_ECC_ALGO_BCH && mtd->writesize < 2048) {
                dev_err(ctrl->dev, "BCH supports 2K or 4K page size only\n");
                return -EINVAL;
        }
@@ -952,7 +957,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
                if (ret < 0) {
                        dev_err(ctrl->dev,
                                "No valid strength found, minimum %d\n",
-                               chip->base.eccreq.strength);
+                               requirements->strength);
                        return ret;
                }
 
@@ -963,7 +968,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
                           CONFIG_SKIP_SPARE_SIZE_4;
 
        switch (chip->ecc.algo) {
-       case NAND_ECC_RS:
+       case NAND_ECC_ALGO_RS:
                bits_per_step = BITS_PER_STEP_RS * chip->ecc.strength;
                mtd_set_ooblayout(mtd, &tegra_nand_oob_rs_ops);
                nand->config_ecc |= CONFIG_HW_ECC | CONFIG_ECC_SEL |
@@ -984,7 +989,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
                        return -EINVAL;
                }
                break;
-       case NAND_ECC_BCH:
+       case NAND_ECC_ALGO_BCH:
                bits_per_step = BITS_PER_STEP_BCH * chip->ecc.strength;
                mtd_set_ooblayout(mtd, &tegra_nand_oob_bch_ops);
                nand->bch_config = BCH_ENABLE;
@@ -1013,7 +1018,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
        }
 
        dev_info(ctrl->dev, "Using %s with strength %d per 512 byte step\n",
-                chip->ecc.algo == NAND_ECC_BCH ? "BCH" : "RS",
+                chip->ecc.algo == NAND_ECC_ALGO_BCH ? "BCH" : "RS",
                 chip->ecc.strength);
 
        chip->ecc.bytes = DIV_ROUND_UP(bits_per_step, BITS_PER_BYTE);
index 843a868..235a2f7 100644 (file)
@@ -410,7 +410,7 @@ static int tmio_probe(struct platform_device *dev)
        nand_chip->legacy.read_buf = tmio_nand_read_buf;
 
        /* set eccmode using hardware ECC */
-       nand_chip->ecc.mode = NAND_ECC_HW;
+       nand_chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
        nand_chip->ecc.size = 512;
        nand_chip->ecc.bytes = 6;
        nand_chip->ecc.strength = 2;
index 47d9668..ef81dce 100644 (file)
@@ -329,7 +329,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
                chip->ecc.calculate = txx9ndfmc_calculate_ecc;
                chip->ecc.correct = txx9ndfmc_correct_data;
                chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
-               chip->ecc.mode = NAND_ECC_HW;
+               chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
                chip->ecc.strength = 1;
                chip->legacy.chip_delay = 100;
                chip->controller = &drvdata->controller;
index 7248c59..40d70f9 100644 (file)
@@ -323,11 +323,6 @@ static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode)
                            CONFIG_ECC_MODE_SHIFT, ecc_mode);
 }
 
-static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size)
-{
-       vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size);
-}
-
 static inline void vf610_nfc_run(struct vf610_nfc *nfc, u32 col, u32 row,
                                 u32 cmd1, u32 cmd2, u32 trfr_sz)
 {
@@ -732,7 +727,7 @@ static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
        else
                vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
 
-       if (nfc->chip.ecc.mode == NAND_ECC_HW) {
+       if (nfc->chip.ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) {
                /* Set ECC status offset in SRAM */
                vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
                                    CONFIG_ECC_SRAM_ADDR_MASK,
@@ -761,7 +756,7 @@ static int vf610_nfc_attach_chip(struct nand_chip *chip)
                return -ENXIO;
        }
 
-       if (chip->ecc.mode != NAND_ECC_HW)
+       if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
                return 0;
 
        if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
@@ -779,7 +774,7 @@ static int vf610_nfc_attach_chip(struct nand_chip *chip)
                mtd->oobsize = 64;
 
        /* Use default large page ECC layout defined in NAND core */
-       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+       mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
        if (chip->ecc.strength == 32) {
                nfc->ecc_mode = ECC_60_BYTE;
                chip->ecc.bytes = 60;
@@ -852,8 +847,10 @@ static int vf610_nfc_probe(struct platform_device *pdev)
        }
 
        of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
-       if (!of_id)
-               return -ENODEV;
+       if (!of_id) {
+               err = -ENODEV;
+               goto err_disable_clk;
+       }
 
        nfc->variant = (enum vf610_nfc_variant)of_id->data;
 
index 2925547..f2dbd63 100644 (file)
@@ -180,8 +180,8 @@ static int xway_nand_probe(struct platform_device *pdev)
        data->chip.legacy.read_byte = xway_read_byte;
        data->chip.legacy.chip_delay = 30;
 
-       data->chip.ecc.mode = NAND_ECC_SOFT;
-       data->chip.ecc.algo = NAND_ECC_HAMMING;
+       data->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+       data->chip.ecc.algo = NAND_ECC_ALGO_HAMMING;
 
        platform_set_drvdata(pdev, data);
        nand_set_controller_data(&data->chip, data);
index e2c382f..c352217 100644 (file)
@@ -419,7 +419,7 @@ static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
                 * fixed, so let's return the maximum possible value so that
                 * wear-leveling layers move the data immediately.
                 */
-               return nand->eccreq.strength;
+               return nanddev_get_ecc_conf(nand)->strength;
 
        case STATUS_ECC_UNCOR_ERROR:
                return -EBADMSG;
@@ -497,7 +497,7 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
 
        mutex_lock(&spinand->lock);
 
-       nanddev_io_for_each_page(nand, from, ops, &iter) {
+       nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) {
                ret = spinand_select_target(spinand, iter.req.pos.target);
                if (ret)
                        break;
@@ -545,7 +545,7 @@ static int spinand_mtd_write(struct mtd_info *mtd, loff_t to,
 
        mutex_lock(&spinand->lock);
 
-       nanddev_io_for_each_page(nand, to, ops, &iter) {
+       nanddev_io_for_each_page(nand, NAND_PAGE_WRITE, to, ops, &iter) {
                ret = spinand_select_target(spinand, iter.req.pos.target);
                if (ret)
                        break;
@@ -902,7 +902,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
                        continue;
 
                nand->memorg = table[i].memorg;
-               nand->eccreq = table[i].eccreq;
+               nanddev_set_ecc_requirements(nand, &table[i].eccreq);
                spinand->eccinfo = table[i].eccinfo;
                spinand->flags = table[i].flags;
                spinand->id.len = 1 + table[i].devid.len;
@@ -1090,8 +1090,8 @@ static int spinand_init(struct spinand_device *spinand)
        mtd->oobavail = ret;
 
        /* Propagate ECC information to mtd_info */
-       mtd->ecc_strength = nand->eccreq.strength;
-       mtd->ecc_step_size = nand->eccreq.step_size;
+       mtd->ecc_strength = nanddev_get_ecc_conf(nand)->strength;
+       mtd->ecc_step_size = nanddev_get_ecc_conf(nand)->step_size;
 
        return 0;
 
index d219c97..33c6740 100644 (file)
@@ -21,7 +21,7 @@
 #define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR  (7 << 4)
 
 static SPINAND_OP_VARIANTS(read_cache_variants,
-               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -29,7 +29,7 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
                SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
 
 static SPINAND_OP_VARIANTS(read_cache_variants_f,
-               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
                SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
@@ -132,6 +132,35 @@ static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = {
        .free = gd5fxgq4_variant2_ooblayout_free,
 };
 
+static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
+                                       struct mtd_oob_region *oobregion)
+{
+       if (section)
+               return -ERANGE;
+
+       oobregion->offset = 128;
+       oobregion->length = 128;
+
+       return 0;
+}
+
+static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section,
+                                        struct mtd_oob_region *oobregion)
+{
+       if (section)
+               return -ERANGE;
+
+       oobregion->offset = 1;
+       oobregion->length = 127;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = {
+       .ecc = gd5fxgq4xc_ooblayout_256_ecc,
+       .free = gd5fxgq4xc_ooblayout_256_free,
+};
+
 static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
                                        u8 status)
 {
@@ -202,7 +231,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
                                              &update_cache_variants),
-                    0,
+                    SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
                                     gd5fxgq4xa_ecc_get_status)),
        SPINAND_INFO("GD5F2GQ4xA",
@@ -212,7 +241,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
                                              &update_cache_variants),
-                    0,
+                    SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
                                     gd5fxgq4xa_ecc_get_status)),
        SPINAND_INFO("GD5F4GQ4xA",
@@ -222,9 +251,29 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
                                              &update_cache_variants),
-                    0,
+                    SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
                                     gd5fxgq4xa_ecc_get_status)),
+       SPINAND_INFO("GD5F4GQ4RC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xa4, 0x68),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+                                    gd5fxgq4ufxxg_ecc_get_status)),
+       SPINAND_INFO("GD5F4GQ4UC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb4, 0x68),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+                                    gd5fxgq4ufxxg_ecc_get_status)),
        SPINAND_INFO("GD5F1GQ4UExxG",
                     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
                     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
@@ -232,7 +281,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
                                              &update_cache_variants),
-                    0,
+                    SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
                                     gd5fxgq4uexxg_ecc_get_status)),
        SPINAND_INFO("GD5F1GQ4UFxxG",
@@ -242,7 +291,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
                                              &write_cache_variants,
                                              &update_cache_variants),
-                    0,
+                    SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
                                     gd5fxgq4ufxxg_ecc_get_status)),
 };
index 0f900f3..8e801e4 100644 (file)
@@ -84,10 +84,11 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
                 * data around if it's not necessary.
                 */
                if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
-                       return nand->eccreq.strength;
+                       return nanddev_get_ecc_conf(nand)->strength;
 
-               if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
-                       return nand->eccreq.strength;
+               if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength ||
+                           !eccsr))
+                       return nanddev_get_ecc_conf(nand)->strength;
 
                return eccsr;
 
@@ -118,6 +119,26 @@ static const struct spinand_info macronix_spinand_table[] = {
                                              &update_cache_variants),
                     SPINAND_HAS_QE_BIT,
                     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+       SPINAND_INFO("MX31LF1GE4BC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0 /*SPINAND_HAS_QE_BIT*/,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+       SPINAND_INFO("MX31UF1GE4BC",
+                    SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9e),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0 /*SPINAND_HAS_QE_BIT*/,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
 };
 
 static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
index bc801d8..21fde28 100644 (file)
@@ -90,12 +90,12 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
                 * data around if it's not necessary.
                 */
                if (spi_mem_exec_op(spinand->spimem, &op))
-                       return nand->eccreq.strength;
+                       return nanddev_get_ecc_conf(nand)->strength;
 
                mbf >>= 4;
 
-               if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
-                       return nand->eccreq.strength;
+               if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf))
+                       return nanddev_get_ecc_conf(nand)->strength;
 
                return mbf;
 
index f98363c..e723543 100644 (file)
@@ -12,7 +12,7 @@ config MTD_BCM47XX_PARTS
          boards.
 
 config MTD_BCM63XX_PARTS
-       tristate "BCM63XX CFE partitioning parser"
+       bool "BCM63XX CFE partitioning parser"
        depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
        select CRC32
        select MTD_PARSER_IMAGETAG
index af99041..697ea24 100644 (file)
@@ -82,8 +82,19 @@ struct nand_pos {
        unsigned int page;
 };
 
+/**
+ * enum nand_page_io_req_type - Direction of an I/O request
+ * @NAND_PAGE_READ: from the chip, to the controller
+ * @NAND_PAGE_WRITE: from the controller, to the chip
+ */
+enum nand_page_io_req_type {
+       NAND_PAGE_READ = 0,
+       NAND_PAGE_WRITE,
+};
+
 /**
  * struct nand_page_io_req - NAND I/O request object
+ * @type: the type of page I/O: read or write
  * @pos: the position this I/O request is targeting
  * @dataoffs: the offset within the page
  * @datalen: number of data bytes to read from/write to this page
@@ -99,6 +110,7 @@ struct nand_pos {
  * specific commands/operations.
  */
 struct nand_page_io_req {
+       enum nand_page_io_req_type type;
        struct nand_pos pos;
        unsigned int dataoffs;
        unsigned int datalen;
@@ -115,18 +127,77 @@ struct nand_page_io_req {
        int mode;
 };
 
+const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void);
+const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void);
+const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void);
+
+/**
+ * enum nand_ecc_engine_type - NAND ECC engine type
+ * @NAND_ECC_ENGINE_TYPE_INVALID: Invalid value
+ * @NAND_ECC_ENGINE_TYPE_NONE: No ECC correction
+ * @NAND_ECC_ENGINE_TYPE_SOFT: Software ECC correction
+ * @NAND_ECC_ENGINE_TYPE_ON_HOST: On host hardware ECC correction
+ * @NAND_ECC_ENGINE_TYPE_ON_DIE: On chip hardware ECC correction
+ */
+enum nand_ecc_engine_type {
+       NAND_ECC_ENGINE_TYPE_INVALID,
+       NAND_ECC_ENGINE_TYPE_NONE,
+       NAND_ECC_ENGINE_TYPE_SOFT,
+       NAND_ECC_ENGINE_TYPE_ON_HOST,
+       NAND_ECC_ENGINE_TYPE_ON_DIE,
+};
+
+/**
+ * enum nand_ecc_placement - NAND ECC bytes placement
+ * @NAND_ECC_PLACEMENT_UNKNOWN: The actual position of the ECC bytes is unknown
+ * @NAND_ECC_PLACEMENT_OOB: The ECC bytes are located in the OOB area
+ * @NAND_ECC_PLACEMENT_INTERLEAVED: Syndrome layout, there are ECC bytes
+ *                                  interleaved with regular data in the main
+ *                                  area
+ */
+enum nand_ecc_placement {
+       NAND_ECC_PLACEMENT_UNKNOWN,
+       NAND_ECC_PLACEMENT_OOB,
+       NAND_ECC_PLACEMENT_INTERLEAVED,
+};
+
+/**
+ * enum nand_ecc_algo - NAND ECC algorithm
+ * @NAND_ECC_ALGO_UNKNOWN: Unknown algorithm
+ * @NAND_ECC_ALGO_HAMMING: Hamming algorithm
+ * @NAND_ECC_ALGO_BCH: Bose-Chaudhuri-Hocquenghem algorithm
+ * @NAND_ECC_ALGO_RS: Reed-Solomon algorithm
+ */
+enum nand_ecc_algo {
+       NAND_ECC_ALGO_UNKNOWN,
+       NAND_ECC_ALGO_HAMMING,
+       NAND_ECC_ALGO_BCH,
+       NAND_ECC_ALGO_RS,
+};
+
 /**
  * struct nand_ecc_props - NAND ECC properties
+ * @engine_type: ECC engine type
+ * @placement: OOB placement (if relevant)
+ * @algo: ECC algorithm (if relevant)
  * @strength: ECC strength
  * @step_size: Number of bytes per step
+ * @flags: Misc properties
  */
 struct nand_ecc_props {
+       enum nand_ecc_engine_type engine_type;
+       enum nand_ecc_placement placement;
+       enum nand_ecc_algo algo;
        unsigned int strength;
        unsigned int step_size;
+       unsigned int flags;
 };
 
 #define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) }
 
+/* NAND ECC misc flags */
+#define NAND_ECC_MAXIMIZE_STRENGTH BIT(0)
+
 /**
  * struct nand_bbt - bad block table object
  * @cache: in memory BBT cache
@@ -157,11 +228,80 @@ struct nand_ops {
        bool (*isbad)(struct nand_device *nand, const struct nand_pos *pos);
 };
 
+/**
+ * struct nand_ecc_context - Context for the ECC engine
+ * @conf: basic ECC engine parameters
+ * @total: total number of bytes used for storing ECC codes, this is used by
+ *         generic OOB layouts
+ * @priv: ECC engine driver private data
+ */
+struct nand_ecc_context {
+       struct nand_ecc_props conf;
+       unsigned int total;
+       void *priv;
+};
+
+/**
+ * struct nand_ecc_engine_ops - ECC engine operations
+ * @init_ctx: given a desired user configuration for the pointed NAND device,
+ *            requests the ECC engine driver to setup a configuration with
+ *            values it supports.
+ * @cleanup_ctx: clean the context initialized by @init_ctx.
+ * @prepare_io_req: is called before reading/writing a page to prepare the I/O
+ *                  request to be performed with ECC correction.
+ * @finish_io_req: is called after reading/writing a page to terminate the I/O
+ *                 request and ensure proper ECC correction.
+ */
+struct nand_ecc_engine_ops {
+       int (*init_ctx)(struct nand_device *nand);
+       void (*cleanup_ctx)(struct nand_device *nand);
+       int (*prepare_io_req)(struct nand_device *nand,
+                             struct nand_page_io_req *req);
+       int (*finish_io_req)(struct nand_device *nand,
+                            struct nand_page_io_req *req);
+};
+
+/**
+ * struct nand_ecc_engine - ECC engine abstraction for NAND devices
+ * @ops: ECC engine operations
+ */
+struct nand_ecc_engine {
+       struct nand_ecc_engine_ops *ops;
+};
+
+void of_get_nand_ecc_user_config(struct nand_device *nand);
+int nand_ecc_init_ctx(struct nand_device *nand);
+void nand_ecc_cleanup_ctx(struct nand_device *nand);
+int nand_ecc_prepare_io_req(struct nand_device *nand,
+                           struct nand_page_io_req *req);
+int nand_ecc_finish_io_req(struct nand_device *nand,
+                          struct nand_page_io_req *req);
+bool nand_ecc_is_strong_enough(struct nand_device *nand);
+
+/**
+ * struct nand_ecc - Information relative to the ECC
+ * @defaults: Default values, depend on the underlying subsystem
+ * @requirements: ECC requirements from the NAND chip perspective
+ * @user_conf: User desires in terms of ECC parameters
+ * @ctx: ECC context for the ECC engine, derived from the device @requirements
+ *       the @user_conf and the @defaults
+ * @ondie_engine: On-die ECC engine reference, if any
+ * @engine: ECC engine actually bound
+ */
+struct nand_ecc {
+       struct nand_ecc_props defaults;
+       struct nand_ecc_props requirements;
+       struct nand_ecc_props user_conf;
+       struct nand_ecc_context ctx;
+       struct nand_ecc_engine *ondie_engine;
+       struct nand_ecc_engine *engine;
+};
+
 /**
  * struct nand_device - NAND device
  * @mtd: MTD instance attached to the NAND device
  * @memorg: memory layout
- * @eccreq: ECC requirements
+ * @ecc: NAND ECC object attached to the NAND device
  * @rowconv: position to row address converter
  * @bbt: bad block table info
  * @ops: NAND operations attached to the NAND device
@@ -169,8 +309,8 @@ struct nand_ops {
  * Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND)
  * should declare their own NAND object embedding a nand_device struct (that's
  * how inheritance is done).
- * struct_nand_device->memorg and struct_nand_device->eccreq should be filled
- * at device detection time to reflect the NAND device
+ * struct_nand_device->memorg and struct_nand_device->ecc.requirements should
+ * be filled at device detection time to reflect the NAND device
  * capabilities/requirements. Once this is done nanddev_init() can be called.
  * It will take care of converting NAND information into MTD ones, which means
  * the specialized NAND layers should never manually tweak
@@ -179,7 +319,7 @@ struct nand_ops {
 struct nand_device {
        struct mtd_info mtd;
        struct nand_memory_organization memorg;
-       struct nand_ecc_props eccreq;
+       struct nand_ecc ecc;
        struct nand_row_converter rowconv;
        struct nand_bbt bbt;
        const struct nand_ops *ops;
@@ -383,6 +523,40 @@ nanddev_get_memorg(struct nand_device *nand)
        return &nand->memorg;
 }
 
+/**
+ * nanddev_get_ecc_conf() - Extract the ECC configuration from a NAND device
+ * @nand: NAND device
+ */
+static inline const struct nand_ecc_props *
+nanddev_get_ecc_conf(struct nand_device *nand)
+{
+       return &nand->ecc.ctx.conf;
+}
+
+/**
+ * nanddev_get_ecc_requirements() - Extract the ECC requirements from a NAND
+ *                                  device
+ * @nand: NAND device
+ */
+static inline const struct nand_ecc_props *
+nanddev_get_ecc_requirements(struct nand_device *nand)
+{
+       return &nand->ecc.requirements;
+}
+
+/**
+ * nanddev_set_ecc_requirements() - Assign the ECC requirements of a NAND
+ *                                  device
+ * @nand: NAND device
+ * @reqs: Requirements
+ */
+static inline void
+nanddev_set_ecc_requirements(struct nand_device *nand,
+                            const struct nand_ecc_props *reqs)
+{
+       nand->ecc.requirements = *reqs;
+}
+
 int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
                 struct module *owner);
 void nanddev_cleanup(struct nand_device *nand);
@@ -624,11 +798,13 @@ static inline void nanddev_pos_next_page(struct nand_device *nand,
  * layer.
  */
 static inline void nanddev_io_iter_init(struct nand_device *nand,
+                                       enum nand_page_io_req_type reqtype,
                                        loff_t offs, struct mtd_oob_ops *req,
                                        struct nand_io_iter *iter)
 {
        struct mtd_info *mtd = nanddev_to_mtd(nand);
 
+       iter->req.type = reqtype;
        iter->req.mode = req->mode;
        iter->req.dataoffs = nanddev_offs_to_pos(nand, offs, &iter->req.pos);
        iter->req.ooboffs = req->ooboffs;
@@ -698,8 +874,8 @@ static inline bool nanddev_io_iter_end(struct nand_device *nand,
  *
  * Should be used for iterate over pages that are contained in an MTD request.
  */
-#define nanddev_io_for_each_page(nand, start, req, iter)               \
-       for (nanddev_io_iter_init(nand, start, req, iter);              \
+#define nanddev_io_for_each_page(nand, type, start, req, iter)         \
+       for (nanddev_io_iter_init(nand, type, start, req, iter);        \
             !nanddev_io_iter_end(nand, iter);                          \
             nanddev_io_iter_next_page(nand, iter))
 
index 6166e7c..146413d 100644 (file)
@@ -121,37 +121,4 @@ static inline void send_pfow_command(struct map_info *map,
        map_write(map, CMD(LPDDR_START_EXECUTION),
                        map->pfow_base + PFOW_COMMAND_EXECUTE);
 }
-
-static inline void print_drs_error(unsigned dsr)
-{
-       int prog_status = (dsr & DSR_RPS) >> 8;
-
-       if (!(dsr & DSR_AVAILABLE))
-               printk(KERN_NOTICE"DSR.15: (0) Device not Available\n");
-       if (prog_status & 0x03)
-               printk(KERN_NOTICE"DSR.9,8: (11) Attempt to program invalid "
-                                               "half with 41h command\n");
-       else if (prog_status & 0x02)
-               printk(KERN_NOTICE"DSR.9,8: (10) Object Mode Program attempt "
-                                       "in region with Control Mode data\n");
-       else if (prog_status &  0x01)
-               printk(KERN_NOTICE"DSR.9,8: (01) Program attempt in region "
-                                               "with Object Mode data\n");
-       if (!(dsr & DSR_READY_STATUS))
-               printk(KERN_NOTICE"DSR.7: (0) Device is Busy\n");
-       if (dsr & DSR_ESS)
-               printk(KERN_NOTICE"DSR.6: (1) Erase Suspended\n");
-       if (dsr & DSR_ERASE_STATUS)
-               printk(KERN_NOTICE"DSR.5: (1) Erase/Blank check error\n");
-       if (dsr & DSR_PROGRAM_STATUS)
-               printk(KERN_NOTICE"DSR.4: (1) Program Error\n");
-       if (dsr & DSR_VPPS)
-               printk(KERN_NOTICE"DSR.3: (1) Vpp low detect, operation "
-                                       "aborted\n");
-       if (dsr & DSR_PSS)
-               printk(KERN_NOTICE"DSR.2: (1) Program suspended\n");
-       if (dsr & DSR_DPS)
-               printk(KERN_NOTICE"DSR.1: (1) Aborted Erase/Program attempt "
-                                       "on locked block\n");
-}
 #endif /* __LINUX_MTD_PFOW_H */
index a725b62..aac0794 100644 (file)
@@ -14,6 +14,7 @@
 #define __LINUX_MTD_RAWNAND_H
 
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/flashchip.h>
 #include <linux/mtd/bbm.h>
 #include <linux/mtd/jedec.h>
@@ -80,25 +81,6 @@ struct nand_chip;
 
 #define NAND_DATA_IFACE_CHECK_ONLY     -1
 
-/*
- * Constants for ECC_MODES
- */
-enum nand_ecc_mode {
-       NAND_ECC_INVALID,
-       NAND_ECC_NONE,
-       NAND_ECC_SOFT,
-       NAND_ECC_HW,
-       NAND_ECC_HW_SYNDROME,
-       NAND_ECC_ON_DIE,
-};
-
-enum nand_ecc_algo {
-       NAND_ECC_UNKNOWN,
-       NAND_ECC_HAMMING,
-       NAND_ECC_BCH,
-       NAND_ECC_RS,
-};
-
 /*
  * Constants for Hardware ECC
  */
@@ -116,7 +98,6 @@ enum nand_ecc_algo {
  * pages and you want to rely on the default implementation.
  */
 #define NAND_ECC_GENERIC_ERASED_CHECK  BIT(0)
-#define NAND_ECC_MAXIMIZE              BIT(1)
 
 /*
  * Option constants for bizarre disfunctionality and real
@@ -310,7 +291,8 @@ static const struct nand_ecc_caps __name = {                        \
 
 /**
  * struct nand_ecc_ctrl - Control structure for ECC
- * @mode:      ECC mode
+ * @engine_type: ECC engine type
+ * @placement: OOB bytes placement
  * @algo:      ECC algorithm
  * @steps:     number of ECC steps per page
  * @size:      data bytes per ECC step
@@ -338,7 +320,7 @@ static const struct nand_ecc_caps __name = {                        \
  *                     controller and always return contiguous in-band and
  *                     out-of-band data even if they're not stored
  *                     contiguously on the NAND chip (e.g.
- *                     NAND_ECC_HW_SYNDROME interleaves in-band and
+ *                     NAND_ECC_PLACEMENT_INTERLEAVED interleaves in-band and
  *                     out-of-band data).
  * @write_page_raw:    function to write a raw page without ECC. This function
  *                     should hide the specific layout used by the ECC
@@ -346,7 +328,7 @@ static const struct nand_ecc_caps __name = {                        \
  *                     in-band and out-of-band data. ECC controller is
  *                     responsible for doing the appropriate transformations
  *                     to adapt to its specific layout (e.g.
- *                     NAND_ECC_HW_SYNDROME interleaves in-band and
+ *                     NAND_ECC_PLACEMENT_INTERLEAVED interleaves in-band and
  *                     out-of-band data).
  * @read_page: function to read a page according to the ECC generator
  *             requirements; returns maximum number of bitflips corrected in
@@ -362,7 +344,8 @@ static const struct nand_ecc_caps __name = {                        \
  * @write_oob: function to write chip OOB data
  */
 struct nand_ecc_ctrl {
-       enum nand_ecc_mode mode;
+       enum nand_ecc_engine_type engine_type;
+       enum nand_ecc_placement placement;
        enum nand_ecc_algo algo;
        int steps;
        int size;
@@ -1161,9 +1144,6 @@ struct nand_chip {
        void *priv;
 };
 
-extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
-extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops;
-
 static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
 {
        return container_of(mtd, struct nand_chip, base.mtd);
index 03e92c7..dd474dd 100644 (file)
@@ -60,15 +60,16 @@ struct davinci_nand_pdata {         /* platform_data */
        struct mtd_partition    *parts;
        unsigned                nr_parts;
 
-       /* none  == NAND_ECC_NONE (strongly *not* advised!!)
-        * soft  == NAND_ECC_SOFT
-        * else  == NAND_ECC_HW, according to ecc_bits
+       /* none  == NAND_ECC_ENGINE_TYPE_NONE (strongly *not* advised!!)
+        * soft  == NAND_ECC_ENGINE_TYPE_SOFT
+        * else  == NAND_ECC_ENGINE_TYPE_ON_HOST, according to ecc_bits
         *
         * All DaVinci-family chips support 1-bit hardware ECC.
         * Newer ones also support 4-bit ECC, but are awkward
         * using it with large page chips.
         */
-       enum nand_ecc_mode      ecc_mode;
+       enum nand_ecc_engine_type engine_type;
+       enum nand_ecc_placement ecc_placement;
        u8                      ecc_bits;
 
        /* e.g. NAND_BUSWIDTH_16 */
index 08675b1..25390fc 100644 (file)
@@ -49,7 +49,7 @@ struct s3c2410_platform_nand {
 
        unsigned int    ignore_unset_ecc:1;
 
-       enum nand_ecc_mode      ecc_mode;
+       enum nand_ecc_engine_type engine_type;
 
        int                     nr_sets;
        struct s3c2410_nand_set *sets;