]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'nand/for-4.10' of github.com:linux-nand/linux
authorBrian Norris <computersforpeace@gmail.com>
Wed, 30 Nov 2016 02:28:30 +0000 (18:28 -0800)
committerBrian Norris <computersforpeace@gmail.com>
Wed, 30 Nov 2016 02:28:30 +0000 (18:28 -0800)
From Boris Brezillon:

"""
This pull request contains the following notable changes:
- new tango NAND controller driver
- new ox820 NAND controller driver
- addition of a new full-ID entry in the nand_ids table
- rework of the s3c240 driver to support DT
- extension of the nand_sdr_timings to expose tCCS, tPROG and tR
- addition of a new flag to ask the core to wait for tCCS when sending
  a RNDIN/RNDOUT command
- addition of a new flag to ask the core to let the controller driver
  send the READ/PROGPAGE command

This pull request also contains minor fixes/cleanup/cosmetic changes:
- properly support 512 ECC step size in the sunxi driver
- improve the error messages in the pxa probe path
- fix module autoload in the omap2 driver
- cleanup of several nand drivers to return nand_scan{_tail}() error
  code instead of returning -EIO
- various cleanups in the denali driver
- cleanups in the ooblayout handling (MTD core)
- fix an error check in nandsim
"""

57 files changed:
Documentation/devicetree/bindings/mtd/oxnas-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/tango-nand.txt [new file with mode: 0644]
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/mtdcore.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/cmx270_nand.c
drivers/mtd/nand/cs553x_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_dt.c
drivers/mtd/nand/denali_pci.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/hisi504_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/lpc32xx_slc.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mtk_nand.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nand_timings.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/oxnas_nand.c [new file with mode: 0644]
drivers/mtd/nand/pasemi_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/socrates_nand.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/nand/tango_nand.c [new file with mode: 0644]
drivers/mtd/nand/tmio_nand.c
drivers/mtd/nand/vf610_nfc.c
include/linux/mtd/nand.h
include/linux/platform_data/mtd-nand-s3c2410.h

diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
new file mode 100644 (file)
index 0000000..56d5c19
--- /dev/null
@@ -0,0 +1,41 @@
+* Oxford Semiconductor OXNAS NAND Controller
+
+Please refer to nand.txt for generic information regarding MTD NAND bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox820-nand"
+ - reg: Base address and length for NAND mapped memory.
+
+Optional Properties:
+ - clocks: phandle to the NAND gate clock if needed.
+ - resets: phandle to the NAND reset control if needed.
+
+Example:
+
+nandc: nand-controller@41000000 {
+       compatible = "oxsemi,ox820-nand";
+       reg = <0x41000000 0x100000>;
+       clocks = <&stdclk CLK_820_NAND>;
+       resets = <&reset RESET_NAND>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       nand@0 {
+               reg = <0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               nand-ecc-mode = "soft";
+               nand-ecc-algo = "hamming";
+
+               partition@0 {
+                       label = "boot";
+                       reg = <0x00000000 0x00e00000>;
+                       read-only;
+               };
+
+               partition@e00000 {
+                       label = "ubi";
+                       reg = <0x00e00000 0x07200000>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt b/Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
new file mode 100644 (file)
index 0000000..0040eb8
--- /dev/null
@@ -0,0 +1,56 @@
+* Samsung S3C2410 and compatible NAND flash controller
+
+Required properties:
+- compatible : The possible values are:
+       "samsung,s3c2410-nand"
+       "samsung,s3c2412-nand"
+       "samsung,s3c2440-nand"
+- reg : register's location and length.
+- #address-cells, #size-cells : see nand.txt
+- clocks : phandle to the nand controller clock
+- clock-names : must contain "nand"
+
+Optional child nodes:
+Child nodes representing the available nand chips.
+
+Optional child properties:
+- nand-ecc-mode : see nand.txt
+- nand-on-flash-bbt : see nand.txt
+
+Each child device node may optionally contain a 'partitions' sub-node,
+which further contains sub-nodes describing the flash partition mapping.
+See partition.txt for more detail.
+
+Example:
+
+nand-controller@4e000000 {
+       compatible = "samsung,s3c2440-nand";
+       reg = <0x4e000000 0x40>;
+
+       #address-cells = <1>;
+        #size-cells = <0>;
+
+       clocks = <&clocks HCLK_NAND>;
+       clock-names = "nand";
+
+       nand {
+               nand-ecc-mode = "soft";
+               nand-on-flash-bbt;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "u-boot";
+                               reg = <0 0x040000>;
+                       };
+
+                       partition@40000 {
+                               label = "kernel";
+                               reg = <0x040000 0x500000>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/tango-nand.txt b/Documentation/devicetree/bindings/mtd/tango-nand.txt
new file mode 100644 (file)
index 0000000..ad5a02f
--- /dev/null
@@ -0,0 +1,38 @@
+Sigma Designs Tango4 NAND Flash Controller (NFC)
+
+Required properties:
+
+- compatible: "sigma,smp8758-nand"
+- reg: address/size of nfc_reg, nfc_mem, and pbus_reg
+- dmas: reference to the DMA channel used by the controller
+- dma-names: "nfc_sbox"
+- clocks: reference to the system clock
+- #address-cells: <1>
+- #size-cells: <0>
+
+Children nodes represent the available NAND chips.
+See Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.
+
+Example:
+
+       nandc: nand-controller@2c000 {
+               compatible = "sigma,smp8758-nand";
+               reg = <0x2c000 0x30 0x2d000 0x800 0x20000 0x1000>;
+               dmas = <&dma0 3>;
+               dma-names = "nfc_sbox";
+               clocks = <&clkgen SYS_CLK>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               nand@0 {
+                       reg = <0>; /* CS0 */
+                       nand-ecc-strength = <14>;
+                       nand-ecc-step-size = <1024>;
+               };
+
+               nand@1 {
+                       reg = <1>; /* CS1 */
+                       nand-ecc-strength = <14>;
+                       nand-ecc-step-size = <1024>;
+               };
+       };
index e9fbcc91c5c0214811b41cd73c54cc41d18964ab..9e0bc46e90ecf54ad7ee0c42ea2326eec3992b3a 100644 (file)
@@ -171,6 +171,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,
 };
 
 /* devices we initialise */
index d03df0df01fa204cea8f172e6cf681984d3b664d..029ef1b58925499bbe657c267dab534a657e2d0b 100644 (file)
@@ -223,6 +223,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,
 };
 
 /* IDE channels */
index 9ae170fef2a7b89ca53c60f4ca3b2c48e5975c29..7b28eb623fc1ff745baf5d88fc138179c174855c 100644 (file)
@@ -114,6 +114,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,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
index ed07cf392d4bb9e2d6321a6c2c85ce0d91c52a3a..5185036765db2d096ee057774dbeadaafff11304 100644 (file)
@@ -299,6 +299,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,
 };
 
 /* DM9000 */
index 27ae6877550f7b8972c288ee32fa43a7e9a3a07c..b0ed401da3a3aaa4a901c92159cfe585cf054284 100644 (file)
@@ -443,6 +443,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,
 };
 
 
index 7d99fe8f6157612767b667d8a2360178d4c065ab..895aca225952d62f137aae798f603fa2006fc60e 100644 (file)
@@ -232,6 +232,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,
 };
 
 static int __init jive_mtdset(char *options)
index ec60bd4a1646f094edead1037483b5ed3aea3fba..71af8d2fd3201ffd95fa8588a440905d6a44abad 100644 (file)
@@ -287,6 +287,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_SOFT,
 };
 
 /* DM9000AEP 10/100 ethernet controller */
index 2f6fdc32683524b45933f3173ee3fd7d6aacbda1..70b0eb7d31347f8fbb6371148bbcc8de89a2aae0 100644 (file)
@@ -238,6 +238,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,
 };
 
 /* PCMCIA control and configuration */
index 984516e8307aa599272cdc3bee33142567e0069a..868c8208740396f649163882c238469e6a45ee7a 100644 (file)
@@ -284,6 +284,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,
 };
 
 /* UDC */
index 25a139bb9826dadfafd327bb1f2e1e4163993566..e86ad6a68a0b8f3f7c22e5ae6a5a595a611bec0e 100644 (file)
@@ -611,6 +611,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,
 };
 
 static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
index cf55196f89ca34ae4139ede777bc6a35af05fead..a39fb9780dd30649aaf7a9890c46083914f0e6ba 100644 (file)
@@ -164,6 +164,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,
 };
 
 static struct platform_device *rx3715_devices[] __initdata = {
index b4460d5f70112354e702ad799929db0d87d47aa3..f5e6322145fa9343d2a04d8d9aa9a088423054c0 100644 (file)
@@ -117,6 +117,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,
 };
 
 static struct platform_device *vstms_devices[] __initdata = {
index bc7dc1fcbf7dca8874e63a2bbbb9c24782f9bda1..59b5531f198743363eed55b3a316744eaae6d491 100644 (file)
@@ -204,6 +204,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,
 };
 
 static struct gpio_led hmt_leds[] = {
index ae999fb3fe6df564083391ba6f5a69f97bf7edb2..a3e3e25728b41f10e9c8e92908f60bda3c6b47fc 100644 (file)
@@ -142,6 +142,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,
 };
 
 static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
