Merge tag 'mtd/for-4.19' of git://git.infradead.org/linux-mtd
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Aug 2018 17:57:44 +0000 (10:57 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Aug 2018 17:57:44 +0000 (10:57 -0700)
Pull mtd updates from Boris Brezillon:
 "JFFS2 changes:
   - Support 64-bit timestamps

  MTD core changes:
   - Support sub-partitions
   - Clarify mtd_oob_ops documentation
   - Make Kconfig formatting consistent
   - Fix potential overflows in mtdchar_{write,read}()
   - Fallback to ->_{read,write}() when ->_{read,write}_oob() is missing
     and no OOB data were requested
   - Remove VLA usage in the bch lib

  MTD driver changes:
   - Use mtd_device_register() instead of mtd_device_parse_register()
     where applicable
   - Use proper printk format to print physical addresses in the
     solutionengine driver
   - Add missing mtd_set_of_node() call in the powernv driver
   - Remove unneeded variables in a few drivers
   - Plug the TRX part parser to the DT partition parsers logic
   - Check ioremap_cache() return code in the gpio-addr-flash driver
   - Stop using VMLINUX_SYMBOL_STR() in gen_probe.c

  SPI NOR core changes:
   - Apply reset hacks only when reset is explicitly marked as broken in
     the DT

   SPI NOR driver changes:
   - Minor cleanup/fixes in the m25p80 driver
   - Release flash_np in the nxp-spifi driver
   - Add suspend/resume hooks to the atmel-quadspi driver
   - Include gpio/consumer.h instead of gpio.h in the atmel-quadspi
     driver
   - Use %pK instead of %p in the stm32-quadspi driver
   - Improve timeout handling in the cadence-quadspi driver
   - Use mtd_device_register() instead of mtd_device_parse_register() in
     the intel-spi driver

  NAND core changes:
   - Add the SPI-NAND framework.
   - Create a helper to find the best ECC configuration.
   - Create NAND controller operations.
   - Allocate dynamically ONFI parameters structure.
   - Add defines for ONFI version bits.
   - Add manufacturer fixup for ONFI parameter page.
   - Add an option to specify NAND chip as a boot device.
   - Add Reed-Solomon error correction algorithm.
   - Better name for the controller structure.
   - Remove unused caller_is_module() definition.
   - Make subop helpers return unsigned values.
   - Expose _notsupp() helpers for raw page accessors.
   - Add default values for dynamic timings.
   - Kill the chip->scan_bbt() hook.
   - Rename nand_default_bbt() into nand_create_bbt().
   - Start to clean the nand_chip structure.
   - Remove stale prototype from rawnand.h.

  Raw NAND controllers drivers changes:
   - Qcom: structuring cleanup.
   - Denali: use core helper to find the best ECC configuration.
   - Possible build of almost all drivers by adding a dependency on
     COMPILE_TEST for almost all of them in Kconfig, implies various
     fixes, Kconfig cleanup, GPIO headers inclusion cleanup, and even
     changes in sparc64 and ia64 architectures.
   - Clean the ->probe() functions error path of a lot of drivers.
   - Migrate all drivers to use nand_scan() instead of
     nand_scan_ident()/nand_scan_tail() pair.
   - Use mtd_device_register() where applicable to simplify the code.
   - Marvell:
      * Handle on-die ECC.
      * Better clocks handling.
      * Remove bogus comment.
      * Add suspend and resume support.
   - Tegra: add NAND controller driver.
   - Atmel:
      * Add module param to avoid using dma.
      * Drop Wenyou Yang from MAINTAINERS.
   - Denali: optimize timings handling.
   - FSMC: Stop using chip->read_buf().
   - FSL:
      * Switch to SPDX license tag identifiers.
      * Fix qualifiers in MXC init functions.

  Raw NAND chip drivers changes:
   - Micron:
      * Add fixup for ONFI revision.
      * Update ecc_stats.corrected.
      * Make ECC activation stateful.
      * Avoid enabling/disabling ECC when it can't be disabled.
      * Get the actual number of bitflips.
      * Allow forced on-die ECC.
      * Support 8/512 on-die ECC.
      * Fix on-die ECC detection logic.
   - Hynix:
      * Fix decoding the OOB size on H27UCG8T2BTR.
      * Use ->exec_op() in hynix_nand_reg_write_op()"

* tag 'mtd/for-4.19' of git://git.infradead.org/linux-mtd: (188 commits)
  mtd: rawnand: atmel: Select GENERIC_ALLOCATOR
  MAINTAINERS: drop Wenyou Yang from Atmel NAND driver support
  mtd: rawnand: allocate dynamically ONFI parameters during detection
  mtd: spi-nor: only apply reset hacks to broken hardware
  mtd: spi-nor: cadence-quadspi: fix timeout handling
  mtd: spi-nor: atmel-quadspi: Include gpio/consumer.h instead of gpio.h
  mtd: spi-nor: intel-spi: use mtd_device_register()
  mtd: spi-nor: stm32-quadspi: replace "%p" with "%pK"
  mtd: spi-nor: atmel-quadspi: add suspend/resume hooks
  mtd: rawnand: allocate model parameter dynamically
  mtd: rawnand: do not export nand_scan_[ident|tail]() anymore
  mtd: rawnand: txx9ndfmc: convert driver to nand_scan()
  mtd: rawnand: txx9ndfmc: clarify ECC parameters assignation
  mtd: rawnand: tegra: convert driver to nand_scan()
  mtd: rawnand: jz4740: convert driver to nand_scan()
  mtd: rawnand: jz4740: group nand_scan_{ident, tail} calls
  mtd: rawnand: jz4740: fix probe function error path
  mtd: rawnand: docg4: convert driver to nand_scan()
  mtd: rawnand: do not execute nand_scan_ident() if maxchips is zero
  mtd: rawnand: atmel: convert driver to nand_scan()
  ...

123 files changed:
Documentation/devicetree/bindings/mtd/denali-nand.txt
Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt
Documentation/devicetree/bindings/mtd/nand.txt
Documentation/devicetree/bindings/mtd/nvidia-tegra20-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/partition.txt
Documentation/devicetree/bindings/mtd/partitions/brcm,trx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/qcom_nandc.txt
Documentation/devicetree/bindings/mtd/spi-nand.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/em-x270.c
arch/ia64/include/asm/io.h
arch/mips/include/asm/mach-jz4740/jz4740_nand.h [deleted file]
arch/mips/include/asm/txx9/ndfmc.h [deleted file]
arch/mips/jz4740/board-qi_lb60.c
arch/mips/txx9/generic/setup.c
arch/mips/txx9/generic/setup_tx4938.c
arch/mips/txx9/generic/setup_tx4939.c
arch/sparc/include/asm/io_64.h
drivers/bcma/Kconfig
drivers/memory/Kconfig
drivers/mtd/Kconfig
drivers/mtd/chips/Kconfig
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/gen_probe.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/powernv_flash.c
drivers/mtd/devices/sst25l.c
drivers/mtd/lpddr/Kconfig
drivers/mtd/lpddr/lpddr2_nvm.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/gpio-addr-flash.c
drivers/mtd/maps/impa7.c
drivers/mtd/maps/intel_vr_nor.c
drivers/mtd/maps/latch-addr-flash.c
drivers/mtd/maps/rbtx4939-flash.c
drivers/mtd/maps/solutionengine.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/onenand/generic.c
drivers/mtd/nand/onenand/samsung.c
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/Makefile
drivers/mtd/nand/raw/atmel/nand-controller.c
drivers/mtd/nand/raw/au1550nd.c
drivers/mtd/nand/raw/brcmnand/brcmnand.c
drivers/mtd/nand/raw/cafe_nand.c
drivers/mtd/nand/raw/cmx270_nand.c
drivers/mtd/nand/raw/cs553x_nand.c
drivers/mtd/nand/raw/davinci_nand.c
drivers/mtd/nand/raw/denali.c
drivers/mtd/nand/raw/denali.h
drivers/mtd/nand/raw/denali_dt.c
drivers/mtd/nand/raw/denali_pci.c
drivers/mtd/nand/raw/diskonchip.c
drivers/mtd/nand/raw/docg4.c
drivers/mtd/nand/raw/fsl_elbc_nand.c
drivers/mtd/nand/raw/fsl_ifc_nand.c
drivers/mtd/nand/raw/fsmc_nand.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
drivers/mtd/nand/raw/hisi504_nand.c
drivers/mtd/nand/raw/jz4740_nand.c
drivers/mtd/nand/raw/jz4780_nand.c
drivers/mtd/nand/raw/lpc32xx_mlc.c
drivers/mtd/nand/raw/lpc32xx_slc.c
drivers/mtd/nand/raw/marvell_nand.c
drivers/mtd/nand/raw/mtk_nand.c
drivers/mtd/nand/raw/mxc_nand.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/nand_bbt.c
drivers/mtd/nand/raw/nand_hynix.c
drivers/mtd/nand/raw/nand_micron.c
drivers/mtd/nand/raw/nand_timings.c
drivers/mtd/nand/raw/nandsim.c
drivers/mtd/nand/raw/ndfc.c
drivers/mtd/nand/raw/omap2.c
drivers/mtd/nand/raw/orion_nand.c
drivers/mtd/nand/raw/oxnas_nand.c
drivers/mtd/nand/raw/plat_nand.c
drivers/mtd/nand/raw/qcom_nandc.c
drivers/mtd/nand/raw/s3c2410.c
drivers/mtd/nand/raw/sh_flctl.c
drivers/mtd/nand/raw/sharpsl.c
drivers/mtd/nand/raw/sm_common.c
drivers/mtd/nand/raw/sunxi_nand.c
drivers/mtd/nand/raw/tango_nand.c
drivers/mtd/nand/raw/tegra_nand.c [new file with mode: 0644]
drivers/mtd/nand/raw/txx9ndfmc.c
drivers/mtd/nand/raw/vf610_nfc.c
drivers/mtd/nand/spi/Kconfig [new file with mode: 0644]
drivers/mtd/nand/spi/Makefile [new file with mode: 0644]
drivers/mtd/nand/spi/core.c [new file with mode: 0644]
drivers/mtd/nand/spi/macronix.c [new file with mode: 0644]
drivers/mtd/nand/spi/micron.c [new file with mode: 0644]
drivers/mtd/nand/spi/winbond.c [new file with mode: 0644]
drivers/mtd/nftlmount.c
drivers/mtd/parsers/parser_trx.c
drivers/mtd/spi-nor/atmel-quadspi.c
drivers/mtd/spi-nor/cadence-quadspi.c
drivers/mtd/spi-nor/intel-spi.c
drivers/mtd/spi-nor/nxp-spifi.c
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/spi-nor/stm32-quadspi.c
fs/jffs2/dir.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/os-linux.h
include/linux/mtd/mtd.h
include/linux/mtd/rawnand.h
include/linux/mtd/spi-nor.h
include/linux/mtd/spinand.h [new file with mode: 0644]
include/linux/platform_data/jz4740/jz4740_nand.h [new file with mode: 0644]
include/linux/platform_data/mtd-orion_nand.h
include/linux/platform_data/txx9/ndfmc.h [new file with mode: 0644]
include/linux/spi/spi-mem.h
lib/Makefile
lib/bch.c

index 0ee8edb60efc6d07e106314b57fa1cbaa943ed4d..f33da87827410fffe9d799fcc7a780b73c010fb0 100644 (file)
@@ -8,6 +8,9 @@ Required properties:
   - reg : should contain registers location and length for data and reg.
   - reg-names: Should contain the reg names "nand_data" and "denali_reg"
   - interrupts : The interrupt number.
+  - clocks: should contain phandle of the controller core clock, the bus
+    interface clock, and the ECC circuit clock.
+  - clock-names: should contain "nand", "nand_x", "ecc"
 
 Optional properties:
   - nand-ecc-step-size: see nand.txt for details.  If present, the value must be
@@ -31,5 +34,7 @@ nand: nand@ff900000 {
        compatible = "altr,socfpga-denali-nand";
        reg = <0xff900000 0x20>, <0xffb80000 0x1000>;
        reg-names = "nand_data", "denali_reg";
+       clocks = <&nand_clk>, <&nand_x_clk>, <&nand_ecc_clk>;
+       clock-names = "nand", "nand_x", "ecc";
        interrupts = <0 144 4>;
 };
index 956bb046e599d576e3f881b2901e0d369a3c9802..f03be904d3c228d8e46cc117ea0d5893f68e6e9b 100644 (file)
@@ -69,6 +69,15 @@ Optional properties:
                    all chips and support for it can not be detected at runtime.
                    Refer to your chips' datasheet to check if this is supported
                    by your chip.
+- broken-flash-reset : Some flash devices utilize stateful addressing modes
+                  (e.g., for 32-bit addressing) which need to be managed
+                  carefully by a system. Because these sorts of flash don't
+                  have a standardized software reset command, and because some
+                  systems don't toggle the flash RESET# pin upon system reset
+                  (if the pin even exists at all), there are systems which
+                  cannot reboot properly if the flash is left in the "wrong"
+                  state. This boolean flag can be used on such systems, to
+                  denote the absence of a reliable reset mechanism.
 
 Example:
 
index 8bb11d809429d7a28713da8523e1c15c09494ff7..e949c778e9837e4a0963c005371463294823dc72 100644 (file)
@@ -25,7 +25,7 @@ Optional NAND chip properties:
                  Deprecated values:
                  "soft_bch": use "soft" and nand-ecc-algo instead
 - nand-ecc-algo: string, algorithm of NAND ECC.
-                Supported values are: "hamming", "bch".
+                Valid values are: "hamming", "bch", "rs".
 - 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
 
@@ -43,6 +43,10 @@ Optional NAND chip properties:
                     This is particularly useful when only the in-band area is
                     used by the upper layers, and you want to make your NAND
                     as reliable as possible.
+- nand-is-boot-medium: Whether the NAND chip is a boot medium. Drivers might use
+                      this information to select ECC algorithms supported by
+                      the boot ROM or similar restrictions.
+
 - nand-rb: shall contain the native Ready/Busy ids.
 
 The ECC strength and ECC step size properties define the correction capability
diff --git a/Documentation/devicetree/bindings/mtd/nvidia-tegra20-nand.txt b/Documentation/devicetree/bindings/mtd/nvidia-tegra20-nand.txt
new file mode 100644 (file)
index 0000000..b2f2ca1
--- /dev/null
@@ -0,0 +1,64 @@
+NVIDIA Tegra NAND Flash controller
+
+Required properties:
+- compatible: Must be one of:
+  - "nvidia,tegra20-nand"
+- reg: MMIO address range
+- interrupts: interrupt output of the NFC controller
+- clocks: Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+  - nand
+- resets: Must contain an entry for each entry in reset-names.
+  See ../reset/reset.txt for details.
+- reset-names: Must include the following entries:
+  - nand
+
+Optional children nodes:
+Individual NAND chips are children of the NAND controller node. Currently
+only one NAND chip supported.
+
+Required children node properties:
+- reg: An integer ranging from 1 to 6 representing the CS line to use.
+
+Optional children node properties:
+- nand-ecc-mode: String, operation mode of the NAND ecc mode. Currently only
+                "hw" is supported.
+- nand-ecc-algo: string, algorithm of NAND ECC.
+                Supported values with "hw" ECC mode are: "rs", "bch".
+- nand-bus-width : See nand.txt
+- nand-on-flash-bbt: See nand.txt
+- nand-ecc-strength: integer representing the number of bits to correct
+                    per ECC step (always 512). Supported strength using HW ECC
+                    modes are:
+                    - RS: 4, 6, 8
+                    - BCH: 4, 8, 14, 16
+- nand-ecc-maximize: See nand.txt
+- nand-is-boot-medium: Makes sure only ECC strengths supported by the boot ROM
+                      are chosen.
+- wp-gpios: GPIO specifier for the write protect pin.
+
+Optional child node of NAND chip nodes:
+Partitions: see partition.txt
+
+  Example:
+       nand-controller@70008000 {
+               compatible = "nvidia,tegra20-nand";
+               reg = <0x70008000 0x100>;
+               interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&tegra_car TEGRA20_CLK_NDFLASH>;
+               clock-names = "nand";
+               resets = <&tegra_car 13>;
+               reset-names = "nand";
+
+               nand@0 {
+                       reg = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       nand-bus-width = <8>;
+                       nand-on-flash-bbt;
+                       nand-ecc-algo = "bch";
+                       nand-ecc-strength = <8>;
+                       wp-gpios = <&gpio TEGRA_GPIO(S, 0) GPIO_ACTIVE_LOW>;
+               };
+       };
index a8f382642ba9613764ffee288596f7db65446758..afbbd870496de54417b67473eb4fbb4adc3859ab 100644 (file)
@@ -14,6 +14,13 @@ method is used for a given flash device. To describe the method there should be
 a subnode of the flash device that is named 'partitions'. It must have a
 'compatible' property, which is used to identify the method to use.
 
+When a single partition is represented with a DT node (it depends on a used
+format) it may also be described using above rules ('compatible' and optionally
+some extra properties / subnodes). It allows describing more complex,
+hierarchical (multi-level) layouts and should be used if there is some
+significant relation between partitions or some partition internally uses
+another partitioning method.
+
 Available bindings are listed in the "partitions" subdirectory.
 
 
@@ -109,3 +116,42 @@ flash@2 {
                };
        };
 };
