Browse Source

Merge tag 'for-linus-20130909' of git://git.infradead.org/linux-mtd

Pull mtd updates from David Woodhouse:
 - factor out common code from MTD tests
 - nand-gpio cleanup and portability to non-ARM
 - m25p80 support for 4-byte addressing chips, other new chips
 - pxa3xx cleanup and support for new platforms
 - remove obsolete alauda, octagon-5066 drivers
 - erase/write support for bcm47xxsflash
 - improve detection of ECC requirements for NAND, controller setup
 - NFC acceleration support for atmel-nand, read/write via SRAM
 - etc

* tag 'for-linus-20130909' of git://git.infradead.org/linux-mtd: (184 commits)
  mtd: chips: Add support for PMC SPI Flash chips in m25p80.c
  mtd: ofpart: use for_each_child_of_node() macro
  mtd: mtdswap: replace strict_strtoul() with kstrtoul()
  mtd cs553x_nand: use kzalloc() instead of memset
  mtd: atmel_nand: fix error return code in atmel_nand_probe()
  mtd: bcm47xxsflash: writing support
  mtd: bcm47xxsflash: implement erasing support
  mtd: bcm47xxsflash: convert to module_platform_driver instead of init/exit
  mtd: bcm47xxsflash: convert kzalloc to avoid invalid access
  mtd: remove alauda driver
  mtd: nand: mxc_nand: mark 'const' properly
  mtd: maps: cfi_flagadm: add missing __iomem annotation
  mtd: spear_smi: add missing __iomem annotation
  mtd: r852: Staticize local symbols
  mtd: nandsim: Staticize local symbols
  mtd: impa7: add missing __iomem annotation
  mtd: sm_ftl: Staticize local symbols
  mtd: m25p80: add support for mr25h10
  mtd: m25p80: make CONFIG_M25PXX_USE_FAST_READ safe to enable
  mtd: m25p80: Pass flags through CAT25_INFO macro
  ...
Linus Torvalds 12 years ago
parent
commit
ef9a61bef9
99 changed files with 2732 additions and 3201 deletions
  1. 14 3
      Documentation/ABI/testing/sysfs-class-mtd
  2. 0 2
      Documentation/DocBook/mtdnand.tmpl
  3. 28 0
      Documentation/devicetree/bindings/mtd/atmel-nand.txt
  4. 24 1
      Documentation/devicetree/bindings/mtd/fsmc-nand.txt
  5. 1 0
      Documentation/devicetree/bindings/mtd/partition.txt
  6. 3 0
      arch/avr32/mach-at32ap/at32ap700x.c
  7. 11 0
      arch/mips/bcm63xx/nvram.c
  8. 2 0
      arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h
  9. 6 3
      drivers/mtd/bcm63xxpart.c
  10. 2 2
      drivers/mtd/chips/cfi_cmdset_0002.c
  11. 1 3
      drivers/mtd/chips/gen_probe.c
  12. 7 6
      drivers/mtd/chips/jedec_probe.c
  13. 0 55
      drivers/mtd/devices/Kconfig
  14. 239 36
      drivers/mtd/devices/bcm47xxsflash.c
  15. 2 0
      drivers/mtd/devices/bcm47xxsflash.h
  16. 31 27
      drivers/mtd/devices/block2mtd.c
  17. 120 9
      drivers/mtd/devices/elm.c
  18. 60 21
      drivers/mtd/devices/m25p80.c
  19. 5 5
      drivers/mtd/devices/mtd_dataflash.c
  20. 7 12
      drivers/mtd/devices/spear_smi.c
  21. 4 4
      drivers/mtd/devices/sst25l.c
  22. 0 18
      drivers/mtd/maps/Kconfig
  23. 0 2
      drivers/mtd/maps/Makefile
  24. 1 1
      drivers/mtd/maps/bfin-async-flash.c
  25. 5 5
      drivers/mtd/maps/cfi_flagadm.c
  26. 1 1
      drivers/mtd/maps/gpio-addr-flash.c
  27. 5 5
      drivers/mtd/maps/impa7.c
  28. 2 4
      drivers/mtd/maps/ixp4xx.c
  29. 2 3
      drivers/mtd/maps/latch-addr-flash.c
  30. 0 246
      drivers/mtd/maps/octagon-5066.c
  31. 3 4
      drivers/mtd/maps/physmap.c
  32. 2 4
      drivers/mtd/maps/plat-ram.c
  33. 1 3
      drivers/mtd/maps/pxa2xx-flash.c
  34. 2 3
      drivers/mtd/maps/rbtx4939-flash.c
  35. 2 3
      drivers/mtd/maps/sa1100-flash.c
  36. 0 196
      drivers/mtd/maps/vmax301.c
  37. 11 0
      drivers/mtd/mtdcore.c
  38. 1 0
      drivers/mtd/mtdpart.c
  39. 1 1
      drivers/mtd/mtdswap.c
  40. 3 9
      drivers/mtd/nand/Kconfig
  41. 0 1
      drivers/mtd/nand/Makefile
  42. 0 723
      drivers/mtd/nand/alauda.c
  43. 0 1
      drivers/mtd/nand/ams-delta.c
  44. 732 191
      drivers/mtd/nand/atmel_nand.c
  45. 98 0
      drivers/mtd/nand/atmel_nand_nfc.h
  46. 1 1
      drivers/mtd/nand/au1550nd.c
  47. 1 4
      drivers/mtd/nand/bf5xx_nand.c
  48. 1 5
      drivers/mtd/nand/cs553x_nand.c
  49. 11 8
      drivers/mtd/nand/davinci_nand.c
  50. 1 1
      drivers/mtd/nand/denali.c
  51. 2 2
      drivers/mtd/nand/diskonchip.c
  52. 0 8
      drivers/mtd/nand/docg4.c
  53. 1 2
      drivers/mtd/nand/fsl_ifc_nand.c
  54. 20 18
      drivers/mtd/nand/fsmc_nand.c
  55. 61 170
      drivers/mtd/nand/gpio.c
  56. 192 76
      drivers/mtd/nand/gpmi-nand/gpmi-nand.c
  57. 2 4
      drivers/mtd/nand/jz4740_nand.c
  58. 1 3
      drivers/mtd/nand/lpc32xx_mlc.c
  59. 1 3
      drivers/mtd/nand/lpc32xx_slc.c
  60. 3 9
      drivers/mtd/nand/mxc_nand.c
  61. 206 90
      drivers/mtd/nand/nand_base.c
  62. 103 91
      drivers/mtd/nand/nand_bbt.c
  63. 4 4
      drivers/mtd/nand/nand_ids.c
  64. 15 24
      drivers/mtd/nand/nandsim.c
  65. 0 2
      drivers/mtd/nand/nuc900_nand.c
  66. 2 3
      drivers/mtd/nand/omap2.c
  67. 3 3
      drivers/mtd/nand/orion_nand.c
  68. 2 3
      drivers/mtd/nand/plat_nand.c
  69. 221 163
      drivers/mtd/nand/pxa3xx_nand.c
  70. 23 26
      drivers/mtd/nand/r852.c
  71. 1 3
      drivers/mtd/nand/s3c2410.c
  72. 2 2
      drivers/mtd/nand/sh_flctl.c
  73. 1 4
      drivers/mtd/nand/sharpsl.c
  74. 4 5
      drivers/mtd/nand/sm_common.c
  75. 1 1
      drivers/mtd/nand/tmio_nand.c
  76. 5 8
      drivers/mtd/nand/txx9ndfmc.c
  77. 14 4
      drivers/mtd/ofpart.c
  78. 1 3
      drivers/mtd/onenand/generic.c
  79. 1 2
      drivers/mtd/onenand/omap2.c
  80. 0 1
      drivers/mtd/onenand/onenand_bbt.c
  81. 1 2
      drivers/mtd/onenand/samsung.c
  82. 13 13
      drivers/mtd/sm_ftl.c
  83. 9 0
      drivers/mtd/tests/Makefile
  84. 114 0
      drivers/mtd/tests/mtd_test.c
  85. 11 0
      drivers/mtd/tests/mtd_test.h
  86. 4 37
      drivers/mtd/tests/nandbiterrs.c
  87. 14 88
      drivers/mtd/tests/oobtest.c
  88. 60 211
      drivers/mtd/tests/pagetest.c
  89. 10 51
      drivers/mtd/tests/readtest.c
  90. 33 177
      drivers/mtd/tests/speedtest.c
  91. 13 88
      drivers/mtd/tests/stresstest.c
  92. 11 86
      drivers/mtd/tests/subpagetest.c
  93. 7 59
      drivers/mtd/tests/torturetest.c
  94. 0 2
      include/linux/mtd/bbm.h
  95. 1 0
      include/linux/mtd/fsmc.h
  96. 3 0
      include/linux/mtd/mtd.h
  97. 78 5
      include/linux/mtd/nand.h
  98. 4 0
      include/linux/platform_data/atmel.h
  99. 0 13
      include/linux/platform_data/mtd-nand-pxa3xx.h

+ 14 - 3
Documentation/ABI/testing/sysfs-class-mtd

@@ -128,9 +128,8 @@ KernelVersion:	3.4
 Contact:	linux-mtd@lists.infradead.org
 Contact:	linux-mtd@lists.infradead.org
 Description:
 Description:
 		Maximum number of bit errors that the device is capable of
 		Maximum number of bit errors that the device is capable of
-		correcting within each region covering an ecc step.  This will
-		always be a non-negative integer.  Note that some devices will
-		have multiple ecc steps within each writesize region.
+		correcting within each region covering an ECC step (see
+		ecc_step_size).  This will always be a non-negative integer.
 
 
 		In the case of devices lacking any ECC capability, it is 0.
 		In the case of devices lacking any ECC capability, it is 0.
 
 
@@ -173,3 +172,15 @@ Description:
 		This is generally applicable only to NAND flash devices with ECC
 		This is generally applicable only to NAND flash devices with ECC
 		capability.  It is ignored on devices lacking ECC capability;
 		capability.  It is ignored on devices lacking ECC capability;
 		i.e., devices for which ecc_strength is zero.
 		i.e., devices for which ecc_strength is zero.
+
+What:		/sys/class/mtd/mtdX/ecc_step_size
+Date:		May 2013
+KernelVersion:	3.10
+Contact:	linux-mtd@lists.infradead.org
+Description:
+		The size of a single region covered by ECC, known as the ECC
+		step.  Devices may have several equally sized ECC steps within
+		each writesize region.
+
+		It will always be a non-negative integer.  In the case of
+		devices lacking any ECC capability, it is 0.

+ 0 - 2
Documentation/DocBook/mtdnand.tmpl

@@ -1224,8 +1224,6 @@ in this page</entry>
 #define NAND_BBT_CREATE		0x00000200
 #define NAND_BBT_CREATE		0x00000200
 /* Search good / bad pattern through all pages of a block */
 /* Search good / bad pattern through all pages of a block */
 #define NAND_BBT_SCANALLPAGES	0x00000400
 #define NAND_BBT_SCANALLPAGES	0x00000400
-/* Scan block empty during good / bad block scan */
-#define NAND_BBT_SCANEMPTY	0x00000800
 /* Write bbt if neccecary */
 /* Write bbt if neccecary */
 #define NAND_BBT_WRITE		0x00001000
 #define NAND_BBT_WRITE		0x00001000
 /* Read and write back block contents when writing bbt */
 /* Read and write back block contents when writing bbt */

+ 28 - 0
Documentation/devicetree/bindings/mtd/atmel-nand.txt

@@ -15,6 +15,7 @@ Required properties:
   optional gpio and may be set to 0 if not present.
   optional gpio and may be set to 0 if not present.
 
 
 Optional properties:
 Optional properties:
+- atmel,nand-has-dma : boolean to support dma transfer for nand read/write.
 - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
 - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
   Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
   Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
   "soft_bch".
   "soft_bch".
@@ -29,6 +30,14 @@ Optional properties:
   sector size 1024.
   sector size 1024.
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+- Nand Flash Controller(NFC) is a slave driver under Atmel nand flash
+  - Required properties:
+    - compatible : "atmel,sama5d3-nfc".
+    - reg : should specify the address and size used for NFC command registers,
+            NFC registers and NFC Sram. NFC Sram address and size can be absent
+            if don't want to use it.
+  - Optional properties:
+    - atmel,write-by-sram: boolean to enable NFC write by sram.
 
 
 Examples:
 Examples:
 nand0: nand@40000000,0 {
 nand0: nand@40000000,0 {
@@ -77,3 +86,22 @@ nand0: nand@40000000 {
 		...
 		...
 	};
 	};
 };
 };
+
+/* for NFC supported chips */
+nand0: nand@40000000 {
+	compatible = "atmel,at91rm9200-nand";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+        ...
+        nfc@70000000 {
+		compatible = "atmel,sama5d3-nfc";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <
+			0x70000000 0x10000000	/* NFC Command Registers */
+			0xffffc000 0x00000070	/* NFC HSMC regs */
+			0x00200000 0x00100000	/* NFC SRAM banks */
+		>;
+	};
+};

+ 24 - 1
Documentation/devicetree/bindings/mtd/fsmc-nand.txt

@@ -1,4 +1,5 @@
-* FSMC NAND
+ST Microelectronics Flexible Static Memory Controller (FSMC)
+NAND Interface
 
 
 Required properties:
 Required properties:
 - compatible : "st,spear600-fsmc-nand", "stericsson,fsmc-nand"
 - compatible : "st,spear600-fsmc-nand", "stericsson,fsmc-nand"
@@ -9,6 +10,26 @@ Optional properties:
 - bank-width : Width (in bytes) of the device.  If not present, the width
 - bank-width : Width (in bytes) of the device.  If not present, the width
   defaults to 1 byte
   defaults to 1 byte
 - nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
 - nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
+- timings: array of 6 bytes for NAND timings. The meanings of these bytes
+  are:
+  byte 0 TCLR  : CLE to RE delay in number of AHB clock cycles, only 4 bits
+                 are valid. Zero means one clockcycle, 15 means 16 clock
+                 cycles.
+  byte 1 TAR   : ALE to RE delay, 4 bits are valid. Same format as TCLR.
+  byte 2 THIZ  : number of HCLK clock cycles during which the data bus is
+                 kept in Hi-Z (tristate) after the start of a write access.
+                 Only valid for write transactions. Zero means zero cycles,
+                 255 means 255 cycles.
+  byte 3 THOLD : number of HCLK clock cycles to hold the address (and data
+                 when writing) after the command deassertation. Zero means
+                 one cycle, 255 means 256 cycles.
+  byte 4 TWAIT : number of HCLK clock cycles to assert the command to the
+                 NAND flash in response to SMWAITn. Zero means 1 cycle,
+                 255 means 256 cycles.
+  byte 5 TSET  : number of HCLK clock cycles to assert the address before the
+                 command is asserted. Zero means one cycle, 255 means 256
+                 cycles.
+- bank: default NAND bank to use (0-3 are valid, 0 is the default).
 
 
 Example:
 Example:
 
 
@@ -24,6 +45,8 @@ Example:
 
 
 		bank-width = <1>;
 		bank-width = <1>;
 		nand-skip-bbtscan;
 		nand-skip-bbtscan;
+		timings = /bits/ 8 <0 0 0 2 3 0>;
+		bank = <1>;
 
 
 		partition@0 {
 		partition@0 {
 			...
 			...

+ 1 - 0
Documentation/devicetree/bindings/mtd/partition.txt

@@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
 on platforms which have strong conventions about which portions of a flash are
 on platforms which have strong conventions about which portions of a flash are
 used for what purposes, but which don't use an on-flash partition table such
 used for what purposes, but which don't use an on-flash partition table such
 as RedBoot.
 as RedBoot.
+NOTE: if the sub-node has a compatible string, then it is not a partition.
 
 
 #address-cells & #size-cells must both be present in the mtd device. There are
 #address-cells & #size-cells must both be present in the mtd device. There are
 two valid values for both:
 two valid values for both:

+ 3 - 0
arch/avr32/mach-at32ap/at32ap700x.c

@@ -1983,6 +1983,9 @@ at32_add_device_nand(unsigned int id, struct atmel_nand_data *data)
 				ARRAY_SIZE(smc_cs3_resource)))
 				ARRAY_SIZE(smc_cs3_resource)))
 		goto fail;
 		goto fail;
 
 
+	/* For at32ap7000, we use the reset workaround for nand driver */
+	data->need_reset_workaround = true;
+
 	if (platform_device_add_data(pdev, data,
 	if (platform_device_add_data(pdev, data,
 				sizeof(struct atmel_nand_data)))
 				sizeof(struct atmel_nand_data)))
 		goto fail;
 		goto fail;

+ 11 - 0
arch/mips/bcm63xx/nvram.c

@@ -35,6 +35,8 @@ struct bcm963xx_nvram {
 	u32	checksum_high;
 	u32	checksum_high;
 };
 };
 
 
+#define BCM63XX_DEFAULT_PSI_SIZE	64
+
 static struct bcm963xx_nvram nvram;
 static struct bcm963xx_nvram nvram;
 static int mac_addr_used;
 static int mac_addr_used;
 
 
@@ -114,3 +116,12 @@ int bcm63xx_nvram_get_mac_address(u8 *mac)
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
 EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
+
+int bcm63xx_nvram_get_psi_size(void)
+{
+	if (nvram.psi_size > 0)
+		return nvram.psi_size;
+
+	return BCM63XX_DEFAULT_PSI_SIZE;
+}
+EXPORT_SYMBOL(bcm63xx_nvram_get_psi_size);

+ 2 - 0
arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h

@@ -30,4 +30,6 @@ u8 *bcm63xx_nvram_get_name(void);
  */
  */
 int bcm63xx_nvram_get_mac_address(u8 *mac);
 int bcm63xx_nvram_get_mac_address(u8 *mac);
 
 
+int bcm63xx_nvram_get_psi_size(void);
+
 #endif /* BCM63XX_NVRAM_H */
 #endif /* BCM63XX_NVRAM_H */

+ 6 - 3
drivers/mtd/bcm63xxpart.c

@@ -4,7 +4,7 @@
  * Copyright © 2006-2008  Florian Fainelli <florian@openwrt.org>
  * Copyright © 2006-2008  Florian Fainelli <florian@openwrt.org>
  *			  Mike Albon <malbon@openwrt.org>
  *			  Mike Albon <malbon@openwrt.org>
  * Copyright © 2009-2010  Daniel Dickinson <openwrt@cshore.neomailbox.net>
  * Copyright © 2009-2010  Daniel Dickinson <openwrt@cshore.neomailbox.net>
- * Copyright © 2011-2012  Jonas Gorski <jonas.gorski@gmail.com>
+ * Copyright © 2011-2013  Jonas Gorski <jonas.gorski@gmail.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * it under the terms of the GNU General Public License as published by
@@ -27,17 +27,19 @@
 #include <linux/crc32.h>
 #include <linux/crc32.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
 
 
+#include <asm/mach-bcm63xx/bcm63xx_nvram.h>
 #include <asm/mach-bcm63xx/bcm963xx_tag.h>
 #include <asm/mach-bcm63xx/bcm963xx_tag.h>
 #include <asm/mach-bcm63xx/board_bcm963xx.h>
 #include <asm/mach-bcm63xx/board_bcm963xx.h>
 
 
 #define BCM63XX_EXTENDED_SIZE	0xBFC00000	/* Extended flash address */
 #define BCM63XX_EXTENDED_SIZE	0xBFC00000	/* Extended flash address */
 
 
-#define BCM63XX_CFE_BLOCK_SIZE	0x10000		/* always at least 64KiB */
+#define BCM63XX_CFE_BLOCK_SIZE	SZ_64K		/* always at least 64KiB */
 
 
 #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
 #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
 
 
@@ -90,7 +92,8 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
 			      BCM63XX_CFE_BLOCK_SIZE);
 			      BCM63XX_CFE_BLOCK_SIZE);
 
 
 	cfelen = cfe_erasesize;
 	cfelen = cfe_erasesize;
-	nvramlen = cfe_erasesize;
+	nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
+	nvramlen = roundup(nvramlen, cfe_erasesize);
 
 
 	/* Allocate memory for buffer */
 	/* Allocate memory for buffer */
 	buf = vmalloc(sizeof(struct bcm_tag));
 	buf = vmalloc(sizeof(struct bcm_tag));

+ 2 - 2
drivers/mtd/chips/cfi_cmdset_0002.c

@@ -1571,8 +1571,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 	xip_enable(map, chip, adr);
 	xip_enable(map, chip, adr);
 	/* FIXME - should have reset delay before continuing */
 	/* FIXME - should have reset delay before continuing */
 
 
-	printk(KERN_WARNING "MTD %s(): software timeout\n",
-	       __func__ );
+	printk(KERN_WARNING "MTD %s(): software timeout, address:0x%.8lx.\n",
+	       __func__, adr);
 
 
 	ret = -EIO;
 	ret = -EIO;
  op_done:
  op_done:

+ 1 - 3
drivers/mtd/chips/gen_probe.c

@@ -211,9 +211,7 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
 
 
 	probe_function = __symbol_get(probename);
 	probe_function = __symbol_get(probename);
 	if (!probe_function) {
 	if (!probe_function) {
-		char modname[sizeof("cfi_cmdset_%4.4X")];
-		sprintf(modname, "cfi_cmdset_%4.4X", type);
-		request_module(modname);
+		request_module("cfi_cmdset_%4.4X", type);
 		probe_function = __symbol_get(probename);
 		probe_function = __symbol_get(probename);
 	}
 	}
 
 

+ 7 - 6
drivers/mtd/chips/jedec_probe.c

@@ -120,7 +120,7 @@
 #define PM49FL008	0x006A
 #define PM49FL008	0x006A
 
 
 /* Sharp */
 /* Sharp */
-#define LH28F640BF	0x00b0
+#define LH28F640BF	0x00B0
 
 
 /* ST - www.st.com */
 /* ST - www.st.com */
 #define M29F800AB	0x0058
 #define M29F800AB	0x0058
@@ -1299,13 +1299,14 @@ static const struct amd_flash_info jedec_table[] = {
 		.mfr_id		= CFI_MFR_SHARP,
 		.mfr_id		= CFI_MFR_SHARP,
 		.dev_id		= LH28F640BF,
 		.dev_id		= LH28F640BF,
 		.name		= "LH28F640BF",
 		.name		= "LH28F640BF",
-		.devtypes	= CFI_DEVICETYPE_X8,
+		.devtypes	= CFI_DEVICETYPE_X16,
 		.uaddr		= MTD_UADDR_UNNECESSARY,
 		.uaddr		= MTD_UADDR_UNNECESSARY,
-		.dev_size	= SIZE_4MiB,
-		.cmd_set	= P_ID_INTEL_STD,
-		.nr_regions	= 1,
+		.dev_size	= SIZE_8MiB,
+		.cmd_set	= P_ID_INTEL_EXT,
+		.nr_regions	= 2,
 		.regions	= {
 		.regions	= {
-			ERASEINFO(0x40000,16),
+			ERASEINFO(0x10000, 127),
+			ERASEINFO(0x02000, 8),
 		}
 		}
 	}, {
 	}, {
 		.mfr_id		= CFI_MFR_SST,
 		.mfr_id		= CFI_MFR_SST,

+ 0 - 55
drivers/mtd/devices/Kconfig

@@ -224,59 +224,4 @@ config BCH_CONST_T
 	default 4
 	default 4
 endif
 endif
 
 
-config MTD_DOCPROBE
-	tristate
-	select MTD_DOCECC
-
-config MTD_DOCECC
-	tristate
-
-config MTD_DOCPROBE_ADVANCED
-	bool "Advanced detection options for DiskOnChip"
-	depends on MTD_DOCPROBE
-	help
-	  This option allows you to specify nonstandard address at which to
-	  probe for a DiskOnChip, or to change the detection options.  You
-	  are unlikely to need any of this unless you are using LinuxBIOS.
-	  Say 'N'.
-
-config MTD_DOCPROBE_ADDRESS
-	hex "Physical address of DiskOnChip" if MTD_DOCPROBE_ADVANCED
-	depends on MTD_DOCPROBE
-	default "0x0"
-	---help---
-	  By default, the probe for DiskOnChip devices will look for a
-	  DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-	  This option allows you to specify a single address at which to probe
-	  for the device, which is useful if you have other devices in that
-	  range which get upset when they are probed.
-
-	  (Note that on PowerPC, the normal probe will only check at
-	  0xE4000000.)
-
-	  Normally, you should leave this set to zero, to allow the probe at
-	  the normal addresses.
-
-config MTD_DOCPROBE_HIGH
-	bool "Probe high addresses"
-	depends on MTD_DOCPROBE_ADVANCED
-	help
-	  By default, the probe for DiskOnChip devices will look for a
-	  DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-	  This option changes to make it probe between 0xFFFC8000 and
-	  0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
-	  useful to you.  Say 'N'.
-
-config MTD_DOCPROBE_55AA
-	bool "Probe for 0x55 0xAA BIOS Extension Signature"
-	depends on MTD_DOCPROBE_ADVANCED
-	help
-	  Check for the 0x55 0xAA signature of a DiskOnChip, and do not
-	  continue with probing if it is absent.  The signature will always be
-	  present for a DiskOnChip 2000 or a normal DiskOnChip Millennium.
-	  Only if you have overwritten the first block of a DiskOnChip
-	  Millennium will it be absent.  Enable this option if you are using
-	  LinuxBIOS or if you need to recover a DiskOnChip Millennium on which
-	  you have managed to wipe the first block.
-
 endmenu
 endmenu

+ 239 - 36
drivers/mtd/devices/bcm47xxsflash.c

@@ -1,6 +1,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/mtd.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 #include <linux/bcma/bcma.h>
@@ -12,6 +13,93 @@ MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
 
 
 static const char * const probes[] = { "bcm47xxpart", NULL };
 static const char * const probes[] = { "bcm47xxpart", NULL };
 
 
+/**************************************************
+ * Various helpers
+ **************************************************/
+
+static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode)
+{
+	int i;
+
+	b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode);
+	for (i = 0; i < 1000; i++) {
+		if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) &
+		      BCMA_CC_FLASHCTL_BUSY))
+			return;
+		cpu_relax();
+	}
+	pr_err("Control command failed (timeout)!\n");
+}
+
+static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout)
+{
+	unsigned long deadline = jiffies + timeout;
+
+	do {
+		switch (b47s->type) {
+		case BCM47XXSFLASH_TYPE_ST:
+			bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR);
+			if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
+			      SR_ST_WIP))
+				return 0;
+			break;
+		case BCM47XXSFLASH_TYPE_ATMEL:
+			bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS);
+			if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
+			    SR_AT_READY)
+				return 0;
+			break;
+		}
+
+		cpu_relax();
+		udelay(1);
+	} while (!time_after_eq(jiffies, deadline));
+
+	pr_err("Timeout waiting for flash to be ready!\n");
+
+	return -EBUSY;
+}
+
+/**************************************************
+ * MTD ops
+ **************************************************/
+
+static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+	struct bcm47xxsflash *b47s = mtd->priv;
+	int err;
+
+	switch (b47s->type) {
+	case BCM47XXSFLASH_TYPE_ST:
+		bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
+		b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr);
+		/* Newer flashes have "sub-sectors" which can be erased
+		 * independently with a new command: ST_SSE. The ST_SE command
+		 * erases 64KB just as before.
+		 */
+		if (b47s->blocksize < (64 * 1024))
+			bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE);
+		else
+			bcm47xxsflash_cmd(b47s, OPCODE_ST_SE);
+		break;
+	case BCM47XXSFLASH_TYPE_ATMEL:
+		b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1);
+		bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE);
+		break;
+	}
+
+	err = bcm47xxsflash_poll(b47s, HZ);
+	if (err)
+		erase->state = MTD_ERASE_FAILED;
+	else
+		erase->state = MTD_ERASE_DONE;
+
+	if (erase->callback)
+		erase->callback(erase);
+
+	return err;
+}
+
 static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
 static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
 			      size_t *retlen, u_char *buf)
 			      size_t *retlen, u_char *buf)
 {
 {
@@ -28,6 +116,127 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
 	return len;
 	return len;
 }
 }
 
 
+static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
+				  const u_char *buf)
+{
+	struct bcm47xxsflash *b47s = mtd->priv;
+	int written = 0;
+
+	/* Enable writes */
+	bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
+
+	/* Write first byte */
+	b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset);
+	b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
+
+	/* Program page */
+	if (b47s->bcma_cc->core->id.rev < 20) {
+		bcm47xxsflash_cmd(b47s, OPCODE_ST_PP);
+		return 1; /* 1B written */
+	}
+
+	/* Program page and set CSA (on newer chips we can continue writing) */
+	bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP);
+	offset++;
+	len--;
+	written++;
+
+	while (len > 0) {
+		/* Page boundary, another function call is needed */
+		if ((offset & 0xFF) == 0)
+			break;
+
+		bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++);
+		offset++;
+		len--;
+		written++;
+	}
+
+	/* All done, drop CSA & poll */
+	b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0);
+	udelay(1);
+	if (bcm47xxsflash_poll(b47s, HZ / 10))
+		pr_err("Flash rejected dropping CSA\n");
+
+	return written;
+}
+
+static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len,
+				  const u_char *buf)
+{
+	struct bcm47xxsflash *b47s = mtd->priv;
+	u32 mask = b47s->blocksize - 1;
+	u32 page = (offset & ~mask) << 1;
+	u32 byte = offset & mask;
+	int written = 0;
+
+	/* If we don't overwrite whole page, read it to the buffer first */
+	if (byte || (len < b47s->blocksize)) {
+		int err;
+
+		b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
+		bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD);
+		/* 250 us for AT45DB321B */
+		err = bcm47xxsflash_poll(b47s, HZ / 1000);
+		if (err) {
+			pr_err("Timeout reading page 0x%X info buffer\n", page);
+			return err;
+		}
+	}
+
+	/* Change buffer content with our data */
+	while (len > 0) {
+		/* Page boundary, another function call is needed */
+		if (byte == b47s->blocksize)
+			break;
+
+		b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++);
+		b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
+		bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE);
+		len--;
+		written++;
+	}
+
+	/* Program page with the buffer content */
+	b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
+	bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM);
+
+	return written;
+}
+
+static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len,
+			       size_t *retlen, const u_char *buf)
+{
+	struct bcm47xxsflash *b47s = mtd->priv;
+	int written;
+
+	/* Writing functions can return without writing all passed data, for
+	 * example when the hardware is too old or when we git page boundary.
+	 */
+	while (len > 0) {
+		switch (b47s->type) {
+		case BCM47XXSFLASH_TYPE_ST:
+			written = bcm47xxsflash_write_st(mtd, to, len, buf);
+			break;
+		case BCM47XXSFLASH_TYPE_ATMEL:
+			written = bcm47xxsflash_write_at(mtd, to, len, buf);
+			break;
+		default:
+			BUG_ON(1);
+		}
+		if (written < 0) {
+			pr_err("Error writing at offset 0x%llX\n", to);
+			return written;
+		}
+		to += (loff_t)written;
+		len -= written;
+		*retlen += written;
+		buf += written;
+	}
+
+	return 0;
+}
+
 static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
 static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
 {
 {
 	struct mtd_info *mtd = &b47s->mtd;
 	struct mtd_info *mtd = &b47s->mtd;
@@ -35,33 +244,48 @@ static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
 	mtd->priv = b47s;
 	mtd->priv = b47s;
 	mtd->name = "bcm47xxsflash";
 	mtd->name = "bcm47xxsflash";
 	mtd->owner = THIS_MODULE;
 	mtd->owner = THIS_MODULE;
-	mtd->type = MTD_ROM;
+
+	mtd->type = MTD_NORFLASH;
+	mtd->flags = MTD_CAP_NORFLASH;
 	mtd->size = b47s->size;
 	mtd->size = b47s->size;
-	mtd->_read = bcm47xxsflash_read;
+	mtd->erasesize = b47s->blocksize;
+	mtd->writesize = 1;
+	mtd->writebufsize = 1;
 
 
-	/* TODO: implement writing support and verify/change following code */
-	mtd->flags = MTD_CAP_ROM;
-	mtd->writebufsize = mtd->writesize = 1;
+	mtd->_erase = bcm47xxsflash_erase;
+	mtd->_read = bcm47xxsflash_read;
+	mtd->_write = bcm47xxsflash_write;
 }
 }
 
 
 /**************************************************
 /**************************************************
  * BCMA
  * BCMA
  **************************************************/
  **************************************************/
 
 
+static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset)
+{
+	return bcma_cc_read32(b47s->bcma_cc, offset);
+}
+
+static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
+					u32 value)
+{
+	bcma_cc_write32(b47s->bcma_cc, offset, value);
+}
+
 static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 {
 {
 	struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
 	struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
 	struct bcm47xxsflash *b47s;
 	struct bcm47xxsflash *b47s;
 	int err;
 	int err;
 
 
-	b47s = kzalloc(sizeof(*b47s), GFP_KERNEL);
-	if (!b47s) {
-		err = -ENOMEM;
-		goto out;
-	}
+	b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
+	if (!b47s)
+		return -ENOMEM;
 	sflash->priv = b47s;
 	sflash->priv = b47s;
 
 
 	b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
 	b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
+	b47s->cc_read = bcm47xxsflash_bcma_cc_read;
+	b47s->cc_write = bcm47xxsflash_bcma_cc_write;
 
 
 	switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
 	switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
 	case BCMA_CC_FLASHT_STSER:
 	case BCMA_CC_FLASHT_STSER:
@@ -81,15 +305,13 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 	err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
 	err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
 	if (err) {
 	if (err) {
 		pr_err("Failed to register MTD device: %d\n", err);
 		pr_err("Failed to register MTD device: %d\n", err);
-		goto err_dev_reg;
+		return err;
 	}
 	}
 
 
-	return 0;
+	if (bcm47xxsflash_poll(b47s, HZ / 10))
+		pr_warn("Serial flash busy\n");
 
 
-err_dev_reg:
-	kfree(&b47s->mtd);
-out:
-	return err;
+	return 0;
 }
 }
 
 
 static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
 static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
@@ -98,7 +320,6 @@ static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
 	struct bcm47xxsflash *b47s = sflash->priv;
 	struct bcm47xxsflash *b47s = sflash->priv;
 
 
 	mtd_device_unregister(&b47s->mtd);
 	mtd_device_unregister(&b47s->mtd);
-	kfree(b47s);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -116,22 +337,4 @@ static struct platform_driver bcma_sflash_driver = {
  * Init
  * Init
  **************************************************/
  **************************************************/
 
 
-static int __init bcm47xxsflash_init(void)
-{
-	int err;
-
-	err = platform_driver_register(&bcma_sflash_driver);
-	if (err)
-		pr_err("Failed to register BCMA serial flash driver: %d\n",
-		       err);
-
-	return err;
-}
-
-static void __exit bcm47xxsflash_exit(void)
-{
-	platform_driver_unregister(&bcma_sflash_driver);
-}
-
-module_init(bcm47xxsflash_init);
-module_exit(bcm47xxsflash_exit);
+module_platform_driver(bcma_sflash_driver);

+ 2 - 0
drivers/mtd/devices/bcm47xxsflash.h

@@ -60,6 +60,8 @@ enum bcm47xxsflash_type {
 
 
 struct bcm47xxsflash {
 struct bcm47xxsflash {
 	struct bcma_drv_cc *bcma_cc;
 	struct bcma_drv_cc *bcma_cc;
+	int (*cc_read)(struct bcm47xxsflash *b47s, u16 offset);
+	void (*cc_write)(struct bcm47xxsflash *b47s, u16 offset, u32 value);
 
 
 	enum bcm47xxsflash_type type;
 	enum bcm47xxsflash_type type;
 
 

+ 31 - 27
drivers/mtd/devices/block2mtd.c

@@ -6,6 +6,9 @@
  *
  *
  * Licence: GPL
  * Licence: GPL
  */
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/fs.h>
 #include <linux/blkdev.h>
 #include <linux/blkdev.h>
@@ -18,10 +21,6 @@
 #include <linux/mount.h>
 #include <linux/mount.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
-#define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
-#define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args)
-
-
 /* Info for the block device */
 /* Info for the block device */
 struct block2mtd_dev {
 struct block2mtd_dev {
 	struct list_head list;
 	struct list_head list;
@@ -84,7 +83,7 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 	err = _block2mtd_erase(dev, from, len);
 	err = _block2mtd_erase(dev, from, len);
 	mutex_unlock(&dev->write_mutex);
 	mutex_unlock(&dev->write_mutex);
 	if (err) {
 	if (err) {
-		ERROR("erase failed err = %d", err);
+		pr_err("erase failed err = %d\n", err);
 		instr->state = MTD_ERASE_FAILED;
 		instr->state = MTD_ERASE_FAILED;
 	} else
 	} else
 		instr->state = MTD_ERASE_DONE;
 		instr->state = MTD_ERASE_DONE;
@@ -239,13 +238,13 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 #endif
 #endif
 
 
 	if (IS_ERR(bdev)) {
 	if (IS_ERR(bdev)) {
-		ERROR("error: cannot open device %s", devname);
+		pr_err("error: cannot open device %s\n", devname);
 		goto devinit_err;
 		goto devinit_err;
 	}
 	}
 	dev->blkdev = bdev;
 	dev->blkdev = bdev;
 
 
 	if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
 	if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
-		ERROR("attempting to use an MTD device as a block device");
+		pr_err("attempting to use an MTD device as a block device\n");
 		goto devinit_err;
 		goto devinit_err;
 	}
 	}
 
 
@@ -277,9 +276,10 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 		goto devinit_err;
 		goto devinit_err;
 	}
 	}
 	list_add(&dev->list, &blkmtd_device_list);
 	list_add(&dev->list, &blkmtd_device_list);
-	INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index,
-			dev->mtd.name + strlen("block2mtd: "),
-			dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+	pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
+		dev->mtd.index,
+		dev->mtd.name + strlen("block2mtd: "),
+		dev->mtd.erasesize >> 10, dev->mtd.erasesize);
 	return dev;
 	return dev;
 
 
 devinit_err:
 devinit_err:
@@ -339,17 +339,11 @@ static inline void kill_final_newline(char *str)
 }
 }
 
 
 
 
-#define parse_err(fmt, args...) do {	\
-	ERROR(fmt, ## args);		\
-	return 0;			\
-} while (0)
-
 #ifndef MODULE
 #ifndef MODULE
 static int block2mtd_init_called = 0;
 static int block2mtd_init_called = 0;
 static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
 static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
 #endif
 #endif
 
 
-
 static int block2mtd_setup2(const char *val)
 static int block2mtd_setup2(const char *val)
 {
 {
 	char buf[80 + 12]; /* 80 for device, 12 for erase size */
 	char buf[80 + 12]; /* 80 for device, 12 for erase size */
@@ -359,8 +353,10 @@ static int block2mtd_setup2(const char *val)
 	size_t erase_size = PAGE_SIZE;
 	size_t erase_size = PAGE_SIZE;
 	int i, ret;
 	int i, ret;
 
 
-	if (strnlen(val, sizeof(buf)) >= sizeof(buf))
-		parse_err("parameter too long");
+	if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
+		pr_err("parameter too long\n");
+		return 0;
+	}
 
 
 	strcpy(str, val);
 	strcpy(str, val);
 	kill_final_newline(str);
 	kill_final_newline(str);
@@ -368,20 +364,27 @@ static int block2mtd_setup2(const char *val)
 	for (i = 0; i < 2; i++)
 	for (i = 0; i < 2; i++)
 		token[i] = strsep(&str, ",");
 		token[i] = strsep(&str, ",");
 
 
-	if (str)
-		parse_err("too many arguments");
+	if (str) {
+		pr_err("too many arguments\n");
+		return 0;
+	}
 
 
-	if (!token[0])
-		parse_err("no argument");
+	if (!token[0]) {
+		pr_err("no argument\n");
+		return 0;
+	}
 
 
 	name = token[0];
 	name = token[0];
-	if (strlen(name) + 1 > 80)
-		parse_err("device name too long");
+	if (strlen(name) + 1 > 80) {
+		pr_err("device name too long\n");
+		return 0;
+	}
 
 
 	if (token[1]) {
 	if (token[1]) {
 		ret = parse_num(&erase_size, token[1]);
 		ret = parse_num(&erase_size, token[1]);
 		if (ret) {
 		if (ret) {
-			parse_err("illegal erase size");
+			pr_err("illegal erase size\n");
+			return 0;
 		}
 		}
 	}
 	}
 
 
@@ -444,8 +447,9 @@ static void block2mtd_exit(void)
 		struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
 		struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
 		block2mtd_sync(&dev->mtd);
 		block2mtd_sync(&dev->mtd);
 		mtd_device_unregister(&dev->mtd);
 		mtd_device_unregister(&dev->mtd);
-		INFO("mtd%d: [%s] removed", dev->mtd.index,
-				dev->mtd.name + strlen("block2mtd: "));
+		pr_info("mtd%d: [%s] removed\n",
+			dev->mtd.index,
+			dev->mtd.name + strlen("block2mtd: "));
 		list_del(&dev->list);
 		list_del(&dev->list);
 		block2mtd_free_device(dev);
 		block2mtd_free_device(dev);
 	}
 	}

+ 120 - 9
drivers/mtd/devices/elm.c

@@ -20,14 +20,21 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of.h>
+#include <linux/sched.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/elm.h>
 #include <linux/platform_data/elm.h>
 
 
+#define ELM_SYSCONFIG			0x010
 #define ELM_IRQSTATUS			0x018
 #define ELM_IRQSTATUS			0x018
 #define ELM_IRQENABLE			0x01c
 #define ELM_IRQENABLE			0x01c
 #define ELM_LOCATION_CONFIG		0x020
 #define ELM_LOCATION_CONFIG		0x020
 #define ELM_PAGE_CTRL			0x080
 #define ELM_PAGE_CTRL			0x080
 #define ELM_SYNDROME_FRAGMENT_0		0x400
 #define ELM_SYNDROME_FRAGMENT_0		0x400
+#define ELM_SYNDROME_FRAGMENT_1		0x404
+#define ELM_SYNDROME_FRAGMENT_2		0x408
+#define ELM_SYNDROME_FRAGMENT_3		0x40c
+#define ELM_SYNDROME_FRAGMENT_4		0x410
+#define ELM_SYNDROME_FRAGMENT_5		0x414
 #define ELM_SYNDROME_FRAGMENT_6		0x418
 #define ELM_SYNDROME_FRAGMENT_6		0x418
 #define ELM_LOCATION_STATUS		0x800
 #define ELM_LOCATION_STATUS		0x800
 #define ELM_ERROR_LOCATION_0		0x880
 #define ELM_ERROR_LOCATION_0		0x880
@@ -56,12 +63,27 @@
 #define SYNDROME_FRAGMENT_REG_SIZE	0x40
 #define SYNDROME_FRAGMENT_REG_SIZE	0x40
 #define ERROR_LOCATION_SIZE		0x100
 #define ERROR_LOCATION_SIZE		0x100
 
 
+struct elm_registers {
+	u32 elm_irqenable;
+	u32 elm_sysconfig;
+	u32 elm_location_config;
+	u32 elm_page_ctrl;
+	u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
+	u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
+};
+
 struct elm_info {
 struct elm_info {
 	struct device *dev;
 	struct device *dev;
 	void __iomem *elm_base;
 	void __iomem *elm_base;
 	struct completion elm_completion;
 	struct completion elm_completion;
 	struct list_head list;
 	struct list_head list;
 	enum bch_ecc bch_type;
 	enum bch_ecc bch_type;
+	struct elm_registers elm_regs;
 };
 };
 
 
 static LIST_HEAD(elm_devices);
 static LIST_HEAD(elm_devices);
@@ -346,14 +368,9 @@ static int elm_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "no memory resource defined\n");
-		return -ENODEV;
-	}
-
-	info->elm_base = devm_request_and_ioremap(&pdev->dev, res);
-	if (!info->elm_base)
-		return -EADDRNOTAVAIL;
+	info->elm_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(info->elm_base))
+		return PTR_ERR(info->elm_base);
 
 
 	ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
 	ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
 			pdev->name, info);
 			pdev->name, info);
@@ -381,10 +398,103 @@ static int elm_remove(struct platform_device *pdev)
 {
 {
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
-	platform_set_drvdata(pdev, NULL);
 	return 0;
 	return 0;
 }
 }
 
 
+/**
+ * elm_context_save
+ * saves ELM configurations to preserve them across Hardware powered-down
+ */
+static int elm_context_save(struct elm_info *info)
+{
+	struct elm_registers *regs = &info->elm_regs;
+	enum bch_ecc bch_type = info->bch_type;
+	u32 offset = 0, i;
+
+	regs->elm_irqenable       = elm_read_reg(info, ELM_IRQENABLE);
+	regs->elm_sysconfig       = elm_read_reg(info, ELM_SYSCONFIG);
+	regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
+	regs->elm_page_ctrl       = elm_read_reg(info, ELM_PAGE_CTRL);
+	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+		switch (bch_type) {
+		case BCH8_ECC:
+			regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_3 + offset);
+			regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_2 + offset);
+		case BCH4_ECC:
+			regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_1 + offset);
+			regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_0 + offset);
+		default:
+			return -EINVAL;
+		}
+		/* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
+		 * to be saved for all BCH schemes*/
+		regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
+					ELM_SYNDROME_FRAGMENT_6 + offset);
+	}
+	return 0;
+}
+
+/**
+ * elm_context_restore
+ * writes configurations saved duing power-down back into ELM registers
+ */
+static int elm_context_restore(struct elm_info *info)
+{
+	struct elm_registers *regs = &info->elm_regs;
+	enum bch_ecc bch_type = info->bch_type;
+	u32 offset = 0, i;
+
+	elm_write_reg(info, ELM_IRQENABLE,	 regs->elm_irqenable);
+	elm_write_reg(info, ELM_SYSCONFIG,	 regs->elm_sysconfig);
+	elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
+	elm_write_reg(info, ELM_PAGE_CTRL,	 regs->elm_page_ctrl);
+	for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+		offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+		switch (bch_type) {
+		case BCH8_ECC:
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
+					regs->elm_syndrome_fragment_3[i]);
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
+					regs->elm_syndrome_fragment_2[i]);
+		case BCH4_ECC:
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
+					regs->elm_syndrome_fragment_1[i]);
+			elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
+					regs->elm_syndrome_fragment_0[i]);
+		default:
+			return -EINVAL;
+		}
+		/* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
+		elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
+					regs->elm_syndrome_fragment_6[i] &
+							 ELM_SYNDROME_VALID);
+	}
+	return 0;
+}
+
+static int elm_suspend(struct device *dev)
+{
+	struct elm_info *info = dev_get_drvdata(dev);
+	elm_context_save(info);
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int elm_resume(struct device *dev)
+{
+	struct elm_info *info = dev_get_drvdata(dev);
+	pm_runtime_get_sync(dev);
+	elm_context_restore(info);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
+
 #ifdef CONFIG_OF
 #ifdef CONFIG_OF
 static const struct of_device_id elm_of_match[] = {
 static const struct of_device_id elm_of_match[] = {
 	{ .compatible = "ti,am3352-elm" },
 	{ .compatible = "ti,am3352-elm" },
@@ -398,6 +508,7 @@ static struct platform_driver elm_driver = {
 		.name	= "elm",
 		.name	= "elm",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(elm_of_match),
 		.of_match_table = of_match_ptr(elm_of_match),
+		.pm	= &elm_pm_ops,
 	},
 	},
 	.probe	= elm_probe,
 	.probe	= elm_probe,
 	.remove	= elm_remove,
 	.remove	= elm_remove,

+ 60 - 21
drivers/mtd/devices/m25p80.c

@@ -43,17 +43,24 @@
 #define	OPCODE_FAST_READ	0x0b	/* Read data bytes (high frequency) */
 #define	OPCODE_FAST_READ	0x0b	/* Read data bytes (high frequency) */
 #define	OPCODE_PP		0x02	/* Page program (up to 256 bytes) */
 #define	OPCODE_PP		0x02	/* Page program (up to 256 bytes) */
 #define	OPCODE_BE_4K		0x20	/* Erase 4KiB block */
 #define	OPCODE_BE_4K		0x20	/* Erase 4KiB block */
+#define	OPCODE_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
 #define	OPCODE_BE_32K		0x52	/* Erase 32KiB block */
 #define	OPCODE_BE_32K		0x52	/* Erase 32KiB block */
 #define	OPCODE_CHIP_ERASE	0xc7	/* Erase whole flash chip */
 #define	OPCODE_CHIP_ERASE	0xc7	/* Erase whole flash chip */
 #define	OPCODE_SE		0xd8	/* Sector erase (usually 64KiB) */
 #define	OPCODE_SE		0xd8	/* Sector erase (usually 64KiB) */
 #define	OPCODE_RDID		0x9f	/* Read JEDEC ID */
 #define	OPCODE_RDID		0x9f	/* Read JEDEC ID */
 
 
+/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+#define	OPCODE_NORM_READ_4B	0x13	/* Read data bytes (low frequency) */
+#define	OPCODE_FAST_READ_4B	0x0c	/* Read data bytes (high frequency) */
+#define	OPCODE_PP_4B		0x12	/* Page program (up to 256 bytes) */
+#define	OPCODE_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
+
 /* Used for SST flashes only. */
 /* Used for SST flashes only. */
 #define	OPCODE_BP		0x02	/* Byte program */
 #define	OPCODE_BP		0x02	/* Byte program */
 #define	OPCODE_WRDI		0x04	/* Write disable */
 #define	OPCODE_WRDI		0x04	/* Write disable */
 #define	OPCODE_AAI_WP		0xad	/* Auto address increment word program */
 #define	OPCODE_AAI_WP		0xad	/* Auto address increment word program */
 
 
-/* Used for Macronix flashes only. */
+/* Used for Macronix and Winbond flashes. */
 #define	OPCODE_EN4B		0xb7	/* Enter 4-byte mode */
 #define	OPCODE_EN4B		0xb7	/* Enter 4-byte mode */
 #define	OPCODE_EX4B		0xe9	/* Exit 4-byte mode */
 #define	OPCODE_EX4B		0xe9	/* Exit 4-byte mode */
 
 
@@ -84,6 +91,8 @@ struct m25p {
 	u16			page_size;
 	u16			page_size;
 	u16			addr_width;
 	u16			addr_width;
 	u8			erase_opcode;
 	u8			erase_opcode;
+	u8			read_opcode;
+	u8			program_opcode;
 	u8			*command;
 	u8			*command;
 	bool			fast_read;
 	bool			fast_read;
 };
 };
@@ -161,6 +170,7 @@ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
 {
 {
 	switch (JEDEC_MFR(jedec_id)) {
 	switch (JEDEC_MFR(jedec_id)) {
 	case CFI_MFR_MACRONIX:
 	case CFI_MFR_MACRONIX:
+	case CFI_MFR_ST: /* Micron, actually */
 	case 0xEF /* winbond */:
 	case 0xEF /* winbond */:
 		flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
 		flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
 		return spi_write(flash->spi, flash->command, 1);
 		return spi_write(flash->spi, flash->command, 1);
@@ -371,7 +381,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
 	 */
 	 */
 
 
 	/* Set up the write data buffer. */
 	/* Set up the write data buffer. */
-	opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ;
+	opcode = flash->read_opcode;
 	flash->command[0] = opcode;
 	flash->command[0] = opcode;
 	m25p_addr2cmd(flash, from, flash->command);
 	m25p_addr2cmd(flash, from, flash->command);
 
 
@@ -422,7 +432,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
 	write_enable(flash);
 	write_enable(flash);
 
 
 	/* Set up the opcode in the write buffer. */
 	/* Set up the opcode in the write buffer. */
-	flash->command[0] = OPCODE_PP;
+	flash->command[0] = flash->program_opcode;
 	m25p_addr2cmd(flash, to, flash->command);
 	m25p_addr2cmd(flash, to, flash->command);
 
 
 	page_offset = to & (flash->page_size - 1);
 	page_offset = to & (flash->page_size - 1);
@@ -682,6 +692,8 @@ struct flash_info {
 #define	SECT_4K		0x01		/* OPCODE_BE_4K works uniformly */
 #define	SECT_4K		0x01		/* OPCODE_BE_4K works uniformly */
 #define	M25P_NO_ERASE	0x02		/* No erase command needed */
 #define	M25P_NO_ERASE	0x02		/* No erase command needed */
 #define	SST_WRITE	0x04		/* use SST byte programming */
 #define	SST_WRITE	0x04		/* use SST byte programming */
+#define	M25P_NO_FR	0x08		/* Can't do fastread */
+#define	SECT_4K_PMC	0x10		/* OPCODE_BE_4K_PMC works uniformly */
 };
 };
 
 
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
@@ -694,13 +706,13 @@ struct flash_info {
 		.flags = (_flags),					\
 		.flags = (_flags),					\
 	})
 	})
 
 
-#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width)	\
+#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags)	\
 	((kernel_ulong_t)&(struct flash_info) {				\
 	((kernel_ulong_t)&(struct flash_info) {				\
 		.sector_size = (_sector_size),				\
 		.sector_size = (_sector_size),				\
 		.n_sectors = (_n_sectors),				\
 		.n_sectors = (_n_sectors),				\
 		.page_size = (_page_size),				\
 		.page_size = (_page_size),				\
 		.addr_width = (_addr_width),				\
 		.addr_width = (_addr_width),				\
-		.flags = M25P_NO_ERASE,					\
+		.flags = (_flags),					\
 	})
 	})
 
 
 /* NOTE: double check command sets and memory organization when you add
 /* NOTE: double check command sets and memory organization when you add
@@ -732,7 +744,8 @@ static const struct spi_device_id m25p_ids[] = {
 	{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
 	{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
 
 
 	/* Everspin */
 	/* Everspin */
-	{ "mr25h256", CAT25_INFO(  32 * 1024, 1, 256, 2) },
+	{ "mr25h256", CAT25_INFO(  32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) },
+	{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) },
 
 
 	/* GigaDevice */
 	/* GigaDevice */
 	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
 	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
@@ -762,6 +775,11 @@ static const struct spi_device_id m25p_ids[] = {
 	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
 	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
 	{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
 	{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
 
 
+	/* PMC */
+	{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
+	{ "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) },
+	{ "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024,  64, SECT_4K) },
+
 	/* Spansion -- single (large) sector size only, at least
 	/* Spansion -- single (large) sector size only, at least
 	 * for the chips listed here (without boot sectors).
 	 * for the chips listed here (without boot sectors).
 	 */
 	 */
@@ -840,17 +858,18 @@ static const struct spi_device_id m25p_ids[] = {
 	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
 	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
 	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
 	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
 	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
 	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
+	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
 	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
 	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
 	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
 	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
 	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
 	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
 	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
 	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
 
 
 	/* Catalyst / On Semiconductor -- non-JEDEC */
 	/* Catalyst / On Semiconductor -- non-JEDEC */
-	{ "cat25c11", CAT25_INFO(  16, 8, 16, 1) },
-	{ "cat25c03", CAT25_INFO(  32, 8, 16, 2) },
-	{ "cat25c09", CAT25_INFO( 128, 8, 32, 2) },
-	{ "cat25c17", CAT25_INFO( 256, 8, 32, 2) },
-	{ "cat25128", CAT25_INFO(2048, 8, 64, 2) },
+	{ "cat25c11", CAT25_INFO(  16, 8, 16, 1, M25P_NO_ERASE | M25P_NO_FR) },
+	{ "cat25c03", CAT25_INFO(  32, 8, 16, 2, M25P_NO_ERASE | M25P_NO_FR) },
+	{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
+	{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
+	{ "cat25128", CAT25_INFO(2048, 8, 64, 2, M25P_NO_ERASE | M25P_NO_FR) },
 	{ },
 	{ },
 };
 };
 MODULE_DEVICE_TABLE(spi, m25p_ids);
 MODULE_DEVICE_TABLE(spi, m25p_ids);
@@ -920,7 +939,7 @@ static int m25p_probe(struct spi_device *spi)
 	 * a chip ID, try the JEDEC id commands; they'll work for most
 	 * a chip ID, try the JEDEC id commands; they'll work for most
 	 * newer chips, even if we don't recognize the particular chip.
 	 * newer chips, even if we don't recognize the particular chip.
 	 */
 	 */
-	data = spi->dev.platform_data;
+	data = dev_get_platdata(&spi->dev);
 	if (data && data->type) {
 	if (data && data->type) {
 		const struct spi_device_id *plat_id;
 		const struct spi_device_id *plat_id;
 
 
@@ -972,7 +991,7 @@ static int m25p_probe(struct spi_device *spi)
 
 
 	flash->spi = spi;
 	flash->spi = spi;
 	mutex_init(&flash->lock);
 	mutex_init(&flash->lock);
-	dev_set_drvdata(&spi->dev, flash);
+	spi_set_drvdata(spi, flash);
 
 
 	/*
 	/*
 	 * Atmel, SST and Intel/Numonyx serial flash tend to power
 	 * Atmel, SST and Intel/Numonyx serial flash tend to power
@@ -1014,6 +1033,9 @@ static int m25p_probe(struct spi_device *spi)
 	if (info->flags & SECT_4K) {
 	if (info->flags & SECT_4K) {
 		flash->erase_opcode = OPCODE_BE_4K;
 		flash->erase_opcode = OPCODE_BE_4K;
 		flash->mtd.erasesize = 4096;
 		flash->mtd.erasesize = 4096;
+	} else if (info->flags & SECT_4K_PMC) {
+		flash->erase_opcode = OPCODE_BE_4K_PMC;
+		flash->mtd.erasesize = 4096;
 	} else {
 	} else {
 		flash->erase_opcode = OPCODE_SE;
 		flash->erase_opcode = OPCODE_SE;
 		flash->mtd.erasesize = info->sector_size;
 		flash->mtd.erasesize = info->sector_size;
@@ -1028,24 +1050,41 @@ static int m25p_probe(struct spi_device *spi)
 	flash->mtd.writebufsize = flash->page_size;
 	flash->mtd.writebufsize = flash->page_size;
 
 
 	flash->fast_read = false;
 	flash->fast_read = false;
-#ifdef CONFIG_OF
 	if (np && of_property_read_bool(np, "m25p,fast-read"))
 	if (np && of_property_read_bool(np, "m25p,fast-read"))
 		flash->fast_read = true;
 		flash->fast_read = true;
-#endif
 
 
 #ifdef CONFIG_M25PXX_USE_FAST_READ
 #ifdef CONFIG_M25PXX_USE_FAST_READ
 	flash->fast_read = true;
 	flash->fast_read = true;
 #endif
 #endif
+	if (info->flags & M25P_NO_FR)
+		flash->fast_read = false;
+
+	/* Default commands */
+	if (flash->fast_read)
+		flash->read_opcode = OPCODE_FAST_READ;
+	else
+		flash->read_opcode = OPCODE_NORM_READ;
+
+	flash->program_opcode = OPCODE_PP;
 
 
 	if (info->addr_width)
 	if (info->addr_width)
 		flash->addr_width = info->addr_width;
 		flash->addr_width = info->addr_width;
-	else {
+	else if (flash->mtd.size > 0x1000000) {
 		/* enable 4-byte addressing if the device exceeds 16MiB */
 		/* enable 4-byte addressing if the device exceeds 16MiB */
-		if (flash->mtd.size > 0x1000000) {
-			flash->addr_width = 4;
-			set_4byte(flash, info->jedec_id, 1);
+		flash->addr_width = 4;
+		if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
+			/* Dedicated 4-byte command set */
+			flash->read_opcode = flash->fast_read ?
+				OPCODE_FAST_READ_4B :
+				OPCODE_NORM_READ_4B;
+			flash->program_opcode = OPCODE_PP_4B;
+			/* No small sector erase for 4-byte command set */
+			flash->erase_opcode = OPCODE_SE_4B;
+			flash->mtd.erasesize = info->sector_size;
 		} else
 		} else
-			flash->addr_width = 3;
+			set_4byte(flash, info->jedec_id, 1);
+	} else {
+		flash->addr_width = 3;
 	}
 	}
 
 
 	dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
 	dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
@@ -1080,7 +1119,7 @@ static int m25p_probe(struct spi_device *spi)
 
 
 static int m25p_remove(struct spi_device *spi)
 static int m25p_remove(struct spi_device *spi)
 {
 {
-	struct m25p	*flash = dev_get_drvdata(&spi->dev);
+	struct m25p	*flash = spi_get_drvdata(spi);
 	int		status;
 	int		status;
 
 
 	/* Clean up MTD stuff. */
 	/* Clean up MTD stuff. */

+ 5 - 5
drivers/mtd/devices/mtd_dataflash.c

@@ -622,7 +622,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
 	struct dataflash		*priv;
 	struct dataflash		*priv;
 	struct mtd_info			*device;
 	struct mtd_info			*device;
 	struct mtd_part_parser_data	ppdata;
 	struct mtd_part_parser_data	ppdata;
-	struct flash_platform_data	*pdata = spi->dev.platform_data;
+	struct flash_platform_data	*pdata = dev_get_platdata(&spi->dev);
 	char				*otp_tag = "";
 	char				*otp_tag = "";
 	int				err = 0;
 	int				err = 0;
 
 
@@ -661,7 +661,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
 	dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n",
 	dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n",
 			name, (long long)((device->size + 1023) >> 10),
 			name, (long long)((device->size + 1023) >> 10),
 			pagesize, otp_tag);
 			pagesize, otp_tag);
-	dev_set_drvdata(&spi->dev, priv);
+	spi_set_drvdata(spi, priv);
 
 
 	ppdata.of_node = spi->dev.of_node;
 	ppdata.of_node = spi->dev.of_node;
 	err = mtd_device_parse_register(device, NULL, &ppdata,
 	err = mtd_device_parse_register(device, NULL, &ppdata,
@@ -671,7 +671,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
 	if (!err)
 	if (!err)
 		return 0;
 		return 0;
 
 
-	dev_set_drvdata(&spi->dev, NULL);
+	spi_set_drvdata(spi, NULL);
 	kfree(priv);
 	kfree(priv);
 	return err;
 	return err;
 }
 }
@@ -895,14 +895,14 @@ static int dataflash_probe(struct spi_device *spi)
 
 
 static int dataflash_remove(struct spi_device *spi)
 static int dataflash_remove(struct spi_device *spi)
 {
 {
-	struct dataflash	*flash = dev_get_drvdata(&spi->dev);
+	struct dataflash	*flash = spi_get_drvdata(spi);
 	int			status;
 	int			status;
 
 
 	pr_debug("%s: remove\n", dev_name(&spi->dev));
 	pr_debug("%s: remove\n", dev_name(&spi->dev));
 
 
 	status = mtd_device_unregister(&flash->mtd);
 	status = mtd_device_unregister(&flash->mtd);
 	if (status == 0) {
 	if (status == 0) {
-		dev_set_drvdata(&spi->dev, NULL);
+		spi_set_drvdata(spi, NULL);
 		kfree(flash);
 		kfree(flash);
 	}
 	}
 	return status;
 	return status;

+ 7 - 12
drivers/mtd/devices/spear_smi.c

@@ -550,7 +550,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
 {
 {
 	struct spear_snor_flash *flash = get_flash_data(mtd);
 	struct spear_snor_flash *flash = get_flash_data(mtd);
 	struct spear_smi *dev = mtd->priv;
 	struct spear_smi *dev = mtd->priv;
-	void *src;
+	void __iomem *src;
 	u32 ctrlreg1, val;
 	u32 ctrlreg1, val;
 	int ret;
 	int ret;
 
 
@@ -583,7 +583,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
 
 
 	writel(val, dev->io_base + SMI_CR1);
 	writel(val, dev->io_base + SMI_CR1);
 
 
-	memcpy_fromio(buf, (u8 *)src, len);
+	memcpy_fromio(buf, src, len);
 
 
 	/* restore ctrl reg1 */
 	/* restore ctrl reg1 */
 	writel(ctrlreg1, dev->io_base + SMI_CR1);
 	writel(ctrlreg1, dev->io_base + SMI_CR1);
@@ -596,7 +596,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
 }
 }
 
 
 static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
 static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
-		void *dest, const void *src, size_t len)
+		void __iomem *dest, const void *src, size_t len)
 {
 {
 	int ret;
 	int ret;
 	u32 ctrlreg1;
 	u32 ctrlreg1;
@@ -643,7 +643,7 @@ static int spear_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
 {
 {
 	struct spear_snor_flash *flash = get_flash_data(mtd);
 	struct spear_snor_flash *flash = get_flash_data(mtd);
 	struct spear_smi *dev = mtd->priv;
 	struct spear_smi *dev = mtd->priv;
-	void *dest;
+	void __iomem *dest;
 	u32 page_offset, page_size;
 	u32 page_offset, page_size;
 	int ret;
 	int ret;
 
 
@@ -995,14 +995,12 @@ static int spear_smi_probe(struct platform_device *pdev)
 		ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
 		ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
 		if (ret) {
 		if (ret) {
 			dev_err(&dev->pdev->dev, "bank setup failed\n");
 			dev_err(&dev->pdev->dev, "bank setup failed\n");
-			goto err_bank_setup;
+			goto err_irq;
 		}
 		}
 	}
 	}
 
 
 	return 0;
 	return 0;
 
 
-err_bank_setup:
-	platform_set_drvdata(pdev, NULL);
 err_irq:
 err_irq:
 	clk_disable_unprepare(dev->clk);
 	clk_disable_unprepare(dev->clk);
 err:
 err:
@@ -1040,12 +1038,11 @@ static int spear_smi_remove(struct platform_device *pdev)
 	}
 	}
 
 
 	clk_disable_unprepare(dev->clk);
 	clk_disable_unprepare(dev->clk);
-	platform_set_drvdata(pdev, NULL);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int spear_smi_suspend(struct device *dev)
 static int spear_smi_suspend(struct device *dev)
 {
 {
 	struct spear_smi *sdev = dev_get_drvdata(dev);
 	struct spear_smi *sdev = dev_get_drvdata(dev);
@@ -1068,9 +1065,9 @@ static int spear_smi_resume(struct device *dev)
 		spear_smi_hw_init(sdev);
 		spear_smi_hw_init(sdev);
 	return ret;
 	return ret;
 }
 }
+#endif
 
 
 static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume);
 static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume);
-#endif
 
 
 #ifdef CONFIG_OF
 #ifdef CONFIG_OF
 static const struct of_device_id spear_smi_id_table[] = {
 static const struct of_device_id spear_smi_id_table[] = {
@@ -1086,9 +1083,7 @@ static struct platform_driver spear_smi_driver = {
 		.bus = &platform_bus_type,
 		.bus = &platform_bus_type,
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 		.of_match_table = of_match_ptr(spear_smi_id_table),
 		.of_match_table = of_match_ptr(spear_smi_id_table),
-#ifdef CONFIG_PM
 		.pm = &spear_smi_pm_ops,
 		.pm = &spear_smi_pm_ops,
-#endif
 	},
 	},
 	.probe = spear_smi_probe,
 	.probe = spear_smi_probe,
 	.remove = spear_smi_remove,
 	.remove = spear_smi_remove,

+ 4 - 4
drivers/mtd/devices/sst25l.c

@@ -370,9 +370,9 @@ static int sst25l_probe(struct spi_device *spi)
 
 
 	flash->spi = spi;
 	flash->spi = spi;
 	mutex_init(&flash->lock);
 	mutex_init(&flash->lock);
-	dev_set_drvdata(&spi->dev, flash);
+	spi_set_drvdata(spi, flash);
 
 
-	data = spi->dev.platform_data;
+	data = dev_get_platdata(&spi->dev);
 	if (data && data->name)
 	if (data && data->name)
 		flash->mtd.name = data->name;
 		flash->mtd.name = data->name;
 	else
 	else
@@ -404,7 +404,7 @@ static int sst25l_probe(struct spi_device *spi)
 					data ? data->nr_parts : 0);
 					data ? data->nr_parts : 0);
 	if (ret) {
 	if (ret) {
 		kfree(flash);
 		kfree(flash);
-		dev_set_drvdata(&spi->dev, NULL);
+		spi_set_drvdata(spi, NULL);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -413,7 +413,7 @@ static int sst25l_probe(struct spi_device *spi)
 
 
 static int sst25l_remove(struct spi_device *spi)
 static int sst25l_remove(struct spi_device *spi)
 {
 {
-	struct sst25l_flash *flash = dev_get_drvdata(&spi->dev);
+	struct sst25l_flash *flash = spi_get_drvdata(spi);
 	int ret;
 	int ret;
 
 
 	ret = mtd_device_unregister(&flash->mtd);
 	ret = mtd_device_unregister(&flash->mtd);

+ 0 - 18
drivers/mtd/maps/Kconfig

@@ -157,24 +157,6 @@ config MTD_PXA2XX
 	help
 	help
 	  This provides a driver for the NOR flash attached to a PXA2xx chip.
 	  This provides a driver for the NOR flash attached to a PXA2xx chip.
 
 
-config MTD_OCTAGON
-	tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
-	depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
-	help
-	  This provides a 'mapping' driver which supports the way in which
-	  the flash chips are connected in the Octagon-5066 Single Board
-	  Computer. More information on the board is available at
-	  <http://www.octagonsystems.com/products/5066.aspx>.
-
-config MTD_VMAX
-	tristate "JEDEC Flash device mapped on Tempustech VMAX SBC301"
-	depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
-	help
-	  This provides a 'mapping' driver which supports the way in which
-	  the flash chips are connected in the Tempustech VMAX SBC301 Single
-	  Board Computer. More information on the board is available at
-	  <http://www.tempustech.com/>.
-
 config MTD_SCx200_DOCFLASH
 config MTD_SCx200_DOCFLASH
 	tristate "Flash device mapped with DOCCS on NatSemi SCx200"
 	tristate "Flash device mapped with DOCCS on NatSemi SCx200"
 	depends on SCx200 && MTD_CFI
 	depends on SCx200 && MTD_CFI

+ 0 - 2
drivers/mtd/maps/Makefile

@@ -16,7 +16,6 @@ obj-$(CONFIG_MTD_ICHXROM)	+= ichxrom.o
 obj-$(CONFIG_MTD_CK804XROM)	+= ck804xrom.o
 obj-$(CONFIG_MTD_CK804XROM)	+= ck804xrom.o
 obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
 obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
 obj-$(CONFIG_MTD_PXA2XX)	+= pxa2xx-flash.o
 obj-$(CONFIG_MTD_PXA2XX)	+= pxa2xx-flash.o
-obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
 obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o
 obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o
 obj-$(CONFIG_MTD_PHYSMAP_OF)	+= physmap_of.o
 obj-$(CONFIG_MTD_PHYSMAP_OF)	+= physmap_of.o
 obj-$(CONFIG_MTD_PISMO)		+= pismo.o
 obj-$(CONFIG_MTD_PISMO)		+= pismo.o
@@ -28,7 +27,6 @@ obj-$(CONFIG_MTD_SC520CDP)	+= sc520cdp.o
 obj-$(CONFIG_MTD_NETSC520)	+= netsc520.o
 obj-$(CONFIG_MTD_NETSC520)	+= netsc520.o
 obj-$(CONFIG_MTD_TS5500)	+= ts5500_flash.o
 obj-$(CONFIG_MTD_TS5500)	+= ts5500_flash.o
 obj-$(CONFIG_MTD_SUN_UFLASH)	+= sun_uflash.o
 obj-$(CONFIG_MTD_SUN_UFLASH)	+= sun_uflash.o
-obj-$(CONFIG_MTD_VMAX)		+= vmax301.o
 obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)		+= pci.o
 obj-$(CONFIG_MTD_PCI)		+= pci.o

+ 1 - 1
drivers/mtd/maps/bfin-async-flash.c

@@ -128,7 +128,7 @@ static const char * const part_probe_types[] = {
 static int bfin_flash_probe(struct platform_device *pdev)
 static int bfin_flash_probe(struct platform_device *pdev)
 {
 {
 	int ret;
 	int ret;
-	struct physmap_flash_data *pdata = pdev->dev.platform_data;
+	struct physmap_flash_data *pdata = dev_get_platdata(&pdev->dev);
 	struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	struct async_state *state;
 	struct async_state *state;

+ 5 - 5
drivers/mtd/maps/cfi_flagadm.c

@@ -55,13 +55,13 @@
 #define FLASH_PARTITION3_SIZE 0x001C0000
 #define FLASH_PARTITION3_SIZE 0x001C0000
 
 
 
 
-struct map_info flagadm_map = {
+static struct map_info flagadm_map = {
 		.name =		"FlagaDM flash device",
 		.name =		"FlagaDM flash device",
 		.size =		FLASH_SIZE,
 		.size =		FLASH_SIZE,
 		.bankwidth =	2,
 		.bankwidth =	2,
 };
 };
 
 
-struct mtd_partition flagadm_parts[] = {
+static struct mtd_partition flagadm_parts[] = {
 	{
 	{
 		.name =		"Bootloader",
 		.name =		"Bootloader",
 		.offset	=	FLASH_PARTITION0_ADDR,
 		.offset	=	FLASH_PARTITION0_ADDR,
@@ -112,7 +112,7 @@ static int __init init_flagadm(void)
 		return 0;
 		return 0;
 	}
 	}
 
 
-	iounmap((void *)flagadm_map.virt);
+	iounmap((void __iomem *)flagadm_map.virt);
 	return -ENXIO;
 	return -ENXIO;
 }
 }
 
 
@@ -123,8 +123,8 @@ static void __exit cleanup_flagadm(void)
 		map_destroy(mymtd);
 		map_destroy(mymtd);
 	}
 	}
 	if (flagadm_map.virt) {
 	if (flagadm_map.virt) {
-		iounmap((void *)flagadm_map.virt);
-		flagadm_map.virt = 0;
+		iounmap((void __iomem *)flagadm_map.virt);
+		flagadm_map.virt = NULL;
 	}
 	}
 }
 }
 
 

+ 1 - 1
drivers/mtd/maps/gpio-addr-flash.c

@@ -196,7 +196,7 @@ static int gpio_flash_probe(struct platform_device *pdev)
 	struct resource *gpios;
 	struct resource *gpios;
 	struct async_state *state;
 	struct async_state *state;
 
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
 

+ 5 - 5
drivers/mtd/maps/impa7.c

@@ -79,7 +79,7 @@ static int __init init_impa7(void)
 		}
 		}
 		simple_map_init(&impa7_map[i]);
 		simple_map_init(&impa7_map[i]);
 
 
-		impa7_mtd[i] = 0;
+		impa7_mtd[i] = NULL;
 		type = rom_probe_types;
 		type = rom_probe_types;
 		for(; !impa7_mtd[i] && *type; type++) {
 		for(; !impa7_mtd[i] && *type; type++) {
 			impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
 			impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
@@ -91,9 +91,9 @@ static int __init init_impa7(void)
 			mtd_device_parse_register(impa7_mtd[i], NULL, NULL,
 			mtd_device_parse_register(impa7_mtd[i], NULL, NULL,
 						  partitions,
 						  partitions,
 						  ARRAY_SIZE(partitions));
 						  ARRAY_SIZE(partitions));
+		} else {
+			iounmap((void __iomem *)impa7_map[i].virt);
 		}
 		}
-		else
-			iounmap((void *)impa7_map[i].virt);
 	}
 	}
 	return devicesfound == 0 ? -ENXIO : 0;
 	return devicesfound == 0 ? -ENXIO : 0;
 }
 }
@@ -105,8 +105,8 @@ static void __exit cleanup_impa7(void)
 		if (impa7_mtd[i]) {
 		if (impa7_mtd[i]) {
 			mtd_device_unregister(impa7_mtd[i]);
 			mtd_device_unregister(impa7_mtd[i]);
 			map_destroy(impa7_mtd[i]);
 			map_destroy(impa7_mtd[i]);
-			iounmap((void *)impa7_map[i].virt);
-			impa7_map[i].virt = 0;
+			iounmap((void __iomem *)impa7_map[i].virt);
+			impa7_map[i].virt = NULL;
 		}
 		}
 	}
 	}
 }
 }

+ 2 - 4
drivers/mtd/maps/ixp4xx.c

@@ -152,11 +152,9 @@ static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
 
 
 static int ixp4xx_flash_remove(struct platform_device *dev)
 static int ixp4xx_flash_remove(struct platform_device *dev)
 {
 {
-	struct flash_platform_data *plat = dev->dev.platform_data;
+	struct flash_platform_data *plat = dev_get_platdata(&dev->dev);
 	struct ixp4xx_flash_info *info = platform_get_drvdata(dev);
 	struct ixp4xx_flash_info *info = platform_get_drvdata(dev);
 
 
-	platform_set_drvdata(dev, NULL);
-
 	if(!info)
 	if(!info)
 		return 0;
 		return 0;
 
 
@@ -180,7 +178,7 @@ static int ixp4xx_flash_remove(struct platform_device *dev)
 
 
 static int ixp4xx_flash_probe(struct platform_device *dev)
 static int ixp4xx_flash_probe(struct platform_device *dev)
 {
 {
-	struct flash_platform_data *plat = dev->dev.platform_data;
+	struct flash_platform_data *plat = dev_get_platdata(&dev->dev);
 	struct ixp4xx_flash_info *info;
 	struct ixp4xx_flash_info *info;
 	struct mtd_part_parser_data ppdata = {
 	struct mtd_part_parser_data ppdata = {
 		.origin = dev->resource->start,
 		.origin = dev->resource->start,

+ 2 - 3
drivers/mtd/maps/latch-addr-flash.c

@@ -102,9 +102,8 @@ static int latch_addr_flash_remove(struct platform_device *dev)
 	info = platform_get_drvdata(dev);
 	info = platform_get_drvdata(dev);
 	if (info == NULL)
 	if (info == NULL)
 		return 0;
 		return 0;
-	platform_set_drvdata(dev, NULL);
 
 
-	latch_addr_data = dev->dev.platform_data;
+	latch_addr_data = dev_get_platdata(&dev->dev);
 
 
 	if (info->mtd != NULL) {
 	if (info->mtd != NULL) {
 		mtd_device_unregister(info->mtd);
 		mtd_device_unregister(info->mtd);
@@ -135,7 +134,7 @@ static int latch_addr_flash_probe(struct platform_device *dev)
 	int chipsel;
 	int chipsel;
 	int err;
 	int err;
 
 
-	latch_addr_data = dev->dev.platform_data;
+	latch_addr_data = dev_get_platdata(&dev->dev);
 	if (latch_addr_data == NULL)
 	if (latch_addr_data == NULL)
 		return -ENODEV;
 		return -ENODEV;
 
 

+ 0 - 246
drivers/mtd/maps/octagon-5066.c

@@ -1,246 +0,0 @@
-/* ######################################################################
-
-   Octagon 5066 MTD Driver.
-
-   The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It
-   comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that
-   is replacable by flash. Both units are mapped through a multiplexer
-   into a 32k memory window at 0xe8000. The control register for the
-   multiplexing unit is located at IO 0x208 with a bit map of
-     0-5 Page Selection in 32k increments
-     6-7 Device selection:
-        00 SSD off
-        01 SSD 0 (Socket)
-        10 SSD 1 (Flash chip)
-        11 undefined
-
-   On each SSD, the first 128k is reserved for use by the bios
-   (actually it IS the bios..) This only matters if you are booting off the
-   flash, you must not put a file system starting there.
-
-   The driver tries to do a detection algorithm to guess what sort of devices
-   are plugged into the sockets.
-
-   ##################################################################### */
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-
-#define WINDOW_START 0xe8000
-#define WINDOW_LENGTH 0x8000
-#define WINDOW_SHIFT 27
-#define WINDOW_MASK 0x7FFF
-#define PAGE_IO 0x208
-
-static volatile char page_n_dev = 0;
-static unsigned long iomapadr;
-static DEFINE_SPINLOCK(oct5066_spin);
-
-/*
- * We use map_priv_1 to identify which device we are.
- */
-
-static void __oct5066_page(struct map_info *map, __u8 byte)
-{
-	outb(byte,PAGE_IO);
-	page_n_dev = byte;
-}
-
-static inline void oct5066_page(struct map_info *map, unsigned long ofs)
-{
-	__u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
-
-	if (page_n_dev != byte)
-		__oct5066_page(map, byte);
-}
-
-
-static map_word oct5066_read8(struct map_info *map, unsigned long ofs)
-{
-	map_word ret;
-	spin_lock(&oct5066_spin);
-	oct5066_page(map, ofs);
-	ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
-	spin_unlock(&oct5066_spin);
-	return ret;
-}
-
-static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	while(len) {
-		unsigned long thislen = len;
-		if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
-			thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-
-		spin_lock(&oct5066_spin);
-		oct5066_page(map, from);
-		memcpy_fromio(to, iomapadr + from, thislen);
-		spin_unlock(&oct5066_spin);
-		to += thislen;
-		from += thislen;
-		len -= thislen;
-	}
-}
-
-static void oct5066_write8(struct map_info *map, map_word d, unsigned long adr)
-{
-	spin_lock(&oct5066_spin);
-	oct5066_page(map, adr);
-	writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
-	spin_unlock(&oct5066_spin);
-}
-
-static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	while(len) {
-		unsigned long thislen = len;
-		if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
-			thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-
-		spin_lock(&oct5066_spin);
-		oct5066_page(map, to);
-		memcpy_toio(iomapadr + to, from, thislen);
-		spin_unlock(&oct5066_spin);
-		to += thislen;
-		from += thislen;
-		len -= thislen;
-	}
-}
-
-static struct map_info oct5066_map[2] = {
-	{
-		.name = "Octagon 5066 Socket",
-		.phys = NO_XIP,
-		.size = 512 * 1024,
-		.bankwidth = 1,
-		.read = oct5066_read8,
-		.copy_from = oct5066_copy_from,
-		.write = oct5066_write8,
-		.copy_to = oct5066_copy_to,
-		.map_priv_1 = 1<<6
-	},
-	{
-		.name = "Octagon 5066 Internal Flash",
-		.phys = NO_XIP,
-		.size = 2 * 1024 * 1024,
-		.bankwidth = 1,
-		.read = oct5066_read8,
-		.copy_from = oct5066_copy_from,
-		.write = oct5066_write8,
-		.copy_to = oct5066_copy_to,
-		.map_priv_1 = 2<<6
-	}
-};
-
-static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
-
-// OctProbe - Sense if this is an octagon card
-// ---------------------------------------------------------------------
-/* Perform a simple validity test, we map the window select SSD0 and
-   change pages while monitoring the window. A change in the window,
-   controlled by the PAGE_IO port is a functioning 5066 board. This will
-   fail if the thing in the socket is set to a uniform value. */
-static int __init OctProbe(void)
-{
-   unsigned int Base = (1 << 6);
-   unsigned long I;
-   unsigned long Values[10];
-   for (I = 0; I != 20; I++)
-   {
-      outb(Base + (I%10),PAGE_IO);
-      if (I < 10)
-      {
-	 // Record the value and check for uniqueness
-	 Values[I%10] = readl(iomapadr);
-	 if (I > 0 && Values[I%10] == Values[0])
-	    return -EAGAIN;
-      }
-      else
-      {
-	 // Make sure we get the same values on the second pass
-	 if (Values[I%10] != readl(iomapadr))
-	    return -EAGAIN;
-      }
-   }
-   return 0;
-}
-
-void cleanup_oct5066(void)
-{
-	int i;
-	for (i=0; i<2; i++) {
-		if (oct5066_mtd[i]) {
-			mtd_device_unregister(oct5066_mtd[i]);
-			map_destroy(oct5066_mtd[i]);
-		}
-	}
-	iounmap((void *)iomapadr);
-	release_region(PAGE_IO, 1);
-}
-
-static int __init init_oct5066(void)
-{
-	int i;
-	int ret = 0;
-
-	// Do an autoprobe sequence
-	if (!request_region(PAGE_IO,1,"Octagon SSD")) {
-		printk(KERN_NOTICE "5066: Page Register in Use\n");
-		return -EAGAIN;
-	}
-	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
-	if (!iomapadr) {
-		printk(KERN_NOTICE "Failed to ioremap memory region\n");
-		ret = -EIO;
-		goto out_rel;
-	}
-	if (OctProbe() != 0) {
-		printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
-		iounmap((void *)iomapadr);
-		ret = -EAGAIN;
-		goto out_unmap;
-	}
-
-	// Print out our little header..
-	printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
-	       WINDOW_START+WINDOW_LENGTH);
-
-	for (i=0; i<2; i++) {
-		oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
-		if (!oct5066_mtd[i])
-			oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
-		if (!oct5066_mtd[i])
-			oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[i]);
-		if (!oct5066_mtd[i])
-			oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
-		if (oct5066_mtd[i]) {
-			oct5066_mtd[i]->owner = THIS_MODULE;
-			mtd_device_register(oct5066_mtd[i], NULL, 0);
-		}
-	}
-
-	if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
-		cleanup_oct5066();
-		return -ENXIO;
-	}
-
-	return 0;
-
- out_unmap:
-	iounmap((void *)iomapadr);
- out_rel:
-	release_region(PAGE_IO, 1);
-	return ret;
-}
-
-module_init(init_oct5066);
-module_exit(cleanup_oct5066);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");

+ 3 - 4
drivers/mtd/maps/physmap.c

@@ -40,9 +40,8 @@ static int physmap_flash_remove(struct platform_device *dev)
 	info = platform_get_drvdata(dev);
 	info = platform_get_drvdata(dev);
 	if (info == NULL)
 	if (info == NULL)
 		return 0;
 		return 0;
-	platform_set_drvdata(dev, NULL);
 
 
-	physmap_data = dev->dev.platform_data;
+	physmap_data = dev_get_platdata(&dev->dev);
 
 
 	if (info->cmtd) {
 	if (info->cmtd) {
 		mtd_device_unregister(info->cmtd);
 		mtd_device_unregister(info->cmtd);
@@ -69,7 +68,7 @@ static void physmap_set_vpp(struct map_info *map, int state)
 	unsigned long flags;
 	unsigned long flags;
 
 
 	pdev = (struct platform_device *)map->map_priv_1;
 	pdev = (struct platform_device *)map->map_priv_1;
-	physmap_data = pdev->dev.platform_data;
+	physmap_data = dev_get_platdata(&pdev->dev);
 
 
 	if (!physmap_data->set_vpp)
 	if (!physmap_data->set_vpp)
 		return;
 		return;
@@ -103,7 +102,7 @@ static int physmap_flash_probe(struct platform_device *dev)
 	int i;
 	int i;
 	int devices_found = 0;
 	int devices_found = 0;
 
 
-	physmap_data = dev->dev.platform_data;
+	physmap_data = dev_get_platdata(&dev->dev);
 	if (physmap_data == NULL)
 	if (physmap_data == NULL)
 		return -ENODEV;
 		return -ENODEV;
 
 

+ 2 - 4
drivers/mtd/maps/plat-ram.c

@@ -84,8 +84,6 @@ static int platram_remove(struct platform_device *pdev)
 {
 {
 	struct platram_info *info = to_platram_info(pdev);
 	struct platram_info *info = to_platram_info(pdev);
 
 
-	platform_set_drvdata(pdev, NULL);
-
 	dev_dbg(&pdev->dev, "removing device\n");
 	dev_dbg(&pdev->dev, "removing device\n");
 
 
 	if (info == NULL)
 	if (info == NULL)
@@ -130,13 +128,13 @@ static int platram_probe(struct platform_device *pdev)
 
 
 	dev_dbg(&pdev->dev, "probe entered\n");
 	dev_dbg(&pdev->dev, "probe entered\n");
 
 
-	if (pdev->dev.platform_data == NULL) {
+	if (dev_get_platdata(&pdev->dev) == NULL) {
 		dev_err(&pdev->dev, "no platform data supplied\n");
 		dev_err(&pdev->dev, "no platform data supplied\n");
 		err = -ENOENT;
 		err = -ENOENT;
 		goto exit_error;
 		goto exit_error;
 	}
 	}
 
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 
 
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (info == NULL) {
 	if (info == NULL) {

+ 1 - 3
drivers/mtd/maps/pxa2xx-flash.c

@@ -49,7 +49,7 @@ static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
 
 
 static int pxa2xx_flash_probe(struct platform_device *pdev)
 static int pxa2xx_flash_probe(struct platform_device *pdev)
 {
 {
-	struct flash_platform_data *flash = pdev->dev.platform_data;
+	struct flash_platform_data *flash = dev_get_platdata(&pdev->dev);
 	struct pxa2xx_flash_info *info;
 	struct pxa2xx_flash_info *info;
 	struct resource *res;
 	struct resource *res;
 
 
@@ -107,8 +107,6 @@ static int pxa2xx_flash_remove(struct platform_device *dev)
 {
 {
 	struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 	struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
 
-	platform_set_drvdata(dev, NULL);
-
 	mtd_device_unregister(info->mtd);
 	mtd_device_unregister(info->mtd);
 
 
 	map_destroy(info->mtd);
 	map_destroy(info->mtd);

+ 2 - 3
drivers/mtd/maps/rbtx4939-flash.c

@@ -34,10 +34,9 @@ static int rbtx4939_flash_remove(struct platform_device *dev)
 	info = platform_get_drvdata(dev);
 	info = platform_get_drvdata(dev);
 	if (!info)
 	if (!info)
 		return 0;
 		return 0;
-	platform_set_drvdata(dev, NULL);
 
 
 	if (info->mtd) {
 	if (info->mtd) {
-		struct rbtx4939_flash_data *pdata = dev->dev.platform_data;
+		struct rbtx4939_flash_data *pdata = dev_get_platdata(&dev->dev);
 
 
 		mtd_device_unregister(info->mtd);
 		mtd_device_unregister(info->mtd);
 		map_destroy(info->mtd);
 		map_destroy(info->mtd);
@@ -57,7 +56,7 @@ static int rbtx4939_flash_probe(struct platform_device *dev)
 	int err = 0;
 	int err = 0;
 	unsigned long size;
 	unsigned long size;
 
 
-	pdata = dev->dev.platform_data;
+	pdata = dev_get_platdata(&dev->dev);
 	if (!pdata)
 	if (!pdata)
 		return -ENODEV;
 		return -ENODEV;
 
 

+ 2 - 3
drivers/mtd/maps/sa1100-flash.c

@@ -248,7 +248,7 @@ static const char * const part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
 
 static int sa1100_mtd_probe(struct platform_device *pdev)
 static int sa1100_mtd_probe(struct platform_device *pdev)
 {
 {
-	struct flash_platform_data *plat = pdev->dev.platform_data;
+	struct flash_platform_data *plat = dev_get_platdata(&pdev->dev);
 	struct sa_info *info;
 	struct sa_info *info;
 	int err;
 	int err;
 
 
@@ -277,9 +277,8 @@ static int sa1100_mtd_probe(struct platform_device *pdev)
 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
 {
 {
 	struct sa_info *info = platform_get_drvdata(pdev);
 	struct sa_info *info = platform_get_drvdata(pdev);
-	struct flash_platform_data *plat = pdev->dev.platform_data;
+	struct flash_platform_data *plat = dev_get_platdata(&pdev->dev);
 
 
-	platform_set_drvdata(pdev, NULL);
 	sa1100_destroy(info, plat);
 	sa1100_destroy(info, plat);
 
 
 	return 0;
 	return 0;

+ 0 - 196
drivers/mtd/maps/vmax301.c

@@ -1,196 +0,0 @@
-/* ######################################################################
-
-   Tempustech VMAX SBC301 MTD Driver.
-
-   The VMAx 301 is a SBC based on . It
-   comes with three builtin AMD 29F016B flash chips and a socket for SRAM or
-   more flash. Each unit has it's own 8k mapping into a settable region
-   (0xD8000). There are two 8k mappings for each MTD, the first is always set
-   to the lower 8k of the device the second is paged. Writing a 16 bit page
-   value to anywhere in the first 8k will cause the second 8k to page around.
-
-   To boot the device a bios extension must be installed into the first 8k
-   of flash that is smart enough to copy itself down, page in the rest of
-   itself and begin executing.
-
-   ##################################################################### */
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-
-
-#define WINDOW_START 0xd8000
-#define WINDOW_LENGTH 0x2000
-#define WINDOW_SHIFT 25
-#define WINDOW_MASK 0x1FFF
-
-/* Actually we could use two spinlocks, but we'd have to have
-   more private space in the struct map_info. We lose a little
-   performance like this, but we'd probably lose more by having
-   the extra indirection from having one of the map->map_priv
-   fields pointing to yet another private struct.
-*/
-static DEFINE_SPINLOCK(vmax301_spin);
-
-static void __vmax301_page(struct map_info *map, unsigned long page)
-{
-	writew(page, map->map_priv_2 - WINDOW_LENGTH);
-	map->map_priv_1 = page;
-}
-
-static inline void vmax301_page(struct map_info *map,
-				  unsigned long ofs)
-{
-	unsigned long page = (ofs >> WINDOW_SHIFT);
-	if (map->map_priv_1 != page)
-		__vmax301_page(map, page);
-}
-
-static map_word vmax301_read8(struct map_info *map, unsigned long ofs)
-{
-	map_word ret;
-	spin_lock(&vmax301_spin);
-	vmax301_page(map, ofs);
-	ret.x[0] = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
-	spin_unlock(&vmax301_spin);
-	return ret;
-}
-
-static void vmax301_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	while(len) {
-		unsigned long thislen = len;
-		if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
-			thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-		spin_lock(&vmax301_spin);
-		vmax301_page(map, from);
-		memcpy_fromio(to, map->map_priv_2 + from, thislen);
-		spin_unlock(&vmax301_spin);
-		to += thislen;
-		from += thislen;
-		len -= thislen;
-	}
-}
-
-static void vmax301_write8(struct map_info *map, map_word d, unsigned long adr)
-{
-	spin_lock(&vmax301_spin);
-	vmax301_page(map, adr);
-	writeb(d.x[0], map->map_priv_2 + (adr & WINDOW_MASK));
-	spin_unlock(&vmax301_spin);
-}
-
-static void vmax301_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	while(len) {
-		unsigned long thislen = len;
-		if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
-			thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-
-		spin_lock(&vmax301_spin);
-		vmax301_page(map, to);
-		memcpy_toio(map->map_priv_2 + to, from, thislen);
-		spin_unlock(&vmax301_spin);
-		to += thislen;
-		from += thislen;
-		len -= thislen;
-	}
-}
-
-static struct map_info vmax_map[2] = {
-	{
-		.name = "VMAX301 Internal Flash",
-		.phys = NO_XIP,
-		.size = 3*2*1024*1024,
-		.bankwidth = 1,
-		.read = vmax301_read8,
-		.copy_from = vmax301_copy_from,
-		.write = vmax301_write8,
-		.copy_to = vmax301_copy_to,
-		.map_priv_1 = WINDOW_START + WINDOW_LENGTH,
-		.map_priv_2 = 0xFFFFFFFF
-	},
-	{
-		.name = "VMAX301 Socket",
-		.phys = NO_XIP,
-		.size = 0,
-		.bankwidth = 1,
-		.read = vmax301_read8,
-		.copy_from = vmax301_copy_from,
-		.write = vmax301_write8,
-		.copy_to = vmax301_copy_to,
-		.map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH),
-		.map_priv_2 = 0xFFFFFFFF
-	}
-};
-
-static struct mtd_info *vmax_mtd[2] = {NULL, NULL};
-
-static void __exit cleanup_vmax301(void)
-{
-	int i;
-
-	for (i=0; i<2; i++) {
-		if (vmax_mtd[i]) {
-			mtd_device_unregister(vmax_mtd[i]);
-			map_destroy(vmax_mtd[i]);
-		}
-	}
-	iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START);
-}
-
-static int __init init_vmax301(void)
-{
-	int i;
-	unsigned long iomapadr;
-	// Print out our little header..
-	printk("Tempustech VMAX 301 MEM:0x%x-0x%x\n",WINDOW_START,
-	       WINDOW_START+4*WINDOW_LENGTH);
-
-	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH*4);
-	if (!iomapadr) {
-		printk("Failed to ioremap memory region\n");
-		return -EIO;
-	}
-	/* Put the address in the map's private data area.
-	   We store the actual MTD IO address rather than the
-	   address of the first half, because it's used more
-	   often.
-	*/
-	vmax_map[0].map_priv_2 = iomapadr + WINDOW_START;
-	vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START);
-
-	for (i=0; i<2; i++) {
-		vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]);
-		if (!vmax_mtd[i])
-			vmax_mtd[i] = do_map_probe("jedec", &vmax_map[i]);
-		if (!vmax_mtd[i])
-			vmax_mtd[i] = do_map_probe("map_ram", &vmax_map[i]);
-		if (!vmax_mtd[i])
-			vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]);
-		if (vmax_mtd[i]) {
-			vmax_mtd[i]->owner = THIS_MODULE;
-			mtd_device_register(vmax_mtd[i], NULL, 0);
-		}
-	}
-
-	if (!vmax_mtd[0] && !vmax_mtd[1]) {
-		iounmap((void *)iomapadr);
-		return -ENXIO;
-	}
-
-	return 0;
-}
-
-module_init(init_vmax301);
-module_exit(cleanup_vmax301);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("MTD map driver for Tempustech VMAX SBC301 board");

+ 11 - 0
drivers/mtd/mtdcore.c

@@ -285,6 +285,16 @@ static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR,
 		   mtd_bitflip_threshold_show,
 		   mtd_bitflip_threshold_show,
 		   mtd_bitflip_threshold_store);
 		   mtd_bitflip_threshold_store);
 
 
+static ssize_t mtd_ecc_step_size_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct mtd_info *mtd = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_step_size);
+
+}
+static DEVICE_ATTR(ecc_step_size, S_IRUGO, mtd_ecc_step_size_show, NULL);
+
 static struct attribute *mtd_attrs[] = {
 static struct attribute *mtd_attrs[] = {
 	&dev_attr_type.attr,
 	&dev_attr_type.attr,
 	&dev_attr_flags.attr,
 	&dev_attr_flags.attr,
@@ -296,6 +306,7 @@ static struct attribute *mtd_attrs[] = {
 	&dev_attr_numeraseregions.attr,
 	&dev_attr_numeraseregions.attr,
 	&dev_attr_name.attr,
 	&dev_attr_name.attr,
 	&dev_attr_ecc_strength.attr,
 	&dev_attr_ecc_strength.attr,
+	&dev_attr_ecc_step_size.attr,
 	&dev_attr_bitflip_threshold.attr,
 	&dev_attr_bitflip_threshold.attr,
 	NULL,
 	NULL,
 };
 };

+ 1 - 0
drivers/mtd/mtdpart.c

@@ -516,6 +516,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 	}
 	}
 
 
 	slave->mtd.ecclayout = master->ecclayout;
 	slave->mtd.ecclayout = master->ecclayout;
+	slave->mtd.ecc_step_size = master->ecc_step_size;
 	slave->mtd.ecc_strength = master->ecc_strength;
 	slave->mtd.ecc_strength = master->ecc_strength;
 	slave->mtd.bitflip_threshold = master->bitflip_threshold;
 	slave->mtd.bitflip_threshold = master->bitflip_threshold;
 
 

+ 1 - 1
drivers/mtd/mtdswap.c

@@ -1425,7 +1425,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 		return;
 		return;
 
 
 	while ((this_opt = strsep(&parts, ",")) != NULL) {
 	while ((this_opt = strsep(&parts, ",")) != NULL) {
-		if (strict_strtoul(this_opt, 0, &part) < 0)
+		if (kstrtoul(this_opt, 0, &part) < 0)
 			return;
 			return;
 
 
 		if (mtd->index == part)
 		if (mtd->index == part)

+ 3 - 9
drivers/mtd/nand/Kconfig

@@ -43,6 +43,7 @@ config MTD_SM_COMMON
 
 
 config MTD_NAND_DENALI
 config MTD_NAND_DENALI
         tristate "Support Denali NAND controller"
         tristate "Support Denali NAND controller"
+        depends on HAS_DMA
         help
         help
 	  Enable support for the Denali NAND controller.  This should be
 	  Enable support for the Denali NAND controller.  This should be
 	  combined with either the PCI or platform drivers to provide device
 	  combined with either the PCI or platform drivers to provide device
@@ -75,7 +76,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
 
 
 config MTD_NAND_GPIO
 config MTD_NAND_GPIO
 	tristate "GPIO NAND Flash driver"
 	tristate "GPIO NAND Flash driver"
-	depends on GPIOLIB && ARM
+	depends on GPIOLIB
 	help
 	help
 	  This enables a GPIO based NAND flash driver.
 	  This enables a GPIO based NAND flash driver.
 
 
@@ -354,7 +355,7 @@ config MTD_NAND_ATMEL
 
 
 config MTD_NAND_PXA3xx
 config MTD_NAND_PXA3xx
 	tristate "Support for NAND flash devices on PXA3xx"
 	tristate "Support for NAND flash devices on PXA3xx"
-	depends on PXA3xx || ARCH_MMP
+	depends on PXA3xx || ARCH_MMP || PLAT_ORION
 	help
 	help
 	  This enables the driver for the NAND flash device found on
 	  This enables the driver for the NAND flash device found on
 	  PXA3xx processors
 	  PXA3xx processors
@@ -432,13 +433,6 @@ config MTD_NAND_PLATFORM
 	  devices. You will need to provide platform-specific functions
 	  devices. You will need to provide platform-specific functions
 	  via platform_data.
 	  via platform_data.
 
 
-config MTD_ALAUDA
-	tristate "MTD driver for Olympus MAUSB-10 and Fujifilm DPC-R1"
-	depends on USB
-	help
-	  These two (and possibly other) Alauda-based cardreaders for
-	  SmartMedia and xD allow raw flash access.
-
 config MTD_NAND_ORION
 config MTD_NAND_ORION
 	tristate "NAND Flash support for Marvell Orion SoC"
 	tristate "NAND Flash support for Marvell Orion SoC"
 	depends on PLAT_ORION
 	depends on PLAT_ORION

+ 0 - 1
drivers/mtd/nand/Makefile

@@ -31,7 +31,6 @@ obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
 obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
 obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
 obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
-obj-$(CONFIG_MTD_ALAUDA)		+= alauda.o
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o

+ 0 - 723
drivers/mtd/nand/alauda.c

@@ -1,723 +0,0 @@
-/*
- * MTD driver for Alauda chips
- *
- * Copyright (C) 2007 Joern Engel <joern@logfs.org>
- *
- * Based on drivers/usb/usb-skeleton.c which is:
- * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
- * and on drivers/usb/storage/alauda.c, which is:
- *   (c) 2005 Daniel Drake <dsd@gentoo.org>
- *
- * Idea and initial work by Arnd Bergmann <arnd@arndb.de>
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kref.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand_ecc.h>
-
-/* Control commands */
-#define ALAUDA_GET_XD_MEDIA_STATUS	0x08
-#define ALAUDA_ACK_XD_MEDIA_CHANGE	0x0a
-#define ALAUDA_GET_XD_MEDIA_SIG		0x86
-
-/* Common prefix */
-#define ALAUDA_BULK_CMD			0x40
-
-/* The two ports */
-#define ALAUDA_PORT_XD			0x00
-#define ALAUDA_PORT_SM			0x01
-
-/* Bulk commands */
-#define ALAUDA_BULK_READ_PAGE		0x84
-#define ALAUDA_BULK_READ_OOB		0x85 /* don't use, there's a chip bug */
-#define ALAUDA_BULK_READ_BLOCK		0x94
-#define ALAUDA_BULK_ERASE_BLOCK		0xa3
-#define ALAUDA_BULK_WRITE_PAGE		0xa4
-#define ALAUDA_BULK_WRITE_BLOCK		0xb4
-#define ALAUDA_BULK_RESET_MEDIA		0xe0
-
-/* Address shifting */
-#define PBA_LO(pba) ((pba & 0xF) << 5)
-#define PBA_HI(pba) (pba >> 3)
-#define PBA_ZONE(pba) (pba >> 11)
-
-#define TIMEOUT HZ
-
-static const struct usb_device_id alauda_table[] = {
-	{ USB_DEVICE(0x0584, 0x0008) },	/* Fujifilm DPC-R1 */
-	{ USB_DEVICE(0x07b4, 0x010a) },	/* Olympus MAUSB-10 */
-	{ }
-};
-MODULE_DEVICE_TABLE(usb, alauda_table);
-
-struct alauda_card {
-	u8	id;		/* id byte */
-	u8	chipshift;	/* 1<<chipshift total size */
-	u8	pageshift;	/* 1<<pageshift page size */
-	u8	blockshift;	/* 1<<blockshift block size */
-};
-
-struct alauda {
-	struct usb_device	*dev;
-	struct usb_interface	*interface;
-	struct mtd_info		*mtd;
-	struct alauda_card	*card;
-	struct mutex		card_mutex;
-	u32			pagemask;
-	u32			bytemask;
-	u32			blockmask;
-	unsigned int		write_out;
-	unsigned int		bulk_in;
-	unsigned int		bulk_out;
-	u8			port;
-	struct kref		kref;
-};
-
-static struct alauda_card alauda_card_ids[] = {
-	/* NAND flash */
-	{ 0x6e, 20, 8, 12},	/* 1 MB */
-	{ 0xe8, 20, 8, 12},	/* 1 MB */
-	{ 0xec, 20, 8, 12},	/* 1 MB */
-	{ 0x64, 21, 8, 12},	/* 2 MB */
-	{ 0xea, 21, 8, 12},	/* 2 MB */
-	{ 0x6b, 22, 9, 13},	/* 4 MB */
-	{ 0xe3, 22, 9, 13},	/* 4 MB */
-	{ 0xe5, 22, 9, 13},	/* 4 MB */
-	{ 0xe6, 23, 9, 13},	/* 8 MB */
-	{ 0x73, 24, 9, 14},	/* 16 MB */
-	{ 0x75, 25, 9, 14},	/* 32 MB */
-	{ 0x76, 26, 9, 14},	/* 64 MB */
-	{ 0x79, 27, 9, 14},	/* 128 MB */
-	{ 0x71, 28, 9, 14},	/* 256 MB */
-
-	/* MASK ROM */
-	{ 0x5d, 21, 9, 13},	/* 2 MB */
-	{ 0xd5, 22, 9, 13},	/* 4 MB */
-	{ 0xd6, 23, 9, 13},	/* 8 MB */
-	{ 0x57, 24, 9, 13},	/* 16 MB */
-	{ 0x58, 25, 9, 13},	/* 32 MB */
-	{ }
-};
-
-static struct alauda_card *get_card(u8 id)
-{
-	struct alauda_card *card;
-
-	for (card = alauda_card_ids; card->id; card++)
-		if (card->id == id)
-			return card;
-	return NULL;
-}
-
-static void alauda_delete(struct kref *kref)
-{
-	struct alauda *al = container_of(kref, struct alauda, kref);
-
-	if (al->mtd) {
-		mtd_device_unregister(al->mtd);
-		kfree(al->mtd);
-	}
-	usb_put_dev(al->dev);
-	kfree(al);
-}
-
-static int alauda_get_media_status(struct alauda *al, void *buf)
-{
-	int ret;
-
-	mutex_lock(&al->card_mutex);
-	ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
-			ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ);
-	mutex_unlock(&al->card_mutex);
-	return ret;
-}
-
-static int alauda_ack_media(struct alauda *al)
-{
-	int ret;
-
-	mutex_lock(&al->card_mutex);
-	ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0),
-			ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ);
-	mutex_unlock(&al->card_mutex);
-	return ret;
-}
-
-static int alauda_get_media_signatures(struct alauda *al, void *buf)
-{
-	int ret;
-
-	mutex_lock(&al->card_mutex);
-	ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
-			ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ);
-	mutex_unlock(&al->card_mutex);
-	return ret;
-}
-
-static void alauda_reset(struct alauda *al)
-{
-	u8 command[] = {
-		ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0,
-		0, 0, 0, 0, al->port
-	};
-	mutex_lock(&al->card_mutex);
-	usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ);
-	mutex_unlock(&al->card_mutex);
-}
-
-static void correct_data(void *buf, void *read_ecc,
-		int *corrected, int *uncorrected)
-{
-	u8 calc_ecc[3];
-	int err;
-
-	nand_calculate_ecc(NULL, buf, calc_ecc);
-	err = nand_correct_data(NULL, buf, read_ecc, calc_ecc);
-	if (err) {
-		if (err > 0)
-			(*corrected)++;
-		else
-			(*uncorrected)++;
-	}
-}
-
-struct alauda_sg_request {
-	struct urb *urb[3];
-	struct completion comp;
-};
-
-static void alauda_complete(struct urb *urb)
-{
-	struct completion *comp = urb->context;
-
-	if (comp)
-		complete(comp);
-}
-
-static int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf,
-		void *oob)
-{
-	struct alauda_sg_request sg;
-	struct alauda *al = mtd->priv;
-	u32 pba = from >> al->card->blockshift;
-	u32 page = (from >> al->card->pageshift) & al->pagemask;
-	u8 command[] = {
-		ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba),
-		PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port
-	};
-	int i, err;
-
-	for (i=0; i<3; i++)
-		sg.urb[i] = NULL;
-
-	err = -ENOMEM;
-	for (i=0; i<3; i++) {
-		sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
-		if (!sg.urb[i])
-			goto out;
-	}
-	init_completion(&sg.comp);
-	usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
-			alauda_complete, NULL);
-	usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize,
-			alauda_complete, NULL);
-	usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16,
-			alauda_complete, &sg.comp);
-
-	mutex_lock(&al->card_mutex);
-	for (i=0; i<3; i++) {
-		err = usb_submit_urb(sg.urb[i], GFP_NOIO);
-		if (err)
-			goto cancel;
-	}
-	if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
-		err = -ETIMEDOUT;
-cancel:
-		for (i=0; i<3; i++) {
-			usb_kill_urb(sg.urb[i]);
-		}
-	}
-	mutex_unlock(&al->card_mutex);
-
-out:
-	usb_free_urb(sg.urb[0]);
-	usb_free_urb(sg.urb[1]);
-	usb_free_urb(sg.urb[2]);
-	return err;
-}
-
-static int alauda_read_page(struct mtd_info *mtd, loff_t from,
-		void *buf, u8 *oob, int *corrected, int *uncorrected)
-{
-	int err;
-
-	err = __alauda_read_page(mtd, from, buf, oob);
-	if (err)
-		return err;
-	correct_data(buf, oob+13, corrected, uncorrected);
-	correct_data(buf+256, oob+8, corrected, uncorrected);
-	return 0;
-}
-
-static int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf,
-		void *oob)
-{
-	struct alauda_sg_request sg;
-	struct alauda *al = mtd->priv;
-	u32 pba = to >> al->card->blockshift;
-	u32 page = (to >> al->card->pageshift) & al->pagemask;
-	u8 command[] = {
-		ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba),
-		PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port
-	};
-	int i, err;
-
-	for (i=0; i<3; i++)
-		sg.urb[i] = NULL;
-
-	err = -ENOMEM;
-	for (i=0; i<3; i++) {
-		sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
-		if (!sg.urb[i])
-			goto out;
-	}
-	init_completion(&sg.comp);
-	usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
-			alauda_complete, NULL);
-	usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize,
-			alauda_complete, NULL);
-	usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16,
-			alauda_complete, &sg.comp);
-
-	mutex_lock(&al->card_mutex);
-	for (i=0; i<3; i++) {
-		err = usb_submit_urb(sg.urb[i], GFP_NOIO);
-		if (err)
-			goto cancel;
-	}
-	if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
-		err = -ETIMEDOUT;
-cancel:
-		for (i=0; i<3; i++) {
-			usb_kill_urb(sg.urb[i]);
-		}
-	}
-	mutex_unlock(&al->card_mutex);
-
-out:
-	usb_free_urb(sg.urb[0]);
-	usb_free_urb(sg.urb[1]);
-	usb_free_urb(sg.urb[2]);
-	return err;
-}
-
-static int alauda_erase_block(struct mtd_info *mtd, loff_t ofs)
-{
-	struct alauda_sg_request sg;
-	struct alauda *al = mtd->priv;
-	u32 pba = ofs >> al->card->blockshift;
-	u8 command[] = {
-		ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
-		PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port
-	};
-	u8 buf[2];
-	int i, err;
-
-	for (i=0; i<2; i++)
-		sg.urb[i] = NULL;
-
-	err = -ENOMEM;
-	for (i=0; i<2; i++) {
-		sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
-		if (!sg.urb[i])
-			goto out;
-	}
-	init_completion(&sg.comp);
-	usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
-			alauda_complete, NULL);
-	usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2,
-			alauda_complete, &sg.comp);
-
-	mutex_lock(&al->card_mutex);
-	for (i=0; i<2; i++) {
-		err = usb_submit_urb(sg.urb[i], GFP_NOIO);
-		if (err)
-			goto cancel;
-	}
-	if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
-		err = -ETIMEDOUT;
-cancel:
-		for (i=0; i<2; i++) {
-			usb_kill_urb(sg.urb[i]);
-		}
-	}
-	mutex_unlock(&al->card_mutex);
-
-out:
-	usb_free_urb(sg.urb[0]);
-	usb_free_urb(sg.urb[1]);
-	return err;
-}
-
-static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob)
-{
-	static u8 ignore_buf[512]; /* write only */
-
-	return __alauda_read_page(mtd, from, ignore_buf, oob);
-}
-
-static int alauda_isbad(struct mtd_info *mtd, loff_t ofs)
-{
-	u8 oob[16];
-	int err;
-
-	err = alauda_read_oob(mtd, ofs, oob);
-	if (err)
-		return err;
-
-	/* A block is marked bad if two or more bits are zero */
-	return hweight8(oob[5]) >= 7 ? 0 : 1;
-}
-
-static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
-		size_t *retlen, u_char *buf)
-{
-	struct alauda *al = mtd->priv;
-	void *bounce_buf;
-	int err, corrected=0, uncorrected=0;
-
-	bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);
-	if (!bounce_buf)
-		return -ENOMEM;
-
-	*retlen = len;
-	while (len) {
-		u8 oob[16];
-		size_t byte = from & al->bytemask;
-		size_t cplen = min(len, mtd->writesize - byte);
-
-		err = alauda_read_page(mtd, from, bounce_buf, oob,
-				&corrected, &uncorrected);
-		if (err)
-			goto out;
-
-		memcpy(buf, bounce_buf + byte, cplen);
-		buf += cplen;
-		from += cplen;
-		len -= cplen;
-	}
-	err = 0;
-	if (corrected)
-		err = 1;	/* return max_bitflips per ecc step */
-	if (uncorrected)
-		err = -EBADMSG;
-out:
-	kfree(bounce_buf);
-	return err;
-}
-
-static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
-		size_t *retlen, u_char *buf)
-{
-	struct alauda *al = mtd->priv;
-	int err, corrected=0, uncorrected=0;
-
-	if ((from & al->bytemask) || (len & al->bytemask))
-		return alauda_bounce_read(mtd, from, len, retlen, buf);
-
-	*retlen = len;
-	while (len) {
-		u8 oob[16];
-
-		err = alauda_read_page(mtd, from, buf, oob,
-				&corrected, &uncorrected);
-		if (err)
-			return err;
-
-		buf += mtd->writesize;
-		from += mtd->writesize;
-		len -= mtd->writesize;
-	}
-	err = 0;
-	if (corrected)
-		err = 1;	/* return max_bitflips per ecc step */
-	if (uncorrected)
-		err = -EBADMSG;
-	return err;
-}
-
-static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len,
-		size_t *retlen, const u_char *buf)
-{
-	struct alauda *al = mtd->priv;
-	int err;
-
-	if ((to & al->bytemask) || (len & al->bytemask))
-		return -EINVAL;
-
-	*retlen = len;
-	while (len) {
-		u32 page = (to >> al->card->pageshift) & al->pagemask;
-		u8 oob[16] = {	'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff,
-				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-		/* don't write to bad blocks */
-		if (page == 0) {
-			err = alauda_isbad(mtd, to);
-			if (err) {
-				return -EIO;
-			}
-		}
-		nand_calculate_ecc(mtd, buf, &oob[13]);
-		nand_calculate_ecc(mtd, buf+256, &oob[8]);
-
-		err = alauda_write_page(mtd, to, (void*)buf, oob);
-		if (err)
-			return err;
-
-		buf += mtd->writesize;
-		to += mtd->writesize;
-		len -= mtd->writesize;
-	}
-	return 0;
-}
-
-static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-	struct alauda *al = mtd->priv;
-	u32 ofs = instr->addr;
-	u32 len = instr->len;
-	int err;
-
-	if ((ofs & al->blockmask) || (len & al->blockmask))
-		return -EINVAL;
-
-	while (len) {
-		/* don't erase bad blocks */
-		err = alauda_isbad(mtd, ofs);
-		if (err > 0)
-			err = -EIO;
-		if (err < 0)
-			return err;
-
-		err = alauda_erase_block(mtd, ofs);
-		if (err < 0)
-			return err;
-
-		ofs += mtd->erasesize;
-		len -= mtd->erasesize;
-	}
-	return 0;
-}
-
-static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-	int err;
-
-	err = __alauda_erase(mtd, instr);
-	instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
-	mtd_erase_callback(instr);
-	return err;
-}
-
-static int alauda_init_media(struct alauda *al)
-{
-	u8 buf[4], *b0=buf, *b1=buf+1;
-	struct alauda_card *card;
-	struct mtd_info *mtd;
-	int err;
-
-	mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-	if (!mtd)
-		return -ENOMEM;
-
-	for (;;) {
-		err = alauda_get_media_status(al, buf);
-		if (err < 0)
-			goto error;
-		if (*b0 & 0x10)
-			break;
-		msleep(20);
-	}
-
-	err = alauda_ack_media(al);
-	if (err)
-		goto error;
-
-	msleep(10);
-
-	err = alauda_get_media_status(al, buf);
-	if (err < 0)
-		goto error;
-
-	if (*b0 != 0x14) {
-		/* media not ready */
-		err = -EIO;
-		goto error;
-	}
-	err = alauda_get_media_signatures(al, buf);
-	if (err < 0)
-		goto error;
-
-	card = get_card(*b1);
-	if (!card) {
-		printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1);
-		err = -EIO;
-		goto error;
-	}
-	printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n",
-			1<<card->pageshift, 1<<card->blockshift,
-			1<<(card->chipshift-20));
-	al->card = card;
-	al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1;
-	al->bytemask = (1 << card->pageshift) - 1;
-	al->blockmask = (1 << card->blockshift) - 1;
-
-	mtd->name = "alauda";
-	mtd->size = 1<<card->chipshift;
-	mtd->erasesize = 1<<card->blockshift;
-	mtd->writesize = 1<<card->pageshift;
-	mtd->type = MTD_NANDFLASH;
-	mtd->flags = MTD_CAP_NANDFLASH;
-	mtd->_read = alauda_read;
-	mtd->_write = alauda_write;
-	mtd->_erase = alauda_erase;
-	mtd->_block_isbad = alauda_isbad;
-	mtd->priv = al;
-	mtd->owner = THIS_MODULE;
-	mtd->ecc_strength = 1;
-
-	err = mtd_device_register(mtd, NULL, 0);
-	if (err) {
-		err = -ENFILE;
-		goto error;
-	}
-
-	al->mtd = mtd;
-	alauda_reset(al); /* no clue whether this is necessary */
-	return 0;
-error:
-	kfree(mtd);
-	return err;
-}
-
-static int alauda_check_media(struct alauda *al)
-{
-	u8 buf[2], *b0 = buf, *b1 = buf+1;
-	int err;
-
-	err = alauda_get_media_status(al, buf);
-	if (err < 0)
-		return err;
-
-	if ((*b1 & 0x01) == 0) {
-		/* door open */
-		return -EIO;
-	}
-	if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) {
-		/* no media ? */
-		return -EIO;
-	}
-	if (*b0 & 0x08) {
-		/* media change ? */
-		return alauda_init_media(al);
-	}
-	return 0;
-}
-
-static int alauda_probe(struct usb_interface *interface,
-		const struct usb_device_id *id)
-{
-	struct alauda *al;
-	struct usb_host_interface *iface;
-	struct usb_endpoint_descriptor *ep,
-			*ep_in=NULL, *ep_out=NULL, *ep_wr=NULL;
-	int i, err = -ENOMEM;
-
-	al = kzalloc(2*sizeof(*al), GFP_KERNEL);
-	if (!al)
-		goto error;
-
-	kref_init(&al->kref);
-	usb_set_intfdata(interface, al);
-
-	al->dev = usb_get_dev(interface_to_usbdev(interface));
-	al->interface = interface;
-
-	iface = interface->cur_altsetting;
-	for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
-		ep = &iface->endpoint[i].desc;
-
-		if (usb_endpoint_is_bulk_in(ep)) {
-			ep_in = ep;
-		} else if (usb_endpoint_is_bulk_out(ep)) {
-			if (i==0)
-				ep_wr = ep;
-			else
-				ep_out = ep;
-		}
-	}
-	err = -EIO;
-	if (!ep_wr || !ep_in || !ep_out)
-		goto error;
-
-	al->write_out = usb_sndbulkpipe(al->dev,
-			usb_endpoint_num(ep_wr));
-	al->bulk_in = usb_rcvbulkpipe(al->dev,
-			usb_endpoint_num(ep_in));
-	al->bulk_out = usb_sndbulkpipe(al->dev,
-			usb_endpoint_num(ep_out));
-
-	/* second device is identical up to now */
-	memcpy(al+1, al, sizeof(*al));
-
-	mutex_init(&al[0].card_mutex);
-	mutex_init(&al[1].card_mutex);
-
-	al[0].port = ALAUDA_PORT_XD;
-	al[1].port = ALAUDA_PORT_SM;
-
-	dev_info(&interface->dev, "alauda probed\n");
-	alauda_check_media(al);
-	alauda_check_media(al+1);
-
-	return 0;
-
-error:
-	if (al)
-		kref_put(&al->kref, alauda_delete);
-	return err;
-}
-
-static void alauda_disconnect(struct usb_interface *interface)
-{
-	struct alauda *al;
-
-	al = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
-
-	/* FIXME: prevent more I/O from starting */
-
-	/* decrement our usage count */
-	if (al)
-		kref_put(&al->kref, alauda_delete);
-
-	dev_info(&interface->dev, "alauda gone");
-}
-
-static struct usb_driver alauda_driver = {
-	.name =		"alauda",
-	.probe =	alauda_probe,
-	.disconnect =	alauda_disconnect,
-	.id_table =	alauda_table,
-};
-
-module_usb_driver(alauda_driver);
-
-MODULE_LICENSE("GPL");

+ 0 - 1
drivers/mtd/nand/ams-delta.c

@@ -258,7 +258,6 @@ static int ams_delta_init(struct platform_device *pdev)
  out_mtd:
  out_mtd:
 	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
 	gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
 out_gpio:
 out_gpio:
-	platform_set_drvdata(pdev, NULL);
 	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
 	gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
 	iounmap(io_base);
 	iounmap(io_base);
 out_free:
 out_free:

+ 732 - 191
drivers/mtd/nand/atmel_nand.c

@@ -18,6 +18,9 @@
  *  Add Programmable Multibit ECC support for various AT91 SoC
  *  Add Programmable Multibit ECC support for various AT91 SoC
  *     © Copyright 2012 ATMEL, Hong Xu
  *     © Copyright 2012 ATMEL, Hong Xu
  *
  *
+ *  Add Nand Flash Controller support for SAMA5 SoC
+ *     © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
+ *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  * published by the Free Software Foundation.
@@ -37,13 +40,12 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
 
 
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/dmaengine.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/platform_data/atmel.h>
 #include <linux/platform_data/atmel.h>
-#include <linux/pinctrl/consumer.h>
-
-#include <mach/cpu.h>
 
 
 static int use_dma = 1;
 static int use_dma = 1;
 module_param(use_dma, int, 0);
 module_param(use_dma, int, 0);
@@ -58,6 +60,7 @@ module_param(on_flash_bbt, int, 0);
 	__raw_writel((value), add + ATMEL_ECC_##reg)
 	__raw_writel((value), add + ATMEL_ECC_##reg)
 
 
 #include "atmel_nand_ecc.h"	/* Hardware ECC registers */
 #include "atmel_nand_ecc.h"	/* Hardware ECC registers */
+#include "atmel_nand_nfc.h"	/* Nand Flash Controller definition */
 
 
 /* oob layout for large page size
 /* oob layout for large page size
  * bad block info is on bytes 0 and 1
  * bad block info is on bytes 0 and 1
@@ -85,6 +88,23 @@ static struct nand_ecclayout atmel_oobinfo_small = {
 	},
 	},
 };
 };
 
 
+struct atmel_nfc {
+	void __iomem		*base_cmd_regs;
+	void __iomem		*hsmc_regs;
+	void __iomem		*sram_bank0;
+	dma_addr_t		sram_bank0_phys;
+	bool			use_nfc_sram;
+	bool			write_by_sram;
+
+	bool			is_initialized;
+	struct completion	comp_nfc;
+
+	/* Point to the sram bank which include readed data via NFC */
+	void __iomem		*data_in_sram;
+	bool			will_write_sram;
+};
+static struct atmel_nfc	nand_nfc;
+
 struct atmel_nand_host {
 struct atmel_nand_host {
 	struct nand_chip	nand_chip;
 	struct nand_chip	nand_chip;
 	struct mtd_info		mtd;
 	struct mtd_info		mtd;
@@ -97,6 +117,8 @@ struct atmel_nand_host {
 	struct completion	comp;
 	struct completion	comp;
 	struct dma_chan		*dma_chan;
 	struct dma_chan		*dma_chan;
 
 
+	struct atmel_nfc	*nfc;
+
 	bool			has_pmecc;
 	bool			has_pmecc;
 	u8			pmecc_corr_cap;
 	u8			pmecc_corr_cap;
 	u16			pmecc_sector_size;
 	u16			pmecc_sector_size;
@@ -128,11 +150,6 @@ struct atmel_nand_host {
 
 
 static struct nand_ecclayout atmel_pmecc_oobinfo;
 static struct nand_ecclayout atmel_pmecc_oobinfo;
 
 
-static int cpu_has_dma(void)
-{
-	return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
-}
-
 /*
 /*
  * Enable NAND.
  * Enable NAND.
  */
  */
@@ -186,21 +203,103 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
                 !!host->board.rdy_pin_active_low;
                 !!host->board.rdy_pin_active_low;
 }
 }
 
 
+/* Set up for hardware ready pin and enable pin. */
+static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	int res = 0;
+
+	if (gpio_is_valid(host->board.rdy_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.rdy_pin, "nand_rdy");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		res = gpio_direction_input(host->board.rdy_pin);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request input direction rdy gpio %d\n",
+				host->board.rdy_pin);
+			return res;
+		}
+
+		chip->dev_ready = atmel_nand_device_ready;
+	}
+
+	if (gpio_is_valid(host->board.enable_pin)) {
+		res = devm_gpio_request(host->dev,
+				host->board.enable_pin, "nand_enable");
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+
+		res = gpio_direction_output(host->board.enable_pin, 1);
+		if (res < 0) {
+			dev_err(host->dev,
+				"can't request output direction enable gpio %d\n",
+				host->board.enable_pin);
+			return res;
+		}
+	}
+
+	return res;
+}
+
+static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
+{
+	int i;
+	u32 *t = trg;
+	const __iomem u32 *s = src;
+
+	for (i = 0; i < (size >> 2); i++)
+		*t++ = readl_relaxed(s++);
+}
+
+static void memcpy32_toio(void __iomem *trg, const void *src, int size)
+{
+	int i;
+	u32 __iomem *t = trg;
+	const u32 *s = src;
+
+	for (i = 0; i < (size >> 2); i++)
+		writel_relaxed(*s++, t++);
+}
+
 /*
 /*
  * Minimal-overhead PIO for data access.
  * Minimal-overhead PIO for data access.
  */
  */
 static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
 static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
 {
 {
 	struct nand_chip	*nand_chip = mtd->priv;
 	struct nand_chip	*nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
 
 
-	__raw_readsb(nand_chip->IO_ADDR_R, buf, len);
+	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
+		memcpy32_fromio(buf, host->nfc->data_in_sram, len);
+		host->nfc->data_in_sram += len;
+	} else {
+		__raw_readsb(nand_chip->IO_ADDR_R, buf, len);
+	}
 }
 }
 
 
 static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
 static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
 {
 {
 	struct nand_chip	*nand_chip = mtd->priv;
 	struct nand_chip	*nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
 
 
-	__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
+	if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
+		memcpy32_fromio(buf, host->nfc->data_in_sram, len);
+		host->nfc->data_in_sram += len;
+	} else {
+		__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
+	}
 }
 }
 
 
 static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
 static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
@@ -222,6 +321,40 @@ static void dma_complete_func(void *completion)
 	complete(completion);
 	complete(completion);
 }
 }
 
 
+static int nfc_set_sram_bank(struct atmel_nand_host *host, unsigned int bank)
+{
+	/* NFC only has two banks. Must be 0 or 1 */
+	if (bank > 1)
+		return -EINVAL;
+
+	if (bank) {
+		/* Only for a 2k-page or lower flash, NFC can handle 2 banks */
+		if (host->mtd.writesize > 2048)
+			return -EINVAL;
+		nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK1);
+	} else {
+		nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK0);
+	}
+
+	return 0;
+}
+
+static uint nfc_get_sram_off(struct atmel_nand_host *host)
+{
+	if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
+		return NFC_SRAM_BANK1_OFFSET;
+	else
+		return 0;
+}
+
+static dma_addr_t nfc_sram_phys(struct atmel_nand_host *host)
+{
+	if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
+		return host->nfc->sram_bank0_phys + NFC_SRAM_BANK1_OFFSET;
+	else
+		return host->nfc->sram_bank0_phys;
+}
+
 static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 			       int is_read)
 			       int is_read)
 {
 {
@@ -235,6 +368,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	void *p = buf;
 	void *p = buf;
 	int err = -EIO;
 	int err = -EIO;
 	enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
 	enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	struct atmel_nfc *nfc = host->nfc;
 
 
 	if (buf >= high_memory)
 	if (buf >= high_memory)
 		goto err_buf;
 		goto err_buf;
@@ -251,11 +385,20 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	}
 	}
 
 
 	if (is_read) {
 	if (is_read) {
-		dma_src_addr = host->io_phys;
+		if (nfc && nfc->data_in_sram)
+			dma_src_addr = nfc_sram_phys(host) + (nfc->data_in_sram
+				- (nfc->sram_bank0 + nfc_get_sram_off(host)));
+		else
+			dma_src_addr = host->io_phys;
+
 		dma_dst_addr = phys_addr;
 		dma_dst_addr = phys_addr;
 	} else {
 	} else {
 		dma_src_addr = phys_addr;
 		dma_src_addr = phys_addr;
-		dma_dst_addr = host->io_phys;
+
+		if (nfc && nfc->write_by_sram)
+			dma_dst_addr = nfc_sram_phys(host);
+		else
+			dma_dst_addr = host->io_phys;
 	}
 	}
 
 
 	tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,
 	tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,
@@ -278,6 +421,10 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
 	dma_async_issue_pending(host->dma_chan);
 	dma_async_issue_pending(host->dma_chan);
 	wait_for_completion(&host->comp);
 	wait_for_completion(&host->comp);
 
 
+	if (is_read && nfc && nfc->data_in_sram)
+		/* After read data from SRAM, need to increase the position */
+		nfc->data_in_sram += len;
+
 	err = 0;
 	err = 0;
 
 
 err_dma:
 err_dma:
@@ -366,43 +513,34 @@ static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
 			table_size * sizeof(int16_t);
 			table_size * sizeof(int16_t);
 }
 }
 
 
-static void pmecc_data_free(struct atmel_nand_host *host)
-{
-	kfree(host->pmecc_partial_syn);
-	kfree(host->pmecc_si);
-	kfree(host->pmecc_lmu);
-	kfree(host->pmecc_smu);
-	kfree(host->pmecc_mu);
-	kfree(host->pmecc_dmu);
-	kfree(host->pmecc_delta);
-}
-
 static int pmecc_data_alloc(struct atmel_nand_host *host)
 static int pmecc_data_alloc(struct atmel_nand_host *host)
 {
 {
 	const int cap = host->pmecc_corr_cap;
 	const int cap = host->pmecc_corr_cap;
+	int size;
+
+	size = (2 * cap + 1) * sizeof(int16_t);
+	host->pmecc_partial_syn = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_si = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_lmu = devm_kzalloc(host->dev,
+			(cap + 1) * sizeof(int16_t), GFP_KERNEL);
+	host->pmecc_smu = devm_kzalloc(host->dev,
+			(cap + 2) * size, GFP_KERNEL);
+
+	size = (cap + 1) * sizeof(int);
+	host->pmecc_mu = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_dmu = devm_kzalloc(host->dev, size, GFP_KERNEL);
+	host->pmecc_delta = devm_kzalloc(host->dev, size, GFP_KERNEL);
+
+	if (!host->pmecc_partial_syn ||
+		!host->pmecc_si ||
+		!host->pmecc_lmu ||
+		!host->pmecc_smu ||
+		!host->pmecc_mu ||
+		!host->pmecc_dmu ||
+		!host->pmecc_delta)
+		return -ENOMEM;
 
 
-	host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
-					GFP_KERNEL);
-	host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
-	host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
-	host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
-					GFP_KERNEL);
-	host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-	host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-	host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-
-	if (host->pmecc_partial_syn &&
-			host->pmecc_si &&
-			host->pmecc_lmu &&
-			host->pmecc_smu &&
-			host->pmecc_mu &&
-			host->pmecc_dmu &&
-			host->pmecc_delta)
-		return 0;
-
-	/* error happened */
-	pmecc_data_free(host);
-	return -ENOMEM;
+	return 0;
 }
 }
 
 
 static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
 static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
@@ -763,6 +901,30 @@ normal_check:
 	return total_err;
 	return total_err;
 }
 }
 
 
+static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
+{
+	u32 val;
+
+	if (ecc_op != NAND_ECC_READ && ecc_op != NAND_ECC_WRITE) {
+		dev_err(host->dev, "atmel_nand: wrong pmecc operation type!");
+		return;
+	}
+
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+	val = pmecc_readl_relaxed(host->ecc, CFG);
+
+	if (ecc_op == NAND_ECC_READ)
+		pmecc_writel(host->ecc, CFG, (val & ~PMECC_CFG_WRITE_OP)
+			| PMECC_CFG_AUTO_ENABLE);
+	else
+		pmecc_writel(host->ecc, CFG, (val | PMECC_CFG_WRITE_OP)
+			& ~PMECC_CFG_AUTO_ENABLE);
+
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+}
+
 static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
 	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
 {
 {
@@ -774,13 +936,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
 	unsigned long end_time;
 	unsigned long end_time;
 	int bitflips = 0;
 	int bitflips = 0;
 
 
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-	pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
-		& ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
-
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+	if (!host->nfc || !host->nfc->use_nfc_sram)
+		pmecc_enable(host, NAND_ECC_READ);
 
 
 	chip->read_buf(mtd, buf, eccsize);
 	chip->read_buf(mtd, buf, eccsize);
 	chip->read_buf(mtd, oob, mtd->oobsize);
 	chip->read_buf(mtd, oob, mtd->oobsize);
@@ -813,16 +970,10 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
 	int i, j;
 	int i, j;
 	unsigned long end_time;
 	unsigned long end_time;
 
 
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-
-	pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
-		PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
-
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-	pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
-
-	chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+	if (!host->nfc || !host->nfc->write_by_sram) {
+		pmecc_enable(host, NAND_ECC_WRITE);
+		chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+	}
 
 
 	end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
 	end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
 	while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
 	while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
@@ -967,11 +1118,11 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
 			host->pmecc_corr_cap = 2;
 			host->pmecc_corr_cap = 2;
 		else if (*cap <= 4)
 		else if (*cap <= 4)
 			host->pmecc_corr_cap = 4;
 			host->pmecc_corr_cap = 4;
-		else if (*cap < 8)
+		else if (*cap <= 8)
 			host->pmecc_corr_cap = 8;
 			host->pmecc_corr_cap = 8;
-		else if (*cap < 12)
+		else if (*cap <= 12)
 			host->pmecc_corr_cap = 12;
 			host->pmecc_corr_cap = 12;
-		else if (*cap < 24)
+		else if (*cap <= 24)
 			host->pmecc_corr_cap = 24;
 			host->pmecc_corr_cap = 24;
 		else
 		else
 			return -EINVAL;
 			return -EINVAL;
@@ -1002,7 +1153,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return err_no;
 		return err_no;
 	}
 	}
 
 
-	if (cap != host->pmecc_corr_cap ||
+	if (cap > host->pmecc_corr_cap ||
 			sector_size != host->pmecc_sector_size)
 			sector_size != host->pmecc_sector_size)
 		dev_info(host->dev, "WARNING: Be Caution! Using different PMECC parameters from Nand ONFI ECC reqirement.\n");
 		dev_info(host->dev, "WARNING: Be Caution! Using different PMECC parameters from Nand ONFI ECC reqirement.\n");
 
 
@@ -1023,27 +1174,28 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		return 0;
 		return 0;
 	}
 	}
 
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
 		dev_err(host->dev, "ioremap failed\n");
-		err_no = -EIO;
-		goto err_pmecc_ioremap;
+		err_no = PTR_ERR(host->ecc);
+		goto err;
 	}
 	}
 
 
 	regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
-	if (regs_pmerr && regs_rom) {
-		host->pmerrloc_base = ioremap(regs_pmerr->start,
-			resource_size(regs_pmerr));
-		host->pmecc_rom_base = ioremap(regs_rom->start,
-			resource_size(regs_rom));
+	host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr);
+	if (IS_ERR(host->pmerrloc_base)) {
+		dev_err(host->dev,
+			"Can not get I/O resource for PMECC ERRLOC controller!\n");
+		err_no = PTR_ERR(host->pmerrloc_base);
+		goto err;
 	}
 	}
 
 
-	if (!host->pmerrloc_base || !host->pmecc_rom_base) {
-		dev_err(host->dev,
-			"Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
-		err_no = -EIO;
-		goto err_pmloc_ioremap;
+	regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+	host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
+	if (IS_ERR(host->pmecc_rom_base)) {
+		dev_err(host->dev, "Can not get I/O resource for ROM!\n");
+		err_no = PTR_ERR(host->pmecc_rom_base);
+		goto err;
 	}
 	}
 
 
 	/* ECC is calculated for the whole page (1 step) */
 	/* ECC is calculated for the whole page (1 step) */
@@ -1052,7 +1204,8 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 	/* set ECC page size and oob layout */
 	/* set ECC page size and oob layout */
 	switch (mtd->writesize) {
 	switch (mtd->writesize) {
 	case 2048:
 	case 2048:
-		host->pmecc_degree = PMECC_GF_DIMENSION_13;
+		host->pmecc_degree = (sector_size == 512) ?
+			PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14;
 		host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
 		host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
 		host->pmecc_sector_number = mtd->writesize / sector_size;
 		host->pmecc_sector_number = mtd->writesize / sector_size;
 		host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
 		host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
@@ -1068,7 +1221,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 		if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
 		if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
 			dev_err(host->dev, "No room for ECC bytes\n");
 			dev_err(host->dev, "No room for ECC bytes\n");
 			err_no = -EINVAL;
 			err_no = -EINVAL;
-			goto err_no_ecc_room;
+			goto err;
 		}
 		}
 		pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
 		pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
 					mtd->oobsize,
 					mtd->oobsize,
@@ -1093,7 +1246,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 	if (err_no) {
 	if (err_no) {
 		dev_err(host->dev,
 		dev_err(host->dev,
 				"Cannot allocate memory for PMECC computation!\n");
 				"Cannot allocate memory for PMECC computation!\n");
-		goto err_pmecc_data_alloc;
+		goto err;
 	}
 	}
 
 
 	nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
 	nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
@@ -1103,15 +1256,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 
 
 	return 0;
 	return 0;
 
 
-err_pmecc_data_alloc:
-err_no_ecc_room:
-err_pmloc_ioremap:
-	iounmap(host->ecc);
-	if (host->pmerrloc_base)
-		iounmap(host->pmerrloc_base);
-	if (host->pmecc_rom_base)
-		iounmap(host->pmecc_rom_base);
-err_pmecc_ioremap:
+err:
 	return err_no;
 	return err_no;
 }
 }
 
 
@@ -1174,10 +1319,9 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 	 * Workaround: Reset the parity registers before reading the
 	 * Workaround: Reset the parity registers before reading the
 	 * actual data.
 	 * actual data.
 	 */
 	 */
-	if (cpu_is_at32ap7000()) {
-		struct atmel_nand_host *host = chip->priv;
+	struct atmel_nand_host *host = chip->priv;
+	if (host->board.need_reset_workaround)
 		ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
 		ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
-	}
 
 
 	/* read the page */
 	/* read the page */
 	chip->read_buf(mtd, p, eccsize);
 	chip->read_buf(mtd, p, eccsize);
@@ -1298,11 +1442,11 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
  */
  */
 static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 {
 {
-	if (cpu_is_at32ap7000()) {
-		struct nand_chip *nand_chip = mtd->priv;
-		struct atmel_nand_host *host = nand_chip->priv;
+	struct nand_chip *nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
+
+	if (host->board.need_reset_workaround)
 		ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
 		ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
-	}
 }
 }
 
 
 #if defined(CONFIG_OF)
 #if defined(CONFIG_OF)
@@ -1337,6 +1481,8 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 
 
 	board->on_flash_bbt = of_get_nand_on_flash_bbt(np);
 	board->on_flash_bbt = of_get_nand_on_flash_bbt(np);
 
 
+	board->has_dma = of_property_read_bool(np, "atmel,nand-has-dma");
+
 	if (of_get_nand_bus_width(np) == 16)
 	if (of_get_nand_bus_width(np) == 16)
 		board->bus_width_16 = 1;
 		board->bus_width_16 = 1;
 
 
@@ -1348,6 +1494,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 
 
 	host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
 	host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
 
 
+	/* load the nfc driver if there is */
+	of_platform_populate(np, NULL, NULL, host->dev);
+
 	if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
 	if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
 		return 0;	/* Not using PMECC */
 		return 0;	/* Not using PMECC */
 
 
@@ -1414,10 +1563,10 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 		return 0;
 		return 0;
 	}
 	}
 
 
-	host->ecc = ioremap(regs->start, resource_size(regs));
-	if (host->ecc == NULL) {
+	host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+	if (IS_ERR(host->ecc)) {
 		dev_err(host->dev, "ioremap failed\n");
 		dev_err(host->dev, "ioremap failed\n");
-		return -EIO;
+		return PTR_ERR(host->ecc);
 	}
 	}
 
 
 	/* ECC is calculated for the whole page (1 step) */
 	/* ECC is calculated for the whole page (1 step) */
@@ -1459,6 +1608,382 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
 	return 0;
 	return 0;
 }
 }
 
 
+/* SMC interrupt service routine */
+static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
+{
+	struct atmel_nand_host *host = dev_id;
+	u32 status, mask, pending;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	status = nfc_readl(host->nfc->hsmc_regs, SR);
+	mask = nfc_readl(host->nfc->hsmc_regs, IMR);
+	pending = status & mask;
+
+	if (pending & NFC_SR_XFR_DONE) {
+		complete(&host->nfc->comp_nfc);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
+	} else if (pending & NFC_SR_RB_EDGE) {
+		complete(&host->nfc->comp_nfc);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
+	} else if (pending & NFC_SR_CMD_DONE) {
+		complete(&host->nfc->comp_nfc);
+		nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE);
+	} else {
+		ret = IRQ_NONE;
+	}
+
+	return ret;
+}
+
+/* NFC(Nand Flash Controller) related functions */
+static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
+{
+	unsigned long timeout;
+	init_completion(&host->nfc->comp_nfc);
+
+	/* Enable interrupt that need to wait for */
+	nfc_writel(host->nfc->hsmc_regs, IER, flag);
+
+	timeout = wait_for_completion_timeout(&host->nfc->comp_nfc,
+			msecs_to_jiffies(NFC_TIME_OUT_MS));
+	if (timeout)
+		return 0;
+
+	/* Time out to wait for the interrupt */
+	dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag);
+	return -ETIMEDOUT;
+}
+
+static int nfc_send_command(struct atmel_nand_host *host,
+	unsigned int cmd, unsigned int addr, unsigned char cycle0)
+{
+	unsigned long timeout;
+	dev_dbg(host->dev,
+		"nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n",
+		cmd, addr, cycle0);
+
+	timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
+	while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs)
+			& NFCADDR_CMD_NFCBUSY) {
+		if (time_after(jiffies, timeout)) {
+			dev_err(host->dev,
+				"Time out to wait CMD_NFCBUSY ready!\n");
+			return -ETIMEDOUT;
+		}
+	}
+	nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0);
+	nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs);
+	return nfc_wait_interrupt(host, NFC_SR_CMD_DONE);
+}
+
+static int nfc_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
+	if (!nfc_wait_interrupt(host, NFC_SR_RB_EDGE))
+		return 1;
+	return 0;
+}
+
+static void nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct atmel_nand_host *host = nand_chip->priv;
+
+	if (chip == -1)
+		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_DISABLE);
+	else
+		nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_ENABLE);
+}
+
+static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr,
+		unsigned int *addr1234, unsigned int *cycle0)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	int acycle = 0;
+	unsigned char addr_bytes[8];
+	int index = 0, bit_shift;
+
+	BUG_ON(addr1234 == NULL || cycle0 == NULL);
+
+	*cycle0 = 0;
+	*addr1234 = 0;
+
+	if (column != -1) {
+		if (chip->options & NAND_BUSWIDTH_16)
+			column >>= 1;
+		addr_bytes[acycle++] = column & 0xff;
+		if (mtd->writesize > 512)
+			addr_bytes[acycle++] = (column >> 8) & 0xff;
+	}
+
+	if (page_addr != -1) {
+		addr_bytes[acycle++] = page_addr & 0xff;
+		addr_bytes[acycle++] = (page_addr >> 8) & 0xff;
+		if (chip->chipsize > (128 << 20))
+			addr_bytes[acycle++] = (page_addr >> 16) & 0xff;
+	}
+
+	if (acycle > 4)
+		*cycle0 = addr_bytes[index++];
+
+	for (bit_shift = 0; index < acycle; bit_shift += 8)
+		*addr1234 += addr_bytes[index++] << bit_shift;
+
+	/* return acycle in cmd register */
+	return acycle << NFCADDR_CMD_ACYCLE_BIT_POS;
+}
+
+static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
+				int column, int page_addr)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	unsigned long timeout;
+	unsigned int nfc_addr_cmd = 0;
+
+	unsigned int cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
+
+	/* Set default settings: no cmd2, no addr cycle. read from nand */
+	unsigned int cmd2 = 0;
+	unsigned int vcmd2 = 0;
+	int acycle = NFCADDR_CMD_ACYCLE_NONE;
+	int csid = NFCADDR_CMD_CSID_3;
+	int dataen = NFCADDR_CMD_DATADIS;
+	int nfcwr = NFCADDR_CMD_NFCRD;
+	unsigned int addr1234 = 0;
+	unsigned int cycle0 = 0;
+	bool do_addr = true;
+	host->nfc->data_in_sram = NULL;
+
+	dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
+	     __func__, command, column, page_addr);
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		nfc_addr_cmd = cmd1 | acycle | csid | dataen | nfcwr;
+		nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
+		udelay(chip->chip_delay);
+
+		nfc_nand_command(mtd, NAND_CMD_STATUS, -1, -1);
+		timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
+		while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) {
+			if (time_after(jiffies, timeout)) {
+				dev_err(host->dev,
+					"Time out to wait status ready!\n");
+				break;
+			}
+		}
+		return;
+	case NAND_CMD_STATUS:
+		do_addr = false;
+		break;
+	case NAND_CMD_PARAM:
+	case NAND_CMD_READID:
+		do_addr = false;
+		acycle = NFCADDR_CMD_ACYCLE_1;
+		if (column != -1)
+			addr1234 = column;
+		break;
+	case NAND_CMD_RNDOUT:
+		cmd2 = NAND_CMD_RNDOUTSTART << NFCADDR_CMD_CMD2_BIT_POS;
+		vcmd2 = NFCADDR_CMD_VCMD2;
+		break;
+	case NAND_CMD_READ0:
+	case NAND_CMD_READOOB:
+		if (command == NAND_CMD_READOOB) {
+			column += mtd->writesize;
+			command = NAND_CMD_READ0; /* only READ0 is valid */
+			cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
+		}
+		if (host->nfc->use_nfc_sram) {
+			/* Enable Data transfer to sram */
+			dataen = NFCADDR_CMD_DATAEN;
+
+			/* Need enable PMECC now, since NFC will transfer
+			 * data in bus after sending nfc read command.
+			 */
+			if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
+				pmecc_enable(host, NAND_ECC_READ);
+		}
+
+		cmd2 = NAND_CMD_READSTART << NFCADDR_CMD_CMD2_BIT_POS;
+		vcmd2 = NFCADDR_CMD_VCMD2;
+		break;
+	/* For prgramming command, the cmd need set to write enable */
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_RNDIN:
+		nfcwr = NFCADDR_CMD_NFCWR;
+		if (host->nfc->will_write_sram && command == NAND_CMD_SEQIN)
+			dataen = NFCADDR_CMD_DATAEN;
+		break;
+	default:
+		break;
+	}
+
+	if (do_addr)
+		acycle = nfc_make_addr(mtd, column, page_addr, &addr1234,
+				&cycle0);
+
+	nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
+	nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
+
+	if (dataen == NFCADDR_CMD_DATAEN)
+		if (nfc_wait_interrupt(host, NFC_SR_XFR_DONE))
+			dev_err(host->dev, "something wrong, No XFR_DONE interrupt comes.\n");
+
+	/*
+	 * Program and erase have their own busy handlers status, sequential
+	 * in, and deplete1 need no delay.
+	 */
+	switch (command) {
+	case NAND_CMD_CACHEDPROG:
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_RNDIN:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_RNDOUT:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_READID:
+		return;
+
+	case NAND_CMD_READ0:
+		if (dataen == NFCADDR_CMD_DATAEN) {
+			host->nfc->data_in_sram = host->nfc->sram_bank0 +
+				nfc_get_sram_off(host);
+			return;
+		}
+		/* fall through */
+	default:
+		nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
+	}
+}
+
+static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			uint32_t offset, int data_len, const uint8_t *buf,
+			int oob_required, int page, int cached, int raw)
+{
+	int cfg, len;
+	int status = 0;
+	struct atmel_nand_host *host = chip->priv;
+	void __iomem *sram = host->nfc->sram_bank0 + nfc_get_sram_off(host);
+
+	/* Subpage write is not supported */
+	if (offset || (data_len < mtd->writesize))
+		return -EINVAL;
+
+	cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
+	len = mtd->writesize;
+
+	if (unlikely(raw)) {
+		len += mtd->oobsize;
+		nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
+	} else
+		nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
+
+	/* Copy page data to sram that will write to nand via NFC */
+	if (use_dma) {
+		if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
+			/* Fall back to use cpu copy */
+			memcpy32_toio(sram, buf, len);
+	} else {
+		memcpy32_toio(sram, buf, len);
+	}
+
+	if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
+		/*
+		 * When use NFC sram, need set up PMECC before send
+		 * NAND_CMD_SEQIN command. Since when the nand command
+		 * is sent, nfc will do transfer from sram and nand.
+		 */
+		pmecc_enable(host, NAND_ECC_WRITE);
+
+	host->nfc->will_write_sram = true;
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+	host->nfc->will_write_sram = false;
+
+	if (likely(!raw))
+		/* Need to write ecc into oob */
+		status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+	if (status < 0)
+		return status;
+
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	status = chip->waitfunc(mtd, chip);
+
+	if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+		status = chip->errstat(mtd, chip, FL_WRITING, status, page);
+
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+
+static int nfc_sram_init(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct atmel_nand_host *host = chip->priv;
+	int res = 0;
+
+	/* Initialize the NFC CFG register */
+	unsigned int cfg_nfc = 0;
+
+	/* set page size and oob layout */
+	switch (mtd->writesize) {
+	case 512:
+		cfg_nfc = NFC_CFG_PAGESIZE_512;
+		break;
+	case 1024:
+		cfg_nfc = NFC_CFG_PAGESIZE_1024;
+		break;
+	case 2048:
+		cfg_nfc = NFC_CFG_PAGESIZE_2048;
+		break;
+	case 4096:
+		cfg_nfc = NFC_CFG_PAGESIZE_4096;
+		break;
+	case 8192:
+		cfg_nfc = NFC_CFG_PAGESIZE_8192;
+		break;
+	default:
+		dev_err(host->dev, "Unsupported page size for NFC.\n");
+		res = -ENXIO;
+		return res;
+	}
+
+	/* oob bytes size = (NFCSPARESIZE + 1) * 4
+	 * Max support spare size is 512 bytes. */
+	cfg_nfc |= (((mtd->oobsize / 4) - 1) << NFC_CFG_NFC_SPARESIZE_BIT_POS
+		& NFC_CFG_NFC_SPARESIZE);
+	/* default set a max timeout */
+	cfg_nfc |= NFC_CFG_RSPARE |
+			NFC_CFG_NFC_DTOCYC | NFC_CFG_NFC_DTOMUL;
+
+	nfc_writel(host->nfc->hsmc_regs, CFG, cfg_nfc);
+
+	host->nfc->will_write_sram = false;
+	nfc_set_sram_bank(host, 0);
+
+	/* Use Write page with NFC SRAM only for PMECC or ECC NONE. */
+	if (host->nfc->write_by_sram) {
+		if ((chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) ||
+				chip->ecc.mode == NAND_ECC_NONE)
+			chip->write_page = nfc_sram_write_page;
+		else
+			host->nfc->write_by_sram = false;
+	}
+
+	dev_info(host->dev, "Using NFC Sram read %s\n",
+			host->nfc->write_by_sram ? "and write" : "");
+	return 0;
+}
+
+static struct platform_driver atmel_nand_nfc_driver;
 /*
 /*
  * Probe for the NAND device.
  * Probe for the NAND device.
  */
  */
@@ -1469,30 +1994,27 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	struct nand_chip *nand_chip;
 	struct nand_chip *nand_chip;
 	struct resource *mem;
 	struct resource *mem;
 	struct mtd_part_parser_data ppdata = {};
 	struct mtd_part_parser_data ppdata = {};
-	int res;
-	struct pinctrl *pinctrl;
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
-		return -ENXIO;
-	}
+	int res, irq;
 
 
 	/* Allocate memory for the device structure (and zero it) */
 	/* Allocate memory for the device structure (and zero it) */
-	host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL);
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
 	if (!host) {
 	if (!host) {
 		printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
 		printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
-	host->io_phys = (dma_addr_t)mem->start;
+	res = platform_driver_register(&atmel_nand_nfc_driver);
+	if (res)
+		dev_err(&pdev->dev, "atmel_nand: can't register NFC driver\n");
 
 
-	host->io_base = ioremap(mem->start, resource_size(mem));
-	if (host->io_base == NULL) {
-		printk(KERN_ERR "atmel_nand: ioremap failed\n");
-		res = -EIO;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->io_base = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(host->io_base)) {
+		dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
+		res = PTR_ERR(host->io_base);
 		goto err_nand_ioremap;
 		goto err_nand_ioremap;
 	}
 	}
+	host->io_phys = (dma_addr_t)mem->start;
 
 
 	mtd = &host->mtd;
 	mtd = &host->mtd;
 	nand_chip = &host->nand_chip;
 	nand_chip = &host->nand_chip;
@@ -1500,9 +2022,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	if (pdev->dev.of_node) {
 	if (pdev->dev.of_node) {
 		res = atmel_of_init_port(host, pdev->dev.of_node);
 		res = atmel_of_init_port(host, pdev->dev.of_node);
 		if (res)
 		if (res)
-			goto err_ecc_ioremap;
+			goto err_nand_ioremap;
 	} else {
 	} else {
-		memcpy(&host->board, pdev->dev.platform_data,
+		memcpy(&host->board, dev_get_platdata(&pdev->dev),
 		       sizeof(struct atmel_nand_data));
 		       sizeof(struct atmel_nand_data));
 	}
 	}
 
 
@@ -1513,51 +2035,36 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	/* Set address of NAND IO lines */
 	/* Set address of NAND IO lines */
 	nand_chip->IO_ADDR_R = host->io_base;
 	nand_chip->IO_ADDR_R = host->io_base;
 	nand_chip->IO_ADDR_W = host->io_base;
 	nand_chip->IO_ADDR_W = host->io_base;
-	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 
 
-	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-	if (IS_ERR(pinctrl)) {
-		dev_err(host->dev, "Failed to request pinctrl\n");
-		res = PTR_ERR(pinctrl);
-		goto err_ecc_ioremap;
-	}
+	if (nand_nfc.is_initialized) {
+		/* NFC driver is probed and initialized */
+		host->nfc = &nand_nfc;
 
 
-	if (gpio_is_valid(host->board.rdy_pin)) {
-		res = gpio_request(host->board.rdy_pin, "nand_rdy");
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request rdy gpio %d\n",
-				host->board.rdy_pin);
-			goto err_ecc_ioremap;
-		}
+		nand_chip->select_chip = nfc_select_chip;
+		nand_chip->dev_ready = nfc_device_ready;
+		nand_chip->cmdfunc = nfc_nand_command;
 
 
-		res = gpio_direction_input(host->board.rdy_pin);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request input direction rdy gpio %d\n",
-				host->board.rdy_pin);
-			goto err_ecc_ioremap;
+		/* Initialize the interrupt for NFC */
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0) {
+			dev_err(host->dev, "Cannot get HSMC irq!\n");
+			res = irq;
+			goto err_nand_ioremap;
 		}
 		}
 
 
-		nand_chip->dev_ready = atmel_nand_device_ready;
-	}
-
-	if (gpio_is_valid(host->board.enable_pin)) {
-		res = gpio_request(host->board.enable_pin, "nand_enable");
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request enable gpio %d\n",
-				host->board.enable_pin);
-			goto err_ecc_ioremap;
+		res = devm_request_irq(&pdev->dev, irq, hsmc_interrupt,
+				0, "hsmc", host);
+		if (res) {
+			dev_err(&pdev->dev, "Unable to request HSMC irq %d\n",
+				irq);
+			goto err_nand_ioremap;
 		}
 		}
+	} else {
+		res = atmel_nand_set_enable_ready_pins(mtd);
+		if (res)
+			goto err_nand_ioremap;
 
 
-		res = gpio_direction_output(host->board.enable_pin, 1);
-		if (res < 0) {
-			dev_err(&pdev->dev,
-				"can't request output direction enable gpio %d\n",
-				host->board.enable_pin);
-			goto err_ecc_ioremap;
-		}
+		nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 	}
 	}
 
 
 	nand_chip->ecc.mode = host->board.ecc_mode;
 	nand_chip->ecc.mode = host->board.ecc_mode;
@@ -1573,7 +2080,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 	atmel_nand_enable(host);
 	atmel_nand_enable(host);
 
 
 	if (gpio_is_valid(host->board.det_pin)) {
 	if (gpio_is_valid(host->board.det_pin)) {
-		res = gpio_request(host->board.det_pin, "nand_det");
+		res = devm_gpio_request(&pdev->dev,
+				host->board.det_pin, "nand_det");
 		if (res < 0) {
 		if (res < 0) {
 			dev_err(&pdev->dev,
 			dev_err(&pdev->dev,
 				"can't request det gpio %d\n",
 				"can't request det gpio %d\n",
@@ -1601,7 +2109,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
 		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
 	}
 	}
 
 
-	if (!cpu_has_dma())
+	if (!host->board.has_dma)
 		use_dma = 0;
 		use_dma = 0;
 
 
 	if (use_dma) {
 	if (use_dma) {
@@ -1637,6 +2145,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 			goto err_hw_ecc;
 			goto err_hw_ecc;
 	}
 	}
 
 
+	/* initialize the nfc configuration register */
+	if (host->nfc && host->nfc->use_nfc_sram) {
+		res = nfc_sram_init(mtd);
+		if (res) {
+			host->nfc->use_nfc_sram = false;
+			dev_err(host->dev, "Disable use nfc sram for data transfer.\n");
+		}
+	}
+
 	/* second phase scan */
 	/* second phase scan */
 	if (nand_scan_tail(mtd)) {
 	if (nand_scan_tail(mtd)) {
 		res = -ENXIO;
 		res = -ENXIO;
@@ -1651,27 +2168,16 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 		return res;
 		return res;
 
 
 err_scan_tail:
 err_scan_tail:
-	if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
+	if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW)
 		pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
 		pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-		pmecc_data_free(host);
-	}
-	if (host->ecc)
-		iounmap(host->ecc);
-	if (host->pmerrloc_base)
-		iounmap(host->pmerrloc_base);
-	if (host->pmecc_rom_base)
-		iounmap(host->pmecc_rom_base);
 err_hw_ecc:
 err_hw_ecc:
 err_scan_ident:
 err_scan_ident:
 err_no_card:
 err_no_card:
 	atmel_nand_disable(host);
 	atmel_nand_disable(host);
-	platform_set_drvdata(pdev, NULL);
 	if (host->dma_chan)
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 		dma_release_channel(host->dma_chan);
-err_ecc_ioremap:
-	iounmap(host->io_base);
 err_nand_ioremap:
 err_nand_ioremap:
-	kfree(host);
+	platform_driver_unregister(&atmel_nand_nfc_driver);
 	return res;
 	return res;
 }
 }
 
 
@@ -1691,30 +2197,12 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
 		pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
 		pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
 		pmerrloc_writel(host->pmerrloc_base, ELDIS,
 		pmerrloc_writel(host->pmerrloc_base, ELDIS,
 				PMERRLOC_DISABLE);
 				PMERRLOC_DISABLE);
-		pmecc_data_free(host);
 	}
 	}
 
 
-	if (gpio_is_valid(host->board.det_pin))
-		gpio_free(host->board.det_pin);
-
-	if (gpio_is_valid(host->board.enable_pin))
-		gpio_free(host->board.enable_pin);
-
-	if (gpio_is_valid(host->board.rdy_pin))
-		gpio_free(host->board.rdy_pin);
-
-	if (host->ecc)
-		iounmap(host->ecc);
-	if (host->pmecc_rom_base)
-		iounmap(host->pmecc_rom_base);
-	if (host->pmerrloc_base)
-		iounmap(host->pmerrloc_base);
-
 	if (host->dma_chan)
 	if (host->dma_chan)
 		dma_release_channel(host->dma_chan);
 		dma_release_channel(host->dma_chan);
 
 
-	iounmap(host->io_base);
-	kfree(host);
+	platform_driver_unregister(&atmel_nand_nfc_driver);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1728,6 +2216,59 @@ static const struct of_device_id atmel_nand_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
 MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
 #endif
 #endif
 
 
+static int atmel_nand_nfc_probe(struct platform_device *pdev)
+{
+	struct atmel_nfc *nfc = &nand_nfc;
+	struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
+
+	nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
+	if (IS_ERR(nfc->base_cmd_regs))
+		return PTR_ERR(nfc->base_cmd_regs);
+
+	nfc_hsmc_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	nfc->hsmc_regs = devm_ioremap_resource(&pdev->dev, nfc_hsmc_regs);
+	if (IS_ERR(nfc->hsmc_regs))
+		return PTR_ERR(nfc->hsmc_regs);
+
+	nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (nfc_sram) {
+		nfc->sram_bank0 = devm_ioremap_resource(&pdev->dev, nfc_sram);
+		if (IS_ERR(nfc->sram_bank0)) {
+			dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
+					PTR_ERR(nfc->sram_bank0));
+		} else {
+			nfc->use_nfc_sram = true;
+			nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+
+			if (pdev->dev.of_node)
+				nfc->write_by_sram = of_property_read_bool(
+						pdev->dev.of_node,
+						"atmel,write-by-sram");
+		}
+	}
+
+	nfc->is_initialized = true;
+	dev_info(&pdev->dev, "NFC is probed.\n");
+	return 0;
+}
+
+#if defined(CONFIG_OF)
+static struct of_device_id atmel_nand_nfc_match[] = {
+	{ .compatible = "atmel,sama5d3-nfc" },
+	{ /* sentinel */ }
+};
+#endif
+
+static struct platform_driver atmel_nand_nfc_driver = {
+	.driver = {
+		.name = "atmel_nand_nfc",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(atmel_nand_nfc_match),
+	},
+	.probe = atmel_nand_nfc_probe,
+};
+
 static struct platform_driver atmel_nand_driver = {
 static struct platform_driver atmel_nand_driver = {
 	.remove		= __exit_p(atmel_nand_remove),
 	.remove		= __exit_p(atmel_nand_remove),
 	.driver		= {
 	.driver		= {

+ 98 - 0
drivers/mtd/nand/atmel_nand_nfc.h

@@ -0,0 +1,98 @@
+/*
+ * Atmel Nand Flash Controller (NFC) - System peripherals regsters.
+ * Based on SAMA5D3 datasheet.
+ *
+ * © Copyright 2013 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef ATMEL_NAND_NFC_H
+#define ATMEL_NAND_NFC_H
+
+/*
+ * HSMC NFC registers
+ */
+#define ATMEL_HSMC_NFC_CFG	0x00		/* NFC Configuration Register */
+#define		NFC_CFG_PAGESIZE	(7 << 0)
+#define			NFC_CFG_PAGESIZE_512	(0 << 0)
+#define			NFC_CFG_PAGESIZE_1024	(1 << 0)
+#define			NFC_CFG_PAGESIZE_2048	(2 << 0)
+#define			NFC_CFG_PAGESIZE_4096	(3 << 0)
+#define			NFC_CFG_PAGESIZE_8192	(4 << 0)
+#define		NFC_CFG_WSPARE		(1 << 8)
+#define		NFC_CFG_RSPARE		(1 << 9)
+#define		NFC_CFG_NFC_DTOCYC	(0xf << 16)
+#define		NFC_CFG_NFC_DTOMUL	(0x7 << 20)
+#define		NFC_CFG_NFC_SPARESIZE	(0x7f << 24)
+#define		NFC_CFG_NFC_SPARESIZE_BIT_POS	24
+
+#define ATMEL_HSMC_NFC_CTRL	0x04		/* NFC Control Register */
+#define		NFC_CTRL_ENABLE		(1 << 0)
+#define		NFC_CTRL_DISABLE	(1 << 1)
+
+#define ATMEL_HSMC_NFC_SR	0x08		/* NFC Status Register */
+#define		NFC_SR_XFR_DONE		(1 << 16)
+#define		NFC_SR_CMD_DONE		(1 << 17)
+#define		NFC_SR_RB_EDGE		(1 << 24)
+
+#define ATMEL_HSMC_NFC_IER	0x0c
+#define ATMEL_HSMC_NFC_IDR	0x10
+#define ATMEL_HSMC_NFC_IMR	0x14
+#define ATMEL_HSMC_NFC_CYCLE0	0x18		/* NFC Address Cycle Zero */
+#define		ATMEL_HSMC_NFC_ADDR_CYCLE0	(0xff)
+
+#define ATMEL_HSMC_NFC_BANK	0x1c		/* NFC Bank Register */
+#define		ATMEL_HSMC_NFC_BANK0		(0 << 0)
+#define		ATMEL_HSMC_NFC_BANK1		(1 << 0)
+
+#define nfc_writel(addr, reg, value) \
+	writel((value), (addr) + ATMEL_HSMC_NFC_##reg)
+
+#define nfc_readl(addr, reg) \
+	readl_relaxed((addr) + ATMEL_HSMC_NFC_##reg)
+
+/*
+ * NFC Address Command definitions
+ */
+#define NFCADDR_CMD_CMD1	(0xff << 2)	/* Command for Cycle 1 */
+#define NFCADDR_CMD_CMD1_BIT_POS	2
+#define NFCADDR_CMD_CMD2	(0xff << 10)	/* Command for Cycle 2 */
+#define NFCADDR_CMD_CMD2_BIT_POS	10
+#define NFCADDR_CMD_VCMD2	(0x1 << 18)	/* Valid Cycle 2 Command */
+#define NFCADDR_CMD_ACYCLE	(0x7 << 19)	/* Number of Address required */
+#define		NFCADDR_CMD_ACYCLE_NONE		(0x0 << 19)
+#define		NFCADDR_CMD_ACYCLE_1		(0x1 << 19)
+#define		NFCADDR_CMD_ACYCLE_2		(0x2 << 19)
+#define		NFCADDR_CMD_ACYCLE_3		(0x3 << 19)
+#define		NFCADDR_CMD_ACYCLE_4		(0x4 << 19)
+#define		NFCADDR_CMD_ACYCLE_5		(0x5 << 19)
+#define NFCADDR_CMD_ACYCLE_BIT_POS	19
+#define NFCADDR_CMD_CSID	(0x7 << 22)	/* Chip Select Identifier */
+#define		NFCADDR_CMD_CSID_0		(0x0 << 22)
+#define		NFCADDR_CMD_CSID_1		(0x1 << 22)
+#define		NFCADDR_CMD_CSID_2		(0x2 << 22)
+#define		NFCADDR_CMD_CSID_3		(0x3 << 22)
+#define		NFCADDR_CMD_CSID_4		(0x4 << 22)
+#define		NFCADDR_CMD_CSID_5		(0x5 << 22)
+#define		NFCADDR_CMD_CSID_6		(0x6 << 22)
+#define		NFCADDR_CMD_CSID_7		(0x7 << 22)
+#define NFCADDR_CMD_DATAEN	(0x1 << 25)	/* Data Transfer Enable */
+#define NFCADDR_CMD_DATADIS	(0x0 << 25)	/* Data Transfer Disable */
+#define NFCADDR_CMD_NFCRD	(0x0 << 26)	/* NFC Read Enable */
+#define NFCADDR_CMD_NFCWR	(0x1 << 26)	/* NFC Write Enable */
+#define NFCADDR_CMD_NFCBUSY	(0x1 << 27)	/* NFC Busy */
+
+#define nfc_cmd_addr1234_writel(cmd, addr1234, nfc_base) \
+	writel((addr1234), (cmd) + nfc_base)
+
+#define nfc_cmd_readl(bitstatus, nfc_base) \
+	readl_relaxed((bitstatus) + nfc_base)
+
+#define NFC_TIME_OUT_MS		100
+#define	NFC_SRAM_BANK1_OFFSET	0x1200
+
+#endif

+ 1 - 1
drivers/mtd/nand/au1550nd.c

@@ -411,7 +411,7 @@ static int au1550nd_probe(struct platform_device *pdev)
 	struct resource *r;
 	struct resource *r;
 	int ret, cs;
 	int ret, cs;
 
 
-	pd = pdev->dev.platform_data;
+	pd = dev_get_platdata(&pdev->dev);
 	if (!pd) {
 	if (!pd) {
 		dev_err(&pdev->dev, "missing platform data\n");
 		dev_err(&pdev->dev, "missing platform data\n");
 		return -ENODEV;
 		return -ENODEV;

+ 1 - 4
drivers/mtd/nand/bf5xx_nand.c

@@ -171,7 +171,7 @@ static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
 
 
 static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
 static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
 {
 {
-	return pdev->dev.platform_data;
+	return dev_get_platdata(&pdev->dev);
 }
 }
 
 
 /*
 /*
@@ -671,8 +671,6 @@ static int bf5xx_nand_remove(struct platform_device *pdev)
 {
 {
 	struct bf5xx_nand_info *info = to_nand_info(pdev);
 	struct bf5xx_nand_info *info = to_nand_info(pdev);
 
 
-	platform_set_drvdata(pdev, NULL);
-
 	/* first thing we need to do is release all our mtds
 	/* first thing we need to do is release all our mtds
 	 * and their partitions, then go through freeing the
 	 * and their partitions, then go through freeing the
 	 * resources used
 	 * resources used
@@ -832,7 +830,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
 out_err_nand_scan:
 out_err_nand_scan:
 	bf5xx_nand_dma_remove(info);
 	bf5xx_nand_dma_remove(info);
 out_err_hw_init:
 out_err_hw_init:
-	platform_set_drvdata(pdev, NULL);
 	kfree(info);
 	kfree(info);
 out_err_kzalloc:
 out_err_kzalloc:
 	peripheral_free_list(bfin_nfc_pin_req);
 	peripheral_free_list(bfin_nfc_pin_req);

+ 1 - 5
drivers/mtd/nand/cs553x_nand.c

@@ -197,7 +197,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
 	}
 	}
 
 
 	/* Allocate memory for MTD device structure and private data */
 	/* Allocate memory for MTD device structure and private data */
-	new_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+	new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
 	if (!new_mtd) {
 	if (!new_mtd) {
 		printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n");
 		printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n");
 		err = -ENOMEM;
 		err = -ENOMEM;
@@ -207,10 +207,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
 	/* Get pointer to private data */
 	/* Get pointer to private data */
 	this = (struct nand_chip *)(&new_mtd[1]);
 	this = (struct nand_chip *)(&new_mtd[1]);
 
 
-	/* Initialize structures */
-	memset(new_mtd, 0, sizeof(struct mtd_info));
-	memset(this, 0, sizeof(struct nand_chip));
-
 	/* Link the private data with the MTD structure */
 	/* Link the private data with the MTD structure */
 	new_mtd->priv = this;
 	new_mtd->priv = this;
 	new_mtd->owner = THIS_MODULE;
 	new_mtd->owner = THIS_MODULE;

+ 11 - 8
drivers/mtd/nand/davinci_nand.c

@@ -530,7 +530,7 @@ MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
 static struct davinci_nand_pdata
 static struct davinci_nand_pdata
 	*nand_davinci_get_pdata(struct platform_device *pdev)
 	*nand_davinci_get_pdata(struct platform_device *pdev)
 {
 {
-	if (!pdev->dev.platform_data && pdev->dev.of_node) {
+	if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) {
 		struct davinci_nand_pdata *pdata;
 		struct davinci_nand_pdata *pdata;
 		const char *mode;
 		const char *mode;
 		u32 prop;
 		u32 prop;
@@ -575,13 +575,13 @@ static struct davinci_nand_pdata
 			pdata->bbt_options = NAND_BBT_USE_FLASH;
 			pdata->bbt_options = NAND_BBT_USE_FLASH;
 	}
 	}
 
 
-	return pdev->dev.platform_data;
+	return dev_get_platdata(&pdev->dev);
 }
 }
 #else
 #else
 static struct davinci_nand_pdata
 static struct davinci_nand_pdata
 	*nand_davinci_get_pdata(struct platform_device *pdev)
 	*nand_davinci_get_pdata(struct platform_device *pdev)
 {
 {
-	return pdev->dev.platform_data;
+	return dev_get_platdata(&pdev->dev);
 }
 }
 #endif
 #endif
 
 
@@ -623,11 +623,14 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
 		goto err_nomem;
 		goto err_nomem;
 	}
 	}
 
 
-	vaddr = devm_request_and_ioremap(&pdev->dev, res1);
-	base = devm_request_and_ioremap(&pdev->dev, res2);
-	if (!vaddr || !base) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -EADDRNOTAVAIL;
+	vaddr = devm_ioremap_resource(&pdev->dev, res1);
+	if (IS_ERR(vaddr)) {
+		ret = PTR_ERR(vaddr);
+		goto err_ioremap;
+	}
+	base = devm_ioremap_resource(&pdev->dev, res2);
+	if (IS_ERR(base)) {
+		ret = PTR_ERR(base);
 		goto err_ioremap;
 		goto err_ioremap;
 	}
 	}
 
 

+ 1 - 1
drivers/mtd/nand/denali.c

@@ -1520,7 +1520,7 @@ int denali_init(struct denali_nand_info *denali)
 	 * so just let controller do 15bit ECC for MLC and 8bit ECC for
 	 * so just let controller do 15bit ECC for MLC and 8bit ECC for
 	 * SLC if possible.
 	 * SLC if possible.
 	 * */
 	 * */
-	if (denali->nand.cellinfo & 0xc &&
+	if (denali->nand.cellinfo & NAND_CI_CELLTYPE_MSK &&
 			(denali->mtd.oobsize > (denali->bbtskipbytes +
 			(denali->mtd.oobsize > (denali->bbtskipbytes +
 			ECC_15BITS * (denali->mtd.writesize /
 			ECC_15BITS * (denali->mtd.writesize /
 			ECC_SECTOR_SIZE)))) {
 			ECC_SECTOR_SIZE)))) {

+ 2 - 2
drivers/mtd/nand/diskonchip.c

@@ -46,13 +46,13 @@ static unsigned long __initdata doc_locations[] = {
 	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
 	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
 	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
 	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
 	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
 	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
-#else /*  CONFIG_MTD_DOCPROBE_HIGH */
+#else
 	0xc8000, 0xca000, 0xcc000, 0xce000,
 	0xc8000, 0xca000, 0xcc000, 0xce000,
 	0xd0000, 0xd2000, 0xd4000, 0xd6000,
 	0xd0000, 0xd2000, 0xd4000, 0xd6000,
 	0xd8000, 0xda000, 0xdc000, 0xde000,
 	0xd8000, 0xda000, 0xdc000, 0xde000,
 	0xe0000, 0xe2000, 0xe4000, 0xe6000,
 	0xe0000, 0xe2000, 0xe4000, 0xe6000,
 	0xe8000, 0xea000, 0xec000, 0xee000,
 	0xe8000, 0xea000, 0xec000, 0xee000,
-#endif /*  CONFIG_MTD_DOCPROBE_HIGH */
+#endif
 #endif
 #endif
 	0xffffffff };
 	0xffffffff };
 
 

+ 0 - 8
drivers/mtd/nand/docg4.c

@@ -1093,7 +1093,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	struct nand_chip *nand = mtd->priv;
 	struct nand_chip *nand = mtd->priv;
 	struct docg4_priv *doc = nand->priv;
 	struct docg4_priv *doc = nand->priv;
 	struct nand_bbt_descr *bbtd = nand->badblock_pattern;
 	struct nand_bbt_descr *bbtd = nand->badblock_pattern;
-	int block = (int)(ofs >> nand->bbt_erase_shift);
 	int page = (int)(ofs >> nand->page_shift);
 	int page = (int)(ofs >> nand->page_shift);
 	uint32_t g4_addr = mtd_to_docg4_address(page, 0);
 	uint32_t g4_addr = mtd_to_docg4_address(page, 0);
 
 
@@ -1108,9 +1107,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	if (buf == NULL)
 	if (buf == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	/* update bbt in memory */
-	nand->bbt[block / 4] |= 0x01 << ((block & 0x03) * 2);
-
 	/* write bit-wise negation of pattern to oob buffer */
 	/* write bit-wise negation of pattern to oob buffer */
 	memset(nand->oob_poi, 0xff, mtd->oobsize);
 	memset(nand->oob_poi, 0xff, mtd->oobsize);
 	for (i = 0; i < bbtd->len; i++)
 	for (i = 0; i < bbtd->len; i++)
@@ -1120,8 +1116,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	write_page_prologue(mtd, g4_addr);
 	write_page_prologue(mtd, g4_addr);
 	docg4_write_page(mtd, nand, buf, 1);
 	docg4_write_page(mtd, nand, buf, 1);
 	ret = pageprog(mtd);
 	ret = pageprog(mtd);
-	if (!ret)
-		mtd->ecc_stats.badblocks++;
 
 
 	kfree(buf);
 	kfree(buf);
 
 
@@ -1368,7 +1362,6 @@ static int __init probe_docg4(struct platform_device *pdev)
 		struct nand_chip *nand = mtd->priv;
 		struct nand_chip *nand = mtd->priv;
 		struct docg4_priv *doc = nand->priv;
 		struct docg4_priv *doc = nand->priv;
 		nand_release(mtd); /* deletes partitions and mtd devices */
 		nand_release(mtd); /* deletes partitions and mtd devices */
-		platform_set_drvdata(pdev, NULL);
 		free_bch(doc->bch);
 		free_bch(doc->bch);
 		kfree(mtd);
 		kfree(mtd);
 	}
 	}
@@ -1380,7 +1373,6 @@ static int __exit cleanup_docg4(struct platform_device *pdev)
 {
 {
 	struct docg4_priv *doc = platform_get_drvdata(pdev);
 	struct docg4_priv *doc = platform_get_drvdata(pdev);
 	nand_release(doc->mtd);
 	nand_release(doc->mtd);
-	platform_set_drvdata(pdev, NULL);
 	free_bch(doc->bch);
 	free_bch(doc->bch);
 	kfree(doc->mtd);
 	kfree(doc->mtd);
 	iounmap(doc->virtadr);
 	iounmap(doc->virtadr);

+ 1 - 2
drivers/mtd/nand/fsl_ifc_nand.c

@@ -823,7 +823,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
 
 	/* set up nand options */
 	/* set up nand options */
 	chip->bbt_options = NAND_BBT_USE_FLASH;
 	chip->bbt_options = NAND_BBT_USE_FLASH;
-
+	chip->options = NAND_NO_SUBPAGE_WRITE;
 
 
 	if (ioread32be(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
 	if (ioread32be(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
 		chip->read_byte = fsl_ifc_read_byte16;
 		chip->read_byte = fsl_ifc_read_byte16;
@@ -908,7 +908,6 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
 
 
 	ifc_nand_ctrl->chips[priv->bank] = NULL;
 	ifc_nand_ctrl->chips[priv->bank] = NULL;
 	dev_set_drvdata(priv->dev, NULL);
 	dev_set_drvdata(priv->dev, NULL);
-	kfree(priv);
 
 
 	return 0;
 	return 0;
 }
 }

+ 20 - 18
drivers/mtd/nand/fsmc_nand.c

@@ -889,6 +889,24 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
 	if (of_get_property(np, "nand-skip-bbtscan", NULL))
 	if (of_get_property(np, "nand-skip-bbtscan", NULL))
 		pdata->options = NAND_SKIP_BBTSCAN;
 		pdata->options = NAND_SKIP_BBTSCAN;
 
 
+	pdata->nand_timings = devm_kzalloc(&pdev->dev,
+				sizeof(*pdata->nand_timings), GFP_KERNEL);
+	if (!pdata->nand_timings) {
+		dev_err(&pdev->dev, "no memory for nand_timing\n");
+		return -ENOMEM;
+	}
+	of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
+						sizeof(*pdata->nand_timings));
+
+	/* Set default NAND bank to 0 */
+	pdata->bank = 0;
+	if (!of_property_read_u32(np, "bank", &val)) {
+		if (val > 3) {
+			dev_err(&pdev->dev, "invalid bank %u\n", val);
+			return -EINVAL;
+		}
+		pdata->bank = val;
+	}
 	return 0;
 	return 0;
 }
 }
 #else
 #else
@@ -940,9 +958,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
-	if (!res)
-		return -EINVAL;
-
 	host->data_va = devm_ioremap_resource(&pdev->dev, res);
 	host->data_va = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(host->data_va))
 	if (IS_ERR(host->data_va))
 		return PTR_ERR(host->data_va);
 		return PTR_ERR(host->data_va);
@@ -950,25 +965,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 	host->data_pa = (dma_addr_t)res->start;
 	host->data_pa = (dma_addr_t)res->start;
 
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
-	if (!res)
-		return -EINVAL;
-
 	host->addr_va = devm_ioremap_resource(&pdev->dev, res);
 	host->addr_va = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(host->addr_va))
 	if (IS_ERR(host->addr_va))
 		return PTR_ERR(host->addr_va);
 		return PTR_ERR(host->addr_va);
 
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
-	if (!res)
-		return -EINVAL;
-
 	host->cmd_va = devm_ioremap_resource(&pdev->dev, res);
 	host->cmd_va = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(host->cmd_va))
 	if (IS_ERR(host->cmd_va))
 		return PTR_ERR(host->cmd_va);
 		return PTR_ERR(host->cmd_va);
 
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
-	if (!res)
-		return -EINVAL;
-
 	host->regs_va = devm_ioremap_resource(&pdev->dev, res);
 	host->regs_va = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(host->regs_va))
 	if (IS_ERR(host->regs_va))
 		return PTR_ERR(host->regs_va);
 		return PTR_ERR(host->regs_va);
@@ -1174,8 +1180,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
 {
 {
 	struct fsmc_nand_data *host = platform_get_drvdata(pdev);
 	struct fsmc_nand_data *host = platform_get_drvdata(pdev);
 
 
-	platform_set_drvdata(pdev, NULL);
-
 	if (host) {
 	if (host) {
 		nand_release(&host->mtd);
 		nand_release(&host->mtd);
 
 
@@ -1190,7 +1194,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int fsmc_nand_suspend(struct device *dev)
 static int fsmc_nand_suspend(struct device *dev)
 {
 {
 	struct fsmc_nand_data *host = dev_get_drvdata(dev);
 	struct fsmc_nand_data *host = dev_get_drvdata(dev);
@@ -1210,9 +1214,9 @@ static int fsmc_nand_resume(struct device *dev)
 	}
 	}
 	return 0;
 	return 0;
 }
 }
+#endif
 
 
 static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
 static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
-#endif
 
 
 #ifdef CONFIG_OF
 #ifdef CONFIG_OF
 static const struct of_device_id fsmc_nand_id_table[] = {
 static const struct of_device_id fsmc_nand_id_table[] = {
@@ -1229,9 +1233,7 @@ static struct platform_driver fsmc_nand_driver = {
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 		.name = "fsmc-nand",
 		.name = "fsmc-nand",
 		.of_match_table = of_match_ptr(fsmc_nand_id_table),
 		.of_match_table = of_match_ptr(fsmc_nand_id_table),
-#ifdef CONFIG_PM
 		.pm = &fsmc_nand_pm_ops,
 		.pm = &fsmc_nand_pm_ops,
-#endif
 	},
 	},
 };
 };
 
 

+ 61 - 170
drivers/mtd/nand/gpio.c

@@ -17,6 +17,7 @@
  */
  */
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/module.h>
@@ -86,59 +87,11 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 	gpio_nand_dosync(gpiomtd);
 	gpio_nand_dosync(gpiomtd);
 }
 }
 
 
-static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-	struct nand_chip *this = mtd->priv;
-
-	iowrite8_rep(this->IO_ADDR_W, buf, len);
-}
-
-static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *this = mtd->priv;
-
-	ioread8_rep(this->IO_ADDR_R, buf, len);
-}
-
-static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
-				 int len)
-{
-	struct nand_chip *this = mtd->priv;
-
-	if (IS_ALIGNED((unsigned long)buf, 2)) {
-		iowrite16_rep(this->IO_ADDR_W, buf, len>>1);
-	} else {
-		int i;
-		unsigned short *ptr = (unsigned short *)buf;
-
-		for (i = 0; i < len; i += 2, ptr++)
-			writew(*ptr, this->IO_ADDR_W);
-	}
-}
-
-static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
-{
-	struct nand_chip *this = mtd->priv;
-
-	if (IS_ALIGNED((unsigned long)buf, 2)) {
-		ioread16_rep(this->IO_ADDR_R, buf, len>>1);
-	} else {
-		int i;
-		unsigned short *ptr = (unsigned short *)buf;
-
-		for (i = 0; i < len; i += 2, ptr++)
-			*ptr = readw(this->IO_ADDR_R);
-	}
-}
-
 static int gpio_nand_devready(struct mtd_info *mtd)
 static int gpio_nand_devready(struct mtd_info *mtd)
 {
 {
 	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
 	struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
 
 
-	if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
-		return gpio_get_value(gpiomtd->plat.gpio_rdy);
-
-	return 1;
+	return gpio_get_value(gpiomtd->plat.gpio_rdy);
 }
 }
 
 
 #ifdef CONFIG_OF
 #ifdef CONFIG_OF
@@ -153,6 +106,9 @@ static int gpio_nand_get_config_of(const struct device *dev,
 {
 {
 	u32 val;
 	u32 val;
 
 
+	if (!dev->of_node)
+		return -ENODEV;
+
 	if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
 	if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
 		if (val == 2) {
 		if (val == 2) {
 			plat->options |= NAND_BUSWIDTH_16;
 			plat->options |= NAND_BUSWIDTH_16;
@@ -211,8 +167,8 @@ static inline int gpio_nand_get_config(const struct device *dev,
 	if (!ret)
 	if (!ret)
 		return ret;
 		return ret;
 
 
-	if (dev->platform_data) {
-		memcpy(plat, dev->platform_data, sizeof(*plat));
+	if (dev_get_platdata(dev)) {
+		memcpy(plat, dev_get_platdata(dev), sizeof(*plat));
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -230,145 +186,100 @@ gpio_nand_get_io_sync(struct platform_device *pdev)
 	return platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	return platform_get_resource(pdev, IORESOURCE_MEM, 1);
 }
 }
 
 
-static int gpio_nand_remove(struct platform_device *dev)
+static int gpio_nand_remove(struct platform_device *pdev)
 {
 {
-	struct gpiomtd *gpiomtd = platform_get_drvdata(dev);
-	struct resource *res;
+	struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
 
 
 	nand_release(&gpiomtd->mtd_info);
 	nand_release(&gpiomtd->mtd_info);
 
 
-	res = gpio_nand_get_io_sync(dev);
-	iounmap(gpiomtd->io_sync);
-	if (res)
-		release_mem_region(res->start, resource_size(res));
-
-	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	iounmap(gpiomtd->nand_chip.IO_ADDR_R);
-	release_mem_region(res->start, resource_size(res));
-
 	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
 	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
 		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
 		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
 	gpio_set_value(gpiomtd->plat.gpio_nce, 1);
 	gpio_set_value(gpiomtd->plat.gpio_nce, 1);
 
 
-	gpio_free(gpiomtd->plat.gpio_cle);
-	gpio_free(gpiomtd->plat.gpio_ale);
-	gpio_free(gpiomtd->plat.gpio_nce);
-	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
-		gpio_free(gpiomtd->plat.gpio_nwp);
-	if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
-		gpio_free(gpiomtd->plat.gpio_rdy);
-
 	return 0;
 	return 0;
 }
 }
 
 
-static void __iomem *request_and_remap(struct resource *res, size_t size,
-					const char *name, int *err)
-{
-	void __iomem *ptr;
-
-	if (!request_mem_region(res->start, resource_size(res), name)) {
-		*err = -EBUSY;
-		return NULL;
-	}
-
-	ptr = ioremap(res->start, size);
-	if (!ptr) {
-		release_mem_region(res->start, resource_size(res));
-		*err = -ENOMEM;
-	}
-	return ptr;
-}
-
-static int gpio_nand_probe(struct platform_device *dev)
+static int gpio_nand_probe(struct platform_device *pdev)
 {
 {
 	struct gpiomtd *gpiomtd;
 	struct gpiomtd *gpiomtd;
-	struct nand_chip *this;
-	struct resource *res0, *res1;
+	struct nand_chip *chip;
+	struct resource *res;
 	struct mtd_part_parser_data ppdata = {};
 	struct mtd_part_parser_data ppdata = {};
 	int ret = 0;
 	int ret = 0;
 
 
-	if (!dev->dev.of_node && !dev->dev.platform_data)
-		return -EINVAL;
-
-	res0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	if (!res0)
+	if (!pdev->dev.of_node && !dev_get_platdata(&pdev->dev))
 		return -EINVAL;
 		return -EINVAL;
 
 
-	gpiomtd = devm_kzalloc(&dev->dev, sizeof(*gpiomtd), GFP_KERNEL);
-	if (gpiomtd == NULL) {
-		dev_err(&dev->dev, "failed to create NAND MTD\n");
+	gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
+	if (!gpiomtd) {
+		dev_err(&pdev->dev, "failed to create NAND MTD\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
-	this = &gpiomtd->nand_chip;
-	this->IO_ADDR_R = request_and_remap(res0, 2, "NAND", &ret);
-	if (!this->IO_ADDR_R) {
-		dev_err(&dev->dev, "unable to map NAND\n");
-		goto err_map;
-	}
+	chip = &gpiomtd->nand_chip;
 
 
-	res1 = gpio_nand_get_io_sync(dev);
-	if (res1) {
-		gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret);
-		if (!gpiomtd->io_sync) {
-			dev_err(&dev->dev, "unable to map sync NAND\n");
-			goto err_sync;
-		}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(chip->IO_ADDR_R))
+		return PTR_ERR(chip->IO_ADDR_R);
+
+	res = gpio_nand_get_io_sync(pdev);
+	if (res) {
+		gpiomtd->io_sync = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(gpiomtd->io_sync))
+			return PTR_ERR(gpiomtd->io_sync);
 	}
 	}
 
 
-	ret = gpio_nand_get_config(&dev->dev, &gpiomtd->plat);
+	ret = gpio_nand_get_config(&pdev->dev, &gpiomtd->plat);
 	if (ret)
 	if (ret)
-		goto err_nce;
+		return ret;
 
 
-	ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE");
+	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce, "NAND NCE");
 	if (ret)
 	if (ret)
-		goto err_nce;
+		return ret;
 	gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
 	gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
+
 	if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
 	if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
-		ret = gpio_request(gpiomtd->plat.gpio_nwp, "NAND NWP");
+		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp,
+					"NAND NWP");
 		if (ret)
 		if (ret)
-			goto err_nwp;
-		gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
+			return ret;
 	}
 	}
-	ret = gpio_request(gpiomtd->plat.gpio_ale, "NAND ALE");
+
+	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_ale, "NAND ALE");
 	if (ret)
 	if (ret)
-		goto err_ale;
+		return ret;
 	gpio_direction_output(gpiomtd->plat.gpio_ale, 0);
 	gpio_direction_output(gpiomtd->plat.gpio_ale, 0);
-	ret = gpio_request(gpiomtd->plat.gpio_cle, "NAND CLE");
+
+	ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_cle, "NAND CLE");
 	if (ret)
 	if (ret)
-		goto err_cle;
+		return ret;
 	gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
 	gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
+
 	if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
 	if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
-		ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
+		ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_rdy,
+					"NAND RDY");
 		if (ret)
 		if (ret)
-			goto err_rdy;
+			return ret;
 		gpio_direction_input(gpiomtd->plat.gpio_rdy);
 		gpio_direction_input(gpiomtd->plat.gpio_rdy);
+		chip->dev_ready = gpio_nand_devready;
 	}
 	}
 
 
+	chip->IO_ADDR_W		= chip->IO_ADDR_R;
+	chip->ecc.mode		= NAND_ECC_SOFT;
+	chip->options		= gpiomtd->plat.options;
+	chip->chip_delay	= gpiomtd->plat.chip_delay;
+	chip->cmd_ctrl		= gpio_nand_cmd_ctrl;
 
 
-	this->IO_ADDR_W  = this->IO_ADDR_R;
-	this->ecc.mode   = NAND_ECC_SOFT;
-	this->options    = gpiomtd->plat.options;
-	this->chip_delay = gpiomtd->plat.chip_delay;
-
-	/* install our routines */
-	this->cmd_ctrl   = gpio_nand_cmd_ctrl;
-	this->dev_ready  = gpio_nand_devready;
+	gpiomtd->mtd_info.priv	= chip;
+	gpiomtd->mtd_info.owner	= THIS_MODULE;
 
 
-	if (this->options & NAND_BUSWIDTH_16) {
-		this->read_buf   = gpio_nand_readbuf16;
-		this->write_buf  = gpio_nand_writebuf16;
-	} else {
-		this->read_buf   = gpio_nand_readbuf;
-		this->write_buf  = gpio_nand_writebuf;
-	}
+	platform_set_drvdata(pdev, gpiomtd);
 
 
-	/* set the mtd private data for the nand driver */
-	gpiomtd->mtd_info.priv = this;
-	gpiomtd->mtd_info.owner = THIS_MODULE;
+	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+		gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
 
 
 	if (nand_scan(&gpiomtd->mtd_info, 1)) {
 	if (nand_scan(&gpiomtd->mtd_info, 1)) {
-		dev_err(&dev->dev, "no nand chips found?\n");
 		ret = -ENXIO;
 		ret = -ENXIO;
 		goto err_wp;
 		goto err_wp;
 	}
 	}
@@ -377,38 +288,17 @@ static int gpio_nand_probe(struct platform_device *dev)
 		gpiomtd->plat.adjust_parts(&gpiomtd->plat,
 		gpiomtd->plat.adjust_parts(&gpiomtd->plat,
 					   gpiomtd->mtd_info.size);
 					   gpiomtd->mtd_info.size);
 
 
-	ppdata.of_node = dev->dev.of_node;
+	ppdata.of_node = pdev->dev.of_node;
 	ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata,
 	ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata,
 					gpiomtd->plat.parts,
 					gpiomtd->plat.parts,
 					gpiomtd->plat.num_parts);
 					gpiomtd->plat.num_parts);
-	if (ret)
-		goto err_wp;
-	platform_set_drvdata(dev, gpiomtd);
-
-	return 0;
+	if (!ret)
+		return 0;
 
 
 err_wp:
 err_wp:
 	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
 	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
 		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
 		gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
-	if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
-		gpio_free(gpiomtd->plat.gpio_rdy);
-err_rdy:
-	gpio_free(gpiomtd->plat.gpio_cle);
-err_cle:
-	gpio_free(gpiomtd->plat.gpio_ale);
-err_ale:
-	if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
-		gpio_free(gpiomtd->plat.gpio_nwp);
-err_nwp:
-	gpio_free(gpiomtd->plat.gpio_nce);
-err_nce:
-	iounmap(gpiomtd->io_sync);
-	if (res1)
-		release_mem_region(res1->start, resource_size(res1));
-err_sync:
-	iounmap(gpiomtd->nand_chip.IO_ADDR_R);
-	release_mem_region(res0->start, resource_size(res0));
-err_map:
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -417,6 +307,7 @@ static struct platform_driver gpio_nand_driver = {
 	.remove		= gpio_nand_remove,
 	.remove		= gpio_nand_remove,
 	.driver		= {
 	.driver		= {
 		.name	= "gpio-nand",
 		.name	= "gpio-nand",
+		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(gpio_nand_id_table),
 		.of_match_table = of_match_ptr(gpio_nand_id_table),
 	},
 	},
 };
 };

+ 192 - 76
drivers/mtd/nand/gpmi-nand/gpmi-nand.c

@@ -26,7 +26,6 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
 #include <linux/of_mtd.h>
 #include <linux/of_mtd.h>
@@ -112,7 +111,131 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
 	return true;
 	return true;
 }
 }
 
 
-int common_nfc_set_geometry(struct gpmi_nand_data *this)
+/*
+ * If we can get the ECC information from the nand chip, we do not
+ * need to calculate them ourselves.
+ *
+ * We may have available oob space in this case.
+ */
+static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
+{
+	struct bch_geometry *geo = &this->bch_geometry;
+	struct mtd_info *mtd = &this->mtd;
+	struct nand_chip *chip = mtd->priv;
+	struct nand_oobfree *of = gpmi_hw_ecclayout.oobfree;
+	unsigned int block_mark_bit_offset;
+
+	if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
+		return false;
+
+	switch (chip->ecc_step_ds) {
+	case SZ_512:
+		geo->gf_len = 13;
+		break;
+	case SZ_1K:
+		geo->gf_len = 14;
+		break;
+	default:
+		dev_err(this->dev,
+			"unsupported nand chip. ecc bits : %d, ecc size : %d\n",
+			chip->ecc_strength_ds, chip->ecc_step_ds);
+		return false;
+	}
+	geo->ecc_chunk_size = chip->ecc_step_ds;
+	geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
+	if (!gpmi_check_ecc(this))
+		return false;
+
+	/* Keep the C >= O */
+	if (geo->ecc_chunk_size < mtd->oobsize) {
+		dev_err(this->dev,
+			"unsupported nand chip. ecc size: %d, oob size : %d\n",
+			chip->ecc_step_ds, mtd->oobsize);
+		return false;
+	}
+
+	/* The default value, see comment in the legacy_set_geometry(). */
+	geo->metadata_size = 10;
+
+	geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+
+	/*
+	 * Now, the NAND chip with 2K page(data chunk is 512byte) shows below:
+	 *
+	 *    |                          P                            |
+	 *    |<----------------------------------------------------->|
+	 *    |                                                       |
+	 *    |                                        (Block Mark)   |
+	 *    |                      P'                      |      | |     |
+	 *    |<-------------------------------------------->|  D   | |  O' |
+	 *    |                                              |<---->| |<--->|
+	 *    V                                              V      V V     V
+	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
+	 *    | M |   data   |E|   data   |E|   data   |E|   data   |E|     |
+	 *    +---+----------+-+----------+-+----------+-+----------+-+-----+
+	 *                                                   ^              ^
+	 *                                                   |      O       |
+	 *                                                   |<------------>|
+	 *                                                   |              |
+	 *
+	 *	P : the page size for BCH module.
+	 *	E : The ECC strength.
+	 *	G : the length of Galois Field.
+	 *	N : The chunk count of per page.
+	 *	M : the metasize of per page.
+	 *	C : the ecc chunk size, aka the "data" above.
+	 *	P': the nand chip's page size.
+	 *	O : the nand chip's oob size.
+	 *	O': the free oob.
+	 *
+	 *	The formula for P is :
+	 *
+	 *	            E * G * N
+	 *	       P = ------------ + P' + M
+	 *                      8
+	 *
+	 * The position of block mark moves forward in the ECC-based view
+	 * of page, and the delta is:
+	 *
+	 *                   E * G * (N - 1)
+	 *             D = (---------------- + M)
+	 *                          8
+	 *
+	 * Please see the comment in legacy_set_geometry().
+	 * With the condition C >= O , we still can get same result.
+	 * So the bit position of the physical block mark within the ECC-based
+	 * view of the page is :
+	 *             (P' - D) * 8
+	 */
+	geo->page_size = mtd->writesize + geo->metadata_size +
+		(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
+
+	/* The available oob size we have. */
+	if (geo->page_size < mtd->writesize + mtd->oobsize) {
+		of->offset = geo->page_size - mtd->writesize;
+		of->length = mtd->oobsize - of->offset;
+	}
+
+	geo->payload_size = mtd->writesize;
+
+	geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
+	geo->auxiliary_size = ALIGN(geo->metadata_size, 4)
+				+ ALIGN(geo->ecc_chunk_count, 4);
+
+	if (!this->swap_block_mark)
+		return true;
+
+	/* For bit swap. */
+	block_mark_bit_offset = mtd->writesize * 8 -
+		(geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
+				+ geo->metadata_size * 8);
+
+	geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+	geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
+	return true;
+}
+
+static int legacy_set_geometry(struct gpmi_nand_data *this)
 {
 {
 	struct bch_geometry *geo = &this->bch_geometry;
 	struct bch_geometry *geo = &this->bch_geometry;
 	struct mtd_info *mtd = &this->mtd;
 	struct mtd_info *mtd = &this->mtd;
@@ -224,6 +347,11 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
 	return 0;
 	return 0;
 }
 }
 
 
+int common_nfc_set_geometry(struct gpmi_nand_data *this)
+{
+	return set_geometry_by_ecc_info(this) ? 0 : legacy_set_geometry(this);
+}
+
 struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
 struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
 {
 {
 	int chipnr = this->current_chip;
 	int chipnr = this->current_chip;
@@ -355,7 +483,7 @@ static int acquire_register_block(struct gpmi_nand_data *this,
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
 	if (!r) {
 	if (!r) {
 		pr_err("Can't get resource for %s\n", res_name);
 		pr_err("Can't get resource for %s\n", res_name);
-		return -ENXIO;
+		return -ENODEV;
 	}
 	}
 
 
 	p = ioremap(r->start, resource_size(r));
 	p = ioremap(r->start, resource_size(r));
@@ -396,7 +524,7 @@ static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
 	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
 	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
 	if (!r) {
 	if (!r) {
 		pr_err("Can't get resource for %s\n", res_name);
 		pr_err("Can't get resource for %s\n", res_name);
-		return -ENXIO;
+		return -ENODEV;
 	}
 	}
 
 
 	err = request_irq(r->start, irq_h, 0, res_name, this);
 	err = request_irq(r->start, irq_h, 0, res_name, this);
@@ -473,12 +601,14 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
 	struct resources *r = &this->resources;
 	struct resources *r = &this->resources;
 	char **extra_clks = NULL;
 	char **extra_clks = NULL;
 	struct clk *clk;
 	struct clk *clk;
-	int i;
+	int err, i;
 
 
 	/* The main clock is stored in the first. */
 	/* The main clock is stored in the first. */
 	r->clock[0] = clk_get(this->dev, "gpmi_io");
 	r->clock[0] = clk_get(this->dev, "gpmi_io");
-	if (IS_ERR(r->clock[0]))
+	if (IS_ERR(r->clock[0])) {
+		err = PTR_ERR(r->clock[0]);
 		goto err_clock;
 		goto err_clock;
+	}
 
 
 	/* Get extra clocks */
 	/* Get extra clocks */
 	if (GPMI_IS_MX6Q(this))
 	if (GPMI_IS_MX6Q(this))
@@ -491,8 +621,10 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
 			break;
 			break;
 
 
 		clk = clk_get(this->dev, extra_clks[i - 1]);
 		clk = clk_get(this->dev, extra_clks[i - 1]);
-		if (IS_ERR(clk))
+		if (IS_ERR(clk)) {
+			err = PTR_ERR(clk);
 			goto err_clock;
 			goto err_clock;
+		}
 
 
 		r->clock[i] = clk;
 		r->clock[i] = clk;
 	}
 	}
@@ -511,12 +643,11 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
 err_clock:
 err_clock:
 	dev_dbg(this->dev, "failed in finding the clocks.\n");
 	dev_dbg(this->dev, "failed in finding the clocks.\n");
 	gpmi_put_clks(this);
 	gpmi_put_clks(this);
-	return -ENOMEM;
+	return err;
 }
 }
 
 
 static int acquire_resources(struct gpmi_nand_data *this)
 static int acquire_resources(struct gpmi_nand_data *this)
 {
 {
-	struct pinctrl *pinctrl;
 	int ret;
 	int ret;
 
 
 	ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
 	ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
@@ -535,19 +666,12 @@ static int acquire_resources(struct gpmi_nand_data *this)
 	if (ret)
 	if (ret)
 		goto exit_dma_channels;
 		goto exit_dma_channels;
 
 
-	pinctrl = devm_pinctrl_get_select_default(&this->pdev->dev);
-	if (IS_ERR(pinctrl)) {
-		ret = PTR_ERR(pinctrl);
-		goto exit_pin;
-	}
-
 	ret = gpmi_get_clks(this);
 	ret = gpmi_get_clks(this);
 	if (ret)
 	if (ret)
 		goto exit_clock;
 		goto exit_clock;
 	return 0;
 	return 0;
 
 
 exit_clock:
 exit_clock:
-exit_pin:
 	release_dma_channels(this);
 	release_dma_channels(this);
 exit_dma_channels:
 exit_dma_channels:
 	release_bch_irq(this);
 	release_bch_irq(this);
@@ -1153,43 +1277,31 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
 {
 	struct nand_chip *chip = mtd->priv;
 	struct nand_chip *chip = mtd->priv;
 	struct gpmi_nand_data *this = chip->priv;
 	struct gpmi_nand_data *this = chip->priv;
-	int block, ret = 0;
+	int ret = 0;
 	uint8_t *block_mark;
 	uint8_t *block_mark;
 	int column, page, status, chipnr;
 	int column, page, status, chipnr;
 
 
-	/* Get block number */
-	block = (int)(ofs >> chip->bbt_erase_shift);
-	if (chip->bbt)
-		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+	chipnr = (int)(ofs >> chip->chip_shift);
+	chip->select_chip(mtd, chipnr);
 
 
-	/* Do we have a flash based bad block table ? */
-	if (chip->bbt_options & NAND_BBT_USE_FLASH)
-		ret = nand_update_bbt(mtd, ofs);
-	else {
-		chipnr = (int)(ofs >> chip->chip_shift);
-		chip->select_chip(mtd, chipnr);
+	column = this->swap_block_mark ? mtd->writesize : 0;
 
 
-		column = this->swap_block_mark ? mtd->writesize : 0;
+	/* Write the block mark. */
+	block_mark = this->data_buffer_dma;
+	block_mark[0] = 0; /* bad block marker */
 
 
-		/* Write the block mark. */
-		block_mark = this->data_buffer_dma;
-		block_mark[0] = 0; /* bad block marker */
+	/* Shift to get page */
+	page = (int)(ofs >> chip->page_shift);
 
 
-		/* Shift to get page */
-		page = (int)(ofs >> chip->page_shift);
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
+	chip->write_buf(mtd, block_mark, 1);
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 
 
-		chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
-		chip->write_buf(mtd, block_mark, 1);
-		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	status = chip->waitfunc(mtd, chip);
+	if (status & NAND_STATUS_FAIL)
+		ret = -EIO;
 
 
-		status = chip->waitfunc(mtd, chip);
-		if (status & NAND_STATUS_FAIL)
-			ret = -EIO;
-
-		chip->select_chip(mtd, -1);
-	}
-	if (!ret)
-		mtd->ecc_stats.badblocks++;
+	chip->select_chip(mtd, -1);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -1469,19 +1581,22 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data  *this)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	/* Adjust the ECC strength according to the chip. */
-	this->nand.ecc.strength = this->bch_geometry.ecc_strength;
-	this->mtd.ecc_strength = this->bch_geometry.ecc_strength;
-	this->mtd.bitflip_threshold = this->bch_geometry.ecc_strength;
-
 	/* NAND boot init, depends on the gpmi_set_geometry(). */
 	/* NAND boot init, depends on the gpmi_set_geometry(). */
 	return nand_boot_init(this);
 	return nand_boot_init(this);
 }
 }
 
 
-static int gpmi_scan_bbt(struct mtd_info *mtd)
+static void gpmi_nfc_exit(struct gpmi_nand_data *this)
 {
 {
+	nand_release(&this->mtd);
+	gpmi_free_dma_buffer(this);
+}
+
+static int gpmi_init_last(struct gpmi_nand_data *this)
+{
+	struct mtd_info *mtd = &this->mtd;
 	struct nand_chip *chip = mtd->priv;
 	struct nand_chip *chip = mtd->priv;
-	struct gpmi_nand_data *this = chip->priv;
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+	struct bch_geometry *bch_geo = &this->bch_geometry;
 	int ret;
 	int ret;
 
 
 	/* Prepare for the BBT scan. */
 	/* Prepare for the BBT scan. */
@@ -1489,6 +1604,16 @@ static int gpmi_scan_bbt(struct mtd_info *mtd)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
+	/* Init the nand_ecc_ctrl{} */
+	ecc->read_page	= gpmi_ecc_read_page;
+	ecc->write_page	= gpmi_ecc_write_page;
+	ecc->read_oob	= gpmi_ecc_read_oob;
+	ecc->write_oob	= gpmi_ecc_write_oob;
+	ecc->mode	= NAND_ECC_HW;
+	ecc->size	= bch_geo->ecc_chunk_size;
+	ecc->strength	= bch_geo->ecc_strength;
+	ecc->layout	= &gpmi_hw_ecclayout;
+
 	/*
 	/*
 	 * Can we enable the extra features? such as EDO or Sync mode.
 	 * Can we enable the extra features? such as EDO or Sync mode.
 	 *
 	 *
@@ -1497,14 +1622,7 @@ static int gpmi_scan_bbt(struct mtd_info *mtd)
 	 */
 	 */
 	gpmi_extra_init(this);
 	gpmi_extra_init(this);
 
 
-	/* use the default BBT implementation */
-	return nand_default_bbt(mtd);
-}
-
-static void gpmi_nfc_exit(struct gpmi_nand_data *this)
-{
-	nand_release(&this->mtd);
-	gpmi_free_dma_buffer(this);
+	return 0;
 }
 }
 
 
 static int gpmi_nfc_init(struct gpmi_nand_data *this)
 static int gpmi_nfc_init(struct gpmi_nand_data *this)
@@ -1530,33 +1648,33 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
 	chip->read_byte		= gpmi_read_byte;
 	chip->read_byte		= gpmi_read_byte;
 	chip->read_buf		= gpmi_read_buf;
 	chip->read_buf		= gpmi_read_buf;
 	chip->write_buf		= gpmi_write_buf;
 	chip->write_buf		= gpmi_write_buf;
-	chip->ecc.read_page	= gpmi_ecc_read_page;
-	chip->ecc.write_page	= gpmi_ecc_write_page;
-	chip->ecc.read_oob	= gpmi_ecc_read_oob;
-	chip->ecc.write_oob	= gpmi_ecc_write_oob;
-	chip->scan_bbt		= gpmi_scan_bbt;
 	chip->badblock_pattern	= &gpmi_bbt_descr;
 	chip->badblock_pattern	= &gpmi_bbt_descr;
 	chip->block_markbad	= gpmi_block_markbad;
 	chip->block_markbad	= gpmi_block_markbad;
 	chip->options		|= NAND_NO_SUBPAGE_WRITE;
 	chip->options		|= NAND_NO_SUBPAGE_WRITE;
-	chip->ecc.mode		= NAND_ECC_HW;
-	chip->ecc.size		= 1;
-	chip->ecc.strength	= 8;
-	chip->ecc.layout	= &gpmi_hw_ecclayout;
 	if (of_get_nand_on_flash_bbt(this->dev->of_node))
 	if (of_get_nand_on_flash_bbt(this->dev->of_node))
 		chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
 		chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
 
 
-	/* Allocate a temporary DMA buffer for reading ID in the nand_scan() */
+	/*
+	 * Allocate a temporary DMA buffer for reading ID in the
+	 * nand_scan_ident().
+	 */
 	this->bch_geometry.payload_size = 1024;
 	this->bch_geometry.payload_size = 1024;
 	this->bch_geometry.auxiliary_size = 128;
 	this->bch_geometry.auxiliary_size = 128;
 	ret = gpmi_alloc_dma_buffer(this);
 	ret = gpmi_alloc_dma_buffer(this);
 	if (ret)
 	if (ret)
 		goto err_out;
 		goto err_out;
 
 
-	ret = nand_scan(mtd, 1);
-	if (ret) {
-		pr_err("Chip scan failed\n");
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret)
+		goto err_out;
+
+	ret = gpmi_init_last(this);
+	if (ret)
+		goto err_out;
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
 		goto err_out;
 		goto err_out;
-	}
 
 
 	ppdata.of_node = this->pdev->dev.of_node;
 	ppdata.of_node = this->pdev->dev.of_node;
 	ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
 	ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
@@ -1601,7 +1719,7 @@ static int gpmi_nand_probe(struct platform_device *pdev)
 		pdev->id_entry = of_id->data;
 		pdev->id_entry = of_id->data;
 	} else {
 	} else {
 		pr_err("Failed to find the right device id.\n");
 		pr_err("Failed to find the right device id.\n");
-		return -ENOMEM;
+		return -ENODEV;
 	}
 	}
 
 
 	this = kzalloc(sizeof(*this), GFP_KERNEL);
 	this = kzalloc(sizeof(*this), GFP_KERNEL);
@@ -1633,7 +1751,6 @@ static int gpmi_nand_probe(struct platform_device *pdev)
 exit_nfc_init:
 exit_nfc_init:
 	release_resources(this);
 	release_resources(this);
 exit_acquire_resources:
 exit_acquire_resources:
-	platform_set_drvdata(pdev, NULL);
 	dev_err(this->dev, "driver registration failed: %d\n", ret);
 	dev_err(this->dev, "driver registration failed: %d\n", ret);
 	kfree(this);
 	kfree(this);
 
 
@@ -1646,7 +1763,6 @@ static int gpmi_nand_remove(struct platform_device *pdev)
 
 
 	gpmi_nfc_exit(this);
 	gpmi_nfc_exit(this);
 	release_resources(this);
 	release_resources(this);
-	platform_set_drvdata(pdev, NULL);
 	kfree(this);
 	kfree(this);
 	return 0;
 	return 0;
 }
 }

+ 2 - 4
drivers/mtd/nand/jz4740_nand.c

@@ -411,7 +411,7 @@ static int jz_nand_probe(struct platform_device *pdev)
 	struct jz_nand *nand;
 	struct jz_nand *nand;
 	struct nand_chip *chip;
 	struct nand_chip *chip;
 	struct mtd_info *mtd;
 	struct mtd_info *mtd;
-	struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
+	struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	size_t chipnr, bank_idx;
 	size_t chipnr, bank_idx;
 	uint8_t nand_maf_id = 0, nand_dev_id = 0;
 	uint8_t nand_maf_id = 0, nand_dev_id = 0;
 
 
@@ -538,7 +538,6 @@ err_unclaim_banks:
 err_gpio_busy:
 err_gpio_busy:
 	if (pdata && gpio_is_valid(pdata->busy_gpio))
 	if (pdata && gpio_is_valid(pdata->busy_gpio))
 		gpio_free(pdata->busy_gpio);
 		gpio_free(pdata->busy_gpio);
-	platform_set_drvdata(pdev, NULL);
 err_iounmap_mmio:
 err_iounmap_mmio:
 	jz_nand_iounmap_resource(nand->mem, nand->base);
 	jz_nand_iounmap_resource(nand->mem, nand->base);
 err_free:
 err_free:
@@ -549,7 +548,7 @@ err_free:
 static int jz_nand_remove(struct platform_device *pdev)
 static int jz_nand_remove(struct platform_device *pdev)
 {
 {
 	struct jz_nand *nand = platform_get_drvdata(pdev);
 	struct jz_nand *nand = platform_get_drvdata(pdev);
-	struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
+	struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	size_t i;
 	size_t i;
 
 
 	nand_release(&nand->mtd);
 	nand_release(&nand->mtd);
@@ -570,7 +569,6 @@ static int jz_nand_remove(struct platform_device *pdev)
 
 
 	jz_nand_iounmap_resource(nand->mem, nand->base);
 	jz_nand_iounmap_resource(nand->mem, nand->base);
 
 
-	platform_set_drvdata(pdev, NULL);
 	kfree(nand);
 	kfree(nand);
 
 
 	return 0;
 	return 0;

+ 1 - 3
drivers/mtd/nand/lpc32xx_mlc.c

@@ -696,7 +696,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 	}
 	}
 	lpc32xx_wp_disable(host);
 	lpc32xx_wp_disable(host);
 
 
-	host->pdata = pdev->dev.platform_data;
+	host->pdata = dev_get_platdata(&pdev->dev);
 
 
 	nand_chip->priv = host;		/* link the private data structures */
 	nand_chip->priv = host;		/* link the private data structures */
 	mtd->priv = nand_chip;
 	mtd->priv = nand_chip;
@@ -828,7 +828,6 @@ err_exit3:
 err_exit2:
 err_exit2:
 	clk_disable(host->clk);
 	clk_disable(host->clk);
 	clk_put(host->clk);
 	clk_put(host->clk);
-	platform_set_drvdata(pdev, NULL);
 err_exit1:
 err_exit1:
 	lpc32xx_wp_enable(host);
 	lpc32xx_wp_enable(host);
 	gpio_free(host->ncfg->wp_gpio);
 	gpio_free(host->ncfg->wp_gpio);
@@ -851,7 +850,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 
 
 	clk_disable(host->clk);
 	clk_disable(host->clk);
 	clk_put(host->clk);
 	clk_put(host->clk);
-	platform_set_drvdata(pdev, NULL);
 
 
 	lpc32xx_wp_enable(host);
 	lpc32xx_wp_enable(host);
 	gpio_free(host->ncfg->wp_gpio);
 	gpio_free(host->ncfg->wp_gpio);

+ 1 - 3
drivers/mtd/nand/lpc32xx_slc.c

@@ -798,7 +798,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 	}
 	}
 	lpc32xx_wp_disable(host);
 	lpc32xx_wp_disable(host);
 
 
-	host->pdata = pdev->dev.platform_data;
+	host->pdata = dev_get_platdata(&pdev->dev);
 
 
 	mtd = &host->mtd;
 	mtd = &host->mtd;
 	chip = &host->nand_chip;
 	chip = &host->nand_chip;
@@ -936,7 +936,6 @@ err_exit3:
 err_exit2:
 err_exit2:
 	clk_disable(host->clk);
 	clk_disable(host->clk);
 	clk_put(host->clk);
 	clk_put(host->clk);
-	platform_set_drvdata(pdev, NULL);
 err_exit1:
 err_exit1:
 	lpc32xx_wp_enable(host);
 	lpc32xx_wp_enable(host);
 	gpio_free(host->ncfg->wp_gpio);
 	gpio_free(host->ncfg->wp_gpio);
@@ -963,7 +962,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 
 
 	clk_disable(host->clk);
 	clk_disable(host->clk);
 	clk_put(host->clk);
 	clk_put(host->clk);
-	platform_set_drvdata(pdev, NULL);
 	lpc32xx_wp_enable(host);
 	lpc32xx_wp_enable(host);
 	gpio_free(host->ncfg->wp_gpio);
 	gpio_free(host->ncfg->wp_gpio);
 
 

+ 3 - 9
drivers/mtd/nand/mxc_nand.c

@@ -266,7 +266,7 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
 	}
 	}
 };
 };
 
 
-static const char const *part_probes[] = {
+static const char * const part_probes[] = {
 	"cmdlinepart", "RedBoot", "ofpart", NULL };
 	"cmdlinepart", "RedBoot", "ofpart", NULL };
 
 
 static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
 static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
@@ -1432,7 +1432,8 @@ static int mxcnd_probe(struct platform_device *pdev)
 
 
 	err = mxcnd_probe_dt(host);
 	err = mxcnd_probe_dt(host);
 	if (err > 0) {
 	if (err > 0) {
-		struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
+		struct mxc_nand_platform_data *pdata =
+					dev_get_platdata(&pdev->dev);
 		if (pdata) {
 		if (pdata) {
 			host->pdata = *pdata;
 			host->pdata = *pdata;
 			host->devtype_data = (struct mxc_nand_devtype_data *)
 			host->devtype_data = (struct mxc_nand_devtype_data *)
@@ -1446,8 +1447,6 @@ static int mxcnd_probe(struct platform_device *pdev)
 
 
 	if (host->devtype_data->needs_ip) {
 	if (host->devtype_data->needs_ip) {
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (!res)
-			return -ENODEV;
 		host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
 		host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
 		if (IS_ERR(host->regs_ip))
 		if (IS_ERR(host->regs_ip))
 			return PTR_ERR(host->regs_ip);
 			return PTR_ERR(host->regs_ip);
@@ -1457,9 +1456,6 @@ static int mxcnd_probe(struct platform_device *pdev)
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	}
 	}
 
 
-	if (!res)
-		return -ENODEV;
-
 	host->base = devm_ioremap_resource(&pdev->dev, res);
 	host->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(host->base))
 	if (IS_ERR(host->base))
 		return PTR_ERR(host->base);
 		return PTR_ERR(host->base);
@@ -1578,8 +1574,6 @@ static int mxcnd_remove(struct platform_device *pdev)
 {
 {
 	struct mxc_nand_host *host = platform_get_drvdata(pdev);
 	struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
 
-	platform_set_drvdata(pdev, NULL);
-
 	nand_release(&host->mtd);
 	nand_release(&host->mtd);
 
 
 	return 0;
 	return 0;

+ 206 - 90
drivers/mtd/nand/nand_base.c

@@ -108,13 +108,13 @@ static int check_offs_len(struct mtd_info *mtd,
 	int ret = 0;
 	int ret = 0;
 
 
 	/* Start address must align on block boundary */
 	/* Start address must align on block boundary */
-	if (ofs & ((1 << chip->phys_erase_shift) - 1)) {
+	if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) {
 		pr_debug("%s: unaligned address\n", __func__);
 		pr_debug("%s: unaligned address\n", __func__);
 		ret = -EINVAL;
 		ret = -EINVAL;
 	}
 	}
 
 
 	/* Length must align on block boundary */
 	/* Length must align on block boundary */
-	if (len & ((1 << chip->phys_erase_shift) - 1)) {
+	if (len & ((1ULL << chip->phys_erase_shift) - 1)) {
 		pr_debug("%s: length not block aligned\n", __func__);
 		pr_debug("%s: length not block aligned\n", __func__);
 		ret = -EINVAL;
 		ret = -EINVAL;
 	}
 	}
@@ -211,11 +211,9 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
  */
  */
 static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
 {
-	int i;
 	struct nand_chip *chip = mtd->priv;
 	struct nand_chip *chip = mtd->priv;
 
 
-	for (i = 0; i < len; i++)
-		writeb(buf[i], chip->IO_ADDR_W);
+	iowrite8_rep(chip->IO_ADDR_W, buf, len);
 }
 }
 
 
 /**
 /**
@@ -228,11 +226,9 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
  */
 static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
 {
-	int i;
 	struct nand_chip *chip = mtd->priv;
 	struct nand_chip *chip = mtd->priv;
 
 
-	for (i = 0; i < len; i++)
-		buf[i] = readb(chip->IO_ADDR_R);
+	ioread8_rep(chip->IO_ADDR_R, buf, len);
 }
 }
 
 
 /**
 /**
@@ -245,14 +241,10 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
  */
  */
 static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
 {
-	int i;
 	struct nand_chip *chip = mtd->priv;
 	struct nand_chip *chip = mtd->priv;
 	u16 *p = (u16 *) buf;
 	u16 *p = (u16 *) buf;
-	len >>= 1;
-
-	for (i = 0; i < len; i++)
-		writew(p[i], chip->IO_ADDR_W);
 
 
+	iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
 }
 }
 
 
 /**
 /**
@@ -265,13 +257,10 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
  */
 static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 {
 {
-	int i;
 	struct nand_chip *chip = mtd->priv;
 	struct nand_chip *chip = mtd->priv;
 	u16 *p = (u16 *) buf;
 	u16 *p = (u16 *) buf;
-	len >>= 1;
 
 
-	for (i = 0; i < len; i++)
-		p[i] = readw(chip->IO_ADDR_R);
+	ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
 }
 }
 
 
 /**
 /**
@@ -335,80 +324,88 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 }
 }
 
 
 /**
 /**
- * nand_default_block_markbad - [DEFAULT] mark a block bad
+ * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
  * @mtd: MTD device structure
  * @mtd: MTD device structure
  * @ofs: offset from device start
  * @ofs: offset from device start
  *
  *
  * This is the default implementation, which can be overridden by a hardware
  * This is the default implementation, which can be overridden by a hardware
- * specific driver. We try operations in the following order, according to our
- * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
+ * specific driver. It provides the details for writing a bad block marker to a
+ * block.
+ */
+static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mtd_oob_ops ops;
+	uint8_t buf[2] = { 0, 0 };
+	int ret = 0, res, i = 0;
+
+	ops.datbuf = NULL;
+	ops.oobbuf = buf;
+	ops.ooboffs = chip->badblockpos;
+	if (chip->options & NAND_BUSWIDTH_16) {
+		ops.ooboffs &= ~0x01;
+		ops.len = ops.ooblen = 2;
+	} else {
+		ops.len = ops.ooblen = 1;
+	}
+	ops.mode = MTD_OPS_PLACE_OOB;
+
+	/* Write to first/last page(s) if necessary */
+	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+		ofs += mtd->erasesize - mtd->writesize;
+	do {
+		res = nand_do_write_oob(mtd, ofs, &ops);
+		if (!ret)
+			ret = res;
+
+		i++;
+		ofs += mtd->writesize;
+	} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+
+	return ret;
+}
+
+/**
+ * nand_block_markbad_lowlevel - mark a block bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * This function performs the generic NAND bad block marking steps (i.e., bad
+ * block table(s) and/or marker(s)). We only allow the hardware driver to
+ * specify how to write bad block markers to OOB (chip->block_markbad).
+ *
+ * We try operations in the following order:
  *  (1) erase the affected block, to allow OOB marker to be written cleanly
  *  (1) erase the affected block, to allow OOB marker to be written cleanly
- *  (2) update in-memory BBT
- *  (3) write bad block marker to OOB area of affected block
- *  (4) update flash-based BBT
- * Note that we retain the first error encountered in (3) or (4), finish the
+ *  (2) write bad block marker to OOB area of affected block (unless flag
+ *      NAND_BBT_NO_OOB_BBM is present)
+ *  (3) update the BBT
+ * Note that we retain the first error encountered in (2) or (3), finish the
  * procedures, and dump the error in the end.
  * procedures, and dump the error in the end.
 */
 */
-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
 {
 {
 	struct nand_chip *chip = mtd->priv;
 	struct nand_chip *chip = mtd->priv;
-	uint8_t buf[2] = { 0, 0 };
-	int block, res, ret = 0, i = 0;
-	int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
+	int res, ret = 0;
 
 
-	if (write_oob) {
+	if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
 		struct erase_info einfo;
 		struct erase_info einfo;
 
 
 		/* Attempt erase before marking OOB */
 		/* Attempt erase before marking OOB */
 		memset(&einfo, 0, sizeof(einfo));
 		memset(&einfo, 0, sizeof(einfo));
 		einfo.mtd = mtd;
 		einfo.mtd = mtd;
 		einfo.addr = ofs;
 		einfo.addr = ofs;
-		einfo.len = 1 << chip->phys_erase_shift;
+		einfo.len = 1ULL << chip->phys_erase_shift;
 		nand_erase_nand(mtd, &einfo, 0);
 		nand_erase_nand(mtd, &einfo, 0);
-	}
-
-	/* Get block number */
-	block = (int)(ofs >> chip->bbt_erase_shift);
-	/* Mark block bad in memory-based BBT */
-	if (chip->bbt)
-		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
-
-	/* Write bad block marker to OOB */
-	if (write_oob) {
-		struct mtd_oob_ops ops;
-		loff_t wr_ofs = ofs;
 
 
+		/* Write bad block marker to OOB */
 		nand_get_device(mtd, FL_WRITING);
 		nand_get_device(mtd, FL_WRITING);
-
-		ops.datbuf = NULL;
-		ops.oobbuf = buf;
-		ops.ooboffs = chip->badblockpos;
-		if (chip->options & NAND_BUSWIDTH_16) {
-			ops.ooboffs &= ~0x01;
-			ops.len = ops.ooblen = 2;
-		} else {
-			ops.len = ops.ooblen = 1;
-		}
-		ops.mode = MTD_OPS_PLACE_OOB;
-
-		/* Write to first/last page(s) if necessary */
-		if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
-			wr_ofs += mtd->erasesize - mtd->writesize;
-		do {
-			res = nand_do_write_oob(mtd, wr_ofs, &ops);
-			if (!ret)
-				ret = res;
-
-			i++;
-			wr_ofs += mtd->writesize;
-		} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
-
+		ret = chip->block_markbad(mtd, ofs);
 		nand_release_device(mtd);
 		nand_release_device(mtd);
 	}
 	}
 
 
-	/* Update flash-based bad block table */
-	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
-		res = nand_update_bbt(mtd, ofs);
+	/* Mark block bad in BBT */
+	if (chip->bbt) {
+		res = nand_markbad_bbt(mtd, ofs);
 		if (!ret)
 		if (!ret)
 			ret = res;
 			ret = res;
 	}
 	}
@@ -1983,13 +1980,14 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write
  * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write
  * @mtd:	mtd info structure
  * @mtd:	mtd info structure
  * @chip:	nand chip info structure
  * @chip:	nand chip info structure
- * @column:	column address of subpage within the page
+ * @offset:	column address of subpage within the page
  * @data_len:	data length
  * @data_len:	data length
+ * @buf:	data buffer
  * @oob_required: must write chip->oob_poi to OOB
  * @oob_required: must write chip->oob_poi to OOB
  */
  */
 static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 				struct nand_chip *chip, uint32_t offset,
 				struct nand_chip *chip, uint32_t offset,
-				uint32_t data_len, const uint8_t *data_buf,
+				uint32_t data_len, const uint8_t *buf,
 				int oob_required)
 				int oob_required)
 {
 {
 	uint8_t *oob_buf  = chip->oob_poi;
 	uint8_t *oob_buf  = chip->oob_poi;
@@ -2008,20 +2006,20 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
 
 
 		/* write data (untouched subpages already masked by 0xFF) */
 		/* write data (untouched subpages already masked by 0xFF) */
-		chip->write_buf(mtd, data_buf, ecc_size);
+		chip->write_buf(mtd, buf, ecc_size);
 
 
 		/* mask ECC of un-touched subpages by padding 0xFF */
 		/* mask ECC of un-touched subpages by padding 0xFF */
 		if ((step < start_step) || (step > end_step))
 		if ((step < start_step) || (step > end_step))
 			memset(ecc_calc, 0xff, ecc_bytes);
 			memset(ecc_calc, 0xff, ecc_bytes);
 		else
 		else
-			chip->ecc.calculate(mtd, data_buf, ecc_calc);
+			chip->ecc.calculate(mtd, buf, ecc_calc);
 
 
 		/* mask OOB of un-touched subpages by padding 0xFF */
 		/* mask OOB of un-touched subpages by padding 0xFF */
 		/* if oob_required, preserve OOB metadata of written subpage */
 		/* if oob_required, preserve OOB metadata of written subpage */
 		if (!oob_required || (step < start_step) || (step > end_step))
 		if (!oob_required || (step < start_step) || (step > end_step))
 			memset(oob_buf, 0xff, oob_bytes);
 			memset(oob_buf, 0xff, oob_bytes);
 
 
-		data_buf += ecc_size;
+		buf += ecc_size;
 		ecc_calc += ecc_bytes;
 		ecc_calc += ecc_bytes;
 		oob_buf  += oob_bytes;
 		oob_buf  += oob_bytes;
 	}
 	}
@@ -2633,7 +2631,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 		}
 		}
 
 
 		/* Increment page address and decrement length */
 		/* Increment page address and decrement length */
-		len -= (1 << chip->phys_erase_shift);
+		len -= (1ULL << chip->phys_erase_shift);
 		page += pages_per_block;
 		page += pages_per_block;
 
 
 		/* Check, if we cross a chip boundary */
 		/* Check, if we cross a chip boundary */
@@ -2694,7 +2692,6 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
  */
  */
 static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
 {
-	struct nand_chip *chip = mtd->priv;
 	int ret;
 	int ret;
 
 
 	ret = nand_block_isbad(mtd, ofs);
 	ret = nand_block_isbad(mtd, ofs);
@@ -2705,7 +2702,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 		return ret;
 		return ret;
 	}
 	}
 
 
-	return chip->block_markbad(mtd, ofs);
+	return nand_block_markbad_lowlevel(mtd, ofs);
 }
 }
 
 
 /**
 /**
@@ -2720,7 +2717,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
 {
 {
 	int status;
 	int status;
 
 
-	if (!chip->onfi_version)
+	if (!chip->onfi_version ||
+	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+	      & ONFI_OPT_CMD_SET_GET_FEATURES))
 		return -EINVAL;
 		return -EINVAL;
 
 
 	chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
 	chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
@@ -2741,7 +2740,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
 static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
 static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
 			int addr, uint8_t *subfeature_param)
 			int addr, uint8_t *subfeature_param)
 {
 {
-	if (!chip->onfi_version)
+	if (!chip->onfi_version ||
+	    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+	      & ONFI_OPT_CMD_SET_GET_FEATURES))
 		return -EINVAL;
 		return -EINVAL;
 
 
 	/* clear the sub feature parameters */
 	/* clear the sub feature parameters */
@@ -2793,7 +2794,15 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 
 
 	if (!chip->select_chip)
 	if (!chip->select_chip)
 		chip->select_chip = nand_select_chip;
 		chip->select_chip = nand_select_chip;
-	if (!chip->read_byte)
+
+	/* set for ONFI nand */
+	if (!chip->onfi_set_features)
+		chip->onfi_set_features = nand_onfi_set_features;
+	if (!chip->onfi_get_features)
+		chip->onfi_get_features = nand_onfi_get_features;
+
+	/* If called twice, pointers that depend on busw may need to be reset */
+	if (!chip->read_byte || chip->read_byte == nand_read_byte)
 		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
 		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
 	if (!chip->read_word)
 	if (!chip->read_word)
 		chip->read_word = nand_read_word;
 		chip->read_word = nand_read_word;
@@ -2801,9 +2810,9 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 		chip->block_bad = nand_block_bad;
 		chip->block_bad = nand_block_bad;
 	if (!chip->block_markbad)
 	if (!chip->block_markbad)
 		chip->block_markbad = nand_default_block_markbad;
 		chip->block_markbad = nand_default_block_markbad;
-	if (!chip->write_buf)
+	if (!chip->write_buf || chip->write_buf == nand_write_buf)
 		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
 		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
-	if (!chip->read_buf)
+	if (!chip->read_buf || chip->read_buf == nand_read_buf)
 		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
 		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
 	if (!chip->scan_bbt)
 	if (!chip->scan_bbt)
 		chip->scan_bbt = nand_default_bbt;
 		chip->scan_bbt = nand_default_bbt;
@@ -2846,6 +2855,78 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
 	return crc;
 	return crc;
 }
 }
 
 
+/* Parse the Extended Parameter Page. */
+static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
+		struct nand_chip *chip, struct nand_onfi_params *p)
+{
+	struct onfi_ext_param_page *ep;
+	struct onfi_ext_section *s;
+	struct onfi_ext_ecc_info *ecc;
+	uint8_t *cursor;
+	int ret = -EINVAL;
+	int len;
+	int i;
+
+	len = le16_to_cpu(p->ext_param_page_length) * 16;
+	ep = kmalloc(len, GFP_KERNEL);
+	if (!ep) {
+		ret = -ENOMEM;
+		goto ext_out;
+	}
+
+	/* Send our own NAND_CMD_PARAM. */
+	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
+
+	/* Use the Change Read Column command to skip the ONFI param pages. */
+	chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+			sizeof(*p) * p->num_of_param_pages , -1);
+
+	/* Read out the Extended Parameter Page. */
+	chip->read_buf(mtd, (uint8_t *)ep, len);
+	if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
+		!= le16_to_cpu(ep->crc))) {
+		pr_debug("fail in the CRC.\n");
+		goto ext_out;
+	}
+
+	/*
+	 * Check the signature.
+	 * Do not strictly follow the ONFI spec, maybe changed in future.
+	 */
+	if (strncmp(ep->sig, "EPPS", 4)) {
+		pr_debug("The signature is invalid.\n");
+		goto ext_out;
+	}
+
+	/* find the ECC section. */
+	cursor = (uint8_t *)(ep + 1);
+	for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
+		s = ep->sections + i;
+		if (s->type == ONFI_SECTION_TYPE_2)
+			break;
+		cursor += s->length * 16;
+	}
+	if (i == ONFI_EXT_SECTION_MAX) {
+		pr_debug("We can not find the ECC section.\n");
+		goto ext_out;
+	}
+
+	/* get the info we want. */
+	ecc = (struct onfi_ext_ecc_info *)cursor;
+
+	if (ecc->codeword_size) {
+		chip->ecc_strength_ds = ecc->ecc_bits;
+		chip->ecc_step_ds = 1 << ecc->codeword_size;
+	}
+
+	pr_info("ONFI extended param page detected.\n");
+	return 0;
+
+ext_out:
+	kfree(ep);
+	return ret;
+}
+
 /*
 /*
  * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
  * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
  */
  */
@@ -2907,9 +2988,31 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
 	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
 	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
 	chip->chipsize = le32_to_cpu(p->blocks_per_lun);
 	chip->chipsize = le32_to_cpu(p->blocks_per_lun);
 	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
 	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
-	*busw = 0;
-	if (le16_to_cpu(p->features) & 1)
+
+	if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
 		*busw = NAND_BUSWIDTH_16;
 		*busw = NAND_BUSWIDTH_16;
+	else
+		*busw = 0;
+
+	if (p->ecc_bits != 0xff) {
+		chip->ecc_strength_ds = p->ecc_bits;
+		chip->ecc_step_ds = 512;
+	} else if (chip->onfi_version >= 21 &&
+		(onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
+
+		/*
+		 * The nand_flash_detect_ext_param_page() uses the
+		 * Change Read Column command which maybe not supported
+		 * by the chip->cmdfunc. So try to update the chip->cmdfunc
+		 * now. We do not replace user supplied command function.
+		 */
+		if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
+			chip->cmdfunc = nand_command_lp;
+
+		/* The Extended Parameter Page is supported since ONFI 2.1. */
+		if (nand_flash_detect_ext_param_page(mtd, chip, p))
+			pr_info("Failed to detect the extended param page.\n");
+	}
 
 
 	pr_info("ONFI flash detected\n");
 	pr_info("ONFI flash detected\n");
 	return 1;
 	return 1;
@@ -3086,6 +3189,22 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
 		extid >>= 2;
 		extid >>= 2;
 		/* Get buswidth information */
 		/* Get buswidth information */
 		*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
 		*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+
+		/*
+		 * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
+		 * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
+		 * follows:
+		 * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
+		 *                         110b -> 24nm
+		 * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
+		 */
+		if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
+				!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+				(id_data[5] & 0x7) == 0x6 /* 24nm */ &&
+				!(id_data[4] & 0x80) /* !BENAND */) {
+			mtd->oobsize = 32 * mtd->writesize >> 9;
+		}
+
 	}
 	}
 }
 }
 
 
@@ -3172,6 +3291,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
 		chip->cellinfo = id_data[2];
 		chip->cellinfo = id_data[2];
 		chip->chipsize = (uint64_t)type->chipsize << 20;
 		chip->chipsize = (uint64_t)type->chipsize << 20;
 		chip->options |= type->options;
 		chip->options |= type->options;
+		chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
+		chip->ecc_step_ds = NAND_ECC_STEP(type);
 
 
 		*busw = type->options & NAND_BUSWIDTH_16;
 		*busw = type->options & NAND_BUSWIDTH_16;
 
 
@@ -3446,12 +3567,6 @@ int nand_scan_tail(struct mtd_info *mtd)
 	if (!chip->write_page)
 	if (!chip->write_page)
 		chip->write_page = nand_write_page;
 		chip->write_page = nand_write_page;
 
 
-	/* set for ONFI nand */
-	if (!chip->onfi_set_features)
-		chip->onfi_set_features = nand_onfi_set_features;
-	if (!chip->onfi_get_features)
-		chip->onfi_get_features = nand_onfi_get_features;
-
 	/*
 	/*
 	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is
 	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is
 	 * selected and we have 256 byte pagesize fallback to software ECC
 	 * selected and we have 256 byte pagesize fallback to software ECC
@@ -3674,6 +3789,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 	/* propagate ecc info to mtd_info */
 	/* propagate ecc info to mtd_info */
 	mtd->ecclayout = chip->ecc.layout;
 	mtd->ecclayout = chip->ecc.layout;
 	mtd->ecc_strength = chip->ecc.strength;
 	mtd->ecc_strength = chip->ecc.strength;
+	mtd->ecc_step_size = chip->ecc.size;
 	/*
 	/*
 	 * Initialize bitflip_threshold to its default prior scan_bbt() call.
 	 * Initialize bitflip_threshold to its default prior scan_bbt() call.
 	 * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
 	 * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be

+ 103 - 91
drivers/mtd/nand/nand_bbt.c

@@ -71,6 +71,30 @@
 #include <linux/export.h>
 #include <linux/export.h>
 #include <linux/string.h>
 #include <linux/string.h>
 
 
+#define BBT_BLOCK_GOOD		0x00
+#define BBT_BLOCK_WORN		0x01
+#define BBT_BLOCK_RESERVED	0x02
+#define BBT_BLOCK_FACTORY_BAD	0x03
+
+#define BBT_ENTRY_MASK		0x03
+#define BBT_ENTRY_SHIFT		2
+
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
+
+static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
+{
+	uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
+	entry >>= (block & BBT_ENTRY_MASK) * 2;
+	return entry & BBT_ENTRY_MASK;
+}
+
+static inline void bbt_mark_entry(struct nand_chip *chip, int block,
+		uint8_t mark)
+{
+	uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
+	chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
+}
+
 static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
 static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
 {
 {
 	if (memcmp(buf, td->pattern, td->len))
 	if (memcmp(buf, td->pattern, td->len))
@@ -86,33 +110,17 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
  * @td: search pattern descriptor
  * @td: search pattern descriptor
  *
  *
  * Check for a pattern at the given place. Used to search bad block tables and
  * Check for a pattern at the given place. Used to search bad block tables and
- * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if
- * all bytes except the pattern area contain 0xff.
+ * good / bad block identifiers.
  */
  */
 static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
 static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
 {
 {
-	int end = 0;
-	uint8_t *p = buf;
-
 	if (td->options & NAND_BBT_NO_OOB)
 	if (td->options & NAND_BBT_NO_OOB)
 		return check_pattern_no_oob(buf, td);
 		return check_pattern_no_oob(buf, td);
 
 
-	end = paglen + td->offs;
-	if (td->options & NAND_BBT_SCANEMPTY)
-		if (memchr_inv(p, 0xff, end))
-			return -1;
-	p += end;
-
 	/* Compare the pattern */
 	/* Compare the pattern */
-	if (memcmp(p, td->pattern, td->len))
+	if (memcmp(buf + paglen + td->offs, td->pattern, td->len))
 		return -1;
 		return -1;
 
 
-	if (td->options & NAND_BBT_SCANEMPTY) {
-		p += td->len;
-		end += td->len;
-		if (memchr_inv(p, 0xff, len - end))
-			return -1;
-	}
 	return 0;
 	return 0;
 }
 }
 
 
@@ -159,7 +167,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
  * @page: the starting page
  * @page: the starting page
  * @num: the number of bbt descriptors to read
  * @num: the number of bbt descriptors to read
  * @td: the bbt describtion table
  * @td: the bbt describtion table
- * @offs: offset in the memory table
+ * @offs: block number offset in the table
  *
  *
  * Read the bad block table starting from page.
  * Read the bad block table starting from page.
  */
  */
@@ -209,14 +217,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 		/* Analyse data */
 		/* Analyse data */
 		for (i = 0; i < len; i++) {
 		for (i = 0; i < len; i++) {
 			uint8_t dat = buf[i];
 			uint8_t dat = buf[i];
-			for (j = 0; j < 8; j += bits, act += 2) {
+			for (j = 0; j < 8; j += bits, act++) {
 				uint8_t tmp = (dat >> j) & msk;
 				uint8_t tmp = (dat >> j) & msk;
 				if (tmp == msk)
 				if (tmp == msk)
 					continue;
 					continue;
 				if (reserved_block_code && (tmp == reserved_block_code)) {
 				if (reserved_block_code && (tmp == reserved_block_code)) {
 					pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
 					pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
-						 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
-					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
+						 (loff_t)(offs + act) <<
+						 this->bbt_erase_shift);
+					bbt_mark_entry(this, offs + act,
+							BBT_BLOCK_RESERVED);
 					mtd->ecc_stats.bbtblocks++;
 					mtd->ecc_stats.bbtblocks++;
 					continue;
 					continue;
 				}
 				}
@@ -225,12 +235,15 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 				 * move this message to pr_debug.
 				 * move this message to pr_debug.
 				 */
 				 */
 				pr_info("nand_read_bbt: bad block at 0x%012llx\n",
 				pr_info("nand_read_bbt: bad block at 0x%012llx\n",
-					 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+					 (loff_t)(offs + act) <<
+					 this->bbt_erase_shift);
 				/* Factory marked bad or worn out? */
 				/* Factory marked bad or worn out? */
 				if (tmp == 0)
 				if (tmp == 0)
-					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
+					bbt_mark_entry(this, offs + act,
+							BBT_BLOCK_FACTORY_BAD);
 				else
 				else
-					this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
+					bbt_mark_entry(this, offs + act,
+							BBT_BLOCK_WORN);
 				mtd->ecc_stats.badblocks++;
 				mtd->ecc_stats.badblocks++;
 			}
 			}
 		}
 		}
@@ -265,7 +278,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 					td, offs);
 					td, offs);
 			if (res)
 			if (res)
 				return res;
 				return res;
-			offs += this->chipsize >> (this->bbt_erase_shift + 2);
+			offs += this->chipsize >> this->bbt_erase_shift;
 		}
 		}
 	} else {
 	} else {
 		res = read_bbt(mtd, buf, td->pages[0],
 		res = read_bbt(mtd, buf, td->pages[0],
@@ -478,22 +491,12 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 	else
 	else
 		numpages = 1;
 		numpages = 1;
 
 
-	if (!(bd->options & NAND_BBT_SCANEMPTY)) {
-		/* We need only read few bytes from the OOB area */
-		scanlen = 0;
-		readlen = bd->len;
-	} else {
-		/* Full page content should be read */
-		scanlen = mtd->writesize + mtd->oobsize;
-		readlen = numpages * mtd->writesize;
-	}
+	/* We need only read few bytes from the OOB area */
+	scanlen = 0;
+	readlen = bd->len;
 
 
 	if (chip == -1) {
 	if (chip == -1) {
-		/*
-		 * Note that numblocks is 2 * (real numblocks) here, see i+=2
-		 * below as it makes shifting and masking less painful
-		 */
-		numblocks = mtd->size >> (this->bbt_erase_shift - 1);
+		numblocks = mtd->size >> this->bbt_erase_shift;
 		startblock = 0;
 		startblock = 0;
 		from = 0;
 		from = 0;
 	} else {
 	} else {
@@ -502,16 +505,16 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 			       chip + 1, this->numchips);
 			       chip + 1, this->numchips);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
-		numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
+		numblocks = this->chipsize >> this->bbt_erase_shift;
 		startblock = chip * numblocks;
 		startblock = chip * numblocks;
 		numblocks += startblock;
 		numblocks += startblock;
-		from = (loff_t)startblock << (this->bbt_erase_shift - 1);
+		from = (loff_t)startblock << this->bbt_erase_shift;
 	}
 	}
 
 
 	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
 	if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
 		from += mtd->erasesize - (mtd->writesize * numpages);
 		from += mtd->erasesize - (mtd->writesize * numpages);
 
 
-	for (i = startblock; i < numblocks;) {
+	for (i = startblock; i < numblocks; i++) {
 		int ret;
 		int ret;
 
 
 		BUG_ON(bd->options & NAND_BBT_NO_OOB);
 		BUG_ON(bd->options & NAND_BBT_NO_OOB);
@@ -526,13 +529,12 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 			return ret;
 			return ret;
 
 
 		if (ret) {
 		if (ret) {
-			this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+			bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);
 			pr_warn("Bad eraseblock %d at 0x%012llx\n",
 			pr_warn("Bad eraseblock %d at 0x%012llx\n",
-				i >> 1, (unsigned long long)from);
+				i, (unsigned long long)from);
 			mtd->ecc_stats.badblocks++;
 			mtd->ecc_stats.badblocks++;
 		}
 		}
 
 
-		i += 2;
 		from += (1 << this->bbt_erase_shift);
 		from += (1 << this->bbt_erase_shift);
 	}
 	}
 	return 0;
 	return 0;
@@ -655,9 +657,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 {
 {
 	struct nand_chip *this = mtd->priv;
 	struct nand_chip *this = mtd->priv;
 	struct erase_info einfo;
 	struct erase_info einfo;
-	int i, j, res, chip = 0;
+	int i, res, chip = 0;
 	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
 	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
-	int nrchips, bbtoffs, pageoffs, ooboffs;
+	int nrchips, pageoffs, ooboffs;
 	uint8_t msk[4];
 	uint8_t msk[4];
 	uint8_t rcode = td->reserved_block_code;
 	uint8_t rcode = td->reserved_block_code;
 	size_t retlen, len = 0;
 	size_t retlen, len = 0;
@@ -713,10 +715,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 		for (i = 0; i < td->maxblocks; i++) {
 		for (i = 0; i < td->maxblocks; i++) {
 			int block = startblock + dir * i;
 			int block = startblock + dir * i;
 			/* Check, if the block is bad */
 			/* Check, if the block is bad */
-			switch ((this->bbt[block >> 2] >>
-				 (2 * (block & 0x03))) & 0x03) {
-			case 0x01:
-			case 0x03:
+			switch (bbt_get_entry(this, block)) {
+			case BBT_BLOCK_WORN:
+			case BBT_BLOCK_FACTORY_BAD:
 				continue;
 				continue;
 			}
 			}
 			page = block <<
 			page = block <<
@@ -748,8 +749,6 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 		default: return -EINVAL;
 		default: return -EINVAL;
 		}
 		}
 
 
-		bbtoffs = chip * (numblocks >> 2);
-
 		to = ((loff_t)page) << this->page_shift;
 		to = ((loff_t)page) << this->page_shift;
 
 
 		/* Must we save the block contents? */
 		/* Must we save the block contents? */
@@ -814,16 +813,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 			buf[ooboffs + td->veroffs] = td->version[chip];
 			buf[ooboffs + td->veroffs] = td->version[chip];
 
 
 		/* Walk through the memory table */
 		/* Walk through the memory table */
-		for (i = 0; i < numblocks;) {
+		for (i = 0; i < numblocks; i++) {
 			uint8_t dat;
 			uint8_t dat;
-			dat = this->bbt[bbtoffs + (i >> 2)];
-			for (j = 0; j < 4; j++, i++) {
-				int sftcnt = (i << (3 - sft)) & sftmsk;
-				/* Do not store the reserved bbt blocks! */
-				buf[offs + (i >> sft)] &=
-					~(msk[dat & 0x03] << sftcnt);
-				dat >>= 2;
-			}
+			int sftcnt = (i << (3 - sft)) & sftmsk;
+			dat = bbt_get_entry(this, chip * numblocks + i);
+			/* Do not store the reserved bbt blocks! */
+			buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);
 		}
 		}
 
 
 		memset(&einfo, 0, sizeof(einfo));
 		memset(&einfo, 0, sizeof(einfo));
@@ -865,7 +860,6 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
 {
 {
 	struct nand_chip *this = mtd->priv;
 	struct nand_chip *this = mtd->priv;
 
 
-	bd->options &= ~NAND_BBT_SCANEMPTY;
 	return create_bbt(mtd, this->buffers->databuf, bd, -1);
 	return create_bbt(mtd, this->buffers->databuf, bd, -1);
 }
 }
 
 
@@ -1009,7 +1003,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 {
 {
 	struct nand_chip *this = mtd->priv;
 	struct nand_chip *this = mtd->priv;
 	int i, j, chips, block, nrblocks, update;
 	int i, j, chips, block, nrblocks, update;
-	uint8_t oldval, newval;
+	uint8_t oldval;
 
 
 	/* Do we have a bbt per chip? */
 	/* Do we have a bbt per chip? */
 	if (td->options & NAND_BBT_PERCHIP) {
 	if (td->options & NAND_BBT_PERCHIP) {
@@ -1026,12 +1020,12 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 			if (td->pages[i] == -1)
 			if (td->pages[i] == -1)
 				continue;
 				continue;
 			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
 			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
-			block <<= 1;
-			oldval = this->bbt[(block >> 3)];
-			newval = oldval | (0x2 << (block & 0x06));
-			this->bbt[(block >> 3)] = newval;
-			if ((oldval != newval) && td->reserved_block_code)
-				nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
+			oldval = bbt_get_entry(this, block);
+			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
+			if ((oldval != BBT_BLOCK_RESERVED) &&
+					td->reserved_block_code)
+				nand_update_bbt(mtd, (loff_t)block <<
+						this->bbt_erase_shift);
 			continue;
 			continue;
 		}
 		}
 		update = 0;
 		update = 0;
@@ -1039,14 +1033,12 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 			block = ((i + 1) * nrblocks) - td->maxblocks;
 			block = ((i + 1) * nrblocks) - td->maxblocks;
 		else
 		else
 			block = i * nrblocks;
 			block = i * nrblocks;
-		block <<= 1;
 		for (j = 0; j < td->maxblocks; j++) {
 		for (j = 0; j < td->maxblocks; j++) {
-			oldval = this->bbt[(block >> 3)];
-			newval = oldval | (0x2 << (block & 0x06));
-			this->bbt[(block >> 3)] = newval;
-			if (oldval != newval)
+			oldval = bbt_get_entry(this, block);
+			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
+			if (oldval != BBT_BLOCK_RESERVED)
 				update = 1;
 				update = 1;
-			block += 2;
+			block++;
 		}
 		}
 		/*
 		/*
 		 * If we want reserved blocks to be recorded to flash, and some
 		 * If we want reserved blocks to be recorded to flash, and some
@@ -1054,7 +1046,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 		 * bbts.  This should only happen once.
 		 * bbts.  This should only happen once.
 		 */
 		 */
 		if (update && td->reserved_block_code)
 		if (update && td->reserved_block_code)
-			nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
+			nand_update_bbt(mtd, (loff_t)(block - 1) <<
+					this->bbt_erase_shift);
 	}
 	}
 }
 }
 
 
@@ -1180,13 +1173,13 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 }
 }
 
 
 /**
 /**
- * nand_update_bbt - [NAND Interface] update bad block table(s)
+ * nand_update_bbt - update bad block table(s)
  * @mtd: MTD device structure
  * @mtd: MTD device structure
  * @offs: the offset of the newly marked block
  * @offs: the offset of the newly marked block
  *
  *
  * The function updates the bad block table(s).
  * The function updates the bad block table(s).
  */
  */
-int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
 {
 {
 	struct nand_chip *this = mtd->priv;
 	struct nand_chip *this = mtd->priv;
 	int len, res = 0;
 	int len, res = 0;
@@ -1356,28 +1349,47 @@ int nand_default_bbt(struct mtd_info *mtd)
 int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
 int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
 {
 {
 	struct nand_chip *this = mtd->priv;
 	struct nand_chip *this = mtd->priv;
-	int block;
-	uint8_t res;
+	int block, res;
 
 
-	/* Get block number * 2 */
-	block = (int)(offs >> (this->bbt_erase_shift - 1));
-	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
+	block = (int)(offs >> this->bbt_erase_shift);
+	res = bbt_get_entry(this, block);
 
 
 	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: "
 	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: "
 			"(block %d) 0x%02x\n",
 			"(block %d) 0x%02x\n",
-			(unsigned int)offs, block >> 1, res);
+			(unsigned int)offs, block, res);
 
 
-	switch ((int)res) {
-	case 0x00:
+	switch (res) {
+	case BBT_BLOCK_GOOD:
 		return 0;
 		return 0;
-	case 0x01:
+	case BBT_BLOCK_WORN:
 		return 1;
 		return 1;
-	case 0x02:
+	case BBT_BLOCK_RESERVED:
 		return allowbbt ? 0 : 1;
 		return allowbbt ? 0 : 1;
 	}
 	}
 	return 1;
 	return 1;
 }
 }
 
 
+/**
+ * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
+ * @mtd: MTD device structure
+ * @offs: offset of the bad block
+ */
+int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+{
+	struct nand_chip *this = mtd->priv;
+	int block, ret = 0;
+
+	block = (int)(offs >> this->bbt_erase_shift);
+
+	/* Mark bad block in memory */
+	bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+	/* Update flash-based bad block table */
+	if (this->bbt_options & NAND_BBT_USE_FLASH)
+		ret = nand_update_bbt(mtd, offs);
+
+	return ret;
+}
+
 EXPORT_SYMBOL(nand_scan_bbt);
 EXPORT_SYMBOL(nand_scan_bbt);
 EXPORT_SYMBOL(nand_default_bbt);
 EXPORT_SYMBOL(nand_default_bbt);
-EXPORT_SYMBOL_GPL(nand_update_bbt);

+ 4 - 4
drivers/mtd/nand/nand_ids.c

@@ -33,16 +33,16 @@ struct nand_flash_dev nand_flash_ids[] = {
 	 */
 	 */
 	{"TC58NVG2S0F 4G 3.3V 8-bit",
 	{"TC58NVG2S0F 4G 3.3V 8-bit",
 		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
 		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
-		  SZ_4K, SZ_512, SZ_256K, 0, 8, 224},
+		  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
 	{"TC58NVG3S0F 8G 3.3V 8-bit",
 	{"TC58NVG3S0F 8G 3.3V 8-bit",
 		{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
 		{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
-		  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232},
+		  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
 	{"TC58NVG5D2 32G 3.3V 8-bit",
 	{"TC58NVG5D2 32G 3.3V 8-bit",
 		{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
 		{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
-		  SZ_8K, SZ_4K, SZ_1M, 0, 8, 640},
+		  SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
 	{"TC58NVG6D2 64G 3.3V 8-bit",
 	{"TC58NVG6D2 64G 3.3V 8-bit",
 		{ .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
 		{ .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
-		  SZ_8K, SZ_8K, SZ_2M, 0, 8, 640},
+		  SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
 
 
 	LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
 	LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
 	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
 	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),

+ 15 - 24
drivers/mtd/nand/nandsim.c

@@ -205,7 +205,7 @@ MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
 
 
 /* Calculate the page offset in flash RAM image by (row, column) address */
 /* Calculate the page offset in flash RAM image by (row, column) address */
 #define NS_RAW_OFFSET(ns) \
 #define NS_RAW_OFFSET(ns) \
-	(((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column)
+	(((ns)->regs.row * (ns)->geom.pgszoob) + (ns)->regs.column)
 
 
 /* Calculate the OOB offset in flash RAM image by (row, column) address */
 /* Calculate the OOB offset in flash RAM image by (row, column) address */
 #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
 #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
@@ -336,7 +336,6 @@ struct nandsim {
 		uint pgsec;         /* number of pages per sector */
 		uint pgsec;         /* number of pages per sector */
 		uint secshift;      /* bits number in sector size */
 		uint secshift;      /* bits number in sector size */
 		uint pgshift;       /* bits number in page size */
 		uint pgshift;       /* bits number in page size */
-		uint oobshift;      /* bits number in OOB size */
 		uint pgaddrbytes;   /* bytes per page address */
 		uint pgaddrbytes;   /* bytes per page address */
 		uint secaddrbytes;  /* bytes per sector address */
 		uint secaddrbytes;  /* bytes per sector address */
 		uint idbytes;       /* the number ID bytes that this chip outputs */
 		uint idbytes;       /* the number ID bytes that this chip outputs */
@@ -363,7 +362,7 @@ struct nandsim {
 
 
 	/* Fields needed when using a cache file */
 	/* Fields needed when using a cache file */
 	struct file *cfile; /* Open file */
 	struct file *cfile; /* Open file */
-	unsigned char *pages_written; /* Which pages have been written */
+	unsigned long *pages_written; /* Which pages have been written */
 	void *file_buf;
 	void *file_buf;
 	struct page *held_pages[NS_MAX_HELD_PAGES];
 	struct page *held_pages[NS_MAX_HELD_PAGES];
 	int held_cnt;
 	int held_cnt;
@@ -586,7 +585,8 @@ static int alloc_device(struct nandsim *ns)
 			err = -EINVAL;
 			err = -EINVAL;
 			goto err_close;
 			goto err_close;
 		}
 		}
-		ns->pages_written = vzalloc(ns->geom.pgnum);
+		ns->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
+					    sizeof(unsigned long));
 		if (!ns->pages_written) {
 		if (!ns->pages_written) {
 			NS_ERR("alloc_device: unable to allocate pages written array\n");
 			NS_ERR("alloc_device: unable to allocate pages written array\n");
 			err = -ENOMEM;
 			err = -ENOMEM;
@@ -653,9 +653,7 @@ static void free_device(struct nandsim *ns)
 
 
 static char *get_partition_name(int i)
 static char *get_partition_name(int i)
 {
 {
-	char buf[64];
-	sprintf(buf, "NAND simulator partition %d", i);
-	return kstrdup(buf, GFP_KERNEL);
+	return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
 }
 }
 
 
 /*
 /*
@@ -690,7 +688,6 @@ static int init_nandsim(struct mtd_info *mtd)
 	ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
 	ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
 	ns->geom.secshift = ffs(ns->geom.secsz) - 1;
 	ns->geom.secshift = ffs(ns->geom.secsz) - 1;
 	ns->geom.pgshift  = chip->page_shift;
 	ns->geom.pgshift  = chip->page_shift;
-	ns->geom.oobshift = ffs(ns->geom.oobsz) - 1;
 	ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;
 	ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;
 	ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
 	ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
 	ns->options = 0;
 	ns->options = 0;
@@ -761,12 +758,6 @@ static int init_nandsim(struct mtd_info *mtd)
 		ns->nbparts += 1;
 		ns->nbparts += 1;
 	}
 	}
 
 
-	/* Detect how many ID bytes the NAND chip outputs */
-	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (second_id_byte != nand_flash_ids[i].dev_id)
-			continue;
-	}
-
 	if (ns->busw == 16)
 	if (ns->busw == 16)
 		NS_WARN("16-bit flashes support wasn't tested\n");
 		NS_WARN("16-bit flashes support wasn't tested\n");
 
 
@@ -780,7 +771,7 @@ static int init_nandsim(struct mtd_info *mtd)
 	printk("bus width: %u\n",               ns->busw);
 	printk("bus width: %u\n",               ns->busw);
 	printk("bits in sector size: %u\n",     ns->geom.secshift);
 	printk("bits in sector size: %u\n",     ns->geom.secshift);
 	printk("bits in page size: %u\n",       ns->geom.pgshift);
 	printk("bits in page size: %u\n",       ns->geom.pgshift);
-	printk("bits in OOB size: %u\n",	ns->geom.oobshift);
+	printk("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
 	printk("flash size with OOB: %llu KiB\n",
 	printk("flash size with OOB: %llu KiB\n",
 			(unsigned long long)ns->geom.totszoob >> 10);
 			(unsigned long long)ns->geom.totszoob >> 10);
 	printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
 	printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
@@ -1442,7 +1433,7 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
 	return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
 	return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
 }
 }
 
 
-int do_read_error(struct nandsim *ns, int num)
+static int do_read_error(struct nandsim *ns, int num)
 {
 {
 	unsigned int page_no = ns->regs.row;
 	unsigned int page_no = ns->regs.row;
 
 
@@ -1454,7 +1445,7 @@ int do_read_error(struct nandsim *ns, int num)
 	return 0;
 	return 0;
 }
 }
 
 
-void do_bit_flips(struct nandsim *ns, int num)
+static void do_bit_flips(struct nandsim *ns, int num)
 {
 {
 	if (bitflips && prandom_u32() < (1 << 22)) {
 	if (bitflips && prandom_u32() < (1 << 22)) {
 		int flips = 1;
 		int flips = 1;
@@ -1479,7 +1470,7 @@ static void read_page(struct nandsim *ns, int num)
 	union ns_mem *mypage;
 	union ns_mem *mypage;
 
 
 	if (ns->cfile) {
 	if (ns->cfile) {
-		if (!ns->pages_written[ns->regs.row]) {
+		if (!test_bit(ns->regs.row, ns->pages_written)) {
 			NS_DBG("read_page: page %d not written\n", ns->regs.row);
 			NS_DBG("read_page: page %d not written\n", ns->regs.row);
 			memset(ns->buf.byte, 0xFF, num);
 			memset(ns->buf.byte, 0xFF, num);
 		} else {
 		} else {
@@ -1490,7 +1481,7 @@ static void read_page(struct nandsim *ns, int num)
 				ns->regs.row, ns->regs.column + ns->regs.off);
 				ns->regs.row, ns->regs.column + ns->regs.off);
 			if (do_read_error(ns, num))
 			if (do_read_error(ns, num))
 				return;
 				return;
-			pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
+			pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
 			tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
 			tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
 			if (tx != num) {
 			if (tx != num) {
 				NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
 				NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
@@ -1525,9 +1516,9 @@ static void erase_sector(struct nandsim *ns)
 
 
 	if (ns->cfile) {
 	if (ns->cfile) {
 		for (i = 0; i < ns->geom.pgsec; i++)
 		for (i = 0; i < ns->geom.pgsec; i++)
-			if (ns->pages_written[ns->regs.row + i]) {
+			if (__test_and_clear_bit(ns->regs.row + i,
+						 ns->pages_written)) {
 				NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
 				NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
-				ns->pages_written[ns->regs.row + i] = 0;
 			}
 			}
 		return;
 		return;
 	}
 	}
@@ -1559,8 +1550,8 @@ static int prog_page(struct nandsim *ns, int num)
 
 
 		NS_DBG("prog_page: writing page %d\n", ns->regs.row);
 		NS_DBG("prog_page: writing page %d\n", ns->regs.row);
 		pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
 		pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
-		off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
-		if (!ns->pages_written[ns->regs.row]) {
+		off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+		if (!test_bit(ns->regs.row, ns->pages_written)) {
 			all = 1;
 			all = 1;
 			memset(ns->file_buf, 0xff, ns->geom.pgszoob);
 			memset(ns->file_buf, 0xff, ns->geom.pgszoob);
 		} else {
 		} else {
@@ -1580,7 +1571,7 @@ static int prog_page(struct nandsim *ns, int num)
 				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
 				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
 				return -1;
 				return -1;
 			}
 			}
-			ns->pages_written[ns->regs.row] = 1;
+			__set_bit(ns->regs.row, ns->pages_written);
 		} else {
 		} else {
 			tx = write_file(ns, ns->cfile, pg_off, num, off);
 			tx = write_file(ns, ns->cfile, pg_off, num, off);
 			if (tx != num) {
 			if (tx != num) {

+ 0 - 2
drivers/mtd/nand/nuc900_nand.c

@@ -324,8 +324,6 @@ static int nuc900_nand_remove(struct platform_device *pdev)
 
 
 	kfree(nuc900_nand);
 	kfree(nuc900_nand);
 
 
-	platform_set_drvdata(pdev, NULL);
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 2 - 3
drivers/mtd/nand/omap2.c

@@ -154,7 +154,7 @@ static struct nand_ecclayout omap_oobinfo;
  */
  */
 static uint8_t scan_ff_pattern[] = { 0xff };
 static uint8_t scan_ff_pattern[] = { 0xff };
 static struct nand_bbt_descr bb_descrip_flashbased = {
 static struct nand_bbt_descr bb_descrip_flashbased = {
-	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
+	.options = NAND_BBT_SCANALLPAGES,
 	.offs = 0,
 	.offs = 0,
 	.len = 1,
 	.len = 1,
 	.pattern = scan_ff_pattern,
 	.pattern = scan_ff_pattern,
@@ -1831,7 +1831,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 	struct resource			*res;
 	struct resource			*res;
 	struct mtd_part_parser_data	ppdata = {};
 	struct mtd_part_parser_data	ppdata = {};
 
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (pdata == NULL) {
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "platform data missing\n");
 		dev_err(&pdev->dev, "platform data missing\n");
 		return -ENODEV;
 		return -ENODEV;
@@ -2087,7 +2087,6 @@ static int omap_nand_remove(struct platform_device *pdev)
 							mtd);
 							mtd);
 	omap3_free_bch(&info->mtd);
 	omap3_free_bch(&info->mtd);
 
 
-	platform_set_drvdata(pdev, NULL);
 	if (info->dma)
 	if (info->dma)
 		dma_release_channel(info->dma);
 		dma_release_channel(info->dma);
 
 

+ 3 - 3
drivers/mtd/nand/orion_nand.c

@@ -130,8 +130,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 		if (!of_property_read_u32(pdev->dev.of_node,
 		if (!of_property_read_u32(pdev->dev.of_node,
 						"chip-delay", &val))
 						"chip-delay", &val))
 			board->chip_delay = (u8)val;
 			board->chip_delay = (u8)val;
-	} else
-		board = pdev->dev.platform_data;
+	} else {
+		board = dev_get_platdata(&pdev->dev);
+	}
 
 
 	mtd->priv = nc;
 	mtd->priv = nc;
 	mtd->owner = THIS_MODULE;
 	mtd->owner = THIS_MODULE;
@@ -186,7 +187,6 @@ no_dev:
 		clk_disable_unprepare(clk);
 		clk_disable_unprepare(clk);
 		clk_put(clk);
 		clk_put(clk);
 	}
 	}
-	platform_set_drvdata(pdev, NULL);
 	iounmap(io_base);
 	iounmap(io_base);
 no_res:
 no_res:
 	kfree(nc);
 	kfree(nc);

+ 2 - 3
drivers/mtd/nand/plat_nand.c

@@ -30,7 +30,7 @@ static const char *part_probe_types[] = { "cmdlinepart", NULL };
  */
  */
 static int plat_nand_probe(struct platform_device *pdev)
 static int plat_nand_probe(struct platform_device *pdev)
 {
 {
-	struct platform_nand_data *pdata = pdev->dev.platform_data;
+	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
 	struct mtd_part_parser_data ppdata;
 	struct mtd_part_parser_data ppdata;
 	struct plat_nand_data *data;
 	struct plat_nand_data *data;
 	struct resource *res;
 	struct resource *res;
@@ -122,7 +122,6 @@ static int plat_nand_probe(struct platform_device *pdev)
 out:
 out:
 	if (pdata->ctrl.remove)
 	if (pdata->ctrl.remove)
 		pdata->ctrl.remove(pdev);
 		pdata->ctrl.remove(pdev);
-	platform_set_drvdata(pdev, NULL);
 	iounmap(data->io_base);
 	iounmap(data->io_base);
 out_release_io:
 out_release_io:
 	release_mem_region(res->start, resource_size(res));
 	release_mem_region(res->start, resource_size(res));
@@ -137,7 +136,7 @@ out_free:
 static int plat_nand_remove(struct platform_device *pdev)
 static int plat_nand_remove(struct platform_device *pdev)
 {
 {
 	struct plat_nand_data *data = platform_get_drvdata(pdev);
 	struct plat_nand_data *data = platform_get_drvdata(pdev);
-	struct platform_nand_data *pdata = pdev->dev.platform_data;
+	struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
 	struct resource *res;
 	struct resource *res;
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

+ 221 - 163
drivers/mtd/nand/pxa3xx_nand.c

@@ -25,7 +25,14 @@
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
 
 
+#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
+#define ARCH_HAS_DMA
+#endif
+
+#ifdef ARCH_HAS_DMA
 #include <mach/dma.h>
 #include <mach/dma.h>
+#endif
+
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
 
 
 #define	CHIP_DELAY_TIMEOUT	(2 * HZ/10)
 #define	CHIP_DELAY_TIMEOUT	(2 * HZ/10)
@@ -80,6 +87,7 @@
 #define NDSR_RDDREQ		(0x1 << 1)
 #define NDSR_RDDREQ		(0x1 << 1)
 #define NDSR_WRCMDREQ		(0x1)
 #define NDSR_WRCMDREQ		(0x1)
 
 
+#define NDCB0_LEN_OVRD		(0x1 << 28)
 #define NDCB0_ST_ROW_EN         (0x1 << 26)
 #define NDCB0_ST_ROW_EN         (0x1 << 26)
 #define NDCB0_AUTO_RS		(0x1 << 25)
 #define NDCB0_AUTO_RS		(0x1 << 25)
 #define NDCB0_CSEL		(0x1 << 24)
 #define NDCB0_CSEL		(0x1 << 24)
@@ -123,9 +131,13 @@ enum {
 	STATE_READY,
 	STATE_READY,
 };
 };
 
 
+enum pxa3xx_nand_variant {
+	PXA3XX_NAND_VARIANT_PXA,
+	PXA3XX_NAND_VARIANT_ARMADA370,
+};
+
 struct pxa3xx_nand_host {
 struct pxa3xx_nand_host {
 	struct nand_chip	chip;
 	struct nand_chip	chip;
-	struct pxa3xx_nand_cmdset *cmdset;
 	struct mtd_info         *mtd;
 	struct mtd_info         *mtd;
 	void			*info_data;
 	void			*info_data;
 
 
@@ -139,10 +151,6 @@ struct pxa3xx_nand_host {
 	unsigned int		row_addr_cycles;
 	unsigned int		row_addr_cycles;
 	size_t			read_id_bytes;
 	size_t			read_id_bytes;
 
 
-	/* cached register value */
-	uint32_t		reg_ndcr;
-	uint32_t		ndtr0cs0;
-	uint32_t		ndtr1cs0;
 };
 };
 
 
 struct pxa3xx_nand_info {
 struct pxa3xx_nand_info {
@@ -171,9 +179,16 @@ struct pxa3xx_nand_info {
 	struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
 	struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
 	unsigned int		state;
 	unsigned int		state;
 
 
+	/*
+	 * This driver supports NFCv1 (as found in PXA SoC)
+	 * and NFCv2 (as found in Armada 370/XP SoC).
+	 */
+	enum pxa3xx_nand_variant variant;
+
 	int			cs;
 	int			cs;
 	int			use_ecc;	/* use HW ECC ? */
 	int			use_ecc;	/* use HW ECC ? */
 	int			use_dma;	/* use DMA ? */
 	int			use_dma;	/* use DMA ? */
+	int			use_spare;	/* use spare ? */
 	int			is_ready;
 	int			is_ready;
 
 
 	unsigned int		page_size;	/* page size of attached chip */
 	unsigned int		page_size;	/* page size of attached chip */
@@ -181,33 +196,22 @@ struct pxa3xx_nand_info {
 	unsigned int		oob_size;
 	unsigned int		oob_size;
 	int 			retcode;
 	int 			retcode;
 
 
+	/* cached register value */
+	uint32_t		reg_ndcr;
+	uint32_t		ndtr0cs0;
+	uint32_t		ndtr1cs0;
+
 	/* generated NDCBx register values */
 	/* generated NDCBx register values */
 	uint32_t		ndcb0;
 	uint32_t		ndcb0;
 	uint32_t		ndcb1;
 	uint32_t		ndcb1;
 	uint32_t		ndcb2;
 	uint32_t		ndcb2;
+	uint32_t		ndcb3;
 };
 };
 
 
 static bool use_dma = 1;
 static bool use_dma = 1;
 module_param(use_dma, bool, 0444);
 module_param(use_dma, bool, 0444);
 MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
 MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
 
 
-/*
- * Default NAND flash controller configuration setup by the
- * bootloader. This configuration is used only when pdata->keep_config is set
- */
-static struct pxa3xx_nand_cmdset default_cmdset = {
-	.read1		= 0x3000,
-	.read2		= 0x0050,
-	.program	= 0x1080,
-	.read_status	= 0x0070,
-	.read_id	= 0x0090,
-	.erase		= 0xD060,
-	.reset		= 0x00FF,
-	.lock		= 0x002A,
-	.unlock		= 0x2423,
-	.lock_status	= 0x007A,
-};
-
 static struct pxa3xx_nand_timing timing[] = {
 static struct pxa3xx_nand_timing timing[] = {
 	{ 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
 	{ 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
 	{ 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
 	{ 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
@@ -230,8 +234,6 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
 /* Define a default flash type setting serve as flash detecting only */
 /* Define a default flash type setting serve as flash detecting only */
 #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
 #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
 
 
-const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL};
-
 #define NDTR0_tCH(c)	(min((c), 7) << 19)
 #define NDTR0_tCH(c)	(min((c), 7) << 19)
 #define NDTR0_tCS(c)	(min((c), 7) << 16)
 #define NDTR0_tCS(c)	(min((c), 7) << 16)
 #define NDTR0_tWH(c)	(min((c), 7) << 11)
 #define NDTR0_tWH(c)	(min((c), 7) << 11)
@@ -264,8 +266,8 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
 		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
 		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
 		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
 		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
 
 
-	host->ndtr0cs0 = ndtr0;
-	host->ndtr1cs0 = ndtr1;
+	info->ndtr0cs0 = ndtr0;
+	info->ndtr1cs0 = ndtr1;
 	nand_writel(info, NDTR0CS0, ndtr0);
 	nand_writel(info, NDTR0CS0, ndtr0);
 	nand_writel(info, NDTR1CS0, ndtr1);
 	nand_writel(info, NDTR1CS0, ndtr1);
 }
 }
@@ -273,7 +275,7 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
 static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
 static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
 {
 {
 	struct pxa3xx_nand_host *host = info->host[info->cs];
 	struct pxa3xx_nand_host *host = info->host[info->cs];
-	int oob_enable = host->reg_ndcr & NDCR_SPARE_EN;
+	int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
 
 
 	info->data_size = host->page_size;
 	info->data_size = host->page_size;
 	if (!oob_enable) {
 	if (!oob_enable) {
@@ -299,12 +301,25 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
  */
  */
 static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
 static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
 {
 {
-	struct pxa3xx_nand_host *host = info->host[info->cs];
 	uint32_t ndcr;
 	uint32_t ndcr;
 
 
-	ndcr = host->reg_ndcr;
-	ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
-	ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
+	ndcr = info->reg_ndcr;
+
+	if (info->use_ecc)
+		ndcr |= NDCR_ECC_EN;
+	else
+		ndcr &= ~NDCR_ECC_EN;
+
+	if (info->use_dma)
+		ndcr |= NDCR_DMA_EN;
+	else
+		ndcr &= ~NDCR_DMA_EN;
+
+	if (info->use_spare)
+		ndcr |= NDCR_SPARE_EN;
+	else
+		ndcr &= ~NDCR_SPARE_EN;
+
 	ndcr |= NDCR_ND_RUN;
 	ndcr |= NDCR_ND_RUN;
 
 
 	/* clear status bits and run */
 	/* clear status bits and run */
@@ -333,7 +348,8 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
 	nand_writel(info, NDSR, NDSR_MASK);
 	nand_writel(info, NDSR, NDSR_MASK);
 }
 }
 
 
-static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+static void __maybe_unused
+enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
 {
 {
 	uint32_t ndcr;
 	uint32_t ndcr;
 
 
@@ -373,6 +389,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
 	}
 	}
 }
 }
 
 
+#ifdef ARCH_HAS_DMA
 static void start_data_dma(struct pxa3xx_nand_info *info)
 static void start_data_dma(struct pxa3xx_nand_info *info)
 {
 {
 	struct pxa_dma_desc *desc = info->data_desc;
 	struct pxa_dma_desc *desc = info->data_desc;
@@ -419,6 +436,10 @@ static void pxa3xx_nand_data_dma_irq(int channel, void *data)
 	enable_int(info, NDCR_INT_MASK);
 	enable_int(info, NDCR_INT_MASK);
 	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
 	nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
 }
 }
+#else
+static void start_data_dma(struct pxa3xx_nand_info *info)
+{}
+#endif
 
 
 static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 {
 {
@@ -467,9 +488,22 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 		nand_writel(info, NDSR, NDSR_WRCMDREQ);
 		nand_writel(info, NDSR, NDSR_WRCMDREQ);
 		status &= ~NDSR_WRCMDREQ;
 		status &= ~NDSR_WRCMDREQ;
 		info->state = STATE_CMD_HANDLE;
 		info->state = STATE_CMD_HANDLE;
+
+		/*
+		 * Command buffer registers NDCB{0-2} (and optionally NDCB3)
+		 * must be loaded by writing directly either 12 or 16
+		 * bytes directly to NDCB0, four bytes at a time.
+		 *
+		 * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored
+		 * but each NDCBx register can be read.
+		 */
 		nand_writel(info, NDCB0, info->ndcb0);
 		nand_writel(info, NDCB0, info->ndcb0);
 		nand_writel(info, NDCB0, info->ndcb1);
 		nand_writel(info, NDCB0, info->ndcb1);
 		nand_writel(info, NDCB0, info->ndcb2);
 		nand_writel(info, NDCB0, info->ndcb2);
+
+		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
+		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
+			nand_writel(info, NDCB0, info->ndcb3);
 	}
 	}
 
 
 	/* clear NDSR to let the controller exit the IRQ */
 	/* clear NDSR to let the controller exit the IRQ */
@@ -491,7 +525,6 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
 static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
 static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
 		uint16_t column, int page_addr)
 		uint16_t column, int page_addr)
 {
 {
-	uint16_t cmd;
 	int addr_cycle, exec_cmd;
 	int addr_cycle, exec_cmd;
 	struct pxa3xx_nand_host *host;
 	struct pxa3xx_nand_host *host;
 	struct mtd_info *mtd;
 	struct mtd_info *mtd;
@@ -506,6 +539,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
 	info->buf_count		= 0;
 	info->buf_count		= 0;
 	info->oob_size		= 0;
 	info->oob_size		= 0;
 	info->use_ecc		= 0;
 	info->use_ecc		= 0;
+	info->use_spare		= 1;
+	info->use_dma		= (use_dma) ? 1 : 0;
 	info->is_ready		= 0;
 	info->is_ready		= 0;
 	info->retcode		= ERR_NONE;
 	info->retcode		= ERR_NONE;
 	if (info->cs != 0)
 	if (info->cs != 0)
@@ -520,12 +555,16 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
 	case NAND_CMD_READOOB:
 	case NAND_CMD_READOOB:
 		pxa3xx_set_datasize(info);
 		pxa3xx_set_datasize(info);
 		break;
 		break;
+	case NAND_CMD_PARAM:
+		info->use_spare = 0;
+		break;
 	case NAND_CMD_SEQIN:
 	case NAND_CMD_SEQIN:
 		exec_cmd = 0;
 		exec_cmd = 0;
 		break;
 		break;
 	default:
 	default:
 		info->ndcb1 = 0;
 		info->ndcb1 = 0;
 		info->ndcb2 = 0;
 		info->ndcb2 = 0;
+		info->ndcb3 = 0;
 		break;
 		break;
 	}
 	}
 
 
@@ -535,21 +574,17 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
 	switch (command) {
 	switch (command) {
 	case NAND_CMD_READOOB:
 	case NAND_CMD_READOOB:
 	case NAND_CMD_READ0:
 	case NAND_CMD_READ0:
-		cmd = host->cmdset->read1;
+		info->buf_start = column;
+		info->ndcb0 |= NDCB0_CMD_TYPE(0)
+				| addr_cycle
+				| NAND_CMD_READ0;
+
 		if (command == NAND_CMD_READOOB)
 		if (command == NAND_CMD_READOOB)
-			info->buf_start = mtd->writesize + column;
-		else
-			info->buf_start = column;
+			info->buf_start += mtd->writesize;
 
 
-		if (unlikely(host->page_size < PAGE_CHUNK_SIZE))
-			info->ndcb0 |= NDCB0_CMD_TYPE(0)
-					| addr_cycle
-					| (cmd & NDCB0_CMD1_MASK);
-		else
-			info->ndcb0 |= NDCB0_CMD_TYPE(0)
-					| NDCB0_DBC
-					| addr_cycle
-					| cmd;
+		/* Second command setting for large pages */
+		if (host->page_size >= PAGE_CHUNK_SIZE)
+			info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
 
 
 	case NAND_CMD_SEQIN:
 	case NAND_CMD_SEQIN:
 		/* small page addr setting */
 		/* small page addr setting */
@@ -580,49 +615,58 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
 			break;
 			break;
 		}
 		}
 
 
-		cmd = host->cmdset->program;
 		info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
 		info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
 				| NDCB0_AUTO_RS
 				| NDCB0_AUTO_RS
 				| NDCB0_ST_ROW_EN
 				| NDCB0_ST_ROW_EN
 				| NDCB0_DBC
 				| NDCB0_DBC
-				| cmd
+				| (NAND_CMD_PAGEPROG << 8)
+				| NAND_CMD_SEQIN
 				| addr_cycle;
 				| addr_cycle;
 		break;
 		break;
 
 
+	case NAND_CMD_PARAM:
+		info->buf_count = 256;
+		info->ndcb0 |= NDCB0_CMD_TYPE(0)
+				| NDCB0_ADDR_CYC(1)
+				| NDCB0_LEN_OVRD
+				| command;
+		info->ndcb1 = (column & 0xFF);
+		info->ndcb3 = 256;
+		info->data_size = 256;
+		break;
+
 	case NAND_CMD_READID:
 	case NAND_CMD_READID:
-		cmd = host->cmdset->read_id;
 		info->buf_count = host->read_id_bytes;
 		info->buf_count = host->read_id_bytes;
 		info->ndcb0 |= NDCB0_CMD_TYPE(3)
 		info->ndcb0 |= NDCB0_CMD_TYPE(3)
 				| NDCB0_ADDR_CYC(1)
 				| NDCB0_ADDR_CYC(1)
-				| cmd;
+				| command;
+		info->ndcb1 = (column & 0xFF);
 
 
 		info->data_size = 8;
 		info->data_size = 8;
 		break;
 		break;
 	case NAND_CMD_STATUS:
 	case NAND_CMD_STATUS:
-		cmd = host->cmdset->read_status;
 		info->buf_count = 1;
 		info->buf_count = 1;
 		info->ndcb0 |= NDCB0_CMD_TYPE(4)
 		info->ndcb0 |= NDCB0_CMD_TYPE(4)
 				| NDCB0_ADDR_CYC(1)
 				| NDCB0_ADDR_CYC(1)
-				| cmd;
+				| command;
 
 
 		info->data_size = 8;
 		info->data_size = 8;
 		break;
 		break;
 
 
 	case NAND_CMD_ERASE1:
 	case NAND_CMD_ERASE1:
-		cmd = host->cmdset->erase;
 		info->ndcb0 |= NDCB0_CMD_TYPE(2)
 		info->ndcb0 |= NDCB0_CMD_TYPE(2)
 				| NDCB0_AUTO_RS
 				| NDCB0_AUTO_RS
 				| NDCB0_ADDR_CYC(3)
 				| NDCB0_ADDR_CYC(3)
 				| NDCB0_DBC
 				| NDCB0_DBC
-				| cmd;
+				| (NAND_CMD_ERASE2 << 8)
+				| NAND_CMD_ERASE1;
 		info->ndcb1 = page_addr;
 		info->ndcb1 = page_addr;
 		info->ndcb2 = 0;
 		info->ndcb2 = 0;
 
 
 		break;
 		break;
 	case NAND_CMD_RESET:
 	case NAND_CMD_RESET:
-		cmd = host->cmdset->reset;
 		info->ndcb0 |= NDCB0_CMD_TYPE(5)
 		info->ndcb0 |= NDCB0_CMD_TYPE(5)
-				| cmd;
+				| command;
 
 
 		break;
 		break;
 
 
@@ -652,7 +696,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
 	 * "byte" address into a "word" address appropriate
 	 * "byte" address into a "word" address appropriate
 	 * for indexing a word-oriented device
 	 * for indexing a word-oriented device
 	 */
 	 */
-	if (host->reg_ndcr & NDCR_DWIDTH_M)
+	if (info->reg_ndcr & NDCR_DWIDTH_M)
 		column /= 2;
 		column /= 2;
 
 
 	/*
 	/*
@@ -662,8 +706,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
 	 */
 	 */
 	if (info->cs != host->cs) {
 	if (info->cs != host->cs) {
 		info->cs = host->cs;
 		info->cs = host->cs;
-		nand_writel(info, NDTR0CS0, host->ndtr0cs0);
-		nand_writel(info, NDTR1CS0, host->ndtr1cs0);
+		nand_writel(info, NDTR0CS0, info->ndtr0cs0);
+		nand_writel(info, NDTR1CS0, info->ndtr1cs0);
 	}
 	}
 
 
 	info->state = STATE_PREPARED;
 	info->state = STATE_PREPARED;
@@ -803,7 +847,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
 				    const struct pxa3xx_nand_flash *f)
 				    const struct pxa3xx_nand_flash *f)
 {
 {
 	struct platform_device *pdev = info->pdev;
 	struct platform_device *pdev = info->pdev;
-	struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
+	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct pxa3xx_nand_host *host = info->host[info->cs];
 	struct pxa3xx_nand_host *host = info->host[info->cs];
 	uint32_t ndcr = 0x0; /* enable all interrupts */
 	uint32_t ndcr = 0x0; /* enable all interrupts */
 
 
@@ -818,7 +862,6 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
 	}
 	}
 
 
 	/* calculate flash information */
 	/* calculate flash information */
-	host->cmdset = &default_cmdset;
 	host->page_size = f->page_size;
 	host->page_size = f->page_size;
 	host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
 	host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
 
 
@@ -840,7 +883,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
 	ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes);
 	ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes);
 	ndcr |= NDCR_SPARE_EN; /* enable spare by default */
 	ndcr |= NDCR_SPARE_EN; /* enable spare by default */
 
 
-	host->reg_ndcr = ndcr;
+	info->reg_ndcr = ndcr;
 
 
 	pxa3xx_nand_set_timing(host, f->timing);
 	pxa3xx_nand_set_timing(host, f->timing);
 	return 0;
 	return 0;
@@ -863,12 +906,9 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
 		host->read_id_bytes = 2;
 		host->read_id_bytes = 2;
 	}
 	}
 
 
-	host->reg_ndcr = ndcr & ~NDCR_INT_MASK;
-	host->cmdset = &default_cmdset;
-
-	host->ndtr0cs0 = nand_readl(info, NDTR0CS0);
-	host->ndtr1cs0 = nand_readl(info, NDTR1CS0);
-
+	info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
+	info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
+	info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -878,6 +918,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
  */
  */
 #define MAX_BUFF_SIZE	PAGE_SIZE
 #define MAX_BUFF_SIZE	PAGE_SIZE
 
 
+#ifdef ARCH_HAS_DMA
 static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 {
 {
 	struct platform_device *pdev = info->pdev;
 	struct platform_device *pdev = info->pdev;
@@ -912,6 +953,32 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 	return 0;
 	return 0;
 }
 }
 
 
+static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
+{
+	struct platform_device *pdev = info->pdev;
+	if (use_dma) {
+		pxa_free_dma(info->data_dma_ch);
+		dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
+				  info->data_buff, info->data_buff_phys);
+	} else {
+		kfree(info->data_buff);
+	}
+}
+#else
+static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
+{
+	info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
+	if (info->data_buff == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
+{
+	kfree(info->data_buff);
+}
+#endif
+
 static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
 static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
 {
 {
 	struct mtd_info *mtd;
 	struct mtd_info *mtd;
@@ -934,7 +1001,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
 	struct pxa3xx_nand_host *host = mtd->priv;
 	struct pxa3xx_nand_host *host = mtd->priv;
 	struct pxa3xx_nand_info *info = host->info_data;
 	struct pxa3xx_nand_info *info = host->info_data;
 	struct platform_device *pdev = info->pdev;
 	struct platform_device *pdev = info->pdev;
-	struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
+	struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
 	struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
 	const struct pxa3xx_nand_flash *f = NULL;
 	const struct pxa3xx_nand_flash *f = NULL;
 	struct nand_chip *chip = mtd->priv;
 	struct nand_chip *chip = mtd->priv;
@@ -1003,7 +1070,7 @@ KEEP_CONFIG:
 	chip->ecc.size = host->page_size;
 	chip->ecc.size = host->page_size;
 	chip->ecc.strength = 1;
 	chip->ecc.strength = 1;
 
 
-	if (host->reg_ndcr & NDCR_DWIDTH_M)
+	if (info->reg_ndcr & NDCR_DWIDTH_M)
 		chip->options |= NAND_BUSWIDTH_16;
 		chip->options |= NAND_BUSWIDTH_16;
 
 
 	if (nand_scan_ident(mtd, 1, def))
 	if (nand_scan_ident(mtd, 1, def))
@@ -1019,8 +1086,6 @@ KEEP_CONFIG:
 		host->row_addr_cycles = 3;
 		host->row_addr_cycles = 3;
 	else
 	else
 		host->row_addr_cycles = 2;
 		host->row_addr_cycles = 2;
-
-	mtd->name = mtd_names[0];
 	return nand_scan_tail(mtd);
 	return nand_scan_tail(mtd);
 }
 }
 
 
@@ -1034,13 +1099,11 @@ static int alloc_nand_resource(struct platform_device *pdev)
 	struct resource *r;
 	struct resource *r;
 	int ret, irq, cs;
 	int ret, irq, cs;
 
 
-	pdata = pdev->dev.platform_data;
-	info = kzalloc(sizeof(*info) + (sizeof(*mtd) +
-		       sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
-	if (!info) {
-		dev_err(&pdev->dev, "failed to allocate memory\n");
+	pdata = dev_get_platdata(&pdev->dev);
+	info = devm_kzalloc(&pdev->dev, sizeof(*info) + (sizeof(*mtd) +
+			    sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
+	if (!info)
 		return -ENOMEM;
 		return -ENOMEM;
-	}
 
 
 	info->pdev = pdev;
 	info->pdev = pdev;
 	for (cs = 0; cs < pdata->num_cs; cs++) {
 	for (cs = 0; cs < pdata->num_cs; cs++) {
@@ -1069,72 +1132,64 @@ static int alloc_nand_resource(struct platform_device *pdev)
 
 
 	spin_lock_init(&chip->controller->lock);
 	spin_lock_init(&chip->controller->lock);
 	init_waitqueue_head(&chip->controller->wq);
 	init_waitqueue_head(&chip->controller->wq);
-	info->clk = clk_get(&pdev->dev, NULL);
+	info->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(info->clk)) {
 	if (IS_ERR(info->clk)) {
 		dev_err(&pdev->dev, "failed to get nand clock\n");
 		dev_err(&pdev->dev, "failed to get nand clock\n");
-		ret = PTR_ERR(info->clk);
-		goto fail_free_mtd;
+		return PTR_ERR(info->clk);
 	}
 	}
-	clk_enable(info->clk);
-
-	/*
-	 * This is a dirty hack to make this driver work from devicetree
-	 * bindings. It can be removed once we have a prober DMA controller
-	 * framework for DT.
-	 */
-	if (pdev->dev.of_node && cpu_is_pxa3xx()) {
-		info->drcmr_dat = 97;
-		info->drcmr_cmd = 99;
-	} else {
-		r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-		if (r == NULL) {
-			dev_err(&pdev->dev, "no resource defined for data DMA\n");
-			ret = -ENXIO;
-			goto fail_put_clk;
-		}
-		info->drcmr_dat = r->start;
+	ret = clk_prepare_enable(info->clk);
+	if (ret < 0)
+		return ret;
 
 
-		r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-		if (r == NULL) {
-			dev_err(&pdev->dev, "no resource defined for command DMA\n");
-			ret = -ENXIO;
-			goto fail_put_clk;
+	if (use_dma) {
+		/*
+		 * This is a dirty hack to make this driver work from
+		 * devicetree bindings. It can be removed once we have
+		 * a prober DMA controller framework for DT.
+		 */
+		if (pdev->dev.of_node &&
+		    of_machine_is_compatible("marvell,pxa3xx")) {
+			info->drcmr_dat = 97;
+			info->drcmr_cmd = 99;
+		} else {
+			r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+			if (r == NULL) {
+				dev_err(&pdev->dev,
+					"no resource defined for data DMA\n");
+				ret = -ENXIO;
+				goto fail_disable_clk;
+			}
+			info->drcmr_dat = r->start;
+
+			r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+			if (r == NULL) {
+				dev_err(&pdev->dev,
+					"no resource defined for cmd DMA\n");
+				ret = -ENXIO;
+				goto fail_disable_clk;
+			}
+			info->drcmr_cmd = r->start;
 		}
 		}
-		info->drcmr_cmd = r->start;
 	}
 	}
 
 
 	irq = platform_get_irq(pdev, 0);
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 	if (irq < 0) {
 		dev_err(&pdev->dev, "no IRQ resource defined\n");
 		dev_err(&pdev->dev, "no IRQ resource defined\n");
 		ret = -ENXIO;
 		ret = -ENXIO;
-		goto fail_put_clk;
+		goto fail_disable_clk;
 	}
 	}
 
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "no IO memory resource defined\n");
-		ret = -ENODEV;
-		goto fail_put_clk;
-	}
-
-	r = request_mem_region(r->start, resource_size(r), pdev->name);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "failed to request memory resource\n");
-		ret = -EBUSY;
-		goto fail_put_clk;
-	}
-
-	info->mmio_base = ioremap(r->start, resource_size(r));
-	if (info->mmio_base == NULL) {
-		dev_err(&pdev->dev, "ioremap() failed\n");
-		ret = -ENODEV;
-		goto fail_free_res;
+	info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(info->mmio_base)) {
+		ret = PTR_ERR(info->mmio_base);
+		goto fail_disable_clk;
 	}
 	}
 	info->mmio_phys = r->start;
 	info->mmio_phys = r->start;
 
 
 	ret = pxa3xx_nand_init_buff(info);
 	ret = pxa3xx_nand_init_buff(info);
 	if (ret)
 	if (ret)
-		goto fail_free_io;
+		goto fail_disable_clk;
 
 
 	/* initialize all interrupts to be disabled */
 	/* initialize all interrupts to be disabled */
 	disable_int(info, NDSR_MASK);
 	disable_int(info, NDSR_MASK);
@@ -1152,21 +1207,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
 
 
 fail_free_buf:
 fail_free_buf:
 	free_irq(irq, info);
 	free_irq(irq, info);
-	if (use_dma) {
-		pxa_free_dma(info->data_dma_ch);
-		dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
-			info->data_buff, info->data_buff_phys);
-	} else
-		kfree(info->data_buff);
-fail_free_io:
-	iounmap(info->mmio_base);
-fail_free_res:
-	release_mem_region(r->start, resource_size(r));
-fail_put_clk:
-	clk_disable(info->clk);
-	clk_put(info->clk);
-fail_free_mtd:
-	kfree(info);
+	pxa3xx_nand_free_buff(info);
+fail_disable_clk:
+	clk_disable_unprepare(info->clk);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -1174,44 +1217,48 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
 {
 {
 	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
 	struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
 	struct pxa3xx_nand_platform_data *pdata;
 	struct pxa3xx_nand_platform_data *pdata;
-	struct resource *r;
 	int irq, cs;
 	int irq, cs;
 
 
 	if (!info)
 	if (!info)
 		return 0;
 		return 0;
 
 
-	pdata = pdev->dev.platform_data;
-	platform_set_drvdata(pdev, NULL);
+	pdata = dev_get_platdata(&pdev->dev);
 
 
 	irq = platform_get_irq(pdev, 0);
 	irq = platform_get_irq(pdev, 0);
 	if (irq >= 0)
 	if (irq >= 0)
 		free_irq(irq, info);
 		free_irq(irq, info);
-	if (use_dma) {
-		pxa_free_dma(info->data_dma_ch);
-		dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE,
-				info->data_buff, info->data_buff_phys);
-	} else
-		kfree(info->data_buff);
-
-	iounmap(info->mmio_base);
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(r->start, resource_size(r));
+	pxa3xx_nand_free_buff(info);
 
 
-	clk_disable(info->clk);
-	clk_put(info->clk);
+	clk_disable_unprepare(info->clk);
 
 
 	for (cs = 0; cs < pdata->num_cs; cs++)
 	for (cs = 0; cs < pdata->num_cs; cs++)
 		nand_release(info->host[cs]->mtd);
 		nand_release(info->host[cs]->mtd);
-	kfree(info);
 	return 0;
 	return 0;
 }
 }
 
 
 #ifdef CONFIG_OF
 #ifdef CONFIG_OF
 static struct of_device_id pxa3xx_nand_dt_ids[] = {
 static struct of_device_id pxa3xx_nand_dt_ids[] = {
-	{ .compatible = "marvell,pxa3xx-nand" },
+	{
+		.compatible = "marvell,pxa3xx-nand",
+		.data       = (void *)PXA3XX_NAND_VARIANT_PXA,
+	},
+	{
+		.compatible = "marvell,armada370-nand",
+		.data       = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
+	},
 	{}
 	{}
 };
 };
-MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
+
+static enum pxa3xx_nand_variant
+pxa3xx_nand_get_variant(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+			of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
+	if (!of_id)
+		return PXA3XX_NAND_VARIANT_PXA;
+	return (enum pxa3xx_nand_variant)of_id->data;
+}
 
 
 static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
 static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
 {
 {
@@ -1251,11 +1298,18 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
 	struct pxa3xx_nand_info *info;
 	struct pxa3xx_nand_info *info;
 	int ret, cs, probe_success;
 	int ret, cs, probe_success;
 
 
+#ifndef ARCH_HAS_DMA
+	if (use_dma) {
+		use_dma = 0;
+		dev_warn(&pdev->dev,
+			 "This platform can't do DMA on this device\n");
+	}
+#endif
 	ret = pxa3xx_nand_probe_dt(pdev);
 	ret = pxa3xx_nand_probe_dt(pdev);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (!pdata) {
 	if (!pdata) {
 		dev_err(&pdev->dev, "no platform data defined\n");
 		dev_err(&pdev->dev, "no platform data defined\n");
 		return -ENODEV;
 		return -ENODEV;
@@ -1268,10 +1322,14 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	info = platform_get_drvdata(pdev);
 	info = platform_get_drvdata(pdev);
+	info->variant = pxa3xx_nand_get_variant(pdev);
 	probe_success = 0;
 	probe_success = 0;
 	for (cs = 0; cs < pdata->num_cs; cs++) {
 	for (cs = 0; cs < pdata->num_cs; cs++) {
+		struct mtd_info *mtd = info->host[cs]->mtd;
+
+		mtd->name = pdev->name;
 		info->cs = cs;
 		info->cs = cs;
-		ret = pxa3xx_nand_scan(info->host[cs]->mtd);
+		ret = pxa3xx_nand_scan(mtd);
 		if (ret) {
 		if (ret) {
 			dev_warn(&pdev->dev, "failed to scan nand at cs %d\n",
 			dev_warn(&pdev->dev, "failed to scan nand at cs %d\n",
 				cs);
 				cs);
@@ -1279,7 +1337,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
 		}
 		}
 
 
 		ppdata.of_node = pdev->dev.of_node;
 		ppdata.of_node = pdev->dev.of_node;
-		ret = mtd_device_parse_register(info->host[cs]->mtd, NULL,
+		ret = mtd_device_parse_register(mtd, NULL,
 						&ppdata, pdata->parts[cs],
 						&ppdata, pdata->parts[cs],
 						pdata->nr_parts[cs]);
 						pdata->nr_parts[cs]);
 		if (!ret)
 		if (!ret)
@@ -1302,7 +1360,7 @@ static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
 	struct mtd_info *mtd;
 	struct mtd_info *mtd;
 	int cs;
 	int cs;
 
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (info->state) {
 	if (info->state) {
 		dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);
 		dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);
 		return -EAGAIN;
 		return -EAGAIN;
@@ -1323,7 +1381,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
 	struct mtd_info *mtd;
 	struct mtd_info *mtd;
 	int cs;
 	int cs;
 
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	/* We don't want to handle interrupt without calling mtd routine */
 	/* We don't want to handle interrupt without calling mtd routine */
 	disable_int(info, NDCR_INT_MASK);
 	disable_int(info, NDCR_INT_MASK);
 
 

+ 23 - 26
drivers/mtd/nand/r852.c

@@ -229,7 +229,7 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
 /*
 /*
  * Program data lines of the nand chip to send data to it
  * Program data lines of the nand chip to send data to it
  */
  */
-void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
 {
 	struct r852_device *dev = r852_get_dev(mtd);
 	struct r852_device *dev = r852_get_dev(mtd);
 	uint32_t reg;
 	uint32_t reg;
@@ -261,7 +261,7 @@ void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 /*
 /*
  * Read data lines of the nand chip to retrieve data
  * Read data lines of the nand chip to retrieve data
  */
  */
-void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
 {
 	struct r852_device *dev = r852_get_dev(mtd);
 	struct r852_device *dev = r852_get_dev(mtd);
 	uint32_t reg;
 	uint32_t reg;
@@ -312,7 +312,7 @@ static uint8_t r852_read_byte(struct mtd_info *mtd)
 /*
 /*
  * Control several chip lines & send commands
  * Control several chip lines & send commands
  */
  */
-void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
 {
 {
 	struct r852_device *dev = r852_get_dev(mtd);
 	struct r852_device *dev = r852_get_dev(mtd);
 
 
@@ -357,7 +357,7 @@ void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
  * Wait till card is ready.
  * Wait till card is ready.
  * based on nand_wait, but returns errors on DMA error
  * based on nand_wait, but returns errors on DMA error
  */
  */
-int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
 {
 	struct r852_device *dev = chip->priv;
 	struct r852_device *dev = chip->priv;
 
 
@@ -386,7 +386,7 @@ int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
  * Check if card is ready
  * Check if card is ready
  */
  */
 
 
-int r852_ready(struct mtd_info *mtd)
+static int r852_ready(struct mtd_info *mtd)
 {
 {
 	struct r852_device *dev = r852_get_dev(mtd);
 	struct r852_device *dev = r852_get_dev(mtd);
 	return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
 	return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
@@ -397,7 +397,7 @@ int r852_ready(struct mtd_info *mtd)
  * Set ECC engine mode
  * Set ECC engine mode
 */
 */
 
 
-void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
+static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
 {
 {
 	struct r852_device *dev = r852_get_dev(mtd);
 	struct r852_device *dev = r852_get_dev(mtd);
 
 
@@ -429,7 +429,7 @@ void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
  * Calculate ECC, only used for writes
  * Calculate ECC, only used for writes
  */
  */
 
 
-int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
+static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
 							uint8_t *ecc_code)
 							uint8_t *ecc_code)
 {
 {
 	struct r852_device *dev = r852_get_dev(mtd);
 	struct r852_device *dev = r852_get_dev(mtd);
@@ -461,7 +461,7 @@ int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
  * Correct the data using ECC, hw did almost everything for us
  * Correct the data using ECC, hw did almost everything for us
  */
  */
 
 
-int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
+static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
 				uint8_t *read_ecc, uint8_t *calc_ecc)
 				uint8_t *read_ecc, uint8_t *calc_ecc)
 {
 {
 	uint16_t ecc_reg;
 	uint16_t ecc_reg;
@@ -529,7 +529,7 @@ static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
  * Start the nand engine
  * Start the nand engine
  */
  */
 
 
-void r852_engine_enable(struct r852_device *dev)
+static void r852_engine_enable(struct r852_device *dev)
 {
 {
 	if (r852_read_reg_dword(dev, R852_HW) & R852_HW_UNKNOWN) {
 	if (r852_read_reg_dword(dev, R852_HW) & R852_HW_UNKNOWN) {
 		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
 		r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
@@ -547,7 +547,7 @@ void r852_engine_enable(struct r852_device *dev)
  * Stop the nand engine
  * Stop the nand engine
  */
  */
 
 
-void r852_engine_disable(struct r852_device *dev)
+static void r852_engine_disable(struct r852_device *dev)
 {
 {
 	r852_write_reg_dword(dev, R852_HW, 0);
 	r852_write_reg_dword(dev, R852_HW, 0);
 	r852_write_reg(dev, R852_CTL, R852_CTL_RESET);
 	r852_write_reg(dev, R852_CTL, R852_CTL_RESET);
@@ -557,7 +557,7 @@ void r852_engine_disable(struct r852_device *dev)
  * Test if card is present
  * Test if card is present
  */
  */
 
 
-void r852_card_update_present(struct r852_device *dev)
+static void r852_card_update_present(struct r852_device *dev)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 	uint8_t reg;
 	uint8_t reg;
@@ -572,7 +572,7 @@ void r852_card_update_present(struct r852_device *dev)
  * Update card detection IRQ state according to current card state
  * Update card detection IRQ state according to current card state
  * which is read in r852_card_update_present
  * which is read in r852_card_update_present
  */
  */
-void r852_update_card_detect(struct r852_device *dev)
+static void r852_update_card_detect(struct r852_device *dev)
 {
 {
 	int card_detect_reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
 	int card_detect_reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
 	dev->card_unstable = 0;
 	dev->card_unstable = 0;
@@ -586,8 +586,8 @@ void r852_update_card_detect(struct r852_device *dev)
 	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg);
 	r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg);
 }
 }
 
 
-ssize_t r852_media_type_show(struct device *sys_dev,
-		struct device_attribute *attr, char *buf)
+static ssize_t r852_media_type_show(struct device *sys_dev,
+			struct device_attribute *attr, char *buf)
 {
 {
 	struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev);
 	struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev);
 	struct r852_device *dev = r852_get_dev(mtd);
 	struct r852_device *dev = r852_get_dev(mtd);
@@ -597,11 +597,11 @@ ssize_t r852_media_type_show(struct device *sys_dev,
 	return strlen(data);
 	return strlen(data);
 }
 }
 
 
-DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
+static DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
 
 
 
 
 /* Detect properties of card in slot */
 /* Detect properties of card in slot */
-void r852_update_media_status(struct r852_device *dev)
+static void r852_update_media_status(struct r852_device *dev)
 {
 {
 	uint8_t reg;
 	uint8_t reg;
 	unsigned long flags;
 	unsigned long flags;
@@ -630,7 +630,7 @@ void r852_update_media_status(struct r852_device *dev)
  * Register the nand device
  * Register the nand device
  * Called when the card is detected
  * Called when the card is detected
  */
  */
-int r852_register_nand_device(struct r852_device *dev)
+static int r852_register_nand_device(struct r852_device *dev)
 {
 {
 	dev->mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
 	dev->mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
 
 
@@ -668,7 +668,7 @@ error1:
  * Unregister the card
  * Unregister the card
  */
  */
 
 
-void r852_unregister_nand_device(struct r852_device *dev)
+static void r852_unregister_nand_device(struct r852_device *dev)
 {
 {
 	if (!dev->card_registred)
 	if (!dev->card_registred)
 		return;
 		return;
@@ -682,7 +682,7 @@ void r852_unregister_nand_device(struct r852_device *dev)
 }
 }
 
 
 /* Card state updater */
 /* Card state updater */
-void r852_card_detect_work(struct work_struct *work)
+static void r852_card_detect_work(struct work_struct *work)
 {
 {
 	struct r852_device *dev =
 	struct r852_device *dev =
 		container_of(work, struct r852_device, card_detect_work.work);
 		container_of(work, struct r852_device, card_detect_work.work);
@@ -821,7 +821,7 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
-int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 {
 {
 	int error;
 	int error;
 	struct nand_chip *chip;
 	struct nand_chip *chip;
@@ -961,7 +961,7 @@ error1:
 	return error;
 	return error;
 }
 }
 
 
-void r852_remove(struct pci_dev *pci_dev)
+static void r852_remove(struct pci_dev *pci_dev)
 {
 {
 	struct r852_device *dev = pci_get_drvdata(pci_dev);
 	struct r852_device *dev = pci_get_drvdata(pci_dev);
 
 
@@ -992,7 +992,7 @@ void r852_remove(struct pci_dev *pci_dev)
 	pci_disable_device(pci_dev);
 	pci_disable_device(pci_dev);
 }
 }
 
 
-void r852_shutdown(struct pci_dev *pci_dev)
+static void r852_shutdown(struct pci_dev *pci_dev)
 {
 {
 	struct r852_device *dev = pci_get_drvdata(pci_dev);
 	struct r852_device *dev = pci_get_drvdata(pci_dev);
 
 
@@ -1002,7 +1002,7 @@ void r852_shutdown(struct pci_dev *pci_dev)
 	pci_disable_device(pci_dev);
 	pci_disable_device(pci_dev);
 }
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int r852_suspend(struct device *device)
 static int r852_suspend(struct device *device)
 {
 {
 	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
 	struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
@@ -1055,9 +1055,6 @@ static int r852_resume(struct device *device)
 	r852_update_card_detect(dev);
 	r852_update_card_detect(dev);
 	return 0;
 	return 0;
 }
 }
-#else
-#define r852_suspend	NULL
-#define r852_resume	NULL
 #endif
 #endif
 
 
 static const struct pci_device_id r852_pci_id_tbl[] = {
 static const struct pci_device_id r852_pci_id_tbl[] = {

+ 1 - 3
drivers/mtd/nand/s3c2410.c

@@ -150,7 +150,7 @@ static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
 
 
 static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
 static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
 {
 {
-	return dev->dev.platform_data;
+	return dev_get_platdata(&dev->dev);
 }
 }
 
 
 static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
 static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
@@ -697,8 +697,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
 {
 {
 	struct s3c2410_nand_info *info = to_nand_info(pdev);
 	struct s3c2410_nand_info *info = to_nand_info(pdev);
 
 
-	platform_set_drvdata(pdev, NULL);
-
 	if (info == NULL)
 	if (info == NULL)
 		return 0;
 		return 0;
 
 

+ 2 - 2
drivers/mtd/nand/sh_flctl.c

@@ -137,7 +137,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
 	dma_cap_mask_t mask;
 	dma_cap_mask_t mask;
 	struct dma_slave_config cfg;
 	struct dma_slave_config cfg;
 	struct platform_device *pdev = flctl->pdev;
 	struct platform_device *pdev = flctl->pdev;
-	struct sh_flctl_platform_data *pdata = pdev->dev.platform_data;
+	struct sh_flctl_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	int ret;
 	int ret;
 
 
 	if (!pdata)
 	if (!pdata)
@@ -1131,7 +1131,7 @@ static int flctl_probe(struct platform_device *pdev)
 	if (pdev->dev.of_node)
 	if (pdev->dev.of_node)
 		pdata = flctl_parse_dt(&pdev->dev);
 		pdata = flctl_parse_dt(&pdev->dev);
 	else
 	else
-		pdata = pdev->dev.platform_data;
+		pdata = dev_get_platdata(&pdev->dev);
 
 
 	if (!pdata) {
 	if (!pdata) {
 		dev_err(&pdev->dev, "no setup data defined\n");
 		dev_err(&pdev->dev, "no setup data defined\n");

+ 1 - 4
drivers/mtd/nand/sharpsl.c

@@ -112,7 +112,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
 	struct resource *r;
 	struct resource *r;
 	int err = 0;
 	int err = 0;
 	struct sharpsl_nand *sharpsl;
 	struct sharpsl_nand *sharpsl;
-	struct sharpsl_nand_platform_data *data = pdev->dev.platform_data;
+	struct sharpsl_nand_platform_data *data = dev_get_platdata(&pdev->dev);
 
 
 	if (!data) {
 	if (!data) {
 		dev_err(&pdev->dev, "no platform data!\n");
 		dev_err(&pdev->dev, "no platform data!\n");
@@ -194,7 +194,6 @@ err_add:
 	nand_release(&sharpsl->mtd);
 	nand_release(&sharpsl->mtd);
 
 
 err_scan:
 err_scan:
-	platform_set_drvdata(pdev, NULL);
 	iounmap(sharpsl->io);
 	iounmap(sharpsl->io);
 err_ioremap:
 err_ioremap:
 err_get_res:
 err_get_res:
@@ -212,8 +211,6 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
 	/* Release resources, unregister device */
 	/* Release resources, unregister device */
 	nand_release(&sharpsl->mtd);
 	nand_release(&sharpsl->mtd);
 
 
-	platform_set_drvdata(pdev, NULL);
-
 	iounmap(sharpsl->io);
 	iounmap(sharpsl->io);
 
 
 	/* Free the MTD device structure */
 	/* Free the MTD device structure */

+ 4 - 5
drivers/mtd/nand/sm_common.c

@@ -42,7 +42,7 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
 {
 	struct mtd_oob_ops ops;
 	struct mtd_oob_ops ops;
 	struct sm_oob oob;
 	struct sm_oob oob;
-	int ret, error = 0;
+	int ret;
 
 
 	memset(&oob, -1, SM_OOB_SIZE);
 	memset(&oob, -1, SM_OOB_SIZE);
 	oob.block_status = 0x0F;
 	oob.block_status = 0x0F;
@@ -61,11 +61,10 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
 		printk(KERN_NOTICE
 		printk(KERN_NOTICE
 			"sm_common: can't mark sector at %i as bad\n",
 			"sm_common: can't mark sector at %i as bad\n",
 								(int)ofs);
 								(int)ofs);
-		error = -EIO;
-	} else
-		mtd->ecc_stats.badblocks++;
+		return -EIO;
+	}
 
 
-	return error;
+	return 0;
 }
 }
 
 
 static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
 static struct nand_flash_dev nand_smartmedia_flash_ids[] = {

+ 1 - 1
drivers/mtd/nand/tmio_nand.c

@@ -357,7 +357,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
 
 
 static int tmio_probe(struct platform_device *dev)
 static int tmio_probe(struct platform_device *dev)
 {
 {
-	struct tmio_nand_data *data = dev->dev.platform_data;
+	struct tmio_nand_data *data = dev_get_platdata(&dev->dev);
 	struct resource *fcr = platform_get_resource(dev,
 	struct resource *fcr = platform_get_resource(dev,
 			IORESOURCE_MEM, 0);
 			IORESOURCE_MEM, 0);
 	struct resource *ccr = platform_get_resource(dev,
 	struct resource *ccr = platform_get_resource(dev,

+ 5 - 8
drivers/mtd/nand/txx9ndfmc.c

@@ -87,7 +87,7 @@ static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
 static void __iomem *ndregaddr(struct platform_device *dev, unsigned int reg)
 static void __iomem *ndregaddr(struct platform_device *dev, unsigned int reg)
 {
 {
 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
-	struct txx9ndfmc_platform_data *plat = dev->dev.platform_data;
+	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
 
 
 	return drvdata->base + (reg << plat->shift);
 	return drvdata->base + (reg << plat->shift);
 }
 }
@@ -138,7 +138,7 @@ static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
 	struct nand_chip *chip = mtd->priv;
 	struct nand_chip *chip = mtd->priv;
 	struct txx9ndfmc_priv *txx9_priv = chip->priv;
 	struct txx9ndfmc_priv *txx9_priv = chip->priv;
 	struct platform_device *dev = txx9_priv->dev;
 	struct platform_device *dev = txx9_priv->dev;
-	struct txx9ndfmc_platform_data *plat = dev->dev.platform_data;
+	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
 
 
 	if (ctrl & NAND_CTRL_CHANGE) {
 	if (ctrl & NAND_CTRL_CHANGE) {
 		u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
 		u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
@@ -225,7 +225,7 @@ static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
 
 
 static void txx9ndfmc_initialize(struct platform_device *dev)
 static void txx9ndfmc_initialize(struct platform_device *dev)
 {
 {
-	struct txx9ndfmc_platform_data *plat = dev->dev.platform_data;
+	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
 	int tmout = 100;
 	int tmout = 100;
 
 
@@ -274,19 +274,17 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
 
 
 static int __init txx9ndfmc_probe(struct platform_device *dev)
 static int __init txx9ndfmc_probe(struct platform_device *dev)
 {
 {
-	struct txx9ndfmc_platform_data *plat = dev->dev.platform_data;
+	struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
 	int hold, spw;
 	int hold, spw;
 	int i;
 	int i;
 	struct txx9ndfmc_drvdata *drvdata;
 	struct txx9ndfmc_drvdata *drvdata;
 	unsigned long gbusclk = plat->gbus_clock;
 	unsigned long gbusclk = plat->gbus_clock;
 	struct resource *res;
 	struct resource *res;
 
 
-	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENODEV;
 	drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL);
 	drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata)
 	if (!drvdata)
 		return -ENOMEM;
 		return -ENOMEM;
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	drvdata->base = devm_ioremap_resource(&dev->dev, res);
 	drvdata->base = devm_ioremap_resource(&dev->dev, res);
 	if (IS_ERR(drvdata->base))
 	if (IS_ERR(drvdata->base))
 		return PTR_ERR(drvdata->base);
 		return PTR_ERR(drvdata->base);
@@ -387,7 +385,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
 	struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
 	int i;
 	int i;
 
 
-	platform_set_drvdata(dev, NULL);
 	if (!drvdata)
 	if (!drvdata)
 		return 0;
 		return 0;
 	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
 	for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {

+ 14 - 4
drivers/mtd/ofpart.c

@@ -20,6 +20,11 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
 
 
+static bool node_has_compatible(struct device_node *pp)
+{
+	return of_get_property(pp, "compatible", NULL);
+}
+
 static int parse_ofpart_partitions(struct mtd_info *master,
 static int parse_ofpart_partitions(struct mtd_info *master,
 				   struct mtd_partition **pparts,
 				   struct mtd_partition **pparts,
 				   struct mtd_part_parser_data *data)
 				   struct mtd_part_parser_data *data)
@@ -38,10 +43,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,
 		return 0;
 		return 0;
 
 
 	/* First count the subnodes */
 	/* First count the subnodes */
-	pp = NULL;
 	nr_parts = 0;
 	nr_parts = 0;
-	while ((pp = of_get_next_child(node, pp)))
+	for_each_child_of_node(node,  pp) {
+		if (node_has_compatible(pp))
+			continue;
+
 		nr_parts++;
 		nr_parts++;
+	}
 
 
 	if (nr_parts == 0)
 	if (nr_parts == 0)
 		return 0;
 		return 0;
@@ -50,13 +58,15 @@ static int parse_ofpart_partitions(struct mtd_info *master,
 	if (!*pparts)
 	if (!*pparts)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	pp = NULL;
 	i = 0;
 	i = 0;
-	while ((pp = of_get_next_child(node, pp))) {
+	for_each_child_of_node(node,  pp) {
 		const __be32 *reg;
 		const __be32 *reg;
 		int len;
 		int len;
 		int a_cells, s_cells;
 		int a_cells, s_cells;
 
 
+		if (node_has_compatible(pp))
+			continue;
+
 		reg = of_get_property(pp, "reg", &len);
 		reg = of_get_property(pp, "reg", &len);
 		if (!reg) {
 		if (!reg) {
 			nr_parts--;
 			nr_parts--;

+ 1 - 3
drivers/mtd/onenand/generic.c

@@ -38,7 +38,7 @@ struct onenand_info {
 static int generic_onenand_probe(struct platform_device *pdev)
 static int generic_onenand_probe(struct platform_device *pdev)
 {
 {
 	struct onenand_info *info;
 	struct onenand_info *info;
-	struct onenand_platform_data *pdata = pdev->dev.platform_data;
+	struct onenand_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct resource *res = pdev->resource;
 	struct resource *res = pdev->resource;
 	unsigned long size = resource_size(res);
 	unsigned long size = resource_size(res);
 	int err;
 	int err;
@@ -94,8 +94,6 @@ static int generic_onenand_remove(struct platform_device *pdev)
 	struct resource *res = pdev->resource;
 	struct resource *res = pdev->resource;
 	unsigned long size = resource_size(res);
 	unsigned long size = resource_size(res);
 
 
-	platform_set_drvdata(pdev, NULL);
-
 	if (info) {
 	if (info) {
 		onenand_release(&info->mtd);
 		onenand_release(&info->mtd);
 		release_mem_region(res->start, size);
 		release_mem_region(res->start, size);

+ 1 - 2
drivers/mtd/onenand/omap2.c

@@ -639,7 +639,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
 	struct resource *res;
 	struct resource *res;
 	struct mtd_part_parser_data ppdata = {};
 	struct mtd_part_parser_data ppdata = {};
 
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (pdata == NULL) {
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "platform data missing\n");
 		dev_err(&pdev->dev, "platform data missing\n");
 		return -ENODEV;
 		return -ENODEV;
@@ -810,7 +810,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
 	if (c->dma_channel != -1)
 	if (c->dma_channel != -1)
 		omap_free_dma(c->dma_channel);
 		omap_free_dma(c->dma_channel);
 	omap2_onenand_shutdown(pdev);
 	omap2_onenand_shutdown(pdev);
-	platform_set_drvdata(pdev, NULL);
 	if (c->gpio_irq) {
 	if (c->gpio_irq) {
 		free_irq(gpio_to_irq(c->gpio_irq), c);
 		free_irq(gpio_to_irq(c->gpio_irq), c);
 		gpio_free(c->gpio_irq);
 		gpio_free(c->gpio_irq);

+ 0 - 1
drivers/mtd/onenand/onenand_bbt.c

@@ -133,7 +133,6 @@ static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_desc
 {
 {
 	struct onenand_chip *this = mtd->priv;
 	struct onenand_chip *this = mtd->priv;
 
 
-        bd->options &= ~NAND_BBT_SCANEMPTY;
 	return create_bbt(mtd, this->page_buf, bd, -1);
 	return create_bbt(mtd, this->page_buf, bd, -1);
 }
 }
 
 

+ 1 - 2
drivers/mtd/onenand/samsung.c

@@ -867,7 +867,7 @@ static int s3c_onenand_probe(struct platform_device *pdev)
 	struct resource *r;
 	struct resource *r;
 	int size, err;
 	int size, err;
 
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	/* No need to check pdata. the platform data is optional */
 	/* No need to check pdata. the platform data is optional */
 
 
 	size = sizeof(struct mtd_info) + sizeof(struct onenand_chip);
 	size = sizeof(struct mtd_info) + sizeof(struct onenand_chip);
@@ -1073,7 +1073,6 @@ static int s3c_onenand_remove(struct platform_device *pdev)
 	release_mem_region(onenand->base_res->start,
 	release_mem_region(onenand->base_res->start,
 			   resource_size(onenand->base_res));
 			   resource_size(onenand->base_res));
 
 
-	platform_set_drvdata(pdev, NULL);
 	kfree(onenand->oob_buf);
 	kfree(onenand->oob_buf);
 	kfree(onenand->page_buf);
 	kfree(onenand->page_buf);
 	kfree(onenand);
 	kfree(onenand);

+ 13 - 13
drivers/mtd/sm_ftl.c

@@ -22,7 +22,7 @@
 
 
 
 
 
 
-struct workqueue_struct *cache_flush_workqueue;
+static struct workqueue_struct *cache_flush_workqueue;
 
 
 static int cache_timeout = 1000;
 static int cache_timeout = 1000;
 module_param(cache_timeout, int, S_IRUGO);
 module_param(cache_timeout, int, S_IRUGO);
@@ -41,7 +41,7 @@ struct sm_sysfs_attribute {
 	int len;
 	int len;
 };
 };
 
 
-ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr,
+static ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr,
 		     char *buf)
 		     char *buf)
 {
 {
 	struct sm_sysfs_attribute *sm_attr =
 	struct sm_sysfs_attribute *sm_attr =
@@ -54,7 +54,7 @@ ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr,
 
 
 #define NUM_ATTRIBUTES 1
 #define NUM_ATTRIBUTES 1
 #define SM_CIS_VENDOR_OFFSET 0x59
 #define SM_CIS_VENDOR_OFFSET 0x59
-struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
+static struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
 {
 {
 	struct attribute_group *attr_group;
 	struct attribute_group *attr_group;
 	struct attribute **attributes;
 	struct attribute **attributes;
@@ -107,7 +107,7 @@ error1:
 	return NULL;
 	return NULL;
 }
 }
 
 
-void sm_delete_sysfs_attributes(struct sm_ftl *ftl)
+static void sm_delete_sysfs_attributes(struct sm_ftl *ftl)
 {
 {
 	struct attribute **attributes = ftl->disk_attributes->attrs;
 	struct attribute **attributes = ftl->disk_attributes->attrs;
 	int i;
 	int i;
@@ -571,7 +571,7 @@ static const uint8_t cis_signature[] = {
 };
 };
 /* Find out media parameters.
 /* Find out media parameters.
  * This ideally has to be based on nand id, but for now device size is enough */
  * This ideally has to be based on nand id, but for now device size is enough */
-int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd)
+static int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd)
 {
 {
 	int i;
 	int i;
 	int size_in_megs = mtd->size / (1024 * 1024);
 	int size_in_megs = mtd->size / (1024 * 1024);
@@ -878,7 +878,7 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)
 }
 }
 
 
 /* Get and automatically initialize an FTL mapping for one zone */
 /* Get and automatically initialize an FTL mapping for one zone */
-struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num)
+static struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num)
 {
 {
 	struct ftl_zone *zone;
 	struct ftl_zone *zone;
 	int error;
 	int error;
@@ -899,7 +899,7 @@ struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num)
 /* ----------------- cache handling ------------------------------------------*/
 /* ----------------- cache handling ------------------------------------------*/
 
 
 /* Initialize the one block cache */
 /* Initialize the one block cache */
-void sm_cache_init(struct sm_ftl *ftl)
+static void sm_cache_init(struct sm_ftl *ftl)
 {
 {
 	ftl->cache_data_invalid_bitmap = 0xFFFFFFFF;
 	ftl->cache_data_invalid_bitmap = 0xFFFFFFFF;
 	ftl->cache_clean = 1;
 	ftl->cache_clean = 1;
@@ -909,7 +909,7 @@ void sm_cache_init(struct sm_ftl *ftl)
 }
 }
 
 
 /* Put sector in one block cache */
 /* Put sector in one block cache */
-void sm_cache_put(struct sm_ftl *ftl, char *buffer, int boffset)
+static void sm_cache_put(struct sm_ftl *ftl, char *buffer, int boffset)
 {
 {
 	memcpy(ftl->cache_data + boffset, buffer, SM_SECTOR_SIZE);
 	memcpy(ftl->cache_data + boffset, buffer, SM_SECTOR_SIZE);
 	clear_bit(boffset / SM_SECTOR_SIZE, &ftl->cache_data_invalid_bitmap);
 	clear_bit(boffset / SM_SECTOR_SIZE, &ftl->cache_data_invalid_bitmap);
@@ -917,7 +917,7 @@ void sm_cache_put(struct sm_ftl *ftl, char *buffer, int boffset)
 }
 }
 
 
 /* Read a sector from the cache */
 /* Read a sector from the cache */
-int sm_cache_get(struct sm_ftl *ftl, char *buffer, int boffset)
+static int sm_cache_get(struct sm_ftl *ftl, char *buffer, int boffset)
 {
 {
 	if (test_bit(boffset / SM_SECTOR_SIZE,
 	if (test_bit(boffset / SM_SECTOR_SIZE,
 		&ftl->cache_data_invalid_bitmap))
 		&ftl->cache_data_invalid_bitmap))
@@ -928,7 +928,7 @@ int sm_cache_get(struct sm_ftl *ftl, char *buffer, int boffset)
 }
 }
 
 
 /* Write the cache to hardware */
 /* Write the cache to hardware */
-int sm_cache_flush(struct sm_ftl *ftl)
+static int sm_cache_flush(struct sm_ftl *ftl)
 {
 {
 	struct ftl_zone *zone;
 	struct ftl_zone *zone;
 
 
@@ -1274,10 +1274,10 @@ static struct mtd_blktrans_ops sm_ftl_ops = {
 static __init int sm_module_init(void)
 static __init int sm_module_init(void)
 {
 {
 	int error = 0;
 	int error = 0;
-	cache_flush_workqueue = create_freezable_workqueue("smflush");
 
 
-	if (IS_ERR(cache_flush_workqueue))
-		return PTR_ERR(cache_flush_workqueue);
+	cache_flush_workqueue = create_freezable_workqueue("smflush");
+	if (!cache_flush_workqueue)
+		return -ENOMEM;
 
 
 	error = register_mtd_blktrans(&sm_ftl_ops);
 	error = register_mtd_blktrans(&sm_ftl_ops);
 	if (error)
 	if (error)

+ 9 - 0
drivers/mtd/tests/Makefile

@@ -7,3 +7,12 @@ obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_nandecctest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_nandecctest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_nandbiterrs.o
 obj-$(CONFIG_MTD_TESTS) += mtd_nandbiterrs.o
+
+mtd_oobtest-objs := oobtest.o mtd_test.o
+mtd_pagetest-objs := pagetest.o mtd_test.o
+mtd_readtest-objs := readtest.o mtd_test.o
+mtd_speedtest-objs := speedtest.o mtd_test.o
+mtd_stresstest-objs := stresstest.o mtd_test.o
+mtd_subpagetest-objs := subpagetest.o mtd_test.o
+mtd_torturetest-objs := torturetest.o mtd_test.o
+mtd_nandbiterrs-objs := nandbiterrs.o mtd_test.o

+ 114 - 0
drivers/mtd/tests/mtd_test.c

@@ -0,0 +1,114 @@
+#define pr_fmt(fmt) "mtd_test: " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/printk.h>
+
+#include "mtd_test.h"
+
+int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
+{
+	int err;
+	struct erase_info ei;
+	loff_t addr = ebnum * mtd->erasesize;
+
+	memset(&ei, 0, sizeof(struct erase_info));
+	ei.mtd  = mtd;
+	ei.addr = addr;
+	ei.len  = mtd->erasesize;
+
+	err = mtd_erase(mtd, &ei);
+	if (err) {
+		pr_info("error %d while erasing EB %d\n", err, ebnum);
+		return err;
+	}
+
+	if (ei.state == MTD_ERASE_FAILED) {
+		pr_info("some erase error occurred at EB %d\n", ebnum);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum)
+{
+	int ret;
+	loff_t addr = ebnum * mtd->erasesize;
+
+	ret = mtd_block_isbad(mtd, addr);
+	if (ret)
+		pr_info("block %d is bad\n", ebnum);
+
+	return ret;
+}
+
+int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
+					unsigned int eb, int ebcnt)
+{
+	int i, bad = 0;
+
+	if (!mtd_can_have_bb(mtd))
+		return 0;
+
+	pr_info("scanning for bad eraseblocks\n");
+	for (i = 0; i < ebcnt; ++i) {
+		bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0;
+		if (bbt[i])
+			bad += 1;
+		cond_resched();
+	}
+	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
+
+	return 0;
+}
+
+int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
+				unsigned int eb, int ebcnt)
+{
+	int err;
+	unsigned int i;
+
+	for (i = 0; i < ebcnt; ++i) {
+		if (bbt[i])
+			continue;
+		err = mtdtest_erase_eraseblock(mtd, eb + i);
+		if (err)
+			return err;
+		cond_resched();
+	}
+
+	return 0;
+}
+
+int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf)
+{
+	size_t read;
+	int err;
+
+	err = mtd_read(mtd, addr, size, &read, buf);
+	/* Ignore corrected ECC errors */
+	if (mtd_is_bitflip(err))
+		err = 0;
+	if (!err && read != size)
+		err = -EIO;
+	if (err)
+		pr_err("error: read failed at %#llx\n", addr);
+
+	return err;
+}
+
+int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size,
+		const void *buf)
+{
+	size_t written;
+	int err;
+
+	err = mtd_write(mtd, addr, size, &written, buf);
+	if (!err && written != size)
+		err = -EIO;
+	if (err)
+		pr_err("error: write failed at %#llx\n", addr);
+
+	return err;
+}

+ 11 - 0
drivers/mtd/tests/mtd_test.h

@@ -0,0 +1,11 @@
+#include <linux/mtd/mtd.h>
+
+int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum);
+int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
+					unsigned int eb, int ebcnt);
+int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
+				unsigned int eb, int ebcnt);
+
+int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf);
+int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size,
+		const void *buf);

+ 4 - 37
drivers/mtd/tests/mtd_nandbiterrs.c → drivers/mtd/tests/nandbiterrs.c

@@ -49,6 +49,7 @@
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include "mtd_test.h"
 
 
 static int dev;
 static int dev;
 module_param(dev, int, S_IRUGO);
 module_param(dev, int, S_IRUGO);
@@ -98,47 +99,13 @@ static uint8_t hash(unsigned offset)
 	return c;
 	return c;
 }
 }
 
 
-static int erase_block(void)
-{
-	int err;
-	struct erase_info ei;
-	loff_t addr = eraseblock * mtd->erasesize;
-
-	pr_info("erase_block\n");
-
-	memset(&ei, 0, sizeof(struct erase_info));
-	ei.mtd  = mtd;
-	ei.addr = addr;
-	ei.len  = mtd->erasesize;
-
-	err = mtd_erase(mtd, &ei);
-	if (err || ei.state == MTD_ERASE_FAILED) {
-		pr_err("error %d while erasing\n", err);
-		if (!err)
-			err = -EIO;
-		return err;
-	}
-
-	return 0;
-}
-
 /* Writes wbuffer to page */
 /* Writes wbuffer to page */
 static int write_page(int log)
 static int write_page(int log)
 {
 {
-	int err = 0;
-	size_t written;
-
 	if (log)
 	if (log)
 		pr_info("write_page\n");
 		pr_info("write_page\n");
 
 
-	err = mtd_write(mtd, offset, mtd->writesize, &written, wbuffer);
-	if (err || written != mtd->writesize) {
-		pr_err("error: write failed at %#llx\n", (long long)offset);
-		if (!err)
-			err = -EIO;
-	}
-
-	return err;
+	return mtdtest_write(mtd, offset, mtd->writesize, wbuffer);
 }
 }
 
 
 /* Re-writes the data area while leaving the OOB alone. */
 /* Re-writes the data area while leaving the OOB alone. */
@@ -415,7 +382,7 @@ static int __init mtd_nandbiterrs_init(void)
 		goto exit_rbuffer;
 		goto exit_rbuffer;
 	}
 	}
 
 
-	err = erase_block();
+	err = mtdtest_erase_eraseblock(mtd, eraseblock);
 	if (err)
 	if (err)
 		goto exit_error;
 		goto exit_error;
 
 
@@ -428,7 +395,7 @@ static int __init mtd_nandbiterrs_init(void)
 		goto exit_error;
 		goto exit_error;
 
 
 	/* We leave the block un-erased in case of test failure. */
 	/* We leave the block un-erased in case of test failure. */
-	err = erase_block();
+	err = mtdtest_erase_eraseblock(mtd, eraseblock);
 	if (err)
 	if (err)
 		goto exit_error;
 		goto exit_error;
 
 

+ 14 - 88
drivers/mtd/tests/mtd_oobtest.c → drivers/mtd/tests/oobtest.c

@@ -31,6 +31,8 @@
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/random.h>
 #include <linux/random.h>
 
 
+#include "mtd_test.h"
+
 static int dev = -EINVAL;
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -49,49 +51,6 @@ static int use_len_max;
 static int vary_offset;
 static int vary_offset;
 static struct rnd_state rnd_state;
 static struct rnd_state rnd_state;
 
 
-static int erase_eraseblock(int ebnum)
-{
-	int err;
-	struct erase_info ei;
-	loff_t addr = ebnum * mtd->erasesize;
-
-	memset(&ei, 0, sizeof(struct erase_info));
-	ei.mtd  = mtd;
-	ei.addr = addr;
-	ei.len  = mtd->erasesize;
-
-	err = mtd_erase(mtd, &ei);
-	if (err) {
-		pr_err("error %d while erasing EB %d\n", err, ebnum);
-		return err;
-	}
-
-	if (ei.state == MTD_ERASE_FAILED) {
-		pr_err("some erase error occurred at EB %d\n", ebnum);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int erase_whole_device(void)
-{
-	int err;
-	unsigned int i;
-
-	pr_info("erasing whole device\n");
-	for (i = 0; i < ebcnt; ++i) {
-		if (bbt[i])
-			continue;
-		err = erase_eraseblock(i);
-		if (err)
-			return err;
-		cond_resched();
-	}
-	pr_info("erased %u eraseblocks\n", i);
-	return 0;
-}
-
 static void do_vary_offset(void)
 static void do_vary_offset(void)
 {
 {
 	use_len -= 1;
 	use_len -= 1;
@@ -304,38 +263,6 @@ static int verify_all_eraseblocks(void)
 	return 0;
 	return 0;
 }
 }
 
 
-static int is_block_bad(int ebnum)
-{
-	int ret;
-	loff_t addr = ebnum * mtd->erasesize;
-
-	ret = mtd_block_isbad(mtd, addr);
-	if (ret)
-		pr_info("block %d is bad\n", ebnum);
-	return ret;
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-	int i, bad = 0;
-
-	bbt = kmalloc(ebcnt, GFP_KERNEL);
-	if (!bbt) {
-		pr_err("error: cannot allocate memory\n");
-		return -ENOMEM;
-	}
-
-	pr_info("scanning for bad eraseblocks\n");
-	for (i = 0; i < ebcnt; ++i) {
-		bbt[i] = is_block_bad(i) ? 1 : 0;
-		if (bbt[i])
-			bad += 1;
-		cond_resched();
-	}
-	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-	return 0;
-}
-
 static int __init mtd_oobtest_init(void)
 static int __init mtd_oobtest_init(void)
 {
 {
 	int err = 0;
 	int err = 0;
@@ -380,17 +307,16 @@ static int __init mtd_oobtest_init(void)
 
 
 	err = -ENOMEM;
 	err = -ENOMEM;
 	readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
 	readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-	if (!readbuf) {
-		pr_err("error: cannot allocate memory\n");
+	if (!readbuf)
 		goto out;
 		goto out;
-	}
 	writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
 	writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-	if (!writebuf) {
-		pr_err("error: cannot allocate memory\n");
+	if (!writebuf)
+		goto out;
+	bbt = kzalloc(ebcnt, GFP_KERNEL);
+	if (!bbt)
 		goto out;
 		goto out;
-	}
 
 
-	err = scan_for_bad_eraseblocks();
+	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -402,7 +328,7 @@ static int __init mtd_oobtest_init(void)
 	/* First test: write all OOB, read it back and verify */
 	/* First test: write all OOB, read it back and verify */
 	pr_info("test 1 of 5\n");
 	pr_info("test 1 of 5\n");
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -422,7 +348,7 @@ static int __init mtd_oobtest_init(void)
 	 */
 	 */
 	pr_info("test 2 of 5\n");
 	pr_info("test 2 of 5\n");
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -452,7 +378,7 @@ static int __init mtd_oobtest_init(void)
 	 */
 	 */
 	pr_info("test 3 of 5\n");
 	pr_info("test 3 of 5\n");
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -485,7 +411,7 @@ static int __init mtd_oobtest_init(void)
 	/* Fourth test: try to write off end of device */
 	/* Fourth test: try to write off end of device */
 	pr_info("test 4 of 5\n");
 	pr_info("test 4 of 5\n");
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -577,7 +503,7 @@ static int __init mtd_oobtest_init(void)
 			errcnt += 1;
 			errcnt += 1;
 		}
 		}
 
 
-		err = erase_eraseblock(ebcnt - 1);
+		err = mtdtest_erase_eraseblock(mtd, ebcnt - 1);
 		if (err)
 		if (err)
 			goto out;
 			goto out;
 
 
@@ -626,7 +552,7 @@ static int __init mtd_oobtest_init(void)
 	pr_info("test 5 of 5\n");
 	pr_info("test 5 of 5\n");
 
 
 	/* Erase all eraseblocks */
 	/* Erase all eraseblocks */
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 

+ 60 - 211
drivers/mtd/tests/mtd_pagetest.c → drivers/mtd/tests/pagetest.c

@@ -31,6 +31,8 @@
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/random.h>
 #include <linux/random.h>
 
 
+#include "mtd_test.h"
+
 static int dev = -EINVAL;
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -48,52 +50,18 @@ static int pgcnt;
 static int errcnt;
 static int errcnt;
 static struct rnd_state rnd_state;
 static struct rnd_state rnd_state;
 
 
-static int erase_eraseblock(int ebnum)
-{
-	int err;
-	struct erase_info ei;
-	loff_t addr = ebnum * mtd->erasesize;
-
-	memset(&ei, 0, sizeof(struct erase_info));
-	ei.mtd  = mtd;
-	ei.addr = addr;
-	ei.len  = mtd->erasesize;
-
-	err = mtd_erase(mtd, &ei);
-	if (err) {
-		pr_err("error %d while erasing EB %d\n", err, ebnum);
-		return err;
-	}
-
-	if (ei.state == MTD_ERASE_FAILED) {
-		pr_err("some erase error occurred at EB %d\n",
-		       ebnum);
-		return -EIO;
-	}
-
-	return 0;
-}
-
 static int write_eraseblock(int ebnum)
 static int write_eraseblock(int ebnum)
 {
 {
-	int err = 0;
-	size_t written;
 	loff_t addr = ebnum * mtd->erasesize;
 	loff_t addr = ebnum * mtd->erasesize;
 
 
 	prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
 	prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
 	cond_resched();
 	cond_resched();
-	err = mtd_write(mtd, addr, mtd->erasesize, &written, writebuf);
-	if (err || written != mtd->erasesize)
-		pr_err("error: write failed at %#llx\n",
-		       (long long)addr);
-
-	return err;
+	return mtdtest_write(mtd, addr, mtd->erasesize, writebuf);
 }
 }
 
 
 static int verify_eraseblock(int ebnum)
 static int verify_eraseblock(int ebnum)
 {
 {
 	uint32_t j;
 	uint32_t j;
-	size_t read;
 	int err = 0, i;
 	int err = 0, i;
 	loff_t addr0, addrn;
 	loff_t addr0, addrn;
 	loff_t addr = ebnum * mtd->erasesize;
 	loff_t addr = ebnum * mtd->erasesize;
@@ -109,31 +77,16 @@ static int verify_eraseblock(int ebnum)
 	prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
 	prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
 	for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
 	for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
 		/* Do a read to set the internal dataRAMs to different data */
 		/* Do a read to set the internal dataRAMs to different data */
-		err = mtd_read(mtd, addr0, bufsize, &read, twopages);
-		if (mtd_is_bitflip(err))
-			err = 0;
-		if (err || read != bufsize) {
-			pr_err("error: read failed at %#llx\n",
-			       (long long)addr0);
+		err = mtdtest_read(mtd, addr0, bufsize, twopages);
+		if (err)
 			return err;
 			return err;
-		}
-		err = mtd_read(mtd, addrn - bufsize, bufsize, &read, twopages);
-		if (mtd_is_bitflip(err))
-			err = 0;
-		if (err || read != bufsize) {
-			pr_err("error: read failed at %#llx\n",
-			       (long long)(addrn - bufsize));
+		err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
+		if (err)
 			return err;
 			return err;
-		}
 		memset(twopages, 0, bufsize);
 		memset(twopages, 0, bufsize);
-		err = mtd_read(mtd, addr, bufsize, &read, twopages);
-		if (mtd_is_bitflip(err))
-			err = 0;
-		if (err || read != bufsize) {
-			pr_err("error: read failed at %#llx\n",
-			       (long long)addr);
+		err = mtdtest_read(mtd, addr, bufsize, twopages);
+		if (err)
 			break;
 			break;
-		}
 		if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
 		if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
 			pr_err("error: verify failed at %#llx\n",
 			pr_err("error: verify failed at %#llx\n",
 			       (long long)addr);
 			       (long long)addr);
@@ -145,31 +98,16 @@ static int verify_eraseblock(int ebnum)
 		struct rnd_state old_state = rnd_state;
 		struct rnd_state old_state = rnd_state;
 
 
 		/* Do a read to set the internal dataRAMs to different data */
 		/* Do a read to set the internal dataRAMs to different data */
-		err = mtd_read(mtd, addr0, bufsize, &read, twopages);
-		if (mtd_is_bitflip(err))
-			err = 0;
-		if (err || read != bufsize) {
-			pr_err("error: read failed at %#llx\n",
-			       (long long)addr0);
+		err = mtdtest_read(mtd, addr0, bufsize, twopages);
+		if (err)
 			return err;
 			return err;
-		}
-		err = mtd_read(mtd, addrn - bufsize, bufsize, &read, twopages);
-		if (mtd_is_bitflip(err))
-			err = 0;
-		if (err || read != bufsize) {
-			pr_err("error: read failed at %#llx\n",
-			       (long long)(addrn - bufsize));
+		err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
+		if (err)
 			return err;
 			return err;
-		}
 		memset(twopages, 0, bufsize);
 		memset(twopages, 0, bufsize);
-		err = mtd_read(mtd, addr, bufsize, &read, twopages);
-		if (mtd_is_bitflip(err))
-			err = 0;
-		if (err || read != bufsize) {
-			pr_err("error: read failed at %#llx\n",
-			       (long long)addr);
+		err = mtdtest_read(mtd, addr, bufsize, twopages);
+		if (err)
 			return err;
 			return err;
-		}
 		memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
 		memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
 		prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize);
 		prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize);
 		if (memcmp(twopages, boundary, bufsize)) {
 		if (memcmp(twopages, boundary, bufsize)) {
@@ -184,17 +122,14 @@ static int verify_eraseblock(int ebnum)
 
 
 static int crosstest(void)
 static int crosstest(void)
 {
 {
-	size_t read;
 	int err = 0, i;
 	int err = 0, i;
 	loff_t addr, addr0, addrn;
 	loff_t addr, addr0, addrn;
 	unsigned char *pp1, *pp2, *pp3, *pp4;
 	unsigned char *pp1, *pp2, *pp3, *pp4;
 
 
 	pr_info("crosstest\n");
 	pr_info("crosstest\n");
 	pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
 	pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
-	if (!pp1) {
-		pr_err("error: cannot allocate memory\n");
+	if (!pp1)
 		return -ENOMEM;
 		return -ENOMEM;
-	}
 	pp2 = pp1 + pgsize;
 	pp2 = pp1 + pgsize;
 	pp3 = pp2 + pgsize;
 	pp3 = pp2 + pgsize;
 	pp4 = pp3 + pgsize;
 	pp4 = pp3 + pgsize;
@@ -210,24 +145,16 @@ static int crosstest(void)
 
 
 	/* Read 2nd-to-last page to pp1 */
 	/* Read 2nd-to-last page to pp1 */
 	addr = addrn - pgsize - pgsize;
 	addr = addrn - pgsize - pgsize;
-	err = mtd_read(mtd, addr, pgsize, &read, pp1);
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (err || read != pgsize) {
-		pr_err("error: read failed at %#llx\n",
-		       (long long)addr);
+	err = mtdtest_read(mtd, addr, pgsize, pp1);
+	if (err) {
 		kfree(pp1);
 		kfree(pp1);
 		return err;
 		return err;
 	}
 	}
 
 
 	/* Read 3rd-to-last page to pp1 */
 	/* Read 3rd-to-last page to pp1 */
 	addr = addrn - pgsize - pgsize - pgsize;
 	addr = addrn - pgsize - pgsize - pgsize;
-	err = mtd_read(mtd, addr, pgsize, &read, pp1);
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (err || read != pgsize) {
-		pr_err("error: read failed at %#llx\n",
-		       (long long)addr);
+	err = mtdtest_read(mtd, addr, pgsize, pp1);
+	if (err) {
 		kfree(pp1);
 		kfree(pp1);
 		return err;
 		return err;
 	}
 	}
@@ -235,12 +162,8 @@ static int crosstest(void)
 	/* Read first page to pp2 */
 	/* Read first page to pp2 */
 	addr = addr0;
 	addr = addr0;
 	pr_info("reading page at %#llx\n", (long long)addr);
 	pr_info("reading page at %#llx\n", (long long)addr);
-	err = mtd_read(mtd, addr, pgsize, &read, pp2);
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (err || read != pgsize) {
-		pr_err("error: read failed at %#llx\n",
-		       (long long)addr);
+	err = mtdtest_read(mtd, addr, pgsize, pp2);
+	if (err) {
 		kfree(pp1);
 		kfree(pp1);
 		return err;
 		return err;
 	}
 	}
@@ -248,12 +171,8 @@ static int crosstest(void)
 	/* Read last page to pp3 */
 	/* Read last page to pp3 */
 	addr = addrn - pgsize;
 	addr = addrn - pgsize;
 	pr_info("reading page at %#llx\n", (long long)addr);
 	pr_info("reading page at %#llx\n", (long long)addr);
-	err = mtd_read(mtd, addr, pgsize, &read, pp3);
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (err || read != pgsize) {
-		pr_err("error: read failed at %#llx\n",
-		       (long long)addr);
+	err = mtdtest_read(mtd, addr, pgsize, pp3);
+	if (err) {
 		kfree(pp1);
 		kfree(pp1);
 		return err;
 		return err;
 	}
 	}
@@ -261,12 +180,8 @@ static int crosstest(void)
 	/* Read first page again to pp4 */
 	/* Read first page again to pp4 */
 	addr = addr0;
 	addr = addr0;
 	pr_info("reading page at %#llx\n", (long long)addr);
 	pr_info("reading page at %#llx\n", (long long)addr);
-	err = mtd_read(mtd, addr, pgsize, &read, pp4);
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (err || read != pgsize) {
-		pr_err("error: read failed at %#llx\n",
-		       (long long)addr);
+	err = mtdtest_read(mtd, addr, pgsize, pp4);
+	if (err) {
 		kfree(pp1);
 		kfree(pp1);
 		return err;
 		return err;
 	}
 	}
@@ -285,7 +200,6 @@ static int crosstest(void)
 
 
 static int erasecrosstest(void)
 static int erasecrosstest(void)
 {
 {
-	size_t read, written;
 	int err = 0, i, ebnum, ebnum2;
 	int err = 0, i, ebnum, ebnum2;
 	loff_t addr0;
 	loff_t addr0;
 	char *readbuf = twopages;
 	char *readbuf = twopages;
@@ -304,30 +218,22 @@ static int erasecrosstest(void)
 		ebnum2 -= 1;
 		ebnum2 -= 1;
 
 
 	pr_info("erasing block %d\n", ebnum);
 	pr_info("erasing block %d\n", ebnum);
-	err = erase_eraseblock(ebnum);
+	err = mtdtest_erase_eraseblock(mtd, ebnum);
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
 	pr_info("writing 1st page of block %d\n", ebnum);
 	pr_info("writing 1st page of block %d\n", ebnum);
 	prandom_bytes_state(&rnd_state, writebuf, pgsize);
 	prandom_bytes_state(&rnd_state, writebuf, pgsize);
 	strcpy(writebuf, "There is no data like this!");
 	strcpy(writebuf, "There is no data like this!");
-	err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
-	if (err || written != pgsize) {
-		pr_info("error: write failed at %#llx\n",
-		       (long long)addr0);
-		return err ? err : -1;
-	}
+	err = mtdtest_write(mtd, addr0, pgsize, writebuf);
+	if (err)
+		return err;
 
 
 	pr_info("reading 1st page of block %d\n", ebnum);
 	pr_info("reading 1st page of block %d\n", ebnum);
 	memset(readbuf, 0, pgsize);
 	memset(readbuf, 0, pgsize);
-	err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (err || read != pgsize) {
-		pr_err("error: read failed at %#llx\n",
-		       (long long)addr0);
-		return err ? err : -1;
-	}
+	err = mtdtest_read(mtd, addr0, pgsize, readbuf);
+	if (err)
+		return err;
 
 
 	pr_info("verifying 1st page of block %d\n", ebnum);
 	pr_info("verifying 1st page of block %d\n", ebnum);
 	if (memcmp(writebuf, readbuf, pgsize)) {
 	if (memcmp(writebuf, readbuf, pgsize)) {
@@ -337,35 +243,27 @@ static int erasecrosstest(void)
 	}
 	}
 
 
 	pr_info("erasing block %d\n", ebnum);
 	pr_info("erasing block %d\n", ebnum);
-	err = erase_eraseblock(ebnum);
+	err = mtdtest_erase_eraseblock(mtd, ebnum);
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
 	pr_info("writing 1st page of block %d\n", ebnum);
 	pr_info("writing 1st page of block %d\n", ebnum);
 	prandom_bytes_state(&rnd_state, writebuf, pgsize);
 	prandom_bytes_state(&rnd_state, writebuf, pgsize);
 	strcpy(writebuf, "There is no data like this!");
 	strcpy(writebuf, "There is no data like this!");
-	err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
-	if (err || written != pgsize) {
-		pr_err("error: write failed at %#llx\n",
-		       (long long)addr0);
-		return err ? err : -1;
-	}
+	err = mtdtest_write(mtd, addr0, pgsize, writebuf);
+	if (err)
+		return err;
 
 
 	pr_info("erasing block %d\n", ebnum2);
 	pr_info("erasing block %d\n", ebnum2);
-	err = erase_eraseblock(ebnum2);
+	err = mtdtest_erase_eraseblock(mtd, ebnum2);
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
 	pr_info("reading 1st page of block %d\n", ebnum);
 	pr_info("reading 1st page of block %d\n", ebnum);
 	memset(readbuf, 0, pgsize);
 	memset(readbuf, 0, pgsize);
-	err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (err || read != pgsize) {
-		pr_err("error: read failed at %#llx\n",
-		       (long long)addr0);
-		return err ? err : -1;
-	}
+	err = mtdtest_read(mtd, addr0, pgsize, readbuf);
+	if (err)
+		return err;
 
 
 	pr_info("verifying 1st page of block %d\n", ebnum);
 	pr_info("verifying 1st page of block %d\n", ebnum);
 	if (memcmp(writebuf, readbuf, pgsize)) {
 	if (memcmp(writebuf, readbuf, pgsize)) {
@@ -381,7 +279,6 @@ static int erasecrosstest(void)
 
 
 static int erasetest(void)
 static int erasetest(void)
 {
 {
-	size_t read, written;
 	int err = 0, i, ebnum, ok = 1;
 	int err = 0, i, ebnum, ok = 1;
 	loff_t addr0;
 	loff_t addr0;
 
 
@@ -395,33 +292,25 @@ static int erasetest(void)
 	}
 	}
 
 
 	pr_info("erasing block %d\n", ebnum);
 	pr_info("erasing block %d\n", ebnum);
-	err = erase_eraseblock(ebnum);
+	err = mtdtest_erase_eraseblock(mtd, ebnum);
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
 	pr_info("writing 1st page of block %d\n", ebnum);
 	pr_info("writing 1st page of block %d\n", ebnum);
 	prandom_bytes_state(&rnd_state, writebuf, pgsize);
 	prandom_bytes_state(&rnd_state, writebuf, pgsize);
-	err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
-	if (err || written != pgsize) {
-		pr_err("error: write failed at %#llx\n",
-		       (long long)addr0);
-		return err ? err : -1;
-	}
+	err = mtdtest_write(mtd, addr0, pgsize, writebuf);
+	if (err)
+		return err;
 
 
 	pr_info("erasing block %d\n", ebnum);
 	pr_info("erasing block %d\n", ebnum);
-	err = erase_eraseblock(ebnum);
+	err = mtdtest_erase_eraseblock(mtd, ebnum);
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
 	pr_info("reading 1st page of block %d\n", ebnum);
 	pr_info("reading 1st page of block %d\n", ebnum);
-	err = mtd_read(mtd, addr0, pgsize, &read, twopages);
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (err || read != pgsize) {
-		pr_err("error: read failed at %#llx\n",
-		       (long long)addr0);
-		return err ? err : -1;
-	}
+	err = mtdtest_read(mtd, addr0, pgsize, twopages);
+	if (err)
+		return err;
 
 
 	pr_info("verifying 1st page of block %d is all 0xff\n",
 	pr_info("verifying 1st page of block %d is all 0xff\n",
 	       ebnum);
 	       ebnum);
@@ -440,38 +329,6 @@ static int erasetest(void)
 	return err;
 	return err;
 }
 }
 
 
-static int is_block_bad(int ebnum)
-{
-	loff_t addr = ebnum * mtd->erasesize;
-	int ret;
-
-	ret = mtd_block_isbad(mtd, addr);
-	if (ret)
-		pr_info("block %d is bad\n", ebnum);
-	return ret;
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-	int i, bad = 0;
-
-	bbt = kzalloc(ebcnt, GFP_KERNEL);
-	if (!bbt) {
-		pr_err("error: cannot allocate memory\n");
-		return -ENOMEM;
-	}
-
-	pr_info("scanning for bad eraseblocks\n");
-	for (i = 0; i < ebcnt; ++i) {
-		bbt[i] = is_block_bad(i) ? 1 : 0;
-		if (bbt[i])
-			bad += 1;
-		cond_resched();
-	}
-	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-	return 0;
-}
-
 static int __init mtd_pagetest_init(void)
 static int __init mtd_pagetest_init(void)
 {
 {
 	int err = 0;
 	int err = 0;
@@ -516,36 +373,28 @@ static int __init mtd_pagetest_init(void)
 	err = -ENOMEM;
 	err = -ENOMEM;
 	bufsize = pgsize * 2;
 	bufsize = pgsize * 2;
 	writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
 	writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-	if (!writebuf) {
-		pr_err("error: cannot allocate memory\n");
+	if (!writebuf)
 		goto out;
 		goto out;
-	}
 	twopages = kmalloc(bufsize, GFP_KERNEL);
 	twopages = kmalloc(bufsize, GFP_KERNEL);
-	if (!twopages) {
-		pr_err("error: cannot allocate memory\n");
+	if (!twopages)
 		goto out;
 		goto out;
-	}
 	boundary = kmalloc(bufsize, GFP_KERNEL);
 	boundary = kmalloc(bufsize, GFP_KERNEL);
-	if (!boundary) {
-		pr_err("error: cannot allocate memory\n");
+	if (!boundary)
 		goto out;
 		goto out;
-	}
 
 
-	err = scan_for_bad_eraseblocks();
+	bbt = kzalloc(ebcnt, GFP_KERNEL);
+	if (!bbt)
+		goto out;
+	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
 	/* Erase all eraseblocks */
 	/* Erase all eraseblocks */
 	pr_info("erasing whole device\n");
 	pr_info("erasing whole device\n");
-	for (i = 0; i < ebcnt; ++i) {
-		if (bbt[i])
-			continue;
-		err = erase_eraseblock(i);
-		if (err)
-			goto out;
-		cond_resched();
-	}
-	pr_info("erased %u eraseblocks\n", i);
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+	if (err)
+		goto out;
+	pr_info("erased %u eraseblocks\n", ebcnt);
 
 
 	/* Write all eraseblocks */
 	/* Write all eraseblocks */
 	prandom_seed_state(&rnd_state, 1);
 	prandom_seed_state(&rnd_state, 1);

+ 10 - 51
drivers/mtd/tests/mtd_readtest.c → drivers/mtd/tests/readtest.c

@@ -29,6 +29,8 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 
 
+#include "mtd_test.h"
+
 static int dev = -EINVAL;
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -44,7 +46,6 @@ static int pgcnt;
 
 
 static int read_eraseblock_by_page(int ebnum)
 static int read_eraseblock_by_page(int ebnum)
 {
 {
-	size_t read;
 	int i, ret, err = 0;
 	int i, ret, err = 0;
 	loff_t addr = ebnum * mtd->erasesize;
 	loff_t addr = ebnum * mtd->erasesize;
 	void *buf = iobuf;
 	void *buf = iobuf;
@@ -52,16 +53,10 @@ static int read_eraseblock_by_page(int ebnum)
 
 
 	for (i = 0; i < pgcnt; i++) {
 	for (i = 0; i < pgcnt; i++) {
 		memset(buf, 0 , pgsize);
 		memset(buf, 0 , pgsize);
-		ret = mtd_read(mtd, addr, pgsize, &read, buf);
-		if (ret == -EUCLEAN)
-			ret = 0;
-		if (ret || read != pgsize) {
-			pr_err("error: read failed at %#llx\n",
-			       (long long)addr);
+		ret = mtdtest_read(mtd, addr, pgsize, buf);
+		if (ret) {
 			if (!err)
 			if (!err)
 				err = ret;
 				err = ret;
-			if (!err)
-				err = -EINVAL;
 		}
 		}
 		if (mtd->oobsize) {
 		if (mtd->oobsize) {
 			struct mtd_oob_ops ops;
 			struct mtd_oob_ops ops;
@@ -127,41 +122,6 @@ static void dump_eraseblock(int ebnum)
 		}
 		}
 }
 }
 
 
-static int is_block_bad(int ebnum)
-{
-	loff_t addr = ebnum * mtd->erasesize;
-	int ret;
-
-	ret = mtd_block_isbad(mtd, addr);
-	if (ret)
-		pr_info("block %d is bad\n", ebnum);
-	return ret;
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-	int i, bad = 0;
-
-	bbt = kzalloc(ebcnt, GFP_KERNEL);
-	if (!bbt) {
-		pr_err("error: cannot allocate memory\n");
-		return -ENOMEM;
-	}
-
-	if (!mtd_can_have_bb(mtd))
-		return 0;
-
-	pr_info("scanning for bad eraseblocks\n");
-	for (i = 0; i < ebcnt; ++i) {
-		bbt[i] = is_block_bad(i) ? 1 : 0;
-		if (bbt[i])
-			bad += 1;
-		cond_resched();
-	}
-	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-	return 0;
-}
-
 static int __init mtd_readtest_init(void)
 static int __init mtd_readtest_init(void)
 {
 {
 	uint64_t tmp;
 	uint64_t tmp;
@@ -204,17 +164,16 @@ static int __init mtd_readtest_init(void)
 
 
 	err = -ENOMEM;
 	err = -ENOMEM;
 	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
 	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-	if (!iobuf) {
-		pr_err("error: cannot allocate memory\n");
+	if (!iobuf)
 		goto out;
 		goto out;
-	}
 	iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
 	iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
-	if (!iobuf1) {
-		pr_err("error: cannot allocate memory\n");
+	if (!iobuf1)
 		goto out;
 		goto out;
-	}
 
 
-	err = scan_for_bad_eraseblocks();
+	bbt = kzalloc(ebcnt, GFP_KERNEL);
+	if (!bbt)
+		goto out;
+	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 

+ 33 - 177
drivers/mtd/tests/mtd_speedtest.c → drivers/mtd/tests/speedtest.c

@@ -30,6 +30,8 @@
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/random.h>
 #include <linux/random.h>
 
 
+#include "mtd_test.h"
+
 static int dev = -EINVAL;
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -49,33 +51,6 @@ static int pgcnt;
 static int goodebcnt;
 static int goodebcnt;
 static struct timeval start, finish;
 static struct timeval start, finish;
 
 
-
-static int erase_eraseblock(int ebnum)
-{
-	int err;
-	struct erase_info ei;
-	loff_t addr = ebnum * mtd->erasesize;
-
-	memset(&ei, 0, sizeof(struct erase_info));
-	ei.mtd  = mtd;
-	ei.addr = addr;
-	ei.len  = mtd->erasesize;
-
-	err = mtd_erase(mtd, &ei);
-	if (err) {
-		pr_err("error %d while erasing EB %d\n", err, ebnum);
-		return err;
-	}
-
-	if (ei.state == MTD_ERASE_FAILED) {
-		pr_err("some erase error occurred at EB %d\n",
-		       ebnum);
-		return -EIO;
-	}
-
-	return 0;
-}
-
 static int multiblock_erase(int ebnum, int blocks)
 static int multiblock_erase(int ebnum, int blocks)
 {
 {
 	int err;
 	int err;
@@ -103,54 +78,23 @@ static int multiblock_erase(int ebnum, int blocks)
 	return 0;
 	return 0;
 }
 }
 
 
-static int erase_whole_device(void)
-{
-	int err;
-	unsigned int i;
-
-	for (i = 0; i < ebcnt; ++i) {
-		if (bbt[i])
-			continue;
-		err = erase_eraseblock(i);
-		if (err)
-			return err;
-		cond_resched();
-	}
-	return 0;
-}
-
 static int write_eraseblock(int ebnum)
 static int write_eraseblock(int ebnum)
 {
 {
-	size_t written;
-	int err = 0;
 	loff_t addr = ebnum * mtd->erasesize;
 	loff_t addr = ebnum * mtd->erasesize;
 
 
-	err = mtd_write(mtd, addr, mtd->erasesize, &written, iobuf);
-	if (err || written != mtd->erasesize) {
-		pr_err("error: write failed at %#llx\n", addr);
-		if (!err)
-			err = -EINVAL;
-	}
-
-	return err;
+	return mtdtest_write(mtd, addr, mtd->erasesize, iobuf);
 }
 }
 
 
 static int write_eraseblock_by_page(int ebnum)
 static int write_eraseblock_by_page(int ebnum)
 {
 {
-	size_t written;
 	int i, err = 0;
 	int i, err = 0;
 	loff_t addr = ebnum * mtd->erasesize;
 	loff_t addr = ebnum * mtd->erasesize;
 	void *buf = iobuf;
 	void *buf = iobuf;
 
 
 	for (i = 0; i < pgcnt; i++) {
 	for (i = 0; i < pgcnt; i++) {
-		err = mtd_write(mtd, addr, pgsize, &written, buf);
-		if (err || written != pgsize) {
-			pr_err("error: write failed at %#llx\n",
-			       addr);
-			if (!err)
-				err = -EINVAL;
+		err = mtdtest_write(mtd, addr, pgsize, buf);
+		if (err)
 			break;
 			break;
-		}
 		addr += pgsize;
 		addr += pgsize;
 		buf += pgsize;
 		buf += pgsize;
 	}
 	}
@@ -160,74 +104,41 @@ static int write_eraseblock_by_page(int ebnum)
 
 
 static int write_eraseblock_by_2pages(int ebnum)
 static int write_eraseblock_by_2pages(int ebnum)
 {
 {
-	size_t written, sz = pgsize * 2;
+	size_t sz = pgsize * 2;
 	int i, n = pgcnt / 2, err = 0;
 	int i, n = pgcnt / 2, err = 0;
 	loff_t addr = ebnum * mtd->erasesize;
 	loff_t addr = ebnum * mtd->erasesize;
 	void *buf = iobuf;
 	void *buf = iobuf;
 
 
 	for (i = 0; i < n; i++) {
 	for (i = 0; i < n; i++) {
-		err = mtd_write(mtd, addr, sz, &written, buf);
-		if (err || written != sz) {
-			pr_err("error: write failed at %#llx\n",
-			       addr);
-			if (!err)
-				err = -EINVAL;
+		err = mtdtest_write(mtd, addr, sz, buf);
+		if (err)
 			return err;
 			return err;
-		}
 		addr += sz;
 		addr += sz;
 		buf += sz;
 		buf += sz;
 	}
 	}
-	if (pgcnt % 2) {
-		err = mtd_write(mtd, addr, pgsize, &written, buf);
-		if (err || written != pgsize) {
-			pr_err("error: write failed at %#llx\n",
-			       addr);
-			if (!err)
-				err = -EINVAL;
-		}
-	}
+	if (pgcnt % 2)
+		err = mtdtest_write(mtd, addr, pgsize, buf);
 
 
 	return err;
 	return err;
 }
 }
 
 
 static int read_eraseblock(int ebnum)
 static int read_eraseblock(int ebnum)
 {
 {
-	size_t read;
-	int err = 0;
 	loff_t addr = ebnum * mtd->erasesize;
 	loff_t addr = ebnum * mtd->erasesize;
 
 
-	err = mtd_read(mtd, addr, mtd->erasesize, &read, iobuf);
-	/* Ignore corrected ECC errors */
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (err || read != mtd->erasesize) {
-		pr_err("error: read failed at %#llx\n", addr);
-		if (!err)
-			err = -EINVAL;
-	}
-
-	return err;
+	return mtdtest_read(mtd, addr, mtd->erasesize, iobuf);
 }
 }
 
 
 static int read_eraseblock_by_page(int ebnum)
 static int read_eraseblock_by_page(int ebnum)
 {
 {
-	size_t read;
 	int i, err = 0;
 	int i, err = 0;
 	loff_t addr = ebnum * mtd->erasesize;
 	loff_t addr = ebnum * mtd->erasesize;
 	void *buf = iobuf;
 	void *buf = iobuf;
 
 
 	for (i = 0; i < pgcnt; i++) {
 	for (i = 0; i < pgcnt; i++) {
-		err = mtd_read(mtd, addr, pgsize, &read, buf);
-		/* Ignore corrected ECC errors */
-		if (mtd_is_bitflip(err))
-			err = 0;
-		if (err || read != pgsize) {
-			pr_err("error: read failed at %#llx\n",
-			       addr);
-			if (!err)
-				err = -EINVAL;
+		err = mtdtest_read(mtd, addr, pgsize, buf);
+		if (err)
 			break;
 			break;
-		}
 		addr += pgsize;
 		addr += pgsize;
 		buf += pgsize;
 		buf += pgsize;
 	}
 	}
@@ -237,53 +148,24 @@ static int read_eraseblock_by_page(int ebnum)
 
 
 static int read_eraseblock_by_2pages(int ebnum)
 static int read_eraseblock_by_2pages(int ebnum)
 {
 {
-	size_t read, sz = pgsize * 2;
+	size_t sz = pgsize * 2;
 	int i, n = pgcnt / 2, err = 0;
 	int i, n = pgcnt / 2, err = 0;
 	loff_t addr = ebnum * mtd->erasesize;
 	loff_t addr = ebnum * mtd->erasesize;
 	void *buf = iobuf;
 	void *buf = iobuf;
 
 
 	for (i = 0; i < n; i++) {
 	for (i = 0; i < n; i++) {
-		err = mtd_read(mtd, addr, sz, &read, buf);
-		/* Ignore corrected ECC errors */
-		if (mtd_is_bitflip(err))
-			err = 0;
-		if (err || read != sz) {
-			pr_err("error: read failed at %#llx\n",
-			       addr);
-			if (!err)
-				err = -EINVAL;
+		err = mtdtest_read(mtd, addr, sz, buf);
+		if (err)
 			return err;
 			return err;
-		}
 		addr += sz;
 		addr += sz;
 		buf += sz;
 		buf += sz;
 	}
 	}
-	if (pgcnt % 2) {
-		err = mtd_read(mtd, addr, pgsize, &read, buf);
-		/* Ignore corrected ECC errors */
-		if (mtd_is_bitflip(err))
-			err = 0;
-		if (err || read != pgsize) {
-			pr_err("error: read failed at %#llx\n",
-			       addr);
-			if (!err)
-				err = -EINVAL;
-		}
-	}
+	if (pgcnt % 2)
+		err = mtdtest_read(mtd, addr, pgsize, buf);
 
 
 	return err;
 	return err;
 }
 }
 
 
-static int is_block_bad(int ebnum)
-{
-	loff_t addr = ebnum * mtd->erasesize;
-	int ret;
-
-	ret = mtd_block_isbad(mtd, addr);
-	if (ret)
-		pr_info("block %d is bad\n", ebnum);
-	return ret;
-}
-
 static inline void start_timing(void)
 static inline void start_timing(void)
 {
 {
 	do_gettimeofday(&start);
 	do_gettimeofday(&start);
@@ -308,32 +190,6 @@ static long calc_speed(void)
 	return k;
 	return k;
 }
 }
 
 
-static int scan_for_bad_eraseblocks(void)
-{
-	int i, bad = 0;
-
-	bbt = kzalloc(ebcnt, GFP_KERNEL);
-	if (!bbt) {
-		pr_err("error: cannot allocate memory\n");
-		return -ENOMEM;
-	}
-
-	if (!mtd_can_have_bb(mtd))
-		goto out;
-
-	pr_info("scanning for bad eraseblocks\n");
-	for (i = 0; i < ebcnt; ++i) {
-		bbt[i] = is_block_bad(i) ? 1 : 0;
-		if (bbt[i])
-			bad += 1;
-		cond_resched();
-	}
-	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-out:
-	goodebcnt = ebcnt - bad;
-	return 0;
-}
-
 static int __init mtd_speedtest_init(void)
 static int __init mtd_speedtest_init(void)
 {
 {
 	int err, i, blocks, j, k;
 	int err, i, blocks, j, k;
@@ -384,18 +240,23 @@ static int __init mtd_speedtest_init(void)
 
 
 	err = -ENOMEM;
 	err = -ENOMEM;
 	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
 	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-	if (!iobuf) {
-		pr_err("error: cannot allocate memory\n");
+	if (!iobuf)
 		goto out;
 		goto out;
-	}
 
 
 	prandom_bytes(iobuf, mtd->erasesize);
 	prandom_bytes(iobuf, mtd->erasesize);
 
 
-	err = scan_for_bad_eraseblocks();
+	bbt = kzalloc(ebcnt, GFP_KERNEL);
+	if (!bbt)
+		goto out;
+	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
+	for (i = 0; i < ebcnt; i++) {
+		if (!bbt[i])
+			goodebcnt++;
+	}
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -429,7 +290,7 @@ static int __init mtd_speedtest_init(void)
 	speed = calc_speed();
 	speed = calc_speed();
 	pr_info("eraseblock read speed is %ld KiB/s\n", speed);
 	pr_info("eraseblock read speed is %ld KiB/s\n", speed);
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -463,7 +324,7 @@ static int __init mtd_speedtest_init(void)
 	speed = calc_speed();
 	speed = calc_speed();
 	pr_info("page read speed is %ld KiB/s\n", speed);
 	pr_info("page read speed is %ld KiB/s\n", speed);
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -500,14 +361,9 @@ static int __init mtd_speedtest_init(void)
 	/* Erase all eraseblocks */
 	/* Erase all eraseblocks */
 	pr_info("Testing erase speed\n");
 	pr_info("Testing erase speed\n");
 	start_timing();
 	start_timing();
-	for (i = 0; i < ebcnt; ++i) {
-		if (bbt[i])
-			continue;
-		err = erase_eraseblock(i);
-		if (err)
-			goto out;
-		cond_resched();
-	}
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+	if (err)
+		goto out;
 	stop_timing();
 	stop_timing();
 	speed = calc_speed();
 	speed = calc_speed();
 	pr_info("erase speed is %ld KiB/s\n", speed);
 	pr_info("erase speed is %ld KiB/s\n", speed);

+ 13 - 88
drivers/mtd/tests/mtd_stresstest.c → drivers/mtd/tests/stresstest.c

@@ -31,6 +31,8 @@
 #include <linux/vmalloc.h>
 #include <linux/vmalloc.h>
 #include <linux/random.h>
 #include <linux/random.h>
 
 
+#include "mtd_test.h"
+
 static int dev = -EINVAL;
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -81,49 +83,11 @@ static int rand_len(int offs)
 	return len;
 	return len;
 }
 }
 
 
-static int erase_eraseblock(int ebnum)
-{
-	int err;
-	struct erase_info ei;
-	loff_t addr = ebnum * mtd->erasesize;
-
-	memset(&ei, 0, sizeof(struct erase_info));
-	ei.mtd  = mtd;
-	ei.addr = addr;
-	ei.len  = mtd->erasesize;
-
-	err = mtd_erase(mtd, &ei);
-	if (unlikely(err)) {
-		pr_err("error %d while erasing EB %d\n", err, ebnum);
-		return err;
-	}
-
-	if (unlikely(ei.state == MTD_ERASE_FAILED)) {
-		pr_err("some erase error occurred at EB %d\n",
-		       ebnum);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int is_block_bad(int ebnum)
-{
-	loff_t addr = ebnum * mtd->erasesize;
-	int ret;
-
-	ret = mtd_block_isbad(mtd, addr);
-	if (ret)
-		pr_info("block %d is bad\n", ebnum);
-	return ret;
-}
-
 static int do_read(void)
 static int do_read(void)
 {
 {
-	size_t read;
 	int eb = rand_eb();
 	int eb = rand_eb();
 	int offs = rand_offs();
 	int offs = rand_offs();
-	int len = rand_len(offs), err;
+	int len = rand_len(offs);
 	loff_t addr;
 	loff_t addr;
 
 
 	if (bbt[eb + 1]) {
 	if (bbt[eb + 1]) {
@@ -133,28 +97,17 @@ static int do_read(void)
 			len = mtd->erasesize - offs;
 			len = mtd->erasesize - offs;
 	}
 	}
 	addr = eb * mtd->erasesize + offs;
 	addr = eb * mtd->erasesize + offs;
-	err = mtd_read(mtd, addr, len, &read, readbuf);
-	if (mtd_is_bitflip(err))
-		err = 0;
-	if (unlikely(err || read != len)) {
-		pr_err("error: read failed at 0x%llx\n",
-		       (long long)addr);
-		if (!err)
-			err = -EINVAL;
-		return err;
-	}
-	return 0;
+	return mtdtest_read(mtd, addr, len, readbuf);
 }
 }
 
 
 static int do_write(void)
 static int do_write(void)
 {
 {
 	int eb = rand_eb(), offs, err, len;
 	int eb = rand_eb(), offs, err, len;
-	size_t written;
 	loff_t addr;
 	loff_t addr;
 
 
 	offs = offsets[eb];
 	offs = offsets[eb];
 	if (offs >= mtd->erasesize) {
 	if (offs >= mtd->erasesize) {
-		err = erase_eraseblock(eb);
+		err = mtdtest_erase_eraseblock(mtd, eb);
 		if (err)
 		if (err)
 			return err;
 			return err;
 		offs = offsets[eb] = 0;
 		offs = offsets[eb] = 0;
@@ -165,21 +118,16 @@ static int do_write(void)
 		if (bbt[eb + 1])
 		if (bbt[eb + 1])
 			len = mtd->erasesize - offs;
 			len = mtd->erasesize - offs;
 		else {
 		else {
-			err = erase_eraseblock(eb + 1);
+			err = mtdtest_erase_eraseblock(mtd, eb + 1);
 			if (err)
 			if (err)
 				return err;
 				return err;
 			offsets[eb + 1] = 0;
 			offsets[eb + 1] = 0;
 		}
 		}
 	}
 	}
 	addr = eb * mtd->erasesize + offs;
 	addr = eb * mtd->erasesize + offs;
-	err = mtd_write(mtd, addr, len, &written, writebuf);
-	if (unlikely(err || written != len)) {
-		pr_err("error: write failed at 0x%llx\n",
-		       (long long)addr);
-		if (!err)
-			err = -EINVAL;
+	err = mtdtest_write(mtd, addr, len, writebuf);
+	if (unlikely(err))
 		return err;
 		return err;
-	}
 	offs += len;
 	offs += len;
 	while (offs > mtd->erasesize) {
 	while (offs > mtd->erasesize) {
 		offsets[eb++] = mtd->erasesize;
 		offsets[eb++] = mtd->erasesize;
@@ -197,30 +145,6 @@ static int do_operation(void)
 		return do_write();
 		return do_write();
 }
 }
 
 
-static int scan_for_bad_eraseblocks(void)
-{
-	int i, bad = 0;
-
-	bbt = kzalloc(ebcnt, GFP_KERNEL);
-	if (!bbt) {
-		pr_err("error: cannot allocate memory\n");
-		return -ENOMEM;
-	}
-
-	if (!mtd_can_have_bb(mtd))
-		return 0;
-
-	pr_info("scanning for bad eraseblocks\n");
-	for (i = 0; i < ebcnt; ++i) {
-		bbt[i] = is_block_bad(i) ? 1 : 0;
-		if (bbt[i])
-			bad += 1;
-		cond_resched();
-	}
-	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-	return 0;
-}
-
 static int __init mtd_stresstest_init(void)
 static int __init mtd_stresstest_init(void)
 {
 {
 	int err;
 	int err;
@@ -276,15 +200,16 @@ static int __init mtd_stresstest_init(void)
 	readbuf = vmalloc(bufsize);
 	readbuf = vmalloc(bufsize);
 	writebuf = vmalloc(bufsize);
 	writebuf = vmalloc(bufsize);
 	offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
 	offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
-	if (!readbuf || !writebuf || !offsets) {
-		pr_err("error: cannot allocate memory\n");
+	if (!readbuf || !writebuf || !offsets)
 		goto out;
 		goto out;
-	}
 	for (i = 0; i < ebcnt; i++)
 	for (i = 0; i < ebcnt; i++)
 		offsets[i] = mtd->erasesize;
 		offsets[i] = mtd->erasesize;
 	prandom_bytes(writebuf, bufsize);
 	prandom_bytes(writebuf, bufsize);
 
 
-	err = scan_for_bad_eraseblocks();
+	bbt = kzalloc(ebcnt, GFP_KERNEL);
+	if (!bbt)
+		goto out;
+	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 

+ 11 - 86
drivers/mtd/tests/mtd_subpagetest.c → drivers/mtd/tests/subpagetest.c

@@ -30,6 +30,8 @@
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/random.h>
 #include <linux/random.h>
 
 
+#include "mtd_test.h"
+
 static int dev = -EINVAL;
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -51,50 +53,6 @@ static inline void clear_data(unsigned char *buf, size_t len)
 	memset(buf, 0, len);
 	memset(buf, 0, len);
 }
 }
 
 
-static int erase_eraseblock(int ebnum)
-{
-	int err;
-	struct erase_info ei;
-	loff_t addr = ebnum * mtd->erasesize;
-
-	memset(&ei, 0, sizeof(struct erase_info));
-	ei.mtd  = mtd;
-	ei.addr = addr;
-	ei.len  = mtd->erasesize;
-
-	err = mtd_erase(mtd, &ei);
-	if (err) {
-		pr_err("error %d while erasing EB %d\n", err, ebnum);
-		return err;
-	}
-
-	if (ei.state == MTD_ERASE_FAILED) {
-		pr_err("some erase error occurred at EB %d\n",
-		       ebnum);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int erase_whole_device(void)
-{
-	int err;
-	unsigned int i;
-
-	pr_info("erasing whole device\n");
-	for (i = 0; i < ebcnt; ++i) {
-		if (bbt[i])
-			continue;
-		err = erase_eraseblock(i);
-		if (err)
-			return err;
-		cond_resched();
-	}
-	pr_info("erased %u eraseblocks\n", i);
-	return 0;
-}
-
 static int write_eraseblock(int ebnum)
 static int write_eraseblock(int ebnum)
 {
 {
 	size_t written;
 	size_t written;
@@ -317,38 +275,6 @@ static int verify_all_eraseblocks_ff(void)
 	return 0;
 	return 0;
 }
 }
 
 
-static int is_block_bad(int ebnum)
-{
-	loff_t addr = ebnum * mtd->erasesize;
-	int ret;
-
-	ret = mtd_block_isbad(mtd, addr);
-	if (ret)
-		pr_info("block %d is bad\n", ebnum);
-	return ret;
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-	int i, bad = 0;
-
-	bbt = kzalloc(ebcnt, GFP_KERNEL);
-	if (!bbt) {
-		pr_err("error: cannot allocate memory\n");
-		return -ENOMEM;
-	}
-
-	pr_info("scanning for bad eraseblocks\n");
-	for (i = 0; i < ebcnt; ++i) {
-		bbt[i] = is_block_bad(i) ? 1 : 0;
-		if (bbt[i])
-			bad += 1;
-		cond_resched();
-	}
-	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-	return 0;
-}
-
 static int __init mtd_subpagetest_init(void)
 static int __init mtd_subpagetest_init(void)
 {
 {
 	int err = 0;
 	int err = 0;
@@ -393,21 +319,20 @@ static int __init mtd_subpagetest_init(void)
 	err = -ENOMEM;
 	err = -ENOMEM;
 	bufsize = subpgsize * 32;
 	bufsize = subpgsize * 32;
 	writebuf = kmalloc(bufsize, GFP_KERNEL);
 	writebuf = kmalloc(bufsize, GFP_KERNEL);
-	if (!writebuf) {
-		pr_info("error: cannot allocate memory\n");
+	if (!writebuf)
 		goto out;
 		goto out;
-	}
 	readbuf = kmalloc(bufsize, GFP_KERNEL);
 	readbuf = kmalloc(bufsize, GFP_KERNEL);
-	if (!readbuf) {
-		pr_info("error: cannot allocate memory\n");
+	if (!readbuf)
+		goto out;
+	bbt = kzalloc(ebcnt, GFP_KERNEL);
+	if (!bbt)
 		goto out;
 		goto out;
-	}
 
 
-	err = scan_for_bad_eraseblocks();
+	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -439,7 +364,7 @@ static int __init mtd_subpagetest_init(void)
 	}
 	}
 	pr_info("verified %u eraseblocks\n", i);
 	pr_info("verified %u eraseblocks\n", i);
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -477,7 +402,7 @@ static int __init mtd_subpagetest_init(void)
 	}
 	}
 	pr_info("verified %u eraseblocks\n", i);
 	pr_info("verified %u eraseblocks\n", i);
 
 
-	err = erase_whole_device();
+	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 

+ 7 - 59
drivers/mtd/tests/mtd_torturetest.c → drivers/mtd/tests/torturetest.c

@@ -32,6 +32,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/mtd.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
+#include "mtd_test.h"
 
 
 #define RETRIES 3
 #define RETRIES 3
 
 
@@ -92,35 +93,6 @@ static inline void stop_timing(void)
 	do_gettimeofday(&finish);
 	do_gettimeofday(&finish);
 }
 }
 
 
-/*
- * Erase eraseblock number @ebnum.
- */
-static inline int erase_eraseblock(int ebnum)
-{
-	int err;
-	struct erase_info ei;
-	loff_t addr = ebnum * mtd->erasesize;
-
-	memset(&ei, 0, sizeof(struct erase_info));
-	ei.mtd  = mtd;
-	ei.addr = addr;
-	ei.len  = mtd->erasesize;
-
-	err = mtd_erase(mtd, &ei);
-	if (err) {
-		pr_err("error %d while erasing EB %d\n", err, ebnum);
-		return err;
-	}
-
-	if (ei.state == MTD_ERASE_FAILED) {
-		pr_err("some erase error occurred at EB %d\n",
-		       ebnum);
-		return -EIO;
-	}
-
-	return 0;
-}
-
 /*
 /*
  * Check that the contents of eraseblock number @enbum is equivalent to the
  * Check that the contents of eraseblock number @enbum is equivalent to the
  * @buf buffer.
  * @buf buffer.
@@ -208,7 +180,7 @@ static inline int write_pattern(int ebnum, void *buf)
 static int __init tort_init(void)
 static int __init tort_init(void)
 {
 {
 	int err = 0, i, infinite = !cycles_count;
 	int err = 0, i, infinite = !cycles_count;
-	int *bad_ebs;
+	unsigned char *bad_ebs;
 
 
 	printk(KERN_INFO "\n");
 	printk(KERN_INFO "\n");
 	printk(KERN_INFO "=================================================\n");
 	printk(KERN_INFO "=================================================\n");
@@ -265,7 +237,7 @@ static int __init tort_init(void)
 	if (!check_buf)
 	if (!check_buf)
 		goto out_patt_FF;
 		goto out_patt_FF;
 
 
-	bad_ebs = kcalloc(ebcnt, sizeof(*bad_ebs), GFP_KERNEL);
+	bad_ebs = kzalloc(ebcnt, GFP_KERNEL);
 	if (!bad_ebs)
 	if (!bad_ebs)
 		goto out_check_buf;
 		goto out_check_buf;
 
 
@@ -283,40 +255,16 @@ static int __init tort_init(void)
 		}
 		}
 	}
 	}
 
 
-	/*
-	 * Check if there is a bad eraseblock among those we are going to test.
-	 */
-	if (mtd_can_have_bb(mtd)) {
-		for (i = eb; i < eb + ebcnt; i++) {
-			err = mtd_block_isbad(mtd, (loff_t)i * mtd->erasesize);
-
-			if (err < 0) {
-				pr_info("block_isbad() returned %d "
-				       "for EB %d\n", err, i);
-				goto out;
-			}
-
-			if (err) {
-				pr_err("EB %d is bad. Skip it.\n", i);
-				bad_ebs[i - eb] = 1;
-			}
-		}
-	}
+	err = mtdtest_scan_for_bad_eraseblocks(mtd, bad_ebs, eb, ebcnt);
+	if (err)
+		goto out;
 
 
 	start_timing();
 	start_timing();
 	while (1) {
 	while (1) {
 		int i;
 		int i;
 		void *patt;
 		void *patt;
 
 
-		/* Erase all eraseblocks */
-		for (i = eb; i < eb + ebcnt; i++) {
-			if (bad_ebs[i - eb])
-				continue;
-			err = erase_eraseblock(i);
-			if (err)
-				goto out;
-			cond_resched();
-		}
+		mtdtest_erase_good_eraseblocks(mtd, bad_ebs, eb, ebcnt);
 
 
 		/* Check if the eraseblocks contain only 0xFF bytes */
 		/* Check if the eraseblocks contain only 0xFF bytes */
 		if (check) {
 		if (check) {

+ 0 - 2
include/linux/mtd/bbm.h

@@ -93,8 +93,6 @@ struct nand_bbt_descr {
 #define NAND_BBT_CREATE_EMPTY	0x00000400
 #define NAND_BBT_CREATE_EMPTY	0x00000400
 /* Search good / bad pattern through all pages of a block */
 /* Search good / bad pattern through all pages of a block */
 #define NAND_BBT_SCANALLPAGES	0x00000800
 #define NAND_BBT_SCANALLPAGES	0x00000800
-/* Scan block empty during good / bad block scan */
-#define NAND_BBT_SCANEMPTY	0x00001000
 /* Write bbt if neccecary */
 /* Write bbt if neccecary */
 #define NAND_BBT_WRITE		0x00002000
 #define NAND_BBT_WRITE		0x00002000
 /* Read and write back block contents when writing bbt */
 /* Read and write back block contents when writing bbt */

+ 1 - 0
include/linux/mtd/fsmc.h

@@ -137,6 +137,7 @@ enum access_mode {
 
 
 /**
 /**
  * fsmc_nand_platform_data - platform specific NAND controller config
  * fsmc_nand_platform_data - platform specific NAND controller config
+ * @nand_timings: timing setup for the physical NAND interface
  * @partitions: partition table for the platform, use a default fallback
  * @partitions: partition table for the platform, use a default fallback
  * if this is NULL
  * if this is NULL
  * @nr_partitions: the number of partitions in the previous entry
  * @nr_partitions: the number of partitions in the previous entry

+ 3 - 0
include/linux/mtd/mtd.h

@@ -173,6 +173,9 @@ struct mtd_info {
 	/* ECC layout structure pointer - read only! */
 	/* ECC layout structure pointer - read only! */
 	struct nand_ecclayout *ecclayout;
 	struct nand_ecclayout *ecclayout;
 
 
+	/* the ecc step size. */
+	unsigned int ecc_step_size;
+
 	/* max number of correctible bit errors per ecc step */
 	/* max number of correctible bit errors per ecc step */
 	unsigned int ecc_strength;
 	unsigned int ecc_strength;
 
 

+ 78 - 5
include/linux/mtd/nand.h

@@ -56,7 +56,7 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
  * is supported now. If you add a chip with bigger oobsize/page
  * is supported now. If you add a chip with bigger oobsize/page
  * adjust this accordingly.
  * adjust this accordingly.
  */
  */
-#define NAND_MAX_OOBSIZE	640
+#define NAND_MAX_OOBSIZE	744
 #define NAND_MAX_PAGESIZE	8192
 #define NAND_MAX_PAGESIZE	8192
 
 
 /*
 /*
@@ -202,6 +202,10 @@ typedef enum {
 /* Keep gcc happy */
 /* Keep gcc happy */
 struct nand_chip;
 struct nand_chip;
 
 
+/* ONFI features */
+#define ONFI_FEATURE_16_BIT_BUS		(1 << 0)
+#define ONFI_FEATURE_EXT_PARAM_PAGE	(1 << 7)
+
 /* ONFI timing mode, used in both asynchronous and synchronous mode */
 /* ONFI timing mode, used in both asynchronous and synchronous mode */
 #define ONFI_TIMING_MODE_0		(1 << 0)
 #define ONFI_TIMING_MODE_0		(1 << 0)
 #define ONFI_TIMING_MODE_1		(1 << 1)
 #define ONFI_TIMING_MODE_1		(1 << 1)
@@ -217,6 +221,9 @@ struct nand_chip;
 /* ONFI subfeature parameters length */
 /* ONFI subfeature parameters length */
 #define ONFI_SUBFEATURE_PARAM_LEN	4
 #define ONFI_SUBFEATURE_PARAM_LEN	4
 
 
+/* ONFI optional commands SET/GET FEATURES supported? */
+#define ONFI_OPT_CMD_SET_GET_FEATURES	(1 << 2)
+
 struct nand_onfi_params {
 struct nand_onfi_params {
 	/* rev info and features block */
 	/* rev info and features block */
 	/* 'O' 'N' 'F' 'I'  */
 	/* 'O' 'N' 'F' 'I'  */
@@ -224,7 +231,10 @@ struct nand_onfi_params {
 	__le16 revision;
 	__le16 revision;
 	__le16 features;
 	__le16 features;
 	__le16 opt_cmd;
 	__le16 opt_cmd;
-	u8 reserved[22];
+	u8 reserved0[2];
+	__le16 ext_param_page_length; /* since ONFI 2.1 */
+	u8 num_of_param_pages;        /* since ONFI 2.1 */
+	u8 reserved1[17];
 
 
 	/* manufacturer information block */
 	/* manufacturer information block */
 	char manufacturer[12];
 	char manufacturer[12];
@@ -281,6 +291,40 @@ struct nand_onfi_params {
 
 
 #define ONFI_CRC_BASE	0x4F4E
 #define ONFI_CRC_BASE	0x4F4E
 
 
+/* Extended ECC information Block Definition (since ONFI 2.1) */
+struct onfi_ext_ecc_info {
+	u8 ecc_bits;
+	u8 codeword_size;
+	__le16 bb_per_lun;
+	__le16 block_endurance;
+	u8 reserved[2];
+} __packed;
+
+#define ONFI_SECTION_TYPE_0	0	/* Unused section. */
+#define ONFI_SECTION_TYPE_1	1	/* for additional sections. */
+#define ONFI_SECTION_TYPE_2	2	/* for ECC information. */
+struct onfi_ext_section {
+	u8 type;
+	u8 length;
+} __packed;
+
+#define ONFI_EXT_SECTION_MAX 8
+
+/* Extended Parameter Page Definition (since ONFI 2.1) */
+struct onfi_ext_param_page {
+	__le16 crc;
+	u8 sig[4];             /* 'E' 'P' 'P' 'S' */
+	u8 reserved0[10];
+	struct onfi_ext_section sections[ONFI_EXT_SECTION_MAX];
+
+	/*
+	 * The actual size of the Extended Parameter Page is in
+	 * @ext_param_page_length of nand_onfi_params{}.
+	 * The following are the variable length sections.
+	 * So we do not add any fields below. Please see the ONFI spec.
+	 */
+} __packed;
+
 /**
 /**
  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
  * @lock:               protection lock
  * @lock:               protection lock
@@ -390,8 +434,8 @@ struct nand_buffers {
  * @write_buf:		[REPLACEABLE] write data from the buffer to the chip
  * @write_buf:		[REPLACEABLE] write data from the buffer to the chip
  * @read_buf:		[REPLACEABLE] read data from the chip into the buffer
  * @read_buf:		[REPLACEABLE] read data from the chip into the buffer
  * @select_chip:	[REPLACEABLE] select chip nr
  * @select_chip:	[REPLACEABLE] select chip nr
- * @block_bad:		[REPLACEABLE] check, if the block is bad
- * @block_markbad:	[REPLACEABLE] mark the block bad
+ * @block_bad:		[REPLACEABLE] check if a block is bad, using OOB markers
+ * @block_markbad:	[REPLACEABLE] mark a block bad
  * @cmd_ctrl:		[BOARDSPECIFIC] hardwarespecific function for controlling
  * @cmd_ctrl:		[BOARDSPECIFIC] hardwarespecific function for controlling
  *			ALE/CLE/nCE. Also used to write command and address
  *			ALE/CLE/nCE. Also used to write command and address
  * @init_size:		[BOARDSPECIFIC] hardwarespecific function for setting
  * @init_size:		[BOARDSPECIFIC] hardwarespecific function for setting
@@ -434,6 +478,12 @@ struct nand_buffers {
  *			bad block marker position; i.e., BBM == 11110111b is
  *			bad block marker position; i.e., BBM == 11110111b is
  *			not bad when badblockbits == 7
  *			not bad when badblockbits == 7
  * @cellinfo:		[INTERN] MLC/multichip data from chip ident
  * @cellinfo:		[INTERN] MLC/multichip data from chip ident
+ * @ecc_strength_ds:	[INTERN] ECC correctability from the datasheet.
+ *			Minimum amount of bit errors per @ecc_step_ds guaranteed
+ *			to be correctable. If unknown, set to zero.
+ * @ecc_step_ds:	[INTERN] ECC step required by the @ecc_strength_ds,
+ *                      also from the datasheet. It is the recommended ECC step
+ *			size, if known; if unknown, set to zero.
  * @numchips:		[INTERN] number of physical chips
  * @numchips:		[INTERN] number of physical chips
  * @chipsize:		[INTERN] the size of one chip for multichip arrays
  * @chipsize:		[INTERN] the size of one chip for multichip arrays
  * @pagemask:		[INTERN] page number mask = number of (pages / chip) - 1
  * @pagemask:		[INTERN] page number mask = number of (pages / chip) - 1
@@ -510,6 +560,8 @@ struct nand_chip {
 	unsigned int pagebuf_bitflips;
 	unsigned int pagebuf_bitflips;
 	int subpagesize;
 	int subpagesize;
 	uint8_t cellinfo;
 	uint8_t cellinfo;
+	uint16_t ecc_strength_ds;
+	uint16_t ecc_step_ds;
 	int badblockpos;
 	int badblockpos;
 	int badblockbits;
 	int badblockbits;
 
 
@@ -576,6 +628,11 @@ struct nand_chip {
 	{ .name = (nm), {{ .dev_id = (devid) }}, .chipsize = (chipsz), \
 	{ .name = (nm), {{ .dev_id = (devid) }}, .chipsize = (chipsz), \
 	  .options = (opts) }
 	  .options = (opts) }
 
 
+#define NAND_ECC_INFO(_strength, _step)	\
+			{ .strength_ds = (_strength), .step_ds = (_step) }
+#define NAND_ECC_STRENGTH(type)		((type)->ecc.strength_ds)
+#define NAND_ECC_STEP(type)		((type)->ecc.step_ds)
+
 /**
 /**
  * struct nand_flash_dev - NAND Flash Device ID Structure
  * struct nand_flash_dev - NAND Flash Device ID Structure
  * @name: a human-readable name of the NAND chip
  * @name: a human-readable name of the NAND chip
@@ -593,6 +650,12 @@ struct nand_chip {
  * @options: stores various chip bit options
  * @options: stores various chip bit options
  * @id_len: The valid length of the @id.
  * @id_len: The valid length of the @id.
  * @oobsize: OOB size
  * @oobsize: OOB size
+ * @ecc.strength_ds: The ECC correctability from the datasheet, same as the
+ *                   @ecc_strength_ds in nand_chip{}.
+ * @ecc.step_ds: The ECC step required by the @ecc.strength_ds, same as the
+ *               @ecc_step_ds in nand_chip{}, also from the datasheet.
+ *               For example, the "4bit ECC for each 512Byte" can be set with
+ *               NAND_ECC_INFO(4, 512).
  */
  */
 struct nand_flash_dev {
 struct nand_flash_dev {
 	char *name;
 	char *name;
@@ -609,6 +672,10 @@ struct nand_flash_dev {
 	unsigned int options;
 	unsigned int options;
 	uint16_t id_len;
 	uint16_t id_len;
 	uint16_t oobsize;
 	uint16_t oobsize;
+	struct {
+		uint16_t strength_ds;
+		uint16_t step_ds;
+	} ecc;
 };
 };
 
 
 /**
 /**
@@ -625,8 +692,8 @@ extern struct nand_flash_dev nand_flash_ids[];
 extern struct nand_manufacturers nand_manuf_ids[];
 extern struct nand_manufacturers nand_manuf_ids[];
 
 
 extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
 extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
-extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
 extern int nand_default_bbt(struct mtd_info *mtd);
 extern int nand_default_bbt(struct mtd_info *mtd);
+extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
 extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
 extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
 extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 			   int allowbbt);
 			   int allowbbt);
@@ -708,6 +775,12 @@ struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
 	return chip->priv;
 	return chip->priv;
 }
 }
 
 
+/* return the supported features. */
+static inline int onfi_feature(struct nand_chip *chip)
+{
+	return chip->onfi_version ? le16_to_cpu(chip->onfi_params.features) : 0;
+}
+
 /* return the supported asynchronous timing mode. */
 /* return the supported asynchronous timing mode. */
 static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
 static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
 {
 {

+ 4 - 0
include/linux/platform_data/atmel.h

@@ -71,6 +71,10 @@ struct atmel_nand_data {
 	u8		on_flash_bbt;		/* bbt on flash */
 	u8		on_flash_bbt;		/* bbt on flash */
 	struct mtd_partition *parts;
 	struct mtd_partition *parts;
 	unsigned int	num_parts;
 	unsigned int	num_parts;
+	bool		has_dma;		/* support dma transfer */
+
+	/* default is false, only for at32ap7000 chip is true */
+	bool		need_reset_workaround;
 };
 };
 
 
  /* Serial */
  /* Serial */

+ 0 - 13
include/linux/platform_data/mtd-nand-pxa3xx.h

@@ -16,19 +16,6 @@ struct pxa3xx_nand_timing {
 	unsigned int	tAR;  /* ND_ALE low to ND_nRE low delay */
 	unsigned int	tAR;  /* ND_ALE low to ND_nRE low delay */
 };
 };
 
 
-struct pxa3xx_nand_cmdset {
-	uint16_t	read1;
-	uint16_t	read2;
-	uint16_t	program;
-	uint16_t	read_status;
-	uint16_t	read_id;
-	uint16_t	erase;
-	uint16_t	reset;
-	uint16_t	lock;
-	uint16_t	unlock;
-	uint16_t	lock_status;
-};
-
 struct pxa3xx_nand_flash {
 struct pxa3xx_nand_flash {
 	char		*name;
 	char		*name;
 	uint32_t	chip_id;
 	uint32_t	chip_id;