index 4e240ffa7ac7fbf3227141019141edf23c85ab72..d6b3ffd7704bdf7c18d48a42b6f67969dc755a8f 100644 (file)
@@ -194,6 +194,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,
 };
 
 static struct platform_device *real6410_devices[] __initdata = {
index d46e4adf6d2baa681ba782706615daa47d60b0cf..ca661cee9b77d3953fed37903db9194e687fd02e 100644 (file)
@@ -1274,8 +1274,8 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
                                            int section,
                                            struct mtd_oob_region *oobregion))
 {
-       struct mtd_oob_region oobregion = { };
-       int section = 0, ret;
+       struct mtd_oob_region oobregion;
+       int section, ret;
 
        ret = mtd_ooblayout_find_region(mtd, start, &section,
                                        &oobregion, iter);
@@ -1283,7 +1283,7 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
        while (!ret) {
                int cnt;
 
-               cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
+               cnt = min_t(int, nbytes, oobregion.length);
                memcpy(buf, oobbuf + oobregion.offset, cnt);
                buf += cnt;
                nbytes -= cnt;
@@ -1317,8 +1317,8 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
                                            int section,
                                            struct mtd_oob_region *oobregion))
 {
-       struct mtd_oob_region oobregion = { };
-       int section = 0, ret;
+       struct mtd_oob_region oobregion;
+       int section, ret;
 
        ret = mtd_ooblayout_find_region(mtd, start, &section,
                                        &oobregion, iter);
@@ -1326,7 +1326,7 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
        while (!ret) {
                int cnt;
 
-               cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
+               cnt = min_t(int, nbytes, oobregion.length);
                memcpy(oobbuf + oobregion.offset, buf, cnt);
                buf += cnt;
                nbytes -= cnt;
@@ -1354,7 +1354,7 @@ static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
                                            int section,
                                            struct mtd_oob_region *oobregion))
 {
-       struct mtd_oob_region oobregion = { };
+       struct mtd_oob_region oobregion;
        int section = 0, ret, nbytes = 0;
 
        while (1) {
index 7b7a887b4709f0122f32b60833d8c2e36bc4dead..353a9ddf6b975d48d522da646761660b35b44d4c 100644 (file)
@@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG
        help
          Enable debugging of the S3C NAND driver
 
-config MTD_NAND_S3C2410_HWECC
-       bool "Samsung S3C NAND Hardware ECC"
-       depends on MTD_NAND_S3C2410
-       help
-         Enable the use of the controller's internal ECC generator when
-         using NAND. Early versions of the chips have had problems with
-         incorrect ECC generation, and if using these, the default of
-         software ECC is preferable.
-
 config MTD_NAND_NDFC
        tristate "NDFC NanD Flash Controller"
        depends on 4xx
@@ -205,6 +196,13 @@ config MTD_NAND_S3C2410_CLKSTOP
          when the is NAND chip selected or released, but will save
          approximately 5mA of power when there is nothing happening.
 
+config MTD_NAND_TANGO
+       tristate "NAND Flash support for Tango chips"
+       depends on ARCH_TANGO || COMPILE_TEST
+       depends on HAS_DMA
+       help
+         Enables the NAND Flash controller on Tango chips.
+
 config MTD_NAND_DISKONCHIP
        tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
        depends on HAS_IOMEM
@@ -426,6 +424,11 @@ config MTD_NAND_ORION
          No board specific support is done by this driver, each board
          must advertise a platform_device for the driver to attach.
 
+config MTD_NAND_OXNAS
+       tristate "NAND Flash support for Oxford Semiconductor SoC"
+       help
+         This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
 config MTD_NAND_FSL_ELBC
        tristate "NAND support for Freescale eLBC controllers"
        depends on FSL_SOC
index cafde6f3d95761263d4c5af1395b11bfc000ca9b..19a66e404d5ba949a16a7ba358df25f033e7a51c 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_DENALI_DT)      += denali_dt.o
 obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
 obj-$(CONFIG_MTD_NAND_BF5XX)           += bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_S3C2410)         += s3c2410.o
+obj-$(CONFIG_MTD_NAND_TANGO)           += tango_nand.o
 obj-$(CONFIG_MTD_NAND_DAVINCI)         += davinci_nand.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)      += diskonchip.o
 obj-$(CONFIG_MTD_NAND_DOCG4)           += docg4.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)           += tmio_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)                += plat_nand.o
 obj-$(CONFIG_MTD_NAND_PASEMI)          += pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)           += orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS)           += oxnas_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)                += fsl_elbc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_IFC)         += fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)         += fsl_upm.o
index 78e12cc8bac2f5bc43cc54a7a809c8734571bad1..5d6c26f3cf7fc1115821133b82a2972075791e7c 100644 (file)
@@ -234,10 +234,9 @@ static int ams_delta_init(struct platform_device *pdev)
                goto out_gpio;
 
        /* Scan to find existence of the device */
-       if (nand_scan(ams_delta_mtd, 1)) {
-               err = -ENXIO;
+       err = nand_scan(ams_delta_mtd, 1);
+       if (err)
                goto out_mtd;
-       }
 
        /* Register the partitions */
        mtd_device_register(ams_delta_mtd, partition_info,
index 68b9160108c9f114f6ea83e1cda5892923d0433d..9ebd5ecefea605f1e5965ffa0f2f12395565ff16 100644 (file)
@@ -2267,10 +2267,9 @@ static int atmel_nand_probe(struct platform_device *pdev)
                dev_info(host->dev, "No DMA support for NAND access.\n");
 
        /* first scan to find the device and get the page size */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               res = -ENXIO;
+       res = nand_scan_ident(mtd, 1, NULL);
+       if (res)
                goto err_scan_ident;
-       }
 
        if (host->board.on_flash_bbt || on_flash_bbt)
                nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
@@ -2304,10 +2303,9 @@ static int atmel_nand_probe(struct platform_device *pdev)
        }
 
        /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               res = -ENXIO;
+       res = nand_scan_tail(mtd);
+       if (res)
                goto err_scan_tail;
-       }
 
        mtd->name = "atmel_nand";
        res = mtd_device_register(mtd, host->board.parts,
index 9d2424bfdbf55e221290591372ead4fbcf02ee3c..42ebd73f821dd47b9346113d06375af31b68f68c 100644 (file)
@@ -2209,8 +2209,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
        nand_writereg(ctrl, cfg_offs,
                      nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
 
-       if (nand_scan_ident(mtd, 1, NULL))
-               return -ENXIO;
+       ret = nand_scan_ident(mtd, 1, NULL);
+       if (ret)
+               return ret;
 
        chip->options |= NAND_NO_SUBPAGE_WRITE;
        /*
@@ -2234,8 +2235,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
        if (ret)
                return ret;
 
-       if (nand_scan_tail(mtd))
-               return -ENXIO;
+       ret = nand_scan_tail(mtd);
+       if (ret)
+               return ret;
 
        return mtd_device_register(mtd, NULL, 0);
 }
index 0b0c93702abbd43c96b4e48eda148db9d36ddbee..d40c32d311d8f9cb95ca20fd07cee000d7b69956 100644 (file)
@@ -725,10 +725,9 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        usedma = 0;
 
        /* Scan to find existence of the device */
-       if (nand_scan_ident(mtd, 2, NULL)) {
-               err = -ENXIO;
+       err = nand_scan_ident(mtd, 2, NULL);
+       if (err)
                goto out_irq;
-       }
 
        cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev,
                                2112 + sizeof(struct nand_buffers) +
index 49133783ca5363f723cb2b9983f02e6ef9ba6b40..226ac0bcafc6539ba6389cf1170f05ee05a2acc6 100644 (file)
@@ -195,9 +195,9 @@ static int __init cmx270_init(void)
        this->write_buf = cmx270_write_buf;
 
        /* Scan to find existence of the device */
-       if (nand_scan (cmx270_nand_mtd, 1)) {
+       ret = nand_scan(cmx270_nand_mtd, 1);
+       if (ret) {
                pr_notice("No NAND device\n");
-               ret = -ENXIO;
                goto err_scan;
        }
 
index a65e4e0f57a1c87b7eee27ea98992ed8ff0a5c57..594b28684138f1e25f5949214ffc5a68202506a0 100644 (file)
@@ -242,10 +242,9 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        }
 
        /* Scan to find existence of the device */
-       if (nand_scan(new_mtd, 1)) {
-               err = -ENXIO;
+       err = nand_scan(new_mtd, 1);
+       if (err)
                goto out_free;
-       }
 
        cs553x_mtd[cs] = new_mtd;
        goto out;
index 0476ae8776d938b09e09371d73cca855b85d4665..73b9d4e2dca0a4c7b7f198cb6fdae0922cfb864f 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
-#include <linux/slab.h>
 #include <linux/mtd/mtd.h>
 #include <linux/module.h>
 
@@ -182,9 +181,6 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali)
 {
        int i;
 
-       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
-               __FILE__, __LINE__, __func__);
-
        for (i = 0; i < denali->max_banks; i++)
                iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
                denali->flash_reg + INTR_STATUS(i));
@@ -234,9 +230,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
        uint16_t acc_clks;
        uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
 
-       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
-               __FILE__, __LINE__, __func__);
-
        en_lo = CEIL_DIV(Trp[mode], CLK_X);
        en_hi = CEIL_DIV(Treh[mode], CLK_X);
 #if ONFI_BLOOM_TIME
@@ -403,7 +396,7 @@ static void get_hynix_nand_para(struct denali_nand_info *denali,
                break;
        default:
                dev_warn(denali->dev,
-                        "Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n"
+                        "Unknown Hynix NAND (Device ID: 0x%x).\n"
                         "Will use default parameter values instead.\n",
                         device_id);
        }
@@ -474,33 +467,6 @@ static void detect_max_banks(struct denali_nand_info *denali)
                denali->max_banks = 1 << (features & FEATURES__N_BANKS);
 }
 
-static void detect_partition_feature(struct denali_nand_info *denali)
-{
-       /*
-        * For MRST platform, denali->fwblks represent the
-        * number of blocks firmware is taken,
-        * FW is in protect partition and MTD driver has no
-        * permission to access it. So let driver know how many
-        * blocks it can't touch.
-        */
-       if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) {
-               if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) &
-                       PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) {
-                       denali->fwblks =
-                           ((ioread32(denali->flash_reg + MIN_MAX_BANK(1)) &
-                             MIN_MAX_BANK__MIN_VALUE) *
-                            denali->blksperchip)
-                           +
-                           (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) &
-                           MIN_BLK_ADDR__VALUE);
-               } else {
-                       denali->fwblks = SPECTRA_START_BLOCK;
-               }
-       } else {
-               denali->fwblks = SPECTRA_START_BLOCK;
-       }
-}
-
 static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
 {
        uint16_t status = PASS;
@@ -508,9 +474,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
        uint8_t maf_id, device_id;
        int i;
 
-       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
-                       __FILE__, __LINE__, __func__);
-
        /*
         * Use read id method to get device ID and other params.
         * For some NAND chips, controller can't report the correct
@@ -552,8 +515,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
 
        find_valid_banks(denali);
 
-       detect_partition_feature(denali);
-
        /*
         * If the user specified to override the default timings
         * with a specific ONFI mode, we apply those changes here.
@@ -567,9 +528,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
 static void denali_set_intr_modes(struct denali_nand_info *denali,
                                        uint16_t INT_ENABLE)
 {
-       dev_dbg(denali->dev, "%s, Line %d, Function: %s\n",
-               __FILE__, __LINE__, __func__);
-
        if (INT_ENABLE)
                iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE);
        else
@@ -605,7 +563,6 @@ static void denali_irq_init(struct denali_nand_info *denali)
 static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali)
 {
        denali_set_intr_modes(denali, false);
-       free_irq(irqnum, denali);
 }
 
 static void denali_irq_enable(struct denali_nand_info *denali,
@@ -1437,9 +1394,6 @@ static struct nand_bbt_descr bbt_mirror_descr = {
 /* initialize driver data structures */
 static void denali_drv_init(struct denali_nand_info *denali)
 {
-       denali->idx = 0;
-
-       /* setup interrupt handler */
        /*
         * the completion object will be used to notify
         * the callee that the interrupt is done
@@ -1485,14 +1439,12 @@ int denali_init(struct denali_nand_info *denali)
        denali_hw_init(denali);
        denali_drv_init(denali);
 
-       /*
-        * denali_isr register is done after all the hardware
-        * initilization is finished
-        */
-       if (request_irq(denali->irq, denali_isr, IRQF_SHARED,
-                       DENALI_NAND_NAME, denali)) {
-               pr_err("Spectra: Unable to allocate IRQ\n");
-               return -ENODEV;
+       /* Request IRQ after all the hardware initialization is finished */
+       ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
+                              IRQF_SHARED, DENALI_NAND_NAME, denali);
+       if (ret) {
+               dev_err(denali->dev, "Unable to request IRQ\n");
+               return ret;
        }
 
        /* now that our ISR is registered, we can enable interrupts */
@@ -1510,10 +1462,9 @@ int denali_init(struct denali_nand_info *denali)
         * this is the first stage in a two step process to register
         * with the nand subsystem
         */
-       if (nand_scan_ident(mtd, denali->max_banks, NULL)) {
-               ret = -ENXIO;
+       ret = nand_scan_ident(mtd, denali->max_banks, NULL);
+       if (ret)
                goto failed_req_irq;
-       }
 
        /* allocate the right size buffer now */
        devm_kfree(denali->dev, denali->buf.buf);
@@ -1528,7 +1479,7 @@ int denali_init(struct denali_nand_info *denali)
        /* Is 32-bit DMA supported? */
        ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
        if (ret) {
-               pr_err("Spectra: no usable DMA configuration\n");
+               dev_err(denali->dev, "No usable DMA configuration\n");
                goto failed_req_irq;
        }
 
@@ -1536,7 +1487,7 @@ int denali_init(struct denali_nand_info *denali)
                             mtd->writesize + mtd->oobsize,
                             DMA_BIDIRECTIONAL);
        if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