+
+flash@3 {
+       partitions {
+               compatible = "fixed-partitions";
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               partition@0 {
+                       label = "bootloader";
+                       reg = <0x000000 0x100000>;
+                       read-only;
+               };
+
+               firmware@100000 {
+                       label = "firmware";
+                       reg = <0x100000 0xe00000>;
+                       compatible = "brcm,trx";
+               };
+
+               calibration@f00000 {
+                       label = "calibration";
+                       reg = <0xf00000 0x100000>;
+                       compatible = "fixed-partitions";
+                       ranges = <0 0xf00000 0x100000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "wifi0";
+                               reg = <0x000000 0x080000>;
+                       };
+
+                       partition@80000 {
+                               label = "wifi1";
+                               reg = <0x080000 0x080000>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,trx.txt b/Documentation/devicetree/bindings/mtd/partitions/brcm,trx.txt
new file mode 100644 (file)
index 0000000..b677147
--- /dev/null
@@ -0,0 +1,37 @@
+Broadcom TRX Container Partition
+================================
+
+TRX is Broadcom's official firmware format for the BCM947xx boards. It's used by
+most of the vendors building devices based on Broadcom's BCM47xx SoCs and is
+supported by the CFE bootloader.
+
+Design of the TRX format is very minimalistic. Its header contains
+identification fields, CRC32 checksum and the locations of embedded partitions.
+Its purpose is to store a few partitions in a format that can be distributed as
+a standalone file and written in a flash memory.
+
+Container can hold up to 4 partitions. The first partition has to contain a
+device executable binary (e.g. a kernel) as it's what the CFE bootloader starts
+executing. Other partitions can be used for operating system purposes. This is
+useful for systems that keep kernel and rootfs separated.
+
+TRX doesn't enforce any strict partition boundaries or size limits. All
+partitions have to be less than the 4GiB max size limit.
+
+There are two existing/known TRX variants:
+1) v1 which contains 3 partitions
+2) v2 which contains 4 partitions
+
+There aren't separated compatible bindings for them as version can be trivialy
+detected by a software parsing TRX header.
+
+Required properties:
+- compatible : (required) must be "brcm,trx"
+
+Example:
+
+flash@0 {
+       partitions {
+               compatible = "brcm,trx";
+       };
+};
index 73d336befa081b95fb96d8e33863bb6c602fcca9..1123cc6d56ef3d52bfa9dd455b1981600872dfc3 100644 (file)
@@ -45,11 +45,12 @@ Required properties:
                        number (e.g., 0, 1, 2, etc.)
 - #address-cells:      see partition.txt
 - #size-cells:         see partition.txt
-- nand-ecc-strength:   see nand.txt
-- nand-ecc-step-size:  must be 512. see nand.txt for more details.
 
 Optional properties:
 - nand-bus-width:      see nand.txt
+- nand-ecc-strength:   see nand.txt. If not specified, then ECC strength will
+                       be used according to chip requirement and available
+                       OOB size.
 
 Each nandcs device node may optionally contain a 'partitions' sub-node, which
 further contains sub-nodes describing the flash partition mapping. See
@@ -77,7 +78,6 @@ nand-controller@1ac00000 {
                reg = <0>;
 
                nand-ecc-strength = <4>;
-               nand-ecc-step-size = <512>;
                nand-bus-width = <8>;
 
                partitions {
@@ -117,7 +117,6 @@ nand-controller@79b0000 {
        nand@0 {
                reg = <0>;
                nand-ecc-strength = <4>;
-               nand-ecc-step-size = <512>;
                nand-bus-width = <8>;
 
                partitions {
diff --git a/Documentation/devicetree/bindings/mtd/spi-nand.txt b/Documentation/devicetree/bindings/mtd/spi-nand.txt
new file mode 100644 (file)
index 0000000..8b51f3b
--- /dev/null
@@ -0,0 +1,5 @@
+SPI NAND flash
+
+Required properties:
+- compatible: should be "spi-nand"
+- reg: should encode the chip-select line used to access the NAND chip
index 0a2342770dee2e8db0a99178f10dfd0c43fd3768..78608226c30a502290c7891bc7bb0d0e7bd9863b 100644 (file)
@@ -9353,7 +9353,6 @@ F:        drivers/media/platform/atmel/atmel-isc-regs.h
 F:     devicetree/bindings/media/atmel-isc.txt
 
 MICROCHIP / ATMEL NAND DRIVER
-M:     Wenyou Yang <wenyou.yang@microchip.com>
 M:     Josh Wu <rainyfeeling@outlook.com>
 L:     linux-mtd@lists.infradead.org
 S:     Supported
@@ -14063,6 +14062,13 @@ M:     Laxman Dewangan <ldewangan@nvidia.com>
 S:     Supported
 F:     drivers/input/keyboard/tegra-kbc.c
 
+TEGRA NAND DRIVER
+M:     Stefan Agner <stefan@agner.ch>
+M:     Lucas Stach <dev@lynxeye.de>
+S:     Maintained
+F:     Documentation/devicetree/bindings/mtd/nvidia-tegra20-nand.txt
+F:     drivers/mtd/nand/raw/tegra_nand.c
+
 TEGRA PWM DRIVER
 M:     Thierry Reding <thierry.reding@gmail.com>
 S:     Supported
index f4f8f23bda8cc84c4f482ee760a11ed06ec4e14f..af46d21825331ea5662a8aa042e814c93070f5e8 100644 (file)
@@ -688,7 +688,6 @@ struct platform_nand_data balloon3_nand_pdata = {
                .chip_delay     = 50,
        },
        .ctrl = {
-               .hwcontrol      = 0,
                .dev_ready      = balloon3_nand_dev_ready,
                .select_chip    = balloon3_nand_select_chip,
                .cmd_ctrl       = balloon3_nand_cmd_ctl,
index 49022ad338e911c228962e5ed18af0e378fd4c6e..29be04c6cc4858f3e93b73a8083643578cbc51bc 100644 (file)
@@ -346,7 +346,6 @@ struct platform_nand_data em_x270_nand_platdata = {
                .chip_delay = 20,
        },
        .ctrl = {
-               .hwcontrol = 0,
                .dev_ready = em_x270_nand_device_ready,
                .select_chip = 0,
                .cmd_ctrl = em_x270_nand_cmd_ctl,
index fb0651961e2c2ecf336c4ba1e348bc6b891d9e31..6f952171abf9458ab9777566cb7647e1e03217df 100644 (file)
@@ -83,12 +83,14 @@ virt_to_phys (volatile void *address)
 {
        return (unsigned long) address - PAGE_OFFSET;
 }
+#define virt_to_phys virt_to_phys
 
 static inline void*
 phys_to_virt (unsigned long address)
 {
        return (void *) (address + PAGE_OFFSET);
 }
+#define phys_to_virt phys_to_virt
 
 #define ARCH_HAS_VALID_PHYS_ADDR_RANGE
 extern u64 kern_mem_attribute (unsigned long phys_addr, unsigned long size);
@@ -433,9 +435,11 @@ static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned lo
 {
        return ioremap(phys_addr, size);
 }
+#define ioremap ioremap
+#define ioremap_nocache ioremap_nocache
 #define ioremap_cache ioremap_cache
 #define ioremap_uc ioremap_nocache
-
+#define iounmap iounmap
 
 /*
  * String version of IO memory access ops:
@@ -444,6 +448,13 @@ extern void memcpy_fromio(void *dst, const volatile void __iomem *src, long n);
 extern void memcpy_toio(volatile void __iomem *dst, const void *src, long n);
 extern void memset_io(volatile void __iomem *s, int c, long n);
 
+#define memcpy_fromio memcpy_fromio
+#define memcpy_toio memcpy_toio
+#define memset_io memset_io
+#define xlate_dev_kmem_ptr xlate_dev_kmem_ptr
+#define xlate_dev_mem_ptr xlate_dev_mem_ptr
+#include <asm-generic/io.h>
+
 # endif /* __KERNEL__ */
 
 #endif /* _ASM_IA64_IO_H */
diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
deleted file mode 100644 (file)
index f381d46..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 SoC NAND controller driver
- *
- *  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.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef __ASM_MACH_JZ4740_JZ4740_NAND_H__
-#define __ASM_MACH_JZ4740_JZ4740_NAND_H__
-
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-
-#define JZ_NAND_NUM_BANKS 4
-
-struct jz_nand_platform_data {
-       int                     num_partitions;
-       struct mtd_partition    *partitions;
-
-       unsigned char banks[JZ_NAND_NUM_BANKS];
-
-       void (*ident_callback)(struct platform_device *, struct mtd_info *,
-                               struct mtd_partition **, int *num_partitions);
-};
-
-#endif
diff --git a/arch/mips/include/asm/txx9/ndfmc.h b/arch/mips/include/asm/txx9/ndfmc.h
deleted file mode 100644 (file)
index fa67f3d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * (C) Copyright TOSHIBA CORPORATION 2007
- */
-#ifndef __ASM_TXX9_NDFMC_H
-#define __ASM_TXX9_NDFMC_H
-
-#define NDFMC_PLAT_FLAG_USE_BSPRT      0x01
-#define NDFMC_PLAT_FLAG_NO_RSTR                0x02
-#define NDFMC_PLAT_FLAG_HOLDADD                0x04
-#define NDFMC_PLAT_FLAG_DUMMYWRITE     0x08
-
-struct txx9ndfmc_platform_data {
-       unsigned int shift;
-       unsigned int gbus_clock;
-       unsigned int hold;              /* hold time in nanosecond */
-       unsigned int spw;               /* strobe pulse width in nanosecond */
-       unsigned int flags;
-       unsigned char ch_mask;          /* available channel bitmask */
-       unsigned char wp_mask;          /* write-protect bitmask */
-       unsigned char wide_mask;        /* 16bit-nand bitmask */
-};
-
-void txx9_ndfmc_init(unsigned long baseaddr,
-                    const struct txx9ndfmc_platform_data *plat_data);
-
-#endif /* __ASM_TXX9_NDFMC_H */
index 60f0767507c62c70c98cc469aff43150435b6189..af0c8ace0141667337e39b615220da512ebc8586 100644 (file)
 #include <linux/power/gpio-charger.h>
 #include <linux/pwm.h>
 
+#include <linux/platform_data/jz4740/jz4740_nand.h>
+
 #include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/jz4740_fb.h>
 #include <asm/mach-jz4740/jz4740_mmc.h>
-#include <asm/mach-jz4740/jz4740_nand.h>
 
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
index dde4dc859f79c05a4a3417e43de356d6580361ad..f6d9182ef82a9cd2aa528d2de40f6e4634116119 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/err.h>
 #include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
+#include <linux/platform_data/txx9/ndfmc.h>
 #include <linux/serial_core.h>
 #include <linux/mtd/physmap.h>
 #include <linux/leds.h>
@@ -36,7 +37,6 @@
 #include <asm/txx9/generic.h>
 #include <asm/txx9/pci.h>
 #include <asm/txx9tmr.h>
-#include <asm/txx9/ndfmc.h>
 #include <asm/txx9/dmac.h>
 #ifdef CONFIG_CPU_TX49XX
 #include <asm/txx9/tx4938.h>
index 85d1795652da6d09a4fae6d4fcae08c813e83488..17395d5d15caf9738ec69b3af7e6c17b922603dc 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
+#include <linux/platform_data/txx9/ndfmc.h>
 #include <asm/reboot.h>
 #include <asm/traps.h>
 #include <asm/txx9irq.h>
 #include <asm/txx9tmr.h>
 #include <asm/txx9pio.h>
 #include <asm/txx9/generic.h>
-#include <asm/txx9/ndfmc.h>
 #include <asm/txx9/dmac.h>
 #include <asm/txx9/tx4938.h>
 
index 274928987a21a686e1e76a0d8d9f54fa624607e8..360c388f4c821eeb7ae9c58e77d529cd128263c3 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
+#include <linux/platform_data/txx9/ndfmc.h>
 #include <asm/bootinfo.h>
 #include <asm/reboot.h>
 #include <asm/traps.h>
 #include <asm/txx9irq.h>
 #include <asm/txx9tmr.h>
 #include <asm/txx9/generic.h>
-#include <asm/txx9/ndfmc.h>
 #include <asm/txx9/dmac.h>
 #include <asm/txx9/tx4939.h>
 
index 9a1e9cbc7e6df3a84a0f63fe00656bb6a49adf67..b162c23ae8c2305eea1ce1f8b6bb2a16aadcca24 100644 (file)
@@ -243,35 +243,42 @@ void insb(unsigned long, void *, unsigned long);
 void insw(unsigned long, void *, unsigned long);
 void insl(unsigned long, void *, unsigned long);
 
-static inline void ioread8_rep(void __iomem *port, void *buf, unsigned long count)
+static inline void readsb(void __iomem *port, void *buf, unsigned long count)
 {
        insb((unsigned long __force)port, buf, count);
 }
-static inline void ioread16_rep(void __iomem *port, void *buf, unsigned long count)
+static inline void readsw(void __iomem *port, void *buf, unsigned long count)
 {
        insw((unsigned long __force)port, buf, count);
 }
 
-static inline void ioread32_rep(void __iomem *port, void *buf, unsigned long count)
+static inline void readsl(void __iomem *port, void *buf, unsigned long count)
 {
        insl((unsigned long __force)port, buf, count);
 }
 
-static inline void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count)
+static inline void writesb(void __iomem *port, const void *buf, unsigned long count)
 {
        outsb((unsigned long __force)port, buf, count);
 }
 
-static inline void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count)
+static inline void writesw(void __iomem *port, const void *buf, unsigned long count)
 {
        outsw((unsigned long __force)port, buf, count);
 }
 
-static inline void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count)
+static inline void writesl(void __iomem *port, const void *buf, unsigned long count)
 {
        outsl((unsigned long __force)port, buf, count);
 }
 
+#define ioread8_rep(p,d,l)     readsb(p,d,l)
+#define ioread16_rep(p,d,l)    readsw(p,d,l)
+#define ioread32_rep(p,d,l)    readsl(p,d,l)
+#define iowrite8_rep(p,d,l)    writesb(p,d,l)
+#define iowrite16_rep(p,d,l)   writesw(p,d,l)
+#define iowrite32_rep(p,d,l)   writesl(p,d,l)
+
 /* Valid I/O Space regions are anywhere, because each PCI bus supported
  * can live in an arbitrary area of the physical address range.
  */
index cb0f1aad20b7dd1932e80f5c3b5153fc75eb2b4c..b9558ff20830eec89a3d219172fb179b9b3bced8 100644 (file)
@@ -30,6 +30,7 @@ config BCMA_HOST_PCI
 
 config BCMA_HOST_SOC
        bool "Support for BCMA in a SoC"
+       depends on HAS_IOMEM
        help
          Host interface for a Broadcom AIX bus directly mapped into
          the memory. This only works with the Broadcom SoCs from the
@@ -61,7 +62,7 @@ config BCMA_DRIVER_PCI_HOSTMODE
 
 config BCMA_DRIVER_MIPS
        bool "BCMA Broadcom MIPS core driver"
-       depends on MIPS
+       depends on MIPS || COMPILE_TEST
        help
          Driver for the Broadcom MIPS core attached to Broadcom specific
          Advanced Microcontroller Bus.
index 8d731d6c3e541c39dfa908a116806d0f15dad135..63389f075f1dcab5637f4a72bc1081303fc86075 100644 (file)
@@ -116,12 +116,14 @@ config FSL_CORENET_CF
 
 config FSL_IFC
        bool
-       depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
+       depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST
+       depends on HAS_IOMEM
 
 config JZ4780_NEMC
        bool "Ingenic JZ4780 SoC NEMC driver"
        default y
-       depends on MACH_JZ4780
+       depends on MACH_JZ4780 || COMPILE_TEST
+       depends on HAS_IOMEM && OF
        help
          This driver is for the NAND/External Memory Controller (NEMC) in
          the Ingenic JZ4780. This controller is used to handle external
index 46ab7feec6b686b1f217899420ff160505f46396..c77f537323ecb371d1be527df650bf6fb8ca4713 100644 (file)
@@ -24,7 +24,7 @@ config MTD_TESTS
 
 config MTD_REDBOOT_PARTS
        tristate "RedBoot partition table parsing"
-       ---help---
+       help
          RedBoot is a ROM monitor and bootloader which deals with multiple
          'images' in flash devices by putting a table one of the erase
          blocks on the device, similar to a partition table, which gives
@@ -45,7 +45,7 @@ if MTD_REDBOOT_PARTS
 config MTD_REDBOOT_DIRECTORY_BLOCK
        int "Location of RedBoot partition table"
        default "-1"
-       ---help---
+       help
          This option is the Linux counterpart to the
          CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK RedBoot compile time
          option.
@@ -75,7 +75,7 @@ endif # MTD_REDBOOT_PARTS
 config MTD_CMDLINE_PARTS
        tristate "Command line partition table parsing"
        depends on MTD
-       ---help---
+       help
          Allow generic configuration of the MTD partition tables via the kernel
          command line. Multiple flash resources are supported for hardware where
          different kinds of flash memory are available.
@@ -112,7 +112,7 @@ config MTD_CMDLINE_PARTS
 config MTD_AFS_PARTS
        tristate "ARM Firmware Suite partition parsing"
        depends on (ARM || ARM64)
-       ---help---
+       help
          The ARM Firmware Suite allows the user to divide flash devices into
          multiple 'images'. Each such image has a header containing its name
          and offset/size etc.
@@ -136,7 +136,7 @@ config MTD_OF_PARTS
 
 config MTD_AR7_PARTS
        tristate "TI AR7 partitioning support"
-       ---help---
+       help
          TI AR7 partitioning support
 
 config MTD_BCM63XX_PARTS
@@ -170,7 +170,7 @@ config MTD_BLOCK
        tristate "Caching block device access to MTD devices"
        depends on BLOCK
        select MTD_BLKDEVS
-       ---help---
+       help
          Although most flash chips have an erase size too large to be useful
          as block devices, it is possible to use MTD devices which are based
          on RAM chips in this manner. This block device is a user of MTD
@@ -205,7 +205,7 @@ config FTL
        tristate "FTL (Flash Translation Layer) support"
        depends on BLOCK
        select MTD_BLKDEVS
-       ---help---
+       help
          This provides support for the original Flash Translation Layer which
          is part of the PCMCIA specification. It uses a kind of pseudo-
          file system on a flash device to emulate a block device with
@@ -222,7 +222,7 @@ config NFTL
        tristate "NFTL (NAND Flash Translation Layer) support"
        depends on BLOCK
        select MTD_BLKDEVS
-       ---help---
+       help
          This provides support for the NAND Flash Translation Layer which is
          used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
          file system on a flash device to emulate a block device with
@@ -246,7 +246,7 @@ config INFTL
        tristate "INFTL (Inverse NAND Flash Translation Layer) support"
        depends on BLOCK
        select MTD_BLKDEVS
-       ---help---
+       help
          This provides support for the Inverse NAND Flash Translation
          Layer which is used on M-Systems' newer DiskOnChip devices. It
          uses a kind of pseudo-file system on a flash device to emulate
@@ -261,10 +261,10 @@ config INFTL
          not use it.
 
 config RFD_FTL
-        tristate "Resident Flash Disk (Flash Translation Layer) support"
+       tristate "Resident Flash Disk (Flash Translation Layer) support"
        depends on BLOCK
        select MTD_BLKDEVS
-       ---help---
+       help
          This provides support for the flash translation layer known
          as the Resident Flash Disk (RFD), as used by the Embedded BIOS
          of General Software. There is a blurb at:
@@ -308,7 +308,7 @@ config MTD_SWAP
        select MTD_BLKDEVS
        help
          Provides volatile block device driver on top of mtd partition
-          suitable for swapping.  The mapping of written blocks is not saved.
+         suitable for swapping.  The mapping of written blocks is not saved.
          The driver provides wear leveling by storing erase counter into the
          OOB.
 
index bbfa1f1292668a84f7e0a6e708dfd9a6b01d1d20..39ec32a2905185fd6e14cae44d9bd15d4975d804 100644 (file)
@@ -44,7 +44,7 @@ choice
        prompt "Flash cmd/query data swapping"
        depends on MTD_CFI_ADV_OPTIONS
        default MTD_CFI_NOSWAP
-       ---help---
+       help
          This option defines the way in which the CPU attempts to arrange
          data bits when writing the 'magic' commands to the chips. Saying
          'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't
index 1b64ac8c5bc86309061a5540d385eb6e2ca866cc..72428b6bfc474ba6d757b94d79ff62804cc7c8ec 100644 (file)
@@ -1216,7 +1216,6 @@ static inline int do_read_secsi_onechip(struct map_info *map,
                                        size_t grouplen)
 {
        DECLARE_WAITQUEUE(wait, current);
-       unsigned long timeo = jiffies + HZ;
 
  retry:
        mutex_lock(&chip->mutex);
@@ -1229,7 +1228,6 @@ static inline int do_read_secsi_onechip(struct map_info *map,
 
                schedule();
                remove_wait_queue(&chip->wq, &wait);
-               timeo = jiffies + HZ;
 
                goto retry;
        }
index b57ceea21513acd0e017b994fe2170905f80bf0a..837b04ab96a9c526f19699655cfa9ee174bd190b 100644 (file)
@@ -202,16 +202,19 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
        struct cfi_private *cfi = map->fldrv_priv;
        __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
 #ifdef CONFIG_MODULES
-       char probename[sizeof(VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X))];
        cfi_cmdset_fn_t *probe_function;
+       char *probename;
 
-       sprintf(probename, VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X), type);
+       probename = kasprintf(GFP_KERNEL, "cfi_cmdset_%4.4X", type);
+       if (!probename)
+               return NULL;
 
        probe_function = __symbol_get(probename);
        if (!probe_function) {
                request_module("cfi_cmdset_%4.4X", type);
                probe_function = __symbol_get(probename);
        }
+       kfree(probename);
 
        if (probe_function) {
                struct mtd_info *mtd;
index 57b02c4b3f63b7588751723e036e29c7093fb0c6..e514d57a0419defecb8dcbbc8be4604aea1321da 100644 (file)
@@ -5,7 +5,7 @@ menu "Self-contained MTD device drivers"
 config MTD_PMC551
        tristate "Ramix PMC551 PCI Mezzanine RAM card support"
        depends on PCI
-       ---help---
+       help
          This provides a MTD device driver for the Ramix PMC551 RAM PCI card
          from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
          These devices come in memory configurations from 32M - 1G.  If you
@@ -209,7 +209,7 @@ config MTD_DOCG3
        select BCH
        select BCH_CONST_PARAMS
        select BITREVERSE
-       ---help---
+       help
          This provides an MTD device driver for the M-Systems DiskOnChip
          G3 devices.
 
index e84563d2067f4fe28c1f0ed21defda049323dd36..fe260ccb2d7d4173bf7895c888645312256864f9 100644 (file)
 #include <linux/spi/flash.h>
 #include <linux/mtd/spi-nor.h>
 
-#define        MAX_CMD_SIZE            6
 struct m25p {
        struct spi_mem          *spimem;
        struct spi_nor          spi_nor;
-       u8                      command[MAX_CMD_SIZE];
 };
 
 static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
@@ -70,7 +68,7 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
        struct spi_mem_op op =
                        SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
                                   SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
-                                  SPI_MEM_OP_DUMMY(0, 1),
+                                  SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_DATA_OUT(len, buf, 1));
        size_t remaining = len;
        int ret;
@@ -78,7 +76,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
        /* get transfer protocols. */
        op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
        op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
-       op.dummy.buswidth = op.addr.buswidth;
        op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
 
        if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
index c1312b141ae0538cbaeed3b4ccde20109dd01a62..33593122e49b89646387d7c278ffc96ee1a593d9 100644 (file)
@@ -223,6 +223,7 @@ static int powernv_flash_set_driver_info(struct device *dev,
        mtd->_read = powernv_flash_read;
        mtd->_write = powernv_flash_write;
        mtd->dev.parent = dev;
+       mtd_set_of_node(mtd, dev->of_node);
        return 0;
 }
 
index 1897f33fe3e71dea5c6d75e794f83a7bfe129082..10d24efb46291e092ac96c9c62ccd0db322c5aac 100644 (file)
@@ -394,9 +394,8 @@ static int sst25l_probe(struct spi_device *spi)
              flash->mtd.numeraseregions);
 
 
-       ret = mtd_device_parse_register(&flash->mtd, NULL, NULL,
-                                       data ? data->parts : NULL,
-                                       data ? data->nr_parts : 0);
+       ret = mtd_device_register(&flash->mtd, data ? data->parts : NULL,
+                                 data ? data->nr_parts : 0);
        if (ret)
                return -ENODEV;
 
index 3a19cbee24d7012c96b22d4c5fa94aaa713777f0..a5a332fbd593cbd45388362412c144d8b3c6e6f7 100644 (file)
@@ -13,10 +13,10 @@ config MTD_QINFO_PROBE
        depends on MTD_LPDDR
        tristate "Detect flash chips by QINFO probe"
        help
-           Device Information for LPDDR chips is offered through the Overlay
-           Window QINFO interface, permits software to be used for entire
-           families of devices. This serves similar purpose of CFI on legacy
-           Flash products
+         Device Information for LPDDR chips is offered through the Overlay
+         Window QINFO interface, permits software to be used for entire
+         families of devices. This serves similar purpose of CFI on legacy
+         Flash products
 
 config MTD_LPDDR2_NVM
        # ARM dependency is only for writel_relaxed()
index 5d73db2a496de2693ade04d28bcfb25ce814d7db..c950c880ad5904676e1e16e6433bafc3809ba2cf 100644 (file)
@@ -476,7 +476,7 @@ static int lpddr2_nvm_probe(struct platform_device *pdev)
                return -EINVAL;
        }
        /* Parse partitions and register the MTD device */
-       return mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+       return mtd_device_register(mtd, NULL, 0);
 }
 
 /*
index bdc1283f30fb86bbc146d2ff8154dd04ff6d98a2..afb36bff13a78989b5a8385a0f0da7124558ba90 100644 (file)
@@ -207,13 +207,13 @@ config MTD_ICHXROM
          BE VERY CAREFUL.
 
 config MTD_ESB2ROM
-        tristate "BIOS flash chip on Intel ESB Controller Hub 2"
-        depends on X86 && MTD_JEDECPROBE && PCI
-        help
-          Support for treating the BIOS flash chip on ESB2 motherboards
-          as an MTD device - with this you can reprogram your BIOS.
+       tristate "BIOS flash chip on Intel ESB Controller Hub 2"
+       depends on X86 && MTD_JEDECPROBE && PCI
+       help
+         Support for treating the BIOS flash chip on ESB2 motherboards
+         as an MTD device - with this you can reprogram your BIOS.
 
-          BE VERY CAREFUL.
+         BE VERY CAREFUL.
 
 config MTD_CK804XROM
        tristate "BIOS flash chip on Nvidia CK804"
@@ -401,12 +401,12 @@ config MTD_PISMO
          When built as a module, it will be called pismo.ko
 
 config MTD_LATCH_ADDR
-        tristate "Latch-assisted Flash Chip Support"
-        depends on MTD_COMPLEX_MAPPINGS
-        help
-          Map driver which allows flashes to be partially physically addressed
-          and have the upper address lines set by a board specific code.
+       tristate "Latch-assisted Flash Chip Support"
+       depends on MTD_COMPLEX_MAPPINGS
+       help
+         Map driver which allows flashes to be partially physically addressed
+         and have the upper address lines set by a board specific code.
 
-          If compiled as a module, it will be called latch-addr-flash.
+         If compiled as a module, it will be called latch-addr-flash.
 
 endmenu
index 385305e66fd1c2af4d50f1984a58e7191832be21..9d972369321755b5560c371626d9c8bf9a8d8271 100644 (file)
@@ -239,6 +239,9 @@ static int gpio_flash_probe(struct platform_device *pdev)
        state->map.bankwidth  = pdata->width;
        state->map.size       = state->win_size * (1 << state->gpio_count);
        state->map.virt       = ioremap_nocache(memory->start, state->map.size);
+       if (!state->map.virt)
+               return -ENOMEM;
+
        state->map.phys       = NO_XIP;
        state->map.map_priv_1 = (unsigned long)state;
 
index a0b8fa7849a956c31250fd6946638f3423a9b58e..815e2db87955448f4b3b3f375b4d613fee7ac925 100644 (file)
@@ -88,9 +88,8 @@ static int __init init_impa7(void)
                if (impa7_mtd[i]) {
                        impa7_mtd[i]->owner = THIS_MODULE;
                        devicesfound++;
-                       mtd_device_parse_register(impa7_mtd[i], NULL, NULL,
-                                                 partitions,
-                                                 ARRAY_SIZE(partitions));
+                       mtd_device_register(impa7_mtd[i], partitions,
+                                           ARRAY_SIZE(partitions));
                } else {
                        iounmap((void __iomem *)impa7_map[i].virt);
                }
index dd5d6855f5432083e4745974dbf19213d4a5d690..69503aef981e6f9e059463d25cb958b6f35fd2e8 100644 (file)
@@ -71,7 +71,7 @@ static int vr_nor_init_partitions(struct vr_nor_mtd *p)
 {
        /* register the flash bank */
        /* partition the flash bank */
-       return mtd_device_parse_register(p->info, NULL, NULL, NULL, 0);
+       return mtd_device_register(p->info, NULL, 0);
 }
 
 static void vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
index 6dc97aa667dc553cc44033b34394374b3c8b36d1..51db24b7f88de56d1e945ffa6590bef8f450f0fe 100644 (file)
@@ -197,9 +197,8 @@ static int latch_addr_flash_probe(struct platform_device *dev)
        }
        info->mtd->dev.parent = &dev->dev;
 
-       mtd_device_parse_register(info->mtd, NULL, NULL,
-                                 latch_addr_data->parts,
-                                 latch_addr_data->nr_parts);
+       mtd_device_register(info->mtd, latch_addr_data->parts,
+                           latch_addr_data->nr_parts);
        return 0;
 
 iounmap:
index 3a06ecfc55ff6baf9782cfc78118b2feff564744..80a187167c924b645c363cdbc0ea817289ddfc25 100644 (file)
@@ -97,8 +97,7 @@ static int rbtx4939_flash_probe(struct platform_device *dev)
                goto err_out;
        }
        info->mtd->dev.parent = &dev->dev;
-       err = mtd_device_parse_register(info->mtd, NULL, NULL, pdata->parts,
-                                       pdata->nr_parts);
+       err = mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts);
 
        if (err)
                goto err_out;
index bb580bc164459a3dee5b27ef34125af8f31ba2d5..c07f21b20463252e63a0ac0f313f75a7c4c05eaa 100644 (file)
@@ -59,9 +59,9 @@ static int __init init_soleng_maps(void)
                        return -ENXIO;
                }
        }
-       printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n",
-              soleng_flash_map.phys & 0x1fffffff,
-              soleng_eprom_map.phys & 0x1fffffff);
+       printk(KERN_NOTICE "Solution Engine: Flash at 0x%pap, EPROM at 0x%pap\n",
+              &soleng_flash_map.phys,
+              &soleng_eprom_map.phys);
        flash_mtd->owner = THIS_MODULE;
 
        eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map);
index cd67c85cc87de460b63c2f912f515aca1dc3e14e..02389528f622d819431fe24b0277031b214dd702 100644 (file)
@@ -160,8 +160,12 @@ static ssize_t mtdchar_read(struct file *file, char __user *buf, size_t count,
 
        pr_debug("MTD_read\n");
 
-       if (*ppos + count > mtd->size)
-               count = mtd->size - *ppos;
+       if (*ppos + count > mtd->size) {
+               if (*ppos < mtd->size)
+                       count = mtd->size - *ppos;
+               else
+                       count = 0;
+       }
 
        if (!count)
                return 0;
@@ -246,7 +250,7 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c
 
        pr_debug("MTD_write\n");
 
-       if (*ppos == mtd->size)
+       if (*ppos >= mtd->size)
                return -ENOSPC;
 
        if (*ppos + count > mtd->size)
index 42395df06be9ab3f8a5fd42920e23f9307f2d0b7..97ac219c082e7ef78993084ffcc8c9e98abaaac4 100644 (file)
@@ -1155,21 +1155,29 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 {
        int ret_code;
        ops->retlen = ops->oobretlen = 0;
-       if (!mtd->_read_oob)
-               return -EOPNOTSUPP;
 
        ret_code = mtd_check_oob_ops(mtd, from, ops);
        if (ret_code)
                return ret_code;
 
        ledtrig_mtd_activity();
+
+       /* Check the validity of a potential fallback on mtd->_read */
+       if (!mtd->_read_oob && (!mtd->_read || ops->oobbuf))
+               return -EOPNOTSUPP;
+
+       if (mtd->_read_oob)
+               ret_code = mtd->_read_oob(mtd, from, ops);
+       else
+               ret_code = mtd->_read(mtd, from, ops->len, &ops->retlen,
+                                     ops->datbuf);
+
        /*
         * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
         * similar to mtd->_read(), returning a non-negative integer
         * representing max bitflips. In other cases, mtd->_read_oob() may
         * return -EUCLEAN. In all cases, perform similar logic to mtd_read().
         */
-       ret_code = mtd->_read_oob(mtd, from, ops);
        if (unlikely(ret_code < 0))
                return ret_code;
        if (mtd->ecc_strength == 0)
@@ -1184,8 +1192,7 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
        int ret;
 
        ops->retlen = ops->oobretlen = 0;
-       if (!mtd->_write_oob)
-               return -EOPNOTSUPP;
+
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
 
@@ -1194,7 +1201,16 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
                return ret;
 
        ledtrig_mtd_activity();
-       return mtd->_write_oob(mtd, to, ops);
+
+       /* Check the validity of a potential fallback on mtd->_write */
+       if (!mtd->_write_oob && (!mtd->_write || ops->oobbuf))
+               return -EOPNOTSUPP;
+
+       if (mtd->_write_oob)
+               return mtd->_write_oob(mtd, to, ops);
+       else
+               return mtd->_write(mtd, to, ops->len, &ops->retlen,
+                                  ops->datbuf);
 }
 EXPORT_SYMBOL_GPL(mtd_write_oob);
 
index f8d3a015cdadef3e00920509fdc1a868cef16976..52e2cb35fc7902b1fce895d46e9944a6d908946d 100644 (file)
@@ -322,22 +322,6 @@ static inline void free_partition(struct mtd_part *p)
        kfree(p);
 }
 
-/**
- * mtd_parse_part - parse MTD partition looking for subpartitions
- *
- * @slave: part that is supposed to be a container and should be parsed
- * @types: NULL-terminated array with names of partition parsers to try
- *
- * Some partitions are kind of containers with extra subpartitions (volumes).
- * There can be various formats of such containers. This function tries to use
- * specified parsers to analyze given partition and registers found
- * subpartitions on success.
- */
-static int mtd_parse_part(struct mtd_part *slave, const char *const *types)
-{
-       return parse_mtd_partitions(&slave->mtd, types, NULL);
-}
-
 static struct mtd_part *allocate_partition(struct mtd_info *parent,
                        const struct mtd_partition *part, int partno,
                        uint64_t cur_offset)
@@ -735,8 +719,8 @@ int add_mtd_partitions(struct mtd_info *master,
 
                add_mtd_device(&slave->mtd);
                mtd_add_partition_attrs(slave);
-               if (parts[i].types)
-                       mtd_parse_part(slave, parts[i].types);
+               /* Look for subpartitions */
+               parse_mtd_partitions(&slave->mtd, parts[i].types, NULL);
 
                cur_offset = slave->offset + slave->mtd.size;
        }
@@ -812,6 +796,12 @@ static const char * const default_mtd_part_types[] = {
        NULL
 };
 
+/* Check DT only when looking for subpartitions. */
+static const char * const default_subpartition_types[] = {
+       "ofpart",
+       NULL
+};
+
 static int mtd_part_do_parse(struct mtd_part_parser *parser,
                             struct mtd_info *master,
                             struct mtd_partitions *pparts,
@@ -882,7 +872,9 @@ static int mtd_part_of_parse(struct mtd_info *master,
        const char *fixed = "fixed-partitions";
        int ret, err = 0;
 
-       np = of_get_child_by_name(mtd_get_of_node(master), "partitions");
+       np = mtd_get_of_node(master);
+       if (!mtd_is_partition(master))
+               np = of_get_child_by_name(np, "partitions");
        of_property_for_each_string(np, "compatible", prop, compat) {
                parser = mtd_part_get_compatible_parser(compat);
                if (!parser)
@@ -945,7 +937,8 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
        int ret, err = 0;
 
        if (!types)
-               types = default_mtd_part_types;
+               types = mtd_is_partition(master) ? default_subpartition_types :
+                       default_mtd_part_types;
 
        for ( ; *types; types++) {
                /*
index 88c7d3b4ff8b3661c34f046f36eb651e07b43929..9033215e62ea001b1b39ef02b5e0258115b7875f 100644 (file)
@@ -4,3 +4,4 @@ config MTD_NAND_CORE
 source "drivers/mtd/nand/onenand/Kconfig"
 
 source "drivers/mtd/nand/raw/Kconfig"
+source "drivers/mtd/nand/spi/Kconfig"
index 3f0cb87f1a57f11692a16b5a882d68ba055b0094..7ecd80c0a66e6b53309440a8375041ec6cb967b7 100644 (file)
@@ -5,3 +5,4 @@ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
 
 obj-y  += onenand/
 obj-y  += raw/
+obj-y  += spi/
index d5ccaf943b91f710fde971442cc5c5b4be74dea0..acad17ec6581a247f3377b27024cdb839a75a0a1 100644 (file)
@@ -66,9 +66,8 @@ static int generic_onenand_probe(struct platform_device *pdev)
                goto out_iounmap;
        }
 
-       err = mtd_device_parse_register(&info->mtd, NULL, NULL,
-                                       pdata ? pdata->parts : NULL,
-                                       pdata ? pdata->nr_parts : 0);
+       err = mtd_device_register(&info->mtd, pdata ? pdata->parts : NULL,
+                                 pdata ? pdata->nr_parts : 0);
 
        platform_set_drvdata(pdev, info);
 
index 4cce4c0311ca440c7e57c482a9866c84b3d63f5a..e64d0fdf7eb5a503d94476be04966cbbe9407504 100644 (file)
@@ -933,9 +933,8 @@ static int s3c_onenand_probe(struct platform_device *pdev)
        if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ)
                dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n");
 
-       err = mtd_device_parse_register(mtd, NULL, NULL,
-                                       pdata ? pdata->parts : NULL,
-                                       pdata ? pdata->nr_parts : 0);
+       err = mtd_device_register(mtd, pdata ? pdata->parts : NULL,
+                                 pdata ? pdata->nr_parts : 0);
        if (err) {
                dev_err(&pdev->dev, "failed to parse partitions and register the MTD device\n");
                onenand_release(mtd);
index 6871ff0fd300bb8195f79f993982223c96c870a5..5fc9a1bde4ac2e6d6e8475ab92c81342395d03d7 100644 (file)
@@ -44,12 +44,12 @@ config MTD_NAND_DENALI
        tristate
 
 config MTD_NAND_DENALI_PCI
-        tristate "Support Denali NAND controller on Intel Moorestown"
+       tristate "Support Denali NAND controller on Intel Moorestown"
        select MTD_NAND_DENALI
        depends on PCI
-        help
-          Enable the driver for NAND flash on Intel Moorestown, using the
-          Denali NAND controller core.
+       help
+         Enable the driver for NAND flash on Intel Moorestown, using the
+         Denali NAND controller core.
 
 config MTD_NAND_DENALI_DT
        tristate "Support Denali NAND controller as a DT device"
@@ -77,9 +77,10 @@ config MTD_NAND_AMS_DELTA
 
 config MTD_NAND_OMAP2
        tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
-       depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
+       depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST
+       depends on HAS_IOMEM
        help
-          Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
+         Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
          and Keystone platforms.
 
 config MTD_NAND_OMAP_BCH
@@ -137,7 +138,7 @@ config MTD_NAND_NDFC
        depends on 4xx
        select MTD_NAND_ECC_SMC
        help
-        NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
+         NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
 
 config MTD_NAND_S3C2410_CLKSTOP
        bool "Samsung S3C NAND IDLE clock stop"
@@ -152,6 +153,7 @@ config MTD_NAND_S3C2410_CLKSTOP
 config MTD_NAND_TANGO
        tristate "NAND Flash support for Tango chips"
        depends on ARCH_TANGO || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enables the NAND Flash controller on Tango chips.
 
@@ -168,40 +170,40 @@ config MTD_NAND_DISKONCHIP
          these devices.
 
 config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-        bool "Advanced detection options for DiskOnChip"
-        depends on MTD_NAND_DISKONCHIP
-        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'.
+       bool "Advanced detection options for DiskOnChip"
+       depends on MTD_NAND_DISKONCHIP
+       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_NAND_DISKONCHIP_PROBE_ADDRESS
-        hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-        depends on MTD_NAND_DISKONCHIP
-        default "0"
-        ---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.
+       hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
+       depends on MTD_NAND_DISKONCHIP
+       default "0"
+       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_NAND_DISKONCHIP_PROBE_HIGH
-        bool "Probe high addresses"
-        depends on MTD_NAND_DISKONCHIP_PROBE_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'.
+       bool "Probe high addresses"
+       depends on MTD_NAND_DISKONCHIP_PROBE_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_NAND_DISKONCHIP_BBTWRITE
        bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
@@ -247,7 +249,8 @@ config MTD_NAND_DOCG4
 
 config MTD_NAND_SHARPSL
        tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
-       depends on ARCH_PXA
+       depends on ARCH_PXA || COMPILE_TEST
+       depends on HAS_IOMEM
 
 config MTD_NAND_CAFE
        tristate "NAND support for OLPC CAFÉ chip"
@@ -274,7 +277,9 @@ config MTD_NAND_CS553X
 
 config MTD_NAND_ATMEL
        tristate "Support for NAND Flash / SmartMedia on AT91"
-       depends on ARCH_AT91
+       depends on ARCH_AT91 || COMPILE_TEST
+       depends on HAS_IOMEM
+       select GENERIC_ALLOCATOR
        select MFD_ATMEL_SMC
        help
          Enables support for NAND Flash / Smart Media Card interface
@@ -294,7 +299,8 @@ config MTD_NAND_MARVELL
 
 config MTD_NAND_SLC_LPC32XX
        tristate "NXP LPC32xx SLC Controller"
-       depends on ARCH_LPC32XX
+       depends on ARCH_LPC32XX || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
          chips) NAND controller. This is the default for the PHYTEC 3250
@@ -305,7 +311,8 @@ config MTD_NAND_SLC_LPC32XX
 
 config MTD_NAND_MLC_LPC32XX
        tristate "NXP LPC32xx MLC Controller"
-       depends on ARCH_LPC32XX
+       depends on ARCH_LPC32XX || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
          controller. This is the default for the WORK92105 controller
@@ -339,17 +346,18 @@ config MTD_NAND_NANDSIM
          MTD nand layer.
 
 config MTD_NAND_GPMI_NAND
-        tristate "GPMI NAND Flash Controller driver"
-        depends on MTD_NAND && MXS_DMA
-        help
-        Enables NAND Flash support for IMX23, IMX28 or IMX6.
-        The GPMI controller is very powerful, with the help of BCH
-        module, it can do the hardware ECC. The GPMI supports several
-        NAND flashs at the same time.
+       tristate "GPMI NAND Flash Controller driver"
+       depends on MXS_DMA
+       help
+         Enables NAND Flash support for IMX23, IMX28 or IMX6.
+         The GPMI controller is very powerful, with the help of BCH
+         module, it can do the hardware ECC. The GPMI supports several
+         NAND flashs at the same time.
 
 config MTD_NAND_BRCMNAND
        tristate "Broadcom STB NAND controller"
-       depends on ARM || ARM64 || MIPS
+       depends on ARM || ARM64 || MIPS || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enables the Broadcom NAND controller driver. The controller was
          originally designed for Set-Top Box but is used on various BCM7xxx,
@@ -358,6 +366,7 @@ config MTD_NAND_BRCMNAND
 config MTD_NAND_BCM47XXNFLASH
        tristate "Support for NAND flash on BCM4706 BCMA bus"
        depends on BCMA_NFLASH
+       depends on BCMA
        help
          BCMA bus can have various flash memories attached, they are
          registered by bcma as platform devices. This enables driver for
@@ -399,7 +408,8 @@ config MTD_NAND_FSL_ELBC
 
 config MTD_NAND_FSL_IFC
        tristate "NAND support for Freescale IFC controller"
-       depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
+       depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST
+       depends on HAS_IOMEM
        select FSL_IFC
        select MEMORY
        help
@@ -437,7 +447,8 @@ config MTD_NAND_VF610_NFC
 
 config MTD_NAND_MXC
        tristate "MXC NAND support"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          This enables the driver for the NAND flash controller on the
          MXC processors.
@@ -451,15 +462,17 @@ config MTD_NAND_SH_FLCTL
          for NAND Flash using FLCTL.
 
 config MTD_NAND_DAVINCI
-        tristate "Support NAND on DaVinci/Keystone SoC"
-        depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
-        help
+       tristate "Support NAND on DaVinci/Keystone SoC"
+       depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) || COMPILE_TEST
+       depends on HAS_IOMEM
+       help
          Enable the driver for NAND flash chips on Texas Instruments
          DaVinci/Keystone processors.
 
 config MTD_NAND_TXX9NDFMC
        tristate "NAND Flash support for TXx9 SoC"
-       depends on SOC_TX4938 || SOC_TX4939
+       depends on SOC_TX4938 || SOC_TX4939 || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          This enables the NAND flash controller on the TXx9 SoCs.
 
@@ -471,28 +484,31 @@ config MTD_NAND_SOCRATES
 
 config MTD_NAND_NUC900
        tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
-       depends on ARCH_W90X900
+       depends on ARCH_W90X900 || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          This enables the driver for the NAND Flash on evaluation board based
          on w90p910 / NUC9xx.
 
 config MTD_NAND_JZ4740
        tristate "Support for JZ4740 SoC NAND controller"
-       depends on MACH_JZ4740
+       depends on MACH_JZ4740 || COMPILE_TEST
+       depends on HAS_IOMEM
        help
-               Enables support for NAND Flash on JZ4740 SoC based boards.
+         Enables support for NAND Flash on JZ4740 SoC based boards.
 
 config MTD_NAND_JZ4780
        tristate "Support for NAND on JZ4780 SoC"
-       depends on MACH_JZ4780 && JZ4780_NEMC
+       depends on JZ4780_NEMC
        help
          Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
          based boards, using the BCH controller for hardware error correction.
 
 config MTD_NAND_FSMC
        tristate "Support for NAND on ST Micros FSMC"
-       depends on OF
-       depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
+       depends on OF && HAS_IOMEM
+       depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300 || \
+                  COMPILE_TEST
        help
          Enables support for NAND Flash chips on the ST Microelectronics
          Flexible Static Memory Controller (FSMC)
@@ -506,19 +522,22 @@ config MTD_NAND_XWAY
 
 config MTD_NAND_SUNXI
        tristate "Support for NAND on Allwinner SoCs"
-       depends on ARCH_SUNXI
+       depends on ARCH_SUNXI || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enables support for NAND Flash chips on Allwinner SoCs.
 
 config MTD_NAND_HISI504
        tristate "Support for NAND controller on Hisilicon SoC Hip04"
        depends on ARCH_HISI || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enables support for NAND controller on Hisilicon SoC Hip04.
 
 config MTD_NAND_QCOM
        tristate "Support for NAND on QCOM SoCs"
-       depends on ARCH_QCOM
+       depends on ARCH_QCOM || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enables support for NAND flash chips on SoCs containing the EBI2 NAND
          controller. This controller is found on IPQ806x SoC.
@@ -526,8 +545,20 @@ config MTD_NAND_QCOM
 config MTD_NAND_MTK
        tristate "Support for NAND controller on MTK SoCs"
        depends on ARCH_MEDIATEK || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enables support for NAND controller on MTK SoCs.
          This controller is found on mt27xx, mt81xx, mt65xx SoCs.
 
+config MTD_NAND_TEGRA
+       tristate "Support for NAND controller on NVIDIA Tegra"
+       depends on ARCH_TEGRA || COMPILE_TEST
+       depends on HAS_IOMEM
+       help
+         Enables support for NAND flash controller on NVIDIA Tegra SoC.
+         The driver has been developed and tested on a Tegra 2 SoC. DMA
+         support, raw read/write page as well as HW ECC read/write page
+         is supported. Extra OOB bytes when using HW ECC are currently
+         not supported.
+
 endif # MTD_NAND
index 165b7ef9e9a188cc251097fa7530b5347d10ab3c..d5a5f9832b8879e4cbf16f5dd7f902edcf52c239 100644 (file)
@@ -56,6 +56,7 @@ obj-$(CONFIG_MTD_NAND_HISI504)                += hisi504_nand.o
 obj-$(CONFIG_MTD_NAND_BRCMNAND)                += brcmnand/
 obj-$(CONFIG_MTD_NAND_QCOM)            += qcom_nandc.o
 obj-$(CONFIG_MTD_NAND_MTK)             += mtk_ecc.o mtk_nand.o
+obj-$(CONFIG_MTD_NAND_TEGRA)           += tegra_nand.o
 
 nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
 nand-objs += nand_amd.o
index 12f6753d47ae59c70216721a7638a2a8ceb84770..a068b214ebaa7970fac10d1b0ae4b2af0602e9ae 100644 (file)
@@ -52,7 +52,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/genalloc.h>
-#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/syscon.h>
 #define DEFAULT_TIMEOUT_MS                     1000
 #define MIN_DMA_LEN                            128
 
+static bool atmel_nand_avoid_dma __read_mostly;
+
+MODULE_PARM_DESC(avoiddma, "Avoid using DMA");
+module_param_named(avoiddma, atmel_nand_avoid_dma, bool, 0400);
+
 enum atmel_nand_rb_type {
        ATMEL_NAND_NO_RB,
        ATMEL_NAND_NATIVE_RB,
@@ -197,7 +201,7 @@ struct atmel_nand_controller_ops {
        int (*remove)(struct atmel_nand_controller *nc);
        void (*nand_init)(struct atmel_nand_controller *nc,
                          struct atmel_nand *nand);
-       int (*ecc_init)(struct atmel_nand *nand);
+       int (*ecc_init)(struct nand_chip *chip);
        int (*setup_data_interface)(struct atmel_nand *nand, int csline,
                                    const struct nand_data_interface *conf);
 };
@@ -211,7 +215,7 @@ struct atmel_nand_controller_caps {
 };
 
 struct atmel_nand_controller {
-       struct nand_hw_control base;
+       struct nand_controller base;
        const struct atmel_nand_controller_caps *caps;
        struct device *dev;
        struct regmap *smc;
@@ -222,7 +226,7 @@ struct atmel_nand_controller {
 };
 
 static inline struct atmel_nand_controller *
-to_nand_controller(struct nand_hw_control *ctl)
+to_nand_controller(struct nand_controller *ctl)
 {
        return container_of(ctl, struct atmel_nand_controller, base);
 }
@@ -234,7 +238,7 @@ struct atmel_smc_nand_controller {
 };
 
 static inline struct atmel_smc_nand_controller *
-to_smc_nand_controller(struct nand_hw_control *ctl)
+to_smc_nand_controller(struct nand_controller *ctl)
 {
        return container_of(to_nand_controller(ctl),
                            struct atmel_smc_nand_controller, base);
@@ -258,7 +262,7 @@ struct atmel_hsmc_nand_controller {
 };
 
 static inline struct atmel_hsmc_nand_controller *
-to_hsmc_nand_controller(struct nand_hw_control *ctl)
+to_hsmc_nand_controller(struct nand_controller *ctl)
 {
        return container_of(to_nand_controller(ctl),
                            struct atmel_hsmc_nand_controller, base);
@@ -1128,9 +1132,8 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
        return 0;
 }
 
-static int atmel_nand_ecc_init(struct atmel_nand *nand)
+static int atmel_nand_ecc_init(struct nand_chip *chip)
 {
-       struct nand_chip *chip = &nand->base;
        struct atmel_nand_controller *nc;
        int ret;
 
@@ -1165,12 +1168,11 @@ static int atmel_nand_ecc_init(struct atmel_nand *nand)
        return 0;
 }
 
-static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
+static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip)
 {
-       struct nand_chip *chip = &nand->base;
        int ret;
 
-       ret = atmel_nand_ecc_init(nand);
+       ret = atmel_nand_ecc_init(chip);
        if (ret)
                return ret;
 
@@ -1553,23 +1555,7 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
        chip->select_chip = atmel_hsmc_nand_select_chip;
 }
 
-static int atmel_nand_detect(struct atmel_nand *nand)
-{
-       struct nand_chip *chip = &nand->base;
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct atmel_nand_controller *nc;
-       int ret;
-
-       nc = to_nand_controller(chip->controller);
-
-       ret = nand_scan_ident(mtd, nand->numcs, NULL);
-       if (ret)
-               dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
-
-       return ret;
-}
-
-static int atmel_nand_unregister(struct atmel_nand *nand)
+static int atmel_nand_controller_remove_nand(struct atmel_nand *nand)
 {
        struct nand_chip *chip = &nand->base;
        struct mtd_info *mtd = nand_to_mtd(chip);
@@ -1585,60 +1571,6 @@ static int atmel_nand_unregister(struct atmel_nand *nand)
        return 0;
 }
 
-static int atmel_nand_register(struct atmel_nand *nand)
-{
-       struct nand_chip *chip = &nand->base;
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct atmel_nand_controller *nc;
-       int ret;
-
-       nc = to_nand_controller(chip->controller);
-
-       if (nc->caps->legacy_of_bindings || !nc->dev->of_node) {
-               /*
-                * We keep the MTD name unchanged to avoid breaking platforms
-                * where the MTD cmdline parser is used and the bootloader
-                * has not been updated to use the new naming scheme.
-                */
-               mtd->name = "atmel_nand";
-       } else if (!mtd->name) {
-               /*
-                * If the new bindings are used and the bootloader has not been
-                * updated to pass a new mtdparts parameter on the cmdline, you
-                * should define the following property in your nand node:
-                *
-                *      label = "atmel_nand";
-                *
-                * This way, mtd->name will be set by the core when
-                * nand_set_flash_node() is called.
-                */
-               mtd->name = devm_kasprintf(nc->dev, GFP_KERNEL,
-                                          "%s:nand.%d", dev_name(nc->dev),
-                                          nand->cs[0].id);
-               if (!mtd->name) {
-                       dev_err(nc->dev, "Failed to allocate mtd->name\n");
-                       return -ENOMEM;
-               }
-       }
-
-       ret = nand_scan_tail(mtd);
-       if (ret) {
-               dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
-               return ret;
-       }
-
-       ret = mtd_device_register(mtd, NULL, 0);
-       if (ret) {
-               dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
-               nand_cleanup(chip);
-               return ret;
-       }
-
-       list_add_tail(&nand->node, &nc->chips);
-
-       return 0;
-}
-
 static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
                                            struct device_node *np,
                                            int reg_cells)
@@ -1750,6 +1682,8 @@ static int
 atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
                               struct atmel_nand *nand)
 {
+       struct nand_chip *chip = &nand->base;
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
        /* No card inserted, skip this NAND. */
@@ -1760,15 +1694,22 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
 
        nc->caps->ops->nand_init(nc, nand);
 
-       ret = atmel_nand_detect(nand);
-       if (ret)
+       ret = nand_scan(mtd, nand->numcs);
+       if (ret) {
+               dev_err(nc->dev, "NAND scan failed: %d\n", ret);
                return ret;
+       }
 
-       ret = nc->caps->ops->ecc_init(nand);
-       if (ret)
+       ret = mtd_device_register(mtd, NULL, 0);
+       if (ret) {
+               dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
+               nand_cleanup(chip);
                return ret;
+       }
+
+       list_add_tail(&nand->node, &nc->chips);
 
-       return atmel_nand_register(nand);
+       return 0;
 }
 
 static int
@@ -1778,7 +1719,7 @@ atmel_nand_controller_remove_nands(struct atmel_nand_controller *nc)
        int ret;
 
        list_for_each_entry_safe(nand, tmp, &nc->chips, node) {
-               ret = atmel_nand_unregister(nand);
+               ret = atmel_nand_controller_remove_nand(nand);
                if (ret)
                        return ret;
        }
@@ -1953,6 +1894,51 @@ static const struct of_device_id atmel_matrix_of_ids[] = {
        { /* sentinel */ },
 };
 
+static int atmel_nand_attach_chip(struct nand_chip *chip)
+{
+       struct atmel_nand_controller *nc = to_nand_controller(chip->controller);
+       struct atmel_nand *nand = to_atmel_nand(chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int ret;
+
+       ret = nc->caps->ops->ecc_init(chip);
+       if (ret)
+               return ret;
+
+       if (nc->caps->legacy_of_bindings || !nc->dev->of_node) {
+               /*
+                * We keep the MTD name unchanged to avoid breaking platforms
+                * where the MTD cmdline parser is used and the bootloader
+                * has not been updated to use the new naming scheme.
+                */
+               mtd->name = "atmel_nand";
+       } else if (!mtd->name) {
+               /*
+                * If the new bindings are used and the bootloader has not been
+                * updated to pass a new mtdparts parameter on the cmdline, you
+                * should define the following property in your nand node:
+                *
+                *      label = "atmel_nand";
+                *
+                * This way, mtd->name will be set by the core when
+                * nand_set_flash_node() is called.
+                */
+               mtd->name = devm_kasprintf(nc->dev, GFP_KERNEL,
+                                          "%s:nand.%d", dev_name(nc->dev),
+                                          nand->cs[0].id);
+               if (!mtd->name) {
+                       dev_err(nc->dev, "Failed to allocate mtd->name\n");
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static const struct nand_controller_ops atmel_nand_controller_ops = {
+       .attach_chip = atmel_nand_attach_chip,
+};
+
 static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
                                struct platform_device *pdev,
                                const struct atmel_nand_controller_caps *caps)
@@ -1961,7 +1947,8 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
        struct device_node *np = dev->of_node;
        int ret;
 
-       nand_hw_control_init(&nc->base);
+       nand_controller_init(&nc->base);
+       nc->base.ops = &atmel_nand_controller_ops;
        INIT_LIST_HEAD(&nc->chips);
        nc->dev = dev;
        nc->caps = caps;
@@ -1977,7 +1964,7 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
                return ret;
        }
 
-       if (nc->caps->has_dma) {
+       if (nc->caps->has_dma && !atmel_nand_avoid_dma) {
                dma_cap_mask_t mask;
 
                dma_cap_zero(mask);
@@ -2045,7 +2032,7 @@ atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc)
                return ret;
        }
 
-       nc->ebi_csa_offs = (unsigned int)match->data;
+       nc->ebi_csa_offs = (uintptr_t)match->data;
 
        /*
         * The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1
@@ -2214,9 +2201,9 @@ atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc)
                return -ENOMEM;
        }
 
-       nc->sram.virt = gen_pool_dma_alloc(nc->sram.pool,
-                                           ATMEL_NFC_SRAM_SIZE,
-                                           &nc->sram.dma);
+       nc->sram.virt = (void __iomem *)gen_pool_dma_alloc(nc->sram.pool,
+                                                          ATMEL_NFC_SRAM_SIZE,
+                                                          &nc->sram.dma);
        if (!nc->sram.virt) {
                dev_err(nc->base.dev,
                        "Could not allocate memory from the NFC SRAM pool\n");
index df0ef1f1e2f5f779ec7042e7400033f1fc07b2f8..35f5c84cd33162e4a290ce96795c4dc4a8d40d11 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/slab.h>
-#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
index 1306aaa7a8bfc4e463e226df053897ef107223cb..4b90d5b380c2503fc88426890f719bd018d6d2f7 100644 (file)
@@ -114,7 +114,7 @@ enum {
 
 struct brcmnand_controller {
        struct device           *dev;
-       struct nand_hw_control  controller;
+       struct nand_controller  controller;
        void __iomem            *nand_base;
        void __iomem            *nand_fc; /* flash cache */
        void __iomem            *flash_dma_base;
@@ -2208,6 +2208,40 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
        return 0;
 }
 
+static int brcmnand_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct brcmnand_host *host = nand_get_controller_data(chip);
+       int ret;
+
+       chip->options |= NAND_NO_SUBPAGE_WRITE;
+       /*
+        * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
+        * to/from, and have nand_base pass us a bounce buffer instead, as
+        * needed.
+        */
+       chip->options |= NAND_USE_BOUNCE_BUFFER;
+
+       if (chip->bbt_options & NAND_BBT_USE_FLASH)
+               chip->bbt_options |= NAND_BBT_NO_OOB;
+
+       if (brcmnand_setup_dev(host))
+               return -ENXIO;
+
+       chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
+
+       /* only use our internal HW threshold */
+       mtd->bitflip_threshold = 1;
+
+       ret = brcmstb_choose_ecc_layout(host);
+
+       return ret;
+}
+
+static const struct nand_controller_ops brcmnand_controller_ops = {
+       .attach_chip = brcmnand_attach_chip,
+};
+
 static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
 {
        struct brcmnand_controller *ctrl = host->ctrl;
@@ -2267,33 +2301,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
        nand_writereg(ctrl, cfg_offs,
                      nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
 
-       ret = nand_scan_ident(mtd, 1, NULL);
-       if (ret)
-               return ret;
-
-       chip->options |= NAND_NO_SUBPAGE_WRITE;
-       /*
-        * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
-        * to/from, and have nand_base pass us a bounce buffer instead, as
-        * needed.
-        */
-       chip->options |= NAND_USE_BOUNCE_BUFFER;
-
-       if (chip->bbt_options & NAND_BBT_USE_FLASH)
-               chip->bbt_options |= NAND_BBT_NO_OOB;
-
-       if (brcmnand_setup_dev(host))
-               return -ENXIO;
-
-       chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
-       /* only use our internal HW threshold */
-       mtd->bitflip_threshold = 1;
-
-       ret = brcmstb_choose_ecc_layout(host);
-       if (ret)
-               return ret;
-
-       ret = nand_scan_tail(mtd);
+       ret = nand_scan(mtd, 1);
        if (ret)
                return ret;
 
@@ -2433,7 +2441,8 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
 
        init_completion(&ctrl->done);
        init_completion(&ctrl->dma_done);
-       nand_hw_control_init(&ctrl->controller);
+       nand_controller_init(&ctrl->controller);
+       ctrl->controller.ops = &brcmnand_controller_ops;
        INIT_LIST_HEAD(&ctrl->host_list);
 
        /* NAND register range */
index d721f489b38bcd07a9141782c5942e93d99e727f..1dbe43adcfe7d550aabb31885a0f366e21cc6b1a 100644 (file)
@@ -67,6 +67,7 @@ struct cafe_priv {
        int nr_data;
        int data_pos;
        int page_addr;
+       bool usedma;
        dma_addr_t dmaaddr;
        unsigned char *dmabuf;
 };
@@ -121,7 +122,7 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
        struct nand_chip *chip = mtd_to_nand(mtd);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
 
-       if (usedma)
+       if (cafe->usedma)
                memcpy(cafe->dmabuf + cafe->datalen, buf, len);
        else
                memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
@@ -137,7 +138,7 @@ static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
        struct nand_chip *chip = mtd_to_nand(mtd);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
 
-       if (usedma)
+       if (cafe->usedma)
                memcpy(buf, cafe->dmabuf + cafe->datalen, len);
        else
                memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len);
@@ -253,7 +254,7 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
        /* NB: The datasheet lies -- we really should be subtracting 1 here */
        cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN);
        cafe_writel(cafe, 0x90000000, NAND_IRQ);