-               dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
+               dev_err(denali->dev, "Failed to map DMA buffer\n");
                ret = -EIO;
                goto failed_req_irq;
        }
@@ -1547,16 +1498,16 @@ int denali_init(struct denali_nand_info *denali)
         * the real pagesize and anything necessery
         */
        denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
-       denali->nand.chipsize <<= (denali->devnum - 1);
-       denali->nand.page_shift += (denali->devnum - 1);
+       denali->nand.chipsize <<= denali->devnum - 1;
+       denali->nand.page_shift += denali->devnum - 1;
        denali->nand.pagemask = (denali->nand.chipsize >>
                                                denali->nand.page_shift) - 1;
-       denali->nand.bbt_erase_shift += (denali->devnum - 1);
+       denali->nand.bbt_erase_shift += denali->devnum - 1;
        denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift;
-       denali->nand.chip_shift += (denali->devnum - 1);
-       mtd->writesize <<= (denali->devnum - 1);
-       mtd->oobsize <<= (denali->devnum - 1);
-       mtd->erasesize <<= (denali->devnum - 1);
+       denali->nand.chip_shift += denali->devnum - 1;
+       mtd->writesize <<= denali->devnum - 1;
+       mtd->oobsize <<= denali->devnum - 1;
+       mtd->erasesize <<= denali->devnum - 1;
        mtd->size = denali->nand.numchips * denali->nand.chipsize;
        denali->bbtskipbytes *= denali->devnum;
 
@@ -1606,14 +1557,6 @@ int denali_init(struct denali_nand_info *denali)
        denali->nand.ecc.bytes *= denali->devnum;
        denali->nand.ecc.strength *= denali->devnum;
 
-       /*
-        * Let driver know the total blocks number and how many blocks
-        * contained by each nand chip. blksperchip will help driver to
-        * know how many blocks is taken by FW.
-        */
-       denali->totalblks = mtd->size >> denali->nand.phys_erase_shift;
-       denali->blksperchip = denali->totalblks / denali->nand.numchips;
-
        /* override the default read operations */
        denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
        denali->nand.ecc.read_page = denali_read_page;
@@ -1624,15 +1567,13 @@ int denali_init(struct denali_nand_info *denali)
        denali->nand.ecc.write_oob = denali_write_oob;
        denali->nand.erase = denali_erase;
 
-       if (nand_scan_tail(mtd)) {
-               ret = -ENXIO;
+       ret = nand_scan_tail(mtd);
+       if (ret)
                goto failed_req_irq;
-       }
 
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
-               dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n",
-                               ret);
+               dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
                goto failed_req_irq;
        }
        return 0;
index e7ab4866a5da8a8edb76e0385312a979e30b3000..ea22191e85157c1603c798fef6147a4934c9f50a 100644 (file)
 #define CLK_X  5
 #define CLK_MULTI 4
 
-/* spectraswconfig.h */
-#define CMD_DMA 0
-
-#define SPECTRA_PARTITION_ID    0
-/**** Block Table and Reserved Block Parameters *****/
-#define SPECTRA_START_BLOCK     3
-#define NUM_FREE_BLOCKS_GATE    30
-
 /* KBV - Updated to LNW scratch register address */
 #define SCRATCH_REG_ADDR    CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR
 #define SCRATCH_REG_SIZE    64
@@ -467,13 +459,9 @@ struct denali_nand_info {
        spinlock_t irq_lock;
        uint32_t irq_status;
        int irq_debug_array[32];
-       int idx;
        int irq;
 
        uint32_t devnum;        /* represent how many nands connected */
-       uint32_t fwblks; /* represent how many blocks FW used */
-       uint32_t totalblks;
-       uint32_t blksperchip;
        uint32_t bbtskipbytes;
        uint32_t max_banks;
 };
index 0cb1e8d9fbfcfe6b0d45965b87eff0d9a3c5d6a9..5607fcd3b8ed5f765219ca5bfb084290d18a962b 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/slab.h>
 
 #include "denali.h"
 
@@ -110,7 +109,7 @@ static int denali_dt_remove(struct platform_device *ofdev)
        struct denali_dt *dt = platform_get_drvdata(ofdev);
 
        denali_remove(&dt->denali);
-       clk_disable(dt->clk);
+       clk_disable_unprepare(dt->clk);
 
        return 0;
 }
index de31514df282223ba1c61f13a68631609fbe9b8d..ac843238b77e72f846c63d2eb9a8299a2d3aceb5 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/slab.h>
 
 #include "denali.h"
 
index d4f454a4b35e7e5ed8aff7a6d5a326c86d62032f..4924b43977ef8b1e2781dee0f980b5bf10950737 100644 (file)
@@ -926,8 +926,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        /*
         * Scan to find existence of the device
         */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               ret = -ENXIO;
+       ret = nand_scan_ident(mtd, 1, NULL);
+       if (ret) {
                dev_err(&pdev->dev, "No NAND Device found!\n");
                goto err_scan_ident;
        }
@@ -992,10 +992,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        }
 
        /* Second stage of scan to fill MTD data-structures */
-       if (nand_scan_tail(mtd)) {
-               ret = -ENXIO;
+       ret = nand_scan_tail(mtd);
+       if (ret)
                goto err_probe;
-       }
 
        /*
         * The partition information can is accessed by (in the same precedence)
index 6317f6836022e8cbcd144b8df10fc698524d793b..0d24857469ab396ac10c165076fd380639aa4463 100644 (file)
@@ -286,10 +286,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
 
-       if (nand_scan(mtd, 1)) {
-               ret = -ENXIO;
+       ret = nand_scan(mtd, 1);
+       if (ret)
                goto err_wp;
-       }
 
        if (gpiomtd->plat.adjust_parts)
                gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size);
index 9432546f4cd47051e742f03699c4f6058b4915c4..e40364eeb556bd23e0341a8a089d85047282acd1 100644 (file)
@@ -774,10 +774,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
        }
 
        ret = nand_scan_ident(mtd, max_chips, NULL);
-       if (ret) {
-               ret = -ENODEV;
+       if (ret)
                goto err_res;
-       }
 
        host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
                &host->dma_buffer, GFP_KERNEL);
index 852388171f2033320e7cba102c3be24d312c0f03..5553a5d9efd1144b276a20290f5cb2be9fc302f0 100644 (file)
@@ -747,10 +747,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
         * Scan to find existance of the device and
         * Get the type of NAND device SMALL block or LARGE block
         */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               res = -ENXIO;
+       res = nand_scan_ident(mtd, 1, NULL);
+       if (res)
                goto err_exit3;
-       }
 
        host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
        if (!host->dma_buf) {
@@ -793,10 +792,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
         * Fills out all the uninitialized function pointers with the defaults
         * And scans for a bad block table if appropriate.
         */
-       if (nand_scan_tail(mtd)) {
-               res = -ENXIO;
+       res = nand_scan_tail(mtd);
+       if (res)
                goto err_exit4;
-       }
 
        mtd->name = DRV_NAME;
 
index 8d3edc34958e7b356431c92b0b9ad43c89ac062c..53bafe23ab39eeffb1c51858ac9acd19cf8ca01b 100644 (file)
@@ -894,10 +894,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
 
        /* Find NAND device */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               res = -ENXIO;
+       res = nand_scan_ident(mtd, 1, NULL);
+       if (res)
                goto err_exit3;
-       }
 
        /* OOB and ECC CPU and DMA work areas */
        host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
@@ -929,10 +928,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        /*
         * Fills out all the uninitialized function pointers with the defaults
         */
-       if (nand_scan_tail(mtd)) {
-               res = -ENXIO;
+       res = nand_scan_tail(mtd);
+       if (res)
                goto err_exit3;
-       }
 
        mtd->name = "nxp_lpc3220_slc";
        res = mtd_device_register(mtd, host->ncfg->parts,
index 7eacb2f545f50366cc8996d48d3f46aaf9ed195c..6d6eaed2d20c281321df7e3245ab525866eeca80 100644 (file)
@@ -777,9 +777,9 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        }
 
        /* Detect NAND chips */
-       if (nand_scan(mtd, be32_to_cpup(chips_no))) {
+       retval = nand_scan(mtd, be32_to_cpup(chips_no));
+       if (retval) {
                dev_err(dev, "NAND Flash not found !\n");
-               retval = -ENXIO;
                goto error;
        }
 
index 5223a2182ee44dfbfbda6f578266390f52d4f8b6..6c3eed3c20941c0f9ab0ddb5f7ec86ad623a9b7e 100644 (file)
@@ -1297,7 +1297,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
 
        ret = nand_scan_ident(mtd, nsels, NULL);
        if (ret)
-               return -ENODEV;
+               return ret;
 
        /* store bbt magic in page, cause OOB is not protected */
        if (nand->bbt_options & NAND_BBT_USE_FLASH)
@@ -1323,7 +1323,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
 
        ret = nand_scan_tail(mtd);
        if (ret)
-               return -ENODEV;
+               return ret;
 
        ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
        if (ret) {
index d7f724b24fd70afa37a049ec39df98a4fe510250..61ca020c527295950241c0982b990af5967c9078 100644 (file)
@@ -1747,10 +1747,9 @@ static int mxcnd_probe(struct platform_device *pdev)
        }
 
        /* first scan to find the device and get the page size */
-       if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) {
-               err = -ENXIO;
+       err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
+       if (err)
                goto escan;
-       }
 
        switch (this->ecc.mode) {
        case NAND_ECC_HW:
@@ -1808,10 +1807,9 @@ static int mxcnd_probe(struct platform_device *pdev)
        }
 
        /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               err = -ENXIO;
+       err = nand_scan_tail(mtd);
+       if (err)
                goto escan;