-       if (usedma && (ctl1 & (3<<25))) {
+       if (cafe->usedma && (ctl1 & (3<<25))) {
                uint32_t dmactl = 0xc0000000 + cafe->datalen;
                /* If WR or RD bits set, set up DMA */
                if (ctl1 & (1<<26)) {
@@ -345,11 +346,6 @@ static irqreturn_t cafe_nand_interrupt(int irq, void *id)
        return IRQ_HANDLED;
 }
 
-static void cafe_nand_bug(struct mtd_info *mtd)
-{
-       BUG();
-}
-
 static int cafe_nand_write_oob(struct mtd_info *mtd,
                               struct nand_chip *chip, int page)
 {
@@ -598,6 +594,76 @@ static int cafe_mul(int x)
        return gf4096_mul(x, 0xe01);
 }
 
+static int cafe_nand_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct cafe_priv *cafe = nand_get_controller_data(chip);
+       int err = 0;
+
+       cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
+                                         &cafe->dmaaddr, GFP_KERNEL);
+       if (!cafe->dmabuf)
+               return -ENOMEM;
+
+       /* Set up DMA address */
+       cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
+       cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
+
+       cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
+                    cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
+
+       /* Restore the DMA flag */
+       cafe->usedma = usedma;
+
+       cafe->ctl2 = BIT(27); /* Reed-Solomon ECC */
+       if (mtd->writesize == 2048)
+               cafe->ctl2 |= BIT(29); /* 2KiB page size */
+
+       /* Set up ECC according to the type of chip we found */
+       mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
+       if (mtd->writesize == 2048) {
+               cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
+               cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
+       } else if (mtd->writesize == 512) {
+               cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
+               cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
+       } else {
+               dev_warn(&cafe->pdev->dev,
+                        "Unexpected NAND flash writesize %d. Aborting\n",
+                        mtd->writesize);
+               err = -ENOTSUPP;
+               goto out_free_dma;
+       }
+
+       cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+       cafe->nand.ecc.size = mtd->writesize;
+       cafe->nand.ecc.bytes = 14;
+       cafe->nand.ecc.strength = 4;
+       cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
+       cafe->nand.ecc.write_oob = cafe_nand_write_oob;
+       cafe->nand.ecc.read_page = cafe_nand_read_page;
+       cafe->nand.ecc.read_oob = cafe_nand_read_oob;
+
+       return 0;
+
+ out_free_dma:
+       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+
+       return err;
+}
+
+static void cafe_nand_detach_chip(struct nand_chip *chip)
+{
+       struct cafe_priv *cafe = nand_get_controller_data(chip);
+
+       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+}
+
+static const struct nand_controller_ops cafe_nand_controller_ops = {
+       .attach_chip = cafe_nand_attach_chip,
+       .detach_chip = cafe_nand_detach_chip,
+};
+
 static int cafe_nand_probe(struct pci_dev *pdev,
                                     const struct pci_device_id *ent)
 {
@@ -605,7 +671,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        struct cafe_priv *cafe;
        uint32_t ctrl;
        int err = 0;
-       int old_dma;
 
        /* Very old versions shared the same PCI ident for all three
           functions on the chip. Verify the class too... */
@@ -713,65 +778,15 @@ static int cafe_nand_probe(struct pci_dev *pdev,
                cafe_readl(cafe, GLOBAL_CTRL),
                cafe_readl(cafe, GLOBAL_IRQ_MASK));
 
-       /* Do not use the DMA for the nand_scan_ident() */
-       old_dma = usedma;
-       usedma = 0;
+       /* Do not use the DMA during the NAND identification */
+       cafe->usedma = 0;
 
        /* Scan to find existence of the device */
-       err = nand_scan_ident(mtd, 2, NULL);
+       cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops;
+       err = nand_scan(mtd, 2);
        if (err)
                goto out_irq;
 
-       cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
-                                         &cafe->dmaaddr, GFP_KERNEL);
-       if (!cafe->dmabuf) {
-               err = -ENOMEM;
-               goto out_irq;
-       }
-
-       /* Set up DMA address */
-       cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
-       cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
-
-       cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
-               cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
-
-       /* Restore the DMA flag */
-       usedma = old_dma;
-
-       cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
-       if (mtd->writesize == 2048)
-               cafe->ctl2 |= 1<<29; /* 2KiB page size */
-
-       /* Set up ECC according to the type of chip we found */
-       mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
-       if (mtd->writesize == 2048) {
-               cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
-               cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
-       } else if (mtd->writesize == 512) {
-               cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
-               cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
-       } else {
-               pr_warn("Unexpected NAND flash writesize %d. Aborting\n",
-                       mtd->writesize);
-               goto out_free_dma;
-       }
-       cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
-       cafe->nand.ecc.size = mtd->writesize;
-       cafe->nand.ecc.bytes = 14;
-       cafe->nand.ecc.strength = 4;
-       cafe->nand.ecc.hwctl  = (void *)cafe_nand_bug;
-       cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
-       cafe->nand.ecc.correct  = (void *)cafe_nand_bug;
-       cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
-       cafe->nand.ecc.write_oob = cafe_nand_write_oob;
-       cafe->nand.ecc.read_page = cafe_nand_read_page;
-       cafe->nand.ecc.read_oob = cafe_nand_read_oob;
-
-       err = nand_scan_tail(mtd);
-       if (err)
-               goto out_free_dma;
-
        pci_set_drvdata(pdev, mtd);
 
        mtd->name = "cafe_nand";
@@ -783,8 +798,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 
  out_cleanup_nand:
        nand_cleanup(&cafe->nand);
- out_free_dma:
-       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
  out_irq:
        /* Disable NAND IRQ in global IRQ mask register */
        cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
index 02d6751e9efea6ea8cfcf650a6e2c748b87a43a0..b66e254b680281b4b951866ad9492473f8544f3d 100644 (file)
@@ -200,8 +200,8 @@ static int __init cmx270_init(void)
        }
 
        /* Register the partitions */
-       ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL,
-                                       partition_info, NUM_PARTITIONS);
+       ret = mtd_device_register(cmx270_nand_mtd, partition_info,
+                                 NUM_PARTITIONS);
        if (ret)
                goto err_scan;
 
index 82269fde9e6623b0a4433083cfd1d4a7fcd5cc67..beafad62e7d5007f4a2313cf1dd469b0fabf88f1 100644 (file)
@@ -310,8 +310,7 @@ static int __init cs553x_init(void)
        for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
                if (cs553x_mtd[i]) {
                        /* If any devices registered, return success. Else the last error. */
-                       mtd_device_parse_register(cs553x_mtd[i], NULL, NULL,
-                                                 NULL, 0);
+                       mtd_device_register(cs553x_mtd[i], NULL, 0);
                        err = 0;
                }
        }
index cd12e5abafdefb7641d8b7f2238f2e4f41d92308..40145e206a6b7a1d6c82de067c1e55069dd9a9d5 100644 (file)
 struct davinci_nand_info {
        struct nand_chip        chip;
 
-       struct device           *dev;
+       struct platform_device  *pdev;
 
        bool                    is_readmode;
 
        void __iomem            *base;
        void __iomem            *vaddr;
 
-       uint32_t                ioaddr;
-       uint32_t                current_cs;
+       void __iomem            *current_cs;
 
        uint32_t                mask_chipsel;
        uint32_t                mask_ale;
@@ -102,17 +101,17 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
                                   unsigned int ctrl)
 {
        struct davinci_nand_info        *info = to_davinci_nand(mtd);
-       uint32_t                        addr = info->current_cs;
+       void __iomem                    *addr = info->current_cs;
        struct nand_chip                *nand = mtd_to_nand(mtd);
 
        /* Did the control lines change? */
        if (ctrl & NAND_CTRL_CHANGE) {
                if ((ctrl & NAND_CTRL_CLE) == NAND_CTRL_CLE)
-                       addr |= info->mask_cle;
+                       addr += info->mask_cle;
                else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
-                       addr |= info->mask_ale;
+                       addr += info->mask_ale;
 
-               nand->IO_ADDR_W = (void __iomem __force *)addr;
+               nand->IO_ADDR_W = addr;
        }
 
        if (cmd != NAND_CMD_NONE)
@@ -122,14 +121,14 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
 static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
 {
        struct davinci_nand_info        *info = to_davinci_nand(mtd);
-       uint32_t                        addr = info->ioaddr;
+
+       info->current_cs = info->vaddr;
 
        /* maybe kick in a second chipselect */
        if (chip > 0)
-               addr |= info->mask_chipsel;
-       info->current_cs = addr;
+               info->current_cs += info->mask_chipsel;
 
-       info->chip.IO_ADDR_W = (void __iomem __force *)addr;
+       info->chip.IO_ADDR_W = info->current_cs;
        info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
 }
 
@@ -319,7 +318,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
        /* Unpack ten bytes into eight 10 bit values.  We know we're
         * little-endian, and use type punning for less shifting/masking.
         */
-       if (WARN_ON(0x01 & (unsigned) ecc_code))
+       if (WARN_ON(0x01 & (uintptr_t)ecc_code))
                return -EINVAL;
        ecc16 = (unsigned short *)ecc_code;
 
@@ -441,9 +440,9 @@ static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
 
-       if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
+       if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
                ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
-       else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
+       else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
                ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
        else
                ioread8_rep(chip->IO_ADDR_R, buf, len);
@@ -454,9 +453,9 @@ static void nand_davinci_write_buf(struct mtd_info *mtd,
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
 
-       if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
+       if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
                iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
-       else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
+       else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
                iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
        else
                iowrite8_rep(chip->IO_ADDR_R, buf, len);
@@ -606,6 +605,104 @@ static struct davinci_nand_pdata
 }
 #endif
 
+static int davinci_nand_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct davinci_nand_info *info = to_davinci_nand(mtd);
+       struct davinci_nand_pdata *pdata = nand_davinci_get_pdata(info->pdev);
+       int ret = 0;
+
+       if (IS_ERR(pdata))
+               return PTR_ERR(pdata);
+
+       switch (info->chip.ecc.mode) {
+       case NAND_ECC_NONE:
+               pdata->ecc_bits = 0;
+               break;
+       case NAND_ECC_SOFT:
+               pdata->ecc_bits = 0;
+               /*
+                * This driver expects Hamming based ECC when ecc_mode is set
+                * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
+                * avoid adding an extra ->ecc_algo field to
+                * davinci_nand_pdata.
+                */
+               info->chip.ecc.algo = NAND_ECC_HAMMING;
+               break;
+       case NAND_ECC_HW:
+               if (pdata->ecc_bits == 4) {
+                       /*
+                        * No sanity checks:  CPUs must support this,
+                        * and the chips may not use NAND_BUSWIDTH_16.
+                        */
+
+                       /* No sharing 4-bit hardware between chipselects yet */
+                       spin_lock_irq(&davinci_nand_lock);
+                       if (ecc4_busy)
+                               ret = -EBUSY;
+                       else
+                               ecc4_busy = true;
+                       spin_unlock_irq(&davinci_nand_lock);
+
+                       if (ret == -EBUSY)
+                               return ret;
+
+                       info->chip.ecc.calculate = nand_davinci_calculate_4bit;
+                       info->chip.ecc.correct = nand_davinci_correct_4bit;
+                       info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
+                       info->chip.ecc.bytes = 10;
+                       info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
+                       info->chip.ecc.algo = NAND_ECC_BCH;
+               } else {
+                       /* 1bit ecc hamming */
+                       info->chip.ecc.calculate = nand_davinci_calculate_1bit;
+                       info->chip.ecc.correct = nand_davinci_correct_1bit;
+                       info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
+                       info->chip.ecc.bytes = 3;
+                       info->chip.ecc.algo = NAND_ECC_HAMMING;
+               }
+               info->chip.ecc.size = 512;
+               info->chip.ecc.strength = pdata->ecc_bits;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * Update ECC layout if needed ... for 1-bit HW ECC, the default
+        * is OK, but it allocates 6 bytes when only 3 are needed (for
+        * each 512 bytes).  For the 4-bit HW ECC, that default is not
+        * usable:  10 bytes are needed, not 6.
+        */
+       if (pdata->ecc_bits == 4) {
+               int chunks = mtd->writesize / 512;
+
+               if (!chunks || mtd->oobsize < 16) {
+                       dev_dbg(&info->pdev->dev, "too small\n");
+                       return -EINVAL;
+               }
+
+               /* For small page chips, preserve the manufacturer's
+                * badblock marking data ... and make sure a flash BBT
+                * table marker fits in the free bytes.
+                */
+               if (chunks == 1) {
+                       mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
+               } else if (chunks == 4 || chunks == 8) {
+                       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+                       info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
+               } else {
+                       return -EIO;
+               }
+       }
+
+       return ret;
+}
+
+static const struct nand_controller_ops davinci_nand_controller_ops = {
+       .attach_chip = davinci_nand_attach_chip,
+};
+
 static int nand_davinci_probe(struct platform_device *pdev)
 {
        struct davinci_nand_pdata       *pdata;
@@ -659,7 +756,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
                return -EADDRNOTAVAIL;
        }
 
-       info->dev               = &pdev->dev;
+       info->pdev              = pdev;
        info->base              = base;
        info->vaddr             = vaddr;
 
@@ -680,9 +777,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
        info->chip.bbt_md       = pdata->bbt_md;
        info->timing            = pdata->timing;
 
-       info->ioaddr            = (uint32_t __force) vaddr;
-
-       info->current_cs        = info->ioaddr;
+       info->current_cs        = info->vaddr;
        info->core_chipsel      = pdata->core_chipsel;
        info->mask_chipsel      = pdata->mask_chipsel;
 
@@ -711,100 +806,15 @@ static int nand_davinci_probe(struct platform_device *pdev)
        spin_unlock_irq(&davinci_nand_lock);
 
        /* Scan to find existence of the device(s) */
-       ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
+       info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
+       ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1);
        if (ret < 0) {
                dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
                return ret;
        }
 
-       switch (info->chip.ecc.mode) {
-       case NAND_ECC_NONE:
-               pdata->ecc_bits = 0;
-               break;
-       case NAND_ECC_SOFT:
-               pdata->ecc_bits = 0;
-               /*
-                * This driver expects Hamming based ECC when ecc_mode is set
-                * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
-                * avoid adding an extra ->ecc_algo field to
-                * davinci_nand_pdata.
-                */
-               info->chip.ecc.algo = NAND_ECC_HAMMING;
-               break;
-       case NAND_ECC_HW:
-               if (pdata->ecc_bits == 4) {
-                       /* No sanity checks:  CPUs must support this,
-                        * and the chips may not use NAND_BUSWIDTH_16.
-                        */
-
-                       /* No sharing 4-bit hardware between chipselects yet */
-                       spin_lock_irq(&davinci_nand_lock);
-                       if (ecc4_busy)
-                               ret = -EBUSY;
-                       else
-                               ecc4_busy = true;
-                       spin_unlock_irq(&davinci_nand_lock);
-
-                       if (ret == -EBUSY)
-                               return ret;
-
-                       info->chip.ecc.calculate = nand_davinci_calculate_4bit;
-                       info->chip.ecc.correct = nand_davinci_correct_4bit;
-                       info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
-                       info->chip.ecc.bytes = 10;
-                       info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
-                       info->chip.ecc.algo = NAND_ECC_BCH;
-               } else {
-                       /* 1bit ecc hamming */
-                       info->chip.ecc.calculate = nand_davinci_calculate_1bit;
-                       info->chip.ecc.correct = nand_davinci_correct_1bit;
-                       info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
-                       info->chip.ecc.bytes = 3;
-                       info->chip.ecc.algo = NAND_ECC_HAMMING;
-               }
-               info->chip.ecc.size = 512;
-               info->chip.ecc.strength = pdata->ecc_bits;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* Update ECC layout if needed ... for 1-bit HW ECC, the default
-        * is OK, but it allocates 6 bytes when only 3 are needed (for
-        * each 512 bytes).  For the 4-bit HW ECC, that default is not
-        * usable:  10 bytes are needed, not 6.
-        */
-       if (pdata->ecc_bits == 4) {
-               int     chunks = mtd->writesize / 512;
-
-               if (!chunks || mtd->oobsize < 16) {
-                       dev_dbg(&pdev->dev, "too small\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               /* For small page chips, preserve the manufacturer's
-                * badblock marking data ... and make sure a flash BBT
-                * table marker fits in the free bytes.
-                */
-               if (chunks == 1) {
-                       mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
-               } else if (chunks == 4 || chunks == 8) {
-                       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
-                       info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
-               } else {
-                       ret = -EIO;
-                       goto err;
-               }
-       }
-
-       ret = nand_scan_tail(mtd);
-       if (ret < 0)
-               goto err;
-
        if (pdata->parts)
-               ret = mtd_device_parse_register(mtd, NULL, NULL,
-                                       pdata->parts, pdata->nr_parts);
+               ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
        else
                ret = mtd_device_register(mtd, NULL, 0);
        if (ret < 0)
@@ -819,11 +829,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
 err_cleanup_nand:
        nand_cleanup(&info->chip);
 
-err:
-       spin_lock_irq(&davinci_nand_lock);
-       if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
-               ecc4_busy = false;
-       spin_unlock_irq(&davinci_nand_lock);
        return ret;
 }
 
index 2a302a1d1430de0ef0a7e815fae42007f59e8f4d..ca18612c42014288d48c9ac8180a4b5be88e9a06 100644 (file)
@@ -51,14 +51,6 @@ MODULE_LICENSE("GPL");
 #define DENALI_INVALID_BANK    -1
 #define DENALI_NR_BANKS                4
 
-/*
- * The bus interface clock, clk_x, is phase aligned with the core clock.  The
- * clk_x is an integral multiple N of the core clk.  The value N is configured
- * at IP delivery time, and its available value is 4, 5, or 6.  We need to align
- * to the largest value to make it work with any possible configuration.
- */
-#define DENALI_CLK_X_MULT      6
-
 static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
 {
        return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
@@ -954,7 +946,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        const struct nand_sdr_timings *timings;
-       unsigned long t_clk;
+       unsigned long t_x, mult_x;
        int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
        int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
        int addr_2_data_mask;
@@ -965,15 +957,24 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
                return PTR_ERR(timings);
 
        /* clk_x period in picoseconds */
-       t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
-       if (!t_clk)
+       t_x = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
+       if (!t_x)
+               return -EINVAL;
+
+       /*
+        * The bus interface clock, clk_x, is phase aligned with the core clock.
+        * The clk_x is an integral multiple N of the core clk.  The value N is
+        * configured at IP delivery time, and its available value is 4, 5, 6.
+        */
+       mult_x = DIV_ROUND_CLOSEST_ULL(denali->clk_x_rate, denali->clk_rate);
+       if (mult_x < 4 || mult_x > 6)
                return -EINVAL;
 
        if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
                return 0;
 
        /* tREA -> ACC_CLKS */
-       acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
+       acc_clks = DIV_ROUND_UP(timings->tREA_max, t_x);
        acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
 
        tmp = ioread32(denali->reg + ACC_CLKS);
@@ -982,7 +983,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
        iowrite32(tmp, denali->reg + ACC_CLKS);
 
        /* tRWH -> RE_2_WE */
-       re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
+       re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_x);
        re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
 
        tmp = ioread32(denali->reg + RE_2_WE);
@@ -991,7 +992,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
        iowrite32(tmp, denali->reg + RE_2_WE);
 
        /* tRHZ -> RE_2_RE */
-       re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
+       re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_x);
        re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
 
        tmp = ioread32(denali->reg + RE_2_RE);
@@ -1005,8 +1006,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
         * With WE_2_RE properly set, the Denali controller automatically takes
         * care of the delay; the driver need not set NAND_WAIT_TCCS.
         */
-       we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min),
-                              t_clk);
+       we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min), t_x);
        we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
 
        tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
@@ -1021,7 +1021,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
        if (denali->revision < 0x0501)
                addr_2_data_mask >>= 1;
 
-       addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
+       addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_x);
        addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
 
        tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
@@ -1031,7 +1031,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
 
        /* tREH, tWH -> RDWR_EN_HI_CNT */
        rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
-                                 t_clk);
+                                 t_x);
        rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
 
        tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
@@ -1040,11 +1040,10 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
        iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
 
        /* tRP, tWP -> RDWR_EN_LO_CNT */
-       rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
-                                 t_clk);
+       rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), t_x);
        rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
-                                    t_clk);
-       rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
+                                    t_x);
+       rdwr_en_lo_hi = max_t(int, rdwr_en_lo_hi, mult_x);
        rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
        rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
 
@@ -1054,8 +1053,8 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
        iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
 
        /* tCS, tCEA -> CS_SETUP_CNT */
-       cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
-                       (int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
+       cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_x) - rdwr_en_lo,
+                       (int)DIV_ROUND_UP(timings->tCEA_max, t_x) - acc_clks,
                        0);
        cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
 
@@ -1120,33 +1119,6 @@ int denali_calc_ecc_bytes(int step_size, int strength)
 }
 EXPORT_SYMBOL(denali_calc_ecc_bytes);
 
-static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
-                           struct denali_nand_info *denali)
-{
-       int oobavail = mtd->oobsize - denali->oob_skip_bytes;
-       int ret;
-
-       /*
-        * If .size and .strength are already set (usually by DT),
-        * check if they are supported by this controller.
-        */
-       if (chip->ecc.size && chip->ecc.strength)
-               return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
-
-       /*
-        * We want .size and .strength closest to the chip's requirement
-        * unless NAND_ECC_MAXIMIZE is requested.
-        */
-       if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
-               ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
-               if (!ret)
-                       return 0;
-       }
-
-       /* Max ECC strength is the last thing we can do */
-       return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
-}
-
 static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
                                struct mtd_oob_region *oobregion)
 {
@@ -1233,62 +1205,12 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
        return 0;
 }
 
-int denali_init(struct denali_nand_info *denali)
+static int denali_attach_chip(struct nand_chip *chip)
 {
-       struct nand_chip *chip = &denali->nand;
        struct mtd_info *mtd = nand_to_mtd(chip);
-       u32 features = ioread32(denali->reg + FEATURES);
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
        int ret;
 
-       mtd->dev.parent = denali->dev;
-       denali_hw_init(denali);
-
-       init_completion(&denali->complete);
-       spin_lock_init(&denali->irq_lock);
-
-       denali_clear_irq_all(denali);
-
-       ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
-                              IRQF_SHARED, DENALI_NAND_NAME, denali);
-       if (ret) {
-               dev_err(denali->dev, "Unable to request IRQ\n");
-               return ret;
-       }
-
-       denali_enable_irq(denali);
-       denali_reset_banks(denali);
-
-       denali->active_bank = DENALI_INVALID_BANK;
-
-       nand_set_flash_node(chip, denali->dev->of_node);
-       /* Fallback to the default name if DT did not give "label" property */
-       if (!mtd->name)
-               mtd->name = "denali-nand";
-
-       chip->select_chip = denali_select_chip;
-       chip->read_byte = denali_read_byte;
-       chip->write_byte = denali_write_byte;
-       chip->read_word = denali_read_word;
-       chip->cmd_ctrl = denali_cmd_ctrl;
-       chip->dev_ready = denali_dev_ready;
-       chip->waitfunc = denali_waitfunc;
-
-       if (features & FEATURES__INDEX_ADDR) {
-               denali->host_read = denali_indexed_read;
-               denali->host_write = denali_indexed_write;
-       } else {
-               denali->host_read = denali_direct_read;
-               denali->host_write = denali_direct_write;
-       }
-
-       /* clk rate info is needed for setup_data_interface */
-       if (denali->clk_x_rate)
-               chip->setup_data_interface = denali_setup_data_interface;
-
-       ret = nand_scan_ident(mtd, denali->max_banks, NULL);
-       if (ret)
-               goto disable_irq;
-
        if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
                denali->dma_avail = 1;
 
@@ -1317,10 +1239,11 @@ int denali_init(struct denali_nand_info *denali)
        chip->ecc.mode = NAND_ECC_HW_SYNDROME;
        chip->options |= NAND_NO_SUBPAGE_WRITE;
 
-       ret = denali_ecc_setup(mtd, chip, denali);
+       ret = nand_ecc_choose_conf(chip, denali->ecc_caps,
+                                  mtd->oobsize - denali->oob_skip_bytes);
        if (ret) {
                dev_err(denali->dev, "Failed to setup ECC settings.\n");
-               goto disable_irq;
+               return ret;
        }
 
        dev_dbg(denali->dev,
@@ -1364,7 +1287,7 @@ int denali_init(struct denali_nand_info *denali)
 
        ret = denali_multidev_fixup(denali);
        if (ret)
-               goto disable_irq;
+               return ret;
 
        /*
         * This buffer is DMA-mapped by denali_{read,write}_page_raw.  Do not
@@ -1372,26 +1295,92 @@ int denali_init(struct denali_nand_info *denali)
         * guarantee DMA-safe alignment.
         */
        denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
-       if (!denali->buf) {
-               ret = -ENOMEM;
-               goto disable_irq;
+       if (!denali->buf)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void denali_detach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct denali_nand_info *denali = mtd_to_denali(mtd);
+
+       kfree(denali->buf);
+}
+
+static const struct nand_controller_ops denali_controller_ops = {
+       .attach_chip = denali_attach_chip,
+       .detach_chip = denali_detach_chip,
+};
+
+int denali_init(struct denali_nand_info *denali)
+{
+       struct nand_chip *chip = &denali->nand;
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       u32 features = ioread32(denali->reg + FEATURES);
+       int ret;
+
+       mtd->dev.parent = denali->dev;
+       denali_hw_init(denali);
+
+       init_completion(&denali->complete);
+       spin_lock_init(&denali->irq_lock);
+
+       denali_clear_irq_all(denali);
+
+       ret = devm_request_irq(denali->dev, denali->irq, denali_isr,
+                              IRQF_SHARED, DENALI_NAND_NAME, denali);
+       if (ret) {
+               dev_err(denali->dev, "Unable to request IRQ\n");
+               return ret;
        }
 
-       ret = nand_scan_tail(mtd);
+       denali_enable_irq(denali);
+       denali_reset_banks(denali);
+
+       denali->active_bank = DENALI_INVALID_BANK;
+
+       nand_set_flash_node(chip, denali->dev->of_node);
+       /* Fallback to the default name if DT did not give "label" property */
+       if (!mtd->name)
+               mtd->name = "denali-nand";
+
+       chip->select_chip = denali_select_chip;
+       chip->read_byte = denali_read_byte;
+       chip->write_byte = denali_write_byte;
+       chip->read_word = denali_read_word;
+       chip->cmd_ctrl = denali_cmd_ctrl;
+       chip->dev_ready = denali_dev_ready;
+       chip->waitfunc = denali_waitfunc;
+
+       if (features & FEATURES__INDEX_ADDR) {
+               denali->host_read = denali_indexed_read;
+               denali->host_write = denali_indexed_write;
+       } else {
+               denali->host_read = denali_direct_read;
+               denali->host_write = denali_direct_write;
+       }
+
+       /* clk rate info is needed for setup_data_interface */
+       if (denali->clk_rate && denali->clk_x_rate)
+               chip->setup_data_interface = denali_setup_data_interface;
+
+       chip->dummy_controller.ops = &denali_controller_ops;
+       ret = nand_scan(mtd, denali->max_banks);
        if (ret)
-               goto free_buf;
+               goto disable_irq;
 
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
                dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
                goto cleanup_nand;
        }
+
        return 0;
 
 cleanup_nand:
        nand_cleanup(chip);
-free_buf:
-       kfree(denali->buf);
 disable_irq:
        denali_disable_irq(denali);
 
@@ -1404,7 +1393,6 @@ void denali_remove(struct denali_nand_info *denali)
        struct mtd_info *mtd = nand_to_mtd(&denali->nand);
 
        nand_release(mtd);
-       kfree(denali->buf);
        denali_disable_irq(denali);
 }
 EXPORT_SYMBOL(denali_remove);
index 9ad33d2373787db59cfab2c86399c77beedac08c..1f8feaf924ebc66bc1d62f9fea43a6a915547a1e 100644 (file)
 
 struct denali_nand_info {
        struct nand_chip nand;
+       unsigned long clk_rate;         /* core clock rate */
        unsigned long clk_x_rate;       /* bus interface clock rate */
        int active_bank;                /* currently selected bank */
        struct device *dev;
index 5869e90cc14b3c1f367b17a4f58bdb31c1e188ea..0faaad032e5fbfbcbd7fb7c2e8b92d2c67863a4f 100644 (file)
@@ -27,7 +27,9 @@
 
 struct denali_dt {
        struct denali_nand_info denali;
-       struct clk              *clk;
+       struct clk *clk;        /* core clock */
+       struct clk *clk_x;      /* bus interface clock */
+       struct clk *clk_ecc;    /* ECC circuit clock */
 };
 
 struct denali_dt_data {
@@ -79,63 +81,99 @@ MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
 
 static int denali_dt_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct resource *res;
        struct denali_dt *dt;
        const struct denali_dt_data *data;
        struct denali_nand_info *denali;
        int ret;
 
-       dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
+       dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL);
        if (!dt)
                return -ENOMEM;
        denali = &dt->denali;
 
-       data = of_device_get_match_data(&pdev->dev);
+       data = of_device_get_match_data(dev);
        if (data) {
                denali->revision = data->revision;
                denali->caps = data->caps;
                denali->ecc_caps = data->ecc_caps;
        }
 
-       denali->dev = &pdev->dev;
+       denali->dev = dev;
        denali->irq = platform_get_irq(pdev, 0);
        if (denali->irq < 0) {
-               dev_err(&pdev->dev, "no irq defined\n");
+               dev_err(dev, "no irq defined\n");
                return denali->irq;
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
-       denali->reg = devm_ioremap_resource(&pdev->dev, res);
+       denali->reg = devm_ioremap_resource(dev, res);
        if (IS_ERR(denali->reg))
                return PTR_ERR(denali->reg);
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
-       denali->host = devm_ioremap_resource(&pdev->dev, res);
+       denali->host = devm_ioremap_resource(dev, res);
        if (IS_ERR(denali->host))
                return PTR_ERR(denali->host);
 
-       dt->clk = devm_clk_get(&pdev->dev, NULL);
+       /*
+        * A single anonymous clock is supported for the backward compatibility.
+        * New platforms should support all the named clocks.
+        */
+       dt->clk = devm_clk_get(dev, "nand");
+       if (IS_ERR(dt->clk))
+               dt->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(dt->clk)) {
-               dev_err(&pdev->dev, "no clk available\n");
+               dev_err(dev, "no clk available\n");
                return PTR_ERR(dt->clk);
        }
+
+       dt->clk_x = devm_clk_get(dev, "nand_x");
+       if (IS_ERR(dt->clk_x))
+               dt->clk_x = NULL;
+
+       dt->clk_ecc = devm_clk_get(dev, "ecc");
+       if (IS_ERR(dt->clk_ecc))
+               dt->clk_ecc = NULL;
+
        ret = clk_prepare_enable(dt->clk);
        if (ret)
                return ret;
 
-       /*
-        * Hardcode the clock rate for the backward compatibility.
-        * This works for both SOCFPGA and UniPhier.
-        */
-       denali->clk_x_rate = 200000000;
+       ret = clk_prepare_enable(dt->clk_x);
+       if (ret)
+               goto out_disable_clk;
+
+       ret = clk_prepare_enable(dt->clk_ecc);
+       if (ret)
+               goto out_disable_clk_x;
+
+       if (dt->clk_x) {
+               denali->clk_rate = clk_get_rate(dt->clk);
+               denali->clk_x_rate = clk_get_rate(dt->clk_x);
+       } else {
+               /*
+                * Hardcode the clock rates for the backward compatibility.
+                * This works for both SOCFPGA and UniPhier.
+                */
+               dev_notice(dev,
+                          "necessary clock is missing. default clock rates are used.\n");
+               denali->clk_rate = 50000000;
+               denali->clk_x_rate = 200000000;
+       }
 
        ret = denali_init(denali);
        if (ret)
-               goto out_disable_clk;
+               goto out_disable_clk_ecc;
 
        platform_set_drvdata(pdev, dt);
        return 0;
 
+out_disable_clk_ecc:
+       clk_disable_unprepare(dt->clk_ecc);
+out_disable_clk_x:
+       clk_disable_unprepare(dt->clk_x);
 out_disable_clk:
        clk_disable_unprepare(dt->clk);
 
@@ -147,6 +185,8 @@ static int denali_dt_remove(struct platform_device *pdev)
        struct denali_dt *dt = platform_get_drvdata(pdev);
 
        denali_remove(&dt->denali);
+       clk_disable_unprepare(dt->clk_ecc);
+       clk_disable_unprepare(dt->clk_x);
        clk_disable_unprepare(dt->clk);
 
        return 0;
index 49cb3e1f8bd0607044b52431a1504492f2b762f2..7c8efc4c7bdfe1cd0bf5b07493b7e8da46efccee 100644 (file)
@@ -73,6 +73,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        denali->irq = dev->irq;
        denali->ecc_caps = &denali_pci_ecc_caps;
        denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
+       denali->clk_rate = 50000000;            /* 50 MHz */
        denali->clk_x_rate = 200000000;         /* 200 MHz */
 
        ret = pci_request_regions(dev, DENALI_NAND_NAME);
index 8d10061abb4b27d0d30d5d479d7af27ef3e90d31..3c46188dd6d2ba68a9b78bdd140dcdf1070fa800 100644 (file)
@@ -1291,7 +1291,7 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
                this->bbt_md = NULL;
        }
 
-       ret = this->scan_bbt(mtd);
+       ret = nand_create_bbt(this);
        if (ret)
                return ret;
 
@@ -1338,7 +1338,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
                this->bbt_md->pattern = "TBB_SYSM";
        }
 
-       ret = this->scan_bbt(mtd);
+       ret = nand_create_bbt(this);
        if (ret)
                return ret;
 
index 1314aa99b9ab506e73c457b3c8c9b255f80ae9f6..a3f04315c05c54e6332a269603184cac0fc89dd4 100644 (file)
@@ -1227,10 +1227,9 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
         * required within a nand driver because they are performed by the nand
         * infrastructure code as part of nand_scan().  In this case they need
         * to be initialized here because we skip call to nand_scan_ident() (the
-        * first half of nand_scan()).  The call to nand_scan_ident() is skipped
-        * because for this device the chip id is not read in the manner of a
-        * standard nand device.  Unfortunately, nand_scan_ident() does other
-        * things as well, such as call nand_set_defaults().
+        * first half of nand_scan()).  The call to nand_scan_ident() could be
+        * skipped because for this device the chip id is not read in the manner
+        * of a standard nand device.
         */
 
        struct nand_chip *nand = mtd_to_nand(mtd);
@@ -1257,8 +1256,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
        nand->ecc.strength = DOCG4_T;
        nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
        nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
-       nand->controller = &nand->hwcontrol;
-       nand_hw_control_init(nand->controller);
+       nand->controller = &nand->dummy_controller;
+       nand_controller_init(nand->controller);
 
        /* methods */
        nand->cmdfunc = docg4_command;
@@ -1315,6 +1314,40 @@ static int __init read_id_reg(struct mtd_info *mtd)
 
 static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
 
+static int docg4_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
+       int ret;
+
+       init_mtd_structs(mtd);
+
+       /* Initialize kernel BCH algorithm */
+       doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
+       if (!doc->bch)
+               return -EINVAL;
+
+       reset(mtd);
+
+       ret = read_id_reg(mtd);
+       if (ret)
+               free_bch(doc->bch);
+
+       return ret;
+}
+
+static void docg4_detach_chip(struct nand_chip *chip)
+{
+       struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
+
+       free_bch(doc->bch);
+}
+
+static const struct nand_controller_ops docg4_controller_ops = {
+       .attach_chip = docg4_attach_chip,
+       .detach_chip = docg4_detach_chip,
+};
+
 static int __init probe_docg4(struct platform_device *pdev)
 {
        struct mtd_info *mtd;
@@ -1341,7 +1374,7 @@ static int __init probe_docg4(struct platform_device *pdev)
        nand = kzalloc(len, GFP_KERNEL);
        if (nand == NULL) {
                retval = -ENOMEM;
-               goto fail_unmap;
+               goto unmap;
        }
 
        mtd = nand_to_mtd(nand);
@@ -1350,46 +1383,35 @@ static int __init probe_docg4(struct platform_device *pdev)
        mtd->dev.parent = &pdev->dev;
        doc->virtadr = virtadr;
        doc->dev = dev;
-
-       init_mtd_structs(mtd);
-
-       /* initialize kernel bch algorithm */
-       doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
-       if (doc->bch == NULL) {
-               retval = -EINVAL;
-               goto fail;
-       }
-
        platform_set_drvdata(pdev, doc);
 
-       reset(mtd);
-       retval = read_id_reg(mtd);
-       if (retval == -ENODEV) {
-               dev_warn(dev, "No diskonchip G4 device found.\n");
-               goto fail;
-       }
-
-       retval = nand_scan_tail(mtd);
+       /*
+        * Running nand_scan() with maxchips == 0 will skip nand_scan_ident(),
+        * which is a specific operation with this driver and done in the
+        * ->attach_chip callback.
+        */
+       nand->dummy_controller.ops = &docg4_controller_ops;
+       retval = nand_scan(mtd, 0);
        if (retval)
-               goto fail;
+               goto free_nand;
 
        retval = read_factory_bbt(mtd);
        if (retval)
-               goto fail;
+               goto cleanup_nand;
 
        retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
        if (retval)
-               goto fail;
+               goto cleanup_nand;
 
        doc->mtd = mtd;
+
        return 0;
 
-fail:
-       nand_release(mtd); /* deletes partitions and mtd devices */
-       free_bch(doc->bch);
+cleanup_nand:
+       nand_cleanup(nand);
+free_nand:
        kfree(nand);
-
-fail_unmap:
+unmap:
        iounmap(virtadr);
 
        return retval;
@@ -1399,7 +1421,6 @@ static int __exit cleanup_docg4(struct platform_device *pdev)
 {
        struct docg4_priv *doc = platform_get_drvdata(pdev);
        nand_release(doc->mtd);
-       free_bch(doc->bch);
        kfree(mtd_to_nand(doc->mtd));
        iounmap(doc->virtadr);
        return 0;
index 51f0b340bc0df3371815fbf644984d9b07b03d1f..55f449b711fd9fc4ad8ff2fc68f35524f37a481a 100644 (file)
@@ -61,7 +61,7 @@ struct fsl_elbc_mtd {
 /* Freescale eLBC FCM controller information */
 
 struct fsl_elbc_fcm_ctrl {
-       struct nand_hw_control controller;
+       struct nand_controller controller;
        struct fsl_elbc_mtd *chips[MAX_BANKS];
 
        u8 __iomem *addr;        /* Address of assigned FCM buffer        */
@@ -637,9 +637,9 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
        return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
 }
 
-static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
+static int fsl_elbc_attach_chip(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
        struct fsl_lbc_ctrl *ctrl = priv->ctrl;
        struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@@ -700,12 +700,16 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
                dev_err(priv->dev,
                        "fsl_elbc_init: page size %d is not supported\n",
                        mtd->writesize);
-               return -1;
+               return -ENOTSUPP;
        }
 
        return 0;
 }
 
+static const struct nand_controller_ops fsl_elbc_controller_ops = {
+       .attach_chip = fsl_elbc_attach_chip,
+};
+
 static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                              uint8_t *buf, int oob_required, int page)
 {
@@ -879,7 +883,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
                }
                elbc_fcm_ctrl->counter++;
 
-               nand_hw_control_init(&elbc_fcm_ctrl->controller);
+               nand_controller_init(&elbc_fcm_ctrl->controller);
                fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
        } else {
                elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
@@ -910,15 +914,8 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       ret = nand_scan_ident(mtd, 1, NULL);
-       if (ret)
-               goto err;
-
-       ret = fsl_elbc_chip_init_tail(mtd);
-       if (ret)
-               goto err;
-
-       ret = nand_scan_tail(mtd);
+       priv->chip.controller->ops = &fsl_elbc_controller_ops;
+       ret = nand_scan(mtd, 1);
        if (ret)
                goto err;
 
index 382b67e97174a15735f47639a74aaefaa72154fa..24f59d0066afdd77d586f29b944f566e0038d98c 100644 (file)
@@ -51,7 +51,7 @@ struct fsl_ifc_mtd {
 
 /* overview of the fsl ifc controller */
 struct fsl_ifc_nand_ctrl {
-       struct nand_hw_control controller;
+       struct nand_controller controller;
        struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
 
        void __iomem *addr;     /* Address of assigned IFC buffer       */
@@ -225,7 +225,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
                int bufnum = nctrl->page & priv->bufnum_mask;
                int sector_start = bufnum * chip->ecc.steps;
                int sector_end = sector_start + chip->ecc.steps - 1;
-               __be32 *eccstat_regs;
+               __be32 __iomem *eccstat_regs;
 
                eccstat_regs = ifc->ifc_nand.nand_eccstat;
                eccstat = ifc_in32(&eccstat_regs[sector_start / 4]);
@@ -714,9 +714,9 @@ static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        return nand_prog_page_end_op(chip);
 }
 
-static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
+static int fsl_ifc_attach_chip(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
 
        dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
@@ -757,6 +757,10 @@ static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
        return 0;
 }
 
+static const struct nand_controller_ops fsl_ifc_controller_ops = {
+       .attach_chip = fsl_ifc_attach_chip,
+};
+
 static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
 {
        struct fsl_ifc_ctrl *ctrl = priv->ctrl;
@@ -1004,7 +1008,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
                ifc_nand_ctrl->addr = NULL;
                fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
 
-               nand_hw_control_init(&ifc_nand_ctrl->controller);
+               nand_controller_init(&ifc_nand_ctrl->controller);
        } else {
                ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
        }
@@ -1046,15 +1050,8 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
        if (ret)
                goto err;
 
-       ret = nand_scan_ident(mtd, 1, NULL);
-       if (ret)
-               goto err;
-
-       ret = fsl_ifc_chip_init_tail(mtd);
-       if (ret)
-               goto err;
-
-       ret = nand_scan_tail(mtd);
+       priv->chip.controller->ops = &fsl_ifc_controller_ops;
+       ret = nand_scan(mtd, 1);
        if (ret)
                goto err;
 
index f4a5a317d4ae41abced010018817ac2be16b8ed4..f418236fa020adfdbd502efbc494c8ef66f90154 100644 (file)
@@ -62,7 +62,7 @@
                                                reg)
 
 /* fsmc controller registers for NAND flash */
-#define PC                     0x00
+#define FSMC_PC                        0x00
        /* pc register definitions */
        #define FSMC_RESET              (1 << 0)
        #define FSMC_WAITON             (1 << 1)
@@ -273,12 +273,13 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host,
        tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
 
        if (host->nand.options & NAND_BUSWIDTH_16)
-               writel_relaxed(value | FSMC_DEVWID_16, host->regs_va + PC);
+               writel_relaxed(value | FSMC_DEVWID_16,
+                              host->regs_va + FSMC_PC);
        else
-               writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + PC);
+               writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + FSMC_PC);
 
-       writel_relaxed(readl(host->regs_va + PC) | tclr | tar,
-                      host->regs_va + PC);
+       writel_relaxed(readl(host->regs_va + FSMC_PC) | tclr | tar,
+                      host->regs_va + FSMC_PC);
        writel_relaxed(thiz | thold | twait | tset, host->regs_va + COMM);
        writel_relaxed(thiz | thold | twait | tset, host->regs_va + ATTRIB);
 }
@@ -371,12 +372,12 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
 {
        struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
 
-       writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCPLEN_256,
-                      host->regs_va + PC);
-       writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCEN,
-                      host->regs_va + PC);
-       writel_relaxed(readl(host->regs_va + PC) | FSMC_ECCEN,
-                      host->regs_va + PC);
+       writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCPLEN_256,
+                      host->regs_va + FSMC_PC);
+       writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCEN,
+                      host->regs_va + FSMC_PC);
+       writel_relaxed(readl(host->regs_va + FSMC_PC) | FSMC_ECCEN,
+                      host->regs_va + FSMC_PC);
 }
 
 /*
@@ -546,7 +547,7 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
        struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
        int i;
 
-       if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
+       if (IS_ALIGNED((uintptr_t)buf, sizeof(uint32_t)) &&
                        IS_ALIGNED(len, sizeof(uint32_t))) {
                uint32_t *p = (uint32_t *)buf;
                len = len >> 2;
@@ -569,7 +570,7 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
        struct fsmc_nand_data *host  = mtd_to_fsmc(mtd);
        int i;
 
-       if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
+       if (IS_ALIGNED((uintptr_t)buf, sizeof(uint32_t)) &&
                        IS_ALIGNED(len, sizeof(uint32_t))) {
                uint32_t *p = (uint32_t *)buf;
                len = len >> 2;
@@ -618,11 +619,11 @@ static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
        if (chipnr > 0)
                return;
 
-       pc = readl(host->regs_va + PC);
+       pc = readl(host->regs_va + FSMC_PC);
        if (chipnr < 0)
-               writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + PC);
+               writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + FSMC_PC);
        else
-               writel_relaxed(pc | FSMC_ENABLE, host->regs_va + PC);
+               writel_relaxed(pc | FSMC_ENABLE, host->regs_va + FSMC_PC);
 
        /* nCE line must be asserted before starting any operation */
        mb();
@@ -740,7 +741,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
                nand_read_page_op(chip, page, s * eccsize, NULL, 0);
                chip->ecc.hwctl(mtd, NAND_ECC_READ);
-               chip->read_buf(mtd, p, eccsize);
+               nand_read_data_op(chip, p, eccsize, false);
 
                for (j = 0; j < eccbytes;) {
                        struct mtd_oob_region oobregion;
@@ -918,6 +919,82 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
        return 0;
 }
 
+static int fsmc_nand_attach_chip(struct nand_chip *nand)
+{
+       struct mtd_info *mtd = nand_to_mtd(nand);
+       struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+
+       if (AMBA_REV_BITS(host->pid) >= 8) {
+               switch (mtd->oobsize) {
+               case 16:
+               case 64:
+               case 128:
+               case 224:
+               case 256:
+                       break;
+               default:
+                       dev_warn(host->dev,
+                                "No oob scheme defined for oobsize %d\n",
+                                mtd->oobsize);
+                       return -EINVAL;
+               }
+
+               mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
+
+               return 0;
+       }
+
+       switch (nand->ecc.mode) {
+       case NAND_ECC_HW:
+               dev_info(host->dev, "Using 1-bit HW ECC scheme\n");
+               nand->ecc.calculate = fsmc_read_hwecc_ecc1;
+               nand->ecc.correct = nand_correct_data;
+               nand->ecc.bytes = 3;
+               nand->ecc.strength = 1;
+               break;
+
+       case NAND_ECC_SOFT:
+               if (nand->ecc.algo == NAND_ECC_BCH) {
+                       dev_info(host->dev,
+                                "Using 4-bit SW BCH ECC scheme\n");
+                       break;
+               }
+
+       case NAND_ECC_ON_DIE:
+               break;
+
+       default:
+               dev_err(host->dev, "Unsupported ECC mode!\n");
+               return -ENOTSUPP;
+       }
+
+       /*
+        * Don't set layout for BCH4 SW ECC. This will be
+        * generated later in nand_bch_init() later.
+        */
+       if (nand->ecc.mode == NAND_ECC_HW) {
+               switch (mtd->oobsize) {
+               case 16:
+               case 64:
+               case 128:
+                       mtd_set_ooblayout(mtd,
+                                         &fsmc_ecc1_ooblayout_ops);
+                       break;
+               default:
+                       dev_warn(host->dev,
+                                "No oob scheme defined for oobsize %d\n",
+                                mtd->oobsize);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static const struct nand_controller_ops fsmc_nand_controller_ops = {
+       .attach_chip = fsmc_nand_attach_chip,
+};
+
 /*
  * fsmc_nand_probe - Probe function
  * @pdev:       platform device structure
@@ -1047,76 +1124,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        /*
         * Scan to find existence of the device
         */
-       ret = nand_scan_ident(mtd, 1, NULL);
-       if (ret) {
-               dev_err(&pdev->dev, "No NAND Device found!\n");
-               goto release_dma_write_chan;
-       }
-
-       if (AMBA_REV_BITS(host->pid) >= 8) {
-               switch (mtd->oobsize) {
-               case 16:
-               case 64:
-               case 128:
-               case 224:
-               case 256:
-                       break;
-               default:
-                       dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
-                                mtd->oobsize);
-                       ret = -EINVAL;
-                       goto release_dma_write_chan;
-               }
-
-               mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
-       } else {
-               switch (nand->ecc.mode) {
-               case NAND_ECC_HW:
-                       dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
-                       nand->ecc.calculate = fsmc_read_hwecc_ecc1;
-                       nand->ecc.correct = nand_correct_data;
-                       nand->ecc.bytes = 3;
-                       nand->ecc.strength = 1;
-                       break;
-
-               case NAND_ECC_SOFT:
-                       if (nand->ecc.algo == NAND_ECC_BCH) {
-                               dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
-                               break;
-                       }
-
-               case NAND_ECC_ON_DIE:
-                       break;
-
-               default:
-                       dev_err(&pdev->dev, "Unsupported ECC mode!\n");
-                       goto release_dma_write_chan;
-               }
-
-               /*
-                * Don't set layout for BCH4 SW ECC. This will be
-                * generated later in nand_bch_init() later.
-                */
-               if (nand->ecc.mode == NAND_ECC_HW) {
-                       switch (mtd->oobsize) {
-                       case 16:
-                       case 64:
-                       case 128:
-                               mtd_set_ooblayout(mtd,
-                                                 &fsmc_ecc1_ooblayout_ops);
-                               break;
-                       default:
-                               dev_warn(&pdev->dev,
-                                        "No oob scheme defined for oobsize %d\n",
-                                        mtd->oobsize);
-                               ret = -EINVAL;
-                               goto release_dma_write_chan;
-                       }
-               }
-       }
-
-       /* Second stage of scan to fill MTD data-structures */
-       ret = nand_scan_tail(mtd);
+       nand->dummy_controller.ops = &fsmc_nand_controller_ops;
+       ret = nand_scan(mtd, 1);
        if (ret)
                goto release_dma_write_chan;
 
index 83697b8df8717afaa45a17d1dc2e2887bdb9cc1b..88ea2203e263bcdd1e54d3c4abc558fb42a1c895 100644 (file)
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Freescale GPMI NAND Flash Driver
  *
  * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
  * Copyright (C) 2008 Embedded Alley Solutions, Inc.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 #include <linux/delay.h>
 #include <linux/clk.h>
index f6aa358a345273f6721c63b7e75b3da54b35f15f..1c1ebbc82824362330fe307a67d4246fda2a03ed 100644 (file)
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Freescale GPMI NAND Flash Driver
  *
  * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
  * Copyright (C) 2008 Embedded Alley Solutions, Inc.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 #include <linux/clk.h>
 #include <linux/slab.h>
@@ -757,9 +744,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
         * [2] Allocate a read/write data buffer.
         *     The gpmi_alloc_dma_buffer can be called twice.
         *     We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
-        *     is called before the nand_scan_ident; and we allocate a buffer
-        *     of the real NAND page size when the gpmi_alloc_dma_buffer is
-        *     called after the nand_scan_ident.
+        *     is called before the NAND identification; and we allocate a
+        *     buffer of the real NAND page size when the gpmi_alloc_dma_buffer
+        *     is called after.
         */
        this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
                                        GFP_DMA | GFP_KERNEL);
@@ -957,7 +944,6 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        struct bch_geometry *nfc_geo = &this->bch_geometry;
        struct mtd_info *mtd = nand_to_mtd(chip);
-       void          *payload_virt;
        dma_addr_t    payload_phys;
        unsigned int  i;
        unsigned char *status;
@@ -967,7 +953,6 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
 
        dev_dbg(this->dev, "page number is : %d\n", page);
 
-       payload_virt = this->payload_virt;
        payload_phys = this->payload_phys;
 
        if (virt_addr_valid(buf)) {
@@ -976,7 +961,6 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
                dest_phys = dma_map_single(this->dev, buf, nfc_geo->payload_size,
                                           DMA_FROM_DEVICE);
                if (!dma_mapping_error(this->dev, dest_phys)) {
-                       payload_virt = buf;
                        payload_phys = dest_phys;
                        direct = true;
                }
@@ -1881,6 +1865,34 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
        return 0;
 }
 
+static int gpmi_nand_attach_chip(struct nand_chip *chip)
+{
+       struct gpmi_nand_data *this = nand_get_controller_data(chip);
+       int ret;
+
+       if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+               chip->bbt_options |= NAND_BBT_NO_OOB;
+
+               if (of_property_read_bool(this->dev->of_node,
+                                         "fsl,no-blockmark-swap"))
+                       this->swap_block_mark = false;
+       }
+       dev_dbg(this->dev, "Blockmark swapping %sabled\n",
+               this->swap_block_mark ? "en" : "dis");
+
+       ret = gpmi_init_last(this);
+       if (ret)
+               return ret;
+
+       chip->options |= NAND_SKIP_BBTSCAN;
+
+       return 0;
+}
+
+static const struct nand_controller_ops gpmi_nand_controller_ops = {
+       .attach_chip = gpmi_nand_attach_chip,
+};
+
 static int gpmi_nand_init(struct gpmi_nand_data *this)
 {
        struct nand_chip *chip = &this->nand;
@@ -1921,33 +1933,15 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
        if (ret)
                goto err_out;
 
-       ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
-       if (ret)
-               goto err_out;
-
-       if (chip->bbt_options & NAND_BBT_USE_FLASH) {
-               chip->bbt_options |= NAND_BBT_NO_OOB;
-
-               if (of_property_read_bool(this->dev->of_node,
-                                               "fsl,no-blockmark-swap"))
-                       this->swap_block_mark = false;
-       }
-       dev_dbg(this->dev, "Blockmark swapping %sabled\n",
-               this->swap_block_mark ? "en" : "dis");
-
-       ret = gpmi_init_last(this);
-       if (ret)
-               goto err_out;
-
-       chip->options |= NAND_SKIP_BBTSCAN;
-       ret = nand_scan_tail(mtd);
+       chip->dummy_controller.ops = &gpmi_nand_controller_ops;
+       ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1);
        if (ret)
                goto err_out;
 
        ret = nand_boot_init(this);
        if (ret)
                goto err_nand_cleanup;