-       }
 
        /* Register the partitions */
        mtd_device_parse_register(mtd, part_probes,
index 3bde96a3f7bfd5b8f066fc56af91fb1983279cdf..ec1c28aaaf23c4bb509a9710121224e46e358dde 100644 (file)
@@ -709,6 +709,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
        nand_wait_ready(mtd);
 }
 
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+       /*
+        * The controller already takes care of waiting for tCCS when the RNDIN
+        * or RNDOUT command is sent, return directly.
+        */
+       if (!(chip->options & NAND_WAIT_TCCS))
+               return;
+
+       /*
+        * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+        * (which should be safe for all NANDs).
+        */
+       if (chip->data_interface && chip->data_interface->timings.sdr.tCCS_min)
+               ndelay(chip->data_interface->timings.sdr.tCCS_min / 1000);
+       else
+               ndelay(500);
+}
+
 /**
  * nand_command_lp - [DEFAULT] Send command to NAND large page device
  * @mtd: MTD device structure
@@ -773,10 +792,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
        case NAND_CMD_ERASE1:
        case NAND_CMD_ERASE2:
        case NAND_CMD_SEQIN:
-       case NAND_CMD_RNDIN:
        case NAND_CMD_STATUS:
                return;
 
+       case NAND_CMD_RNDIN:
+               nand_ccs_delay(chip);
+               return;
+
        case NAND_CMD_RESET:
                if (chip->dev_ready)
                        break;
@@ -795,6 +817,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
                               NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
                chip->cmd_ctrl(mtd, NAND_CMD_NONE,
                               NAND_NCE | NAND_CTRL_CHANGE);
+
+               nand_ccs_delay(chip);
                return;
 
        case NAND_CMD_READ0:
@@ -1946,7 +1970,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                                 __func__, buf);
 
 read_retry:
-                       chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+                       if (nand_standard_page_accessors(&chip->ecc))
+                               chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
 
                        /*
                         * Now read the page into the buffer.  Absent an error,
@@ -2634,7 +2659,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        else
                subpage = 0;
 
-       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+       if (nand_standard_page_accessors(&chip->ecc))
+               chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
        if (unlikely(raw))
                status = chip->ecc.write_page_raw(mtd, chip, buf,
@@ -2657,7 +2683,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        if (!cached || !NAND_HAS_CACHEPROG(chip)) {
 
-               chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+               if (nand_standard_page_accessors(&chip->ecc))
+                       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
                status = chip->waitfunc(mtd, chip);
                /*
                 * See if operation failed and additional status checks are
@@ -3985,10 +4012,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
 /*
  * Get the flash and manufacturer id and lookup if the type is supported.
  */
-static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
-                                                 struct nand_chip *chip,
-                                                 int *maf_id, int *dev_id,
-                                                 struct nand_flash_dev *type)
+static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
+                              int *maf_id, int *dev_id,
+                              struct nand_flash_dev *type)
 {
        int busw;
        int i, maf_idx;
@@ -4026,7 +4052,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
                pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
                        *maf_id, *dev_id, id_data[0], id_data[1]);
-               return ERR_PTR(-ENODEV);
+               return -ENODEV;
        }
 
        if (!type)
@@ -4053,7 +4079,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        }
 
        if (!type->name)
-               return ERR_PTR(-ENODEV);
+               return -ENODEV;
 
        if (!mtd->name)
                mtd->name = type->name;
@@ -4098,7 +4124,7 @@ ident_done:
                pr_warn("bus width %d instead %d bit\n",
                           (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
                           busw ? 16 : 8);
-               return ERR_PTR(-EINVAL);
+               return -EINVAL;
        }
 
        nand_decode_bbm_options(mtd, chip, id_data);
@@ -4140,7 +4166,7 @@ ident_done:
        pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
                (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
                mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
-       return type;
+       return 0;
 }
 
 static const char * const nand_ecc_modes[] = {
@@ -4306,7 +4332,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 {
        int i, nand_maf_id, nand_dev_id;
        struct nand_chip *chip = mtd_to_nand(mtd);
-       struct nand_flash_dev *type;
        int ret;
 
        ret = nand_dt_init(chip);
@@ -4329,14 +4354,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
 
        /* Read the flash type */
-       type = nand_get_flash_type(mtd, chip, &nand_maf_id,
-                                  &nand_dev_id, table);
-
-       if (IS_ERR(type)) {
+       ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table);
+       if (ret) {
                if (!(chip->options & NAND_SCAN_SILENT_NODEV))
                        pr_warn("No NAND device found\n");
                chip->select_chip(mtd, -1);
-               return PTR_ERR(type);
+               return ret;
        }
 
        /* Initialize the ->data_interface field. */
@@ -4515,6 +4538,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
        return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
 }
 
+static bool invalid_ecc_page_accessors(struct nand_chip *chip)
+{
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (nand_standard_page_accessors(ecc))
+               return false;
+
+       /*
+        * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
+        * controller driver implements all the page accessors because
+        * default helpers are not suitable when the core does not
+        * send the READ0/PAGEPROG commands.
+        */
+       return (!ecc->read_page || !ecc->write_page ||
+               !ecc->read_page_raw || !ecc->write_page_raw ||
+               (NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) ||
+               (NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage &&
+                ecc->hwctl && ecc->calculate));
+}
+
 /**
  * nand_scan_tail - [NAND Interface] Scan for the NAND device
  * @mtd: MTD device structure
@@ -4535,6 +4578,11 @@ int nand_scan_tail(struct mtd_info *mtd)
                   !(chip->bbt_options & NAND_BBT_USE_FLASH)))
                return -EINVAL;
 
+       if (invalid_ecc_page_accessors(chip)) {
+               pr_err("Invalid ECC page accessors setup\n");
+               return -EINVAL;
+       }
+
        if (!(chip->options & NAND_OWN_BUFFERS)) {
                nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
                                + mtd->oobsize * 3, GFP_KERNEL);
index 2af9869a115e97fb72f34e19ce0b6751b30ddd11..b3a332f37e145044b7b47f999b20382648d16b3e 100644 (file)
@@ -36,6 +36,9 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"TC58NVG2S0F 4G 3.3V 8-bit",
                { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
                  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
+       {"TC58NVG2S0H 4G 3.3V 8-bit",
+               { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
+                 SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
        {"TC58NVG3S0F 8G 3.3V 8-bit",
                { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
                  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
index 13a587407be320e72147bafdc3bf641bbf0da747..f06312df3669c18cb788fc033acf6b5811db8d0a 100644 (file)
@@ -18,6 +18,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 20000,
                        .tALS_min = 50000,
@@ -58,6 +60,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 10000,
                        .tALS_min = 25000,
@@ -98,6 +102,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 10000,
                        .tALS_min = 15000,
@@ -138,6 +144,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 5000,
                        .tALS_min = 10000,
@@ -178,6 +186,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 5000,
                        .tALS_min = 10000,
@@ -218,6 +228,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        {
                .type = NAND_SDR_IFACE,
                .timings.sdr = {
+                       .tCCS_min = 500000,
+                       .tR_max = 200000000,
                        .tADL_min = 400000,
                        .tALH_min = 5000,
                        .tALS_min = 10000,
@@ -290,10 +302,22 @@ int onfi_init_data_interface(struct nand_chip *chip,
        *iface = onfi_sdr_timings[timing_mode];
 
        /*
-        * TODO: initialize timings that cannot be deduced from timing mode:
+        * Initialize timings that cannot be deduced from timing mode:
         * tR, tPROG, tCCS, ...
         * These information are part of the ONFI parameter page.
         */
+       if (chip->onfi_version) {
+               struct nand_onfi_params *params = &chip->onfi_params;
+               struct nand_sdr_timings *timings = &iface->timings.sdr;
+
+               /* microseconds -> picoseconds */
+               timings->tPROG_max = 1000000UL * le16_to_cpu(params->t_prog);
+               timings->tBERS_max = 1000000UL * le16_to_cpu(params->t_bers);
+               timings->tR_max = 1000000UL * le16_to_cpu(params->t_r);
+
+               /* nanoseconds -> picoseconds */
+               timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
+       }
 
        return 0;
 }
index 1eb934414eb5804978994a382dbb1d782ca59e53..c84742671a5f9782a23bec53b0182de0e8871289 100644 (file)
@@ -525,24 +525,20 @@ static int nandsim_debugfs_create(struct nandsim *dev)
 {
        struct nandsim_debug_info *dbg = &dev->dbg;
        struct dentry *dent;
-       int err;
 
        if (!IS_ENABLED(CONFIG_DEBUG_FS))
                return 0;
 
        dent = debugfs_create_dir("nandsim", NULL);
-       if (IS_ERR_OR_NULL(dent)) {
-               int err = dent ? -ENODEV : PTR_ERR(dent);
-
-               NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
-                       err);
-               return err;
+       if (!dent) {
+               NS_ERR("cannot create \"nandsim\" debugfs directory\n");
+               return -ENODEV;
        }
        dbg->dfs_root = dent;
 
        dent = debugfs_create_file("wear_report", S_IRUSR,
                                   dbg->dfs_root, dev, &dfs_fops);
-       if (IS_ERR_OR_NULL(dent))
+       if (!dent)
                goto out_remove;
        dbg->dfs_wear_report = dent;
 
@@ -550,8 +546,7 @@ static int nandsim_debugfs_create(struct nandsim *dev)
 
 out_remove:
        debugfs_remove_recursive(dbg->dfs_root);
-       err = dent ? PTR_ERR(dent) : -ENODEV;
-       return err;
+       return -ENODEV;
 }
 
 /**
@@ -2313,8 +2308,6 @@ static int __init ns_init_module(void)
        retval = nand_scan_ident(nsmtd, 1, NULL);
        if (retval) {
                NS_ERR("cannot scan NAND Simulator device\n");
-               if (retval > 0)
-                       retval = -ENXIO;
                goto error;
        }
 
@@ -2350,8 +2343,6 @@ static int __init ns_init_module(void)
        retval = nand_scan_tail(nsmtd);
        if (retval) {
                NS_ERR("can't register NAND Simulator\n");
-               if (retval > 0)
-                       retval = -ENXIO;
                goto error;
        }
 
index 5513bfd9cdc90ed8e2628e311b7a92e02bfe0cd7..2a52101120d466dc81d27eb8ac2c9fd10b19fb5e 100644 (file)
@@ -1895,10 +1895,10 @@ static int omap_nand_probe(struct platform_device *pdev)
 
        /* scan NAND device connected to chip controller */
        nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
-       if (nand_scan_ident(mtd, 1, NULL)) {
+       err = nand_scan_ident(mtd, 1, NULL);
+       if (err) {
                dev_err(&info->pdev->dev,
                        "scan failed, may be bus-width mismatch\n");
-               err = -ENXIO;
                goto return_error;
        }
 
@@ -2154,10 +2154,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 
 scan_tail:
        /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               err = -ENXIO;
+       err = nand_scan_tail(mtd);
+       if (err)
                goto return_error;
-       }
 
        if (dev->of_node)
                mtd_device_register(mtd, NULL, 0);
@@ -2197,6 +2196,7 @@ static const struct of_device_id omap_nand_ids[] = {
        { .compatible = "ti,omap2-nand", },
        {},
 };
+MODULE_DEVICE_TABLE(of, omap_nand_ids);
 
 static struct platform_driver omap_nand_driver = {
        .probe          = omap_nand_probe,
index 40a7c4a2cf0d44c8f407dc6c170d44cc8d768510..4a91c5d000be790bc6200a50a9d00f80f4de9bc4 100644 (file)
@@ -155,10 +155,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)
                clk_put(clk);
        }
 
-       if (nand_scan(mtd, 1)) {
-               ret = -ENXIO;
+       ret = nand_scan(mtd, 1);
+       if (ret)
                goto no_dev;
-       }
 
        mtd->name = "orion_nand";
        ret = mtd_device_register(mtd, board->parts, board->nr_parts);
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
new file mode 100644 (file)
index 0000000..3e3bf3b
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+
+ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+/* Nand commands */
+#define OXNAS_NAND_CMD_ALE             BIT(18)
+#define OXNAS_NAND_CMD_CLE             BIT(19)
+
+#define OXNAS_NAND_MAX_CHIPS   1
+
+struct oxnas_nand_ctrl {
+       struct nand_hw_control base;
+       void __iomem *io_base;
+       struct clk *clk;
+       struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
+};
+
+static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+       return readb(oxnas->io_base);
+}
+
+static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+       ioread8_rep(oxnas->io_base, buf, len);
+}
+
+static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+       iowrite8_rep(oxnas->io_base, buf, len);
+}
+
+/* Single CS command control */
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+                               unsigned int ctrl)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
+
+       if (ctrl & NAND_CLE)
+               writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
+       else if (ctrl & NAND_ALE)
+               writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *nand_np;
+       struct oxnas_nand_ctrl *oxnas;
+       struct nand_chip *chip;
+       struct mtd_info *mtd;
+       struct resource *res;
+       int nchips = 0;
+       int count = 0;
+       int err = 0;
+
+       /* Allocate memory for the device structure (and zero it) */
+       oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+                            GFP_KERNEL);
+       if (!oxnas)
+               return -ENOMEM;
+
+       nand_hw_control_init(&oxnas->base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(oxnas->io_base))
+               return PTR_ERR(oxnas->io_base);
+
+       oxnas->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(oxnas->clk))
+               oxnas->clk = NULL;
+
+       /* Only a single chip node is supported */
+       count = of_get_child_count(np);
+       if (count > 1)
+               return -EINVAL;
+
+       clk_prepare_enable(oxnas->clk);
+       device_reset_optional(&pdev->dev);
+
+       for_each_child_of_node(np, nand_np) {
+               chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
+                                   GFP_KERNEL);
+               if (!chip)
+                       return -ENOMEM;
+
+               chip->controller = &oxnas->base;
+
+               nand_set_flash_node(chip, nand_np);
+               nand_set_controller_data(chip, oxnas);
+
+               mtd = nand_to_mtd(chip);
+               mtd->dev.parent = &pdev->dev;
+               mtd->priv = chip;
+
+               chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
+               chip->read_buf = oxnas_nand_read_buf;
+               chip->read_byte = oxnas_nand_read_byte;
+               chip->write_buf = oxnas_nand_write_buf;
+               chip->chip_delay = 30;
+
+               /* Scan to find existence of the device */
+               err = nand_scan(mtd, 1);
+               if (err)
+                       return err;
+
+               err = mtd_device_register(mtd, NULL, 0);
+               if (err) {
+                       nand_release(mtd);
+                       return err;
+               }
+
+               oxnas->chips[nchips] = chip;
+               ++nchips;
+       }
+
+       /* Exit if no chips found */
+       if (!nchips)
+               return -ENODEV;
+
+       platform_set_drvdata(pdev, oxnas);
+
+       return 0;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+       struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
+
+       if (oxnas->chips[0])
+               nand_release(nand_to_mtd(oxnas->chips[0]));
+
+       clk_disable_unprepare(oxnas->clk);
+
+       return 0;
+}
+
+static const struct of_device_id oxnas_nand_match[] = {
+       { .compatible = "oxsemi,ox820-nand" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, oxnas_nand_match);
+
+static struct platform_driver oxnas_nand_driver = {
+       .probe  = oxnas_nand_probe,
+       .remove = oxnas_nand_remove,
+       .driver = {
+               .name           = "oxnas_nand",
+               .of_match_table = oxnas_nand_match,
+       },
+};
+
+module_platform_driver(oxnas_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
index 5de7591b05106bcbf172ad3bc3c6c8013c8b4c32..074b8b01289e185bc153135ee9be79c933920bcc 100644 (file)
@@ -156,10 +156,9 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
        chip->bbt_options = NAND_BBT_USE_FLASH;
 
        /* Scan to find existence of the device */
-       if (nand_scan(pasemi_nand_mtd, 1)) {
-               err = -ENXIO;
+       err = nand_scan(pasemi_nand_mtd, 1);
+       if (err)
                goto out_lpc;
-       }
 
        if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) {
                dev_err(dev, "Unable to register MTD device\n");
index 415a53a0deeb306bb5baeaf3f5ad6638fd41d103..791de3e4bbb681392a50c510883f00c95cdd47cd 100644 (file)
@@ -86,10 +86,9 @@ static int plat_nand_probe(struct platform_device *pdev)
        }
 
        /* Scan to find existence of the device */
-       if (nand_scan(mtd, pdata->chip.nr_chips)) {
-               err = -ENXIO;
+       err = nand_scan(mtd, pdata->chip.nr_chips);
+       if (err)
                goto out;
-       }
 
        part_types = pdata->chip.part_probe_types;
 
index b121bf4ed73a2d50aca1935cffe2e6bf3639c26d..649ba8200832d5ba3d237327fd3861d9844c2149 100644 (file)
@@ -1680,8 +1680,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
        chip->ecc.strength = pdata->ecc_strength;
        chip->ecc.size = pdata->ecc_step_size;
 
-       if (nand_scan_ident(mtd, 1, NULL))
-               return -ENODEV;
+       ret = nand_scan_ident(mtd, 1, NULL);
+       if (ret)
+               return ret;
 
        if (!pdata->keep_config) {
                ret = pxa3xx_nand_init(host);
@@ -1774,8 +1775,11 @@ static int alloc_nand_resource(struct platform_device *pdev)
        int ret, irq, cs;
 
        pdata = dev_get_platdata(&pdev->dev);
-       if (pdata->num_cs <= 0)
+       if (pdata->num_cs <= 0) {
+               dev_err(&pdev->dev, "invalid number of chip selects\n");
                return -ENODEV;
+       }
+
        info = devm_kzalloc(&pdev->dev,
                            sizeof(*info) + sizeof(*host) * pdata->num_cs,
                            GFP_KERNEL);
@@ -1813,8 +1817,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
        nand_hw_control_init(chip->controller);
        info->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(info->clk)) {
-               dev_err(&pdev->dev, "failed to get nand clock\n");
-               return PTR_ERR(info->clk);
+               ret = PTR_ERR(info->clk);
+               dev_err(&pdev->dev, "failed to get nand clock: %d\n", ret);
+               return ret;
        }
        ret = clk_prepare_enable(info->clk);
        if (ret < 0)
@@ -1842,6 +1847,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
        info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(info->mmio_base)) {
                ret = PTR_ERR(info->mmio_base);
+               dev_err(&pdev->dev, "failed to map register space: %d\n", ret);
                goto fail_disable_clk;
        }
        info->mmio_phys = r->start;
@@ -1861,7 +1867,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
                                   pxa3xx_nand_irq_thread, IRQF_ONESHOT,
                                   pdev->name, info);
        if (ret < 0) {
-               dev_err(&pdev->dev, "failed to request IRQ\n");
+               dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
                goto fail_free_buf;
        }
 
@@ -1960,10 +1966,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        }
 
        ret = alloc_nand_resource(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "alloc nand resource failed\n");
+       if (ret)
                return ret;
-       }
 
        info = platform_get_drvdata(pdev);
        probe_success = 0;
index d459c19d78de383c1c2a88a1bcda0d1301b3c003..f0b030d44f71ff2add4383196fba0c9e02350277 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -185,6 +187,22 @@ struct s3c2410_nand_info {
 #endif
 };
 