-       ret = chip->scan_bbt(mtd);
+       ret = nand_create_bbt(chip);
        if (ret)
                goto err_nand_cleanup;
 
index 6aa10d6962d6398d8a0151f1fd7276b5e361c18a..69cd0cbde4f2070eb5bfcd6dd3c51158b6625320 100644 (file)
@@ -1,18 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Freescale GPMI NAND Flash Driver
  *
  * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
  * Copyright (C) 2008 Embedded Alley Solutions, Inc.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 #ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H
 #define __DRIVERS_MTD_NAND_GPMI_NAND_H
index a1e009c8e5561917669ee5aae598596241269d1b..950dc7789296fa3d30c3c63adadfa474594f773f 100644 (file)
@@ -709,9 +709,50 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
        return 0;
 }
 
+static int hisi_nfc_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct hinfc_host *host = nand_get_controller_data(chip);
+       int flag;
+
+       host->buffer = dmam_alloc_coherent(host->dev,
+                                          mtd->writesize + mtd->oobsize,
+                                          &host->dma_buffer, GFP_KERNEL);
+       if (!host->buffer)
+               return -ENOMEM;
+
+       host->dma_oob = host->dma_buffer + mtd->writesize;
+       memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
+
+       flag = hinfc_read(host, HINFC504_CON);
+       flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
+       switch (mtd->writesize) {
+       case 2048:
+               flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT);
+               break;
+       /*
+        * TODO: add more pagesize support,
+        * default pagesize has been set in hisi_nfc_host_init
+        */
+       default:
+               dev_err(host->dev, "NON-2KB page size nand flash\n");
+               return -EINVAL;
+       }
+       hinfc_write(host, flag, HINFC504_CON);
+
+       if (chip->ecc.mode == NAND_ECC_HW)
+               hisi_nfc_ecc_probe(host);
+
+       return 0;
+}
+
+static const struct nand_controller_ops hisi_nfc_controller_ops = {
+       .attach_chip = hisi_nfc_attach_chip,
+};
+
 static int hisi_nfc_probe(struct platform_device *pdev)
 {
-       int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
+       int ret = 0, irq, max_chips = HINFC504_MAX_CHIP;
        struct device *dev = &pdev->dev;
        struct hinfc_host *host;
        struct nand_chip  *chip;
@@ -769,42 +810,11 @@ static int hisi_nfc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = nand_scan_ident(mtd, max_chips, NULL);
+       chip->dummy_controller.ops = &hisi_nfc_controller_ops;
+       ret = nand_scan(mtd, max_chips);
        if (ret)
                return ret;
 
-       host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
-               &host->dma_buffer, GFP_KERNEL);
-       if (!host->buffer)
-               return -ENOMEM;
-
-       host->dma_oob = host->dma_buffer + mtd->writesize;
-       memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
-
-       flag = hinfc_read(host, HINFC504_CON);
-       flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
-       switch (mtd->writesize) {
-       case 2048:
-               flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
-       /*
-        * TODO: add more pagesize support,
-        * default pagesize has been set in hisi_nfc_host_init
-        */
-       default:
-               dev_err(dev, "NON-2KB page size nand flash\n");
-               return -EINVAL;
-       }
-       hinfc_write(host, flag, HINFC504_CON);
-
-       if (chip->ecc.mode == NAND_ECC_HW)
-               hisi_nfc_ecc_probe(host);
-
-       ret = nand_scan_tail(mtd);
-       if (ret) {
-               dev_err(dev, "nand_scan_tail failed: %d\n", ret);
-               return ret;
-       }
-
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
                dev_err(dev, "Err MTD partition=%d\n", ret);
index 613b00a9604b4803b83ce5ac8a8899d9a635c412..a7515452bc5976c747b82ddd80c3f6618fbb4dec 100644 (file)
@@ -13,6 +13,7 @@
  *
  */
 
+#include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -23,9 +24,9 @@
 #include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 
-#include <asm/mach-jz4740/jz4740_nand.h>
+#include <linux/platform_data/jz4740/jz4740_nand.h>
 
 #define JZ_REG_NAND_CTRL       0x50
 #define JZ_REG_NAND_ECC_CTRL   0x100
@@ -330,7 +331,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 
        if (chipnr == 0) {
                /* Detect first chip. */
-               ret = nand_scan_ident(mtd, 1, NULL);
+               ret = nand_scan(mtd, 1);
                if (ret)
                        goto notfound_id;
 
@@ -355,7 +356,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
                mtd->size += chip->chipsize;
        }
 
-       dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank);
+       dev_info(&pdev->dev, "Found chip %zu on bank %i\n", chipnr, bank);
        return 0;
 
 notfound_id:
@@ -367,6 +368,24 @@ notfound_id:
        return ret;
 }
 
+static int jz_nand_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct device *dev = mtd->dev.parent;
+       struct jz_nand_platform_data *pdata = dev_get_platdata(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+
+       if (pdata && pdata->ident_callback)
+               pdata->ident_callback(pdev, mtd, &pdata->partitions,
+                                     &pdata->num_partitions);
+
+       return 0;
+}
+
+static const struct nand_controller_ops jz_nand_controller_ops = {
+       .attach_chip = jz_nand_attach_chip,
+};
+
 static int jz_nand_probe(struct platform_device *pdev)
 {
        int ret;
@@ -410,6 +429,7 @@ static int jz_nand_probe(struct platform_device *pdev)
        chip->chip_delay = 50;
        chip->cmd_ctrl = jz_nand_cmd_ctrl;
        chip->select_chip = jz_nand_select_chip;
+       chip->dummy_controller.ops = &jz_nand_controller_ops;
 
        if (nand->busy_gpio)
                chip->dev_ready = jz_nand_dev_ready;
@@ -455,33 +475,20 @@ static int jz_nand_probe(struct platform_device *pdev)
                goto err_iounmap_mmio;
        }
 
-       if (pdata && pdata->ident_callback) {
-               pdata->ident_callback(pdev, mtd, &pdata->partitions,
-                                       &pdata->num_partitions);
-       }
-
-       ret = nand_scan_tail(mtd);
-       if (ret) {
-               dev_err(&pdev->dev,  "Failed to scan NAND\n");
-               goto err_unclaim_banks;
-       }
-
-       ret = mtd_device_parse_register(mtd, NULL, NULL,
-                                       pdata ? pdata->partitions : NULL,
-                                       pdata ? pdata->num_partitions : 0);
+       ret = mtd_device_register(mtd, pdata ? pdata->partitions : NULL,
+                                 pdata ? pdata->num_partitions : 0);
 
        if (ret) {
                dev_err(&pdev->dev, "Failed to add mtd device\n");
-               goto err_nand_release;
+               goto err_cleanup_nand;
        }
 
        dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
 
        return 0;
 
-err_nand_release:
-       nand_release(mtd);
-err_unclaim_banks:
+err_cleanup_nand:
+       nand_cleanup(chip);
        while (chipnr--) {
                unsigned char bank = nand->banks[chipnr];
                jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
index e69f6ae4c53952f0c8d6798c9c0dda5e49057f06..db4fa60bd52acaf5f056e27dcec2803431ad5414 100644 (file)
@@ -44,7 +44,7 @@ struct jz4780_nand_cs {
 struct jz4780_nand_controller {
        struct device *dev;
        struct jz4780_bch *bch;
-       struct nand_hw_control controller;
+       struct nand_controller controller;
        unsigned int num_banks;
        struct list_head chips;
        int selected;
@@ -65,7 +65,8 @@ static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd)
        return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip);
 }
 
-static inline struct jz4780_nand_controller *to_jz4780_nand_controller(struct nand_hw_control *ctrl)
+static inline struct jz4780_nand_controller
+*to_jz4780_nand_controller(struct nand_controller *ctrl)
 {
        return container_of(ctrl, struct jz4780_nand_controller, controller);
 }
@@ -157,9 +158,8 @@ static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
        return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
 }
 
-static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *dev)
+static int jz4780_nand_attach_chip(struct nand_chip *chip)
 {
-       struct nand_chip *chip = &nand->chip;
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
        int eccbytes;
@@ -170,7 +170,8 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
        switch (chip->ecc.mode) {
        case NAND_ECC_HW:
                if (!nfc->bch) {
-                       dev_err(dev, "HW BCH selected, but BCH controller not found\n");
+                       dev_err(nfc->dev,
+                               "HW BCH selected, but BCH controller not found\n");
                        return -ENODEV;
                }
 
@@ -179,15 +180,16 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
                chip->ecc.correct = jz4780_nand_ecc_correct;
                /* fall through */
        case NAND_ECC_SOFT:
-               dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
-                       (nfc->bch) ? "hardware BCH" : "software ECC",
-                       chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
+               dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n",
+                        (nfc->bch) ? "hardware BCH" : "software ECC",
+                        chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
                break;
        case NAND_ECC_NONE:
-               dev_info(dev, "not using ECC\n");
+               dev_info(nfc->dev, "not using ECC\n");
                break;
        default:
-               dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
+               dev_err(nfc->dev, "ECC mode %d not supported\n",
+                       chip->ecc.mode);
                return -EINVAL;
        }
 
@@ -199,7 +201,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
        eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
 
        if (eccbytes > mtd->oobsize - 2) {
-               dev_err(dev,
+               dev_err(nfc->dev,
                        "invalid ECC config: required %d ECC bytes, but only %d are available",
                        eccbytes, mtd->oobsize - 2);
                return -EINVAL;
@@ -210,6 +212,10 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
        return 0;
 }
 
+static const struct nand_controller_ops jz4780_nand_controller_ops = {
+       .attach_chip = jz4780_nand_attach_chip,
+};
+
 static int jz4780_nand_init_chip(struct platform_device *pdev,
                                struct jz4780_nand_controller *nfc,
                                struct device_node *np,
@@ -279,15 +285,8 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
        chip->controller = &nfc->controller;
        nand_set_flash_node(chip, np);
 
-       ret = nand_scan_ident(mtd, 1, NULL);
-       if (ret)
-               return ret;
-
-       ret = jz4780_nand_init_ecc(nand, dev);
-       if (ret)
-               return ret;
-
-       ret = nand_scan_tail(mtd);
+       chip->controller->ops = &jz4780_nand_controller_ops;
+       ret = nand_scan(mtd, 1);
        if (ret)
                return ret;
 
@@ -368,7 +367,7 @@ static int jz4780_nand_probe(struct platform_device *pdev)
        nfc->dev = dev;
        nfc->num_banks = num_banks;
 
-       nand_hw_control_init(&nfc->controller);
+       nand_controller_init(&nfc->controller);
        INIT_LIST_HEAD(&nfc->chips);
 
        ret = jz4780_nand_init_chips(nfc, pdev);
index 052d123a8304074c8a64ab158dc496bc60fbce31..e82abada130a057b0855f64b7f546026b529f0ad 100644 (file)
@@ -184,6 +184,7 @@ static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
 };
 
 struct lpc32xx_nand_host {
+       struct platform_device  *pdev;
        struct nand_chip        nand_chip;
        struct lpc32xx_mlc_platform_data *pdata;
        struct clk              *clk;
@@ -653,6 +654,32 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
        return ncfg;
 }
 
+static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+       struct device *dev = &host->pdev->dev;
+
+       host->dma_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
+       if (!host->dma_buf)
+               return -ENOMEM;
+
+       host->dummy_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
+       if (!host->dummy_buf)
+               return -ENOMEM;
+
+       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.size = 512;
+       mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+       host->mlcsubpages = mtd->writesize / 512;
+
+       return 0;
+}
+
+static const struct nand_controller_ops lpc32xx_nand_controller_ops = {
+       .attach_chip = lpc32xx_nand_attach_chip,
+};
+
 /*
  * Probe for NAND controller
  */
@@ -669,6 +696,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        if (!host)
                return -ENOMEM;
 
+       host->pdev = pdev;
+
        rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->io_base = devm_ioremap_resource(&pdev->dev, rc);
        if (IS_ERR(host->io_base))
@@ -748,31 +777,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
                }
        }
 
-       /*
-        * Scan to find existance of the device and
-        * Get the type of NAND device SMALL block or LARGE block
-        */
-       res = nand_scan_ident(mtd, 1, NULL);
-       if (res)
-               goto release_dma_chan;
-
-       host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
-       if (!host->dma_buf) {
-               res = -ENOMEM;
-               goto release_dma_chan;
-       }
-
-       host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
-       if (!host->dummy_buf) {
-               res = -ENOMEM;
-               goto release_dma_chan;
-       }
-
-       nand_chip->ecc.mode = NAND_ECC_HW;
-       nand_chip->ecc.size = 512;
-       mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
-       host->mlcsubpages = mtd->writesize / 512;
-
        /* initially clear interrupt status */
        readb(MLC_IRQ_SR(host->io_base));
 
@@ -794,10 +798,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
 
        /*
-        * Fills out all the uninitialized function pointers with the defaults
-        * And scans for a bad block table if appropriate.
+        * Scan to find existence of the device and get the type of NAND device:
+        * SMALL block or LARGE block.
         */
-       res = nand_scan_tail(mtd);
+       nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
+       res = nand_scan(mtd, 1);
        if (res)
                goto free_irq;
 
index 42820aa1abab348fcdb2c2c9a4b236e7f62e060c..a4e8b7e7513516c91520814c49519e1259f8f779 100644 (file)
@@ -779,6 +779,46 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
        return ncfg;
 }
 
+static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
+
+       /* OOB and ECC CPU and DMA work areas */
+       host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
+
+       /*
+        * Small page FLASH has a unique OOB layout, but large and huge
+        * page FLASH use the standard layout. Small page FLASH uses a
+        * custom BBT marker layout.
+        */
+       if (mtd->writesize <= 512)
+               mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
+
+       /* These sizes remain the same regardless of page size */
+       chip->ecc.size = 256;
+       chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
+       chip->ecc.prepad = 0;
+       chip->ecc.postpad = 0;
+
+       /*
+        * Use a custom BBT marker setup for small page FLASH that
+        * won't interfere with the ECC layout. Large and huge page
+        * FLASH use the standard layout.
+        */
+       if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
+           mtd->writesize <= 512) {
+               chip->bbt_td = &bbt_smallpage_main_descr;
+               chip->bbt_md = &bbt_smallpage_mirror_descr;
+       }
+
+       return 0;
+}
+
+static const struct nand_controller_ops lpc32xx_nand_controller_ops = {
+       .attach_chip = lpc32xx_nand_attach_chip,
+};
+
 /*
  * Probe for NAND controller
  */
@@ -884,41 +924,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
 
        /* Find NAND device */
-       res = nand_scan_ident(mtd, 1, NULL);
-       if (res)
-               goto release_dma;
-
-       /* OOB and ECC CPU and DMA work areas */
-       host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
-
-       /*
-        * Small page FLASH has a unique OOB layout, but large and huge
-        * page FLASH use the standard layout. Small page FLASH uses a
-        * custom BBT marker layout.
-        */
-       if (mtd->writesize <= 512)
-               mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
-
-       /* These sizes remain the same regardless of page size */
-       chip->ecc.size = 256;
-       chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
-       chip->ecc.prepad = chip->ecc.postpad = 0;
-
-       /*
-        * Use a custom BBT marker setup for small page FLASH that
-        * won't interfere with the ECC layout. Large and huge page
-        * FLASH use the standard layout.
-        */
-       if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
-           mtd->writesize <= 512) {
-               chip->bbt_td = &bbt_smallpage_main_descr;
-               chip->bbt_md = &bbt_smallpage_mirror_descr;
-       }
-
-       /*
-        * Fills out all the uninitialized function pointers with the defaults
-        */
-       res = nand_scan_tail(mtd);
+       chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
+       res = nand_scan(mtd, 1);
        if (res)
                goto release_dma;
 
index ebb1d141b90000c069b0634fe0a3c4d5d5f842d4..218e09431d3dcad2502b60457cddaf2ae6b03c12 100644 (file)
@@ -318,7 +318,7 @@ struct marvell_nfc_caps {
  * @dma_buf:           32-bit aligned buffer for DMA transfers (NFCv1 only)
  */
 struct marvell_nfc {
-       struct nand_hw_control controller;
+       struct nand_controller controller;
        struct device *dev;
        void __iomem *regs;
        struct clk *core_clk;
@@ -335,7 +335,7 @@ struct marvell_nfc {
        u8 *dma_buf;
 };
 
-static inline struct marvell_nfc *to_marvell_nfc(struct nand_hw_control *ctrl)
+static inline struct marvell_nfc *to_marvell_nfc(struct nand_controller *ctrl)
 {
        return container_of(ctrl, struct marvell_nfc, controller);
 }
@@ -650,11 +650,6 @@ static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
                return;
        }
 
-       /*
-        * Do not change the timing registers when using the DT property
-        * marvell,nand-keep-config; in that case ->ndtr0 and ->ndtr1 from the
-        * marvell_nand structure are supposedly empty.
-        */
        writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0);
        writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1);
 
@@ -2157,6 +2152,7 @@ static int marvell_nand_ecc_init(struct mtd_info *mtd,
                break;
        case NAND_ECC_NONE:
        case NAND_ECC_SOFT:
+       case NAND_ECC_ON_DIE:
                if (!nfc->caps->is_nfcv2 && mtd->writesize != SZ_512 &&
                    mtd->writesize != SZ_2K) {
                        dev_err(nfc->dev, "NFCv1 cannot write %d bytes pages\n",
@@ -2294,6 +2290,111 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
        return 0;
 }
 
+static int marvell_nand_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
+       struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
+       struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(nfc->dev);
+       int ret;
+
+       if (pdata && pdata->flash_bbt)
+               chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+       if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+               /*
+                * We'll use a bad block table stored in-flash and don't
+                * allow writing the bad block marker to the flash.
+                */
+               chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+               chip->bbt_td = &bbt_main_descr;
+               chip->bbt_md = &bbt_mirror_descr;
+       }
+
+       /* Save the chip-specific fields of NDCR */
+       marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
+       if (chip->options & NAND_BUSWIDTH_16)
+               marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
+
+       /*
+        * On small page NANDs, only one cycle is needed to pass the
+        * column address.
+        */
+       if (mtd->writesize <= 512) {
+               marvell_nand->addr_cyc = 1;
+       } else {
+               marvell_nand->addr_cyc = 2;
+               marvell_nand->ndcr |= NDCR_RA_START;
+       }
+
+       /*
+        * Now add the number of cycles needed to pass the row
+        * address.
+        *
+        * Addressing a chip using CS 2 or 3 should also need the third row
+        * cycle but due to inconsistance in the documentation and lack of
+        * hardware to test this situation, this case is not supported.
+        */
+       if (chip->options & NAND_ROW_ADDR_3)
+               marvell_nand->addr_cyc += 3;
+       else
+               marvell_nand->addr_cyc += 2;
+
+       if (pdata) {
+               chip->ecc.size = pdata->ecc_step_size;
+               chip->ecc.strength = pdata->ecc_strength;
+       }
+
+       ret = marvell_nand_ecc_init(mtd, &chip->ecc);
+       if (ret) {
+               dev_err(nfc->dev, "ECC init failed: %d\n", ret);
+               return ret;
+       }
+
+       if (chip->ecc.mode == NAND_ECC_HW) {
+               /*
+                * Subpage write not available with hardware ECC, prohibit also
+                * subpage read as in userspace subpage access would still be
+                * allowed and subpage write, if used, would lead to numerous
+                * uncorrectable ECC errors.
+                */
+               chip->options |= NAND_NO_SUBPAGE_WRITE;
+       }
+
+       if (pdata || nfc->caps->legacy_of_bindings) {
+               /*
+                * We keep the MTD name unchanged to avoid breaking platforms
+                * where the MTD cmdline parser is used and the bootloader
+                * has not been updated to use the new naming scheme.
+                */
+               mtd->name = "pxa3xx_nand-0";
+       } else if (!mtd->name) {
+               /*
+                * If the new bindings are used and the bootloader has not been
+                * updated to pass a new mtdparts parameter on the cmdline, you
+                * should define the following property in your NAND node, ie:
+                *
+                *      label = "main-storage";
+                *
+                * This way, mtd->name will be set by the core when
+                * nand_set_flash_node() is called.
+                */
+               mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
+                                          "%s:nand.%d", dev_name(nfc->dev),
+                                          marvell_nand->sels[0].cs);
+               if (!mtd->name) {
+                       dev_err(nfc->dev, "Failed to allocate mtd->name\n");
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static const struct nand_controller_ops marvell_nand_controller_ops = {
+       .attach_chip = marvell_nand_attach_chip,
+};
+
 static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
                                  struct device_node *np)
 {
@@ -2436,105 +2537,10 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
        marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1);
 
        chip->options |= NAND_BUSWIDTH_AUTO;
-       ret = nand_scan_ident(mtd, marvell_nand->nsels, NULL);
-       if (ret) {
-               dev_err(dev, "could not identify the nand chip\n");
-               return ret;
-       }
-
-       if (pdata && pdata->flash_bbt)
-               chip->bbt_options |= NAND_BBT_USE_FLASH;
-
-       if (chip->bbt_options & NAND_BBT_USE_FLASH) {
-               /*
-                * We'll use a bad block table stored in-flash and don't
-                * allow writing the bad block marker to the flash.
-                */
-               chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
-               chip->bbt_td = &bbt_main_descr;
-               chip->bbt_md = &bbt_mirror_descr;
-       }
-
-       /* Save the chip-specific fields of NDCR */
-       marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
-       if (chip->options & NAND_BUSWIDTH_16)
-               marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
-
-       /*
-        * On small page NANDs, only one cycle is needed to pass the
-        * column address.
-        */
-       if (mtd->writesize <= 512) {
-               marvell_nand->addr_cyc = 1;
-       } else {
-               marvell_nand->addr_cyc = 2;
-               marvell_nand->ndcr |= NDCR_RA_START;
-       }
-
-       /*
-        * Now add the number of cycles needed to pass the row
-        * address.
-        *
-        * Addressing a chip using CS 2 or 3 should also need the third row
-        * cycle but due to inconsistance in the documentation and lack of
-        * hardware to test this situation, this case is not supported.
-        */
-       if (chip->options & NAND_ROW_ADDR_3)
-               marvell_nand->addr_cyc += 3;
-       else
-               marvell_nand->addr_cyc += 2;
-
-       if (pdata) {
-               chip->ecc.size = pdata->ecc_step_size;
-               chip->ecc.strength = pdata->ecc_strength;
-       }
 
-       ret = marvell_nand_ecc_init(mtd, &chip->ecc);
+       ret = nand_scan(mtd, marvell_nand->nsels);
        if (ret) {
-               dev_err(dev, "ECC init failed: %d\n", ret);
-               return ret;
-       }
-
-       if (chip->ecc.mode == NAND_ECC_HW) {
-               /*
-                * Subpage write not available with hardware ECC, prohibit also
-                * subpage read as in userspace subpage access would still be
-                * allowed and subpage write, if used, would lead to numerous
-                * uncorrectable ECC errors.
-                */
-               chip->options |= NAND_NO_SUBPAGE_WRITE;
-       }
-
-       if (pdata || nfc->caps->legacy_of_bindings) {
-               /*
-                * We keep the MTD name unchanged to avoid breaking platforms
-                * where the MTD cmdline parser is used and the bootloader
-                * has not been updated to use the new naming scheme.
-                */
-               mtd->name = "pxa3xx_nand-0";
-       } else if (!mtd->name) {
-               /*
-                * If the new bindings are used and the bootloader has not been
-                * updated to pass a new mtdparts parameter on the cmdline, you
-                * should define the following property in your NAND node, ie:
-                *
-                *      label = "main-storage";
-                *
-                * This way, mtd->name will be set by the core when
-                * nand_set_flash_node() is called.
-                */
-               mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
-                                          "%s:nand.%d", dev_name(nfc->dev),
-                                          marvell_nand->sels[0].cs);
-               if (!mtd->name) {
-                       dev_err(nfc->dev, "Failed to allocate mtd->name\n");
-                       return -ENOMEM;
-               }
-       }
-
-       ret = nand_scan_tail(mtd);
-       if (ret) {
-               dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+               dev_err(dev, "could not scan the nand chip\n");
                return ret;
        }
 
@@ -2677,6 +2683,21 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
        return 0;
 }
 
+static void marvell_nfc_reset(struct marvell_nfc *nfc)
+{
+       /*
+        * ECC operations and interruptions are only enabled when specifically
+        * needed. ECC shall not be activated in the early stages (fails probe).
+        * Arbiter flag, even if marked as "reserved", must be set (empirical).
+        * SPARE_EN bit must always be set or ECC bytes will not be at the same
+        * offset in the read page and this will fail the protection.
+        */
+       writel_relaxed(NDCR_ALL_INT | NDCR_ND_ARB_EN | NDCR_SPARE_EN |
+                      NDCR_RD_ID_CNT(NFCV1_READID_LEN), nfc->regs + NDCR);
+       writel_relaxed(0xFFFFFFFF, nfc->regs + NDSR);
+       writel_relaxed(0, nfc->regs + NDECCCTRL);
+}
+
 static int marvell_nfc_init(struct marvell_nfc *nfc)
 {
        struct device_node *np = nfc->dev->of_node;
@@ -2715,17 +2736,7 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
        if (!nfc->caps->is_nfcv2)
                marvell_nfc_init_dma(nfc);
 
-       /*
-        * ECC operations and interruptions are only enabled when specifically
-        * needed. ECC shall not be activated in the early stages (fails probe).
-        * Arbiter flag, even if marked as "reserved", must be set (empirical).
-        * SPARE_EN bit must always be set or ECC bytes will not be at the same
-        * offset in the read page and this will fail the protection.
-        */
-       writel_relaxed(NDCR_ALL_INT | NDCR_ND_ARB_EN | NDCR_SPARE_EN |
-                      NDCR_RD_ID_CNT(NFCV1_READID_LEN), nfc->regs + NDCR);
-       writel_relaxed(0xFFFFFFFF, nfc->regs + NDSR);
-       writel_relaxed(0, nfc->regs + NDECCCTRL);
+       marvell_nfc_reset(nfc);
 
        return 0;
 }