+struct s3c24XX_nand_devtype_data {
+       enum s3c_cpu_type type;
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = {
+       .type = TYPE_S3C2410,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = {
+       .type = TYPE_S3C2412,
+};
+
+static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = {
+       .type = TYPE_S3C2440,
+};
+
 /* conversion functions */
 
 static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
@@ -497,7 +515,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
 
 /* ECC handling functions */
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
                                     u_char *read_ecc, u_char *calc_ecc)
 {
@@ -649,7 +666,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 
        return 0;
 }
-#endif
 
 /* over-ride the standard functions for a little more speed. We can
  * use read/write block to move the data buffers to/from the controller
@@ -796,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
        return -ENODEV;
 }
 
+static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd,
+                                       const struct nand_data_interface *conf,
+                                       bool check_only)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       struct s3c2410_platform_nand *pdata = info->platform;
+       const struct nand_sdr_timings *timings;
+       int tacls;
+
+       timings = nand_get_sdr_timings(conf);
+       if (IS_ERR(timings))
+               return -ENOTSUPP;
+
+       tacls = timings->tCLS_min - timings->tWP_min;
+       if (tacls < 0)
+               tacls = 0;
+
+       pdata->tacls  = DIV_ROUND_UP(tacls, 1000);
+       pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000);
+       pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000);
+
+       return s3c2410_nand_setrate(info);
+}
+
 /**
  * s3c2410_nand_init_chip - initialise a single instance of an chip
  * @info: The base NAND controller the chip is on.
@@ -810,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
                                   struct s3c2410_nand_mtd *nmtd,
                                   struct s3c2410_nand_set *set)
 {
+       struct device_node *np = info->device->of_node;
        struct nand_chip *chip = &nmtd->chip;
        void __iomem *regs = info->regs;
 
+       nand_set_flash_node(chip, set->of_node);
+
        chip->write_buf    = s3c2410_nand_write_buf;
        chip->read_buf     = s3c2410_nand_read_buf;
        chip->select_chip  = s3c2410_nand_select_chip;
@@ -821,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        chip->options      = set->options;
        chip->controller   = &info->controller;
 
+       /*
+        * let's keep behavior unchanged for legacy boards booting via pdata and
+        * auto-detect timings only when booting with a device tree.
+        */
+       if (np)
+               chip->setup_data_interface = s3c2410_nand_setup_data_interface;
+
        switch (info->cpu_type) {
        case TYPE_S3C2410:
                chip->IO_ADDR_W = regs + S3C2410_NFDATA;
@@ -858,58 +908,14 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
        nmtd->info         = info;
        nmtd->set          = set;
 
-#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
-       chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-       chip->ecc.correct   = s3c2410_nand_correct_data;
-       chip->ecc.mode      = NAND_ECC_HW;
-       chip->ecc.strength  = 1;
+       chip->ecc.mode = info->platform->ecc_mode;
 
-       switch (info->cpu_type) {
-       case TYPE_S3C2410:
-               chip->ecc.hwctl     = s3c2410_nand_enable_hwecc;
-               chip->ecc.calculate = s3c2410_nand_calculate_ecc;
-               break;
-
-       case TYPE_S3C2412:
-               chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
-               chip->ecc.calculate = s3c2412_nand_calculate_ecc;
-               break;
-
-       case TYPE_S3C2440:
-               chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-               chip->ecc.calculate = s3c2440_nand_calculate_ecc;
-               break;
-       }
-#else
-       chip->ecc.mode      = NAND_ECC_SOFT;
-       chip->ecc.algo  = NAND_ECC_HAMMING;
-#endif
-
-       if (set->disable_ecc)
-               chip->ecc.mode  = NAND_ECC_NONE;
-
-       switch (chip->ecc.mode) {
-       case NAND_ECC_NONE:
-               dev_info(info->device, "NAND ECC disabled\n");
-               break;
-       case NAND_ECC_SOFT:
-               dev_info(info->device, "NAND soft ECC\n");
-               break;
-       case NAND_ECC_HW:
-               dev_info(info->device, "NAND hardware ECC\n");
-               break;
-       default:
-               dev_info(info->device, "NAND ECC UNKNOWN\n");
-               break;
-       }
-
-       /* If you use u-boot BBT creation code, specifying this flag will
-        * let the kernel fish out the BBT from the NAND, and also skip the
-        * full NAND scan that can take 1/2s or so. Little things... */
-       if (set->flash_bbt) {
+       /*
+        * If you use u-boot BBT creation code, specifying this flag will
+        * let the kernel fish out the BBT from the NAND.
+        */
+       if (set->flash_bbt)
                chip->bbt_options |= NAND_BBT_USE_FLASH;
-               chip->options |= NAND_SKIP_BBTSCAN;
-       }
 }
 
 /**
@@ -923,28 +929,146 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
  *
  * The internal state is currently limited to the ECC state information.
 */
-static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
-                                    struct s3c2410_nand_mtd *nmtd)
+static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
+                                   struct s3c2410_nand_mtd *nmtd)
 {
        struct nand_chip *chip = &nmtd->chip;
 
-       dev_dbg(info->device, "chip %p => page shift %d\n",
-               chip, chip->page_shift);
+       switch (chip->ecc.mode) {
 
-       if (chip->ecc.mode != NAND_ECC_HW)
-               return;
+       case NAND_ECC_NONE:
+               dev_info(info->device, "ECC disabled\n");
+               break;
+
+       case NAND_ECC_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.
+                */
+               chip->ecc.algo = NAND_ECC_HAMMING;
+               dev_info(info->device, "soft ECC\n");
+               break;
+
+       case NAND_ECC_HW:
+               chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+               chip->ecc.correct   = s3c2410_nand_correct_data;
+               chip->ecc.strength  = 1;
+
+               switch (info->cpu_type) {
+               case TYPE_S3C2410:
+                       chip->ecc.hwctl     = s3c2410_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+                       break;
+
+               case TYPE_S3C2412:
+                       chip->ecc.hwctl     = s3c2412_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+                       break;
+
+               case TYPE_S3C2440:
+                       chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+                       chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+                       break;
+               }
+
+               dev_dbg(info->device, "chip %p => page shift %d\n",
+                       chip, chip->page_shift);
 
                /* change the behaviour depending on whether we are using
                 * the large or small page nand device */
+               if (chip->page_shift > 10) {
+                       chip->ecc.size      = 256;
+                       chip->ecc.bytes     = 3;
+               } else {
+                       chip->ecc.size      = 512;
+                       chip->ecc.bytes     = 3;
+                       mtd_set_ooblayout(nand_to_mtd(chip),
+                                         &s3c2410_ooblayout_ops);
+               }
 
-       if (chip->page_shift > 10) {
-               chip->ecc.size      = 256;
-               chip->ecc.bytes     = 3;
-       } else {
-               chip->ecc.size      = 512;
-               chip->ecc.bytes     = 3;
-               mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops);
+               dev_info(info->device, "hardware ECC\n");
+               break;
+
+       default:
+               dev_err(info->device, "invalid ECC mode!\n");
+               return -EINVAL;
        }
+
+       if (chip->bbt_options & NAND_BBT_USE_FLASH)
+               chip->options |= NAND_SKIP_BBTSCAN;
+
+       return 0;
+}
+
+static const struct of_device_id s3c24xx_nand_dt_ids[] = {
+       {
+               .compatible = "samsung,s3c2410-nand",
+               .data = &s3c2410_nand_devtype_data,
+       }, {
+               /* also compatible with s3c6400 */
+               .compatible = "samsung,s3c2412-nand",
+               .data = &s3c2412_nand_devtype_data,
+       }, {
+               .compatible = "samsung,s3c2440-nand",
+               .data = &s3c2440_nand_devtype_data,
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids);
+
+static int s3c24xx_nand_probe_dt(struct platform_device *pdev)
+{
+       const struct s3c24XX_nand_devtype_data *devtype_data;
+       struct s3c2410_platform_nand *pdata;
+       struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+       struct device_node *np = pdev->dev.of_node, *child;
+       struct s3c2410_nand_set *sets;
+
+       devtype_data = of_device_get_match_data(&pdev->dev);
+       if (!devtype_data)
+               return -ENODEV;
+
+       info->cpu_type = devtype_data->type;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       pdev->dev.platform_data = pdata;
+
+       pdata->nr_sets = of_get_child_count(np);
+       if (!pdata->nr_sets)
+               return 0;
+
+       sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets,
+                           GFP_KERNEL);
+       if (!sets)
+               return -ENOMEM;
+
+       pdata->sets = sets;
+
+       for_each_available_child_of_node(np, child) {
+               sets->name = (char *)child->name;
+               sets->of_node = child;
+               sets->nr_chips = 1;
+
+               of_node_get(child);
+
+               sets++;
+       }
+
+       return 0;
+}
+
+static int s3c24xx_nand_probe_pdata(struct platform_device *pdev)
+{
+       struct s3c2410_nand_info *info = platform_get_drvdata(pdev);
+
+       info->cpu_type = platform_get_device_id(pdev)->driver_data;
+
+       return 0;
 }
 
 /* s3c24xx_nand_probe
@@ -956,8 +1080,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
 */
 static int s3c24xx_nand_probe(struct platform_device *pdev)
 {
-       struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
-       enum s3c_cpu_type cpu_type;
+       struct s3c2410_platform_nand *plat;
        struct s3c2410_nand_info *info;
        struct s3c2410_nand_mtd *nmtd;
        struct s3c2410_nand_set *sets;
@@ -967,8 +1090,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
        int nr_sets;
        int setno;
 
-       cpu_type = platform_get_device_id(pdev)->driver_data;
-
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (info == NULL) {
                err = -ENOMEM;
@@ -990,6 +1111,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
        s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
 
+       if (pdev->dev.of_node)
+               err = s3c24xx_nand_probe_dt(pdev);
+       else
+               err = s3c24xx_nand_probe_pdata(pdev);
+
+       if (err)
+               goto exit_error;
+
+       plat = to_nand_plat(pdev);
+
        /* allocate and map the resource */
 
        /* currently we assume we have the one resource */
@@ -998,7 +1129,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
        info->device    = &pdev->dev;
        info->platform  = plat;
-       info->cpu_type  = cpu_type;
 
        info->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(info->regs)) {
@@ -1008,12 +1138,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
 
-       /* initialise the hardware */
-
-       err = s3c2410_nand_inithw(info);
-       if (err != 0)
-               goto exit_error;
-
        sets = (plat != NULL) ? plat->sets : NULL;
        nr_sets = (plat != NULL) ? plat->nr_sets : 1;
 
@@ -1046,7 +1170,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
                                                 NULL);
 
                if (nmtd->scan_res == 0) {
-                       s3c2410_nand_update_chip(info, nmtd);
+                       err = s3c2410_nand_update_chip(info, nmtd);
+                       if (err < 0)
+                               goto exit_error;
                        nand_scan_tail(mtd);
                        s3c2410_nand_add_partition(info, nmtd, sets);
                }
@@ -1055,6 +1181,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
                        sets++;
        }
 
+       /* initialise the hardware */
+       err = s3c2410_nand_inithw(info);
+       if (err != 0)
+               goto exit_error;
+
        err = s3c2410_nand_cpufreq_register(info);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to init cpufreq support\n");
@@ -1155,6 +1286,7 @@ static struct platform_driver s3c24xx_nand_driver = {
        .id_table       = s3c24xx_driver_ids,
        .driver         = {
                .name   = "s3c24xx-nand",
+               .of_match_table = s3c24xx_nand_dt_ids,
        },
 };
 
index 888fd314c62a234b7a43e3c922a3d4dbb14e36c9..72369bd079af2afc216a21a1da6fc3b1fd857462 100644 (file)
@@ -187,17 +187,9 @@ static int socrates_nand_probe(struct platform_device *ofdev)
 
        dev_set_drvdata(&ofdev->dev, host);
 
-       /* first scan to find the device and get the page size */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               res = -ENXIO;
+       res = nand_scan(mtd, 1);
+       if (res)
                goto out;
-       }
-
-       /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               res = -ENXIO;
-               goto out;
-       }
 
        res = mtd_device_register(mtd, NULL, 0);
        if (!res)
index 8b8470c4e6d02d2058264cd2a74847ce343df129..e40482a65de6683264950a0caeba55484b1ffedf 100644 (file)
 #define NFC_ECC_PIPELINE       BIT(3)
 #define NFC_ECC_EXCEPTION      BIT(4)
 #define NFC_ECC_BLOCK_SIZE_MSK BIT(5)
+#define NFC_ECC_BLOCK_512      BIT(5)
 #define NFC_RANDOM_EN          BIT(9)
 #define NFC_RANDOM_DIRECTION   BIT(10)
 #define NFC_ECC_MODE_MSK       GENMASK(15, 12)
@@ -817,6 +818,9 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
        ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION |
                   NFC_ECC_PIPELINE;
 
+       if (nand->ecc.size == 512)
+               ecc_ctl |= NFC_ECC_BLOCK_512;
+
        writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
 }
 
diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
new file mode 100644 (file)
index 0000000..ec87516
--- /dev/null
@@ -0,0 +1,668 @@
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+/* Offsets relative to chip->base */
+#define PBUS_CMD       0
+#define PBUS_ADDR      4
+#define PBUS_DATA      8
+
+/* Offsets relative to reg_base */
+#define NFC_STATUS     0x00
+#define NFC_FLASH_CMD  0x04
+#define NFC_DEVICE_CFG 0x08
+#define NFC_TIMING1    0x0c
+#define NFC_TIMING2    0x10
+#define NFC_XFER_CFG   0x14
+#define NFC_PKT_0_CFG  0x18
+#define NFC_PKT_N_CFG  0x1c
+#define NFC_BB_CFG     0x20
+#define NFC_ADDR_PAGE  0x24
+#define NFC_ADDR_OFFSET        0x28
+#define NFC_XFER_STATUS        0x2c
+
+/* NFC_STATUS values */
+#define CMD_READY      BIT(31)
+
+/* NFC_FLASH_CMD values */
+#define NFC_READ       1
+#define NFC_WRITE      2
+
+/* NFC_XFER_STATUS values */
+#define PAGE_IS_EMPTY  BIT(16)
+
+/* Offsets relative to mem_base */
+#define METADATA       0x000
+#define ERROR_REPORT   0x1c0
+
+/*
+ * Error reports are split in two bytes:
+ * byte 0 for the first packet in the page (PKT_0)
+ * byte 1 for other packets in the page (PKT_N, for N > 0)
+ * ERR_COUNT_PKT_N is the max error count over all but the first packet.
+ */
+#define DECODE_OK_PKT_0(v)     ((v) & BIT(7))
+#define DECODE_OK_PKT_N(v)     ((v) & BIT(15))
+#define ERR_COUNT_PKT_0(v)     (((v) >> 0) & 0x3f)
+#define ERR_COUNT_PKT_N(v)     (((v) >> 8) & 0x3f)
+
+/* Offsets relative to pbus_base */
+#define PBUS_CS_CTRL   0x83c
+#define PBUS_PAD_MODE  0x8f0
+
+/* PBUS_CS_CTRL values */
+#define PBUS_IORDY     BIT(31)
+
+/*
+ * PBUS_PAD_MODE values
+ * In raw mode, the driver communicates directly with the NAND chips.
+ * In NFC mode, the NAND Flash controller manages the communication.
+ * We use NFC mode for read and write; raw mode for everything else.
+ */
+#define MODE_RAW       0
+#define MODE_NFC       BIT(31)
+
+#define METADATA_SIZE  4
+#define BBM_SIZE       6
+#define FIELD_ORDER    15
+
+#define MAX_CS         4
+
+struct tango_nfc {
+       struct nand_hw_control hw;
+       void __iomem *reg_base;
+       void __iomem *mem_base;
+       void __iomem *pbus_base;
+       struct tango_chip *chips[MAX_CS];
+       struct dma_chan *chan;
+       int freq_kHz;
+};
+
+#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw)
+
+struct tango_chip {
+       struct nand_chip nand_chip;
+       void __iomem *base;
+       u32 timing1;
+       u32 timing2;
+       u32 xfer_cfg;
+       u32 pkt_0_cfg;
+       u32 pkt_n_cfg;
+       u32 bb_cfg;
+};
+
+#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip)
+
+#define XFER_CFG(cs, page_count, steps, metadata_size) \
+       ((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size))
+
+#define PKT_CFG(size, strength) ((size) << 16 | (strength))
+
+#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size))
+
+#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
+
+static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+       if (ctrl & NAND_CLE)
+               writeb_relaxed(dat, tchip->base + PBUS_CMD);
+
+       if (ctrl & NAND_ALE)
+               writeb_relaxed(dat, tchip->base + PBUS_ADDR);
+}
+
+static int tango_dev_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+
+       return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
+}
+
+static u8 tango_read_byte(struct mtd_info *mtd)
+{
+       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+       return readb_relaxed(tchip->base + PBUS_DATA);
+}
+
+static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+       ioread8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+
+       iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
+}
+
+static void tango_select_chip(struct mtd_info *mtd, int idx)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+       struct tango_chip *tchip = to_tango_chip(chip);
+
+       if (idx < 0)
+               return; /* No "chip unselect" function */
+
+       writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
+       writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
+       writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
+       writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
+       writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
+       writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
+}
+
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int check_erased_page(struct nand_chip *chip, u8 *buf)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       u8 *meta = chip->oob_poi + BBM_SIZE;
+       u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE;
+       const int ecc_size = chip->ecc.bytes;
+       const int pkt_size = chip->ecc.size;
+       int i, res, meta_len, bitflips = 0;
+
+       for (i = 0; i < chip->ecc.steps; ++i) {
+               meta_len = i ? 0 : METADATA_SIZE;
+               res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+                                                 meta, meta_len,
+                                                 chip->ecc.strength);
+               if (res < 0)
+                       mtd->ecc_stats.failed++;
+
+               bitflips = max(res, bitflips);
+               buf += pkt_size;
+               ecc += ecc_size;
+       }
+
+       return bitflips;
+}
+
+static int decode_error_report(struct tango_nfc *nfc)
+{
+       u32 status, res;
+
+       status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS);
+       if (status & PAGE_IS_EMPTY)
+               return 0;
+
+       res = readl_relaxed(nfc->mem_base + ERROR_REPORT);
+
+       if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res))
+               return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res));
+
+       return -EBADMSG;
+}
+
+static void tango_dma_callback(void *arg)
+{
+       complete(arg);
+}
+
+static int do_dma(struct tango_nfc *nfc, int dir, int cmd, const void *buf,
+                 int len, int page)
+{
+       void __iomem *addr = nfc->reg_base + NFC_STATUS;
+       struct dma_chan *chan = nfc->chan;
+       struct dma_async_tx_descriptor *desc;
+       struct scatterlist sg;
+       struct completion tx_done;
+       int err = -EIO;
+       u32 res, val;
+
+       sg_init_one(&sg, buf, len);
+       if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
+               return -EIO;
+
+       desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
+       if (!desc)
+               goto dma_unmap;
+
+       desc->callback = tango_dma_callback;
+       desc->callback_param = &tx_done;
+       init_completion(&tx_done);
+
+       writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE);
+
+       writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE);
+       writel_relaxed(0, nfc->reg_base + NFC_ADDR_OFFSET);
+       writel_relaxed(cmd, nfc->reg_base + NFC_FLASH_CMD);
+
+       dmaengine_submit(desc);
+       dma_async_issue_pending(chan);
+
+       res = wait_for_completion_timeout(&tx_done, HZ);
+       if (res > 0)
+               err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000);
+
+       writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+
+dma_unmap:
+       dma_unmap_sg(chan->device->dev, &sg, 1, dir);
+
+       return err;
+}
+
+static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                          u8 *buf, int oob_required, int page)
+{
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+       int err, res, len = mtd->writesize;
+
+       if (oob_required)
+               chip->ecc.read_oob(mtd, chip, page);
+
+       err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
+       if (err)
+               return err;
+
+       res = decode_error_report(nfc);
+       if (res < 0) {
+               chip->ecc.read_oob_raw(mtd, chip, page);
+               res = check_erased_page(chip, buf);
+       }
+
+       return res;
+}
+
+static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                           const u8 *buf, int oob_required, int page)
+{
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+       int err, len = mtd->writesize;
+
+       /* Calling tango_write_oob() would send PAGEPROG twice */
+       if (oob_required)
+               return -ENOTSUPP;
+
+       writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
+       err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
+       *pos += len;
+
+       if (!*buf) {
+               /* skip over "len" bytes */
+               chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1);
+       } else {
+               tango_read_buf(mtd, *buf, len);
+               *buf += len;
+       }
+}
+
+static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
+       *pos += len;
+
+       if (!*buf) {
+               /* skip over "len" bytes */
+               chip->cmdfunc(mtd, NAND_CMD_SEQIN, *pos, -1);
+       } else {
+               tango_write_buf(mtd, *buf, len);
+               *buf += len;
+       }
+}
+
+/*
+ * Physical page layout (not drawn to scale)
+ *
+ * NB: Bad Block Marker area splits PKT_N in two (N1, N2).
+ *
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ * | M |      PKT_0      | ECC_0 | ... |     N1    | BBM | N2 | ECC_N |
+ * +---+-----------------+-------+-----+-----------+-----+----+-------+
+ *
+ * Logical page layout:
+ *
+ *       +-----+---+-------+-----+-------+
+ * oob = | BBM | M | ECC_0 | ... | ECC_N |
+ *       +-----+---+-------+-----+-------+
+ *
+ *       +-----------------+-----+-----------------+
+ * buf = |      PKT_0      | ... |      PKT_N      |
+ *       +-----------------+-----+-----------------+
+ */
+static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       u8 *oob_orig = oob;
+       const int page_size = mtd->writesize;
+       const int ecc_size = chip->ecc.bytes;
+       const int pkt_size = chip->ecc.size;
+       int pos = 0; /* position within physical page */
+       int rem = page_size; /* bytes remaining until BBM area */
+
+       if (oob)
+               oob += BBM_SIZE;
+
+       aux_read(chip, &oob, METADATA_SIZE, &pos);
+
+       while (rem > pkt_size) {
+               aux_read(chip, &buf, pkt_size, &pos);
+               aux_read(chip, &oob, ecc_size, &pos);
+               rem = page_size - pos;
+       }
+
+       aux_read(chip, &buf, rem, &pos);
+       aux_read(chip, &oob_orig, BBM_SIZE, &pos);
+       aux_read(chip, &buf, pkt_size - rem, &pos);
+       aux_read(chip, &oob, ecc_size, &pos);
+}
+
+static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       const u8 *oob_orig = oob;
+       const int page_size = mtd->writesize;
+       const int ecc_size = chip->ecc.bytes;
+       const int pkt_size = chip->ecc.size;
+       int pos = 0; /* position within physical page */
+       int rem = page_size; /* bytes remaining until BBM area */
+
+       if (oob)
+               oob += BBM_SIZE;
+
+       aux_write(chip, &oob, METADATA_SIZE, &pos);
+
+       while (rem > pkt_size) {
+               aux_write(chip, &buf, pkt_size, &pos);
+               aux_write(chip, &oob, ecc_size, &pos);
+               rem = page_size - pos;
+       }
+
+       aux_write(chip, &buf, rem, &pos);
+       aux_write(chip, &oob_orig, BBM_SIZE, &pos);
+       aux_write(chip, &buf, pkt_size - rem, &pos);
+       aux_write(chip, &oob, ecc_size, &pos);
+}
+
+static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                              u8 *buf, int oob_required, int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+       raw_read(chip, buf, chip->oob_poi);
+       return 0;
+}
+
+static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                               const u8 *buf, int oob_required, int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+       raw_write(chip, buf, chip->oob_poi);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       return 0;
+}
+
+static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                         int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+       raw_read(chip, NULL, chip->oob_poi);
+       return 0;
+}
+
+static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                          int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
+       raw_write(chip, NULL, chip->oob_poi);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       chip->waitfunc(mtd, chip);
+       return 0;
+}
+
+static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+       if (idx >= ecc->steps)
+               return -ERANGE;
+
+       res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx;
+       res->length = ecc->bytes;
+
+       return 0;
+}
+
+static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
+{
+       return -ERANGE; /* no free space in spare area */
+}
+
+static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = {
+       .ecc    = oob_ecc,
+       .free   = oob_free,
+};
+
+static u32 to_ticks(int kHz, int ps)
+{
+       return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
+}
+
+static int tango_set_timings(struct mtd_info *mtd,
+                            const struct nand_data_interface *conf,
+                            bool check_only)
+{
+       const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+       struct tango_chip *tchip = to_tango_chip(chip);
+       u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
+       int kHz = nfc->freq_kHz;
+
+       if (IS_ERR(sdr))
+               return PTR_ERR(sdr);
+
+       if (check_only)
+               return 0;
+
+       Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max);
+       Textw = to_ticks(kHz, sdr->tWB_max);
+       Twc = to_ticks(kHz, sdr->tWC_min);
+       Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min);
+
+       Tacc = to_ticks(kHz, sdr->tREA_max);
+       Thold = to_ticks(kHz, sdr->tREH_min);
+       Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min);
+       Textr = to_ticks(kHz, sdr->tRHZ_max);
+
+       tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw);
+       tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr);
+
+       return 0;
+}
+
+static int chip_init(struct device *dev, struct device_node *np)
+{
+       u32 cs;
+       int err, res;
+       struct mtd_info *mtd;
+       struct nand_chip *chip;
+       struct tango_chip *tchip;
+       struct nand_ecc_ctrl *ecc;
+       struct tango_nfc *nfc = dev_get_drvdata(dev);
+
+       tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL);
+       if (!tchip)
+               return -ENOMEM;
+
+       res = of_property_count_u32_elems(np, "reg");
+       if (res < 0)
+               return res;
+
+       if (res != 1)
+               return -ENOTSUPP; /* Multi-CS chips are not supported */
+
+       err = of_property_read_u32_index(np, "reg", 0, &cs);
+       if (err)
+               return err;
+
+       if (cs >= MAX_CS)
+               return -EINVAL;
+
+       chip = &tchip->nand_chip;
+       ecc = &chip->ecc;
+       mtd = nand_to_mtd(chip);
+
+       chip->read_byte = tango_read_byte;
+       chip->write_buf = tango_write_buf;
+       chip->read_buf = tango_read_buf;
+       chip->select_chip = tango_select_chip;
+       chip->cmd_ctrl = tango_cmd_ctrl;
+       chip->dev_ready = tango_dev_ready;
+       chip->setup_data_interface = tango_set_timings;
+       chip->options = NAND_USE_BOUNCE_BUFFER |
+                       NAND_NO_SUBPAGE_WRITE |
+                       NAND_WAIT_TCCS;
+       chip->controller = &nfc->hw;
+       tchip->base = nfc->pbus_base + (cs * 256);
+
+       nand_set_flash_node(chip, np);
+       mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
+       mtd->dev.parent = dev;
+
+       err = nand_scan_ident(mtd, 1, NULL);
+       if (err)
+               return err;
+
+       ecc->mode = NAND_ECC_HW;
+       ecc->algo = NAND_ECC_BCH;
+       ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
+
+       ecc->read_page_raw = tango_read_page_raw;
+       ecc->write_page_raw = tango_write_page_raw;
+       ecc->read_page = tango_read_page;
+       ecc->write_page = tango_write_page;
+       ecc->read_oob = tango_read_oob;
+       ecc->write_oob = tango_write_oob;
+       ecc->options = NAND_ECC_CUSTOM_PAGE_ACCESS;
+
+       err = nand_scan_tail(mtd);
+       if (err)
+               return err;
+
+       tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE);
+       tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength);
+       tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength);
+       tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE);
+
+       err = mtd_device_register(mtd, NULL, 0);
+       if (err)
+               return err;
+
+       nfc->chips[cs] = tchip;
+
+       return 0;
+}
+
+static int tango_nand_remove(struct platform_device *pdev)
+{
+       int cs;
+       struct tango_nfc *nfc = platform_get_drvdata(pdev);
+
+       dma_release_channel(nfc->chan);
+
+       for (cs = 0; cs < MAX_CS; ++cs) {
+               if (nfc->chips[cs])
+                       nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
+       }
+
+       return 0;
+}
+
+static int tango_nand_probe(struct platform_device *pdev)
+{
+       int err;
+       struct clk *clk;
+       struct resource *res;
+       struct tango_nfc *nfc;
+       struct device_node *np;
+
+       nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+       if (!nfc)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       nfc->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nfc->reg_base))
+               return PTR_ERR(nfc->reg_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       nfc->mem_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nfc->mem_base))
+               return PTR_ERR(nfc->mem_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nfc->pbus_base))
+               return PTR_ERR(nfc->pbus_base);
+
+       clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox");
+       if (IS_ERR(nfc->chan))
+               return PTR_ERR(nfc->chan);
+
+       platform_set_drvdata(pdev, nfc);
+       nand_hw_control_init(&nfc->hw);
+       nfc->freq_kHz = clk_get_rate(clk) / 1000;
+
+       for_each_child_of_node(pdev->dev.of_node, np) {
+               err = chip_init(&pdev->dev, np);
+               if (err) {
+                       tango_nand_remove(pdev);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static const struct of_device_id tango_nand_ids[] = {
+       { .compatible = "sigma,smp8758-nand" },
+       { /* sentinel */ }
+};
+
+static struct platform_driver tango_nand_driver = {
+       .probe  = tango_nand_probe,
+       .remove = tango_nand_remove,
+       .driver = {
+               .name           = "tango-nand",
+               .of_match_table = tango_nand_ids,
+       },
+};
+
+module_platform_driver(tango_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sigma Designs");
+MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");
index 08b30549ec0a0e61f3cd236102f77f6ad9e16097..fc5e773f8b6015955bed0737116cbf532a299ecb 100644 (file)
@@ -435,10 +435,10 @@ static int tmio_probe(struct platform_device *dev)
        nand_chip->waitfunc = tmio_nand_wait;
 
        /* Scan to find existence of the device */
-       if (nand_scan(mtd, 1)) {
-               retval = -ENODEV;
+       retval = nand_scan(mtd, 1);
+       if (retval)
                goto err_irq;
-       }
+
        /* Register the partitions */
        retval = mtd_device_parse_register(mtd, NULL, NULL,
                                           data ? data->partition : NULL,
index 3ad514c44dcb71a008e816a37e53af8183d6295a..3ea4bb19e12d9de9a52ba8c1479ea925d250e9eb 100644 (file)
@@ -717,10 +717,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
        vf610_nfc_preinit_controller(nfc);
 
        /* first scan to find the device and get the page size */
-       if (nand_scan_ident(mtd, 1, NULL)) {
-               err = -ENXIO;
+       err = nand_scan_ident(mtd, 1, NULL);
+       if (err)
                goto error;
-       }
 
        vf610_nfc_init_controller(nfc);
 
@@ -775,10 +774,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
        }
 
        /* second phase scan */
-       if (nand_scan_tail(mtd)) {
-               err = -ENXIO;
+       err = nand_scan_tail(mtd);
+       if (err)
                goto error;
-       }
 
        platform_set_drvdata(pdev, mtd);
 
index d8905a229f34833a4336b0a69431a4a0a94bc76e..c5f3a012ae62fec6766cf55a85c7f61ddecee3f7 100644 (file)
@@ -142,6 +142,12 @@ enum nand_ecc_algo {
  */
 #define NAND_ECC_GENERIC_ERASED_CHECK  BIT(0)
 #define NAND_ECC_MAXIMIZE              BIT(1)
+/*
+ * If your controller already sends the required NAND commands when
+ * reading or writing a page, then the framework is not supposed to
+ * send READ0 and SEQIN/PAGEPROG respectively.
+ */
+#define NAND_ECC_CUSTOM_PAGE_ACCESS    BIT(2)
 
 /* Bit mask for flags passed to do_nand_read_ecc */
 #define NAND_GET_DEVICE                0x80
@@ -186,6 +192,7 @@ enum nand_ecc_algo {
 /* Macros to identify the above */
 #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
 #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
+#define NAND_HAS_SUBPAGE_WRITE(chip) !((chip)->options & NAND_NO_SUBPAGE_WRITE)
 
 /* Non chip related options */
 /* This option skips the bbt scan during initialization. */
@@ -210,6 +217,16 @@ enum nand_ecc_algo {
  */
 #define NAND_USE_BOUNCE_BUFFER 0x00100000
 
+/*
+ * In case your controller is implementing ->cmd_ctrl() and is relying on the
+ * default ->cmdfunc() implementation, you may want to let the core handle the
+ * tCCS delay which is required when a column change (RNDIN or RNDOUT) is
+ * requested.
+ * If your controller already takes care of this delay, you don't need to set
+ * this flag.
+ */
+#define NAND_WAIT_TCCS         0x00200000
+
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
 #define NAND_CONTROLLER_ALLOC  0x80000000
@@ -558,6 +575,11 @@ struct nand_ecc_ctrl {
                        int page);
 };
 
+static inline int nand_standard_page_accessors(struct nand_ecc_ctrl *ecc)
+{
+       return !(ecc->options & NAND_ECC_CUSTOM_PAGE_ACCESS);
+}
+
 /**
  * struct nand_buffers - buffer structure for read/write
  * @ecccalc:   buffer pointer for calculated ECC, size is oobsize.
@@ -584,6 +606,10 @@ struct nand_buffers {
  *
  * All these timings are expressed in picoseconds.
  *
+ * @tBERS_max: Block erase time
+ * @tCCS_min: Change column setup time
+ * @tPROG_max: Page program time
+ * @tR_max: Page read time
  * @tALH_min: ALE hold time
  * @tADL_min: ALE to data loading time
  * @tALS_min: ALE setup time
@@ -621,6 +647,10 @@ struct nand_buffers {
  * @tWW_min: WP# transition to WE# low
  */
 struct nand_sdr_timings {
+       u32 tBERS_max;
+       u32 tCCS_min;
+       u32 tPROG_max;
+       u32 tR_max;
        u32 tALH_min;
        u32 tADL_min;
        u32 tALS_min;
index c55e42ee57fa0c9ba3083d6bf03b04fae275d13c..f01659026b2681e7c141899097cedc582a58c447 100644 (file)
 #ifndef __MTD_NAND_S3C2410_H
 #define __MTD_NAND_S3C2410_H
 
+#include <linux/mtd/nand.h>
+
 /**
  * struct s3c2410_nand_set - define a set of one or more nand chips
- * @disable_ecc:       Entirely disable ECC - Dangerous
  * @flash_bbt:                 Openmoko u-boot can create a Bad Block Table
  *                     Setting this flag will allow the kernel to
  *                     look for it at boot time and also skip the NAND
@@ -31,7 +32,6 @@
  * a warning at boot time.
  */
 struct s3c2410_nand_set {
-       unsigned int            disable_ecc:1;
        unsigned int            flash_bbt:1;
 
        unsigned int            options;
@@ -40,6 +40,7 @@ struct s3c2410_nand_set {
        char                    *name;
        int                     *nr_map;
        struct mtd_partition    *partitions;
+       struct device_node      *of_node;
 };
 
 struct s3c2410_platform_nand {
@@ -51,6 +52,8 @@ struct s3c2410_platform_nand {
 
        unsigned int    ignore_unset_ecc:1;
 
+       nand_ecc_modes_t        ecc_mode;
+
        int                     nr_sets;
        struct s3c2410_nand_set *sets;