@@ -2744,7 +2755,8 @@ static int marvell_nfc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        nfc->dev = dev;
-       nand_hw_control_init(&nfc->controller);
+       nand_controller_init(&nfc->controller);
+       nfc->controller.ops = &marvell_nand_controller_ops;
        INIT_LIST_HEAD(&nfc->chips);
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2772,17 +2784,19 @@ static int marvell_nfc_probe(struct platform_device *pdev)
                return ret;
 
        nfc->reg_clk = devm_clk_get(&pdev->dev, "reg");
-       if (PTR_ERR(nfc->reg_clk) != -ENOENT) {
-               if (!IS_ERR(nfc->reg_clk)) {
-                       ret = clk_prepare_enable(nfc->reg_clk);
-                       if (ret)
-                               goto unprepare_core_clk;
-               } else {
+       if (IS_ERR(nfc->reg_clk)) {
+               if (PTR_ERR(nfc->reg_clk) != -ENOENT) {
                        ret = PTR_ERR(nfc->reg_clk);
                        goto unprepare_core_clk;
                }
+
+               nfc->reg_clk = NULL;
        }
 
+       ret = clk_prepare_enable(nfc->reg_clk);
+       if (ret)
+               goto unprepare_core_clk;
+
        marvell_nfc_disable_int(nfc, NDCR_ALL_INT);
        marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
        ret = devm_request_irq(dev, irq, marvell_nfc_isr,
@@ -2840,6 +2854,49 @@ static int marvell_nfc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int __maybe_unused marvell_nfc_suspend(struct device *dev)
+{
+       struct marvell_nfc *nfc = dev_get_drvdata(dev);
+       struct marvell_nand_chip *chip;
+
+       list_for_each_entry(chip, &nfc->chips, node)
+               marvell_nfc_wait_ndrun(&chip->chip);
+
+       clk_disable_unprepare(nfc->reg_clk);
+       clk_disable_unprepare(nfc->core_clk);
+
+       return 0;
+}
+
+static int __maybe_unused marvell_nfc_resume(struct device *dev)
+{
+       struct marvell_nfc *nfc = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(nfc->core_clk);
+       if (ret < 0)
+               return ret;
+
+       ret = clk_prepare_enable(nfc->reg_clk);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Reset nfc->selected_chip so the next command will cause the timing
+        * registers to be restored in marvell_nfc_select_chip().
+        */
+       nfc->selected_chip = NULL;
+
+       /* Reset registers that have lost their contents */
+       marvell_nfc_reset(nfc);
+
+       return 0;
+}
+
+static const struct dev_pm_ops marvell_nfc_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(marvell_nfc_suspend, marvell_nfc_resume)
+};
+
 static const struct marvell_nfc_caps marvell_armada_8k_nfc_caps = {
        .max_cs_nb = 4,
        .max_rb_nb = 2,
@@ -2924,6 +2981,7 @@ static struct platform_driver marvell_nfc_driver = {
        .driver = {
                .name           = "marvell-nfc",
                .of_match_table = marvell_nfc_of_ids,
+               .pm             = &marvell_nfc_pm_ops,
        },
        .id_table = marvell_nfc_platform_ids,
        .probe = marvell_nfc_probe,
index 75c845adb05016013e69789ee6bbd74a98d0d55b..57b5ed1699e386e51865ba77c61c6561ffc1775f 100644 (file)
@@ -145,7 +145,7 @@ struct mtk_nfc_clk {
 };
 
 struct mtk_nfc {
-       struct nand_hw_control controller;
+       struct nand_controller controller;
        struct mtk_ecc_config ecc_cfg;
        struct mtk_nfc_clk clk;
        struct mtk_ecc *ecc;
@@ -1250,13 +1250,54 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
        return 0;
 }
 
+static int mtk_nfc_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct device *dev = mtd->dev.parent;
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       int len;
+       int ret;
+
+       if (chip->options & NAND_BUSWIDTH_16) {
+               dev_err(dev, "16bits buswidth not supported");
+               return -EINVAL;
+       }
+
+       /* store bbt magic in page, cause OOB is not protected */
+       if (chip->bbt_options & NAND_BBT_USE_FLASH)
+               chip->bbt_options |= NAND_BBT_NO_OOB;
+
+       ret = mtk_nfc_ecc_init(dev, mtd);
+       if (ret)
+               return ret;
+
+       ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
+       if (ret)
+               return ret;
+
+       mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
+       mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
+
+       len = mtd->writesize + mtd->oobsize;
+       nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
+       if (!nfc->buffer)
+               return  -ENOMEM;
+
+       return 0;
+}
+
+static const struct nand_controller_ops mtk_nfc_controller_ops = {
+       .attach_chip = mtk_nfc_attach_chip,
+};
+
 static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
                                  struct device_node *np)
 {
        struct mtk_nfc_nand_chip *chip;
        struct nand_chip *nand;
        struct mtd_info *mtd;
-       int nsels, len;
+       int nsels;
        u32 tmp;
        int ret;
        int i;
@@ -1324,40 +1365,11 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
 
        mtk_nfc_hw_init(nfc);
 
-       ret = nand_scan_ident(mtd, nsels, NULL);
-       if (ret)
-               return ret;
-
-       /* store bbt magic in page, cause OOB is not protected */
-       if (nand->bbt_options & NAND_BBT_USE_FLASH)
-               nand->bbt_options |= NAND_BBT_NO_OOB;
-
-       ret = mtk_nfc_ecc_init(dev, mtd);
-       if (ret)
-               return -EINVAL;
-
-       if (nand->options & NAND_BUSWIDTH_16) {
-               dev_err(dev, "16bits buswidth not supported");
-               return -EINVAL;
-       }
-
-       ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
-       if (ret)
-               return ret;
-
-       mtk_nfc_set_fdm(&chip->fdm, mtd);
-       mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
-
-       len = mtd->writesize + mtd->oobsize;
-       nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
-       if (!nfc->buffer)
-               return  -ENOMEM;
-
-       ret = nand_scan_tail(mtd);
+       ret = nand_scan(mtd, nsels);
        if (ret)
                return ret;
 
-       ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+       ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
                dev_err(dev, "mtd parse partition error\n");
                nand_release(mtd);
@@ -1443,6 +1455,7 @@ static int mtk_nfc_probe(struct platform_device *pdev)
        spin_lock_init(&nfc->controller.lock);
        init_waitqueue_head(&nfc->controller.wq);
        INIT_LIST_HEAD(&nfc->chips);
+       nfc->controller.ops = &mtk_nfc_controller_ops;
 
        /* probe defer if not ready */
        nfc->ecc = of_mtk_ecc_get(np);
index 26cef218bb43ee1bd1fb2cf1dbadeb8ad38e2f8e..4c9214dea4240b7057df964034ea59d5bca892ac 100644 (file)
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
  * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
- *
- * 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.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
  */
 
 #include <linux/delay.h>
@@ -34,8 +21,6 @@
 #include <linux/completion.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-
-#include <asm/mach/flash.h>
 #include <linux/platform_data/mtd-mxc_nand.h>
 
 #define DRIVER_NAME "mxc_nand"
@@ -1686,7 +1671,7 @@ static const struct of_device_id mxcnd_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
 
-static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
+static int mxcnd_probe_dt(struct mxc_nand_host *host)
 {
        struct device_node *np = host->dev->of_node;
        const struct of_device_id *of_id =
@@ -1700,12 +1685,80 @@ static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
        return 0;
 }
 #else
-static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
+static int mxcnd_probe_dt(struct mxc_nand_host *host)
 {
        return 1;
 }
 #endif
 
+static int mxcnd_attach_chip(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct mxc_nand_host *host = nand_get_controller_data(chip);
+       struct device *dev = mtd->dev.parent;
+
+       switch (chip->ecc.mode) {
+       case NAND_ECC_HW:
+               chip->ecc.read_page = mxc_nand_read_page;
+               chip->ecc.read_page_raw = mxc_nand_read_page_raw;
+               chip->ecc.read_oob = mxc_nand_read_oob;
+               chip->ecc.write_page = mxc_nand_write_page_ecc;
+               chip->ecc.write_page_raw = mxc_nand_write_page_raw;
+               chip->ecc.write_oob = mxc_nand_write_oob;
+               break;
+
+       case NAND_ECC_SOFT:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (chip->bbt_options & NAND_BBT_USE_FLASH) {
+               chip->bbt_td = &bbt_main_descr;
+               chip->bbt_md = &bbt_mirror_descr;
+       }
+
+       /* Allocate the right size buffer now */
+       devm_kfree(dev, (void *)host->data_buf);
+       host->data_buf = devm_kzalloc(dev, mtd->writesize + mtd->oobsize,
+                                     GFP_KERNEL);
+       if (!host->data_buf)
+               return -ENOMEM;
+
+       /* Call preset again, with correct writesize chip time */
+       host->devtype_data->preset(mtd);
+
+       if (!chip->ecc.bytes) {
+               if (host->eccsize == 8)
+                       chip->ecc.bytes = 18;
+               else if (host->eccsize == 4)
+                       chip->ecc.bytes = 9;
+       }
+
+       /*
+        * Experimentation shows that i.MX NFC can only handle up to 218 oob
+        * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
+        * into copying invalid data to/from the spare IO buffer, as this
+        * might cause ECC data corruption when doing sub-page write to a
+        * partially written page.
+        */
+       host->used_oobsize = min(mtd->oobsize, 218U);
+
+       if (chip->ecc.mode == NAND_ECC_HW) {
+               if (is_imx21_nfc(host) || is_imx27_nfc(host))
+                       chip->ecc.strength = 1;
+               else
+                       chip->ecc.strength = (host->eccsize == 4) ? 4 : 8;
+       }
+
+       return 0;
+}
+
+static const struct nand_controller_ops mxcnd_controller_ops = {
+       .attach_chip = mxcnd_attach_chip,
+};
+
 static int mxcnd_probe(struct platform_device *pdev)
 {
        struct nand_chip *this;
@@ -1845,71 +1898,9 @@ static int mxcnd_probe(struct platform_device *pdev)
                host->devtype_data->irq_control(host, 1);
        }
 
-       /* first scan to find the device and get the page size */
-       err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
-       if (err)
-               goto escan;
-
-       switch (this->ecc.mode) {
-       case NAND_ECC_HW:
-               this->ecc.read_page = mxc_nand_read_page;
-               this->ecc.read_page_raw = mxc_nand_read_page_raw;
-               this->ecc.read_oob = mxc_nand_read_oob;
-               this->ecc.write_page = mxc_nand_write_page_ecc;
-               this->ecc.write_page_raw = mxc_nand_write_page_raw;
-               this->ecc.write_oob = mxc_nand_write_oob;
-               break;
-
-       case NAND_ECC_SOFT:
-               break;
-
-       default:
-               err = -EINVAL;
-               goto escan;
-       }
-
-       if (this->bbt_options & NAND_BBT_USE_FLASH) {
-               this->bbt_td = &bbt_main_descr;
-               this->bbt_md = &bbt_mirror_descr;
-       }
-
-       /* allocate the right size buffer now */
-       devm_kfree(&pdev->dev, (void *)host->data_buf);
-       host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
-                                       GFP_KERNEL);
-       if (!host->data_buf) {
-               err = -ENOMEM;
-               goto escan;
-       }
-
-       /* Call preset again, with correct writesize this time */
-       host->devtype_data->preset(mtd);
-
-       if (!this->ecc.bytes) {
-               if (host->eccsize == 8)
-                       this->ecc.bytes = 18;
-               else if (host->eccsize == 4)
-                       this->ecc.bytes = 9;
-       }
-
-       /*
-        * Experimentation shows that i.MX NFC can only handle up to 218 oob
-        * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
-        * into copying invalid data to/from the spare IO buffer, as this
-        * might cause ECC data corruption when doing sub-page write to a
-        * partially written page.
-        */
-       host->used_oobsize = min(mtd->oobsize, 218U);
-
-       if (this->ecc.mode == NAND_ECC_HW) {
-               if (is_imx21_nfc(host) || is_imx27_nfc(host))
-                       this->ecc.strength = 1;
-               else
-                       this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
-       }
-
-       /* second phase scan */
-       err = nand_scan_tail(mtd);
+       /* Scan the NAND device */
+       this->dummy_controller.ops = &mxcnd_controller_ops;
+       err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1);
        if (err)
                goto escan;
 
index b01d15ec4c56bfbdded578526d76e2ed12b65093..d527e448ce19844e89b35b221b4405dac7a8567d 100644 (file)
@@ -2668,8 +2668,8 @@ static bool nand_subop_instr_is_valid(const struct nand_subop *subop,
        return subop && instr_idx < subop->ninstrs;
 }
 
-static int nand_subop_get_start_off(const struct nand_subop *subop,
-                                   unsigned int instr_idx)
+static unsigned int nand_subop_get_start_off(const struct nand_subop *subop,
+                                            unsigned int instr_idx)
 {
        if (instr_idx)
                return 0;
@@ -2688,12 +2688,12 @@ static int nand_subop_get_start_off(const struct nand_subop *subop,
  *
  * Given an address instruction, returns the offset of the first cycle to issue.
  */
-int nand_subop_get_addr_start_off(const struct nand_subop *subop,
-                                 unsigned int instr_idx)
+unsigned int nand_subop_get_addr_start_off(const struct nand_subop *subop,
+                                          unsigned int instr_idx)
 {
-       if (!nand_subop_instr_is_valid(subop, instr_idx) ||
-           subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
-               return -EINVAL;
+       if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) ||
+                   subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR))
+               return 0;
 
        return nand_subop_get_start_off(subop, instr_idx);
 }
@@ -2710,14 +2710,14 @@ EXPORT_SYMBOL_GPL(nand_subop_get_addr_start_off);
  *
  * Given an address instruction, returns the number of address cycle to issue.
  */
-int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
-                               unsigned int instr_idx)
+unsigned int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
+                                        unsigned int instr_idx)
 {
        int start_off, end_off;
 
-       if (!nand_subop_instr_is_valid(subop, instr_idx) ||
-           subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
-               return -EINVAL;
+       if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) ||
+                   subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR))
+               return 0;
 
        start_off = nand_subop_get_addr_start_off(subop, instr_idx);
 
@@ -2742,12 +2742,12 @@ EXPORT_SYMBOL_GPL(nand_subop_get_num_addr_cyc);
  *
  * Given a data instruction, returns the offset to start from.
  */
-int nand_subop_get_data_start_off(const struct nand_subop *subop,
-                                 unsigned int instr_idx)
+unsigned int nand_subop_get_data_start_off(const struct nand_subop *subop,
+                                          unsigned int instr_idx)
 {
-       if (!nand_subop_instr_is_valid(subop, instr_idx) ||
-           !nand_instr_is_data(&subop->instrs[instr_idx]))
-               return -EINVAL;
+       if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) ||
+                   !nand_instr_is_data(&subop->instrs[instr_idx])))
+               return 0;
 
        return nand_subop_get_start_off(subop, instr_idx);
 }
@@ -2764,14 +2764,14 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_start_off);
  *
  * Returns the length of the chunk of data to send/receive.
  */
-int nand_subop_get_data_len(const struct nand_subop *subop,
-                           unsigned int instr_idx)
+unsigned int nand_subop_get_data_len(const struct nand_subop *subop,
+                                    unsigned int instr_idx)
 {
        int start_off = 0, end_off;
 
-       if (!nand_subop_instr_is_valid(subop, instr_idx) ||
-           !nand_instr_is_data(&subop->instrs[instr_idx]))
-               return -EINVAL;
+       if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) ||
+                   !nand_instr_is_data(&subop->instrs[instr_idx])))
+               return 0;
 
        start_off = nand_subop_get_data_start_off(subop, instr_idx);
 
@@ -2966,6 +2966,23 @@ int nand_check_erased_ecc_chunk(void *data, int datalen,
 }
 EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
 
+/**
+ * nand_read_page_raw_notsupp - dummy read raw page function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Returns -ENOTSUPP unconditionally.
+ */
+int nand_read_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
+                              u8 *buf, int oob_required, int page)
+{
+       return -ENOTSUPP;
+}
+EXPORT_SYMBOL(nand_read_page_raw_notsupp);
+
 /**
  * nand_read_page_raw - [INTERN] read raw page data without ecc
  * @mtd: mtd info structure
@@ -3960,6 +3977,22 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
        return ret;
 }
 
+/**
+ * nand_write_page_raw_notsupp - dummy raw page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ * @page: page number to write
+ *
+ * Returns -ENOTSUPP unconditionally.
+ */
+int nand_write_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
+                               const u8 *buf, int oob_required, int page)
+{
+       return -ENOTSUPP;
+}
+EXPORT_SYMBOL(nand_write_page_raw_notsupp);
 
 /**
  * nand_write_page_raw - [INTERN] raw page write function
@@ -4965,12 +4998,10 @@ static void nand_set_defaults(struct nand_chip *chip)
                chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
        if (!chip->read_buf || chip->read_buf == nand_read_buf)
                chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
-       if (!chip->scan_bbt)
-               chip->scan_bbt = nand_default_bbt;
 
        if (!chip->controller) {
-               chip->controller = &chip->hwcontrol;
-               nand_hw_control_init(chip->controller);
+               chip->controller = &chip->dummy_controller;
+               nand_controller_init(chip->controller);
        }
 
        if (!chip->buf_align)
@@ -5120,6 +5151,8 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_onfi_params *p;
+       struct onfi_params *onfi;
+       int onfi_version = 0;
        char id[4];
        int i, ret, val;
 
@@ -5168,30 +5201,35 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
                }
        }
 
+       if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+           chip->manufacturer.desc->ops->fixup_onfi_param_page)
+               chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);
+
        /* Check version */
        val = le16_to_cpu(p->revision);
-       if (val & (1 << 5))
-               chip->parameters.onfi.version = 23;
-       else if (val & (1 << 4))
-               chip->parameters.onfi.version = 22;
-       else if (val & (1 << 3))
-               chip->parameters.onfi.version = 21;
-       else if (val & (1 << 2))
-               chip->parameters.onfi.version = 20;
-       else if (val & (1 << 1))
-               chip->parameters.onfi.version = 10;
-
-       if (!chip->parameters.onfi.version) {
+       if (val & ONFI_VERSION_2_3)
+               onfi_version = 23;
+       else if (val & ONFI_VERSION_2_2)
+               onfi_version = 22;
+       else if (val & ONFI_VERSION_2_1)
+               onfi_version = 21;
+       else if (val & ONFI_VERSION_2_0)
+               onfi_version = 20;
+       else if (val & ONFI_VERSION_1_0)
+               onfi_version = 10;
+
+       if (!onfi_version) {
                pr_info("unsupported ONFI version: %d\n", val);
                goto free_onfi_param_page;
-       } else {
-               ret = 1;
        }
 
        sanitize_string(p->manufacturer, sizeof(p->manufacturer));
        sanitize_string(p->model, sizeof(p->model));
-       strncpy(chip->parameters.model, p->model,
-               sizeof(chip->parameters.model) - 1);
+       chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
+       if (!chip->parameters.model) {
+               ret = -ENOMEM;
+               goto free_onfi_param_page;
+       }
 
        mtd->writesize = le32_to_cpu(p->byte_per_page);
 
@@ -5219,7 +5257,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
        if (p->ecc_bits != 0xff) {
                chip->ecc_strength_ds = p->ecc_bits;
                chip->ecc_step_ds = 512;
-       } else if (chip->parameters.onfi.version >= 21 &&
+       } else if (onfi_version >= 21 &&
                (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
 
                /*
@@ -5246,19 +5284,33 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
                bitmap_set(chip->parameters.set_feature_list,
                           ONFI_FEATURE_ADDR_TIMING_MODE, 1);
        }
-       chip->parameters.onfi.tPROG = le16_to_cpu(p->t_prog);
-       chip->parameters.onfi.tBERS = le16_to_cpu(p->t_bers);
-       chip->parameters.onfi.tR = le16_to_cpu(p->t_r);
-       chip->parameters.onfi.tCCS = le16_to_cpu(p->t_ccs);
-       chip->parameters.onfi.async_timing_mode =
-               le16_to_cpu(p->async_timing_mode);
-       chip->parameters.onfi.vendor_revision =
-               le16_to_cpu(p->vendor_revision);
-       memcpy(chip->parameters.onfi.vendor, p->vendor,
-              sizeof(p->vendor));
 
+       onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
+       if (!onfi) {
+               ret = -ENOMEM;
+               goto free_model;
+       }
+
+       onfi->version = onfi_version;
+       onfi->tPROG = le16_to_cpu(p->t_prog);
+       onfi->tBERS = le16_to_cpu(p->t_bers);
+       onfi->tR = le16_to_cpu(p->t_r);
+       onfi->tCCS = le16_to_cpu(p->t_ccs);
+       onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
+       onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
+       memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
+       chip->parameters.onfi = onfi;
+
+       /* Identification done, free the full ONFI parameter page and exit */
+       kfree(p);
+
+       return 1;
+
+free_model:
+       kfree(chip->parameters.model);
 free_onfi_param_page:
        kfree(p);
+
        return ret;
 }
 
@@ -5321,8 +5373,11 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
 
        sanitize_string(p->manufacturer, sizeof(p->manufacturer));
        sanitize_string(p->model, sizeof(p->model));
-       strncpy(chip->parameters.model, p->model,
-               sizeof(chip->parameters.model) - 1);
+       chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
+       if (!chip->parameters.model) {
+               ret = -ENOMEM;
+               goto free_jedec_param_page;
+       }
 
        mtd->writesize = le32_to_cpu(p->byte_per_page);
 
@@ -5511,8 +5566,9 @@ static bool find_full_id_nand(struct nand_chip *chip,
                chip->onfi_timing_mode_default =
                                        type->onfi_timing_mode_default;
 
-               strncpy(chip->parameters.model, type->name,
-                       sizeof(chip->parameters.model) - 1);
+               chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
+               if (!chip->parameters.model)
+                       return false;
 
                return true;
        }
@@ -5651,7 +5707,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
                }
        }
 
-       chip->parameters.onfi.version = 0;
        if (!type->name || !type->pagesize) {
                /* Check if the chip is ONFI compliant */
                ret = nand_flash_detect_onfi(chip);
@@ -5671,8 +5726,9 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
        if (!type->name)
                return -ENODEV;
 
-       strncpy(chip->parameters.model, type->name,
-               sizeof(chip->parameters.model) - 1);
+       chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
+       if (!chip->parameters.model)
+               return -ENOMEM;
 
        chip->chipsize = (uint64_t)type->chipsize << 20;
 
@@ -5702,7 +5758,9 @@ ident_done:
                        mtd->name);
                pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
                        (chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
-               return -EINVAL;
+               ret = -EINVAL;
+
+               goto free_detect_allocation;
        }
 
        nand_decode_bbm_options(chip);
@@ -5739,6 +5797,11 @@ ident_done:
                (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
                mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
        return 0;
+
+free_detect_allocation:
+       kfree(chip->parameters.model);
+
+       return ret;
 }
 
 static const char * const nand_ecc_modes[] = {
@@ -5777,6 +5840,7 @@ static int of_get_nand_ecc_mode(struct device_node *np)
 static const char * const nand_ecc_algos[] = {
        [NAND_ECC_HAMMING]      = "hamming",
        [NAND_ECC_BCH]          = "bch",
+       [NAND_ECC_RS]           = "rs",
 };
 
 static int of_get_nand_ecc_algo(struct device_node *np)
@@ -5858,6 +5922,9 @@ static int nand_dt_init(struct nand_chip *chip)
        if (of_get_nand_bus_width(dn) == 16)
                chip->options |= NAND_BUSWIDTH_16;
 
+       if (of_property_read_bool(dn, "nand-is-boot-medium"))
+               chip->options |= NAND_IS_BOOT_MEDIUM;
+
        if (of_get_nand_on_flash_bbt(dn))
                chip->bbt_options |= NAND_BBT_USE_FLASH;
 
@@ -5885,7 +5952,7 @@ static int nand_dt_init(struct nand_chip *chip)
 }
 
 /**
- * nand_scan_ident - [NAND Interface] Scan for the NAND device
+ * nand_scan_ident - Scan for the NAND device
  * @mtd: MTD device structure
  * @maxchips: number of chips to scan for
  * @table: alternative NAND ID table
@@ -5893,9 +5960,13 @@ static int nand_dt_init(struct nand_chip *chip)
  * This is the first phase of the normal nand_scan() function. It reads the
  * flash ID and sets up MTD fields accordingly.
  *
+ * This helper used to be called directly from controller drivers that needed
+ * to tweak some ECC-related parameters before nand_scan_tail(). This separation
+ * prevented dynamic allocations during this phase which was unconvenient and
+ * as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks.
  */
-int nand_scan_ident(struct mtd_info *mtd, int maxchips,
-                   struct nand_flash_dev *table)
+static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+                          struct nand_flash_dev *table)
 {
        int i, nand_maf_id, nand_dev_id;
        struct nand_chip *chip = mtd_to_nand(mtd);
@@ -5969,7 +6040,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 
        return 0;
 }
-EXPORT_SYMBOL(nand_scan_ident);
+
+static void nand_scan_ident_cleanup(struct nand_chip *chip)
+{
+       kfree(chip->parameters.model);
+       kfree(chip->parameters.onfi);
+}
 
 static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
 {
@@ -6077,24 +6153,17 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
  * by the controller and the calculated ECC bytes fit within the chip's OOB.
  * On success, the calculated ECC bytes is set.
  */
-int nand_check_ecc_caps(struct nand_chip *chip,
-                       const struct nand_ecc_caps *caps, int oobavail)
+static int
+nand_check_ecc_caps(struct nand_chip *chip,
+                   const struct nand_ecc_caps *caps, int oobavail)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        const struct nand_ecc_step_info *stepinfo;
        int preset_step = chip->ecc.size;
        int preset_strength = chip->ecc.strength;
-       int nsteps, ecc_bytes;
+       int ecc_bytes, nsteps = mtd->writesize / preset_step;
        int i, j;
 
-       if (WARN_ON(oobavail < 0))
-               return -EINVAL;
-
-       if (!preset_step || !preset_strength)
-               return -ENODATA;
-
-       nsteps = mtd->writesize / preset_step;
-
        for (i = 0; i < caps->nstepinfos; i++) {
                stepinfo = &caps->stepinfos[i];
 
@@ -6127,7 +6196,6 @@ int nand_check_ecc_caps(struct nand_chip *chip,
 
        return -ENOTSUPP;
 }
-EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
 
 /**
  * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
@@ -6139,8 +6207,9 @@ EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
  * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
  * On success, the chosen ECC settings are set.
  */
-int nand_match_ecc_req(struct nand_chip *chip,
-                      const struct nand_ecc_caps *caps, int oobavail)
+static int
+nand_match_ecc_req(struct nand_chip *chip,
+                  const struct nand_ecc_caps *caps, int oobavail)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        const struct nand_ecc_step_info *stepinfo;
@@ -6151,9 +6220,6 @@ int nand_match_ecc_req(struct nand_chip *chip,
        int best_ecc_bytes_total = INT_MAX;
        int i, j;
 
-       if (WARN_ON(oobavail < 0))
-               return -EINVAL;
-
        /* No information provided by the NAND chip */
        if (!req_step || !req_strength)
                return -ENOTSUPP;
@@ -6212,7 +6278,6 @@ int nand_match_ecc_req(struct nand_chip *chip,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(nand_match_ecc_req);
 
 /**
  * nand_maximize_ecc - choose the max ECC strength available
@@ -6223,8 +6288,9 @@ EXPORT_SYMBOL_GPL(nand_match_ecc_req);
  * Choose the max ECC strength that is supported on the controller, and can fit
  * within the chip's OOB.  On success, the chosen ECC settings are set.
  */
-int nand_maximize_ecc(struct nand_chip *chip,
-                     const struct nand_ecc_caps *caps, int oobavail)
+static int
+nand_maximize_ecc(struct nand_chip *chip,
+                 const struct nand_ecc_caps *caps, int oobavail)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        const struct nand_ecc_step_info *stepinfo;
@@ -6234,9 +6300,6 @@ int nand_maximize_ecc(struct nand_chip *chip,
        int best_strength, best_ecc_bytes;
        int i, j;
 
-       if (WARN_ON(oobavail < 0))
-               return -EINVAL;
-
        for (i = 0; i < caps->nstepinfos; i++) {
                stepinfo = &caps->stepinfos[i];
                step_size = stepinfo->stepsize;
@@ -6285,7 +6348,44 @@ int nand_maximize_ecc(struct nand_chip *chip,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(nand_maximize_ecc);
+
+/**
+ * nand_ecc_choose_conf - Set the ECC strength and ECC step size
+ * @chip: nand chip info structure
+ * @caps: ECC engine caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * Choose the ECC configuration according to following logic
+ *
+ * 1. If both ECC step size and ECC strength are already set (usually by DT)
+ *    then check if it is supported by this controller.
+ * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
+ * 3. Otherwise, try to match the ECC step size and ECC strength closest
+ *    to the chip's requirement. If available OOB size can't fit the chip
+ *    requirement then fallback to the maximum ECC step size and ECC strength.
+ *
+ * On success, the chosen ECC settings are set.
+ */
+int nand_ecc_choose_conf(struct nand_chip *chip,
+                        const struct nand_ecc_caps *caps, int oobavail)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
+       if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize))
+               return -EINVAL;
+
+       if (chip->ecc.size && chip->ecc.strength)
+               return nand_check_ecc_caps(chip, caps, oobavail);
+
+       if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+               return nand_maximize_ecc(chip, caps, oobavail);
+
+       if (!nand_match_ecc_req(chip, caps, oobavail))
+               return 0;
+
+       return nand_maximize_ecc(chip, caps, oobavail);
+}
+EXPORT_SYMBOL_GPL(nand_ecc_choose_conf);
 
 /*
  * Check if the chip configuration meet the datasheet requirements.
@@ -6322,14 +6422,14 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
 }
 
 /**
- * nand_scan_tail - [NAND Interface] Scan for the NAND device
+ * nand_scan_tail - Scan for the NAND device
  * @mtd: MTD device structure
  *
  * This is the second phase of the normal nand_scan() function. It fills out
  * all the uninitialized function pointers with the defaults and scans for a
  * bad block table if appropriate.
  */
-int nand_scan_tail(struct mtd_info *mtd)
+static int nand_scan_tail(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -6636,7 +6736,7 @@ int nand_scan_tail(struct mtd_info *mtd)
                return 0;
 
        /* Build bad block table */
-       ret = chip->scan_bbt(mtd);
+       ret = nand_create_bbt(chip);
        if (ret)
                goto err_nand_manuf_cleanup;
 
@@ -6653,24 +6753,27 @@ err_free_buf:
 
        return ret;
 }
-EXPORT_SYMBOL(nand_scan_tail);
 
-/*
- * is_module_text_address() isn't exported, and it's mostly a pointless
- * test if this is a module _anyway_ -- they'd have to try _really_ hard
- * to call us from in-kernel code if the core NAND support is modular.
- */
-#ifdef MODULE
-#define caller_is_module() (1)
-#else
-#define caller_is_module() \
-       is_module_text_address((unsigned long)__builtin_return_address(0))
-#endif
+static int nand_attach(struct nand_chip *chip)
+{
+       if (chip->controller->ops && chip->controller->ops->attach_chip)
+               return chip->controller->ops->attach_chip(chip);
+
+       return 0;
+}
+
+static void nand_detach(struct nand_chip *chip)
+{
+       if (chip->controller->ops && chip->controller->ops->detach_chip)
+               chip->controller->ops->detach_chip(chip);
+}
 
 /**
  * nand_scan_with_ids - [NAND Interface] Scan for the NAND device
  * @mtd: MTD device structure
- * @maxchips: number of chips to scan for
+ * @maxchips: number of chips to scan for. @nand_scan_ident() will not be run if
+ *           this parameter is zero (useful for specific drivers that must
+ *           handle this part of the process themselves, e.g docg4).
  * @ids: optional flash IDs table
  *
  * This fills out all the uninitialized function pointers with the defaults.
@@ -6680,11 +6783,30 @@ EXPORT_SYMBOL(nand_scan_tail);
 int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
                       struct nand_flash_dev *ids)
 {
+       struct nand_chip *chip = mtd_to_nand(mtd);
        int ret;
 
-       ret = nand_scan_ident(mtd, maxchips, ids);
-       if (!ret)
-               ret = nand_scan_tail(mtd);
+       if (maxchips) {
+               ret = nand_scan_ident(mtd, maxchips, ids);
+               if (ret)
+                       return ret;
+       }
+
+       ret = nand_attach(chip);
+       if (ret)
+               goto cleanup_ident;
+
+       ret = nand_scan_tail(mtd);
+       if (ret)
+               goto detach_chip;
+
+       return 0;
+
+detach_chip:
+       nand_detach(chip);
+cleanup_ident:
+       nand_scan_ident_cleanup(chip);
+
        return ret;
 }
 EXPORT_SYMBOL(nand_scan_with_ids);
@@ -6712,7 +6834,14 @@ void nand_cleanup(struct nand_chip *chip)
 
        /* Free manufacturer priv data. */
        nand_manufacturer_cleanup(chip);
+
+       /* Free controller specific allocations after chip identification */
+       nand_detach(chip);
+
+       /* Free identification phase allocations */
+       nand_scan_ident_cleanup(chip);
 }
+
 EXPORT_SYMBOL_GPL(nand_cleanup);
 
 /**
index d9f4ceff25682f98e4143912ad80b1d6dfdb42a2..39db352f8757b77d50c4638505270af69677f9be 100644 (file)
@@ -1349,15 +1349,14 @@ static int nand_create_badblock_pattern(struct nand_chip *this)
 }
 
 /**
- * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
- * @mtd: MTD device structure
+ * nand_create_bbt - [NAND Interface] Select a default bad block table for the device
+ * @this: NAND chip object
  *
  * This function selects the default bad block table support for the device and
  * calls the nand_scan_bbt function.
  */
-int nand_default_bbt(struct mtd_info *mtd)
+int nand_create_bbt(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        int ret;
 
        /* Is a flash based bad block table requested? */
@@ -1383,8 +1382,9 @@ int nand_default_bbt(struct mtd_info *mtd)
                        return ret;
        }
 
-       return nand_scan_bbt(mtd, this->badblock_pattern);
+       return nand_scan_bbt(nand_to_mtd(this), this->badblock_pattern);
 }
+EXPORT_SYMBOL(nand_create_bbt);
 
 /**
  * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
index d542908a0ebb505994721f22ca7fa35f03ea55b9..4ffbb26e76d6dad05be6418c2ac31c091eae1b36 100644 (file)
@@ -100,6 +100,16 @@ static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
        struct mtd_info *mtd = nand_to_mtd(chip);
        u16 column = ((u16)addr << 8) | addr;
 
+       if (chip->exec_op) {
+               struct nand_op_instr instrs[] = {
+                       NAND_OP_ADDR(1, &addr, 0),
+                       NAND_OP_8BIT_DATA_OUT(1, &val, 0),
+               };
+               struct nand_operation op = NAND_OPERATION(instrs);
+
+               return nand_exec_op(chip, &op);
+       }
+
        chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
        chip->write_byte(mtd, val);
 
@@ -473,6 +483,19 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
                        WARN(1, "Invalid OOB size");
                        break;
                }
+
+               /*
+                * The datasheet of H27UCG8T2BTR mentions that the "Redundant
+                * Area Size" is encoded "per 8KB" (page size). This chip uses
+                * a page size of 16KiB. The datasheet mentions an OOB size of
+                * 1.280 bytes, but the OOB size encoded in the ID bytes (using
+                * the existing logic above) is 640 bytes.
+                * Update the OOB size for this chip by taking the value
+                * determined above and scaling it to the actual page size (so
+                * the actual OOB size for this chip is: 640 * 16k / 8k).
+                */
+               if (chip->id.data[1] == 0xde)
+                       mtd->oobsize *= mtd->writesize / SZ_8K;
        }
 }
 
index 5ec4c90a637d549a644441461ffc7717c623a4bc..f5dc0a7a2456325a92142ce0f4b537a7dcbbe79d 100644 (file)
  */
 
 #include <linux/mtd/rawnand.h>
+#include <linux/slab.h>
 
 /*
- * Special Micron status bit that indicates when the block has been
- * corrected by on-die ECC and should be rewritten
+ * Special Micron status bit 3 indicates that the block has been
+ * corrected by on-die ECC and should be rewritten.
  */
-#define NAND_STATUS_WRITE_RECOMMENDED  BIT(3)
+#define NAND_ECC_STATUS_WRITE_RECOMMENDED      BIT(3)
+
+/*
+ * On chips with 8-bit ECC and additional bit can be used to distinguish
+ * cases where a errors were corrected without needing a rewrite
+ *
+ * Bit 4 Bit 3 Bit 0 Description
+ * ----- ----- ----- -----------
+ * 0     0     0     No Errors
+ * 0     0     1     Multiple uncorrected errors
+ * 0     1     0     4 - 6 errors corrected, recommend rewrite
+ * 0     1     1     Reserved
+ * 1     0     0     1 - 3 errors corrected
+ * 1     0     1     Reserved
+ * 1     1     0     7 - 8 errors corrected, recommend rewrite
+ */
+#define NAND_ECC_STATUS_MASK           (BIT(4) | BIT(3) | BIT(0))
+#define NAND_ECC_STATUS_UNCORRECTABLE  BIT(0)
+#define NAND_ECC_STATUS_4_6_CORRECTED  BIT(3)
+#define NAND_ECC_STATUS_1_3_CORRECTED  BIT(4)
+#define NAND_ECC_STATUS_7_8_CORRECTED  (BIT(4) | BIT(3))
 
 struct nand_onfi_vendor_micron {
        u8 two_plane_read;
@@ -43,6 +64,16 @@ struct nand_onfi_vendor_micron {
        u8 param_revision;
 } __packed;
 
+struct micron_on_die_ecc {
+       bool forced;
+       bool enabled;
+       void *rawbuf;
+};
+
+struct micron_nand {
+       struct micron_on_die_ecc ecc;
+};
+
 static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
@@ -57,9 +88,10 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
 static int micron_nand_onfi_init(struct nand_chip *chip)
 {
        struct nand_parameters *p = &chip->parameters;
-       struct nand_onfi_vendor_micron *micron = (void *)p->onfi.vendor;
 
-       if (chip->parameters.onfi.version && p->onfi.vendor_revision) {
+       if (p->onfi) {
+               struct nand_onfi_vendor_micron *micron = (void *)p->onfi->vendor;
+
                chip->read_retries = micron->read_retry_options;
                chip->setup_read_retry = micron_nand_setup_read_retry;
        }
@@ -74,8 +106,9 @@ static int micron_nand_onfi_init(struct nand_chip *chip)
        return 0;
 }
 
-static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
-                                           struct mtd_oob_region *oobregion)
+static int micron_nand_on_die_4_ooblayout_ecc(struct mtd_info *mtd,
+                                             int section,
+                                             struct mtd_oob_region *oobregion)
 {
        if (section >= 4)
                return -ERANGE;
@@ -86,8 +119,9 @@ static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
        return 0;
 }
 
-static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
-                                            struct mtd_oob_region *oobregion)
+static int micron_nand_on_die_4_ooblayout_free(struct mtd_info *mtd,
+                                              int section,
+                                              struct mtd_oob_region *oobregion)
 {
        if (section >= 4)
                return -ERANGE;
@@ -98,19 +132,161 @@ static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
        return 0;
 }
 
-static const struct mtd_ooblayout_ops micron_nand_on_die_ooblayout_ops = {
-       .ecc = micron_nand_on_die_ooblayout_ecc,
-       .free = micron_nand_on_die_ooblayout_free,
+static const struct mtd_ooblayout_ops micron_nand_on_die_4_ooblayout_ops = {
+       .ecc = micron_nand_on_die_4_ooblayout_ecc,
+       .free = micron_nand_on_die_4_ooblayout_free,
+};
+
+static int micron_nand_on_die_8_ooblayout_ecc(struct mtd_info *mtd,
+                                             int section,
+                                             struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+
+       if (section)
+               return -ERANGE;
+
+       oobregion->offset = mtd->oobsize - chip->ecc.total;
+       oobregion->length = chip->ecc.total;
+
+       return 0;
+}
+
+static int micron_nand_on_die_8_ooblayout_free(struct mtd_info *mtd,
+                                              int section,
+                                              struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+
+       if (section)
+               return -ERANGE;
+
+       oobregion->offset = 2;
+       oobregion->length = mtd->oobsize - chip->ecc.total - 2;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops micron_nand_on_die_8_ooblayout_ops = {
+       .ecc = micron_nand_on_die_8_ooblayout_ecc,
+       .free = micron_nand_on_die_8_ooblayout_free,
 };
 
 static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
 {
+       struct micron_nand *micron = nand_get_manufacturer_data(chip);
        u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
+       int ret;
+
+       if (micron->ecc.forced)
+               return 0;
+
+       if (micron->ecc.enabled == enable)
+               return 0;
 
        if (enable)
                feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
 
-       return nand_set_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
+       ret = nand_set_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
+       if (!ret)
+               micron->ecc.enabled = enable;
+
+       return ret;
+}
+
+static int micron_nand_on_die_ecc_status_4(struct nand_chip *chip, u8 status,
+                                          void *buf, int page,
+                                          int oob_required)
+{
+       struct micron_nand *micron = nand_get_manufacturer_data(chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       unsigned int step, max_bitflips = 0;
+       int ret;
+
+       if (!(status & NAND_ECC_STATUS_WRITE_RECOMMENDED)) {
+               if (status & NAND_STATUS_FAIL)
+                       mtd->ecc_stats.failed++;
+
+               return 0;
+       }
+
+       /*
+        * The internal ECC doesn't tell us the number of bitflips that have
+        * been corrected, but tells us if it recommends to rewrite the block.
+        * If it's the case, we need to read the page in raw mode and compare
+        * its content to the corrected version to extract the actual number of
+        * bitflips.
+        * But before we do that, we must make sure we have all OOB bytes read
+        * in non-raw mode, even if the user did not request those bytes.
+        */
+       if (!oob_required) {
+               ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
+                                       false);
+               if (ret)
+                       return ret;
+       }
+
+       micron_nand_on_die_ecc_setup(chip, false);
+
+       ret = nand_read_page_op(chip, page, 0, micron->ecc.rawbuf,
+                               mtd->writesize + mtd->oobsize);
+       if (ret)
+               return ret;
+
+       for (step = 0; step < chip->ecc.steps; step++) {
+               unsigned int offs, i, nbitflips = 0;
+               u8 *rawbuf, *corrbuf;
+
+               offs = step * chip->ecc.size;
+               rawbuf = micron->ecc.rawbuf + offs;
+               corrbuf = buf + offs;
+
+               for (i = 0; i < chip->ecc.size; i++)
+                       nbitflips += hweight8(corrbuf[i] ^ rawbuf[i]);
+
+               offs = (step * 16) + 4;
+               rawbuf = micron->ecc.rawbuf + mtd->writesize + offs;
+               corrbuf = chip->oob_poi + offs;
+
+               for (i = 0; i < chip->ecc.bytes + 4; i++)
+                       nbitflips += hweight8(corrbuf[i] ^ rawbuf[i]);
+
+               if (WARN_ON(nbitflips > chip->ecc.strength))
+                       return -EINVAL;
+
+               max_bitflips = max(nbitflips, max_bitflips);
+               mtd->ecc_stats.corrected += nbitflips;
+       }
+
+       return max_bitflips;
+}
+
+static int micron_nand_on_die_ecc_status_8(struct nand_chip *chip, u8 status)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
+       /*
+        * With 8/512 we have more information but still don't know precisely
+        * how many bit-flips were seen.
+        */
+       switch (status & NAND_ECC_STATUS_MASK) {
+       case NAND_ECC_STATUS_UNCORRECTABLE:
+               mtd->ecc_stats.failed++;
+               return 0;
+       case NAND_ECC_STATUS_1_3_CORRECTED:
+               mtd->ecc_stats.corrected += 3;
+               return 3;
+       case NAND_ECC_STATUS_4_6_CORRECTED:
+               mtd->ecc_stats.corrected += 6;
+               /* rewrite recommended */
+               return 6;
+       case NAND_ECC_STATUS_7_8_CORRECTED:
+               mtd->ecc_stats.corrected += 8;
+               /* rewrite recommended */
+               return 8;
+       default:
+               return 0;
+       }
 }
 
 static int
@@ -137,24 +313,18 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
        if (ret)
                goto out;
 
-       if (status & NAND_STATUS_FAIL)
-               mtd->ecc_stats.failed++;
-
-       /*
-        * The internal ECC doesn't tell us the number of bitflips
-        * that have been corrected, but tells us if it recommends to
-        * rewrite the block. If it's the case, then we pretend we had
-        * a number of bitflips equal to the ECC strength, which will
-        * hint the NAND core to rewrite the block.
-        */
-       else if (status & NAND_STATUS_WRITE_RECOMMENDED)
-               max_bitflips = chip->ecc.strength;
-
        ret = nand_read_data_op(chip, buf, mtd->writesize, false);
        if (!ret && oob_required)
                ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
                                        false);
 
+       if (chip->ecc.strength == 4)
+               max_bitflips = micron_nand_on_die_ecc_status_4(chip, status,
+                                                              buf, page,
+                                                              oob_required);
+       else
+               max_bitflips = micron_nand_on_die_ecc_status_8(chip, status);
+
 out:
        micron_nand_on_die_ecc_setup(chip, false);
 
@@ -195,6 +365,9 @@ enum {
        MICRON_ON_DIE_MANDATORY,
 };
 
+#define MICRON_ID_INTERNAL_ECC_MASK    GENMASK(1, 0)
+#define MICRON_ID_ECC_ENABLED          BIT(7)
+
 /*
  * Try to detect if the NAND support on-die ECC. To do this, we enable
  * the feature, and read back if it has been enabled as expected. We
@@ -207,42 +380,52 @@ enum {
  */
 static int micron_supports_on_die_ecc(struct nand_chip *chip)
 {
-       u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
+       u8 id[5];
        int ret;
 
-       if (!chip->parameters.onfi.version)
+       if (!chip->parameters.onfi)
                return MICRON_ON_DIE_UNSUPPORTED;
 
        if (chip->bits_per_cell != 1)
                return MICRON_ON_DIE_UNSUPPORTED;
 
+       /*
+        * We only support on-die ECC of 4/512 or 8/512
+        */
+       if  (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8)
+               return MICRON_ON_DIE_UNSUPPORTED;
+
+       /* 0x2 means on-die ECC is available. */
+       if (chip->id.len != 5 ||
+           (chip->id.data[4] & MICRON_ID_INTERNAL_ECC_MASK) != 0x2)
+               return MICRON_ON_DIE_UNSUPPORTED;
+
        ret = micron_nand_on_die_ecc_setup(chip, true);
        if (ret)
                return MICRON_ON_DIE_UNSUPPORTED;
 
-       ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
-       if (ret < 0)
-               return ret;
+       ret = nand_readid_op(chip, 0, id, sizeof(id));
+       if (ret)
+               return MICRON_ON_DIE_UNSUPPORTED;
 
-       if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0)
+       if (!(id[4] & MICRON_ID_ECC_ENABLED))
                return MICRON_ON_DIE_UNSUPPORTED;
 
        ret = micron_nand_on_die_ecc_setup(chip, false);
        if (ret)
                return MICRON_ON_DIE_UNSUPPORTED;
 
-       ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
-       if (ret < 0)
-               return ret;
+       ret = nand_readid_op(chip, 0, id, sizeof(id));
+       if (ret)
+               return MICRON_ON_DIE_UNSUPPORTED;
 
-       if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN)
+       if (id[4] & MICRON_ID_ECC_ENABLED)
                return MICRON_ON_DIE_MANDATORY;
 
        /*
-        * Some Micron NANDs have an on-die ECC of 4/512, some other
-        * 8/512. We only support the former.
+        * We only support on-die ECC of 4/512 or 8/512
         */
-       if (chip->ecc_strength_ds != 4)
+       if  (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8)
                return MICRON_ON_DIE_UNSUPPORTED;
 
        return MICRON_ON_DIE_SUPPORTED;
@@ -251,44 +434,116 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
 static int micron_nand_init(struct nand_chip *chip)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
+       struct micron_nand *micron;
        int ondie;
        int ret;
 
+       micron = kzalloc(sizeof(*micron), GFP_KERNEL);
+       if (!micron)
+               return -ENOMEM;
+
+       nand_set_manufacturer_data(chip, micron);
+
        ret = micron_nand_onfi_init(chip);
        if (ret)
-               return ret;
+               goto err_free_manuf_data;
 
        if (mtd->writesize == 2048)
                chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
 
        ondie = micron_supports_on_die_ecc(chip);
 
-       if (ondie == MICRON_ON_DIE_MANDATORY) {
+       if (ondie == MICRON_ON_DIE_MANDATORY &&
+           chip->ecc.mode != NAND_ECC_ON_DIE) {
                pr_err("On-die ECC forcefully enabled, not supported\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_free_manuf_data;
        }
 
        if (chip->ecc.mode == NAND_ECC_ON_DIE) {
                if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
                        pr_err("On-die ECC selected but not supported\n");
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_free_manuf_data;
+               }
+
+               if (ondie == MICRON_ON_DIE_MANDATORY) {
+                       micron->ecc.forced = true;
+                       micron->ecc.enabled = true;
+               }
+
+               /*
+                * In case of 4bit on-die ECC, we need a buffer to store a
+                * page dumped in raw mode so that we can compare its content
+                * to the same page after ECC correction happened and extract
+                * the real number of bitflips from this comparison.
+                * That's not needed for 8-bit ECC, because the status expose
+                * a better approximation of the number of bitflips in a page.
+                */
+               if (chip->ecc_strength_ds == 4) {
+                       micron->ecc.rawbuf = kmalloc(mtd->writesize +
+                                                    mtd->oobsize,
+                                                    GFP_KERNEL);
+                       if (!micron->ecc.rawbuf) {
+                               ret = -ENOMEM;
+                               goto err_free_manuf_data;
+                       }
                }
 
-               chip->ecc.bytes = 8;
+               if (chip->ecc_strength_ds == 4)
+                       mtd_set_ooblayout(mtd,
+                                         &micron_nand_on_die_4_ooblayout_ops);
+               else
+                       mtd_set_ooblayout(mtd,
+                                         &micron_nand_on_die_8_ooblayout_ops);
+
+               chip->ecc.bytes = chip->ecc_strength_ds * 2;
                chip->ecc.size = 512;
-               chip->ecc.strength = 4;
+               chip->ecc.strength = chip->ecc_strength_ds;
                chip->ecc.algo = NAND_ECC_BCH;
                chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
                chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
-               chip->ecc.read_page_raw = nand_read_page_raw;
-               chip->ecc.write_page_raw = nand_write_page_raw;
 
-               mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops);
+               if (ondie == MICRON_ON_DIE_MANDATORY) {
+                       chip->ecc.read_page_raw = nand_read_page_raw_notsupp;
+                       chip->ecc.write_page_raw = nand_write_page_raw_notsupp;
+               } else {
+                       chip->ecc.read_page_raw = nand_read_page_raw;
+                       chip->ecc.write_page_raw = nand_write_page_raw;
+               }
        }
 
        return 0;
+
+err_free_manuf_data:
+       kfree(micron->ecc.rawbuf);
+       kfree(micron);
+
+       return ret;
+}
+
+static void micron_nand_cleanup(struct nand_chip *chip)
+{
+       struct micron_nand *micron = nand_get_manufacturer_data(chip);
+
+       kfree(micron->ecc.rawbuf);
+       kfree(micron);
+}
+
+static void micron_fixup_onfi_param_page(struct nand_chip *chip,
+                                        struct nand_onfi_params *p)
+{
+       /*
+        * MT29F1G08ABAFAWP-ITE:F and possibly others report 00 00 for the
+        * revision number field of the ONFI parameter page. Assume ONFI
+        * version 1.0 if the revision number is 00 00.
+        */
+       if (le16_to_cpu(p->revision) == 0)
+               p->revision = cpu_to_le16(ONFI_VERSION_1_0);
 }
 
 const struct nand_manufacturer_ops micron_nand_manuf_ops = {
        .init = micron_nand_init,
+       .cleanup = micron_nand_cleanup,
+       .fixup_onfi_param_page = micron_fixup_onfi_param_page,
 };
index 7c4e4a371bbc586a07b28ea087f62ddf881dae96..ebc7b5f76f77b26f3971047f378e319de9749d43 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/export.h>
 #include <linux/mtd/rawnand.h>
 
+#define ONFI_DYN_TIMING_MAX U16_MAX
+
 static const struct nand_data_interface onfi_sdr_timings[] = {
 &