Merge tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Oct 2018 00:09:22 +0000 (01:09 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Oct 2018 00:09:22 +0000 (01:09 +0100)
Pull mtd updates from Boris Brezillon:
 "SPI NOR core changes:
   - Support non-uniform erase size
   - Support controllers with limited TX fifo size

 Driver changes:
   - m25p80: Re-issue a WREN command after each write access
   - cadence: Pass a proper dir value to dma_[un]map_single()
   - fsl-qspi: Check fsl_qspi_get_seqid() return val make sure 4B
     addressing opcodes are properly handled
   - intel-spi: Add a new PCI entry for Ice Lake

 Raw NAND core changes:
   - Two batchs of cleanups of the NAND API, including:
      * Deprecating a lot of interfaces (now replaced by ->exec_op()).
      * Moving code in separate drivers (JEDEC, ONFI), in private files
        (internals), in platform drivers, etc.
      * Functions/structures reordering.
      * Exclusive use of the nand_chip structure instead of the MTD one
        all across the subsystem.
   - Addition of the nand_wait_readrdy/rdy_op() helpers.

 Raw NAND controllers drivers changes:
   - Various coccinelle patches.
   - Marvell:
      * Use regmap_update_bits() for syscon access.
      * More documentation.
      * BCH failure path rework.
      * More layouts to be supported.
      * IRQ handler complete() condition fixed.
   - Fsl_ifc:
      * SRAM initialization fixed for newer controller versions.
   - Denali:
      * Fix licenses mismatch and use a SPDX tag.
      * Set SPARE_AREA_SKIP_BYTES register to 8 if unset.
   - Qualcomm:
      * Do not include dma-direct.h.
   - Docg4:
      * Removed.
   - Ams-delta:
      * Use of a GPIO lookup table
      * Internal machinery changes.

 Raw NAND chip drivers changes:
   - Toshiba:
      * Add support for Toshiba memory BENAND
      * Pass a single nand_chip object to the status helper.
   - ESMT:
      * New driver to retrieve the ECC requirements from the 5th ID
        byte.

  MTD changes:
   - physmap cleanups/fixe
   - gpio-addr-flash cleanups/fixes"

* tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd: (93 commits)
  jffs2: free jffs2_sb_info through jffs2_kill_sb()
  mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
  mtd: spi-nor: intel-spi: Add support for Intel Ice Lake SPI serial flash
  mtd: maps: gpio-addr-flash: Convert to gpiod
  mtd: maps: gpio-addr-flash: Replace array with an integer
  mtd: maps: gpio-addr-flash: Use order instead of size
  mtd: spi-nor: fsl-quadspi: Don't let -EINVAL on the bus
  mtd: devices: m25p80: Make sure WRITE_EN is issued before each write
  mtd: spi-nor: Support controllers with limited TX FIFO size
  mtd: spi-nor: cadence-quadspi: Use proper enum for dma_[un]map_single
  mtd: spi-nor: parse SFDP Sector Map Parameter Table
  mtd: spi-nor: add support to non-uniform SFDP SPI NOR flash memories
  mtd: rawnand: marvell: fix the IRQ handler complete() condition
  mtd: rawnand: denali: set SPARE_AREA_SKIP_BYTES register to 8 if unset
  mtd: rawnand: r852: fix spelling mistake "card_registred" -> "card_registered"
  mtd: rawnand: toshiba: Pass a single nand_chip object to the status helper
  mtd: maps: gpio-addr-flash: Use devm_* functions
  mtd: maps: gpio-addr-flash: Fix ioremapped size
  mtd: maps: gpio-addr-flash: Replace custom printk
  mtd: physmap_of: Release resources on error
  ...

119 files changed:
Documentation/driver-api/mtdnand.rst
Documentation/mtd/nand/pxa3xx-nand.txt [deleted file]
arch/arm/mach-ep93xx/snappercl15.c
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-imx/mach-qong.c
arch/arm/mach-ixp4xx/ixdp425-setup.c
arch/arm/mach-omap1/board-fsample.c
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-nand.c
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/common.h
arch/arm/mach-orion5x/ts78xx-setup.c
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/palmtreo.c
arch/arm/mach-pxa/palmtx.c
arch/mips/alchemy/devboards/db1200.c
arch/mips/alchemy/devboards/db1300.c
arch/mips/alchemy/devboards/db1550.c
arch/mips/netlogic/xlr/platform-flash.c
arch/mips/pnx833x/common/platform.c
arch/mips/rb532/devices.c
arch/sh/boards/mach-migor/setup.c
drivers/mtd/devices/m25p80.c
drivers/mtd/maps/gpio-addr-flash.c
drivers/mtd/maps/physmap_of_core.c
drivers/mtd/maps/physmap_of_gemini.c
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/Makefile
drivers/mtd/nand/raw/ams-delta.c
drivers/mtd/nand/raw/atmel/nand-controller.c
drivers/mtd/nand/raw/au1550nd.c
drivers/mtd/nand/raw/bcm47xxnflash/main.c
drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.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 [deleted file]
drivers/mtd/nand/raw/fsl_elbc_nand.c
drivers/mtd/nand/raw/fsl_ifc_nand.c
drivers/mtd/nand/raw/fsl_upm.c
drivers/mtd/nand/raw/fsmc_nand.c
drivers/mtd/nand/raw/gpio.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-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/internals.h [new file with mode: 0644]
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/mpc5121_nfc.c
drivers/mtd/nand/raw/mtk_nand.c
drivers/mtd/nand/raw/mxc_nand.c
drivers/mtd/nand/raw/nand_amd.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/nand_bbt.c
drivers/mtd/nand/raw/nand_bch.c
drivers/mtd/nand/raw/nand_ecc.c
drivers/mtd/nand/raw/nand_esmt.c [new file with mode: 0644]
drivers/mtd/nand/raw/nand_hynix.c
drivers/mtd/nand/raw/nand_ids.c
drivers/mtd/nand/raw/nand_jedec.c [new file with mode: 0644]
drivers/mtd/nand/raw/nand_legacy.c [new file with mode: 0644]
drivers/mtd/nand/raw/nand_macronix.c
drivers/mtd/nand/raw/nand_micron.c
drivers/mtd/nand/raw/nand_onfi.c [new file with mode: 0644]
drivers/mtd/nand/raw/nand_samsung.c
drivers/mtd/nand/raw/nand_timings.c
drivers/mtd/nand/raw/nand_toshiba.c
drivers/mtd/nand/raw/nandsim.c
drivers/mtd/nand/raw/ndfc.c
drivers/mtd/nand/raw/nuc900_nand.c
drivers/mtd/nand/raw/omap2.c
drivers/mtd/nand/raw/orion_nand.c
drivers/mtd/nand/raw/oxnas_nand.c
drivers/mtd/nand/raw/pasemi_nand.c
drivers/mtd/nand/raw/plat_nand.c
drivers/mtd/nand/raw/qcom_nandc.c
drivers/mtd/nand/raw/r852.c
drivers/mtd/nand/raw/r852.h
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/socrates_nand.c
drivers/mtd/nand/raw/sunxi_nand.c
drivers/mtd/nand/raw/tango_nand.c
drivers/mtd/nand/raw/tegra_nand.c
drivers/mtd/nand/raw/tmio_nand.c
drivers/mtd/nand/raw/txx9ndfmc.c
drivers/mtd/nand/raw/vf610_nfc.c
drivers/mtd/nand/raw/xway_nand.c
drivers/mtd/sm_ftl.c
drivers/mtd/spi-nor/cadence-quadspi.c
drivers/mtd/spi-nor/fsl-quadspi.c
drivers/mtd/spi-nor/intel-spi-pci.c
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/tests/mtd_nandecctest.c
drivers/staging/mt29f_spinand/mt29f_spinand.c
fs/jffs2/super.c
include/linux/fsl_ifc.h
include/linux/mtd/jedec.h [new file with mode: 0644]
include/linux/mtd/nand_bch.h
include/linux/mtd/nand_ecc.h
include/linux/mtd/onfi.h [new file with mode: 0644]
include/linux/mtd/platnand.h [new file with mode: 0644]
include/linux/mtd/rawnand.h
include/linux/mtd/spi-nor.h

index c55a6034c397d4e12fc80d064c3f730bc079cdc1..55447659b81fa41b9bcfac13402109ffc421e9ad 100644 (file)
@@ -180,10 +180,10 @@ by a chip select decoder.
     {
         struct nand_chip *this = mtd_to_nand(mtd);
         switch(cmd){
-            case NAND_CTL_SETCLE: this->IO_ADDR_W |= CLE_ADRR_BIT;  break;
-            case NAND_CTL_CLRCLE: this->IO_ADDR_W &= ~CLE_ADRR_BIT; break;
-            case NAND_CTL_SETALE: this->IO_ADDR_W |= ALE_ADRR_BIT;  break;
-            case NAND_CTL_CLRALE: this->IO_ADDR_W &= ~ALE_ADRR_BIT; break;
+            case NAND_CTL_SETCLE: this->legacy.IO_ADDR_W |= CLE_ADRR_BIT;  break;
+            case NAND_CTL_CLRCLE: this->legacy.IO_ADDR_W &= ~CLE_ADRR_BIT; break;
+            case NAND_CTL_SETALE: this->legacy.IO_ADDR_W |= ALE_ADRR_BIT;  break;
+            case NAND_CTL_CLRALE: this->legacy.IO_ADDR_W &= ~ALE_ADRR_BIT; break;
         }
     }
 
@@ -197,7 +197,7 @@ to read back the state of the pin. The function has no arguments and
 should return 0, if the device is busy (R/B pin is low) and 1, if the
 device is ready (R/B pin is high). If the hardware interface does not
 give access to the ready busy pin, then the function must not be defined
-and the function pointer this->dev_ready is set to NULL.
+and the function pointer this->legacy.dev_ready is set to NULL.
 
 Init function
 -------------
@@ -235,18 +235,18 @@ necessary information about the device.
         }
 
         /* Set address of NAND IO lines */
-        this->IO_ADDR_R = baseaddr;
-        this->IO_ADDR_W = baseaddr;
+        this->legacy.IO_ADDR_R = baseaddr;
+        this->legacy.IO_ADDR_W = baseaddr;
         /* Reference hardware control function */
         this->hwcontrol = board_hwcontrol;
         /* Set command delay time, see datasheet for correct value */
-        this->chip_delay = CHIP_DEPENDEND_COMMAND_DELAY;
+        this->legacy.chip_delay = CHIP_DEPENDEND_COMMAND_DELAY;
         /* Assign the device ready function, if available */
-        this->dev_ready = board_dev_ready;
+        this->legacy.dev_ready = board_dev_ready;
         this->eccmode = NAND_ECC_SOFT;
 
         /* Scan to find existence of the device */
-        if (nand_scan (board_mtd, 1)) {
+        if (nand_scan (this, 1)) {
             err = -ENXIO;
             goto out_ior;
         }
@@ -277,7 +277,7 @@ unregisters the partitions in the MTD layer.
     static void __exit board_cleanup (void)
     {
         /* Release resources, unregister device */
-        nand_release (board_mtd);
+        nand_release (mtd_to_nand(board_mtd));
 
         /* unmap physical address */
         iounmap(baseaddr);
@@ -336,17 +336,17 @@ connected to an address decoder.
         struct nand_chip *this = mtd_to_nand(mtd);
 
         /* Deselect all chips */
-        this->IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK;
-        this->IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK;
+        this->legacy.IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK;
+        this->legacy.IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK;
         switch (chip) {
         case 0:
-            this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0;
-            this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIP0;
+            this->legacy.IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0;
+            this->legacy.IO_ADDR_W |= BOARD_NAND_ADDR_CHIP0;
             break;
         ....
         case n:
-            this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIPn;
-            this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIPn;
+            this->legacy.IO_ADDR_R |= BOARD_NAND_ADDR_CHIPn;
+            this->legacy.IO_ADDR_W |= BOARD_NAND_ADDR_CHIPn;
             break;
         }
     }
diff --git a/Documentation/mtd/nand/pxa3xx-nand.txt b/Documentation/mtd/nand/pxa3xx-nand.txt
deleted file mode 100644 (file)
index 1074cbc..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-
-About this document
-===================
-
-Some notes about Marvell's NAND controller available in PXA and Armada 370/XP
-SoC (aka NFCv1 and NFCv2), with an emphasis on the latter.
-
-NFCv2 controller background
-===========================
-
-The controller has a 2176 bytes FIFO buffer. Therefore, in order to support
-larger pages, I/O operations on 4 KiB and 8 KiB pages is done with a set of
-chunked transfers.
-
-For instance, if we choose a 2048 data chunk and set "BCH" ECC (see below)
-we'll have this layout in the pages:
-
-  ------------------------------------------------------------------------------
-  | 2048B data | 32B spare | 30B ECC || 2048B data | 32B spare | 30B ECC | ... |
-  ------------------------------------------------------------------------------
-
-The driver reads the data and spare portions independently and builds an internal
-buffer with this layout (in the 4 KiB page case):
-
-  ------------------------------------------
-  |     4096B data     |     64B spare     |
-  ------------------------------------------
-
-Also, for the READOOB command the driver disables the ECC and reads a 'spare + ECC'
-OOB, one per chunk read.
-
-  -------------------------------------------------------------------
-  |     4096B data     |  32B spare | 30B ECC | 32B spare | 30B ECC |
-  -------------------------------------------------------------------
-
-So, in order to achieve reading (for instance), we issue several READ0 commands
-(with some additional controller-specific magic) and read two chunks of 2080B
-(2048 data + 32 spare) each.
-The driver accommodates this data to expose the NAND core a contiguous buffer
-(4096 data + spare) or (4096 + spare + ECC + spare + ECC).
-
-ECC
-===
-
-The controller has built-in hardware ECC capabilities. In addition it is
-configurable between two modes: 1) Hamming, 2) BCH.
-
-Note that the actual BCH mode: BCH-4 or BCH-8 will depend on the way
-the controller is configured to transfer the data.
-
-In the BCH mode the ECC code will be calculated for each transferred chunk
-and expected to be located (when reading/programming) right after the spare
-bytes as the figure above shows.
-
-So, repeating the above scheme, a 2048B data chunk will be followed by 32B
-spare, and then the ECC controller will read/write the ECC code (30B in
-this case):
-
-  ------------------------------------
-  | 2048B data | 32B spare | 30B ECC |
-  ------------------------------------
-
-If the ECC mode is 'BCH' then the ECC is *always* 30 bytes long.
-If the ECC mode is 'Hamming' the ECC is 6 bytes long, for each 512B block.
-So in Hamming mode, a 2048B page will have a 24B ECC.
-
-Despite all of the above, the controller requires the driver to only read or
-write in multiples of 8-bytes, because the data buffer is 64-bits.
-
-OOB
-===
-
-Because of the above scheme, and because the "spare" OOB is really located in
-the middle of a page, spare OOB cannot be read or write independently of the
-data area. In other words, in order to read the OOB (aka READOOB), the entire
-page (aka READ0) has to be read.
-
-In the same sense, in order to write to the spare OOB the driver has to write
-an *entire* page.
-
-Factory bad blocks handling
-===========================
-
-Given the ECC BCH requires to layout the device's pages in a split
-data/OOB/data/OOB way, the controller has a view of the flash page that's
-different from the specified (aka the manufacturer's) view. In other words,
-
-Factory view:
-
-  -----------------------------------------------
-  |                    Data           |x  OOB   |
-  -----------------------------------------------
-
-Driver's view:
-
-  -----------------------------------------------
-  |      Data      | OOB |      Data   x  | OOB |
-  -----------------------------------------------
-
-It can be seen from the above, that the factory bad block marker must be
-searched within the 'data' region, and not in the usual OOB region.
-
-In addition, this means under regular usage the driver will write such
-position (since it belongs to the data region) and every used block is
-likely to be marked as bad.
-
-For this reason, marking the block as bad in the OOB is explicitly
-disabled by using the NAND_BBT_NO_OOB_BBM option in the driver. The rationale
-for this is that there's no point in marking a block as bad, because good
-blocks are also 'marked as bad' (in the OOB BBM sense) under normal usage.
-
-Instead, the driver relies on the bad block table alone, and should only perform
-the bad block scan on the very first time (when the device hasn't been used).
index 45940c1d778789f3b76a5e465c787ab05b22682f..cf0cb58b3454009d6d41fbf1c5d0431674dca5e9 100644 (file)
@@ -23,8 +23,7 @@
 #include <linux/i2c.h>
 #include <linux/fb.h>
 
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/rawnand.h>
+#include <linux/mtd/platnand.h>
 
 #include <mach/hardware.h>
 #include <linux/platform_data/video-ep93xx.h>
 #define SNAPPERCL15_NAND_CEN   (1 << 11) /* Chip enable (active low) */
 #define SNAPPERCL15_NAND_RDY   (1 << 14) /* Device ready */
 
-#define NAND_CTRL_ADDR(chip)   (chip->IO_ADDR_W + 0x40)
+#define NAND_CTRL_ADDR(chip)   (chip->legacy.IO_ADDR_W + 0x40)
 
-static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void snappercl15_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
                                      unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        static u16 nand_state = SNAPPERCL15_NAND_WPN;
        u16 set;
 
@@ -70,13 +68,12 @@ static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
        }
 
        if (cmd != NAND_CMD_NONE)
-               __raw_writew((cmd & 0xff) | nand_state, chip->IO_ADDR_W);
+               __raw_writew((cmd & 0xff) | nand_state,
+                            chip->legacy.IO_ADDR_W);
 }
 
-static int snappercl15_nand_dev_ready(struct mtd_info *mtd)
+static int snappercl15_nand_dev_ready(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        return !!(__raw_readw(NAND_CTRL_ADDR(chip)) & SNAPPERCL15_NAND_RDY);
 }
 
index c089a2a4fe307150a3b4066b9bc7447aae8788bd..c6a533699b003bda6842daacc27a0fa320c63a9f 100644 (file)
@@ -16,8 +16,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/spi/mmc_spi.h>
@@ -76,13 +75,11 @@ static void __init ts72xx_map_io(void)
 #define TS72XX_NAND_CONTROL_ADDR_LINE  22      /* 0xN0400000 */
 #define TS72XX_NAND_BUSY_ADDR_LINE     23      /* 0xN0800000 */
 
-static void ts72xx_nand_hwcontrol(struct mtd_info *mtd,
+static void ts72xx_nand_hwcontrol(struct nand_chip *chip,
                                  int cmd, unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        if (ctrl & NAND_CTRL_CHANGE) {
-               void __iomem *addr = chip->IO_ADDR_R;
+               void __iomem *addr = chip->legacy.IO_ADDR_R;
                unsigned char bits;
 
                addr += (1 << TS72XX_NAND_CONTROL_ADDR_LINE);
@@ -96,13 +93,12 @@ static void ts72xx_nand_hwcontrol(struct mtd_info *mtd,
        }
 
        if (cmd != NAND_CMD_NONE)
-               __raw_writeb(cmd, chip->IO_ADDR_W);
+               __raw_writeb(cmd, chip->legacy.IO_ADDR_W);
 }
 
-static int ts72xx_nand_device_ready(struct mtd_info *mtd)
+static int ts72xx_nand_device_ready(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       void __iomem *addr = chip->IO_ADDR_R;
+       void __iomem *addr = chip->legacy.IO_ADDR_R;
 
        addr += (1 << TS72XX_NAND_BUSY_ADDR_LINE);
 
index 42a700053103ebf57b9682a5e6dc9da05629d8a7..5c5df8ca38dd92eb179ebad5879506797d5a3b7f 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/memory.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mtd/rawnand.h>
+#include <linux/mtd/platnand.h>
 #include <linux/gpio.h>
 
 #include <asm/mach-types.h>
@@ -129,30 +129,29 @@ static void qong_init_nor_mtd(void)
 /*
  * Hardware specific access to control-lines
  */
-static void qong_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void qong_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
+                              unsigned int ctrl)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
-
        if (cmd == NAND_CMD_NONE)
                return;
 
        if (ctrl & NAND_CLE)
-               writeb(cmd, nand_chip->IO_ADDR_W + (1 << 24));
+               writeb(cmd, nand_chip->legacy.IO_ADDR_W + (1 << 24));
        else
-               writeb(cmd, nand_chip->IO_ADDR_W + (1 << 23));
+               writeb(cmd, nand_chip->legacy.IO_ADDR_W + (1 << 23));
 }
 
 /*
  * Read the Device Ready pin.
  */
-static int qong_nand_device_ready(struct mtd_info *mtd)
+static int qong_nand_device_ready(struct nand_chip *chip)
 {
        return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_NFRB));
 }
 
-static void qong_nand_select_chip(struct mtd_info *mtd, int chip)
+static void qong_nand_select_chip(struct nand_chip *chip, int cs)
 {
-       if (chip >= 0)
+       if (cs >= 0)
                gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 0);
        else
                gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 1);
index 3ec829d52cdd2143a76113f9380cd54696b23395..57d7df79d8389b8373d1e0c24a3133f26ba70643 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <asm/types.h>
@@ -75,9 +76,8 @@ static struct mtd_partition ixdp425_partitions[] = {
 };
 
 static void
-ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+ixdp425_flash_nand_cmd_ctrl(struct nand_chip *this, int cmd, unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        int offset = (int)nand_get_controller_data(this);
 
        if (ctrl & NAND_CTRL_CHANGE) {
@@ -93,7 +93,7 @@ ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
        }
 
        if (cmd != NAND_CMD_NONE)
-               writeb(cmd, this->IO_ADDR_W + offset);
+               writeb(cmd, this->legacy.IO_ADDR_W + offset);
 }
 
 static struct platform_nand_data ixdp425_flash_nand_data = {
index 69bd601feb83d8ff04e1b8f6bbf24bc3fd86b217..4a0a66815ca0059e39183394a1c73b987e5b9650 100644 (file)
@@ -16,8 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
 #include <linux/smc91x.h>
@@ -186,7 +185,7 @@ static struct platform_device nor_device = {
 
 #define FSAMPLE_NAND_RB_GPIO_PIN       62
 
-static int nand_dev_ready(struct mtd_info *mtd)
+static int nand_dev_ready(struct nand_chip *chip)
 {
        return gpio_get_value(FSAMPLE_NAND_RB_GPIO_PIN);
 }
index 9aeb8ad8c3270cb5761f2a82408f2ba96e9c1a63..9d9a6ca15df0d49728bd625518bd6f3862db4d44 100644 (file)
@@ -24,8 +24,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
 #include <linux/mfd/tps65010.h>
@@ -182,7 +181,7 @@ static struct mtd_partition h2_nand_partitions[] = {
 
 #define H2_NAND_RB_GPIO_PIN    62
 
-static int h2_nand_dev_ready(struct mtd_info *mtd)
+static int h2_nand_dev_ready(struct nand_chip *chip)
 {
        return gpio_get_value(H2_NAND_RB_GPIO_PIN);
 }
index 2edcd6356f2d635011d55b1e77f04ef44aa1cd13..cd6e02c5c01a35a1b8235cbcaa8f70c038cd36da 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
+#include <linux/mtd/platnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
@@ -185,7 +185,7 @@ static struct mtd_partition nand_partitions[] = {
 
 #define H3_NAND_RB_GPIO_PIN    10
 
-static int nand_dev_ready(struct mtd_info *mtd)
+static int nand_dev_ready(struct nand_chip *chip)
 {
        return gpio_get_value(H3_NAND_RB_GPIO_PIN);
 }
index 1bffbb4e050f2c1823cfaa18c7829deecad3c634..20923eb2d9b6bae15efebce2b9971429d568b822 100644 (file)
@@ -20,9 +20,8 @@
 
 #include "common.h"
 
-void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+void omap1_nand_cmd_ctl(struct nand_chip *this, int cmd, unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        unsigned long mask;
 
        if (cmd == NAND_CMD_NONE)
@@ -32,6 +31,6 @@ void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
        if (ctrl & NAND_ALE)
                mask |= 0x04;
 
-       writeb(cmd, this->IO_ADDR_W + mask);
+       writeb(cmd, this->legacy.IO_ADDR_W + mask);
 }
 
index b4951eb8289884549bb67f00e5a17bf8a05cab5e..06a584fef5b86ff05e72eae73459aa29cb65d81a 100644 (file)
@@ -16,8 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
 #include <linux/smc91x.h>
@@ -144,7 +143,7 @@ static struct platform_device nor_device = {
 
 #define P2_NAND_RB_GPIO_PIN    62
 
-static int nand_dev_ready(struct mtd_info *mtd)
+static int nand_dev_ready(struct nand_chip *chip)
 {
        return gpio_get_value(P2_NAND_RB_GPIO_PIN);
 }
index c6537d2c28597ac1f8296322085d591198d508f4..504b959ba5cfc8378bd54caf9d11bcb8a86591e3 100644 (file)
@@ -26,7 +26,6 @@
 #ifndef __ARCH_ARM_MACH_OMAP1_COMMON_H
 #define __ARCH_ARM_MACH_OMAP1_COMMON_H
 
-#include <linux/mtd/mtd.h>
 #include <linux/platform_data/i2c-omap.h>
 #include <linux/reboot.h>
 
@@ -82,7 +81,8 @@ void omap1_restart(enum reboot_mode, const char *);
 
 extern void __init omap_check_revision(void);
 
-extern void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
+struct nand_chip;
+extern void omap1_nand_cmd_ctl(struct nand_chip *this, int cmd,
                               unsigned int ctrl);
 
 extern void omap1_timer_init(void);
index 94778739e38f0cbf85535525c478a19b2c12fbad..fda9b75c3a333678518b235b0ff0ddfb888eedec 100644 (file)
@@ -16,8 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/timeriomem-rng.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -131,11 +130,9 @@ static void ts78xx_ts_rtc_unload(void)
  * NAND_CLE: bit 1 -> bit 1
  * NAND_ALE: bit 2 -> bit 0
  */
-static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-                       unsigned int ctrl)
+static void ts78xx_ts_nand_cmd_ctrl(struct nand_chip *this, int cmd,
+                                   unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-
        if (ctrl & NAND_CTRL_CHANGE) {
                unsigned char bits;
 
@@ -147,19 +144,18 @@ static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
        }
 
        if (cmd != NAND_CMD_NONE)
-               writeb(cmd, this->IO_ADDR_W);
+               writeb(cmd, this->legacy.IO_ADDR_W);
 }
 
-static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
+static int ts78xx_ts_nand_dev_ready(struct nand_chip *chip)
 {
        return readb(TS_NAND_CTRL) & 0x20;
 }
 
-static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
-                       const uint8_t *buf, int len)
+static void ts78xx_ts_nand_write_buf(struct nand_chip *chip,
+                                    const uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       void __iomem *io_base = chip->IO_ADDR_W;
+       void __iomem *io_base = chip->legacy.IO_ADDR_W;
        unsigned long off = ((unsigned long)buf & 3);
        int sz;
 
@@ -182,11 +178,10 @@ static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
                writesb(io_base, buf, len);
 }
 
-static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
-                       uint8_t *buf, int len)
+static void ts78xx_ts_nand_read_buf(struct nand_chip *chip,
+                                   uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       void __iomem *io_base = chip->IO_ADDR_R;
+       void __iomem *io_base = chip->legacy.IO_ADDR_R;
        unsigned long off = ((unsigned long)buf & 3);
        int sz;
 
index af46d21825331ea5662a8aa042e814c93070f5e8..c52c081eb6d9dcbc8db7f49df5ce4f8b59f05b3b 100644 (file)
 #include <linux/ioport.h>
 #include <linux/ucb1400.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
 #include <linux/types.h>
 #include <linux/platform_data/pcf857x.h>
 #include <linux/platform_data/i2c-pxa.h>
-#include <linux/mtd/rawnand.h>
+#include <linux/mtd/platnand.h>
 #include <linux/mtd/physmap.h>
 #include <linux/regulator/max1586.h>
 
@@ -571,9 +570,9 @@ static inline void balloon3_i2c_init(void) {}
  * NAND
  ******************************************************************************/
 #if defined(CONFIG_MTD_NAND_PLATFORM)||defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
-static void balloon3_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void balloon3_nand_cmd_ctl(struct nand_chip *this, int cmd,
+                                 unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        uint8_t balloon3_ctl_set = 0, balloon3_ctl_clr = 0;
 
        if (ctrl & NAND_CTRL_CHANGE) {
@@ -597,10 +596,10 @@ static void balloon3_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ct
        }
 
        if (cmd != NAND_CMD_NONE)
-               writeb(cmd, this->IO_ADDR_W);
+               writeb(cmd, this->legacy.IO_ADDR_W);
 }
 
-static void balloon3_nand_select_chip(struct mtd_info *mtd, int chip)
+static void balloon3_nand_select_chip(struct nand_chip *this, int chip)
 {
        if (chip < 0 || chip > 3)
                return;
@@ -616,7 +615,7 @@ static void balloon3_nand_select_chip(struct mtd_info *mtd, int chip)
                BALLOON3_NAND_CONTROL_REG);
 }
 
-static int balloon3_nand_dev_ready(struct mtd_info *mtd)
+static int balloon3_nand_dev_ready(struct nand_chip *this)
 {
        return __raw_readl(BALLOON3_NAND_STAT_REG) & BALLOON3_NAND_STAT_RNB;
 }
index 29be04c6cc4858f3e93b73a8083643578cbc51bc..c30d20e1fb7a1ca60c7d58c8fa61feccbd76deac 100644 (file)
@@ -15,8 +15,7 @@
 
 #include <linux/dm9000.h>
 #include <linux/platform_data/rtc-v3020.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/mtd/physmap.h>
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
@@ -285,11 +284,10 @@ static void nand_cs_off(void)
 }
 
 /* hardware specific access to control-lines */
-static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat,
+static void em_x270_nand_cmd_ctl(struct nand_chip *this, int dat,
                                 unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
+       unsigned long nandaddr = (unsigned long)this->legacy.IO_ADDR_W;
 
        dsb();
 
@@ -309,15 +307,15 @@ static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat,
        }
 
        dsb();
-       this->IO_ADDR_W = (void __iomem *)nandaddr;
+       this->legacy.IO_ADDR_W = (void __iomem *)nandaddr;
        if (dat != NAND_CMD_NONE)
-               writel(dat, this->IO_ADDR_W);
+               writel(dat, this->legacy.IO_ADDR_W);
 
        dsb();
 }
 
 /* read device ready pin */
-static int em_x270_nand_device_ready(struct mtd_info *mtd)
+static int em_x270_nand_device_ready(struct nand_chip *this)
 {
        dsb();
 
index 4cc05ecce6181755b2bb77b3e37589e0fcad3b35..b66b0b11d7172f4ad0e3db9e4a3fc80f0775f04d 100644 (file)
@@ -403,36 +403,6 @@ static void __init palmtreo_leds_init(void)
        platform_device_register(&palmtreo_leds);
 }
 
-/******************************************************************************
- * diskonchip docg4 flash
- ******************************************************************************/
-#if defined(CONFIG_MACH_TREO680)
-/* REVISIT: does the centro have this device also? */
-#if IS_ENABLED(CONFIG_MTD_NAND_DOCG4)
-static struct resource docg4_resources[] = {
-       {
-               .start  = 0x00000000,
-               .end    = 0x00001FFF,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device treo680_docg4_flash = {
-       .name   = "docg4",
-       .id     = -1,
-       .resource = docg4_resources,
-       .num_resources = ARRAY_SIZE(docg4_resources),
-};
-
-static void __init treo680_docg4_flash_init(void)
-{
-       platform_device_register(&treo680_docg4_flash);
-}
-#else
-static inline void treo680_docg4_flash_init(void) {}
-#endif
-#endif
-
 /******************************************************************************
  * Machine init
  ******************************************************************************/
@@ -517,7 +487,6 @@ static void __init treo680_init(void)
        treo680_gpio_init();
        palm27x_mmc_init(GPIO_NR_TREO_SD_DETECT_N, GPIO_NR_TREO680_SD_READONLY,
                        GPIO_NR_TREO680_SD_POWER, 0);
-       treo680_docg4_flash_init();
 }
 #endif
 
index 47e3e38e9becd229ad88b38ce90dcbeff1fa6035..1d06a8e91d8f9376b4a88a93b8dc4f58c9e4911b 100644 (file)
@@ -28,8 +28,7 @@
 #include <linux/wm97xx.h>
 #include <linux/power_supply.h>
 #include <linux/usb/gpio_vbus.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/physmap.h>
 
@@ -247,11 +246,10 @@ static inline void palmtx_keys_init(void) {}
  ******************************************************************************/
 #if defined(CONFIG_MTD_NAND_PLATFORM) || \
        defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
-static void palmtx_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
-                                unsigned int ctrl)
+static void palmtx_nand_cmd_ctl(struct nand_chip *this, int cmd,
+                               unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       char __iomem *nandaddr = this->IO_ADDR_W;
+       char __iomem *nandaddr = this->legacy.IO_ADDR_W;
 
        if (cmd == NAND_CMD_NONE)
                return;
index da76637704253e3610f4f15b69a42e75af99d516..4bf02f96ab7ffd0eceb5b9d2ce28fff5ffe01068 100644 (file)
@@ -29,8 +29,7 @@
 #include <linux/leds.h>
 #include <linux/mmc/host.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/spi/spi.h>
@@ -197,11 +196,10 @@ static struct i2c_board_info db1200_i2c_devs[] __initdata = {
 
 /**********************************************************************/
 
-static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void au1200_nand_cmd_ctrl(struct nand_chip *this, int cmd,
                                 unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
+       unsigned long ioaddr = (unsigned long)this->legacy.IO_ADDR_W;
 
        ioaddr &= 0xffffff00;
 
@@ -213,14 +211,14 @@ static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
                /* assume we want to r/w real data  by default */
                ioaddr += MEM_STNAND_DATA;
        }
-       this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
+       this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = (void __iomem *)ioaddr;
        if (cmd != NAND_CMD_NONE) {
-               __raw_writeb(cmd, this->IO_ADDR_W);
+               __raw_writeb(cmd, this->legacy.IO_ADDR_W);
                wmb();
        }
 }
 
-static int au1200_nand_device_ready(struct mtd_info *mtd)
+static int au1200_nand_device_ready(struct nand_chip *this)
 {
        return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1;
 }
index efb318e03e0a3d53163307d84c0d850c6a747869..ad7dd8e89598045986556ce685f21e1439a42a5d 100644 (file)
@@ -19,8 +19,7 @@
 #include <linux/mmc/host.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/platform_device.h>
 #include <linux/smsc911x.h>
 #include <linux/wm97xx.h>
@@ -149,11 +148,10 @@ static void __init db1300_gpio_config(void)
 
 /**********************************************************************/
 
-static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void au1300_nand_cmd_ctrl(struct nand_chip *this, int cmd,
                                 unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
+       unsigned long ioaddr = (unsigned long)this->legacy.IO_ADDR_W;
 
        ioaddr &= 0xffffff00;
 
@@ -165,14 +163,14 @@ static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
                /* assume we want to r/w real data  by default */
                ioaddr += MEM_STNAND_DATA;
        }
-       this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
+       this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = (void __iomem *)ioaddr;
        if (cmd != NAND_CMD_NONE) {
-               __raw_writeb(cmd, this->IO_ADDR_W);
+               __raw_writeb(cmd, this->legacy.IO_ADDR_W);
                wmb();
        }
 }
 
-static int au1300_nand_device_ready(struct mtd_info *mtd)
+static int au1300_nand_device_ready(struct nand_chip *this)
 {
        return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1;
 }
index 7d3dfaa10231754e8d3eb683c8ab2439e1192a9b..7700ad0b93b4ce6b9f49fa2aeb496a572e6bc8c1 100644 (file)
@@ -13,8 +13,7 @@
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/spi/spi.h>
@@ -126,11 +125,10 @@ static struct i2c_board_info db1550_i2c_devs[] __initdata = {
 
 /**********************************************************************/
 
-static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void au1550_nand_cmd_ctrl(struct nand_chip *this, int cmd,
                                 unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
+       unsigned long ioaddr = (unsigned long)this->legacy.IO_ADDR_W;
 
        ioaddr &= 0xffffff00;
 
@@ -142,14 +140,14 @@ static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
                /* assume we want to r/w real data  by default */
                ioaddr += MEM_STNAND_DATA;
        }
-       this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
+       this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = (void __iomem *)ioaddr;
        if (cmd != NAND_CMD_NONE) {
-               __raw_writeb(cmd, this->IO_ADDR_W);
+               __raw_writeb(cmd, this->legacy.IO_ADDR_W);
                wmb();
        }
 }
 
-static int au1550_nand_device_ready(struct mtd_info *mtd)
+static int au1550_nand_device_ready(struct nand_chip *this)
 {
        return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1;
 }
index 4d1b4c003376d1d0d196c623738e60f8d07826e4..cf9162284b0760df2b7b2433cf62987430c5df76 100644 (file)
@@ -19,8 +19,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 
 #include <asm/netlogic/haldefs.h>
 #include <asm/netlogic/xlr/iomap.h>
@@ -92,8 +91,8 @@ struct xlr_nand_flash_priv {
 
 static struct xlr_nand_flash_priv nand_priv;
 
-static void xlr_nand_ctrl(struct mtd_info *mtd, int cmd,
-               unsigned int ctrl)
+static void xlr_nand_ctrl(struct nand_chip *chip, int cmd,
+                         unsigned int ctrl)
 {
        if (ctrl & NAND_CLE)
                nlm_write_reg(nand_priv.flash_mmio,
index a7a4e9f5146d8264fa5452ed744f3331345e810e..dafbf027fad0185ea6af7df7b477313802a9102e 100644 (file)
@@ -30,8 +30,7 @@
 #include <linux/resource.h>
 #include <linux/serial.h>
 #include <linux/serial_pnx8xxx.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 
 #include <irq.h>
 #include <irq-mapping.h>
@@ -178,10 +177,9 @@ static struct platform_device pnx833x_sata_device = {
 };
 
 static void
-pnx833x_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+pnx833x_flash_nand_cmd_ctrl(struct nand_chip *this, int cmd, unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
+       unsigned long nandaddr = (unsigned long)this->legacy.IO_ADDR_W;
 
        if (cmd == NAND_CMD_NONE)
                return;
index 354d258396ff993f32878941d8c01621b887c8d7..2b23ad640f399f31118376a437d22a66621eaf3b 100644 (file)
@@ -20,9 +20,8 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/rawnand.h>
+#include <linux/mtd/platnand.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
@@ -141,14 +140,13 @@ static struct platform_device cf_slot0 = {
 };
 
 /* Resources and device for NAND */
-static int rb532_dev_ready(struct mtd_info *mtd)
+static int rb532_dev_ready(struct nand_chip *chip)
 {
        return gpio_get_value(GPIO_RDY);
 }
 
-static void rb532_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void rb532_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        unsigned char orbits, nandbits;
 
        if (ctrl & NAND_CTRL_CHANGE) {
@@ -161,7 +159,7 @@ static void rb532_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
                set_latch_u5(orbits, nandbits);
        }
        if (cmd != NAND_CMD_NONE)
-               writeb(cmd, chip->IO_ADDR_W);
+               writeb(cmd, chip->legacy.IO_ADDR_W);
 }
 
 static struct resource nand_slot0_res[] = {
index 254f2c66270362845524352e5ad73a1b6bdecf9b..f4ad33c6d2aaa9c6e0564b11db724cbc4bdc8f28 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mfd/tmio.h>
-#include <linux/mtd/rawnand.h>
+#include <linux/mtd/platnand.h>
 #include <linux/i2c.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
@@ -165,23 +165,21 @@ static struct mtd_partition migor_nand_flash_partitions[] = {
        },
 };
 
-static void migor_nand_flash_cmd_ctl(struct mtd_info *mtd, int cmd,
+static void migor_nand_flash_cmd_ctl(struct nand_chip *chip, int cmd,
                                     unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        if (cmd == NAND_CMD_NONE)
                return;
 
        if (ctrl & NAND_CLE)
-               writeb(cmd, chip->IO_ADDR_W + 0x00400000);
+               writeb(cmd, chip->legacy.IO_ADDR_W + 0x00400000);
        else if (ctrl & NAND_ALE)
-               writeb(cmd, chip->IO_ADDR_W + 0x00800000);
+               writeb(cmd, chip->legacy.IO_ADDR_W + 0x00800000);
        else
-               writeb(cmd, chip->IO_ADDR_W);
+               writeb(cmd, chip->legacy.IO_ADDR_W);
 }
 
-static int migor_nand_flash_ready(struct mtd_info *mtd)
+static int migor_nand_flash_ready(struct nand_chip *chip)
 {
        return gpio_get_value(GPIO_PTA1); /* NAND_RBn */
 }
index 270d3c9580c51195ccb6b05e3719e98fb1836031..c4a1d04b8c800d1b090e99dc9975025d4b61009c 100644 (file)
@@ -90,7 +90,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
                                   SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_DATA_OUT(len, buf, 1));
-       size_t remaining = len;
        int ret;
 
        /* get transfer protocols. */
@@ -101,22 +100,16 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
        if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
                op.addr.nbytes = 0;
 
-       while (remaining) {
-               op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
-               ret = spi_mem_adjust_op_size(flash->spimem, &op);
-               if (ret)
-                       return ret;
-
-               ret = spi_mem_exec_op(flash->spimem, &op);
-               if (ret)
-                       return ret;
+       ret = spi_mem_adjust_op_size(flash->spimem, &op);
+       if (ret)
+               return ret;
+       op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
 
-               op.addr.val += op.data.nbytes;
-               remaining -= op.data.nbytes;
-               op.data.buf.out += op.data.nbytes;
-       }
+       ret = spi_mem_exec_op(flash->spimem, &op);
+       if (ret)
+               return ret;
 
-       return len;
+       return op.data.nbytes;
 }
 
 /*
index 9d972369321755b5560c371626d9c8bf9a8d8271..a20e85aa770e37248b2c9e34e7cc2ac67bbc9778 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 
-#define pr_devinit(fmt, args...) \
-       ({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
+#define win_mask(x) ((BIT(x)) - 1)
 
 #define DRIVER_NAME "gpio-addr-flash"
-#define PFX DRIVER_NAME ": "
 
 /**
  * struct async_state - keep GPIO flash state
  *     @mtd:         MTD state for this mapping
  *     @map:         MTD map state for this flash
- *     @gpio_count:  number of GPIOs used to address
- *     @gpio_addrs:  array of GPIOs to twiddle
+ *     @gpios:       Struct containing the array of GPIO descriptors
  *     @gpio_values: cached GPIO values
- *     @win_size:    dedicated memory size (if no GPIOs)
+ *     @win_order:   dedicated memory size (if no GPIOs)
  */
 struct async_state {
        struct mtd_info *mtd;
        struct map_info map;
-       size_t gpio_count;
-       unsigned *gpio_addrs;
-       int *gpio_values;
-       unsigned long win_size;
+       struct gpio_descs *gpios;
+       unsigned int gpio_values;
+       unsigned int win_order;
 };
 #define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
 
@@ -57,21 +54,25 @@ struct async_state {
  *
  * Rather than call the GPIO framework every time, cache the last-programmed
  * value.  This speeds up sequential accesses (which are by far the most common
- * type).  We rely on the GPIO framework to treat non-zero value as high so
- * that we don't have to normalize the bits.
+ * type).
  */
 static void gf_set_gpios(struct async_state *state, unsigned long ofs)
 {
-       size_t i = 0;
-       int value;
-       ofs /= state->win_size;
-       do {
-               value = ofs & (1 << i);
-               if (state->gpio_values[i] != value) {
-                       gpio_set_value(state->gpio_addrs[i], value);
-                       state->gpio_values[i] = value;
-               }
-       } while (++i < state->gpio_count);
+       int i;
+
+       ofs >>= state->win_order;
+
+       if (ofs == state->gpio_values)
+               return;
+
+       for (i = 0; i < state->gpios->ndescs; i++) {
+               if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))
+                       continue;
+
+               gpiod_set_value(state->gpios->desc[i], !!(ofs & BIT(i)));
+       }
+
+       state->gpio_values = ofs;
 }
 
 /**
@@ -87,7 +88,7 @@ static map_word gf_read(struct map_info *map, unsigned long ofs)
 
        gf_set_gpios(state, ofs);
 
-       word = readw(map->virt + (ofs % state->win_size));
+       word = readw(map->virt + (ofs & win_mask(state->win_order)));
        test.x[0] = word;
        return test;
 }
@@ -109,14 +110,14 @@ static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssi
        int this_len;
 
        while (len) {
-               if ((from % state->win_size) + len > state->win_size)
-                       this_len = state->win_size - (from % state->win_size);
-               else
-                       this_len = len;
+               this_len = from & win_mask(state->win_order);
+               this_len = BIT(state->win_order) - this_len;
+               this_len = min_t(int, len, this_len);
 
                gf_set_gpios(state, from);
-               memcpy_fromio(to, map->virt + (from % state->win_size),
-                        this_len);
+               memcpy_fromio(to,
+                             map->virt + (from & win_mask(state->win_order)),
+                             this_len);
                len -= this_len;
                from += this_len;
                to += this_len;
@@ -136,7 +137,7 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
        gf_set_gpios(state, ofs);
 
        d = d1.x[0];
-       writew(d, map->virt + (ofs % state->win_size));
+       writew(d, map->virt + (ofs & win_mask(state->win_order)));
 }
 
 /**
@@ -156,13 +157,13 @@ static void gf_copy_to(struct map_info *map, unsigned long to,
        int this_len;
 
        while (len) {
-               if ((to % state->win_size) + len > state->win_size)
-                       this_len = state->win_size - (to % state->win_size);
-               else
-                       this_len = len;
+               this_len = to & win_mask(state->win_order);
+               this_len = BIT(state->win_order) - this_len;
+               this_len = min_t(int, len, this_len);
 
                gf_set_gpios(state, to);
-               memcpy_toio(map->virt + (to % state->win_size), from, len);
+               memcpy_toio(map->virt + (to & win_mask(state->win_order)),
+                           from, len);
 
                len -= this_len;
                to += this_len;
@@ -180,18 +181,22 @@ static const char * const part_probe_types[] = {
  * The platform resource layout expected looks something like:
  * struct mtd_partition partitions[] = { ... };
  * struct physmap_flash_data flash_data = { ... };
- * unsigned flash_gpios[] = { GPIO_XX, GPIO_XX, ... };
+ * static struct gpiod_lookup_table addr_flash_gpios = {
+ *             .dev_id = "gpio-addr-flash.0",
+ *             .table = {
+ *             GPIO_LOOKUP_IDX("gpio.0", 15, "addr", 0, GPIO_ACTIVE_HIGH),
+ *             GPIO_LOOKUP_IDX("gpio.0", 16, "addr", 1, GPIO_ACTIVE_HIGH),
+ *             );
+ * };
+ * gpiod_add_lookup_table(&addr_flash_gpios);
+ *
  * struct resource flash_resource[] = {
  *     {
  *             .name  = "cfi_probe",
  *             .start = 0x20000000,
  *             .end   = 0x201fffff,
  *             .flags = IORESOURCE_MEM,
- *     }, {
- *             .start = (unsigned long)flash_gpios,
- *             .end   = ARRAY_SIZE(flash_gpios),
- *             .flags = IORESOURCE_IRQ,
- *     }
+ *     },
  * };
  * struct platform_device flash_device = {
  *     .name          = "gpio-addr-flash",
@@ -203,33 +208,25 @@ static const char * const part_probe_types[] = {
  */
 static int gpio_flash_probe(struct platform_device *pdev)
 {
-       size_t i, arr_size;
        struct physmap_flash_data *pdata;
        struct resource *memory;
-       struct resource *gpios;
        struct async_state *state;
 
        pdata = dev_get_platdata(&pdev->dev);
        memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
-       if (!memory || !gpios || !gpios->end)
+       if (!memory)
                return -EINVAL;
 
-       arr_size = sizeof(int) * gpios->end;
-       state = kzalloc(sizeof(*state) + arr_size, GFP_KERNEL);
+       state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
        if (!state)
                return -ENOMEM;
 
-       /*
-        * We cast start/end to known types in the boards file, so cast
-        * away their pointer types here to the known types (gpios->xxx).
-        */
-       state->gpio_count     = gpios->end;
-       state->gpio_addrs     = (void *)(unsigned long)gpios->start;
-       state->gpio_values    = (void *)(state + 1);
-       state->win_size       = resource_size(memory);
-       memset(state->gpio_values, 0xff, arr_size);
+       state->gpios = devm_gpiod_get_array(&pdev->dev, "addr", GPIOD_OUT_LOW);
+       if (IS_ERR(state->gpios))
+               return PTR_ERR(state->gpios);
+
+       state->win_order      = get_bitmask_order(resource_size(memory)) - 1;
 
        state->map.name       = DRIVER_NAME;
        state->map.read       = gf_read;
@@ -237,38 +234,21 @@ static int gpio_flash_probe(struct platform_device *pdev)
        state->map.write      = gf_write;
        state->map.copy_to    = gf_copy_to;
        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.size       = BIT(state->win_order + state->gpios->ndescs);
+       state->map.virt       = devm_ioremap_resource(&pdev->dev, memory);
+       if (IS_ERR(state->map.virt))
+               return PTR_ERR(state->map.virt);
 
        state->map.phys       = NO_XIP;
        state->map.map_priv_1 = (unsigned long)state;
 
        platform_set_drvdata(pdev, state);
 
-       i = 0;
-       do {
-               if (gpio_request(state->gpio_addrs[i], DRIVER_NAME)) {
-                       pr_devinit(KERN_ERR PFX "failed to request gpio %d\n",
-                               state->gpio_addrs[i]);
-                       while (i--)
-                               gpio_free(state->gpio_addrs[i]);
-                       kfree(state);
-                       return -EBUSY;
-               }
-               gpio_direction_output(state->gpio_addrs[i], 0);
-       } while (++i < state->gpio_count);
-
-       pr_devinit(KERN_NOTICE PFX "probing %d-bit flash bus\n",
-               state->map.bankwidth * 8);
+       dev_notice(&pdev->dev, "probing %d-bit flash bus\n",
+                  state->map.bankwidth * 8);
        state->mtd = do_map_probe(memory->name, &state->map);
-       if (!state->mtd) {
-               for (i = 0; i < state->gpio_count; ++i)
-                       gpio_free(state->gpio_addrs[i]);
-               kfree(state);
+       if (!state->mtd)
                return -ENXIO;
-       }
        state->mtd->dev.parent = &pdev->dev;
 
        mtd_device_parse_register(state->mtd, part_probe_types, NULL,
@@ -280,13 +260,9 @@ static int gpio_flash_probe(struct platform_device *pdev)
 static int gpio_flash_remove(struct platform_device *pdev)
 {
        struct async_state *state = platform_get_drvdata(pdev);
-       size_t i = 0;
-       do {
-               gpio_free(state->gpio_addrs[i]);
-       } while (++i < state->gpio_count);
+
        mtd_device_unregister(state->mtd);
        map_destroy(state->mtd);
-       kfree(state);
        return 0;
 }
 
index 4129535b8e46f34e8891c3d86f0c6fb5160f6095..ece605d78c215670af7334fff835fb095e155bd0 100644 (file)
@@ -31,7 +31,6 @@
 struct of_flash_list {
        struct mtd_info *mtd;
        struct map_info map;
-       struct resource *res;
 };
 
 struct of_flash {
@@ -56,18 +55,10 @@ static int of_flash_remove(struct platform_device *dev)
                        mtd_concat_destroy(info->cmtd);
        }
 
-       for (i = 0; i < info->list_size; i++) {
+       for (i = 0; i < info->list_size; i++)
                if (info->list[i].mtd)
                        map_destroy(info->list[i].mtd);
 
-               if (info->list[i].map.virt)
-                       iounmap(info->list[i].map.virt);
-
-               if (info->list[i].res) {
-                       release_resource(info->list[i].res);
-                       kfree(info->list[i].res);
-               }
-       }
        return 0;
 }
 
@@ -215,10 +206,11 @@ static int of_flash_probe(struct platform_device *dev)
 
                err = -EBUSY;
                res_size = resource_size(&res);
-               info->list[i].res = request_mem_region(res.start, res_size,
-                                                      dev_name(&dev->dev));
-               if (!info->list[i].res)
+               info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res);
+               if (IS_ERR(info->list[i].map.virt)) {
+                       err = PTR_ERR(info->list[i].map.virt);
                        goto err_out;
+               }
 
                err = -ENXIO;
                width = of_get_property(dp, "bank-width", NULL);
@@ -246,15 +238,6 @@ static int of_flash_probe(struct platform_device *dev)
                if (err)
                        goto err_out;
 
-               err = -ENOMEM;
-               info->list[i].map.virt = ioremap(info->list[i].map.phys,
-                                                info->list[i].map.size);
-               if (!info->list[i].map.virt) {
-                       dev_err(&dev->dev, "Failed to ioremap() flash"
-                               " region\n");
-                       goto err_out;
-               }
-
                simple_map_init(&info->list[i].map);
 
                /*
index 830b1b7e702bc7433425bc37c21422d0fb3276a3..9df62ca721d5dd624a9bb738aa9d1fcb47cce244 100644 (file)
 
 #define FLASH_PARALLEL_HIGH_PIN_CNT    (1 << 20)       /* else low pin cnt */
 
-static const struct of_device_id syscon_match[] = {
-       { .compatible = "cortina,gemini-syscon" },
-       { },
-};
-
 int of_flash_probe_gemini(struct platform_device *pdev,
                          struct device_node *np,
                          struct map_info *map)
index 5fc9a1bde4ac2e6d6e8475ab92c81342395d03d7..c7efc31384d52726199a63869cc3dd1b547128e4 100644 (file)
@@ -227,26 +227,6 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
          load time (assuming you build diskonchip as a module) with the module
          parameter "inftl_bbt_write=1".
 
-config MTD_NAND_DOCG4
-       tristate "Support for DiskOnChip G4"
-       depends on HAS_IOMEM
-       select BCH
-       select BITREVERSE
-       help
-         Support for diskonchip G4 nand flash, found in various smartphones and
-         PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
-         Portege G900, Asus P526, and O2 XDA Zinc.
-
-         With this driver you will be able to use UBI and create a ubifs on the
-         device, so you may wish to consider enabling UBI and UBIFS as well.
-
-         These devices ship with the Mys/Sandisk SAFTL formatting, for which
-         there is currently no mtd parser, so you may want to use command line
-         partitioning to segregate write-protected blocks. On the Treo680, the
-         first five erase blocks (256KiB each) are write-protected, followed
-         by the block containing the saftl partition table.  This is probably
-         typical.
-
 config MTD_NAND_SHARPSL
        tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
        depends on ARCH_PXA || COMPILE_TEST
index d5a5f9832b8879e4cbf16f5dd7f902edcf52c239..57159b349054ddf2065890326a5809633f8c4f16 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_NAND_S3C2410)                += s3c2410.o
 obj-$(CONFIG_MTD_NAND_TANGO)           += tango_nand.o
 obj-$(CONFIG_MTD_NAND_DAVINCI)         += davinci_nand.o
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)      += diskonchip.o
-obj-$(CONFIG_MTD_NAND_DOCG4)           += docg4.o
 obj-$(CONFIG_MTD_NAND_FSMC)            += fsmc_nand.o
 obj-$(CONFIG_MTD_NAND_SHARPSL)         += sharpsl.o
 obj-$(CONFIG_MTD_NAND_NANDSIM)         += nandsim.o
@@ -58,8 +57,11 @@ 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_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
+nand-objs += nand_onfi.o
+nand-objs += nand_jedec.o
 nand-objs += nand_amd.o
+nand-objs += nand_esmt.o
 nand-objs += nand_hynix.o
 nand-objs += nand_macronix.o
 nand-objs += nand_micron.o
index 37a3cc21c7bccd396d92d6655e0004cd1aeddf6b..5ba180a291eb2986004b76af286e9582146e2d62 100644 (file)
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
-#include <linux/gpio.h>
 #include <linux/platform_data/gpio-omap.h>
 
 #include <asm/io.h>
 #include <asm/sizes.h>
 
-#include <mach/board-ams-delta.h>
-
 #include <mach/hardware.h>
 
 /*
  * MTD structure for E3 (Delta)
  */
-static struct mtd_info *ams_delta_mtd = NULL;
+
+struct ams_delta_nand {
+       struct nand_chip        nand_chip;
+       struct gpio_desc        *gpiod_rdy;
+       struct gpio_desc        *gpiod_nce;
+       struct gpio_desc        *gpiod_nre;
+       struct gpio_desc        *gpiod_nwp;
+       struct gpio_desc        *gpiod_nwe;
+       struct gpio_desc        *gpiod_ale;
+       struct gpio_desc        *gpiod_cle;
+       void __iomem            *io_base;
+       bool                    data_in;
+};
 
 /*
  * Define partitions for flash devices
@@ -63,48 +73,64 @@ static const struct mtd_partition partition_info[] = {
          .size         =  3 * SZ_256K },
 };
 
-static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
+static void ams_delta_io_write(struct ams_delta_nand *priv, u_char byte)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
-
-       writew(0, io_base + OMAP_MPUIO_IO_CNTL);
-       writew(byte, this->IO_ADDR_W);
-       gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
+       writew(byte, priv->nand_chip.legacy.IO_ADDR_W);
+       gpiod_set_value(priv->gpiod_nwe, 0);
        ndelay(40);
-       gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
+       gpiod_set_value(priv->gpiod_nwe, 1);
 }
 
-static u_char ams_delta_read_byte(struct mtd_info *mtd)
+static u_char ams_delta_io_read(struct ams_delta_nand *priv)
 {
        u_char res;
-       struct nand_chip *this = mtd_to_nand(mtd);
-       void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
 
-       gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
+       gpiod_set_value(priv->gpiod_nre, 0);
        ndelay(40);
-       writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
-       res = readw(this->IO_ADDR_R);
-       gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
+       res = readw(priv->nand_chip.legacy.IO_ADDR_R);
+       gpiod_set_value(priv->gpiod_nre, 1);
 
        return res;
 }
 
-static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
+static void ams_delta_dir_input(struct ams_delta_nand *priv, bool in)
+{
+       writew(in ? ~0 : 0, priv->io_base + OMAP_MPUIO_IO_CNTL);
+       priv->data_in = in;
+}
+
+static void ams_delta_write_buf(struct nand_chip *this, const u_char *buf,
                                int len)
 {
+       struct ams_delta_nand *priv = nand_get_controller_data(this);
        int i;
 
-       for (i=0; i<len; i++)
-               ams_delta_write_byte(mtd, buf[i]);
+       if (priv->data_in)
+               ams_delta_dir_input(priv, false);
+
+       for (i = 0; i < len; i++)
+               ams_delta_io_write(priv, buf[i]);
 }
 
-static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void ams_delta_read_buf(struct nand_chip *this, u_char *buf, int len)
 {
+       struct ams_delta_nand *priv = nand_get_controller_data(this);
        int i;
 
-       for (i=0; i<len; i++)
-               buf[i] = ams_delta_read_byte(mtd);
+       if (!priv->data_in)
+               ams_delta_dir_input(priv, true);
+
+       for (i = 0; i < len; i++)
+               buf[i] = ams_delta_io_read(priv);
+}
+
+static u_char ams_delta_read_byte(struct nand_chip *this)
+{
+       u_char res;
+
+       ams_delta_read_buf(this, &res, 1);
+
+       return res;
 }
 
 /*
@@ -115,67 +141,40 @@ static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
  * NAND_CLE: bit 1 -> bit 7
  * NAND_ALE: bit 2 -> bit 6
  */
-static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
+static void ams_delta_hwcontrol(struct nand_chip *this, int cmd,
                                unsigned int ctrl)
 {
+       struct ams_delta_nand *priv = nand_get_controller_data(this);
 
        if (ctrl & NAND_CTRL_CHANGE) {
-               gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
-                               (ctrl & NAND_NCE) == 0);
-               gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
-                               (ctrl & NAND_CLE) != 0);
-               gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
-                               (ctrl & NAND_ALE) != 0);
+               gpiod_set_value(priv->gpiod_nce, !(ctrl & NAND_NCE));
+               gpiod_set_value(priv->gpiod_cle, !!(ctrl & NAND_CLE));
+               gpiod_set_value(priv->gpiod_ale, !!(ctrl & NAND_ALE));
        }
 
-       if (cmd != NAND_CMD_NONE)
-               ams_delta_write_byte(mtd, cmd);
+       if (cmd != NAND_CMD_NONE) {
+               u_char byte = cmd;
+
+               ams_delta_write_buf(this, &byte, 1);
+       }
 }
 
-static int ams_delta_nand_ready(struct mtd_info *mtd)
+static int ams_delta_nand_ready(struct nand_chip *this)
 {
-       return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
+       struct ams_delta_nand *priv = nand_get_controller_data(this);
+
+       return gpiod_get_value(priv->gpiod_rdy);
 }
 
-static const struct gpio _mandatory_gpio[] = {
-       {
-               .gpio   = AMS_DELTA_GPIO_PIN_NAND_NCE,
-               .flags  = GPIOF_OUT_INIT_HIGH,
-               .label  = "nand_nce",
-       },
-       {
-               .gpio   = AMS_DELTA_GPIO_PIN_NAND_NRE,
-               .flags  = GPIOF_OUT_INIT_HIGH,
-               .label  = "nand_nre",
-       },
-       {
-               .gpio   = AMS_DELTA_GPIO_PIN_NAND_NWP,
-               .flags  = GPIOF_OUT_INIT_HIGH,
-               .label  = "nand_nwp",
-       },
-       {
-               .gpio   = AMS_DELTA_GPIO_PIN_NAND_NWE,
-               .flags  = GPIOF_OUT_INIT_HIGH,
-               .label  = "nand_nwe",
-       },
-       {
-               .gpio   = AMS_DELTA_GPIO_PIN_NAND_ALE,
-               .flags  = GPIOF_OUT_INIT_LOW,
-               .label  = "nand_ale",
-       },
-       {
-               .gpio   = AMS_DELTA_GPIO_PIN_NAND_CLE,
-               .flags  = GPIOF_OUT_INIT_LOW,
-               .label  = "nand_cle",
-       },
-};
 
 /*
  * Main initialization routine
  */
 static int ams_delta_init(struct platform_device *pdev)
 {
+       struct ams_delta_nand *priv;
        struct nand_chip *this;
+       struct mtd_info *mtd;
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        void __iomem *io_base;
        int err = 0;
@@ -184,15 +183,16 @@ static int ams_delta_init(struct platform_device *pdev)
                return -ENXIO;
 
        /* Allocate memory for MTD device structure and private data */
-       this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
-       if (!this) {
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand),
+                           GFP_KERNEL);
+       if (!priv) {
                pr_warn("Unable to allocate E3 NAND MTD device structure.\n");
-               err = -ENOMEM;
-               goto out;
+               return -ENOMEM;
        }
+       this = &priv->nand_chip;
 
-       ams_delta_mtd = nand_to_mtd(this);
-       ams_delta_mtd->owner = THIS_MODULE;
+       mtd = nand_to_mtd(this);
+       mtd->dev.parent = &pdev->dev;
 
        /*
         * Don't try to request the memory region from here,
@@ -207,51 +207,93 @@ static int ams_delta_init(struct platform_device *pdev)
                goto out_free;
        }
 
-       nand_set_controller_data(this, (void *)io_base);
+       priv->io_base = io_base;
+       nand_set_controller_data(this, priv);
 
        /* Set address of NAND IO lines */
-       this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
-       this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
-       this->read_byte = ams_delta_read_byte;
-       this->write_buf = ams_delta_write_buf;
-       this->read_buf = ams_delta_read_buf;
-       this->cmd_ctrl = ams_delta_hwcontrol;
-       if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
-               this->dev_ready = ams_delta_nand_ready;
-       } else {
-               this->dev_ready = NULL;
-               pr_notice("Couldn't request gpio for Delta NAND ready.\n");
+       this->legacy.IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
+       this->legacy.IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
+       this->legacy.read_byte = ams_delta_read_byte;
+       this->legacy.write_buf = ams_delta_write_buf;
+       this->legacy.read_buf = ams_delta_read_buf;
+       this->legacy.cmd_ctrl = ams_delta_hwcontrol;
+
+       priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN);
+       if (IS_ERR(priv->gpiod_rdy)) {
+               err = PTR_ERR(priv->gpiod_rdy);
+               dev_warn(&pdev->dev, "RDY GPIO request failed (%d)\n", err);
+               goto out_mtd;
        }
+
+       if (priv->gpiod_rdy)
+               this->legacy.dev_ready = ams_delta_nand_ready;
+
        /* 25 us command delay time */
-       this->chip_delay = 30;
+       this->legacy.chip_delay = 30;
        this->ecc.mode = NAND_ECC_SOFT;
        this->ecc.algo = NAND_ECC_HAMMING;
 
-       platform_set_drvdata(pdev, io_base);
+       platform_set_drvdata(pdev, priv);
 
        /* Set chip enabled, but  */
-       err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
-       if (err)
-               goto out_gpio;
+       priv->gpiod_nwp = devm_gpiod_get(&pdev->dev, "nwp", GPIOD_OUT_HIGH);
+       if (IS_ERR(priv->gpiod_nwp)) {
+               err = PTR_ERR(priv->gpiod_nwp);
+               dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err);
+               goto out_mtd;
+       }
+
+       priv->gpiod_nce = devm_gpiod_get(&pdev->dev, "nce", GPIOD_OUT_HIGH);
+       if (IS_ERR(priv->gpiod_nce)) {
+               err = PTR_ERR(priv->gpiod_nce);
+               dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err);
+               goto out_mtd;
+       }
+
+       priv->gpiod_nre = devm_gpiod_get(&pdev->dev, "nre", GPIOD_OUT_HIGH);
+       if (IS_ERR(priv->gpiod_nre)) {
+               err = PTR_ERR(priv->gpiod_nre);
+               dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err);
+               goto out_mtd;
+       }
+
+       priv->gpiod_nwe = devm_gpiod_get(&pdev->dev, "nwe", GPIOD_OUT_HIGH);
+       if (IS_ERR(priv->gpiod_nwe)) {
+               err = PTR_ERR(priv->gpiod_nwe);
+               dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err);
+               goto out_mtd;
+       }
+
+       priv->gpiod_ale = devm_gpiod_get(&pdev->dev, "ale", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->gpiod_ale)) {
+               err = PTR_ERR(priv->gpiod_ale);
+               dev_err(&pdev->dev, "ALE GPIO request failed (%d)\n", err);
+               goto out_mtd;
+       }
+
+       priv->gpiod_cle = devm_gpiod_get(&pdev->dev, "cle", GPIOD_OUT_LOW);
+       if (IS_ERR(priv->gpiod_cle)) {
+               err = PTR_ERR(priv->gpiod_cle);
+               dev_err(&pdev->dev, "CLE GPIO request failed (%d)\n", err);
+               goto out_mtd;
+       }
+
+       /* Initialize data port direction to a known state */
+       ams_delta_dir_input(priv, true);
 
        /* Scan to find existence of the device */
-       err = nand_scan(ams_delta_mtd, 1);
+       err = nand_scan(this, 1);
        if (err)
                goto out_mtd;
 
        /* Register the partitions */
-       mtd_device_register(ams_delta_mtd, partition_info,
-                           ARRAY_SIZE(partition_info));
+       mtd_device_register(mtd, partition_info, ARRAY_SIZE(partition_info));
 
        goto out;
 
  out_mtd:
-       gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
-out_gpio:
-       gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
        iounmap(io_base);
 out_free:
-       kfree(this);
  out:
        return err;
 }
@@ -261,18 +303,15 @@ out_free:
  */
 static int ams_delta_cleanup(struct platform_device *pdev)
 {
-       void __iomem *io_base = platform_get_drvdata(pdev);
+       struct ams_delta_nand *priv = platform_get_drvdata(pdev);
+       struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip);
+       void __iomem *io_base = priv->io_base;
 
        /* Release resources, unregister device */
-       nand_release(ams_delta_mtd);
+       nand_release(mtd_to_nand(mtd));
 
-       gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
-       gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
        iounmap(io_base);
 
-       /* Free the MTD device structure */
-       kfree(mtd_to_nand(ams_delta_mtd));
-
        return 0;
 }
 
index a068b214ebaa7970fac10d1b0ae4b2af0602e9ae..fb33f6be7c4ff7306f391931e1843f6712edbdb7 100644 (file)
@@ -410,25 +410,15 @@ err:
        return -EIO;
 }
 
-static u8 atmel_nand_read_byte(struct mtd_info *mtd)
+static u8 atmel_nand_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
 
        return ioread8(nand->activecs->io.virt);
 }
 
-static u16 atmel_nand_read_word(struct mtd_info *mtd)
+static void atmel_nand_write_byte(struct nand_chip *chip, u8 byte)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct atmel_nand *nand = to_atmel_nand(chip);
-
-       return ioread16(nand->activecs->io.virt);
-}
-
-static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
 
        if (chip->options & NAND_BUSWIDTH_16)
@@ -437,9 +427,8 @@ static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
                iowrite8(byte, nand->activecs->io.virt);
 }
 
-static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void atmel_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_nand_controller *nc;
 
@@ -462,9 +451,8 @@ static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
                ioread8_rep(nand->activecs->io.virt, buf, len);
 }
 
-static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void atmel_nand_write_buf(struct nand_chip *chip, const u8 *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_nand_controller *nc;
 
@@ -487,34 +475,31 @@ static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
                iowrite8_rep(nand->activecs->io.virt, buf, len);
 }
 
-static int atmel_nand_dev_ready(struct mtd_info *mtd)
+static int atmel_nand_dev_ready(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
 
        return gpiod_get_value(nand->activecs->rb.gpio);
 }
 
-static void atmel_nand_select_chip(struct mtd_info *mtd, int cs)
+static void atmel_nand_select_chip(struct nand_chip *chip, int cs)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
 
        if (cs < 0 || cs >= nand->numcs) {
                nand->activecs = NULL;
-               chip->dev_ready = NULL;
+               chip->legacy.dev_ready = NULL;
                return;
        }
 
        nand->activecs = &nand->cs[cs];
 
        if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
-               chip->dev_ready = atmel_nand_dev_ready;
+               chip->legacy.dev_ready = atmel_nand_dev_ready;
 }
 
-static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
+static int atmel_hsmc_nand_dev_ready(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_hsmc_nand_controller *nc;
        u32 status;
@@ -526,15 +511,15 @@ static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
        return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
 }
 
-static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
+static void atmel_hsmc_nand_select_chip(struct nand_chip *chip, int cs)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_hsmc_nand_controller *nc;
 
        nc = to_hsmc_nand_controller(chip->controller);
 
-       atmel_nand_select_chip(mtd, cs);
+       atmel_nand_select_chip(chip, cs);
 
        if (!nand->activecs) {
                regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
@@ -543,7 +528,7 @@ static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
        }
 
        if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
-               chip->dev_ready = atmel_hsmc_nand_dev_ready;
+               chip->legacy.dev_ready = atmel_hsmc_nand_dev_ready;
 
        regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
                           ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
@@ -607,10 +592,9 @@ static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
        return ret;
 }
 
-static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
+static void atmel_hsmc_nand_cmd_ctrl(struct nand_chip *chip, int dat,
                                     unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_hsmc_nand_controller *nc;
 
@@ -634,10 +618,9 @@ static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
        }
 }
 
-static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void atmel_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
                                unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_nand_controller *nc;
 
@@ -851,7 +834,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
        if (ret)
                return ret;
 
-       atmel_nand_write_buf(mtd, buf, mtd->writesize);
+       atmel_nand_write_buf(chip, buf, mtd->writesize);
 
        ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
        if (ret) {
@@ -861,20 +844,18 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
 
        atmel_nand_pmecc_disable(chip, raw);
 
-       atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        return nand_prog_page_end_op(chip);
 }
 
-static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
-                                      struct nand_chip *chip, const u8 *buf,
+static int atmel_nand_pmecc_write_page(struct nand_chip *chip, const u8 *buf,
                                       int oob_required, int page)
 {
        return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false);
 }
 
-static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd,
-                                          struct nand_chip *chip,
+static int atmel_nand_pmecc_write_page_raw(struct nand_chip *chip,
                                           const u8 *buf, int oob_required,
                                           int page)
 {
@@ -893,8 +874,8 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
        if (ret)
                return ret;
 
-       atmel_nand_read_buf(mtd, buf, mtd->writesize);
-       atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+       atmel_nand_read_buf(chip, buf, mtd->writesize);
+       atmel_nand_read_buf(chip, chip->oob_poi, mtd->oobsize);
 
        ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
 
@@ -903,15 +884,13 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
        return ret;
 }
 
-static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
-                                     struct nand_chip *chip, u8 *buf,
+static int atmel_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf,
                                      int oob_required, int page)
 {
        return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false);
 }
 
-static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd,
-                                         struct nand_chip *chip, u8 *buf,
+static int atmel_nand_pmecc_read_page_raw(struct nand_chip *chip, u8 *buf,
                                          int oob_required, int page)
 {
        return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true);
@@ -956,7 +935,7 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
        if (ret)
                return ret;
 
-       atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        nc->op.cmds[0] = NAND_CMD_PAGEPROG;
        nc->op.ncmds = 1;
@@ -966,15 +945,14 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
                dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
                        ret);
 
-       status = chip->waitfunc(mtd, chip);
+       status = chip->legacy.waitfunc(chip);
        if (status & NAND_STATUS_FAIL)
                return -EIO;
 
        return ret;
 }
 
-static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
-                                           struct nand_chip *chip,
+static int atmel_hsmc_nand_pmecc_write_page(struct nand_chip *chip,
                                            const u8 *buf, int oob_required,
                                            int page)
 {
@@ -982,8 +960,7 @@ static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
                                              false);
 }
 
-static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd,
-                                               struct nand_chip *chip,
+static int atmel_hsmc_nand_pmecc_write_page_raw(struct nand_chip *chip,
                                                const u8 *buf,
                                                int oob_required, int page)
 {
@@ -1045,16 +1022,14 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
        return ret;
 }
 
-static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd,
-                                          struct nand_chip *chip, u8 *buf,
+static int atmel_hsmc_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf,
                                           int oob_required, int page)
 {
        return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
                                             false);
 }
 
-static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd,
-                                              struct nand_chip *chip,
+static int atmel_hsmc_nand_pmecc_read_page_raw(struct nand_chip *chip,
                                               u8 *buf, int oob_required,
                                               int page)
 {
@@ -1473,10 +1448,9 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
        return 0;
 }
 
-static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline,
                                        const struct nand_data_interface *conf)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct atmel_nand *nand = to_atmel_nand(chip);
        struct atmel_nand_controller *nc;
 
@@ -1498,19 +1472,18 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
        mtd->dev.parent = nc->dev;
        nand->base.controller = &nc->base;
 
-       chip->cmd_ctrl = atmel_nand_cmd_ctrl;
-       chip->read_byte = atmel_nand_read_byte;
-       chip->read_word = atmel_nand_read_word;
-       chip->write_byte = atmel_nand_write_byte;
-       chip->read_buf = atmel_nand_read_buf;
-       chip->write_buf = atmel_nand_write_buf;
+       chip->legacy.cmd_ctrl = atmel_nand_cmd_ctrl;
+       chip->legacy.read_byte = atmel_nand_read_byte;
+       chip->legacy.write_byte = atmel_nand_write_byte;
+       chip->legacy.read_buf = atmel_nand_read_buf;
+       chip->legacy.write_buf = atmel_nand_write_buf;
        chip->select_chip = atmel_nand_select_chip;
 
        if (nc->mck && nc->caps->ops->setup_data_interface)
                chip->setup_data_interface = atmel_nand_setup_data_interface;
 
        /* Some NANDs require a longer delay than the default one (20us). */
-       chip->chip_delay = 40;
+       chip->legacy.chip_delay = 40;
 
        /*
         * Use a bounce buffer when the buffer passed by the MTD user is not
@@ -1551,7 +1524,7 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
        atmel_nand_init(nc, nand);
 
        /* Overload some methods for the HSMC controller. */
-       chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
+       chip->legacy.cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
        chip->select_chip = atmel_hsmc_nand_select_chip;
 }
 
@@ -1586,9 +1559,7 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
                return ERR_PTR(-EINVAL);
        }
 
-       nand = devm_kzalloc(nc->dev,
-                           sizeof(*nand) + (numcs * sizeof(*nand->cs)),
-                           GFP_KERNEL);
+       nand = devm_kzalloc(nc->dev, struct_size(nand, cs, numcs), GFP_KERNEL);
        if (!nand) {
                dev_err(nc->dev, "Failed to allocate NAND object\n");
                return ERR_PTR(-ENOMEM);
@@ -1694,7 +1665,7 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
 
        nc->caps->ops->nand_init(nc, nand);
 
-       ret = nand_scan(mtd, nand->numcs);
+       ret = nand_scan(chip, nand->numcs);
        if (ret) {
                dev_err(nc->dev, "NAND scan failed: %d\n", ret);
                return ret;
@@ -2063,6 +2034,10 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
        nand_np = dev->of_node;
        nfc_np = of_find_compatible_node(dev->of_node, NULL,
                                         "atmel,sama5d3-nfc");
+       if (!nfc_np) {
+               dev_err(dev, "Could not find device node for sama5d3-nfc\n");
+               return -ENODEV;
+       }
 
        nc->clk = of_clk_get(nfc_np, 0);
        if (IS_ERR(nc->clk)) {
index 35f5c84cd33162e4a290ce96795c4dc4a8d40d11..9731c1c487f6e723d54d8cad1af98e043c68291d 100644 (file)
@@ -24,134 +24,113 @@ struct au1550nd_ctx {
 
        int cs;
        void __iomem *base;
-       void (*write_byte)(struct mtd_info *, u_char);
+       void (*write_byte)(struct nand_chip *, u_char);
 };
 
 /**
  * au_read_byte -  read one byte from the chip
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  *
  * read function for 8bit buswidth
  */
-static u_char au_read_byte(struct mtd_info *mtd)
+static u_char au_read_byte(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       u_char ret = readb(this->IO_ADDR_R);
+       u_char ret = readb(this->legacy.IO_ADDR_R);
        wmb(); /* drain writebuffer */
        return ret;
 }
 
 /**
  * au_write_byte -  write one byte to the chip
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  * @byte:      pointer to data byte to write
  *
  * write function for 8it buswidth
  */
-static void au_write_byte(struct mtd_info *mtd, u_char byte)
+static void au_write_byte(struct nand_chip *this, u_char byte)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       writeb(byte, this->IO_ADDR_W);
+       writeb(byte, this->legacy.IO_ADDR_W);
        wmb(); /* drain writebuffer */
 }
 
 /**
  * au_read_byte16 -  read one byte endianness aware from the chip
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  *
  * read function for 16bit buswidth with endianness conversion
  */
-static u_char au_read_byte16(struct mtd_info *mtd)
+static u_char au_read_byte16(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
+       u_char ret = (u_char) cpu_to_le16(readw(this->legacy.IO_ADDR_R));
        wmb(); /* drain writebuffer */
        return ret;
 }
 
 /**
  * au_write_byte16 -  write one byte endianness aware to the chip
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  * @byte:      pointer to data byte to write
  *
  * write function for 16bit buswidth with endianness conversion
  */
-static void au_write_byte16(struct mtd_info *mtd, u_char byte)
+static void au_write_byte16(struct nand_chip *this, u_char byte)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
+       writew(le16_to_cpu((u16) byte), this->legacy.IO_ADDR_W);
        wmb(); /* drain writebuffer */
 }
 
-/**
- * au_read_word -  read one word from the chip
- * @mtd:       MTD device structure
- *
- * read function for 16bit buswidth without endianness conversion
- */
-static u16 au_read_word(struct mtd_info *mtd)
-{
-       struct nand_chip *this = mtd_to_nand(mtd);
-       u16 ret = readw(this->IO_ADDR_R);
-       wmb(); /* drain writebuffer */
-       return ret;
-}
-
 /**
  * au_write_buf -  write buffer to chip
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  * @buf:       data buffer
  * @len:       number of bytes to write
  *
  * write function for 8bit buswidth
  */
-static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void au_write_buf(struct nand_chip *this, const u_char *buf, int len)
 {
        int i;
-       struct nand_chip *this = mtd_to_nand(mtd);
 
        for (i = 0; i < len; i++) {
-               writeb(buf[i], this->IO_ADDR_W);
+               writeb(buf[i], this->legacy.IO_ADDR_W);
                wmb(); /* drain writebuffer */
        }
 }
 
 /**
  * au_read_buf -  read chip data into buffer
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  * @buf:       buffer to store date
  * @len:       number of bytes to read
  *
  * read function for 8bit buswidth
  */
-static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void au_read_buf(struct nand_chip *this, u_char *buf, int len)
 {
        int i;
-       struct nand_chip *this = mtd_to_nand(mtd);
 
        for (i = 0; i < len; i++) {
-               buf[i] = readb(this->IO_ADDR_R);
+               buf[i] = readb(this->legacy.IO_ADDR_R);
                wmb(); /* drain writebuffer */
        }
 }
 
 /**
  * au_write_buf16 -  write buffer to chip
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  * @buf:       data buffer
  * @len:       number of bytes to write
  *
  * write function for 16bit buswidth
  */
-static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+static void au_write_buf16(struct nand_chip *this, const u_char *buf, int len)
 {
        int i;
-       struct nand_chip *this = mtd_to_nand(mtd);
        u16 *p = (u16 *) buf;
        len >>= 1;
 
        for (i = 0; i < len; i++) {
-               writew(p[i], this->IO_ADDR_W);
+               writew(p[i], this->legacy.IO_ADDR_W);
                wmb(); /* drain writebuffer */
        }
 
@@ -173,7 +152,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
        len >>= 1;
 
        for (i = 0; i < len; i++) {
-               p[i] = readw(this->IO_ADDR_R);
+               p[i] = readw(this->legacy.IO_ADDR_R);
                wmb(); /* drain writebuffer */
        }
 }
@@ -200,19 +179,19 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
        switch (cmd) {
 
        case NAND_CTL_SETCLE:
-               this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
+               this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
                break;
 
        case NAND_CTL_CLRCLE:
-               this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+               this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
                break;
 
        case NAND_CTL_SETALE:
-               this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
+               this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
                break;
 
        case NAND_CTL_CLRALE:
-               this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+               this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
                /* FIXME: Nobody knows why this is necessary,
                 * but it works only that way */
                udelay(1);
@@ -229,12 +208,12 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
                break;
        }
 
-       this->IO_ADDR_R = this->IO_ADDR_W;
+       this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W;
 
        wmb(); /* Drain the writebuffer */
 }
 
-int au1550_device_ready(struct mtd_info *mtd)
+int au1550_device_ready(struct nand_chip *this)
 {
        return (alchemy_rdsmem(AU1000_MEM_STSTAT) & 0x1) ? 1 : 0;
 }
@@ -248,23 +227,24 @@ int au1550_device_ready(struct mtd_info *mtd)
  *     chip needs it to be asserted during chip not ready time but the NAND
  *     controller keeps it released.
  *
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  * @chip:      chipnumber to select, -1 for deselect
  */
-static void au1550_select_chip(struct mtd_info *mtd, int chip)
+static void au1550_select_chip(struct nand_chip *this, int chip)
 {
 }
 
 /**
  * au1550_command - Send command to NAND device
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  * @command:   the command to be sent
  * @column:    the column address for this command, -1 if none
  * @page_addr: the page address for this command, -1 if none
  */
-static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static void au1550_command(struct nand_chip *this, unsigned command,
+                          int column, int page_addr)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
                                                chip);
        int ce_override = 0, i;
@@ -289,9 +269,9 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
                        column -= 256;
                        readcmd = NAND_CMD_READ1;
                }
-               ctx->write_byte(mtd, readcmd);
+               ctx->write_byte(this, readcmd);
        }
-       ctx->write_byte(mtd, command);
+       ctx->write_byte(this, command);
 
        /* Set ALE and clear CLE to start address cycle */
        au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
@@ -305,10 +285,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
                        if (this->options & NAND_BUSWIDTH_16 &&
                                        !nand_opcode_8bits(command))
                                column >>= 1;
-                       ctx->write_byte(mtd, column);
+                       ctx->write_byte(this, column);
                }
                if (page_addr != -1) {
-                       ctx->write_byte(mtd, (u8)(page_addr & 0xff));
+                       ctx->write_byte(this, (u8)(page_addr & 0xff));
 
                        if (command == NAND_CMD_READ0 ||
                            command == NAND_CMD_READ1 ||
@@ -326,10 +306,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
                                au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
                        }
 
-                       ctx->write_byte(mtd, (u8)(page_addr >> 8));
+                       ctx->write_byte(this, (u8)(page_addr >> 8));
 
                        if (this->options & NAND_ROW_ADDR_3)
-                               ctx->write_byte(mtd,
+                               ctx->write_byte(this,
                                                ((page_addr >> 16) & 0x0f));
                }
                /* Latch in address */
@@ -362,7 +342,8 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
                /* Apply a short delay always to ensure that we do wait tWB. */
                ndelay(100);
                /* Wait for a chip to become ready... */
-               for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i)
+               for (i = this->legacy.chip_delay;
+                    !this->legacy.dev_ready(this) && i > 0; --i)
                        udelay(1);
 
                /* Release -CE and re-enable interrupts. */
@@ -373,7 +354,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
        /* Apply this short delay always to ensure that we do wait tWB. */
        ndelay(100);
 
-       while(!this->dev_ready(mtd));
+       while(!this->legacy.dev_ready(this));
 }
 
 static int find_nand_cs(unsigned long nand_base)
@@ -448,25 +429,24 @@ static int au1550nd_probe(struct platform_device *pdev)
        }
        ctx->cs = cs;
 
-       this->dev_ready = au1550_device_ready;
+       this->legacy.dev_ready = au1550_device_ready;
        this->select_chip = au1550_select_chip;
-       this->cmdfunc = au1550_command;
+       this->legacy.cmdfunc = au1550_command;
 
        /* 30 us command delay time */
-       this->chip_delay = 30;
+       this->legacy.chip_delay = 30;
        this->ecc.mode = NAND_ECC_SOFT;
        this->ecc.algo = NAND_ECC_HAMMING;
 
        if (pd->devwidth)
                this->options |= NAND_BUSWIDTH_16;
 
-       this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
+       this->legacy.read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
        ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte;
-       this->read_word = au_read_word;
-       this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
-       this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
+       this->legacy.write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
+       this->legacy.read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
 
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(this, 1);
        if (ret) {
                dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
                goto out3;
@@ -492,7 +472,7 @@ static int au1550nd_remove(struct platform_device *pdev)
        struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
        struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       nand_release(nand_to_mtd(&ctx->chip));
+       nand_release(&ctx->chip);
        iounmap(ctx->base);
        release_mem_region(r->start, 0x1000);
        kfree(ctx);
index fb31429b70a9a2428d45daee8e9c3c45b3f2b542..d79694160845760f03fa59a40173e348756e3418 100644 (file)
@@ -65,7 +65,7 @@ static int bcm47xxnflash_remove(struct platform_device *pdev)
 {
        struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
 
-       nand_release(nand_to_mtd(&nflash->nand_chip));
+       nand_release(&nflash->nand_chip);
 
        return 0;
 }
index 60874de430eb7b743327f204d5d4cfcd6f770adf..9095a79ebc7db4f3d3273958cff7551ea99ba10f 100644 (file)
@@ -170,10 +170,9 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
  * NAND chip ops
  **************************************************/
 
-static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
-                                              unsigned int ctrl)
+static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct nand_chip *nand_chip,
+                                              int cmd, unsigned int ctrl)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
        u32 code = 0;
 
@@ -191,15 +190,14 @@ static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
 }
 
 /* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
-static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
-                                                 int chip)
+static void bcm47xxnflash_ops_bcm4706_select_chip(struct nand_chip *chip,
+                                                 int cs)
 {
        return;
 }
 
-static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
+static int bcm47xxnflash_ops_bcm4706_dev_ready(struct nand_chip *nand_chip)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 
        return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
@@ -212,11 +210,11 @@ static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
  * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
  * standard commands would be much more complicated.
  */
-static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
+static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct nand_chip *nand_chip,
                                              unsigned command, int column,
                                              int page_addr)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(nand_chip);
        struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
        struct bcma_drv_cc *cc = b47n->cc;
        u32 ctlcode;
@@ -229,10 +227,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
 
        switch (command) {
        case NAND_CMD_RESET:
-               nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
+               nand_chip->legacy.cmd_ctrl(nand_chip, command, NAND_CTRL_CLE);
 
                ndelay(100);
-               nand_wait_ready(mtd);
+               nand_wait_ready(nand_chip);
                break;
        case NAND_CMD_READID:
                ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
@@ -310,9 +308,9 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
        b47n->curr_command = command;
 }
 
-static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
+static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct nand_chip *nand_chip)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(nand_chip);
        struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
        struct bcma_drv_cc *cc = b47n->cc;
        u32 tmp = 0;
@@ -338,31 +336,31 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
        return 0;
 }
 
-static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
+static void bcm47xxnflash_ops_bcm4706_read_buf(struct nand_chip *nand_chip,
                                               uint8_t *buf, int len)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 
        switch (b47n->curr_command) {
        case NAND_CMD_READ0:
        case NAND_CMD_READOOB:
-               bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
+               bcm47xxnflash_ops_bcm4706_read(nand_to_mtd(nand_chip), buf,
+                                              len);
                return;
        }
 
        pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
 }
 
-static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
+static void bcm47xxnflash_ops_bcm4706_write_buf(struct nand_chip *nand_chip,
                                                const uint8_t *buf, int len)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
 
        switch (b47n->curr_command) {
        case NAND_CMD_SEQIN:
-               bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
+               bcm47xxnflash_ops_bcm4706_write(nand_to_mtd(nand_chip), buf,
+                                               len);
                return;
        }
 
@@ -386,16 +384,16 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
        u32 val;
 
        b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
-       nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
-       nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
-       b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
-       b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
-       b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
-       b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
-       b47n->nand_chip.set_features = nand_get_set_features_notsupp;
-       b47n->nand_chip.get_features = nand_get_set_features_notsupp;
-
-       nand_chip->chip_delay = 50;
+       nand_chip->legacy.cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
+       nand_chip->legacy.dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
+       b47n->nand_chip.legacy.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
+       b47n->nand_chip.legacy.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
+       b47n->nand_chip.legacy.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
+       b47n->nand_chip.legacy.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
+       b47n->nand_chip.legacy.set_features = nand_get_set_features_notsupp;
+       b47n->nand_chip.legacy.get_features = nand_get_set_features_notsupp;
+
+       nand_chip->legacy.chip_delay = 50;
        b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
        b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
 
@@ -423,7 +421,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
                        (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
 
        /* Scan NAND */
-       err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
+       err = nand_scan(&b47n->nand_chip, 1);
        if (err) {
                pr_err("Could not scan NAND flash: %d\n", err);
                goto exit;
index 4b90d5b380c2503fc88426890f719bd018d6d2f7..482c6f093f996cb5f2f04c0ab2389d5cc49a5c61 100644 (file)
@@ -1231,15 +1231,14 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
  * NAND MTD API: read/program/erase
  ***********************************************************************/
 
-static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
-       unsigned int ctrl)
+static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat,
+                             unsigned int ctrl)
 {
        /* intentionally left blank */
 }
 
-static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
+static int brcmnand_waitfunc(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct brcmnand_host *host = nand_get_controller_data(chip);
        struct brcmnand_controller *ctrl = host->ctrl;
        unsigned long timeo = msecs_to_jiffies(100);
@@ -1274,7 +1273,6 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
                                 enum brcmnand_llop_type type, u32 data,
                                 bool last_op)
 {
-       struct mtd_info *mtd = nand_to_mtd(&host->chip);
        struct nand_chip *chip = &host->chip;
        struct brcmnand_controller *ctrl = host->ctrl;
        u32 tmp;
@@ -1307,13 +1305,13 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
        (void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
 
        brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
-       return brcmnand_waitfunc(mtd, chip);
+       return brcmnand_waitfunc(chip);
 }
 
-static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
+static void brcmnand_cmdfunc(struct nand_chip *chip, unsigned command,
                             int column, int page_addr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct brcmnand_host *host = nand_get_controller_data(chip);
        struct brcmnand_controller *ctrl = host->ctrl;
        u64 addr = (u64)page_addr << chip->page_shift;
@@ -1383,7 +1381,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
        (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
 
        brcmnand_send_cmd(host, native_cmd);
-       brcmnand_waitfunc(mtd, chip);
+       brcmnand_waitfunc(chip);
 
        if (native_cmd == CMD_PARAMETER_READ ||
                        native_cmd == CMD_PARAMETER_CHANGE_COL) {
@@ -1417,9 +1415,8 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
                brcmnand_wp(mtd, 1);
 }
 
-static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
+static uint8_t brcmnand_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct brcmnand_host *host = nand_get_controller_data(chip);
        struct brcmnand_controller *ctrl = host->ctrl;
        uint8_t ret = 0;
@@ -1474,19 +1471,18 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
        return ret;
 }
 
-static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void brcmnand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
        int i;
 
        for (i = 0; i < len; i++, buf++)
-               *buf = brcmnand_read_byte(mtd);
+               *buf = brcmnand_read_byte(chip);
 }
 
-static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
-                                  int len)
+static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf,
+                              int len)
 {
        int i;
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct brcmnand_host *host = nand_get_controller_data(chip);
 
        switch (host->last_cmd) {
@@ -1617,7 +1613,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
                (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
                /* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
                brcmnand_send_cmd(host, CMD_PAGE_READ);
-               brcmnand_waitfunc(mtd, chip);
+               brcmnand_waitfunc(chip);
 
                if (likely(buf)) {
                        brcmnand_soc_data_bus_prepare(ctrl->soc, false);
@@ -1689,7 +1685,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
        sas = mtd->oobsize / chip->ecc.steps;
 
        /* read without ecc for verification */
-       ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
+       ret = chip->ecc.read_page_raw(chip, buf, true, page);
        if (ret)
                return ret;
 
@@ -1786,9 +1782,10 @@ try_dmaread:
        return 0;
 }
 
-static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                             uint8_t *buf, int oob_required, int page)
+static int brcmnand_read_page(struct nand_chip *chip, uint8_t *buf,
+                             int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct brcmnand_host *host = nand_get_controller_data(chip);
        u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
 
@@ -1798,10 +1795,11 @@ static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                        mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
 }
 
-static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                 uint8_t *buf, int oob_required, int page)
+static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+                                 int oob_required, int page)
 {
        struct brcmnand_host *host = nand_get_controller_data(chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
        int ret;
 
@@ -1814,17 +1812,18 @@ static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
        return ret;
 }
 
-static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                            int page)
+static int brcmnand_read_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
                        mtd->writesize >> FC_SHIFT,
                        NULL, (u8 *)chip->oob_poi);
 }
 
-static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                int page)
+static int brcmnand_read_oob_raw(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct brcmnand_host *host = nand_get_controller_data(chip);
 
        brcmnand_set_ecc_enabled(host, 0);
@@ -1892,7 +1891,7 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
 
                /* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
                brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
-               status = brcmnand_waitfunc(mtd, chip);
+               status = brcmnand_waitfunc(chip);
 
                if (status & NAND_STATUS_FAIL) {
                        dev_info(ctrl->dev, "program failed at %llx\n",
@@ -1906,9 +1905,10 @@ out:
        return ret;
 }
 
-static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                              const uint8_t *buf, int oob_required, int page)
+static int brcmnand_write_page(struct nand_chip *chip, const uint8_t *buf,
+                              int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct brcmnand_host *host = nand_get_controller_data(chip);
        void *oob = oob_required ? chip->oob_poi : NULL;
 
@@ -1918,10 +1918,10 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        return nand_prog_page_end_op(chip);
 }
 
-static int brcmnand_write_page_raw(struct mtd_info *mtd,
-                                  struct nand_chip *chip, const uint8_t *buf,
+static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
                                   int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct brcmnand_host *host = nand_get_controller_data(chip);
        void *oob = oob_required ? chip->oob_poi : NULL;
 
@@ -1933,16 +1933,16 @@ static int brcmnand_write_page_raw(struct mtd_info *mtd,
        return nand_prog_page_end_op(chip);
 }
 
-static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                                 int page)
+static int brcmnand_write_oob(struct nand_chip *chip, int page)
 {
-       return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
-                                 NULL, chip->oob_poi);
+       return brcmnand_write(nand_to_mtd(chip), chip,
+                             (u64)page << chip->page_shift, NULL,
+                             chip->oob_poi);
 }
 
-static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                 int page)
+static int brcmnand_write_oob_raw(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct brcmnand_host *host = nand_get_controller_data(chip);
        int ret;
 
@@ -2270,15 +2270,12 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
        mtd->owner = THIS_MODULE;
        mtd->dev.parent = &pdev->dev;
 
-       chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
-       chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
-
-       chip->cmd_ctrl = brcmnand_cmd_ctrl;
-       chip->cmdfunc = brcmnand_cmdfunc;
-       chip->waitfunc = brcmnand_waitfunc;
-       chip->read_byte = brcmnand_read_byte;
-       chip->read_buf = brcmnand_read_buf;
-       chip->write_buf = brcmnand_write_buf;
+       chip->legacy.cmd_ctrl = brcmnand_cmd_ctrl;
+       chip->legacy.cmdfunc = brcmnand_cmdfunc;
+       chip->legacy.waitfunc = brcmnand_waitfunc;
+       chip->legacy.read_byte = brcmnand_read_byte;
+       chip->legacy.read_buf = brcmnand_read_buf;
+       chip->legacy.write_buf = brcmnand_write_buf;
 
        chip->ecc.mode = NAND_ECC_HW;
        chip->ecc.read_page = brcmnand_read_page;
@@ -2301,7 +2298,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(mtd, 1);
+       ret = nand_scan(chip, 1);
        if (ret)
                return ret;
 
@@ -2616,7 +2613,7 @@ int brcmnand_remove(struct platform_device *pdev)
        struct brcmnand_host *host;
 
        list_for_each_entry(host, &ctrl->host_list, node)
-               nand_release(nand_to_mtd(&host->chip));
+               nand_release(&host->chip);
 
        clk_disable_unprepare(ctrl->clk);
 
index 1dbe43adcfe7d550aabb31885a0f366e21cc6b1a..c1a745940d12936123433878b5c63b4a81c39002 100644 (file)
@@ -100,9 +100,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 #define cafe_readl(cafe, addr)                 readl((cafe)->mmio + CAFE_##addr)
 #define cafe_writel(cafe, datum, addr)         writel(datum, (cafe)->mmio + CAFE_##addr)
 
-static int cafe_device_ready(struct mtd_info *mtd)
+static int cafe_device_ready(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
        int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
        uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
@@ -117,9 +116,8 @@ static int cafe_device_ready(struct mtd_info *mtd)
 }
 
 
-static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void cafe_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
 
        if (cafe->usedma)
@@ -133,9 +131,8 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
                len, cafe->datalen);
 }
 
-static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void cafe_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
 
        if (cafe->usedma)
@@ -148,22 +145,21 @@ static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
        cafe->datalen += len;
 }
 
-static uint8_t cafe_read_byte(struct mtd_info *mtd)
+static uint8_t cafe_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
        uint8_t d;
 
-       cafe_read_buf(mtd, &d, 1);
+       cafe_read_buf(chip, &d, 1);
        cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
 
        return d;
 }
 
-static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command,
                              int column, int page_addr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
        int adrbytes = 0;
        uint32_t ctl1;
@@ -313,13 +309,12 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
                cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
                return;
        }
-       nand_wait_ready(mtd);
+       nand_wait_ready(chip);
        cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
 }
 
-static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
+static void cafe_select_chip(struct nand_chip *chip, int chipnr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
 
        cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
@@ -346,17 +341,19 @@ static irqreturn_t cafe_nand_interrupt(int irq, void *id)
        return IRQ_HANDLED;
 }
 
-static int cafe_nand_write_oob(struct mtd_info *mtd,
-                              struct nand_chip *chip, int page)
+static int cafe_nand_write_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
                                 mtd->oobsize);
 }
 
 /* Don't use -- use nand_read_oob_std for now */
-static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                             int page)
+static int cafe_nand_read_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
 }
 /**
@@ -369,9 +366,10 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
  * The hw generator calculates the error syndrome automatically. Therefore
  * we need a special oob layout and handling.
  */
-static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                              uint8_t *buf, int oob_required, int page)
+static int cafe_nand_read_page(struct nand_chip *chip, uint8_t *buf,
+                              int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
        unsigned int max_bitflips = 0;
 
@@ -380,7 +378,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                     cafe_readl(cafe, NAND_ECC_SYN01));
 
        nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
 
        if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
                unsigned short syn[8], pat[4];
@@ -531,15 +529,15 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
 };
 
 
-static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
-                                         struct nand_chip *chip,
-                                         const uint8_t *buf, int oob_required,
-                                         int page)
+static int cafe_nand_write_page_lowlevel(struct nand_chip *chip,
+                                        const uint8_t *buf, int oob_required,
+                                        int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct cafe_priv *cafe = nand_get_controller_data(chip);
 
        nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        /* Set up ECC autogeneration */
        cafe->ctl2 |= (1<<30);
@@ -547,7 +545,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
        return nand_prog_page_end_op(chip);
 }
 
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int cafe_nand_block_bad(struct nand_chip *chip, loff_t ofs)
 {
        return 0;
 }
@@ -705,23 +703,23 @@ static int cafe_nand_probe(struct pci_dev *pdev,
                goto out_ior;
        }
 
-       cafe->nand.cmdfunc = cafe_nand_cmdfunc;
-       cafe->nand.dev_ready = cafe_device_ready;
-       cafe->nand.read_byte = cafe_read_byte;
-       cafe->nand.read_buf = cafe_read_buf;
-       cafe->nand.write_buf = cafe_write_buf;
+       cafe->nand.legacy.cmdfunc = cafe_nand_cmdfunc;
+       cafe->nand.legacy.dev_ready = cafe_device_ready;
+       cafe->nand.legacy.read_byte = cafe_read_byte;
+       cafe->nand.legacy.read_buf = cafe_read_buf;
+       cafe->nand.legacy.write_buf = cafe_write_buf;
        cafe->nand.select_chip = cafe_select_chip;
-       cafe->nand.set_features = nand_get_set_features_notsupp;
-       cafe->nand.get_features = nand_get_set_features_notsupp;
+       cafe->nand.legacy.set_features = nand_get_set_features_notsupp;
+       cafe->nand.legacy.get_features = nand_get_set_features_notsupp;
 
-       cafe->nand.chip_delay = 0;
+       cafe->nand.legacy.chip_delay = 0;
 
        /* Enable the following for a flash based bad block table */
        cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
 
        if (skipbbt) {
                cafe->nand.options |= NAND_SKIP_BBTSCAN;
-               cafe->nand.block_bad = cafe_nand_block_bad;
+               cafe->nand.legacy.block_bad = cafe_nand_block_bad;
        }
 
        if (numtimings && numtimings != 3) {
@@ -783,7 +781,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 
        /* Scan to find existence of the device */
        cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops;
-       err = nand_scan(mtd, 2);
+       err = nand_scan(&cafe->nand, 2);
        if (err)
                goto out_irq;
 
@@ -819,7 +817,7 @@ static void cafe_nand_remove(struct pci_dev *pdev)
        /* Disable NAND IRQ in global IRQ mask register */
        cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
        free_irq(pdev->irq, mtd);
-       nand_release(mtd);
+       nand_release(chip);
        free_rs(cafe->rs);
        pci_iounmap(pdev, cafe->mmio);
        dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
index b66e254b680281b4b951866ad9492473f8544f3d..143e4acacaae2acbb9f4e1347f12e994e2b9f0c1 100644 (file)
@@ -49,29 +49,26 @@ static const struct mtd_partition partition_info[] = {
 };
 #define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
 
-static u_char cmx270_read_byte(struct mtd_info *mtd)
+static u_char cmx270_read_byte(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-
-       return (readl(this->IO_ADDR_R) >> 16);
+       return (readl(this->legacy.IO_ADDR_R) >> 16);
 }
 
-static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void cmx270_write_buf(struct nand_chip *this, const u_char *buf,
+                            int len)
 {
        int i;
-       struct nand_chip *this = mtd_to_nand(mtd);
 
        for (i=0; i<len; i++)
-               writel((*buf++ << 16), this->IO_ADDR_W);
+               writel((*buf++ << 16), this->legacy.IO_ADDR_W);
 }
 
-static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void cmx270_read_buf(struct nand_chip *this, u_char *buf, int len)
 {
        int i;
-       struct nand_chip *this = mtd_to_nand(mtd);
 
        for (i=0; i<len; i++)
-               *buf++ = readl(this->IO_ADDR_R) >> 16;
+               *buf++ = readl(this->legacy.IO_ADDR_R) >> 16;
 }
 
 static inline void nand_cs_on(void)
@@ -89,11 +86,10 @@ static void nand_cs_off(void)
 /*
  *     hardware specific access to control-lines
  */
-static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
+static void cmx270_hwcontrol(struct nand_chip *this, int dat,
                             unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
+       unsigned int nandaddr = (unsigned int)this->legacy.IO_ADDR_W;
 
        dsb();
 
@@ -113,9 +109,9 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
        }
 
        dsb();
-       this->IO_ADDR_W = (void __iomem*)nandaddr;
+       this->legacy.IO_ADDR_W = (void __iomem*)nandaddr;
        if (dat != NAND_CMD_NONE)
-               writel((dat << 16), this->IO_ADDR_W);
+               writel((dat << 16), this->legacy.IO_ADDR_W);
 
        dsb();
 }
@@ -123,7 +119,7 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
 /*
  *     read device ready pin
  */
-static int cmx270_device_ready(struct mtd_info *mtd)
+static int cmx270_device_ready(struct nand_chip *this)
 {
        dsb();
 
@@ -177,23 +173,23 @@ static int __init cmx270_init(void)
        cmx270_nand_mtd->owner = THIS_MODULE;
 
        /* insert callbacks */
-       this->IO_ADDR_R = cmx270_nand_io;
-       this->IO_ADDR_W = cmx270_nand_io;
-       this->cmd_ctrl = cmx270_hwcontrol;
-       this->dev_ready = cmx270_device_ready;
+       this->legacy.IO_ADDR_R = cmx270_nand_io;
+       this->legacy.IO_ADDR_W = cmx270_nand_io;
+       this->legacy.cmd_ctrl = cmx270_hwcontrol;
+       this->legacy.dev_ready = cmx270_device_ready;
 
        /* 15 us command delay time */
-       this->chip_delay = 20;
+       this->legacy.chip_delay = 20;
        this->ecc.mode = NAND_ECC_SOFT;
        this->ecc.algo = NAND_ECC_HAMMING;
 
        /* read/write functions */
-       this->read_byte = cmx270_read_byte;
-       this->read_buf = cmx270_read_buf;
-       this->write_buf = cmx270_write_buf;
+       this->legacy.read_byte = cmx270_read_byte;
+       this->legacy.read_buf = cmx270_read_buf;
+       this->legacy.write_buf = cmx270_write_buf;
 
        /* Scan to find existence of the device */
-       ret = nand_scan(cmx270_nand_mtd, 1);
+       ret = nand_scan(this, 1);
        if (ret) {
                pr_notice("No NAND device\n");
                goto err_scan;
@@ -228,7 +224,7 @@ module_init(cmx270_init);
 static void __exit cmx270_cleanup(void)
 {
        /* Release resources, unregister device */
-       nand_release(cmx270_nand_mtd);
+       nand_release(mtd_to_nand(cmx270_nand_mtd));
 
        gpio_free(GPIO_NAND_RB);
        gpio_free(GPIO_NAND_CS);
index beafad62e7d5007f4a2313cf1dd469b0fabf88f1..c6f578aff5d90415a0c1f62f640c75c6b9c8f1d6 100644 (file)
 #define CS_NAND_ECC_CLRECC     (1<<1)
 #define CS_NAND_ECC_ENECC      (1<<0)
 
-static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void cs553x_read_buf(struct nand_chip *this, u_char *buf, int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-
        while (unlikely(len > 0x800)) {
-               memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
+               memcpy_fromio(buf, this->legacy.IO_ADDR_R, 0x800);
                buf += 0x800;
                len -= 0x800;
        }
-       memcpy_fromio(buf, this->IO_ADDR_R, len);
+       memcpy_fromio(buf, this->legacy.IO_ADDR_R, len);
 }
 
-static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void cs553x_write_buf(struct nand_chip *this, const u_char *buf, int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-
        while (unlikely(len > 0x800)) {
-               memcpy_toio(this->IO_ADDR_R, buf, 0x800);
+               memcpy_toio(this->legacy.IO_ADDR_R, buf, 0x800);
                buf += 0x800;
                len -= 0x800;
        }
-       memcpy_toio(this->IO_ADDR_R, buf, len);
+       memcpy_toio(this->legacy.IO_ADDR_R, buf, len);
 }
 
-static unsigned char cs553x_read_byte(struct mtd_info *mtd)
+static unsigned char cs553x_read_byte(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       return readb(this->IO_ADDR_R);
+       return readb(this->legacy.IO_ADDR_R);
 }
 
-static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
+static void cs553x_write_byte(struct nand_chip *this, u_char byte)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        int i = 100000;
 
-       while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
+       while (i && readb(this->legacy.IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
                udelay(1);
                i--;
        }
-       writeb(byte, this->IO_ADDR_W + 0x801);
+       writeb(byte, this->legacy.IO_ADDR_W + 0x801);
 }
 
-static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
+static void cs553x_hwcontrol(struct nand_chip *this, int cmd,
                             unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       void __iomem *mmio_base = this->IO_ADDR_R;
+       void __iomem *mmio_base = this->legacy.IO_ADDR_R;
        if (ctrl & NAND_CTRL_CHANGE) {
                unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
                writeb(ctl, mmio_base + MM_NAND_CTL);
        }
        if (cmd != NAND_CMD_NONE)
-               cs553x_write_byte(mtd, cmd);
+               cs553x_write_byte(this, cmd);
 }
 
-static int cs553x_device_ready(struct mtd_info *mtd)
+static int cs553x_device_ready(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       void __iomem *mmio_base = this->IO_ADDR_R;
+       void __iomem *mmio_base = this->legacy.IO_ADDR_R;
        unsigned char foo = readb(mmio_base + MM_NAND_STS);
 
        return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
 }
 
-static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
+static void cs_enable_hwecc(struct nand_chip *this, int mode)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       void __iomem *mmio_base = this->IO_ADDR_R;
+       void __iomem *mmio_base = this->legacy.IO_ADDR_R;
 
        writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
 }
 
-static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat,
+                           u_char *ecc_code)
 {
        uint32_t ecc;
-       struct nand_chip *this = mtd_to_nand(mtd);
-       void __iomem *mmio_base = this->IO_ADDR_R;
+       void __iomem *mmio_base = this->legacy.IO_ADDR_R;
 
        ecc = readl(mmio_base + MM_NAND_STS);
 
@@ -208,20 +199,20 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        new_mtd->owner = THIS_MODULE;
 
        /* map physical address */
-       this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
-       if (!this->IO_ADDR_R) {
+       this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = ioremap(adr, 4096);
+       if (!this->legacy.IO_ADDR_R) {
                pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr);
                err = -EIO;
                goto out_mtd;
        }
 
-       this->cmd_ctrl = cs553x_hwcontrol;
-       this->dev_ready = cs553x_device_ready;
-       this->read_byte = cs553x_read_byte;
-       this->read_buf = cs553x_read_buf;
-       this->write_buf = cs553x_write_buf;
+       this->legacy.cmd_ctrl = cs553x_hwcontrol;
+       this->legacy.dev_ready = cs553x_device_ready;
+       this->legacy.read_byte = cs553x_read_byte;
+       this->legacy.read_buf = cs553x_read_buf;
+       this->legacy.write_buf = cs553x_write_buf;
 
-       this->chip_delay = 0;
+       this->legacy.chip_delay = 0;
 
        this->ecc.mode = NAND_ECC_HW;
        this->ecc.size = 256;
@@ -241,7 +232,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        }
 
        /* Scan to find existence of the device */
-       err = nand_scan(new_mtd, 1);
+       err = nand_scan(this, 1);
        if (err)
                goto out_free;
 
@@ -251,7 +242,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
 out_free:
        kfree(new_mtd->name);
 out_ior:
-       iounmap(this->IO_ADDR_R);
+       iounmap(this->legacy.IO_ADDR_R);
 out_mtd:
        kfree(this);
 out:
@@ -333,10 +324,10 @@ static void __exit cs553x_cleanup(void)
                        continue;
 
                this = mtd_to_nand(mtd);
-               mmio_base = this->IO_ADDR_R;
+               mmio_base = this->legacy.IO_ADDR_R;
 
                /* Release resources, unregister device */
-               nand_release(mtd);
+               nand_release(this);
                kfree(mtd->name);
                cs553x_mtd[i] = NULL;
 
index 40145e206a6b7a1d6c82de067c1e55069dd9a9d5..80f228d23cd26da3c118e595edd4e5406ef0610f 100644 (file)
@@ -97,12 +97,11 @@ static inline void davinci_nand_writel(struct davinci_nand_info *info,
  * Access to hardware control lines:  ALE, CLE, secondary chipselect.
  */
 
-static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
+static void nand_davinci_hwcontrol(struct nand_chip *nand, int cmd,
                                   unsigned int ctrl)
 {
-       struct davinci_nand_info        *info = to_davinci_nand(mtd);
+       struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand));
        void __iomem                    *addr = info->current_cs;
-       struct nand_chip                *nand = mtd_to_nand(mtd);
 
        /* Did the control lines change? */
        if (ctrl & NAND_CTRL_CHANGE) {
@@ -111,16 +110,16 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
                else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
                        addr += info->mask_ale;
 
-               nand->IO_ADDR_W = addr;
+               nand->legacy.IO_ADDR_W = addr;
        }
 
        if (cmd != NAND_CMD_NONE)
-               iowrite8(cmd, nand->IO_ADDR_W);
+               iowrite8(cmd, nand->legacy.IO_ADDR_W);
 }
 
-static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
+static void nand_davinci_select_chip(struct nand_chip *nand, int chip)
 {
-       struct davinci_nand_info        *info = to_davinci_nand(mtd);
+       struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand));
 
        info->current_cs = info->vaddr;
 
@@ -128,8 +127,8 @@ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
        if (chip > 0)
                info->current_cs += info->mask_chipsel;
 
-       info->chip.IO_ADDR_W = info->current_cs;
-       info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
+       info->chip.legacy.IO_ADDR_W = info->current_cs;
+       info->chip.legacy.IO_ADDR_R = info->chip.legacy.IO_ADDR_W;
 }
 
 /*----------------------------------------------------------------------*/
@@ -146,16 +145,16 @@ static inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
                        + 4 * info->core_chipsel);
 }
 
-static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
+static void nand_davinci_hwctl_1bit(struct nand_chip *chip, int mode)
 {
        struct davinci_nand_info *info;
        uint32_t nandcfr;
        unsigned long flags;
 
-       info = to_davinci_nand(mtd);
+       info = to_davinci_nand(nand_to_mtd(chip));
 
        /* Reset ECC hardware */
-       nand_davinci_readecc_1bit(mtd);
+       nand_davinci_readecc_1bit(nand_to_mtd(chip));
 
        spin_lock_irqsave(&davinci_nand_lock, flags);
 
@@ -170,10 +169,10 @@ static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
 /*
  * Read hardware ECC value and pack into three bytes
  */
-static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
-                                     const u_char *dat, u_char *ecc_code)
+static int nand_davinci_calculate_1bit(struct nand_chip *chip,
+                                      const u_char *dat, u_char *ecc_code)
 {
-       unsigned int ecc_val = nand_davinci_readecc_1bit(mtd);
+       unsigned int ecc_val = nand_davinci_readecc_1bit(nand_to_mtd(chip));
        unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
 
        /* invert so that erased block ecc is correct */
@@ -185,10 +184,9 @@ static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
        return 0;
 }
 
-static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
+static int nand_davinci_correct_1bit(struct nand_chip *chip, u_char *dat,
                                     u_char *read_ecc, u_char *calc_ecc)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
                                          (read_ecc[2] << 16);
        uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
@@ -231,9 +229,9 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
  * OOB without recomputing ECC.
  */
 
-static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
+static void nand_davinci_hwctl_4bit(struct nand_chip *chip, int mode)
 {
-       struct davinci_nand_info *info = to_davinci_nand(mtd);
+       struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
        unsigned long flags;
        u32 val;
 
@@ -266,10 +264,10 @@ nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
 }
 
 /* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
-static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
-               const u_char *dat, u_char *ecc_code)
+static int nand_davinci_calculate_4bit(struct nand_chip *chip,
+                                      const u_char *dat, u_char *ecc_code)
 {
-       struct davinci_nand_info *info = to_davinci_nand(mtd);
+       struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
        u32 raw_ecc[4], *p;
        unsigned i;
 
@@ -303,11 +301,11 @@ static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
 /* Correct up to 4 bits in data we just read, using state left in the
  * hardware plus the ecc_code computed when it was first written.
  */
-static int nand_davinci_correct_4bit(struct mtd_info *mtd,
-               u_char *data, u_char *ecc_code, u_char *null)
+static int nand_davinci_correct_4bit(struct nand_chip *chip, u_char *data,
+                                    u_char *ecc_code, u_char *null)
 {
        int i;
-       struct davinci_nand_info *info = to_davinci_nand(mtd);
+       struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
        unsigned short ecc10[8];
        unsigned short *ecc16;
        u32 syndrome[4];
@@ -436,38 +434,35 @@ correct:
  * the two LSBs for NAND access ... so we can issue 32-bit reads/writes
  * and have that transparently morphed into multiple NAND operations.
  */
-static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void nand_davinci_read_buf(struct nand_chip *chip, uint8_t *buf,
+                                 int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
-               ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
+               ioread32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2);
        else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
-               ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
+               ioread16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1);
        else
-               ioread8_rep(chip->IO_ADDR_R, buf, len);
+               ioread8_rep(chip->legacy.IO_ADDR_R, buf, len);
 }
 
-static void nand_davinci_write_buf(struct mtd_info *mtd,
-               const uint8_t *buf, int len)
+static void nand_davinci_write_buf(struct nand_chip *chip, const uint8_t *buf,
+                                  int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
-               iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
+               iowrite32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2);
        else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
-               iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
+               iowrite16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1);
        else
-               iowrite8_rep(chip->IO_ADDR_R, buf, len);
+               iowrite8_rep(chip->legacy.IO_ADDR_R, buf, len);
 }
 
 /*
  * Check hardware register for wait status. Returns 1 if device is ready,
  * 0 if it is still busy.
  */
-static int nand_davinci_dev_ready(struct mtd_info *mtd)
+static int nand_davinci_dev_ready(struct nand_chip *chip)
 {
-       struct davinci_nand_info *info = to_davinci_nand(mtd);
+       struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
 
        return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
 }
@@ -764,9 +759,9 @@ static int nand_davinci_probe(struct platform_device *pdev)
        mtd->dev.parent         = &pdev->dev;
        nand_set_flash_node(&info->chip, pdev->dev.of_node);
 
-       info->chip.IO_ADDR_R    = vaddr;
-       info->chip.IO_ADDR_W    = vaddr;
-       info->chip.chip_delay   = 0;
+       info->chip.legacy.IO_ADDR_R     = vaddr;
+       info->chip.legacy.IO_ADDR_W     = vaddr;
+       info->chip.legacy.chip_delay    = 0;
        info->chip.select_chip  = nand_davinci_select_chip;
 
        /* options such as NAND_BBT_USE_FLASH */
@@ -786,12 +781,12 @@ static int nand_davinci_probe(struct platform_device *pdev)
        info->mask_cle          = pdata->mask_cle ? : MASK_CLE;
 
        /* Set address of hardware control function */
-       info->chip.cmd_ctrl     = nand_davinci_hwcontrol;
-       info->chip.dev_ready    = nand_davinci_dev_ready;
+       info->chip.legacy.cmd_ctrl      = nand_davinci_hwcontrol;
+       info->chip.legacy.dev_ready     = nand_davinci_dev_ready;
 
        /* Speed up buffer I/O */
-       info->chip.read_buf     = nand_davinci_read_buf;
-       info->chip.write_buf    = nand_davinci_write_buf;
+       info->chip.legacy.read_buf     = nand_davinci_read_buf;
+       info->chip.legacy.write_buf    = nand_davinci_write_buf;
 
        /* Use board-specific ECC config */
        info->chip.ecc.mode     = pdata->ecc_mode;
@@ -807,7 +802,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
 
        /* Scan to find existence of the device(s) */
        info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
-       ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1);
+       ret = nand_scan(&info->chip, pdata->mask_chipsel ? 2 : 1);
        if (ret < 0) {
                dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
                return ret;
@@ -841,7 +836,7 @@ static int nand_davinci_remove(struct platform_device *pdev)
                ecc4_busy = false;
        spin_unlock_irq(&davinci_nand_lock);
 
-       nand_release(nand_to_mtd(&info->chip));
+       nand_release(&info->chip);
 
        return 0;
 }
index b864b93dd289ed6eda8b2591006a6ab57922c1b7..830ea247277b1cac529e4814834eb20c05212e7f 100644 (file)
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * NAND Flash Controller Device Driver
  * Copyright Â© 2009-2010, Intel Corporation and its suppliers.
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
+ * Copyright (c) 2017 Socionext Inc.
+ *   Reworked by Masahiro Yamada <yamada.masahiro@socionext.com>
  */
 
 #include <linux/bitfield.h>
@@ -25,9 +20,8 @@
 
 #include "denali.h"
 
-MODULE_LICENSE("GPL");
-
 #define DENALI_NAND_NAME    "denali-nand"
+#define DENALI_DEFAULT_OOB_SKIP_BYTES  8
 
 /* for Indexed Addressing */
 #define DENALI_INDEXED_CTRL    0x00
@@ -222,8 +216,9 @@ static uint32_t denali_check_irq(struct denali_nand_info *denali)
        return irq_status;
 }
 
-static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void denali_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
        int i;
@@ -232,9 +227,10 @@ static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
                buf[i] = denali->host_read(denali, addr);
 }
 
-static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void denali_write_buf(struct nand_chip *chip, const uint8_t *buf,
+                            int len)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
        int i;
 
@@ -242,9 +238,9 @@ static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
                denali->host_write(denali, addr, buf[i]);
 }
 
-static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+static void denali_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
        uint16_t *buf16 = (uint16_t *)buf;
        int i;
@@ -253,10 +249,10 @@ static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
                buf16[i] = denali->host_read(denali, addr);
 }
 
-static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
+static void denali_write_buf16(struct nand_chip *chip, const uint8_t *buf,
                               int len)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
        const uint16_t *buf16 = (const uint16_t *)buf;
        int i;
@@ -265,32 +261,23 @@ static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
                denali->host_write(denali, addr, buf16[i]);
 }
 
-static uint8_t denali_read_byte(struct mtd_info *mtd)
+static uint8_t denali_read_byte(struct nand_chip *chip)
 {
        uint8_t byte;
 
-       denali_read_buf(mtd, &byte, 1);
+       denali_read_buf(chip, &byte, 1);
 
        return byte;
 }
 
-static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
-{
-       denali_write_buf(mtd, &byte, 1);
-}
-
-static uint16_t denali_read_word(struct mtd_info *mtd)
+static void denali_write_byte(struct nand_chip *chip, uint8_t byte)
 {
-       uint16_t word;
-
-       denali_read_buf16(mtd, (uint8_t *)&word, 2);
-
-       return word;
+       denali_write_buf(chip, &byte, 1);
 }
 
-static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        uint32_t type;
 
        if (ctrl & NAND_CLE)
@@ -301,7 +288,8 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
                return;
 
        /*
-        * Some commands are followed by chip->dev_ready or chip->waitfunc.
+        * Some commands are followed by chip->legacy.dev_ready or
+        * chip->legacy.waitfunc.
         * irq_status must be cleared here to catch the R/B# interrupt later.
         */
        if (ctrl & NAND_CTRL_CHANGE)
@@ -310,9 +298,9 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
        denali->host_write(denali, DENALI_BANK(denali) | type, dat);
 }
 
-static int denali_dev_ready(struct mtd_info *mtd)
+static int denali_dev_ready(struct nand_chip *chip)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
 
        return !!(denali_check_irq(denali) & INTR__INT_ACT);
 }
@@ -698,9 +686,10 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
                                           false);
 }
 
-static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int oob_required, int page)
+static int denali_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+                               int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        int writesize = mtd->writesize;
        int oobsize = mtd->oobsize;
@@ -773,17 +762,18 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
        return 0;
 }
 
-static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                          int page)
+static int denali_read_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        denali_oob_xfer(mtd, chip, page, 0);
 
        return 0;
 }
 
-static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                           int page)
+static int denali_write_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
 
        denali_reset_irq(denali);
@@ -793,9 +783,10 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
        return nand_prog_page_end_op(chip);
 }
 
-static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                           uint8_t *buf, int oob_required, int page)
+static int denali_read_page(struct nand_chip *chip, uint8_t *buf,
+                           int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        unsigned long uncor_ecc_flags = 0;
        int stat = 0;
@@ -814,7 +805,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                return stat;
 
        if (uncor_ecc_flags) {
-               ret = denali_read_oob(mtd, chip, page);
+               ret = denali_read_oob(chip, page);
                if (ret)
                        return ret;
 
@@ -825,9 +816,10 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        return stat;
 }
 
-static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                const uint8_t *buf, int oob_required, int page)
+static int denali_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+                                int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
        int writesize = mtd->writesize;
        int oobsize = mtd->oobsize;
@@ -903,25 +895,26 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
        return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
 }
 
-static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                            const uint8_t *buf, int oob_required, int page)
+static int denali_write_page(struct nand_chip *chip, const uint8_t *buf,
+                            int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct denali_nand_info *denali = mtd_to_denali(mtd);
 
        return denali_data_xfer(denali, (void *)buf, mtd->writesize,
                                page, 0, 1);
 }
 
-static void denali_select_chip(struct mtd_info *mtd, int chip)
+static void denali_select_chip(struct nand_chip *chip, int cs)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
 
-       denali->active_bank = chip;
+       denali->active_bank = cs;
 }
 
-static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+static int denali_waitfunc(struct nand_chip *chip)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        uint32_t irq_status;
 
        /* R/B# pin transitioned from low to high? */
@@ -930,9 +923,9 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
        return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
 }
 
-static int denali_erase(struct mtd_info *mtd, int page)
+static int denali_erase(struct nand_chip *chip, int page)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        uint32_t irq_status;
 
        denali_reset_irq(denali);
@@ -947,10 +940,10 @@ static int denali_erase(struct mtd_info *mtd, int page)
        return irq_status & INTR__ERASE_COMP ? 0 : -EIO;
 }
 
-static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
+static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
                                       const struct nand_data_interface *conf)
 {
-       struct denali_nand_info *denali = mtd_to_denali(mtd);
+       struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
        const struct nand_sdr_timings *timings;
        unsigned long t_x, mult_x;
        int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
@@ -1105,12 +1098,17 @@ static void denali_hw_init(struct denali_nand_info *denali)
                denali->revision = swab16(ioread32(denali->reg + REVISION));
 
        /*
-        * tell driver how many bit controller will skip before
-        * writing ECC code in OOB, this register may be already
-        * set by firmware. So we read this value out.
-        * if this value is 0, just let it be.
+        * Set how many bytes should be skipped before writing data in OOB.
+        * If a non-zero value has already been set (by firmware or something),
+        * just use it.  Otherwise, set the driver default.
         */
        denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
+       if (!denali->oob_skip_bytes) {
+               denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES;
+               iowrite32(denali->oob_skip_bytes,
+                         denali->reg + SPARE_AREA_SKIP_BYTES);
+       }
+
        denali_detect_max_banks(denali);
        iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
        iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
@@ -1277,11 +1275,11 @@ static int denali_attach_chip(struct nand_chip *chip)
        mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
 
        if (chip->options & NAND_BUSWIDTH_16) {
-               chip->read_buf = denali_read_buf16;
-               chip->write_buf = denali_write_buf16;
+               chip->legacy.read_buf = denali_read_buf16;
+               chip->legacy.write_buf = denali_write_buf16;
        } else {
-               chip->read_buf = denali_read_buf;
-               chip->write_buf = denali_write_buf;
+               chip->legacy.read_buf = denali_read_buf;
+               chip->legacy.write_buf = denali_write_buf;
        }
        chip->ecc.read_page = denali_read_page;
        chip->ecc.read_page_raw = denali_read_page_raw;
@@ -1289,7 +1287,7 @@ static int denali_attach_chip(struct nand_chip *chip)
        chip->ecc.write_page_raw = denali_write_page_raw;
        chip->ecc.read_oob = denali_read_oob;
        chip->ecc.write_oob = denali_write_oob;
-       chip->erase = denali_erase;
+       chip->legacy.erase = denali_erase;
 
        ret = denali_multidev_fixup(denali);
        if (ret)
@@ -1358,12 +1356,11 @@ int denali_init(struct denali_nand_info *denali)
                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;
+       chip->legacy.read_byte = denali_read_byte;
+       chip->legacy.write_byte = denali_write_byte;
+       chip->legacy.cmd_ctrl = denali_cmd_ctrl;
+       chip->legacy.dev_ready = denali_dev_ready;
+       chip->legacy.waitfunc = denali_waitfunc;
 
        if (features & FEATURES__INDEX_ADDR) {
                denali->host_read = denali_indexed_read;
@@ -1378,7 +1375,7 @@ int denali_init(struct denali_nand_info *denali)
                chip->setup_data_interface = denali_setup_data_interface;
 
        chip->dummy_controller.ops = &denali_controller_ops;
-       ret = nand_scan(mtd, denali->max_banks);
+       ret = nand_scan(chip, denali->max_banks);
        if (ret)
                goto disable_irq;
 
@@ -1401,9 +1398,11 @@ EXPORT_SYMBOL(denali_init);
 
 void denali_remove(struct denali_nand_info *denali)
 {
-       struct mtd_info *mtd = nand_to_mtd(&denali->nand);
-
-       nand_release(mtd);
+       nand_release(&denali->nand);
        denali_disable_irq(denali);
 }
 EXPORT_SYMBOL(denali_remove);
+
+MODULE_DESCRIPTION("Driver core for Denali NAND controller");
+MODULE_AUTHOR("Intel Corporation and its suppliers");
+MODULE_LICENSE("GPL v2");
index 1f8feaf924ebc66bc1d62f9fea43a6a915547a1e..57a5498f58bbb493dc8379c0341e45ea33e6a2ac 100644 (file)
@@ -1,15 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * NAND Flash Controller Device Driver
  * Copyright (c) 2009 - 2010, Intel Corporation and its suppliers.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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 __DENALI_H__
index 0faaad032e5fbfbcbd7fb7c2e8b92d2c67863a4f..7c6a8a426606afdf37ff59e63108c262437a4017 100644 (file)
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * NAND Flash Controller Device Driver for DT
  *
  * Copyright Â© 2011, Picochip.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
  */
 
 #include <linux/clk.h>
@@ -202,6 +194,6 @@ static struct platform_driver denali_dt_driver = {
 };
 module_platform_driver(denali_dt_driver);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Jamie Iles");
 MODULE_DESCRIPTION("DT driver for Denali NAND controller");
index 7c8efc4c7bdfe1cd0bf5b07493b7e8da46efccee..48e9ac54ad531a884fe5d24519fbadfbb0ff2547 100644 (file)
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * NAND Flash Controller Device Driver
  * Copyright Â© 2009-2010, Intel Corporation and its suppliers.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
  */
 
 #include <linux/errno.h>
index 3c46188dd6d2ba68a9b78bdd140dcdf1070fa800..3a4c373affab3048866b40cda681c2a1335c3029 100644 (file)
@@ -83,9 +83,9 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
 #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
 #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
 
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+static void doc200x_hwcontrol(struct nand_chip *this, int cmd,
                              unsigned int bitmask);
-static void doc200x_select_chip(struct mtd_info *mtd, int chip);
+static void doc200x_select_chip(struct nand_chip *this, int chip);
 
 static int debug = 0;
 module_param(debug, int, 0);
@@ -290,9 +290,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
        return ret;
 }
 
-static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
+static void doc2000_write_byte(struct nand_chip *this, u_char datum)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
 
@@ -302,9 +301,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
        WriteDOC(datum, docptr, 2k_CDSN_IO);
 }
 
-static u_char doc2000_read_byte(struct mtd_info *mtd)
+static u_char doc2000_read_byte(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        u_char ret;
@@ -317,9 +315,9 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
        return ret;
 }
 
-static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+static void doc2000_writebuf(struct nand_chip *this, const u_char *buf,
+                            int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int i;
@@ -334,9 +332,8 @@ static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
                printk("\n");
 }
 
-static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2000_readbuf(struct nand_chip *this, u_char *buf, int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int i;
@@ -344,14 +341,12 @@ static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
        if (debug)
                printk("readbuf of %d bytes: ", len);
 
-       for (i = 0; i < len; i++) {
+       for (i = 0; i < len; i++)
                buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
-       }
 }
 
-static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2000_readbuf_dword(struct nand_chip *this, u_char *buf, int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int i;
@@ -376,19 +371,19 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
        struct doc_priv *doc = nand_get_controller_data(this);
        uint16_t ret;
 
-       doc200x_select_chip(mtd, nr);
-       doc200x_hwcontrol(mtd, NAND_CMD_READID,
+       doc200x_select_chip(this, nr);
+       doc200x_hwcontrol(this, NAND_CMD_READID,
                          NAND_CTRL_CLE | NAND_CTRL_CHANGE);
-       doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
-       doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+       doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+       doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
 
        /* We can't use dev_ready here, but at least we wait for the
         * command to complete
         */
        udelay(50);
 
-       ret = this->read_byte(mtd) << 8;
-       ret |= this->read_byte(mtd);
+       ret = this->legacy.read_byte(this) << 8;
+       ret |= this->legacy.read_byte(this);
 
        if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
                /* First chip probe. See if we get same results by 32-bit access */
@@ -398,10 +393,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
                } ident;
                void __iomem *docptr = doc->virtadr;
 
-               doc200x_hwcontrol(mtd, NAND_CMD_READID,
+               doc200x_hwcontrol(this, NAND_CMD_READID,
                                  NAND_CTRL_CLE | NAND_CTRL_CHANGE);
-               doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
-               doc200x_hwcontrol(mtd, NAND_CMD_NONE,
+               doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+               doc200x_hwcontrol(this, NAND_CMD_NONE,
                                  NAND_NCE | NAND_CTRL_CHANGE);
 
                udelay(50);
@@ -409,7 +404,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
                ident.dword = readl(docptr + DoC_2k_CDSN_IO);
                if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
                        pr_info("DiskOnChip 2000 responds to DWORD access\n");
-                       this->read_buf = &doc2000_readbuf_dword;
+                       this->legacy.read_buf = &doc2000_readbuf_dword;
                }
        }
 
@@ -438,7 +433,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
        pr_debug("Detected %d chips per floor.\n", i);
 }
 
-static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
+static int doc200x_wait(struct nand_chip *this)
 {
        struct doc_priv *doc = nand_get_controller_data(this);
 
@@ -447,14 +442,13 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
        DoC_WaitReady(doc);
        nand_status_op(this, NULL);
        DoC_WaitReady(doc);
-       status = (int)this->read_byte(mtd);
+       status = (int)this->legacy.read_byte(this);
 
        return status;
 }
 
-static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
+static void doc2001_write_byte(struct nand_chip *this, u_char datum)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
 
@@ -463,9 +457,8 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
        WriteDOC(datum, docptr, WritePipeTerm);
 }
 
-static u_char doc2001_read_byte(struct mtd_info *mtd)
+static u_char doc2001_read_byte(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
 
@@ -477,9 +470,8 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
        return ReadDOC(docptr, LastDataRead);
 }
 
-static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+static void doc2001_writebuf(struct nand_chip *this, const u_char *buf, int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int i;
@@ -490,9 +482,8 @@ static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
        WriteDOC(0x00, docptr, WritePipeTerm);
 }
 
-static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2001_readbuf(struct nand_chip *this, u_char *buf, int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int i;
@@ -507,9 +498,8 @@ static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
        buf[i] = ReadDOC(docptr, LastDataRead);
 }
 
-static u_char doc2001plus_read_byte(struct mtd_info *mtd)
+static u_char doc2001plus_read_byte(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        u_char ret;
@@ -522,9 +512,8 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
        return ret;
 }
 
-static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+static void doc2001plus_writebuf(struct nand_chip *this, const u_char *buf, int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int i;
@@ -540,9 +529,8 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int le
                printk("\n");
 }
 
-static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2001plus_readbuf(struct nand_chip *this, u_char *buf, int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int i;
@@ -571,9 +559,8 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
                printk("\n");
 }
 
-static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
+static void doc2001plus_select_chip(struct nand_chip *this, int chip)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int floor = 0;
@@ -598,9 +585,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
        doc->curfloor = floor;
 }
 
-static void doc200x_select_chip(struct mtd_info *mtd, int chip)
+static void doc200x_select_chip(struct nand_chip *this, int chip)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int floor = 0;
@@ -615,12 +601,12 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
        chip -= (floor * doc->chips_per_floor);
 
        /* 11.4.4 -- deassert CE before changing chip */
-       doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+       doc200x_hwcontrol(this, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
 
        WriteDOC(floor, docptr, FloorSelect);
        WriteDOC(chip, docptr, CDSNDeviceSelect);
 
-       doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+       doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
 
        doc->curchip = chip;
        doc->curfloor = floor;
@@ -628,10 +614,9 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
 
 #define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
 
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+static void doc200x_hwcontrol(struct nand_chip *this, int cmd,
                              unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
 
@@ -646,15 +631,16 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
        }
        if (cmd != NAND_CMD_NONE) {
                if (DoC_is_2000(doc))
-                       doc2000_write_byte(mtd, cmd);
+                       doc2000_write_byte(this, cmd);
                else
-                       doc2001_write_byte(mtd, cmd);
+                       doc2001_write_byte(this, cmd);
        }
 }
 
-static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static void doc2001plus_command(struct nand_chip *this, unsigned command,
+                               int column, int page_addr)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
 
@@ -729,13 +715,13 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
                return;
 
        case NAND_CMD_RESET:
-               if (this->dev_ready)
+               if (this->legacy.dev_ready)
                        break;
-               udelay(this->chip_delay);
+               udelay(this->legacy.chip_delay);
                WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
                WriteDOC(0, docptr, Mplus_WritePipeTerm);
                WriteDOC(0, docptr, Mplus_WritePipeTerm);
-               while (!(this->read_byte(mtd) & 0x40)) ;
+               while (!(this->legacy.read_byte(this) & 0x40)) ;
                return;
 
                /* This applies to read commands */
@@ -744,8 +730,8 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
                 * If we don't have access to the busy pin, we apply the given
                 * command delay
                 */
-               if (!this->dev_ready) {
-                       udelay(this->chip_delay);
+               if (!this->legacy.dev_ready) {
+                       udelay(this->legacy.chip_delay);
                        return;
                }
        }
@@ -754,12 +740,11 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
         * any case on any machine. */
        ndelay(100);
        /* wait until command is processed */
-       while (!this->dev_ready(mtd)) ;
+       while (!this->legacy.dev_ready(this)) ;
 }
 
-static int doc200x_dev_ready(struct mtd_info *mtd)
+static int doc200x_dev_ready(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
 
@@ -790,16 +775,15 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
        }
 }
 
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int doc200x_block_bad(struct nand_chip *this, loff_t ofs)
 {
        /* This is our last resort if we couldn't find or create a BBT.  Just
           pretend all blocks are good. */
        return 0;
 }
 
-static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
+static void doc200x_enable_hwecc(struct nand_chip *this, int mode)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
 
@@ -816,9 +800,8 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
        }
 }
 
-static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
+static void doc2001plus_enable_hwecc(struct nand_chip *this, int mode)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
 
@@ -836,9 +819,9 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
 }
 
 /* This code is only called on write */
-static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
+static int doc200x_calculate_ecc(struct nand_chip *this, const u_char *dat,
+                                unsigned char *ecc_code)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        int i;
@@ -895,11 +878,10 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsign
        return 0;
 }
 
-static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
+static int doc200x_correct_data(struct nand_chip *this, u_char *dat,
                                u_char *read_ecc, u_char *isnull)
 {
        int i, ret = 0;
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
        void __iomem *docptr = doc->virtadr;
        uint8_t calc_ecc[6];
@@ -1357,9 +1339,9 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
        struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
 
-       this->read_byte = doc2000_read_byte;
-       this->write_buf = doc2000_writebuf;
-       this->read_buf = doc2000_readbuf;
+       this->legacy.read_byte = doc2000_read_byte;
+       this->legacy.write_buf = doc2000_writebuf;
+       this->legacy.read_buf = doc2000_readbuf;
        doc->late_init = nftl_scan_bbt;
 
        doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
@@ -1373,9 +1355,9 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
        struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
 
-       this->read_byte = doc2001_read_byte;
-       this->write_buf = doc2001_writebuf;
-       this->read_buf = doc2001_readbuf;
+       this->legacy.read_byte = doc2001_read_byte;
+       this->legacy.write_buf = doc2001_writebuf;
+       this->legacy.read_buf = doc2001_readbuf;
 
        ReadDOC(doc->virtadr, ChipID);
        ReadDOC(doc->virtadr, ChipID);
@@ -1403,13 +1385,13 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
        struct nand_chip *this = mtd_to_nand(mtd);
        struct doc_priv *doc = nand_get_controller_data(this);
 
-       this->read_byte = doc2001plus_read_byte;
-       this->write_buf = doc2001plus_writebuf;
-       this->read_buf = doc2001plus_readbuf;
+       this->legacy.read_byte = doc2001plus_read_byte;
+       this->legacy.write_buf = doc2001plus_writebuf;
+       this->legacy.read_buf = doc2001plus_readbuf;
        doc->late_init = inftl_scan_bbt;
-       this->cmd_ctrl = NULL;
+       this->legacy.cmd_ctrl = NULL;
        this->select_chip = doc2001plus_select_chip;
-       this->cmdfunc = doc2001plus_command;
+       this->legacy.cmdfunc = doc2001plus_command;
        this->ecc.hwctl = doc2001plus_enable_hwecc;
 
        doc->chips_per_floor = 1;
@@ -1587,10 +1569,10 @@ static int __init doc_probe(unsigned long physadr)
 
        nand_set_controller_data(nand, doc);
        nand->select_chip       = doc200x_select_chip;
-       nand->cmd_ctrl          = doc200x_hwcontrol;
-       nand->dev_ready         = doc200x_dev_ready;
-       nand->waitfunc          = doc200x_wait;
-       nand->block_bad         = doc200x_block_bad;
+       nand->legacy.cmd_ctrl           = doc200x_hwcontrol;
+       nand->legacy.dev_ready  = doc200x_dev_ready;
+       nand->legacy.waitfunc   = doc200x_wait;
+       nand->legacy.block_bad  = doc200x_block_bad;
        nand->ecc.hwctl         = doc200x_enable_hwecc;
        nand->ecc.calculate     = doc200x_calculate_ecc;
        nand->ecc.correct       = doc200x_correct_data;
@@ -1620,14 +1602,14 @@ static int __init doc_probe(unsigned long physadr)
        else
                numchips = doc2001_init(mtd);
 
-       if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
+       if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) {
                /* DBB note: i believe nand_release is necessary here, as
                   buffers may have been allocated in nand_base.  Check with
                   Thomas. FIX ME! */
                /* nand_release will call mtd_device_unregister, but we
                   haven't yet added it.  This is handled without incident by
                   mtd_device_unregister, as far as I can tell. */
-               nand_release(mtd);
+               nand_release(nand);
                goto fail;
        }
 
@@ -1662,7 +1644,7 @@ static void release_nanddoc(void)
                doc = nand_get_controller_data(nand);
 
                nextmtd = doc->nextdoc;
-               nand_release(mtd);
+               nand_release(nand);
                iounmap(doc->virtadr);
                release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
                free_rs(doc->rs_decoder);
diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c
deleted file mode 100644 (file)
index 427fcbc..0000000
+++ /dev/null
@@ -1,1442 +0,0 @@
-/*
- *  Copyright Â© 2012 Mike Dunn <mikedunn@newsguy.com>
- *
- * mtd nand driver for M-Systems DiskOnChip G4
- *
- * 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.
- *
- * Tested on the Palm Treo 680.  The G4 is also present on Toshiba Portege, Asus
- * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others.
- * Should work on these as well.  Let me know!
- *
- * TODO:
- *
- *  Mechanism for management of password-protected areas
- *
- *  Hamming ecc when reading oob only
- *
- *  According to the M-Sys documentation, this device is also available in a
- *  "dual-die" configuration having a 256MB capacity, but no mechanism for
- *  detecting this variant is documented.  Currently this driver assumes 128MB
- *  capacity.
- *
- *  Support for multiple cascaded devices ("floors").  Not sure which gadgets
- *  contain multiple G4s in a cascaded configuration, if any.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/bitops.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/bch.h>
-#include <linux/bitrev.h>
-#include <linux/jiffies.h>
-
-/*
- * In "reliable mode" consecutive 2k pages are used in parallel (in some
- * fashion) to store the same data.  The data can be read back from the
- * even-numbered pages in the normal manner; odd-numbered pages will appear to
- * contain junk.  Systems that boot from the docg4 typically write the secondary
- * program loader (SPL) code in this mode.  The SPL is loaded by the initial
- * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
- * to the reset vector address).  This module parameter enables you to use this
- * driver to write the SPL.  When in this mode, no more than 2k of data can be
- * written at a time, because the addresses do not increment in the normal
- * manner, and the starting offset must be within an even-numbered 2k region;
- * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
- * 0x1a00, ...  Reliable mode is a special case and should not be used unless
- * you know what you're doing.
- */
-static bool reliable_mode;
-module_param(reliable_mode, bool, 0);
-MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
-
-/*
- * You'll want to ignore badblocks if you're reading a partition that contains
- * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
- * it does not use mtd nand's method for marking bad blocks (using oob area).
- * This will also skip the check of the "page written" flag.
- */
-static bool ignore_badblocks;
-module_param(ignore_badblocks, bool, 0);
-MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed");
-
-struct docg4_priv {
-       struct mtd_info *mtd;
-       struct device *dev;
-       void __iomem *virtadr;
-       int status;
-       struct {
-               unsigned int command;
-               int column;
-               int page;
-       } last_command;
-       uint8_t oob_buf[16];
-       uint8_t ecc_buf[7];
-       int oob_page;
-       struct bch_control *bch;
-};
-
-/*
- * Defines prefixed with DOCG4 are unique to the diskonchip G4.  All others are
- * shared with other diskonchip devices (P3, G3 at least).
- *
- * Functions with names prefixed with docg4_ are mtd / nand interface functions
- * (though they may also be called internally).  All others are internal.
- */
-
-#define DOC_IOSPACE_DATA               0x0800
-
-/* register offsets */
-#define DOC_CHIPID                     0x1000
-#define DOC_DEVICESELECT               0x100a
-#define DOC_ASICMODE                   0x100c
-#define DOC_DATAEND                    0x101e
-#define DOC_NOP                                0x103e
-
-#define DOC_FLASHSEQUENCE              0x1032
-#define DOC_FLASHCOMMAND               0x1034
-#define DOC_FLASHADDRESS               0x1036
-#define DOC_FLASHCONTROL               0x1038
-#define DOC_ECCCONF0                   0x1040
-#define DOC_ECCCONF1                   0x1042
-#define DOC_HAMMINGPARITY              0x1046
-#define DOC_BCH_SYNDROM(idx)           (0x1048 + idx)
-
-#define DOC_ASICMODECONFIRM            0x1072
-#define DOC_CHIPID_INV                 0x1074
-#define DOC_POWERMODE                  0x107c
-
-#define DOCG4_MYSTERY_REG              0x1050
-
-/* apparently used only to write oob bytes 6 and 7 */
-#define DOCG4_OOB_6_7                  0x1052
-
-/* DOC_FLASHSEQUENCE register commands */
-#define DOC_SEQ_RESET                  0x00
-#define DOCG4_SEQ_PAGE_READ            0x03
-#define DOCG4_SEQ_FLUSH                        0x29
-#define DOCG4_SEQ_PAGEWRITE            0x16
-#define DOCG4_SEQ_PAGEPROG             0x1e
-#define DOCG4_SEQ_BLOCKERASE           0x24
-#define DOCG4_SEQ_SETMODE              0x45
-
-/* DOC_FLASHCOMMAND register commands */
-#define DOCG4_CMD_PAGE_READ             0x00
-#define DOC_CMD_ERASECYCLE2            0xd0
-#define DOCG4_CMD_FLUSH                 0x70
-#define DOCG4_CMD_READ2                 0x30
-#define DOC_CMD_PROG_BLOCK_ADDR                0x60
-#define DOCG4_CMD_PAGEWRITE            0x80
-#define DOC_CMD_PROG_CYCLE2            0x10
-#define DOCG4_CMD_FAST_MODE            0xa3 /* functionality guessed */
-#define DOC_CMD_RELIABLE_MODE          0x22
-#define DOC_CMD_RESET                  0xff
-
-/* DOC_POWERMODE register bits */
-#define DOC_POWERDOWN_READY            0x80
-
-/* DOC_FLASHCONTROL register bits */
-#define DOC_CTRL_CE                    0x10
-#define DOC_CTRL_UNKNOWN               0x40
-#define DOC_CTRL_FLASHREADY            0x01
-
-/* DOC_ECCCONF0 register bits */
-#define DOC_ECCCONF0_READ_MODE         0x8000
-#define DOC_ECCCONF0_UNKNOWN           0x2000
-#define DOC_ECCCONF0_ECC_ENABLE                0x1000
-#define DOC_ECCCONF0_DATA_BYTES_MASK   0x07ff
-
-/* DOC_ECCCONF1 register bits */
-#define DOC_ECCCONF1_BCH_SYNDROM_ERR   0x80
-#define DOC_ECCCONF1_ECC_ENABLE         0x07
-#define DOC_ECCCONF1_PAGE_IS_WRITTEN   0x20
-
-/* DOC_ASICMODE register bits */
-#define DOC_ASICMODE_RESET             0x00
-#define DOC_ASICMODE_NORMAL            0x01
-#define DOC_ASICMODE_POWERDOWN         0x02
-#define DOC_ASICMODE_MDWREN            0x04
-#define DOC_ASICMODE_BDETCT_RESET      0x08
-#define DOC_ASICMODE_RSTIN_RESET       0x10
-#define DOC_ASICMODE_RAM_WE            0x20
-
-/* good status values read after read/write/erase operations */
-#define DOCG4_PROGSTATUS_GOOD          0x51
-#define DOCG4_PROGSTATUS_GOOD_2        0xe0
-
-/*
- * On read operations (page and oob-only), the first byte read from I/O reg is a
- * status.  On error, it reads 0x73; otherwise, it reads either 0x71 (first read
- * after reset only) or 0x51, so bit 1 is presumed to be an error indicator.
- */
-#define DOCG4_READ_ERROR           0x02 /* bit 1 indicates read error */
-
-/* anatomy of the device */
-#define DOCG4_CHIP_SIZE        0x8000000
-#define DOCG4_PAGE_SIZE        0x200
-#define DOCG4_PAGES_PER_BLOCK  0x200
-#define DOCG4_BLOCK_SIZE       (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE)
-#define DOCG4_NUMBLOCKS        (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE)
-#define DOCG4_OOB_SIZE         0x10
-#define DOCG4_CHIP_SHIFT       27    /* log_2(DOCG4_CHIP_SIZE) */
-#define DOCG4_PAGE_SHIFT       9     /* log_2(DOCG4_PAGE_SIZE) */
-#define DOCG4_ERASE_SHIFT      18    /* log_2(DOCG4_BLOCK_SIZE) */
-
-/* all but the last byte is included in ecc calculation */
-#define DOCG4_BCH_SIZE         (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1)
-
-#define DOCG4_USERDATA_LEN     520 /* 512 byte page plus 8 oob avail to user */
-
-/* expected values from the ID registers */
-#define DOCG4_IDREG1_VALUE     0x0400
-#define DOCG4_IDREG2_VALUE     0xfbff
-
-/* primitive polynomial used to build the Galois field used by hw ecc gen */
-#define DOCG4_PRIMITIVE_POLY   0x4443
-
-#define DOCG4_M                14  /* Galois field is of order 2^14 */
-#define DOCG4_T                4   /* BCH alg corrects up to 4 bit errors */
-
-#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
-#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
-
-/*
- * Bytes 0, 1 are used as badblock marker.
- * Bytes 2 - 6 are available to the user.
- * Byte 7 is hamming ecc for first 7 oob bytes only.
- * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
- * Byte 15 (the last) is used by the driver as a "page written" flag.
- */
-static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section,
-                              struct mtd_oob_region *oobregion)
-{
-       if (section)
-               return -ERANGE;
-
-       oobregion->offset = 7;
-       oobregion->length = 9;
-
-       return 0;
-}
-
-static int docg4_ooblayout_free(struct mtd_info *mtd, int section,
-                               struct mtd_oob_region *oobregion)
-{
-       if (section)
-               return -ERANGE;
-
-       oobregion->offset = 2;
-       oobregion->length = 5;
-
-       return 0;
-}
-
-static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
-       .ecc = docg4_ooblayout_ecc,
-       .free = docg4_ooblayout_free,
-};
-
-/*
- * The device has a nop register which M-Sys claims is for the purpose of
- * inserting precise delays.  But beware; at least some operations fail if the
- * nop writes are replaced with a generic delay!
- */
-static inline void write_nop(void __iomem *docptr)
-{
-       writew(0, docptr + DOC_NOP);
-}
-
-static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-       int i;
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       uint16_t *p = (uint16_t *) buf;
-       len >>= 1;
-
-       for (i = 0; i < len; i++)
-               p[i] = readw(nand->IO_ADDR_R);
-}
-
-static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-       int i;
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       uint16_t *p = (uint16_t *) buf;
-       len >>= 1;
-
-       for (i = 0; i < len; i++)
-               writew(p[i], nand->IO_ADDR_W);
-}
-
-static int poll_status(struct docg4_priv *doc)
-{
-       /*
-        * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
-        * register.  Operations known to take a long time (e.g., block erase)
-        * should sleep for a while before calling this.
-        */
-
-       uint16_t flash_status;
-       unsigned long timeo;
-       void __iomem *docptr = doc->virtadr;
-
-       dev_dbg(doc->dev, "%s...\n", __func__);
-
-       /* hardware quirk requires reading twice initially */
-       flash_status = readw(docptr + DOC_FLASHCONTROL);
-
-       timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */
-       do {
-               cpu_relax();
-               flash_status = readb(docptr + DOC_FLASHCONTROL);
-       } while (!(flash_status & DOC_CTRL_FLASHREADY) &&
-                time_before(jiffies, timeo));
-
-       if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) {
-               dev_err(doc->dev, "%s: timed out!\n", __func__);
-               return NAND_STATUS_FAIL;
-       }
-
-       return 0;
-}
-
-
-static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand)
-{
-
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       int status = NAND_STATUS_WP;       /* inverse logic?? */
-       dev_dbg(doc->dev, "%s...\n", __func__);
-
-       /* report any previously unreported error */
-       if (doc->status) {
-               status |= doc->status;
-               doc->status = 0;
-               return status;
-       }
-
-       status |= poll_status(doc);
-       return status;
-}
-
-static void docg4_select_chip(struct mtd_info *mtd, int chip)
-{
-       /*
-        * Select among multiple cascaded chips ("floors").  Multiple floors are
-        * not yet supported, so the only valid non-negative value is 0.
-        */
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-
-       dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip);
-
-       if (chip < 0)
-               return;         /* deselected */
-
-       if (chip > 0)
-               dev_warn(doc->dev, "multiple floors currently unsupported\n");
-
-       writew(0, docptr + DOC_DEVICESELECT);
-}
-
-static void reset(struct mtd_info *mtd)
-{
-       /* full device reset */
-
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-
-       writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN,
-              docptr + DOC_ASICMODE);
-       writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN),
-              docptr + DOC_ASICMODECONFIRM);
-       write_nop(docptr);
-
-       writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN,
-              docptr + DOC_ASICMODE);
-       writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN),
-              docptr + DOC_ASICMODECONFIRM);
-
-       writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1);
-
-       poll_status(doc);
-}
-
-static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf)
-{
-       /* read the 7 hw-generated ecc bytes */
-
-       int i;
-       for (i = 0; i < 7; i++) { /* hw quirk; read twice */
-               ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
-               ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
-       }
-}
-
-static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
-{
-       /*
-        * Called after a page read when hardware reports bitflips.
-        * Up to four bitflips can be corrected.
-        */
-
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-       int i, numerrs, errpos[4];
-       const uint8_t blank_read_hwecc[8] = {
-               0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 };
-
-       read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */
-
-       /* check if read error is due to a blank page */
-       if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7))
-               return 0;       /* yes */
-
-       /* skip additional check of "written flag" if ignore_badblocks */
-       if (ignore_badblocks == false) {
-
-               /*
-                * If the hw ecc bytes are not those of a blank page, there's
-                * still a chance that the page is blank, but was read with
-                * errors.  Check the "written flag" in last oob byte, which
-                * is set to zero when a page is written.  If more than half
-                * the bits are set, assume a blank page.  Unfortunately, the
-                * bit flips(s) are not reported in stats.
-                */
-
-               if (nand->oob_poi[15]) {
-                       int bit, numsetbits = 0;
-                       unsigned long written_flag = nand->oob_poi[15];
-                       for_each_set_bit(bit, &written_flag, 8)
-                               numsetbits++;
-                       if (numsetbits > 4) { /* assume blank */
-                               dev_warn(doc->dev,
-                                        "error(s) in blank page "
-                                        "at offset %08x\n",
-                                        page * DOCG4_PAGE_SIZE);
-                               return 0;
-                       }
-               }
-       }
-
-       /*
-        * The hardware ecc unit produces oob_ecc ^ calc_ecc.  The kernel's bch
-        * algorithm is used to decode this.  However the hw operates on page
-        * data in a bit order that is the reverse of that of the bch alg,
-        * requiring that the bits be reversed on the result.  Thanks to Ivan
-        * Djelic for his analysis!
-        */
-       for (i = 0; i < 7; i++)
-               doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]);
-
-       numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL,
-                            doc->ecc_buf, NULL, errpos);
-
-       if (numerrs == -EBADMSG) {
-               dev_warn(doc->dev, "uncorrectable errors at offset %08x\n",
-                        page * DOCG4_PAGE_SIZE);
-               return -EBADMSG;
-       }
-
-       BUG_ON(numerrs < 0);    /* -EINVAL, or anything other than -EBADMSG */
-
-       /* undo last step in BCH alg (modulo mirroring not needed) */
-       for (i = 0; i < numerrs; i++)
-               errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7));
-
-       /* fix the errors */
-       for (i = 0; i < numerrs; i++) {
-
-               /* ignore if error within oob ecc bytes */
-               if (errpos[i] > DOCG4_USERDATA_LEN * 8)
-                       continue;
-
-               /* if error within oob area preceeding ecc bytes... */
-               if (errpos[i] > DOCG4_PAGE_SIZE * 8)
-                       change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8,
-                                  (unsigned long *)nand->oob_poi);
-
-               else    /* error in page data */
-                       change_bit(errpos[i], (unsigned long *)buf);
-       }
-
-       dev_notice(doc->dev, "%d error(s) corrected at offset %08x\n",
-                  numerrs, page * DOCG4_PAGE_SIZE);
-
-       return numerrs;
-}
-
-static uint8_t docg4_read_byte(struct mtd_info *mtd)
-{
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-
-       dev_dbg(doc->dev, "%s\n", __func__);
-
-       if (doc->last_command.command == NAND_CMD_STATUS) {
-               int status;
-
-               /*
-                * Previous nand command was status request, so nand
-                * infrastructure code expects to read the status here.  If an
-                * error occurred in a previous operation, report it.
-                */
-               doc->last_command.command = 0;
-
-               if (doc->status) {
-                       status = doc->status;
-                       doc->status = 0;
-               }
-
-               /* why is NAND_STATUS_WP inverse logic?? */
-               else
-                       status = NAND_STATUS_WP | NAND_STATUS_READY;
-
-               return status;
-       }
-
-       dev_warn(doc->dev, "unexpected call to read_byte()\n");
-
-       return 0;
-}
-
-static void write_addr(struct docg4_priv *doc, uint32_t docg4_addr)
-{
-       /* write the four address bytes packed in docg4_addr to the device */
-
-       void __iomem *docptr = doc->virtadr;
-       writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-       docg4_addr >>= 8;
-       writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-       docg4_addr >>= 8;
-       writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-       docg4_addr >>= 8;
-       writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-}
-
-static int read_progstatus(struct docg4_priv *doc)
-{
-       /*
-        * This apparently checks the status of programming.  Done after an
-        * erasure, and after page data is written.  On error, the status is
-        * saved, to be later retrieved by the nand infrastructure code.
-        */
-       void __iomem *docptr = doc->virtadr;
-
-       /* status is read from the I/O reg */
-       uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA);
-       uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA);
-       uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG);
-
-       dev_dbg(doc->dev, "docg4: %s: %02x %02x %02x\n",
-             __func__, status1, status2, status3);
-
-       if (status1 != DOCG4_PROGSTATUS_GOOD
-           || status2 != DOCG4_PROGSTATUS_GOOD_2
-           || status3 != DOCG4_PROGSTATUS_GOOD_2) {
-               doc->status = NAND_STATUS_FAIL;
-               dev_warn(doc->dev, "read_progstatus failed: "
-                        "%02x, %02x, %02x\n", status1, status2, status3);
-               return -EIO;
-       }
-       return 0;
-}
-
-static int pageprog(struct mtd_info *mtd)
-{
-       /*
-        * Final step in writing a page.  Writes the contents of its
-        * internal buffer out to the flash array, or some such.
-        */
-
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-       int retval = 0;
-
-       dev_dbg(doc->dev, "docg4: %s\n", __func__);
-
-       writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE);
-       writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND);
-       write_nop(docptr);
-       write_nop(docptr);
-
-       /* Just busy-wait; usleep_range() slows things down noticeably. */
-       poll_status(doc);
-
-       writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
-       writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
-       writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-
-       retval = read_progstatus(doc);
-       writew(0, docptr + DOC_DATAEND);
-       write_nop(docptr);
-       poll_status(doc);
-       write_nop(docptr);
-
-       return retval;
-}
-
-static void sequence_reset(struct mtd_info *mtd)
-{
-       /* common starting sequence for all operations */
-
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-
-       writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL);
-       writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
-       writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
-       write_nop(docptr);
-       write_nop(docptr);
-       poll_status(doc);
-       write_nop(docptr);
-}
-
-static void read_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
-{
-       /* first step in reading a page */
-
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-
-       dev_dbg(doc->dev,
-             "docg4: %s: g4 page %08x\n", __func__, docg4_addr);
-
-       sequence_reset(mtd);
-
-       writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
-       writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
-       write_nop(docptr);
-
-       write_addr(doc, docg4_addr);
-
-       write_nop(docptr);
-       writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
-       write_nop(docptr);
-       write_nop(docptr);
-
-       poll_status(doc);
-}
-
-static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
-{
-       /* first step in writing a page */
-
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-
-       dev_dbg(doc->dev,
-             "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
-       sequence_reset(mtd);
-
-       if (unlikely(reliable_mode)) {
-               writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
-               writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
-               writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
-               write_nop(docptr);
-       }
-
-       writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
-       writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
-       write_nop(docptr);
-       write_addr(doc, docg4_addr);
-       write_nop(docptr);
-       write_nop(docptr);
-       poll_status(doc);
-}
-
-static uint32_t mtd_to_docg4_address(int page, int column)
-{
-       /*
-        * Convert mtd address to format used by the device, 32 bit packed.
-        *
-        * Some notes on G4 addressing... The M-Sys documentation on this device
-        * claims that pages are 2K in length, and indeed, the format of the
-        * address used by the device reflects that.  But within each page are
-        * four 512 byte "sub-pages", each with its own oob data that is
-        * read/written immediately after the 512 bytes of page data.  This oob
-        * data contains the ecc bytes for the preceeding 512 bytes.
-        *
-        * Rather than tell the mtd nand infrastructure that page size is 2k,
-        * with four sub-pages each, we engage in a little subterfuge and tell
-        * the infrastructure code that pages are 512 bytes in size.  This is
-        * done because during the course of reverse-engineering the device, I
-        * never observed an instance where an entire 2K "page" was read or
-        * written as a unit.  Each "sub-page" is always addressed individually,
-        * its data read/written, and ecc handled before the next "sub-page" is
-        * addressed.
-        *
-        * This requires us to convert addresses passed by the mtd nand
-        * infrastructure code to those used by the device.
-        *
-        * The address that is written to the device consists of four bytes: the
-        * first two are the 2k page number, and the second is the index into
-        * the page.  The index is in terms of 16-bit half-words and includes
-        * the preceeding oob data, so e.g., the index into the second
-        * "sub-page" is 0x108, and the full device address of the start of mtd
-        * page 0x201 is 0x00800108.
-        */
-       int g4_page = page / 4;                       /* device's 2K page */
-       int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */
-       return (g4_page << 16) | g4_index;            /* pack */
-}
-
-static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
-                         int page_addr)
-{
-       /* handle standard nand commands */
-
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
-
-       dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n",
-             __func__, command, page_addr, column);
-
-       /*
-        * Save the command and its arguments.  This enables emulation of
-        * standard flash devices, and also some optimizations.
-        */
-       doc->last_command.command = command;
-       doc->last_command.column = column;
-       doc->last_command.page = page_addr;
-
-       switch (command) {
-
-       case NAND_CMD_RESET:
-               reset(mtd);
-               break;
-
-       case NAND_CMD_READ0:
-               read_page_prologue(mtd, g4_addr);
-               break;
-
-       case NAND_CMD_STATUS:
-               /* next call to read_byte() will expect a status */
-               break;
-
-       case NAND_CMD_SEQIN:
-               if (unlikely(reliable_mode)) {
-                       uint16_t g4_page = g4_addr >> 16;
-
-                       /* writes to odd-numbered 2k pages are invalid */
-                       if (g4_page & 0x01)
-                               dev_warn(doc->dev,
-                                        "invalid reliable mode address\n");
-               }
-
-               write_page_prologue(mtd, g4_addr);
-
-               /* hack for deferred write of oob bytes */
-               if (doc->oob_page == page_addr)
-                       memcpy(nand->oob_poi, doc->oob_buf, 16);
-               break;
-
-       case NAND_CMD_PAGEPROG:
-               pageprog(mtd);
-               break;
-
-       /* we don't expect these, based on review of nand_base.c */
-       case NAND_CMD_READOOB:
-       case NAND_CMD_READID:
-       case NAND_CMD_ERASE1:
-       case NAND_CMD_ERASE2:
-               dev_warn(doc->dev, "docg4_command: "
-                        "unexpected nand command 0x%x\n", command);
-               break;
-
-       }
-}
-
-static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
-                    uint8_t *buf, int page, bool use_ecc)
-{
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-       uint16_t status, edc_err, *buf16;
-       int bits_corrected = 0;
-
-       dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
-
-       nand_read_page_op(nand, page, 0, NULL, 0);
-
-       writew(DOC_ECCCONF0_READ_MODE |
-              DOC_ECCCONF0_ECC_ENABLE |
-              DOC_ECCCONF0_UNKNOWN |
-              DOCG4_BCH_SIZE,
-              docptr + DOC_ECCCONF0);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-
-       /* the 1st byte from the I/O reg is a status; the rest is page data */
-       status = readw(docptr + DOC_IOSPACE_DATA);
-       if (status & DOCG4_READ_ERROR) {
-               dev_err(doc->dev,
-                       "docg4_read_page: bad status: 0x%02x\n", status);
-               writew(0, docptr + DOC_DATAEND);
-               return -EIO;
-       }
-
-       dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
-
-       docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */
-
-       /* this device always reads oob after page data */
-       /* first 14 oob bytes read from I/O reg */
-       docg4_read_buf(mtd, nand->oob_poi, 14);
-
-       /* last 2 read from another reg */
-       buf16 = (uint16_t *)(nand->oob_poi + 14);
-       *buf16 = readw(docptr + DOCG4_MYSTERY_REG);
-
-       write_nop(docptr);
-
-       if (likely(use_ecc == true)) {
-
-               /* read the register that tells us if bitflip(s) detected  */
-               edc_err = readw(docptr + DOC_ECCCONF1);
-               edc_err = readw(docptr + DOC_ECCCONF1);
-               dev_dbg(doc->dev, "%s: edc_err = 0x%02x\n", __func__, edc_err);
-
-               /* If bitflips are reported, attempt to correct with ecc */
-               if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
-                       bits_corrected = correct_data(mtd, buf, page);
-                       if (bits_corrected == -EBADMSG)
-                               mtd->ecc_stats.failed++;
-                       else
-                               mtd->ecc_stats.corrected += bits_corrected;
-               }
-       }
-
-       writew(0, docptr + DOC_DATAEND);
-       if (bits_corrected == -EBADMSG)   /* uncorrectable errors */
-               return 0;
-       return bits_corrected;
-}
-
-
-static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
-                              uint8_t *buf, int oob_required, int page)
-{
-       return read_page(mtd, nand, buf, page, false);
-}
-
-static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
-                          uint8_t *buf, int oob_required, int page)
-{
-       return read_page(mtd, nand, buf, page, true);
-}
-
-static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
-                         int page)
-{
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-       uint16_t status;
-
-       dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
-
-       nand_read_page_op(nand, page, nand->ecc.size, NULL, 0);
-
-       writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-
-       /* the 1st byte from the I/O reg is a status; the rest is oob data */
-       status = readw(docptr + DOC_IOSPACE_DATA);
-       if (status & DOCG4_READ_ERROR) {
-               dev_warn(doc->dev,
-                        "docg4_read_oob failed: status = 0x%02x\n", status);
-               return -EIO;
-       }
-
-       dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
-
-       docg4_read_buf(mtd, nand->oob_poi, 16);
-
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-       writew(0, docptr + DOC_DATAEND);
-       write_nop(docptr);
-
-       return 0;
-}
-
-static int docg4_erase_block(struct mtd_info *mtd, int page)
-{
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-       uint16_t g4_page;
-       int status;
-
-       dev_dbg(doc->dev, "%s: page %04x\n", __func__, page);
-
-       sequence_reset(mtd);
-
-       writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE);
-       writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND);
-       write_nop(docptr);
-
-       /* only 2 bytes of address are written to specify erase block */
-       g4_page = (uint16_t)(page / 4);  /* to g4's 2k page addressing */
-       writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
-       g4_page >>= 8;
-       writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
-       write_nop(docptr);
-
-       /* start the erasure */
-       writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND);
-       write_nop(docptr);
-       write_nop(docptr);
-
-       usleep_range(500, 1000); /* erasure is long; take a snooze */
-       poll_status(doc);
-       writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
-       writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
-       writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-       write_nop(docptr);
-
-       read_progstatus(doc);
-
-       writew(0, docptr + DOC_DATAEND);
-       write_nop(docptr);
-       poll_status(doc);
-       write_nop(docptr);
-
-       status = nand->waitfunc(mtd, nand);
-       if (status < 0)
-               return status;
-
-       return status & NAND_STATUS_FAIL ? -EIO : 0;
-}
-
-static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
-                     const uint8_t *buf, int page, bool use_ecc)
-{
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-       uint8_t ecc_buf[8];
-
-       dev_dbg(doc->dev, "%s...\n", __func__);
-
-       nand_prog_page_begin_op(nand, page, 0, NULL, 0);
-
-       writew(DOC_ECCCONF0_ECC_ENABLE |
-              DOC_ECCCONF0_UNKNOWN |
-              DOCG4_BCH_SIZE,
-              docptr + DOC_ECCCONF0);
-       write_nop(docptr);
-
-       /* write the page data */
-       docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE);
-
-       /* oob bytes 0 through 5 are written to I/O reg */
-       docg4_write_buf16(mtd, nand->oob_poi, 6);
-
-       /* oob byte 6 written to a separate reg */
-       writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7);
-
-       write_nop(docptr);
-       write_nop(docptr);
-
-       /* write hw-generated ecc bytes to oob */
-       if (likely(use_ecc == true)) {
-               /* oob byte 7 is hamming code */
-               uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY);
-               hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */
-               writew(hamming, docptr + DOCG4_OOB_6_7);
-               write_nop(docptr);
-
-               /* read the 7 bch bytes from ecc regs */
-               read_hw_ecc(docptr, ecc_buf);
-               ecc_buf[7] = 0;         /* clear the "page written" flag */
-       }
-
-       /* write user-supplied bytes to oob */
-       else {
-               writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7);
-               write_nop(docptr);
-               memcpy(ecc_buf, &nand->oob_poi[8], 8);
-       }
-
-       docg4_write_buf16(mtd, ecc_buf, 8);
-       write_nop(docptr);
-       write_nop(docptr);
-       writew(0, docptr + DOC_DATAEND);
-       write_nop(docptr);
-
-       return nand_prog_page_end_op(nand);
-}
-
-static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
-                               const uint8_t *buf, int oob_required, int page)
-{
-       return write_page(mtd, nand, buf, page, false);
-}
-
-static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
-                            const uint8_t *buf, int oob_required, int page)
-{
-       return write_page(mtd, nand, buf, page, true);
-}
-
-static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
-                          int page)
-{
-       /*
-        * Writing oob-only is not really supported, because MLC nand must write
-        * oob bytes at the same time as page data.  Nonetheless, we save the
-        * oob buffer contents here, and then write it along with the page data
-        * if the same page is subsequently written.  This allows user space
-        * utilities that write the oob data prior to the page data to work
-        * (e.g., nandwrite).  The disdvantage is that, if the intention was to
-        * write oob only, the operation is quietly ignored.  Also, oob can get
-        * corrupted if two concurrent processes are running nandwrite.
-        */
-
-       /* note that bytes 7..14 are hw generated hamming/ecc and overwritten */
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       doc->oob_page = page;
-       memcpy(doc->oob_buf, nand->oob_poi, 16);
-       return 0;
-}
-
-static int __init read_factory_bbt(struct mtd_info *mtd)
-{
-       /*
-        * The device contains a read-only factory bad block table.  Read it and
-        * update the memory-based bbt accordingly.
-        */
-
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
-       uint8_t *buf;
-       int i, block;
-       __u32 eccfailed_stats = mtd->ecc_stats.failed;
-
-       buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
-       if (buf == NULL)
-               return -ENOMEM;
-
-       read_page_prologue(mtd, g4_addr);
-       docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
-
-       /*
-        * If no memory-based bbt was created, exit.  This will happen if module
-        * parameter ignore_badblocks is set.  Then why even call this function?
-        * For an unknown reason, block erase always fails if it's the first
-        * operation after device power-up.  The above read ensures it never is.
-        * Ugly, I know.
-        */
-       if (nand->bbt == NULL)  /* no memory-based bbt */
-               goto exit;
-
-       if (mtd->ecc_stats.failed > eccfailed_stats) {
-               /*
-                * Whoops, an ecc failure ocurred reading the factory bbt.
-                * It is stored redundantly, so we get another chance.
-                */
-               eccfailed_stats = mtd->ecc_stats.failed;
-               docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
-               if (mtd->ecc_stats.failed > eccfailed_stats) {
-                       dev_warn(doc->dev,
-                                "The factory bbt could not be read!\n");
-                       goto exit;
-               }
-       }
-
-       /*
-        * Parse factory bbt and update memory-based bbt.  Factory bbt format is
-        * simple: one bit per block, block numbers increase left to right (msb
-        * to lsb).  Bit clear means bad block.
-        */
-       for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) {
-               int bitnum;
-               unsigned long bits = ~buf[i];
-               for_each_set_bit(bitnum, &bits, 8) {
-                       int badblock = block + 7 - bitnum;
-                       nand->bbt[badblock / 4] |=
-                               0x03 << ((badblock % 4) * 2);
-                       mtd->ecc_stats.badblocks++;
-                       dev_notice(doc->dev, "factory-marked bad block: %d\n",
-                                  badblock);
-               }
-       }
- exit:
-       kfree(buf);
-       return 0;
-}
-
-static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
-       /*
-        * Mark a block as bad.  Bad blocks are marked in the oob area of the
-        * first page of the block.  The default scan_bbt() in the nand
-        * infrastructure code works fine for building the memory-based bbt
-        * during initialization, as does the nand infrastructure function that
-        * checks if a block is bad by reading the bbt.  This function replaces
-        * the nand default because writes to oob-only are not supported.
-        */
-
-       int ret, i;
-       uint8_t *buf;
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       struct nand_bbt_descr *bbtd = nand->badblock_pattern;
-       int page = (int)(ofs >> nand->page_shift);
-       uint32_t g4_addr = mtd_to_docg4_address(page, 0);
-
-       dev_dbg(doc->dev, "%s: %08llx\n", __func__, ofs);
-
-       if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1)))
-               dev_warn(doc->dev, "%s: ofs %llx not start of block!\n",
-                        __func__, ofs);
-
-       /* allocate blank buffer for page data */
-       buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
-       if (buf == NULL)
-               return -ENOMEM;
-
-       /* write bit-wise negation of pattern to oob buffer */
-       memset(nand->oob_poi, 0xff, mtd->oobsize);
-       for (i = 0; i < bbtd->len; i++)
-               nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i];
-
-       /* write first page of block */
-       write_page_prologue(mtd, g4_addr);
-       docg4_write_page(mtd, nand, buf, 1, page);
-       ret = pageprog(mtd);
-
-       kfree(buf);
-
-       return ret;
-}
-
-static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
-{
-       /* only called when module_param ignore_badblocks is set */
-       return 0;
-}
-
-static int docg4_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       /*
-        * Put the device into "deep power-down" mode.  Note that CE# must be
-        * deasserted for this to take effect.  The xscale, e.g., can be
-        * configured to float this signal when the processor enters power-down,
-        * and a suitable pull-up ensures its deassertion.
-        */
-
-       int i;
-       uint8_t pwr_down;
-       struct docg4_priv *doc = platform_get_drvdata(pdev);
-       void __iomem *docptr = doc->virtadr;
-
-       dev_dbg(doc->dev, "%s...\n", __func__);
-
-       /* poll the register that tells us we're ready to go to sleep */
-       for (i = 0; i < 10; i++) {
-               pwr_down = readb(docptr + DOC_POWERMODE);
-               if (pwr_down & DOC_POWERDOWN_READY)
-                       break;
-               usleep_range(1000, 4000);
-       }
-
-       if (pwr_down & DOC_POWERDOWN_READY) {
-               dev_err(doc->dev, "suspend failed; "
-                       "timeout polling DOC_POWERDOWN_READY\n");
-               return -EIO;
-       }
-
-       writew(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN,
-              docptr + DOC_ASICMODE);
-       writew(~(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN),
-              docptr + DOC_ASICMODECONFIRM);
-
-       write_nop(docptr);
-
-       return 0;
-}
-
-static int docg4_resume(struct platform_device *pdev)
-{
-
-       /*
-        * Exit power-down.  Twelve consecutive reads of the address below
-        * accomplishes this, assuming CE# has been asserted.
-        */
-
-       struct docg4_priv *doc = platform_get_drvdata(pdev);
-       void __iomem *docptr = doc->virtadr;
-       int i;
-
-       dev_dbg(doc->dev, "%s...\n", __func__);
-
-       for (i = 0; i < 12; i++)
-               readb(docptr + 0x1fff);
-
-       return 0;
-}
-
-static void init_mtd_structs(struct mtd_info *mtd)
-{
-       /* initialize mtd and nand data structures */
-
-       /*
-        * Note that some of the following initializations are not usually
-        * 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() 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);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-
-       mtd->size = DOCG4_CHIP_SIZE;
-       mtd->name = "Msys_Diskonchip_G4";
-       mtd->writesize = DOCG4_PAGE_SIZE;
-       mtd->erasesize = DOCG4_BLOCK_SIZE;
-       mtd->oobsize = DOCG4_OOB_SIZE;
-       mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
-       nand->chipsize = DOCG4_CHIP_SIZE;
-       nand->chip_shift = DOCG4_CHIP_SHIFT;
-       nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
-       nand->chip_delay = 20;
-       nand->page_shift = DOCG4_PAGE_SHIFT;
-       nand->pagemask = 0x3ffff;
-       nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
-       nand->badblockbits = 8;
-       nand->ecc.mode = NAND_ECC_HW_SYNDROME;
-       nand->ecc.size = DOCG4_PAGE_SIZE;
-       nand->ecc.prepad = 8;
-       nand->ecc.bytes = 8;
-       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->dummy_controller;
-       nand_controller_init(nand->controller);
-
-       /* methods */
-       nand->cmdfunc = docg4_command;
-       nand->waitfunc = docg4_wait;
-       nand->select_chip = docg4_select_chip;
-       nand->read_byte = docg4_read_byte;
-       nand->block_markbad = docg4_block_markbad;
-       nand->read_buf = docg4_read_buf;
-       nand->write_buf = docg4_write_buf16;
-       nand->erase = docg4_erase_block;
-       nand->set_features = nand_get_set_features_notsupp;
-       nand->get_features = nand_get_set_features_notsupp;
-       nand->ecc.read_page = docg4_read_page;
-       nand->ecc.write_page = docg4_write_page;
-       nand->ecc.read_page_raw = docg4_read_page_raw;
-       nand->ecc.write_page_raw = docg4_write_page_raw;
-       nand->ecc.read_oob = docg4_read_oob;
-       nand->ecc.write_oob = docg4_write_oob;
-
-       /*
-        * The way the nand infrastructure code is written, a memory-based bbt
-        * is not created if NAND_SKIP_BBTSCAN is set.  With no memory bbt,
-        * nand->block_bad() is used.  So when ignoring bad blocks, we skip the
-        * scan and define a dummy block_bad() which always returns 0.
-        */
-       if (ignore_badblocks) {
-               nand->options |= NAND_SKIP_BBTSCAN;
-               nand->block_bad = docg4_block_neverbad;
-       }
-
-}
-
-static int read_id_reg(struct mtd_info *mtd)
-{
-       struct nand_chip *nand = mtd_to_nand(mtd);
-       struct docg4_priv *doc = nand_get_controller_data(nand);
-       void __iomem *docptr = doc->virtadr;
-       uint16_t id1, id2;
-
-       /* check for presence of g4 chip by reading id registers */
-       id1 = readw(docptr + DOC_CHIPID);
-       id1 = readw(docptr + DOCG4_MYSTERY_REG);
-       id2 = readw(docptr + DOC_CHIPID_INV);
-       id2 = readw(docptr + DOCG4_MYSTERY_REG);
-
-       if (id1 == DOCG4_IDREG1_VALUE && id2 == DOCG4_IDREG2_VALUE) {
-               dev_info(doc->dev,
-                        "NAND device: 128MiB Diskonchip G4 detected\n");
-               return 0;
-       }
-
-       return -ENODEV;
-}
-
-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;
-       struct nand_chip *nand;
-       void __iomem *virtadr;
-       struct docg4_priv *doc;
-       int len, retval;
-       struct resource *r;
-       struct device *dev = &pdev->dev;
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               dev_err(dev, "no io memory resource defined!\n");
-               return -ENODEV;
-       }
-
-       virtadr = ioremap(r->start, resource_size(r));
-       if (!virtadr) {
-               dev_err(dev, "Diskonchip ioremap failed: %pR\n", r);
-               return -EIO;
-       }
-
-       len = sizeof(struct nand_chip) + sizeof(struct docg4_priv);
-       nand = kzalloc(len, GFP_KERNEL);
-       if (nand == NULL) {
-               retval = -ENOMEM;
-               goto unmap;
-       }
-
-       mtd = nand_to_mtd(nand);
-       doc = (struct docg4_priv *) (nand + 1);
-       nand_set_controller_data(nand, doc);
-       mtd->dev.parent = &pdev->dev;
-       doc->virtadr = virtadr;
-       doc->dev = dev;
-       platform_set_drvdata(pdev, doc);
-
-       /*
-        * 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 free_nand;
-
-       retval = read_factory_bbt(mtd);
-       if (retval)
-               goto cleanup_nand;
-
-       retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
-       if (retval)
-               goto cleanup_nand;
-
-       doc->mtd = mtd;
-
-       return 0;
-
-cleanup_nand:
-       nand_cleanup(nand);
-free_nand:
-       kfree(nand);
-unmap:
-       iounmap(virtadr);
-
-       return retval;
-}
-
-static int __exit cleanup_docg4(struct platform_device *pdev)
-{
-       struct docg4_priv *doc = platform_get_drvdata(pdev);
-       nand_release(doc->mtd);
-       kfree(mtd_to_nand(doc->mtd));
-       iounmap(doc->virtadr);
-       return 0;
-}
-
-static struct platform_driver docg4_driver = {
-       .driver         = {
-               .name   = "docg4",
-       },
-       .suspend        = docg4_suspend,
-       .resume         = docg4_resume,
-       .remove         = __exit_p(cleanup_docg4),
-};
-
-module_platform_driver_probe(docg4_driver, probe_docg4);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mike Dunn");
-MODULE_DESCRIPTION("M-Systems DiskOnChip G4 device driver");
index 55f449b711fd9fc4ad8ff2fc68f35524f37a481a..d6ed697fcfe6e6e4ddd8b4ddc97fca7000918502 100644 (file)
@@ -317,10 +317,10 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
 }
 
 /* cmdfunc send commands to the FCM */
-static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+static void fsl_elbc_cmdfunc(struct nand_chip *chip, unsigned int command,
                              int column, int page_addr)
 {
-       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_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
@@ -533,7 +533,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
        }
 }
 
-static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
+static void fsl_elbc_select_chip(struct nand_chip *chip, int cs)
 {
        /* The hardware does not seem to support multiple
         * chips per bank.
@@ -543,9 +543,9 @@ static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
 /*
  * Write buf to the FCM Controller Data Buffer
  */
-static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void fsl_elbc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
 {
-       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_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
        unsigned int bufsize = mtd->writesize + mtd->oobsize;
@@ -581,9 +581,8 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
  * read a byte from either the FCM hardware buffer if it has any data left
  * otherwise issue a command to read a single byte.
  */
-static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
+static u8 fsl_elbc_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
        struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
 
@@ -598,9 +597,8 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
 /*
  * Read from the FCM Controller Data Buffer
  */
-static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void fsl_elbc_read_buf(struct nand_chip *chip, u8 *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
        struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
        int avail;
@@ -623,7 +621,7 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 /* This function is called after Program and Erase Operations to
  * check for success or failure.
  */
-static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int fsl_elbc_wait(struct nand_chip *chip)
 {
        struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
        struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
@@ -660,8 +658,8 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
                chip->chipsize);
        dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
                chip->pagemask);
-       dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
-               chip->chip_delay);
+       dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n",
+               chip->legacy.chip_delay);
        dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
                chip->badblockpos);
        dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
@@ -710,18 +708,19 @@ 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)
+static int fsl_elbc_read_page(struct nand_chip *chip, uint8_t *buf,
+                             int oob_required, int page)
 {
+       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_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
 
        nand_read_page_op(chip, page, 0, buf, mtd->writesize);
        if (oob_required)
-               fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+               fsl_elbc_read_buf(chip, chip->oob_poi, mtd->oobsize);
 
-       if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
+       if (fsl_elbc_wait(chip) & NAND_STATUS_FAIL)
                mtd->ecc_stats.failed++;
 
        return elbc_fcm_ctrl->max_bitflips;
@@ -730,11 +729,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 /* ECC will be calculated automatically, and errors will be detected in
  * waitfunc.
  */
-static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf, int oob_required, int page)
+static int fsl_elbc_write_page(struct nand_chip *chip, const uint8_t *buf,
+                              int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-       fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        return nand_prog_page_end_op(chip);
 }
@@ -742,13 +743,15 @@ static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 /* ECC will be calculated automatically, and errors will be detected in
  * waitfunc.
  */
-static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint32_t offset, uint32_t data_len,
-                               const uint8_t *buf, int oob_required, int page)
+static int fsl_elbc_write_subpage(struct nand_chip *chip, uint32_t offset,
+                                 uint32_t data_len, const uint8_t *buf,
+                                 int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-       fsl_elbc_write_buf(mtd, buf, mtd->writesize);
-       fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       fsl_elbc_write_buf(chip, buf, mtd->writesize);
+       fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize);
        return nand_prog_page_end_op(chip);
 }
 
@@ -773,14 +776,14 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
 
        /* fill in nand_chip structure */
        /* set up function call table */
-       chip->read_byte = fsl_elbc_read_byte;
-       chip->write_buf = fsl_elbc_write_buf;
-       chip->read_buf = fsl_elbc_read_buf;
+       chip->legacy.read_byte = fsl_elbc_read_byte;
+       chip->legacy.write_buf = fsl_elbc_write_buf;
+       chip->legacy.read_buf = fsl_elbc_read_buf;
        chip->select_chip = fsl_elbc_select_chip;
-       chip->cmdfunc = fsl_elbc_cmdfunc;
-       chip->waitfunc = fsl_elbc_wait;
-       chip->set_features = nand_get_set_features_notsupp;
-       chip->get_features = nand_get_set_features_notsupp;
+       chip->legacy.cmdfunc = fsl_elbc_cmdfunc;
+       chip->legacy.waitfunc = fsl_elbc_wait;
+       chip->legacy.set_features = nand_get_set_features_notsupp;
+       chip->legacy.get_features = nand_get_set_features_notsupp;
 
        chip->bbt_td = &bbt_main_descr;
        chip->bbt_md = &bbt_mirror_descr;
@@ -915,7 +918,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
                goto err;
 
        priv->chip.controller->ops = &fsl_elbc_controller_ops;
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(&priv->chip, 1);
        if (ret)
                goto err;
 
@@ -942,9 +945,8 @@ static int fsl_elbc_nand_remove(struct platform_device *pdev)
 {
        struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
        struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
-       struct mtd_info *mtd = nand_to_mtd(&priv->chip);
 
-       nand_release(mtd);
+       nand_release(&priv->chip);
        fsl_elbc_chip_remove(priv);
 
        mutex_lock(&fsl_elbc_nand_mutex);
index 24f59d0066afdd77d586f29b944f566e0038d98c..6f4afc44381a3e05affc9bfbe14d2069e876a398 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/fsl_ifc.h>
+#include <linux/iopoll.h>
 
 #define ERR_BYTE               0xFF /* Value returned for read
                                        bytes when read failed  */
@@ -300,9 +301,9 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
 }
 
 /* cmdfunc send commands to the IFC NAND Machine */
-static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
-                            int column, int page_addr) {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+static void fsl_ifc_cmdfunc(struct nand_chip *chip, unsigned int command,
+                           int column, int page_addr) {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
        struct fsl_ifc_ctrl *ctrl = priv->ctrl;
        struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
@@ -508,7 +509,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
        }
 }
 
-static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
+static void fsl_ifc_select_chip(struct nand_chip *chip, int cs)
 {
        /* The hardware does not seem to support multiple
         * chips per bank.
@@ -518,9 +519,9 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
 /*
  * Write buf to the IFC NAND Controller Data Buffer
  */
-static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void fsl_ifc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
 {
-       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);
        unsigned int bufsize = mtd->writesize + mtd->oobsize;
 
@@ -544,9 +545,8 @@ static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
  * Read a byte from either the IFC hardware buffer
  * read function for 8-bit buswidth
  */
-static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
+static uint8_t fsl_ifc_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
        unsigned int offset;
 
@@ -567,9 +567,8 @@ static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
  * Read two bytes from the IFC hardware buffer
  * read function for 16-bit buswith
  */
-static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
+static uint8_t fsl_ifc_read_byte16(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
        uint16_t data;
 
@@ -590,9 +589,8 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
 /*
  * Read from the IFC Controller Data Buffer
  */
-static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void fsl_ifc_read_buf(struct nand_chip *chip, u8 *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
        int avail;
 
@@ -616,8 +614,9 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
  * This function is called after Program and Erase Operations to
  * check for success or failure.
  */
-static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int fsl_ifc_wait(struct nand_chip *chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
        struct fsl_ifc_ctrl *ctrl = priv->ctrl;
        struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
@@ -678,20 +677,21 @@ static int check_erased_page(struct nand_chip *chip, u8 *buf)
        return bitflips;
 }
 
-static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                            uint8_t *buf, int oob_required, int page)
+static int fsl_ifc_read_page(struct nand_chip *chip, uint8_t *buf,
+                            int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
        struct fsl_ifc_ctrl *ctrl = priv->ctrl;
        struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
 
        nand_read_page_op(chip, page, 0, buf, mtd->writesize);
        if (oob_required)
-               fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+               fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
 
        if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
                if (!oob_required)
-                       fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+                       fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
 
                return check_erased_page(chip, buf);
        }
@@ -705,11 +705,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 /* ECC will be calculated automatically, and errors will be detected in
  * waitfunc.
  */
-static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                              const uint8_t *buf, int oob_required, int page)
+static int fsl_ifc_write_page(struct nand_chip *chip, const uint8_t *buf,
+                             int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-       fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       fsl_ifc_write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        return nand_prog_page_end_op(chip);
 }
@@ -725,8 +727,8 @@ static int fsl_ifc_attach_chip(struct nand_chip *chip)
                                                        chip->chipsize);
        dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
                                                        chip->pagemask);
-       dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
-                                                       chip->chip_delay);
+       dev_dbg(priv->dev, "%s: nand->legacy.chip_delay = %d\n", __func__,
+               chip->legacy.chip_delay);
        dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
                                                        chip->badblockpos);
        dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
@@ -761,7 +763,7 @@ 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)
+static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
 {
        struct fsl_ifc_ctrl *ctrl = priv->ctrl;
        struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
@@ -769,6 +771,27 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
        uint32_t csor = 0, csor_8k = 0, csor_ext = 0;
        uint32_t cs = priv->bank;
 
+       if (ctrl->version < FSL_IFC_VERSION_1_1_0)
+               return 0;
+
+       if (ctrl->version > FSL_IFC_VERSION_1_1_0) {
+               u32 ncfgr, status;
+               int ret;
+
+               /* Trigger auto initialization */
+               ncfgr = ifc_in32(&ifc_runtime->ifc_nand.ncfgr);
+               ifc_out32(ncfgr | IFC_NAND_NCFGR_SRAM_INIT_EN, &ifc_runtime->ifc_nand.ncfgr);
+
+               /* Wait until done */
+               ret = readx_poll_timeout(ifc_in32, &ifc_runtime->ifc_nand.ncfgr,
+                                        status, !(status & IFC_NAND_NCFGR_SRAM_INIT_EN),
+                                        10, IFC_TIMEOUT_MSECS * 1000);
+               if (ret)
+                       dev_err(priv->dev, "Failed to initialize SRAM!\n");
+
+               return ret;
+       }
+
        /* Save CSOR and CSOR_ext */
        csor = ifc_in32(&ifc_global->csor_cs[cs].csor);
        csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext);
@@ -805,12 +828,16 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
        wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
                           msecs_to_jiffies(IFC_TIMEOUT_MSECS));
 
-       if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+       if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) {
                pr_err("fsl-ifc: Failed to Initialise SRAM\n");
+               return -ETIMEDOUT;
+       }
 
        /* Restore CSOR and CSOR_ext */
        ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
        ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext);
+
+       return 0;
 }
 
 static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
@@ -821,6 +848,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
        struct nand_chip *chip = &priv->chip;
        struct mtd_info *mtd = nand_to_mtd(&priv->chip);
        u32 csor;
+       int ret;
 
        /* Fill in fsl_ifc_mtd structure */
        mtd->dev.parent = priv->dev;
@@ -830,17 +858,17 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
        /* set up function call table */
        if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr))
                & CSPR_PORT_SIZE_16)
-               chip->read_byte = fsl_ifc_read_byte16;
+               chip->legacy.read_byte = fsl_ifc_read_byte16;
        else
-               chip->read_byte = fsl_ifc_read_byte;
+               chip->legacy.read_byte = fsl_ifc_read_byte;
 
-       chip->write_buf = fsl_ifc_write_buf;
-       chip->read_buf = fsl_ifc_read_buf;
+       chip->legacy.write_buf = fsl_ifc_write_buf;
+       chip->legacy.read_buf = fsl_ifc_read_buf;
        chip->select_chip = fsl_ifc_select_chip;
-       chip->cmdfunc = fsl_ifc_cmdfunc;
-       chip->waitfunc = fsl_ifc_wait;
-       chip->set_features = nand_get_set_features_notsupp;
-       chip->get_features = nand_get_set_features_notsupp;
+       chip->legacy.cmdfunc = fsl_ifc_cmdfunc;
+       chip->legacy.waitfunc = fsl_ifc_wait;
+       chip->legacy.set_features = nand_get_set_features_notsupp;
+       chip->legacy.get_features = nand_get_set_features_notsupp;
 
        chip->bbt_td = &bbt_main_descr;
        chip->bbt_md = &bbt_mirror_descr;
@@ -853,10 +881,10 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
        if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)
                & CSPR_PORT_SIZE_16) {
-               chip->read_byte = fsl_ifc_read_byte16;
+               chip->legacy.read_byte = fsl_ifc_read_byte16;
                chip->options |= NAND_BUSWIDTH_16;
        } else {
-               chip->read_byte = fsl_ifc_read_byte;
+               chip->legacy.read_byte = fsl_ifc_read_byte;
        }
 
        chip->controller = &ifc_nand_ctrl->controller;
@@ -914,8 +942,9 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
                chip->ecc.algo = NAND_ECC_HAMMING;
        }
 
-       if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
-               fsl_ifc_sram_init(priv);
+       ret = fsl_ifc_sram_init(priv);
+       if (ret)
+               return ret;
 
        /*
         * As IFC version 2.0.0 has 16KB of internal SRAM as compared to older
@@ -1051,7 +1080,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
                goto err;
 
        priv->chip.controller->ops = &fsl_ifc_controller_ops;
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(&priv->chip, 1);
        if (ret)
                goto err;
 
@@ -1077,9 +1106,8 @@ err:
 static int fsl_ifc_nand_remove(struct platform_device *dev)
 {
        struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
-       struct mtd_info *mtd = nand_to_mtd(&priv->chip);
 
-       nand_release(mtd);
+       nand_release(&priv->chip);
        fsl_ifc_chip_remove(priv);
 
        mutex_lock(&fsl_ifc_nand_mutex);
index a88e2cf66e0f69a0d5d94ea4d1340701c82884ec..673c5a0c9345691160bb76a2415f2a8791d44ec9 100644 (file)
@@ -52,9 +52,9 @@ static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
                            chip);
 }
 
-static int fun_chip_ready(struct mtd_info *mtd)
+static int fun_chip_ready(struct nand_chip *chip)
 {
-       struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+       struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
 
        if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
                return 1;
@@ -69,7 +69,7 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
                struct mtd_info *mtd = nand_to_mtd(&fun->chip);
                int cnt = 1000000;
 
-               while (--cnt && !fun_chip_ready(mtd))
+               while (--cnt && !fun_chip_ready(&fun->chip))
                        cpu_relax();
                if (!cnt)
                        dev_err(fun->dev, "tired waiting for RNB\n");
@@ -78,10 +78,9 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
        }
 }
 
-static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void fun_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+       struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
        u32 mar;
 
        if (!(ctrl & fun->last_ctrl)) {
@@ -102,51 +101,50 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 
        mar = (cmd << (32 - fun->upm.width)) |
                fun->mchip_offsets[fun->mchip_number];
-       fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar);
+       fsl_upm_run_pattern(&fun->upm, chip->legacy.IO_ADDR_R, mar);
 
        if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN)
                fun_wait_rnb(fun);
 }
 
-static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
+static void fun_select_chip(struct nand_chip *chip, int mchip_nr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+       struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
 
        if (mchip_nr == -1) {
-               chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
        } else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
                fun->mchip_number = mchip_nr;
-               chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
-               chip->IO_ADDR_W = chip->IO_ADDR_R;
+               chip->legacy.IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
+               chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
        } else {
                BUG();
        }
 }
 
-static uint8_t fun_read_byte(struct mtd_info *mtd)
+static uint8_t fun_read_byte(struct nand_chip *chip)
 {
-       struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+       struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
 
-       return in_8(fun->chip.IO_ADDR_R);
+       return in_8(fun->chip.legacy.IO_ADDR_R);
 }
 
-static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void fun_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+       struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
        int i;
 
        for (i = 0; i < len; i++)
-               buf[i] = in_8(fun->chip.IO_ADDR_R);
+               buf[i] = in_8(fun->chip.legacy.IO_ADDR_R);
 }
 
-static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void fun_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
 {
-       struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+       struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
        int i;
 
        for (i = 0; i < len; i++) {
-               out_8(fun->chip.IO_ADDR_W, buf[i]);
+               out_8(fun->chip.legacy.IO_ADDR_W, buf[i]);
                if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE)
                        fun_wait_rnb(fun);
        }
@@ -162,20 +160,20 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
        int ret;
        struct device_node *flash_np;
 
-       fun->chip.IO_ADDR_R = fun->io_base;
-       fun->chip.IO_ADDR_W = fun->io_base;
-       fun->chip.cmd_ctrl = fun_cmd_ctrl;
-       fun->chip.chip_delay = fun->chip_delay;
-       fun->chip.read_byte = fun_read_byte;
-       fun->chip.read_buf = fun_read_buf;
-       fun->chip.write_buf = fun_write_buf;
+       fun->chip.legacy.IO_ADDR_R = fun->io_base;
+       fun->chip.legacy.IO_ADDR_W = fun->io_base;
+       fun->chip.legacy.cmd_ctrl = fun_cmd_ctrl;
+       fun->chip.legacy.chip_delay = fun->chip_delay;
+       fun->chip.legacy.read_byte = fun_read_byte;
+       fun->chip.legacy.read_buf = fun_read_buf;
+       fun->chip.legacy.write_buf = fun_write_buf;
        fun->chip.ecc.mode = NAND_ECC_SOFT;
        fun->chip.ecc.algo = NAND_ECC_HAMMING;
        if (fun->mchip_count > 1)
                fun->chip.select_chip = fun_select_chip;
 
        if (fun->rnb_gpio[0] >= 0)
-               fun->chip.dev_ready = fun_chip_ready;
+               fun->chip.legacy.dev_ready = fun_chip_ready;
 
        mtd->dev.parent = fun->dev;
 
@@ -184,14 +182,14 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
                return -ENODEV;
 
        nand_set_flash_node(&fun->chip, flash_np);
-       mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
-                             flash_np->name);
+       mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%pOFn", (u64)io_res->start,
+                             flash_np);
        if (!mtd->name) {
                ret = -ENOMEM;
                goto err;
        }
 
-       ret = nand_scan(mtd, fun->mchip_count);
+       ret = nand_scan(&fun->chip, fun->mchip_count);
        if (ret)
                goto err;
 
@@ -326,7 +324,7 @@ static int fun_remove(struct platform_device *ofdev)
        struct mtd_info *mtd = nand_to_mtd(&fun->chip);
        int i;
 
-       nand_release(mtd);
+       nand_release(&fun->chip);
        kfree(mtd->name);
 
        for (i = 0; i < fun->mchip_count; i++) {
index f418236fa020adfdbd502efbc494c8ef66f90154..70ac8d875218e5010a30ad020f944586eee8241c 100644 (file)
@@ -340,10 +340,9 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
        return 0;
 }
 
-static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
+static int fsmc_setup_data_interface(struct nand_chip *nand, int csline,
                                     const struct nand_data_interface *conf)
 {
-       struct nand_chip *nand = mtd_to_nand(mtd);
        struct fsmc_nand_data *host = nand_get_controller_data(nand);
        struct fsmc_nand_timings tims;
        const struct nand_sdr_timings *sdrt;
@@ -368,9 +367,9 @@ static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
 /*
  * fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
  */
-static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
+static void fsmc_enable_hwecc(struct nand_chip *chip, int mode)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
 
        writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCPLEN_256,
                       host->regs_va + FSMC_PC);
@@ -385,10 +384,10 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
  * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to
  * max of 8-bits)
  */
-static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
+static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const uint8_t *data,
                                uint8_t *ecc)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
        uint32_t ecc_tmp;
        unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
 
@@ -433,10 +432,10 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
  * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to
  * max of 1-bit)
  */
-static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
+static int fsmc_read_hwecc_ecc1(struct nand_chip *chip, const uint8_t *data,
                                uint8_t *ecc)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
        uint32_t ecc_tmp;
 
        ecc_tmp = readl_relaxed(host->regs_va + ECC1);
@@ -610,9 +609,9 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
 }
 
 /* fsmc_select_chip - assert or deassert nCE */
-static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
+static void fsmc_select_chip(struct nand_chip *chip, int chipnr)
 {
-       struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
        u32 pc;
 
        /* Support only one CS */
@@ -707,7 +706,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
 
 /*
  * fsmc_read_page_hwecc
- * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
  * @oob_required:      caller expects OOB data read to chip->oob_poi
@@ -719,9 +717,10 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
  * After this read, fsmc hardware generates and reports error data bits(up to a
  * max of 8 bits)
  */
-static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                uint8_t *buf, int oob_required, int page)
+static int fsmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+                               int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int i, j, s, stat, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
@@ -740,7 +739,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->ecc.hwctl(chip, NAND_ECC_READ);
                nand_read_data_op(chip, p, eccsize, false);
 
                for (j = 0; j < eccbytes;) {
@@ -767,9 +766,9 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                }
 
                memcpy(&ecc_code[i], oob, chip->ecc.bytes);
-               chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+               chip->ecc.calculate(chip, p, &ecc_calc[i]);
 
-               stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+               stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
                if (stat < 0) {
                        mtd->ecc_stats.failed++;
                } else {
@@ -791,11 +790,10 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * calc_ecc is a 104 bit information containing maximum of 8 error
  * offset informations of 13 bits each in 512 bytes of read data.
  */
-static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
-                            uint8_t *read_ecc, uint8_t *calc_ecc)
+static int fsmc_bch8_correct_data(struct nand_chip *chip, uint8_t *dat,
+                                 uint8_t *read_ecc, uint8_t *calc_ecc)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+       struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
        uint32_t err_idx[8];
        uint32_t num_err, i;
        uint32_t ecc1, ecc2, ecc3, ecc4;
@@ -951,6 +949,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
                nand->ecc.correct = nand_correct_data;
                nand->ecc.bytes = 3;
                nand->ecc.strength = 1;
+               nand->ecc.options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
                break;
 
        case NAND_ECC_SOFT:
@@ -1082,7 +1081,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        mtd->dev.parent = &pdev->dev;
        nand->exec_op = fsmc_exec_op;
        nand->select_chip = fsmc_select_chip;
-       nand->chip_delay = 30;
 
        /*
         * Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
@@ -1125,7 +1123,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
         * Scan to find existence of the device
         */
        nand->dummy_controller.ops = &fsmc_nand_controller_ops;
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(nand, 1);
        if (ret)
                goto release_dma_write_chan;
 
@@ -1161,7 +1159,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
        struct fsmc_nand_data *host = platform_get_drvdata(pdev);
 
        if (host) {
-               nand_release(nand_to_mtd(&host->nand));
+               nand_release(&host->nand);
 
                if (host->mode == USE_DMA_ACCESS) {
                        dma_release_channel(host->write_dma_chan);
index 2780af26d9ab7db286d4d17b6c6e2ed165a192a6..a6c9a824a7d415fae44d9f7a228db87b915df556 100644 (file)
@@ -73,9 +73,10 @@ static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
 static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
 #endif
 
-static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void gpio_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
+                              unsigned int ctrl)
 {
-       struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+       struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
 
        gpio_nand_dosync(gpiomtd);
 
@@ -89,13 +90,13 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
        if (cmd == NAND_CMD_NONE)
                return;
 
-       writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
+       writeb(cmd, gpiomtd->nand_chip.legacy.IO_ADDR_W);
        gpio_nand_dosync(gpiomtd);
 }
 
-static int gpio_nand_devready(struct mtd_info *mtd)
+static int gpio_nand_devready(struct nand_chip *chip)
 {
-       struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+       struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
 
        return gpiod_get_value(gpiomtd->rdy);
 }
@@ -194,7 +195,7 @@ static int gpio_nand_remove(struct platform_device *pdev)
 {
        struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
 
-       nand_release(nand_to_mtd(&gpiomtd->nand_chip));
+       nand_release(&gpiomtd->nand_chip);
 
        /* Enable write protection and disable the chip */
        if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
@@ -224,9 +225,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
        chip = &gpiomtd->nand_chip;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       chip->IO_ADDR_R = devm_ioremap_resource(dev, res);
-       if (IS_ERR(chip->IO_ADDR_R))
-               return PTR_ERR(chip->IO_ADDR_R);
+       chip->legacy.IO_ADDR_R = devm_ioremap_resource(dev, res);
+       if (IS_ERR(chip->legacy.IO_ADDR_R))
+               return PTR_ERR(chip->legacy.IO_ADDR_R);
 
        res = gpio_nand_get_io_sync(pdev);
        if (res) {
@@ -270,15 +271,15 @@ static int gpio_nand_probe(struct platform_device *pdev)
        }
        /* Using RDY pin */
        if (gpiomtd->rdy)
-               chip->dev_ready = gpio_nand_devready;
+               chip->legacy.dev_ready = gpio_nand_devready;
 
        nand_set_flash_node(chip, pdev->dev.of_node);
-       chip->IO_ADDR_W         = chip->IO_ADDR_R;
+       chip->legacy.IO_ADDR_W  = chip->legacy.IO_ADDR_R;
        chip->ecc.mode          = NAND_ECC_SOFT;
        chip->ecc.algo          = NAND_ECC_HAMMING;
        chip->options           = gpiomtd->plat.options;
-       chip->chip_delay        = gpiomtd->plat.chip_delay;
-       chip->cmd_ctrl          = gpio_nand_cmd_ctrl;
+       chip->legacy.chip_delay = gpiomtd->plat.chip_delay;
+       chip->legacy.cmd_ctrl   = gpio_nand_cmd_ctrl;
 
        mtd                     = nand_to_mtd(chip);
        mtd->dev.parent         = dev;
@@ -289,7 +290,7 @@ static int gpio_nand_probe(struct platform_device *pdev)
        if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
                gpiod_direction_output(gpiomtd->nwp, 1);
 
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(chip, 1);
        if (ret)
                goto err_wp;
 
index 88ea2203e263bcdd1e54d3c4abc558fb42a1c895..bd4cfac6b5aa69e8dbc6cec34c02ca59a8399912 100644 (file)
@@ -471,10 +471,9 @@ void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
        udelay(dll_wait_time_us);
 }
 
-int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
+int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
                              const struct nand_data_interface *conf)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        const struct nand_sdr_timings *sdr;
 
index 1c1ebbc82824362330fe307a67d4246fda2a03ed..94c2b7525c85e5942ad2ed26fe7e16bde3c21852 100644 (file)
@@ -783,9 +783,8 @@ error_alloc:
        return -ENOMEM;
 }
 
-static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
+static void gpmi_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        int ret;
 
@@ -817,17 +816,15 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
        this->command_length = 0;
 }
 
-static int gpmi_dev_ready(struct mtd_info *mtd)
+static int gpmi_dev_ready(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
 
        return gpmi_is_ready(this, this->current_chip);
 }
 
-static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
+static void gpmi_select_chip(struct nand_chip *chip, int chipnr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        int ret;
 
@@ -859,9 +856,8 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
        this->current_chip = chipnr;
 }
 
-static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void gpmi_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
 
        dev_dbg(this->dev, "len is %d\n", len);
@@ -869,9 +865,8 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
        gpmi_read_data(this, buf, len);
 }
 
-static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void gpmi_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
 
        dev_dbg(this->dev, "len is %d\n", len);
@@ -879,13 +874,12 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
        gpmi_send_data(this, buf, len);
 }
 
-static uint8_t gpmi_read_byte(struct mtd_info *mtd)
+static uint8_t gpmi_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        uint8_t *buf = this->data_buffer_dma;
 
-       gpmi_read_buf(mtd, buf, 1);
+       gpmi_read_buf(chip, buf, 1);
        return buf[0];
 }
 
@@ -1085,8 +1079,8 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
        return max_bitflips;
 }
 
-static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                             uint8_t *buf, int oob_required, int page)
+static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
+                             int oob_required, int page)
 {
        nand_read_page_op(chip, page, 0, NULL, 0);
 
@@ -1094,8 +1088,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /* Fake a virtual small page for the subpage read */
-static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint32_t offs, uint32_t len, uint8_t *buf, int page)
+static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs,
+                                uint32_t len, uint8_t *buf, int page)
 {
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        void __iomem *bch_regs = this->resources.bch_regs;
@@ -1130,7 +1124,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
                        dev_dbg(this->dev,
                                "page:%d, first:%d, last:%d, marker at:%d\n",
                                page, first, last, marker_pos);
-                       return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+                       return gpmi_ecc_read_page(chip, buf, 0, page);
                }
        }
 
@@ -1182,9 +1176,10 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        return max_bitflips;
 }
 
-static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf, int oob_required, int page)
+static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf,
+                              int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        struct bch_geometry *nfc_geo = &this->bch_geometry;
        const void *payload_virt;
@@ -1324,9 +1319,9 @@ exit_auxiliary:
  * ECC-based or raw view of the page is implicit in which function it calls
  * (there is a similar pair of ECC-based/raw functions for writing).
  */
-static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                               int page)
+static int gpmi_ecc_read_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
 
        dev_dbg(this->dev, "page number is %d\n", page);
@@ -1335,7 +1330,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
 
        /* Read out the conventional OOB. */
        nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
-       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
 
        /*
         * Now, we want to make sure the block mark is correct. In the
@@ -1345,15 +1340,15 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
        if (GPMI_IS_MX23(this)) {
                /* Read the block mark into the first byte of the OOB buffer. */
                nand_read_page_op(chip, page, 0, NULL, 0);
-               chip->oob_poi[0] = chip->read_byte(mtd);
+               chip->oob_poi[0] = chip->legacy.read_byte(chip);
        }
 
        return 0;
 }
 
-static int
-gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+static int gpmi_ecc_write_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct mtd_oob_region of = { };
 
        /* Do we have available oob area? */
@@ -1380,10 +1375,10 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
  * See set_geometry_by_ecc_info inline comments to have a full description
  * of the layout used by the GPMI controller.
  */
-static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
-                                 struct nand_chip *chip, uint8_t *buf,
+static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
                                  int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        struct bch_geometry *nfc_geo = &this->bch_geometry;
        int eccsize = nfc_geo->ecc_chunk_size;
@@ -1464,11 +1459,10 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
  * See set_geometry_by_ecc_info inline comments to have a full description
  * of the layout used by the GPMI controller.
  */
-static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
-                                  struct nand_chip *chip,
-                                  const uint8_t *buf,
+static int gpmi_ecc_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
                                   int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        struct bch_geometry *nfc_geo = &this->bch_geometry;
        int eccsize = nfc_geo->ecc_chunk_size;
@@ -1536,28 +1530,26 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
                                 mtd->writesize + mtd->oobsize);
 }
 
-static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                int page)
+static int gpmi_ecc_read_oob_raw(struct nand_chip *chip, int page)
 {
-       return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
+       return gpmi_ecc_read_page_raw(chip, NULL, 1, page);
 }
 
-static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                int page)
+static int gpmi_ecc_write_oob_raw(struct nand_chip *chip, int page)
 {
-       return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
+       return gpmi_ecc_write_page_raw(chip, NULL, 1, page);
 }
 
-static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int gpmi_block_markbad(struct nand_chip *chip, loff_t ofs)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        int ret = 0;
        uint8_t *block_mark;
        int column, page, chipnr;
 
        chipnr = (int)(ofs >> chip->chip_shift);
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
 
        column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
 
@@ -1570,7 +1562,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
 
        ret = nand_prog_page_op(chip, page, column, block_mark, 1);
 
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
 
        return ret;
 }
@@ -1607,7 +1599,6 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
        struct boot_rom_geometry *rom_geo = &this->rom_geometry;
        struct device *dev = this->dev;
        struct nand_chip *chip = &this->nand;
-       struct mtd_info *mtd = nand_to_mtd(chip);
        unsigned int search_area_size_in_strides;
        unsigned int stride;
        unsigned int page;
@@ -1619,7 +1610,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
        search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
 
        saved_chip_number = this->current_chip;
-       chip->select_chip(mtd, 0);
+       chip->select_chip(chip, 0);
 
        /*
         * Loop through the first search area, looking for the NCB fingerprint.
@@ -1637,7 +1628,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
                 * and starts in the 12th byte of the page.
                 */
                nand_read_page_op(chip, page, 12, NULL, 0);
-               chip->read_buf(mtd, buffer, strlen(fingerprint));
+               chip->legacy.read_buf(chip, buffer, strlen(fingerprint));
 
                /* Look for the fingerprint. */
                if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
@@ -1647,7 +1638,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
 
        }
 
-       chip->select_chip(mtd, saved_chip_number);
+       chip->select_chip(chip, saved_chip_number);
 
        if (found_an_ncb_fingerprint)
                dev_dbg(dev, "\tFound a fingerprint\n");
@@ -1690,7 +1681,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
 
        /* Select chip 0. */
        saved_chip_number = this->current_chip;
-       chip->select_chip(mtd, 0);
+       chip->select_chip(chip, 0);
 
        /* Loop over blocks in the first search area, erasing them. */
        dev_dbg(dev, "Erasing the search area...\n");
@@ -1716,13 +1707,13 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
                /* Write the first page of the current stride. */
                dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
 
-               status = chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
+               status = chip->ecc.write_page_raw(chip, buffer, 0, page);
                if (status)
                        dev_err(dev, "[%s] Write failed.\n", __func__);
        }
 
        /* Deselect chip 0. */
-       chip->select_chip(mtd, saved_chip_number);
+       chip->select_chip(chip, saved_chip_number);
        return 0;
 }
 
@@ -1771,10 +1762,10 @@ static int mx23_boot_init(struct gpmi_nand_data  *this)
                byte = block <<  chip->phys_erase_shift;
 
                /* Send the command to read the conventional block mark. */
-               chip->select_chip(mtd, chipnr);
+               chip->select_chip(chip, chipnr);
                nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
-               block_mark = chip->read_byte(mtd);
-               chip->select_chip(mtd, -1);
+               block_mark = chip->legacy.read_byte(chip);
+               chip->select_chip(chip, -1);
 
                /*
                 * Check if the block is marked bad. If so, we need to mark it
@@ -1783,7 +1774,7 @@ static int mx23_boot_init(struct gpmi_nand_data  *this)
                 */
                if (block_mark != 0xff) {
                        dev_dbg(dev, "Transcribing mark in block %u\n", block);
-                       ret = chip->block_markbad(mtd, byte);
+                       ret = chip->legacy.block_markbad(chip, byte);
                        if (ret)
                                dev_err(dev,
                                        "Failed to mark block bad with ret %d\n",
@@ -1911,13 +1902,13 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
        nand_set_flash_node(chip, this->pdev->dev.of_node);
        chip->select_chip       = gpmi_select_chip;
        chip->setup_data_interface = gpmi_setup_data_interface;
-       chip->cmd_ctrl          = gpmi_cmd_ctrl;
-       chip->dev_ready         = gpmi_dev_ready;
-       chip->read_byte         = gpmi_read_byte;
-       chip->read_buf          = gpmi_read_buf;
-       chip->write_buf         = gpmi_write_buf;
+       chip->legacy.cmd_ctrl   = gpmi_cmd_ctrl;
+       chip->legacy.dev_ready  = gpmi_dev_ready;
+       chip->legacy.read_byte  = gpmi_read_byte;
+       chip->legacy.read_buf   = gpmi_read_buf;
+       chip->legacy.write_buf  = gpmi_write_buf;
        chip->badblock_pattern  = &gpmi_bbt_descr;
-       chip->block_markbad     = gpmi_block_markbad;
+       chip->legacy.block_markbad = gpmi_block_markbad;
        chip->options           |= NAND_NO_SUBPAGE_WRITE;
 
        /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
@@ -1934,7 +1925,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
                goto err_out;
 
        chip->dummy_controller.ops = &gpmi_nand_controller_ops;
-       ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1);
+       ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1);
        if (ret)
                goto err_out;
 
@@ -2026,7 +2017,7 @@ static int gpmi_nand_remove(struct platform_device *pdev)
 {
        struct gpmi_nand_data *this = platform_get_drvdata(pdev);
 
-       nand_release(nand_to_mtd(&this->nand));
+       nand_release(&this->nand);
        gpmi_free_dma_buffer(this);
        release_resources(this);
        return 0;
index 69cd0cbde4f2070eb5bfcd6dd3c51158b6625320..d0b79bac2728072ff359a9137cdedac4fe13b67a 100644 (file)
@@ -178,7 +178,7 @@ int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
 int gpmi_send_command(struct gpmi_nand_data *);
 int gpmi_enable_clk(struct gpmi_nand_data *this);
 int gpmi_disable_clk(struct gpmi_nand_data *this);
-int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
+int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
                              const struct nand_data_interface *conf);
 void gpmi_nfc_apply_timings(struct gpmi_nand_data *this);
 int gpmi_read_data(struct gpmi_nand_data *, void *buf, int len);
index 950dc7789296fa3d30c3c63adadfa474594f773f..f043938ee36b7fb5848fa505d8edd9c3f5e0e477 100644 (file)
@@ -353,9 +353,8 @@ static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
        return 0;
 }
 
-static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
+static void hisi_nfc_select_chip(struct nand_chip *chip, int chipselect)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct hinfc_host *host = nand_get_controller_data(chip);
 
        if (chipselect < 0)
@@ -364,9 +363,8 @@ static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
        host->chipselect = chipselect;
 }
 
-static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
+static uint8_t hisi_nfc_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct hinfc_host *host = nand_get_controller_data(chip);
 
        if (host->command == NAND_CMD_STATUS)
@@ -380,28 +378,17 @@ static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
        return *(uint8_t *)(host->buffer + host->offset - 1);
 }
 
-static u16 hisi_nfc_read_word(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       struct hinfc_host *host = nand_get_controller_data(chip);
-
-       host->offset += 2;
-       return *(u16 *)(host->buffer + host->offset - 2);
-}
-
 static void
-hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+hisi_nfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct hinfc_host *host = nand_get_controller_data(chip);
 
        memcpy(host->buffer + host->offset, buf, len);
        host->offset += len;
 }
 
-static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void hisi_nfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct hinfc_host *host = nand_get_controller_data(chip);
 
        memcpy(buf, host->buffer + host->offset, len);
@@ -442,10 +429,10 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr)
        }
 }
 
-static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
-               int page_addr)
+static void hisi_nfc_cmdfunc(struct nand_chip *chip, unsigned command,
+                            int column, int page_addr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct hinfc_host *host = nand_get_controller_data(chip);
        int is_cache_invalid = 1;
        unsigned int flag = 0;
@@ -537,15 +524,16 @@ static irqreturn_t hinfc_irq_handle(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
-static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
-       struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+static int hisi_nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+                                    int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct hinfc_host *host = nand_get_controller_data(chip);
        int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
        int stat_1, stat_2;
 
        nand_read_page_op(chip, page, 0, buf, mtd->writesize);
-       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
 
        /* errors which can not be corrected by ECC */
        if (host->irq_status & HINFC504_INTS_UE) {
@@ -569,9 +557,9 @@ static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
        return max_bitflips;
 }
 
-static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                               int page)
+static int hisi_nand_read_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct hinfc_host *host = nand_get_controller_data(chip);
 
        nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
@@ -585,13 +573,15 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
        return 0;
 }
 
-static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
-               struct nand_chip *chip, const uint8_t *buf, int oob_required,
-               int page)
+static int hisi_nand_write_page_hwecc(struct nand_chip *chip,
+                                     const uint8_t *buf, int oob_required,
+                                     int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
        if (oob_required)
-               chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+               chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        return nand_prog_page_end_op(chip);
 }
@@ -792,15 +782,14 @@ static int hisi_nfc_probe(struct platform_device *pdev)
 
        nand_set_controller_data(chip, host);
        nand_set_flash_node(chip, np);
-       chip->cmdfunc           = hisi_nfc_cmdfunc;
+       chip->legacy.cmdfunc    = hisi_nfc_cmdfunc;
        chip->select_chip       = hisi_nfc_select_chip;
-       chip->read_byte         = hisi_nfc_read_byte;
-       chip->read_word         = hisi_nfc_read_word;
-       chip->write_buf         = hisi_nfc_write_buf;
-       chip->read_buf          = hisi_nfc_read_buf;
-       chip->chip_delay        = HINFC504_CHIP_DELAY;
-       chip->set_features      = nand_get_set_features_notsupp;
-       chip->get_features      = nand_get_set_features_notsupp;
+       chip->legacy.read_byte  = hisi_nfc_read_byte;
+       chip->legacy.write_buf  = hisi_nfc_write_buf;
+       chip->legacy.read_buf   = hisi_nfc_read_buf;
+       chip->legacy.chip_delay = HINFC504_CHIP_DELAY;
+       chip->legacy.set_features       = nand_get_set_features_notsupp;
+       chip->legacy.get_features       = nand_get_set_features_notsupp;
 
        hisi_nfc_host_init(host);
 
@@ -811,7 +800,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
        }
 
        chip->dummy_controller.ops = &hisi_nfc_controller_ops;
-       ret = nand_scan(mtd, max_chips);
+       ret = nand_scan(chip, max_chips);
        if (ret)
                return ret;
 
@@ -828,9 +817,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
 static int hisi_nfc_remove(struct platform_device *pdev)
 {
        struct hinfc_host *host = platform_get_drvdata(pdev);
-       struct mtd_info *mtd = nand_to_mtd(&host->chip);
 
-       nand_release(mtd);
+       nand_release(&host->chip);
 
        return 0;
 }
diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h
new file mode 100644 (file)
index 0000000..04c2cf7
--- /dev/null
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 - Bootlin
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ *
+ * Header containing internal definitions to be used only by core files.
+ * NAND controller drivers should not include this file.
+ */
+
+#ifndef __LINUX_RAWNAND_INTERNALS
+#define __LINUX_RAWNAND_INTERNALS
+
+#include <linux/mtd/rawnand.h>
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_AMD           0x01
+#define NAND_MFR_ATO           0x9b
+#define NAND_MFR_EON           0x92
+#define NAND_MFR_ESMT          0xc8
+#define NAND_MFR_FUJITSU       0x04
+#define NAND_MFR_HYNIX         0xad
+#define NAND_MFR_INTEL         0x89
+#define NAND_MFR_MACRONIX      0xc2
+#define NAND_MFR_MICRON                0x2c
+#define NAND_MFR_NATIONAL      0x8f
+#define NAND_MFR_RENESAS       0x07
+#define NAND_MFR_SAMSUNG       0xec
+#define NAND_MFR_SANDISK       0x45
+#define NAND_MFR_STMICRO       0x20
+#define NAND_MFR_TOSHIBA       0x98
+#define NAND_MFR_WINBOND       0xef
+
+/**
+ * struct nand_manufacturer_ops - NAND Manufacturer operations
+ * @detect: detect the NAND memory organization and capabilities
+ * @init: initialize all vendor specific fields (like the ->read_retry()
+ *       implementation) if any.
+ * @cleanup: the ->init() function may have allocated resources, ->cleanup()
+ *          is here to let vendor specific code release those resources.
+ * @fixup_onfi_param_page: apply vendor specific fixups to the ONFI parameter
+ *                        page. This is called after the checksum is verified.
+ */
+struct nand_manufacturer_ops {
+       void (*detect)(struct nand_chip *chip);
+       int (*init)(struct nand_chip *chip);
+       void (*cleanup)(struct nand_chip *chip);
+       void (*fixup_onfi_param_page)(struct nand_chip *chip,
+                                     struct nand_onfi_params *p);
+};
+
+/**
+ * struct nand_manufacturer - NAND Flash Manufacturer structure
+ * @name: Manufacturer name
+ * @id: manufacturer ID code of device.
+ * @ops: manufacturer operations
+ */
+struct nand_manufacturer {
+       int id;
+       char *name;
+       const struct nand_manufacturer_ops *ops;
+};
+
+
+extern struct nand_flash_dev nand_flash_ids[];
+
+extern const struct nand_manufacturer_ops amd_nand_manuf_ops;
+extern const struct nand_manufacturer_ops esmt_nand_manuf_ops;
+extern const struct nand_manufacturer_ops hynix_nand_manuf_ops;
+extern const struct nand_manufacturer_ops macronix_nand_manuf_ops;
+extern const struct nand_manufacturer_ops micron_nand_manuf_ops;
+extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
+extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
+
+/* Core functions */
+const struct nand_manufacturer *nand_get_manufacturer(u8 id);
+int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs);
+int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
+                   int allowbbt);
+int onfi_fill_data_interface(struct nand_chip *chip,
+                            enum nand_data_interface_type type,
+                            int timing_mode);
+int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
+int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
+int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
+                              int oob_required, int page);
+int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf,
+                               int oob_required, int page);
+int nand_exit_status_op(struct nand_chip *chip);
+int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
+                           unsigned int len);
+void nand_decode_ext_id(struct nand_chip *chip);
+void panic_nand_wait(struct nand_chip *chip, unsigned long timeo);
+void sanitize_string(uint8_t *s, size_t len);
+
+/* BBT functions */
+int nand_markbad_bbt(struct nand_chip *chip, loff_t offs);
+int nand_isreserved_bbt(struct nand_chip *chip, loff_t offs);
+int nand_isbad_bbt(struct nand_chip *chip, loff_t offs, int allowbbt);
+
+/* Legacy */
+void nand_legacy_set_defaults(struct nand_chip *chip);
+void nand_legacy_adjust_cmdfunc(struct nand_chip *chip);
+int nand_legacy_check_hooks(struct nand_chip *chip);
+
+/* ONFI functions */
+u16 onfi_crc16(u16 crc, u8 const *p, size_t len);
+int nand_onfi_detect(struct nand_chip *chip);
+
+/* JEDEC functions */
+int nand_jedec_detect(struct nand_chip *chip);
+
+#endif /* __LINUX_RAWNAND_INTERNALS */
index a7515452bc5976c747b82ddd80c3f6618fbb4dec..fb59cfca11a7c109513ecf5aeca511bc698e41de 100644 (file)
@@ -78,10 +78,9 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
        return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
 }
 
-static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
+static void jz_nand_select_chip(struct nand_chip *chip, int chipnr)
 {
-       struct jz_nand *nand = mtd_to_jz_nand(mtd);
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
        uint32_t ctrl;
        int banknr;
 
@@ -92,18 +91,18 @@ static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
                banknr = -1;
        } else {
                banknr = nand->banks[chipnr] - 1;
-               chip->IO_ADDR_R = nand->bank_base[banknr];
-               chip->IO_ADDR_W = nand->bank_base[banknr];
+               chip->legacy.IO_ADDR_R = nand->bank_base[banknr];
+               chip->legacy.IO_ADDR_W = nand->bank_base[banknr];
        }
        writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
 
        nand->selected_bank = banknr;
 }
 
-static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat,
+                            unsigned int ctrl)
 {
-       struct jz_nand *nand = mtd_to_jz_nand(mtd);
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
        uint32_t reg;
        void __iomem *bank_base = nand->bank_base[nand->selected_bank];
 
@@ -115,7 +114,7 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
                        bank_base += JZ_NAND_MEM_ADDR_OFFSET;
                else if (ctrl & NAND_CLE)
                        bank_base += JZ_NAND_MEM_CMD_OFFSET;
-               chip->IO_ADDR_W = bank_base;
+               chip->legacy.IO_ADDR_W = bank_base;
 
                reg = readl(nand->base + JZ_REG_NAND_CTRL);
                if (ctrl & NAND_NCE)
@@ -125,18 +124,18 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
                writel(reg, nand->base + JZ_REG_NAND_CTRL);
        }
        if (dat != NAND_CMD_NONE)
-               writeb(dat, chip->IO_ADDR_W);
+               writeb(dat, chip->legacy.IO_ADDR_W);
 }
 
-static int jz_nand_dev_ready(struct mtd_info *mtd)
+static int jz_nand_dev_ready(struct nand_chip *chip)
 {
-       struct jz_nand *nand = mtd_to_jz_nand(mtd);
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
        return gpiod_get_value_cansleep(nand->busy_gpio);
 }
 
-static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
+static void jz_nand_hwctl(struct nand_chip *chip, int mode)
 {
-       struct jz_nand *nand = mtd_to_jz_nand(mtd);
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
        uint32_t reg;
 
        writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
@@ -162,10 +161,10 @@ static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
        writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
 }
 
-static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat,
-       uint8_t *ecc_code)
+static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat,
+                                   uint8_t *ecc_code)
 {
-       struct jz_nand *nand = mtd_to_jz_nand(mtd);
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
        uint32_t reg, status;
        int i;
        unsigned int timeout = 1000;
@@ -215,10 +214,10 @@ static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
        dat[index+1] = (data >> 8) & 0xff;
 }
 
-static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
-       uint8_t *read_ecc, uint8_t *calc_ecc)
+static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat,
+                                 uint8_t *read_ecc, uint8_t *calc_ecc)
 {
-       struct jz_nand *nand = mtd_to_jz_nand(mtd);
+       struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
        int i, error_count, index;
        uint32_t reg, status, error;
        unsigned int timeout = 1000;
@@ -331,19 +330,19 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 
        if (chipnr == 0) {
                /* Detect first chip. */
-               ret = nand_scan(mtd, 1);
+               ret = nand_scan(chip, 1);
                if (ret)
                        goto notfound_id;
 
                /* Retrieve the IDs from the first chip. */
-               chip->select_chip(mtd, 0);
+               chip->select_chip(chip, 0);
                nand_reset_op(chip);
                nand_readid_op(chip, 0, id, sizeof(id));
                *nand_maf_id = id[0];
                *nand_dev_id = id[1];
        } else {
                /* Detect additional chip. */
-               chip->select_chip(mtd, chipnr);
+               chip->select_chip(chip, chipnr);
                nand_reset_op(chip);
                nand_readid_op(chip, 0, id, sizeof(id));
                if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
@@ -426,13 +425,13 @@ static int jz_nand_probe(struct platform_device *pdev)
        chip->ecc.strength      = 4;
        chip->ecc.options       = NAND_ECC_GENERIC_ERASED_CHECK;
 
-       chip->chip_delay = 50;
-       chip->cmd_ctrl = jz_nand_cmd_ctrl;
+       chip->legacy.chip_delay = 50;
+       chip->legacy.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;
+               chip->legacy.dev_ready = jz_nand_dev_ready;
 
        platform_set_drvdata(pdev, nand);
 
@@ -507,7 +506,7 @@ static int jz_nand_remove(struct platform_device *pdev)
        struct jz_nand *nand = platform_get_drvdata(pdev);
        size_t i;
 
-       nand_release(nand_to_mtd(&nand->chip));
+       nand_release(&nand->chip);
 
        /* Deassert and disable all chips */
        writel(0, nand->base + JZ_REG_NAND_CTRL);
index db4fa60bd52acaf5f056e27dcec2803431ad5414..cdf22100ab7719841c63851cd5c6702ed3facdcc 100644 (file)
@@ -71,9 +71,9 @@ static inline struct jz4780_nand_controller
        return container_of(ctrl, struct jz4780_nand_controller, controller);
 }
 
-static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
+static void jz4780_nand_select_chip(struct nand_chip *chip, int chipnr)
 {
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
        struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
        struct jz4780_nand_cs *cs;
 
@@ -86,10 +86,10 @@ static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
        nfc->selected = chipnr;
 }
 
-static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void jz4780_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
                                 unsigned int ctrl)
 {
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
        struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
        struct jz4780_nand_cs *cs;
 
@@ -109,24 +109,24 @@ static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
                writeb(cmd, cs->base + OFFSET_CMD);
 }
 
-static int jz4780_nand_dev_ready(struct mtd_info *mtd)
+static int jz4780_nand_dev_ready(struct nand_chip *chip)
 {
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
 
        return !gpiod_get_value_cansleep(nand->busy_gpio);
 }
 
-static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+static void jz4780_nand_ecc_hwctl(struct nand_chip *chip, int mode)
 {
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
 
        nand->reading = (mode == NAND_ECC_READ);
 }
 
-static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
+static int jz4780_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat,
                                     u8 *ecc_code)
 {
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
        struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
        struct jz4780_bch_params params;
 
@@ -144,10 +144,10 @@ static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
        return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code);
 }
 
-static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
+static int jz4780_nand_ecc_correct(struct nand_chip *chip, u8 *dat,
                                   u8 *read_ecc, u8 *calc_ecc)
 {
-       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+       struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
        struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
        struct jz4780_bch_params params;
 
@@ -256,7 +256,7 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
                dev_err(dev, "failed to request busy GPIO: %d\n", ret);
                return ret;
        } else if (nand->busy_gpio) {
-               nand->chip.dev_ready = jz4780_nand_dev_ready;
+               nand->chip.legacy.dev_ready = jz4780_nand_dev_ready;
        }
 
        nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
@@ -275,24 +275,24 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
                return -ENOMEM;
        mtd->dev.parent = dev;
 
-       chip->IO_ADDR_R = cs->base + OFFSET_DATA;
-       chip->IO_ADDR_W = cs->base + OFFSET_DATA;
-       chip->chip_delay = RB_DELAY_US;
+       chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA;
+       chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA;
+       chip->legacy.chip_delay = RB_DELAY_US;
        chip->options = NAND_NO_SUBPAGE_WRITE;
        chip->select_chip = jz4780_nand_select_chip;
-       chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
+       chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl;
        chip->ecc.mode = NAND_ECC_HW;
        chip->controller = &nfc->controller;
        nand_set_flash_node(chip, np);
 
        chip->controller->ops = &jz4780_nand_controller_ops;
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(chip, 1);
        if (ret)
                return ret;
 
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
-               nand_release(mtd);
+               nand_release(chip);
                return ret;
        }
 
@@ -307,7 +307,7 @@ static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
 
        while (!list_empty(&nfc->chips)) {
                chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
-               nand_release(nand_to_mtd(&chip->chip));
+               nand_release(&chip->chip);
                list_del(&chip->chip_list);
        }
 }
@@ -352,7 +352,7 @@ static int jz4780_nand_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL);
+       nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL);
        if (!nfc)
                return -ENOMEM;
 
index e82abada130a057b0855f64b7f546026b529f0ad..abbb655fe154dfc834ea42488d2fba5fd500b073 100644 (file)
@@ -286,10 +286,9 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
 /*
  * Hardware specific access to control lines
  */
-static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void lpc32xx_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
                                  unsigned int ctrl)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
 
        if (cmd != NAND_CMD_NONE) {
@@ -303,9 +302,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 /*
  * Read Device Ready (NAND device _and_ controller ready)
  */
-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+static int lpc32xx_nand_device_ready(struct nand_chip *nand_chip)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
 
        if ((readb(MLC_ISR(host->io_base)) &
@@ -330,8 +328,9 @@ static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
        return IRQ_HANDLED;
 }
 
-static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
+static int lpc32xx_waitfunc_nand(struct nand_chip *chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
        if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
@@ -349,9 +348,9 @@ exit:
        return NAND_STATUS_READY;
 }
 
-static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
-                                      struct nand_chip *chip)
+static int lpc32xx_waitfunc_controller(struct nand_chip *chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
        if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
@@ -369,10 +368,10 @@ exit:
        return NAND_STATUS_READY;
 }
 
-static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+static int lpc32xx_waitfunc(struct nand_chip *chip)
 {
-       lpc32xx_waitfunc_nand(mtd, chip);
-       lpc32xx_waitfunc_controller(mtd, chip);
+       lpc32xx_waitfunc_nand(chip);
+       lpc32xx_waitfunc_controller(chip);
 
        return NAND_STATUS_READY;
 }
@@ -442,9 +441,10 @@ out1:
        return -ENXIO;
 }
 
-static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                            uint8_t *buf, int oob_required, int page)
+static int lpc32xx_read_page(struct nand_chip *chip, uint8_t *buf,
+                            int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
        int i, j;
        uint8_t *oobbuf = chip->oob_poi;
@@ -470,7 +470,7 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
 
                /* Wait for Controller Ready */
-               lpc32xx_waitfunc_controller(mtd, chip);
+               lpc32xx_waitfunc_controller(chip);
 
                /* Check ECC Error status */
                mlc_isr = readl(MLC_ISR(host->io_base));
@@ -507,11 +507,11 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        return 0;
 }
 
-static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
-                                      struct nand_chip *chip,
+static int lpc32xx_write_page_lowlevel(struct nand_chip *chip,
                                       const uint8_t *buf, int oob_required,
                                       int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
        const uint8_t *oobbuf = chip->oob_poi;
        uint8_t *dma_buf = (uint8_t *)buf;
@@ -551,32 +551,30 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
                writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
 
                /* Wait for Controller Ready */
-               lpc32xx_waitfunc_controller(mtd, chip);
+               lpc32xx_waitfunc_controller(chip);
        }
 
        return nand_prog_page_end_op(chip);
 }
 
-static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                           int page)
+static int lpc32xx_read_oob(struct nand_chip *chip, int page)
 {
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
        /* Read whole page - necessary with MLC controller! */
-       lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
+       lpc32xx_read_page(chip, host->dummy_buf, 1, page);
 
        return 0;
 }
 
-static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                             int page)
+static int lpc32xx_write_oob(struct nand_chip *chip, int page)
 {
        /* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
        return 0;
 }
 
 /* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
-static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
+static void lpc32xx_ecc_enable(struct nand_chip *chip, int mode)
 {
        /* Always enabled! */
 }
@@ -741,11 +739,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        if (res)
                goto put_clk;
 
-       nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
-       nand_chip->dev_ready = lpc32xx_nand_device_ready;
-       nand_chip->chip_delay = 25; /* us */
-       nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
-       nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
+       nand_chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+       nand_chip->legacy.dev_ready = lpc32xx_nand_device_ready;
+       nand_chip->legacy.chip_delay = 25; /* us */
+       nand_chip->legacy.IO_ADDR_R = MLC_DATA(host->io_base);
+       nand_chip->legacy.IO_ADDR_W = MLC_DATA(host->io_base);
 
        /* Init NAND controller */
        lpc32xx_nand_setup(host);
@@ -762,7 +760,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        nand_chip->ecc.read_oob = lpc32xx_read_oob;
        nand_chip->ecc.strength = 4;
        nand_chip->ecc.bytes = 10;
-       nand_chip->waitfunc = lpc32xx_waitfunc;
+       nand_chip->legacy.waitfunc = lpc32xx_waitfunc;
 
        nand_chip->options = NAND_NO_SUBPAGE_WRITE;
        nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
@@ -802,7 +800,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
         * SMALL block or LARGE block.
         */
        nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
-       res = nand_scan(mtd, 1);
+       res = nand_scan(nand_chip, 1);
        if (res)
                goto free_irq;
 
@@ -839,9 +837,8 @@ free_gpio:
 static int lpc32xx_nand_remove(struct platform_device *pdev)
 {
        struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-       struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
 
-       nand_release(mtd);
+       nand_release(&host->nand_chip);
        free_irq(host->irq, host);
        if (use_dma)
                dma_release_channel(host->dma_chan);
index a4e8b7e7513516c91520814c49519e1259f8f779..f2f2cdbb9d04c6ea72ad30c8ea375f2dcff7492a 100644 (file)
@@ -278,11 +278,10 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
 /*
  * Hardware specific access to control lines
  */
-static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-       unsigned int ctrl)
+static void lpc32xx_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
+                                 unsigned int ctrl)
 {
        uint32_t tmp;
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
        /* Does CE state need to be changed? */
@@ -304,9 +303,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 /*
  * Read the Device Ready pin
  */
-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+static int lpc32xx_nand_device_ready(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
        int rdy = 0;
 
@@ -337,7 +335,7 @@ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
 /*
  * Prepares SLC for transfers with H/W ECC enabled
  */
-static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
+static void lpc32xx_nand_ecc_enable(struct nand_chip *chip, int mode)
 {
        /* Hardware ECC is enabled automatically in hardware as needed */
 }
@@ -345,7 +343,7 @@ static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
 /*
  * Calculates the ECC for the data
  */
-static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
+static int lpc32xx_nand_ecc_calculate(struct nand_chip *chip,
                                      const unsigned char *buf,
                                      unsigned char *code)
 {
@@ -359,9 +357,8 @@ static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
 /*
  * Read a single byte from NAND device
  */
-static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
+static uint8_t lpc32xx_nand_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
        return (uint8_t)readl(SLC_DATA(host->io_base));
@@ -370,9 +367,8 @@ static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
 /*
  * Simple device read without ECC
  */
-static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void lpc32xx_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
        /* Direct device read with no ECC */
@@ -383,9 +379,9 @@ static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 /*
  * Simple device write without ECC
  */
-static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void lpc32xx_nand_write_buf(struct nand_chip *chip, const uint8_t *buf,
+                                  int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
 
        /* Direct device write with no ECC */
@@ -396,18 +392,20 @@ static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int
 /*
  * Read the OOB data from the device without ECC using FIFO method
  */
-static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
-                                         struct nand_chip *chip, int page)
+static int lpc32xx_nand_read_oob_syndrome(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
 }
 
 /*
  * Write the OOB data to the device without ECC using FIFO method
  */
-static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
-       struct nand_chip *chip, int page)
+static int lpc32xx_nand_write_oob_syndrome(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
                                 mtd->oobsize);
 }
@@ -610,10 +608,10 @@ static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
  * Read the data and OOB data from the device, use ECC correction with the
  * data, disable ECC for the OOB data
  */
-static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
-                                          struct nand_chip *chip, uint8_t *buf,
+static int lpc32xx_nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
                                           int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
        struct mtd_oob_region oobregion = { };
        int stat, i, status, error;
@@ -626,7 +624,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
        status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
 
        /* Get OOB data */
-       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
 
        /* Convert to stored ECC format */
        lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
@@ -639,7 +637,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
        oobecc = chip->oob_poi + oobregion.offset;
 
        for (i = 0; i < chip->ecc.steps; i++) {
-               stat = chip->ecc.correct(mtd, buf, oobecc,
+               stat = chip->ecc.correct(chip, buf, oobecc,
                                         &tmpecc[i * chip->ecc.bytes]);
                if (stat < 0)
                        mtd->ecc_stats.failed++;
@@ -657,17 +655,18 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
  * Read the data and OOB data from the device, no ECC correction with the
  * data or OOB data
  */
-static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
-                                              struct nand_chip *chip,
+static int lpc32xx_nand_read_page_raw_syndrome(struct nand_chip *chip,
                                               uint8_t *buf, int oob_required,
                                               int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        /* Issue read command */
        nand_read_page_op(chip, page, 0, NULL, 0);
 
        /* Raw reads can just use the FIFO interface */
-       chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
-       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.read_buf(chip, buf, chip->ecc.size * chip->ecc.steps);
+       chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
 
        return 0;
 }
@@ -676,11 +675,11 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
  * Write the data and OOB data to the device, use ECC with the data,
  * disable ECC for the OOB data
  */
-static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
-                                           struct nand_chip *chip,
+static int lpc32xx_nand_write_page_syndrome(struct nand_chip *chip,
                                            const uint8_t *buf,
                                            int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
        struct mtd_oob_region oobregion = { };
        uint8_t *pb;
@@ -705,7 +704,7 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
        lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
 
        /* Write ECC data to device */
-       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        return nand_prog_page_end_op(chip);
 }
@@ -714,15 +713,16 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
  * Write the data and OOB data to the device, no ECC correction with the
  * data or OOB data
  */
-static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
-                                               struct nand_chip *chip,
+static int lpc32xx_nand_write_page_raw_syndrome(struct nand_chip *chip,
                                                const uint8_t *buf,
                                                int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        /* Raw writes can just use the FIFO interface */
        nand_prog_page_begin_op(chip, page, 0, buf,
                                chip->ecc.size * chip->ecc.steps);
-       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        return nand_prog_page_end_op(chip);
 }
@@ -878,11 +878,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
                goto enable_wp;
 
        /* Set NAND IO addresses and command/ready functions */
-       chip->IO_ADDR_R = SLC_DATA(host->io_base);
-       chip->IO_ADDR_W = SLC_DATA(host->io_base);
-       chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
-       chip->dev_ready = lpc32xx_nand_device_ready;
-       chip->chip_delay = 20; /* 20us command delay time */
+       chip->legacy.IO_ADDR_R = SLC_DATA(host->io_base);
+       chip->legacy.IO_ADDR_W = SLC_DATA(host->io_base);
+       chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+       chip->legacy.dev_ready = lpc32xx_nand_device_ready;
+       chip->legacy.chip_delay = 20; /* 20us command delay time */
 
        /* Init NAND controller */
        lpc32xx_nand_setup(host);
@@ -891,9 +891,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 
        /* NAND callbacks for LPC32xx SLC hardware */
        chip->ecc.mode = NAND_ECC_HW_SYNDROME;
-       chip->read_byte = lpc32xx_nand_read_byte;
-       chip->read_buf = lpc32xx_nand_read_buf;
-       chip->write_buf = lpc32xx_nand_write_buf;
+       chip->legacy.read_byte = lpc32xx_nand_read_byte;
+       chip->legacy.read_buf = lpc32xx_nand_read_buf;
+       chip->legacy.write_buf = lpc32xx_nand_write_buf;
        chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
        chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
        chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
@@ -925,7 +925,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 
        /* Find NAND device */
        chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
-       res = nand_scan(mtd, 1);
+       res = nand_scan(chip, 1);
        if (res)
                goto release_dma;
 
@@ -956,9 +956,8 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 {
        uint32_t tmp;
        struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
-       struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
 
-       nand_release(mtd);
+       nand_release(&host->nand_chip);
        dma_release_channel(host->dma_chan);
 
        /* Force CE high */
index bc2ef52097834f7c43194835a5177d102e6e2c88..650f2b490a054c16c8c20f882f0c72134fadd7b1 100644 (file)
@@ -5,6 +5,73 @@
  * Copyright (C) 2017 Marvell
  * Author: Miquel RAYNAL <miquel.raynal@free-electrons.com>
  *
+ *
+ * This NAND controller driver handles two versions of the hardware,
+ * one is called NFCv1 and is available on PXA SoCs and the other is
+ * called NFCv2 and is available on Armada SoCs.
+ *
+ * The main visible difference is that NFCv1 only has Hamming ECC
+ * capabilities, while NFCv2 also embeds a BCH ECC engine. Also, DMA
+ * is not used with NFCv2.
+ *
+ * The ECC layouts are depicted in details in Marvell AN-379, but here
+ * is a brief description.
+ *
+ * When using Hamming, the data is split in 512B chunks (either 1, 2
+ * or 4) and each chunk will have its own ECC "digest" of 6B at the
+ * beginning of the OOB area and eventually the remaining free OOB
+ * bytes (also called "spare" bytes in the driver). This engine
+ * corrects up to 1 bit per chunk and detects reliably an error if
+ * there are at most 2 bitflips. Here is the page layout used by the
+ * controller when Hamming is chosen:
+ *
+ * +-------------------------------------------------------------+
+ * | Data 1 | ... | Data N | ECC 1 | ... | ECCN | Free OOB bytes |
+ * +-------------------------------------------------------------+
+ *
+ * When using the BCH engine, there are N identical (data + free OOB +
+ * ECC) sections and potentially an extra one to deal with
+ * configurations where the chosen (data + free OOB + ECC) sizes do
+ * not align with the page (data + OOB) size. ECC bytes are always
+ * 30B per ECC chunk. Here is the page layout used by the controller
+ * when BCH is chosen:
+ *
+ * +-----------------------------------------
+ * | Data 1 | Free OOB bytes 1 | ECC 1 | ...
+ * +-----------------------------------------
+ *
+ *      -------------------------------------------
+ *       ... | Data N | Free OOB bytes N | ECC N |
+ *      -------------------------------------------
+ *
+ *           --------------------------------------------+
+ *            Last Data | Last Free OOB bytes | Last ECC |
+ *           --------------------------------------------+
+ *
+ * In both cases, the layout seen by the user is always: all data
+ * first, then all free OOB bytes and finally all ECC bytes. With BCH,
+ * ECC bytes are 30B long and are padded with 0xFF to align on 32
+ * bytes.
+ *
+ * The controller has certain limitations that are handled by the
+ * driver:
+ *   - It can only read 2k at a time. To overcome this limitation, the
+ *     driver issues data cycles on the bus, without issuing new
+ *     CMD + ADDR cycles. The Marvell term is "naked" operations.
+ *   - The ECC strength in BCH mode cannot be tuned. It is fixed 16
+ *     bits. What can be tuned is the ECC block size as long as it
+ *     stays between 512B and 2kiB. It's usually chosen based on the
+ *     chip ECC requirements. For instance, using 2kiB ECC chunks
+ *     provides 4b/512B correctability.
+ *   - The controller will always treat data bytes, free OOB bytes
+ *     and ECC bytes in that order, no matter what the real layout is
+ *     (which is usually all data then all OOB bytes). The
+ *     marvell_nfc_layouts array below contains the currently
+ *     supported layouts.
+ *   - Because of these weird layouts, the Bad Block Markers can be
+ *     located in data section. In this case, the NAND_BBT_NO_OOB_BBM
+ *     option must be set to prevent scanning/writing bad block
+ *     markers.
  */
 
 #include <linux/module.h>
@@ -217,8 +284,11 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
        MARVELL_LAYOUT(  512,   512,  1,  1,  1,  512,  8,  8,  0,  0,  0),
        MARVELL_LAYOUT( 2048,   512,  1,  1,  1, 2048, 40, 24,  0,  0,  0),
        MARVELL_LAYOUT( 2048,   512,  4,  1,  1, 2048, 32, 30,  0,  0,  0),
+       MARVELL_LAYOUT( 2048,   512,  8,  2,  1, 1024,  0, 30,1024,32, 30),
        MARVELL_LAYOUT( 4096,   512,  4,  2,  2, 2048, 32, 30,  0,  0,  0),
        MARVELL_LAYOUT( 4096,   512,  8,  5,  4, 1024,  0, 30,  0, 64, 30),
+       MARVELL_LAYOUT( 8192,   512,  4,  4,  4, 2048,  0, 30,  0,  0,  0),
+       MARVELL_LAYOUT( 8192,   512,  8,  9,  8, 1024,  0, 30,  0, 160, 30),
 };
 
 /**
@@ -634,9 +704,8 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
        return 0;
 }
 
-static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
+static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
        struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
        u32 ndcr_generic;
@@ -686,7 +755,7 @@ static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
 
        marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
 
-       if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
+       if (st & (NDSR_RDY(0) | NDSR_RDY(1)))
                complete(&nfc->complete);
 
        return IRQ_HANDLED;
@@ -959,18 +1028,15 @@ static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip,
        return ret;
 }
 
-static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
-                                               struct nand_chip *chip, u8 *buf,
+static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf,
                                                int oob_required, int page)
 {
        return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
                                                   true, page);
 }
 
-static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
-                                           struct nand_chip *chip,
-                                           u8 *buf, int oob_required,
-                                           int page)
+static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf,
+                                           int oob_required, int page)
 {
        const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
        unsigned int full_sz = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
@@ -1008,8 +1074,7 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
  * it appears before the ECC bytes when reading), the ->read_oob_raw() function
  * also stands for ->read_oob().
  */
-static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct mtd_info *mtd,
-                                              struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page)
 {
        /* Invalidate page cache */
        chip->pagebuf = -1;
@@ -1073,8 +1138,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
        return ret;
 }
 
-static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
-                                                struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
                                                 const u8 *buf,
                                                 int oob_required, int page)
 {
@@ -1082,8 +1146,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
                                                    true, page);
 }
 
-static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
-                                            struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip,
                                             const u8 *buf,
                                             int oob_required, int page)
 {
@@ -1102,10 +1165,11 @@ static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
  * it appears before the ECC bytes when reading), the ->write_oob_raw() function
  * also stands for ->write_oob().
  */
-static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
-                                               struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip,
                                                int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        /* Invalidate page cache */
        chip->pagebuf = -1;
 
@@ -1116,10 +1180,10 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
 }
 
 /* BCH read helpers */
-static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
-                                               struct nand_chip *chip, u8 *buf,
+static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf,
                                                int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
        u8 *oob = chip->oob_poi;
        int chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
@@ -1228,17 +1292,17 @@ static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
        }
 }
 
-static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
-                                           struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip,
                                            u8 *buf, int oob_required,
                                            int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
-       int data_len = lt->data_bytes, spare_len = lt->spare_bytes, ecc_len;
-       u8 *data = buf, *spare = chip->oob_poi, *ecc;
+       int data_len = lt->data_bytes, spare_len = lt->spare_bytes;
+       u8 *data = buf, *spare = chip->oob_poi;
        int max_bitflips = 0;
        u32 failure_mask = 0;
-       int chunk, ecc_offset_in_page, ret;
+       int chunk, ret;
 
        /*
         * With BCH, OOB is not fully used (and thus not read entirely), not
@@ -1279,73 +1343,98 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
         * the controller in normal mode and must be re-read in raw mode. To
         * avoid dropping the performances, we prefer not to include them. The
         * user should re-read the page in raw mode if ECC bytes are required.
+        */
+
+       /*
+        * In case there is any subpage read error reported by ->correct(), we
+        * usually re-read only ECC bytes in raw mode and check if the whole
+        * page is empty. In this case, it is normal that the ECC check failed
+        * and we just ignore the error.
         *
-        * However, for any subpage read error reported by ->correct(), the ECC
-        * bytes must be read in raw mode and the full subpage must be checked
-        * to see if it is entirely empty of if there was an actual error.
+        * However, it has been empirically observed that for some layouts (e.g
+        * 2k page, 8b strength per 512B chunk), the controller tries to correct
+        * bits and may create itself bitflips in the erased area. To overcome
+        * this strange behavior, the whole page is re-read in raw mode, not
+        * only the ECC bytes.
         */
        for (chunk = 0; chunk < lt->nchunks; chunk++) {
+               int data_off_in_page, spare_off_in_page, ecc_off_in_page;
+               int data_off, spare_off, ecc_off;
+               int data_len, spare_len, ecc_len;
+
                /* No failure reported for this chunk, move to the next one */
                if (!(failure_mask & BIT(chunk)))
                        continue;
 
-               /* Derive ECC bytes positions (in page/buffer) and length */
-               ecc = chip->oob_poi +
-                       (lt->full_chunk_cnt * lt->spare_bytes) +
-                       lt->last_spare_bytes +
-                       (chunk * ALIGN(lt->ecc_bytes, 32));
-               ecc_offset_in_page =
-                       (chunk * (lt->data_bytes + lt->spare_bytes +
-                                 lt->ecc_bytes)) +
-                       (chunk < lt->full_chunk_cnt ?
-                        lt->data_bytes + lt->spare_bytes :
-                        lt->last_data_bytes + lt->last_spare_bytes);
-               ecc_len = chunk < lt->full_chunk_cnt ?
-                       lt->ecc_bytes : lt->last_ecc_bytes;
-
-               /* Do the actual raw read of the ECC bytes */
-               nand_change_read_column_op(chip, ecc_offset_in_page,
-                                          ecc, ecc_len, false);
-
-               /* Derive data/spare bytes positions (in buffer) and length */
-               data = buf + (chunk * lt->data_bytes);
-               data_len = chunk < lt->full_chunk_cnt ?
-                       lt->data_bytes : lt->last_data_bytes;
-               spare = chip->oob_poi + (chunk * (lt->spare_bytes +
-                                                 lt->ecc_bytes));
-               spare_len = chunk < lt->full_chunk_cnt ?
-                       lt->spare_bytes : lt->last_spare_bytes;
+               data_off_in_page = chunk * (lt->data_bytes + lt->spare_bytes +
+                                           lt->ecc_bytes);
+               spare_off_in_page = data_off_in_page +
+                       (chunk < lt->full_chunk_cnt ? lt->data_bytes :
+                                                     lt->last_data_bytes);
+               ecc_off_in_page = spare_off_in_page +
+                       (chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+                                                     lt->last_spare_bytes);
+
+               data_off = chunk * lt->data_bytes;
+               spare_off = chunk * lt->spare_bytes;
+               ecc_off = (lt->full_chunk_cnt * lt->spare_bytes) +
+                         lt->last_spare_bytes +
+                         (chunk * (lt->ecc_bytes + 2));
+
+               data_len = chunk < lt->full_chunk_cnt ? lt->data_bytes :
+                                                       lt->last_data_bytes;
+               spare_len = chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+                                                        lt->last_spare_bytes;
+               ecc_len = chunk < lt->full_chunk_cnt ? lt->ecc_bytes :
+                                                      lt->last_ecc_bytes;
+
+               /*
+                * Only re-read the ECC bytes, unless we are using the 2k/8b
+                * layout which is buggy in the sense that the ECC engine will
+                * try to correct data bytes anyway, creating bitflips. In this
+                * case, re-read the entire page.
+                */
+               if (lt->writesize == 2048 && lt->strength == 8) {
+                       nand_change_read_column_op(chip, data_off_in_page,
+                                                  buf + data_off, data_len,
+                                                  false);
+                       nand_change_read_column_op(chip, spare_off_in_page,
+                                                  chip->oob_poi + spare_off, spare_len,
+                                                  false);
+               }
+
+               nand_change_read_column_op(chip, ecc_off_in_page,
+                                          chip->oob_poi + ecc_off, ecc_len,
+                                          false);
 
                /* Check the entire chunk (data + spare + ecc) for emptyness */
-               marvell_nfc_check_empty_chunk(chip, data, data_len, spare,
-                                             spare_len, ecc, ecc_len,
+               marvell_nfc_check_empty_chunk(chip, buf + data_off, data_len,
+                                             chip->oob_poi + spare_off, spare_len,
+                                             chip->oob_poi + ecc_off, ecc_len,
                                              &max_bitflips);
        }
 
        return max_bitflips;
 }
 
-static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
-                                              struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page)
 {
        /* Invalidate page cache */
        chip->pagebuf = -1;
 
-       return chip->ecc.read_page_raw(mtd, chip, chip->data_buf, true, page);
+       return chip->ecc.read_page_raw(chip, chip->data_buf, true, page);
 }
 
-static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
-                                          struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page)
 {
        /* Invalidate page cache */
        chip->pagebuf = -1;
 
-       return chip->ecc.read_page(mtd, chip, chip->data_buf, true, page);
+       return chip->ecc.read_page(chip, chip->data_buf, true, page);
 }
 
 /* BCH write helpers */
-static int marvell_nfc_hw_ecc_bch_write_page_raw(struct mtd_info *mtd,
-                                                struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip,
                                                 const u8 *buf,
                                                 int oob_required, int page)
 {
@@ -1458,11 +1547,11 @@ marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
        return 0;
 }
 
-static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
-                                            struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
                                             const u8 *buf,
                                             int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
        const u8 *data = buf;
        const u8 *spare = chip->oob_poi;
@@ -1507,27 +1596,29 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
        return 0;
 }
 
-static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
-                                               struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip,
                                                int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        /* Invalidate page cache */
        chip->pagebuf = -1;
 
        memset(chip->data_buf, 0xFF, mtd->writesize);
 
-       return chip->ecc.write_page_raw(mtd, chip, chip->data_buf, true, page);
+       return chip->ecc.write_page_raw(chip, chip->data_buf, true, page);
 }
 
-static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
-                                           struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        /* Invalidate page cache */
        chip->pagebuf = -1;
 
        memset(chip->data_buf, 0xFF, mtd->writesize);
 
-       return chip->ecc.write_page(mtd, chip, chip->data_buf, true, page);
+       return chip->ecc.write_page(chip, chip->data_buf, true, page);
 }
 
 /* NAND framework ->exec_op() hooks and related helpers */
@@ -2097,6 +2188,16 @@ static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
                return -ENOTSUPP;
        }
 
+       /* Special care for the layout 2k/8-bit/512B  */
+       if (l->writesize == 2048 && l->strength == 8) {
+               if (mtd->oobsize < 128) {
+                       dev_err(nfc->dev, "Requested layout needs at least 128 OOB bytes\n");
+                       return -ENOTSUPP;
+               } else {
+                       chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+               }
+       }
+
        mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
        ecc->steps = l->nchunks;
        ecc->size = l->data_bytes;
@@ -2192,11 +2293,10 @@ static struct nand_bbt_descr bbt_mirror_descr = {
        .pattern = bbt_mirror_pattern
 };
 
-static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
+static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
                                            const struct nand_data_interface
                                            *conf)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
        struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
        unsigned int period_ns = 1000000000 / clk_get_rate(nfc->core_clk) * 2;
@@ -2540,7 +2640,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
 
        chip->options |= NAND_BUSWIDTH_AUTO;
 
-       ret = nand_scan(mtd, marvell_nand->nsels);
+       ret = nand_scan(chip, marvell_nand->nsels);
        if (ret) {
                dev_err(dev, "could not scan the nand chip\n");
                return ret;
@@ -2553,7 +2653,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
                ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
                dev_err(dev, "failed to register mtd device: %d\n", ret);
-               nand_release(mtd);
+               nand_release(chip);
                return ret;
        }
 
@@ -2608,7 +2708,7 @@ static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
        struct marvell_nand_chip *entry, *temp;
 
        list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
-               nand_release(nand_to_mtd(&entry->chip));
+               nand_release(&entry->chip);
                list_del(&entry->node);
        }
 }
@@ -2699,24 +2799,23 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
                struct regmap *sysctrl_base =
                        syscon_regmap_lookup_by_phandle(np,
                                                        "marvell,system-controller");
-               u32 reg;
 
                if (IS_ERR(sysctrl_base))
                        return PTR_ERR(sysctrl_base);
 
-               reg = GENCONF_SOC_DEVICE_MUX_NFC_EN |
-                     GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
-                     GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
-                     GENCONF_SOC_DEVICE_MUX_NFC_INT_EN;
-               regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
+               regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX,
+                            GENCONF_SOC_DEVICE_MUX_NFC_EN |
+                            GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
+                            GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
+                            GENCONF_SOC_DEVICE_MUX_NFC_INT_EN);
 
-               regmap_read(sysctrl_base, GENCONF_CLK_GATING_CTRL, &reg);
-               reg |= GENCONF_CLK_GATING_CTRL_ND_GATE;
-               regmap_write(sysctrl_base, GENCONF_CLK_GATING_CTRL, reg);
+               regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
+                                  GENCONF_CLK_GATING_CTRL_ND_GATE,
+                                  GENCONF_CLK_GATING_CTRL_ND_GATE);
 
-               regmap_read(sysctrl_base, GENCONF_ND_CLK_CTRL, &reg);
-               reg |= GENCONF_ND_CLK_CTRL_EN;
-               regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
+               regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL,
+                                  GENCONF_ND_CLK_CTRL_EN,
+                                  GENCONF_ND_CLK_CTRL_EN);
        }
 
        /* Configure the DMA if appropriate */
index 6d1740d54e0de7e9794de892ed1afb61120bddab..86a0aabe08df941bd6931a40d1f72918ec6fa3e6 100644 (file)
@@ -263,8 +263,10 @@ static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
 }
 
 /* Control chip select signals */
-static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void mpc5121_nfc_select_chip(struct nand_chip *nand, int chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(nand);
+
        if (chip < 0) {
                nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
                return;
@@ -299,9 +301,9 @@ static int ads5121_chipselect_init(struct mtd_info *mtd)
 }
 
 /* Control chips select signal on ADS5121 board */
-static void ads5121_select_chip(struct mtd_info *mtd, int chip)
+static void ads5121_select_chip(struct nand_chip *nand, int chip)
 {
-       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(nand);
        struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
        u8 v;
 
@@ -309,16 +311,16 @@ static void ads5121_select_chip(struct mtd_info *mtd, int chip)
        v |= 0x0F;
 
        if (chip >= 0) {
-               mpc5121_nfc_select_chip(mtd, 0);
+               mpc5121_nfc_select_chip(nand, 0);
                v &= ~(1 << chip);
        } else
-               mpc5121_nfc_select_chip(mtd, -1);
+               mpc5121_nfc_select_chip(nand, -1);
 
        out_8(prv->csreg, v);
 }
 
 /* Read NAND Ready/Busy signal */
-static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
+static int mpc5121_nfc_dev_ready(struct nand_chip *nand)
 {
        /*
         * NFC handles ready/busy signal internally. Therefore, this function
@@ -328,10 +330,10 @@ static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
 }
 
 /* Write command to NAND flash */
-static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
-                                                       int column, int page)
+static void mpc5121_nfc_command(struct nand_chip *chip, unsigned command,
+                               int column, int page)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
 
        prv->column = (column >= 0) ? column : 0;
@@ -362,7 +364,7 @@ static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
                break;
 
        case NAND_CMD_SEQIN:
-               mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
+               mpc5121_nfc_command(chip, NAND_CMD_READ0, column, page);
                column = 0;
                break;
 
@@ -493,34 +495,24 @@ static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
 }
 
 /* Read data from NFC buffers */
-static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void mpc5121_nfc_read_buf(struct nand_chip *chip, u_char *buf, int len)
 {
-       mpc5121_nfc_buf_copy(mtd, buf, len, 0);
+       mpc5121_nfc_buf_copy(nand_to_mtd(chip), buf, len, 0);
 }
 
 /* Write data to NFC buffers */
-static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
-                                               const u_char *buf, int len)
+static void mpc5121_nfc_write_buf(struct nand_chip *chip, const u_char *buf,
+                                 int len)
 {
-       mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
+       mpc5121_nfc_buf_copy(nand_to_mtd(chip), (u_char *)buf, len, 1);
 }
 
 /* Read byte from NFC buffers */
-static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
+static u8 mpc5121_nfc_read_byte(struct nand_chip *chip)
 {
        u8 tmp;
 
-       mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
-
-       return tmp;
-}
-
-/* Read word from NFC buffers */
-static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
-{
-       u16 tmp;
-
-       mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+       mpc5121_nfc_read_buf(chip, &tmp, sizeof(tmp));
 
        return tmp;
 }
@@ -700,15 +692,14 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        }
 
        mtd->name = "MPC5121 NAND";
-       chip->dev_ready = mpc5121_nfc_dev_ready;
-       chip->cmdfunc = mpc5121_nfc_command;
-       chip->read_byte = mpc5121_nfc_read_byte;
-       chip->read_word = mpc5121_nfc_read_word;
-       chip->read_buf = mpc5121_nfc_read_buf;
-       chip->write_buf = mpc5121_nfc_write_buf;
+       chip->legacy.dev_ready = mpc5121_nfc_dev_ready;
+       chip->legacy.cmdfunc = mpc5121_nfc_command;
+       chip->legacy.read_byte = mpc5121_nfc_read_byte;
+       chip->legacy.read_buf = mpc5121_nfc_read_buf;
+       chip->legacy.write_buf = mpc5121_nfc_write_buf;
        chip->select_chip = mpc5121_nfc_select_chip;
-       chip->set_features      = nand_get_set_features_notsupp;
-       chip->get_features      = nand_get_set_features_notsupp;
+       chip->legacy.set_features = nand_get_set_features_notsupp;
+       chip->legacy.get_features = nand_get_set_features_notsupp;
        chip->bbt_options = NAND_BBT_USE_FLASH;
        chip->ecc.mode = NAND_ECC_SOFT;
        chip->ecc.algo = NAND_ECC_HAMMING;
@@ -778,7 +769,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        }
 
        /* Detect NAND chips */
-       retval = nand_scan(mtd, be32_to_cpup(chips_no));
+       retval = nand_scan(chip, be32_to_cpup(chips_no));
        if (retval) {
                dev_err(dev, "NAND Flash not found !\n");
                goto error;
@@ -828,7 +819,7 @@ static int mpc5121_nfc_remove(struct platform_device *op)
        struct device *dev = &op->dev;
        struct mtd_info *mtd = dev_get_drvdata(dev);
 
-       nand_release(mtd);
+       nand_release(mtd_to_nand(mtd));
        mpc5121_nfc_free(dev, mtd);
 
        return 0;
index 57b5ed1699e386e51865ba77c61c6561ffc1775f..2bb0df1b7244795658e2620ace4c6bc4b45d4359 100644 (file)
@@ -389,23 +389,22 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
        return 0;
 }
 
-static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void mtk_nfc_select_chip(struct nand_chip *nand, int chip)
 {
-       struct nand_chip *nand = mtd_to_nand(mtd);
        struct mtk_nfc *nfc = nand_get_controller_data(nand);
        struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
 
        if (chip < 0)
                return;
 
-       mtk_nfc_hw_runtime_config(mtd);
+       mtk_nfc_hw_runtime_config(nand_to_mtd(nand));
 
        nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
 }
 
-static int mtk_nfc_dev_ready(struct mtd_info *mtd)
+static int mtk_nfc_dev_ready(struct nand_chip *nand)
 {
-       struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+       struct mtk_nfc *nfc = nand_get_controller_data(nand);
 
        if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
                return 0;
@@ -413,9 +412,10 @@ static int mtk_nfc_dev_ready(struct mtd_info *mtd)
        return 1;
 }
 
-static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void mtk_nfc_cmd_ctrl(struct nand_chip *chip, int dat,
+                            unsigned int ctrl)
 {
-       struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
 
        if (ctrl & NAND_ALE) {
                mtk_nfc_send_address(nfc, dat);
@@ -438,9 +438,8 @@ static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
                dev_err(nfc->dev, "data not ready\n");
 }
 
-static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
+static inline u8 mtk_nfc_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct mtk_nfc *nfc = nand_get_controller_data(chip);
        u32 reg;
 
@@ -467,17 +466,17 @@ static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
        return nfi_readb(nfc, NFI_DATAR);
 }
 
-static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void mtk_nfc_read_buf(struct nand_chip *chip, u8 *buf, int len)
 {
        int i;
 
        for (i = 0; i < len; i++)
-               buf[i] = mtk_nfc_read_byte(mtd);
+               buf[i] = mtk_nfc_read_byte(chip);
 }
 
-static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
+static void mtk_nfc_write_byte(struct nand_chip *chip, u8 byte)
 {
-       struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
        u32 reg;
 
        reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
@@ -496,18 +495,18 @@ static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
        nfi_writeb(nfc, byte, NFI_DATAW);
 }
 
-static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
 {
        int i;
 
        for (i = 0; i < len; i++)
-               mtk_nfc_write_byte(mtd, buf[i]);
+               mtk_nfc_write_byte(chip, buf[i]);
 }
 
-static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
                                        const struct nand_data_interface *conf)
 {
-       struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
        const struct nand_sdr_timings *timings;
        u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
 
@@ -807,27 +806,27 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        return nand_prog_page_end_op(chip);
 }
 
-static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
-                                   struct nand_chip *chip, const u8 *buf,
+static int mtk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
                                    int oob_on, int page)
 {
-       return mtk_nfc_write_page(mtd, chip, buf, page, 0);
+       return mtk_nfc_write_page(nand_to_mtd(chip), chip, buf, page, 0);
 }
 
-static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                 const u8 *buf, int oob_on, int pg)
+static int mtk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
+                                 int oob_on, int pg)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct mtk_nfc *nfc = nand_get_controller_data(chip);
 
        mtk_nfc_format_page(mtd, buf);
        return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
 }
 
-static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
-                                      struct nand_chip *chip, u32 offset,
+static int mtk_nfc_write_subpage_hwecc(struct nand_chip *chip, u32 offset,
                                       u32 data_len, const u8 *buf,
                                       int oob_on, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct mtk_nfc *nfc = nand_get_controller_data(chip);
        int ret;
 
@@ -839,10 +838,9 @@ static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
        return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
 }
 
-static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
-                                int page)
+static int mtk_nfc_write_oob_std(struct nand_chip *chip, int page)
 {
-       return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
+       return mtk_nfc_write_page_raw(chip, NULL, 1, page);
 }
 
 static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
@@ -969,23 +967,25 @@ done:
        return bitflips;
 }
 
-static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
-                                     struct nand_chip *chip, u32 off,
+static int mtk_nfc_read_subpage_hwecc(struct nand_chip *chip, u32 off,
                                      u32 len, u8 *p, int pg)
 {
-       return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
+       return mtk_nfc_read_subpage(nand_to_mtd(chip), chip, off, len, p, pg,
+                                   0);
 }
 
-static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
-                                  struct nand_chip *chip, u8 *p,
-                                  int oob_on, int pg)
+static int mtk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *p, int oob_on,
+                                  int pg)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
 }
 
-static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                u8 *buf, int oob_on, int page)
+static int mtk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on,
+                                int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
        struct mtk_nfc *nfc = nand_get_controller_data(chip);
        struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
@@ -1011,10 +1011,9 @@ static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
        return ret;
 }
 
-static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
-                               int page)
+static int mtk_nfc_read_oob_std(struct nand_chip *chip, int page)
 {
-       return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
+       return mtk_nfc_read_page_raw(chip, NULL, 1, page);
 }
 
 static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
@@ -1333,13 +1332,13 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
        nand_set_controller_data(nand, nfc);
 
        nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
-       nand->dev_ready = mtk_nfc_dev_ready;
+       nand->legacy.dev_ready = mtk_nfc_dev_ready;
        nand->select_chip = mtk_nfc_select_chip;
-       nand->write_byte = mtk_nfc_write_byte;
-       nand->write_buf = mtk_nfc_write_buf;
-       nand->read_byte = mtk_nfc_read_byte;
-       nand->read_buf = mtk_nfc_read_buf;
-       nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
+       nand->legacy.write_byte = mtk_nfc_write_byte;
+       nand->legacy.write_buf = mtk_nfc_write_buf;
+       nand->legacy.read_byte = mtk_nfc_read_byte;
+       nand->legacy.read_buf = mtk_nfc_read_buf;
+       nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl;
        nand->setup_data_interface = mtk_nfc_setup_data_interface;
 
        /* set default mode in case dt entry is missing */
@@ -1365,14 +1364,14 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
 
        mtk_nfc_hw_init(nfc);
 
-       ret = nand_scan(mtd, nsels);
+       ret = nand_scan(nand, nsels);
        if (ret)
                return ret;
 
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
                dev_err(dev, "mtd parse partition error\n");
-               nand_release(mtd);
+               nand_release(nand);
                return ret;
        }
 
@@ -1538,7 +1537,7 @@ static int mtk_nfc_remove(struct platform_device *pdev)
        while (!list_empty(&nfc->chips)) {
                chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
                                        node);
-               nand_release(nand_to_mtd(&chip->nand));
+               nand_release(&chip->nand);
                list_del(&chip->node);
        }
 
index 4c9214dea4240b7057df964034ea59d5bca892ac..88bd3f6a499c02a213ba84341084ae11ffd23a67 100644 (file)
@@ -136,8 +136,8 @@ struct mxc_nand_devtype_data {
        void (*irq_control)(struct mxc_nand_host *, int);
        u32 (*get_ecc_status)(struct mxc_nand_host *);
        const struct mtd_ooblayout_ops *ooblayout;
-       void (*select_chip)(struct mtd_info *mtd, int chip);
-       int (*setup_data_interface)(struct mtd_info *mtd, int csline,
+       void (*select_chip)(struct nand_chip *chip, int cs);
+       int (*setup_data_interface)(struct nand_chip *chip, int csline,
                                    const struct nand_data_interface *conf);
        void (*enable_hwecc)(struct nand_chip *chip, bool enable);
 
@@ -701,7 +701,7 @@ static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable)
 }
 
 /* This functions is used by upper layer to checks if device is ready */
-static int mxc_nand_dev_ready(struct mtd_info *mtd)
+static int mxc_nand_dev_ready(struct nand_chip *chip)
 {
        /*
         * NFC handles R/B internally. Therefore, this function
@@ -816,8 +816,8 @@ static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf,
        return max_bitflips;
 }
 
-static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                             uint8_t *buf, int oob_required, int page)
+static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf,
+                             int oob_required, int page)
 {
        struct mxc_nand_host *host = nand_get_controller_data(chip);
        void *oob_buf;
@@ -830,8 +830,8 @@ static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        return host->devtype_data->read_page(chip, buf, oob_buf, 1, page);
 }
 
-static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                 uint8_t *buf, int oob_required, int page)
+static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+                                 int oob_required, int page)
 {
        struct mxc_nand_host *host = nand_get_controller_data(chip);
        void *oob_buf;
@@ -844,8 +844,7 @@ static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
        return host->devtype_data->read_page(chip, buf, oob_buf, 0, page);
 }
 
-static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                            int page)
+static int mxc_nand_read_oob(struct nand_chip *chip, int page)
 {
        struct mxc_nand_host *host = nand_get_controller_data(chip);
 
@@ -874,22 +873,21 @@ static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf,
        return 0;
 }
 
-static int mxc_nand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                  const uint8_t *buf, int oob_required,
-                                  int page)
+static int mxc_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf,
+                                  int oob_required, int page)
 {
        return mxc_nand_write_page(chip, buf, true, page);
 }
 
-static int mxc_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                                  const uint8_t *buf, int oob_required, int page)
+static int mxc_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+                                  int oob_required, int page)
 {
        return mxc_nand_write_page(chip, buf, false, page);
 }
 
-static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                             int page)
+static int mxc_nand_write_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct mxc_nand_host *host = nand_get_controller_data(chip);
 
        memset(host->data_buf, 0xff, mtd->writesize);
@@ -897,9 +895,8 @@ static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
        return mxc_nand_write_page(chip, host->data_buf, false, page);
 }
 
-static u_char mxc_nand_read_byte(struct mtd_info *mtd)
+static u_char mxc_nand_read_byte(struct nand_chip *nand_chip)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
        uint8_t ret;
 
@@ -921,25 +918,13 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
        return ret;
 }
 
-static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
-{
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
-       struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
-       uint16_t ret;
-
-       ret = *(uint16_t *)(host->data_buf + host->buf_start);
-       host->buf_start += 2;
-
-       return ret;
-}
-
 /* Write data of length len to buffer buf. The data to be
  * written on NAND Flash is first copied to RAMbuffer. After the Data Input
  * Operation by the NFC, the data is written to NAND Flash */
-static void mxc_nand_write_buf(struct mtd_info *mtd,
-                               const u_char *buf, int len)
+static void mxc_nand_write_buf(struct nand_chip *nand_chip, const u_char *buf,
+                              int len)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(nand_chip);
        struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
        u16 col = host->buf_start;
        int n = mtd->oobsize + mtd->writesize - col;
@@ -955,9 +940,10 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
  * Flash first the data output cycle is initiated by the NFC, which copies
  * the data to RAMbuffer. This data of length len is then copied to buffer buf.
  */
-static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void mxc_nand_read_buf(struct nand_chip *nand_chip, u_char *buf,
+                             int len)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(nand_chip);
        struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
        u16 col = host->buf_start;
        int n = mtd->oobsize + mtd->writesize - col;
@@ -971,9 +957,8 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 
 /* This function is used by upper layer for select and
  * deselect of the NAND chip */
-static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
+static void mxc_nand_select_chip_v1_v3(struct nand_chip *nand_chip, int chip)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 
        if (chip == -1) {
@@ -992,9 +977,8 @@ static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
        }
 }
 
-static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
+static void mxc_nand_select_chip_v2(struct nand_chip *nand_chip, int chip)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 
        if (chip == -1) {
@@ -1155,11 +1139,10 @@ static void preset_v1(struct mtd_info *mtd)
        writew(0x4, NFC_V1_V2_WRPROT);
 }
 
-static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
+static int mxc_nand_v2_setup_data_interface(struct nand_chip *chip, int csline,
                                        const struct nand_data_interface *conf)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
-       struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+       struct mxc_nand_host *host = nand_get_controller_data(chip);
        int tRC_min_ns, tRC_ps, ret;
        unsigned long rate, rate_round;
        const struct nand_sdr_timings *timings;
@@ -1349,10 +1332,10 @@ static void preset_v3(struct mtd_info *mtd)
 
 /* Used by the upper layer to write command to NAND Flash for
  * different operations to be carried out on NAND Flash */
-static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
-                               int column, int page_addr)
+static void mxc_nand_command(struct nand_chip *nand_chip, unsigned command,
+                            int column, int page_addr)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(nand_chip);
        struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
 
        dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
@@ -1409,17 +1392,17 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
        }
 }
 
-static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip,
-                                int addr, u8 *subfeature_param)
+static int mxc_nand_set_features(struct nand_chip *chip, int addr,
+                                u8 *subfeature_param)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
-       struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct mxc_nand_host *host = nand_get_controller_data(chip);
        int i;
 
        host->buf_start = 0;
 
        for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-               chip->write_byte(mtd, subfeature_param[i]);
+               chip->legacy.write_byte(chip, subfeature_param[i]);
 
        memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
        host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
@@ -1429,11 +1412,11 @@ static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip,
        return 0;
 }
 
-static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip,
-                                int addr, u8 *subfeature_param)
+static int mxc_nand_get_features(struct nand_chip *chip, int addr,
+                                u8 *subfeature_param)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
-       struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct mxc_nand_host *host = nand_get_controller_data(chip);
        int i;
 
        host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
@@ -1443,7 +1426,7 @@ static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip,
        host->buf_start = 0;
 
        for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-               *subfeature_param++ = chip->read_byte(mtd);
+               *subfeature_param++ = chip->legacy.read_byte(chip);
 
        return 0;
 }
@@ -1786,18 +1769,17 @@ static int mxcnd_probe(struct platform_device *pdev)
        mtd->name = DRIVER_NAME;
 
        /* 50 us command delay time */
-       this->chip_delay = 5;
+       this->legacy.chip_delay = 5;
 
        nand_set_controller_data(this, host);
        nand_set_flash_node(this, pdev->dev.of_node),
-       this->dev_ready = mxc_nand_dev_ready;
-       this->cmdfunc = mxc_nand_command;
-       this->read_byte = mxc_nand_read_byte;
-       this->read_word = mxc_nand_read_word;
-       this->write_buf = mxc_nand_write_buf;
-       this->read_buf = mxc_nand_read_buf;
-       this->set_features = mxc_nand_set_features;
-       this->get_features = mxc_nand_get_features;
+       this->legacy.dev_ready = mxc_nand_dev_ready;
+       this->legacy.cmdfunc = mxc_nand_command;
+       this->legacy.read_byte = mxc_nand_read_byte;
+       this->legacy.write_buf = mxc_nand_write_buf;
+       this->legacy.read_buf = mxc_nand_read_buf;
+       this->legacy.set_features = mxc_nand_set_features;
+       this->legacy.get_features = mxc_nand_get_features;
 
        host->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk))
@@ -1900,7 +1882,7 @@ static int mxcnd_probe(struct platform_device *pdev)
 
        /* Scan the NAND device */
        this->dummy_controller.ops = &mxcnd_controller_ops;
-       err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1);
+       err = nand_scan(this, is_imx25_nfc(host) ? 4 : 1);
        if (err)
                goto escan;
 
@@ -1928,7 +1910,7 @@ static int mxcnd_remove(struct platform_device *pdev)
 {
        struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
-       nand_release(nand_to_mtd(&host->nand));
+       nand_release(&host->nand);
        if (host->clk_act)
                clk_disable_unprepare(host->clk);
 
index 22f060f38123b62a60f2557897d3dbf5d313bdd1..890c5b43e03c53e3019151acba6f1d568466d92e 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
 
 static void amd_nand_decode_id(struct nand_chip *chip)
 {
index d527e448ce19844e89b35b221b4405dac7a8567d..05bd0779fe9bf7eae08acca31b7ba30f7592b9b1 100644 (file)
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/nmi.h>
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/nand_bch.h>
 #include <linux/interrupt.h>
@@ -48,6 +46,8 @@
 #include <linux/mtd/partitions.h>
 #include <linux/of.h>
 
+#include "internals.h"
+
 static int nand_get_device(struct mtd_info *mtd, int new_state);
 
 static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
@@ -252,184 +252,17 @@ static void nand_release_device(struct mtd_info *mtd)
        spin_unlock(&chip->controller->lock);
 }
 
-/**
- * nand_read_byte - [DEFAULT] read one byte from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 8bit buswidth
- */
-static uint8_t nand_read_byte(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       return readb(chip->IO_ADDR_R);
-}
-
-/**
- * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 16bit buswidth with endianness conversion.
- *
- */
-static uint8_t nand_read_byte16(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
-}
-
-/**
- * nand_read_word - [DEFAULT] read one word from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 16bit buswidth without endianness conversion.
- */
-static u16 nand_read_word(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       return readw(chip->IO_ADDR_R);
-}
-
-/**
- * nand_select_chip - [DEFAULT] control CE line
- * @mtd: MTD device structure
- * @chipnr: chipnumber to select, -1 for deselect
- *
- * Default select function for 1 chip devices.
- */
-static void nand_select_chip(struct mtd_info *mtd, int chipnr)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
-       switch (chipnr) {
-       case -1:
-               chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
-               break;
-       case 0:
-               break;
-
-       default:
-               BUG();
-       }
-}
-
-/**
- * nand_write_byte - [DEFAULT] write single byte to chip
- * @mtd: MTD device structure
- * @byte: value to write
- *
- * Default function to write a byte to I/O[7:0]
- */
-static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
-       chip->write_buf(mtd, &byte, 1);
-}
-
-/**
- * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
- * @mtd: MTD device structure
- * @byte: value to write
- *
- * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
- */
-static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       uint16_t word = byte;
-
-       /*
-        * It's not entirely clear what should happen to I/O[15:8] when writing
-        * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
-        *
-        *    When the host supports a 16-bit bus width, only data is
-        *    transferred at the 16-bit width. All address and command line
-        *    transfers shall use only the lower 8-bits of the data bus. During
-        *    command transfers, the host may place any value on the upper
-        *    8-bits of the data bus. During address transfers, the host shall
-        *    set the upper 8-bits of the data bus to 00h.
-        *
-        * One user of the write_byte callback is nand_set_features. The
-        * four parameters are specified to be written to I/O[7:0], but this is
-        * neither an address nor a command transfer. Let's assume a 0 on the
-        * upper I/O lines is OK.
-        */
-       chip->write_buf(mtd, (uint8_t *)&word, 2);
-}
-
-/**
- * nand_write_buf - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 8bit buswidth.
- */
-static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
-       iowrite8_rep(chip->IO_ADDR_W, buf, len);
-}
-
-/**
- * nand_read_buf - [DEFAULT] read chip data into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- *
- * Default read function for 8bit buswidth.
- */
-static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
-       ioread8_rep(chip->IO_ADDR_R, buf, len);
-}
-
-/**
- * nand_write_buf16 - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 16bit buswidth.
- */
-static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       u16 *p = (u16 *) buf;
-
-       iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
-}
-
-/**
- * nand_read_buf16 - [DEFAULT] read chip data into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- *
- * Default read function for 16bit buswidth.
- */
-static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       u16 *p = (u16 *) buf;
-
-       ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
-}
-
 /**
  * nand_block_bad - [DEFAULT] Read bad block marker from the chip
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @ofs: offset from device start
  *
  * Check, if the block is bad.
  */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int page, page_end, res;
-       struct nand_chip *chip = mtd_to_nand(mtd);
        u8 bad;
 
        if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
@@ -439,7 +272,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
        page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
 
        for (; page < page_end; page++) {
-               res = chip->ecc.read_oob(mtd, chip, page);
+               res = chip->ecc.read_oob(chip, page);
                if (res < 0)
                        return res;
 
@@ -458,16 +291,16 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 
 /**
  * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @ofs: offset from device start
  *
  * This is the default implementation, which can be overridden by a hardware
  * specific driver. It provides the details for writing a bad block marker to a
  * block.
  */
-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct mtd_oob_ops ops;
        uint8_t buf[2] = { 0, 0 };
        int ret = 0, res, i = 0;
@@ -498,6 +331,27 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        return ret;
 }
 
+/**
+ * nand_markbad_bbm - mark a block by updating the BBM
+ * @chip: NAND chip object
+ * @ofs: offset of the block to mark bad
+ */
+int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs)
+{
+       if (chip->legacy.block_markbad)
+               return chip->legacy.block_markbad(chip, ofs);
+
+       return nand_default_block_markbad(chip, ofs);
+}
+
+static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
+{
+       if (chip->legacy.block_bad)
+               return chip->legacy.block_bad(chip, ofs);
+
+       return nand_block_bad(chip, ofs);
+}
+
 /**
  * nand_block_markbad_lowlevel - mark a block bad
  * @mtd: MTD device structure
@@ -505,7 +359,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
  *
  * This function performs the generic NAND bad block marking steps (i.e., bad
  * block table(s) and/or marker(s)). We only allow the hardware driver to
- * specify how to write bad block markers to OOB (chip->block_markbad).
+ * specify how to write bad block markers to OOB (chip->legacy.block_markbad).
  *
  * We try operations in the following order:
  *
@@ -529,17 +383,17 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
                memset(&einfo, 0, sizeof(einfo));
                einfo.addr = ofs;
                einfo.len = 1ULL << chip->phys_erase_shift;
-               nand_erase_nand(mtd, &einfo, 0);
+               nand_erase_nand(chip, &einfo, 0);
 
                /* Write bad block marker to OOB */
                nand_get_device(mtd, FL_WRITING);
-               ret = chip->block_markbad(mtd, ofs);
+               ret = nand_markbad_bbm(chip, ofs);
                nand_release_device(mtd);
        }
 
        /* Mark block bad in BBT */
        if (chip->bbt) {
-               res = nand_markbad_bbt(mtd, ofs);
+               res = nand_markbad_bbt(chip, ofs);
                if (!ret)
                        ret = res;
        }
@@ -589,7 +443,7 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
        if (!chip->bbt)
                return 0;
        /* Return info from the table */
-       return nand_isreserved_bbt(mtd, ofs);
+       return nand_isreserved_bbt(chip, ofs);
 }
 
 /**
@@ -605,88 +459,13 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
 
-       if (!chip->bbt)
-               return chip->block_bad(mtd, ofs);
-
        /* Return info from the table */
-       return nand_isbad_bbt(mtd, ofs, allowbbt);
-}
-
-/**
- * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
- * @mtd: MTD device structure
- * @timeo: Timeout
- *
- * Helper function for nand_wait_ready used when needing to wait in interrupt
- * context.
- */
-static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       int i;
+       if (chip->bbt)
+               return nand_isbad_bbt(chip, ofs, allowbbt);
 
-       /* Wait for the device to get ready */
-       for (i = 0; i < timeo; i++) {
-               if (chip->dev_ready(mtd))
-                       break;
-               touch_softlockup_watchdog();
-               mdelay(1);
-       }
+       return nand_isbad_bbm(chip, ofs);
 }
 
-/**
- * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
- * @mtd: MTD device structure
- *
- * Wait for the ready pin after a command, and warn if a timeout occurs.
- */
-void nand_wait_ready(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       unsigned long timeo = 400;
-
-       if (in_interrupt() || oops_in_progress)
-               return panic_nand_wait_ready(mtd, timeo);
-
-       /* Wait until command is processed or timeout occurs */
-       timeo = jiffies + msecs_to_jiffies(timeo);
-       do {
-               if (chip->dev_ready(mtd))
-                       return;
-               cond_resched();
-       } while (time_before(jiffies, timeo));
-
-       if (!chip->dev_ready(mtd))
-               pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
-}
-EXPORT_SYMBOL_GPL(nand_wait_ready);
-
-/**
- * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
- * @mtd: MTD device structure
- * @timeo: Timeout in ms
- *
- * Wait for status ready (i.e. command done) or timeout.
- */
-static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
-{
-       register struct nand_chip *chip = mtd_to_nand(mtd);
-       int ret;
-
-       timeo = jiffies + msecs_to_jiffies(timeo);
-       do {
-               u8 status;
-
-               ret = nand_read_data_op(chip, &status, sizeof(status), true);
-               if (ret)
-                       return;
-
-               if (status & NAND_STATUS_READY)
-                       break;
-               touch_softlockup_watchdog();
-       } while (time_before(jiffies, timeo));
-};
-
 /**
  * nand_soft_waitrdy - Poll STATUS reg until RDY bit is set to 1
  * @chip: NAND chip structure
@@ -752,273 +531,6 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
 };
 EXPORT_SYMBOL_GPL(nand_soft_waitrdy);
 
-/**
- * nand_command - [DEFAULT] Send command to NAND device
- * @mtd: MTD device structure
- * @command: the command to be sent
- * @column: the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
- *
- * Send command to NAND device. This function is used for small page devices
- * (512 Bytes per page).
- */
-static void nand_command(struct mtd_info *mtd, unsigned int command,
-                        int column, int page_addr)
-{
-       register struct nand_chip *chip = mtd_to_nand(mtd);
-       int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
-
-       /* Write out the command to the device */
-       if (command == NAND_CMD_SEQIN) {
-               int readcmd;
-
-               if (column >= mtd->writesize) {
-                       /* OOB area */
-                       column -= mtd->writesize;
-                       readcmd = NAND_CMD_READOOB;
-               } else if (column < 256) {
-                       /* First 256 bytes --> READ0 */
-                       readcmd = NAND_CMD_READ0;
-               } else {
-                       column -= 256;
-                       readcmd = NAND_CMD_READ1;
-               }
-               chip->cmd_ctrl(mtd, readcmd, ctrl);
-               ctrl &= ~NAND_CTRL_CHANGE;
-       }
-       if (command != NAND_CMD_NONE)
-               chip->cmd_ctrl(mtd, command, ctrl);
-
-       /* Address cycle, when necessary */
-       ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
-       /* Serially input address */
-       if (column != -1) {
-               /* Adjust columns for 16 bit buswidth */
-               if (chip->options & NAND_BUSWIDTH_16 &&
-                               !nand_opcode_8bits(command))
-                       column >>= 1;
-               chip->cmd_ctrl(mtd, column, ctrl);
-               ctrl &= ~NAND_CTRL_CHANGE;
-       }
-       if (page_addr != -1) {
-               chip->cmd_ctrl(mtd, page_addr, ctrl);
-               ctrl &= ~NAND_CTRL_CHANGE;
-               chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
-               if (chip->options & NAND_ROW_ADDR_3)
-                       chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
-       }
-       chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
-       /*
-        * Program and erase have their own busy handlers status and sequential
-        * in needs no delay
-        */
-       switch (command) {
-
-       case NAND_CMD_NONE:
-       case NAND_CMD_PAGEPROG:
-       case NAND_CMD_ERASE1:
-       case NAND_CMD_ERASE2:
-       case NAND_CMD_SEQIN:
-       case NAND_CMD_STATUS:
-       case NAND_CMD_READID:
-       case NAND_CMD_SET_FEATURES:
-               return;
-
-       case NAND_CMD_RESET:
-               if (chip->dev_ready)
-                       break;
-               udelay(chip->chip_delay);
-               chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
-                              NAND_CTRL_CLE | NAND_CTRL_CHANGE);
-               chip->cmd_ctrl(mtd,
-                              NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-               /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
-               nand_wait_status_ready(mtd, 250);
-               return;
-
-               /* This applies to read commands */
-       case NAND_CMD_READ0:
-               /*
-                * READ0 is sometimes used to exit GET STATUS mode. When this
-                * is the case no address cycles are requested, and we can use
-                * this information to detect that we should not wait for the
-                * device to be ready.
-                */
-               if (column == -1 && page_addr == -1)
-                       return;
-
-       default:
-               /*
-                * If we don't have access to the busy pin, we apply the given
-                * command delay
-                */
-               if (!chip->dev_ready) {
-                       udelay(chip->chip_delay);
-                       return;
-               }
-       }
-       /*
-        * Apply this short delay always to ensure that we do wait tWB in
-        * any case on any machine.
-        */
-       ndelay(100);
-
-       nand_wait_ready(mtd);
-}
-
-static void nand_ccs_delay(struct nand_chip *chip)
-{
-       /*
-        * The controller already takes care of waiting for tCCS when the RNDIN
-        * or RNDOUT command is sent, return directly.
-        */
-       if (!(chip->options & NAND_WAIT_TCCS))
-               return;
-
-       /*
-        * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
-        * (which should be safe for all NANDs).
-        */
-       if (chip->setup_data_interface)
-               ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
-       else
-               ndelay(500);
-}
-
-/**
- * nand_command_lp - [DEFAULT] Send command to NAND large page device
- * @mtd: MTD device structure
- * @command: the command to be sent
- * @column: the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
- *
- * Send command to NAND device. This is the version for the new large page
- * devices. We don't have the separate regions as we have in the small page
- * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
- */
-static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
-                           int column, int page_addr)
-{
-       register struct nand_chip *chip = mtd_to_nand(mtd);
-
-       /* Emulate NAND_CMD_READOOB */
-       if (command == NAND_CMD_READOOB) {
-               column += mtd->writesize;
-               command = NAND_CMD_READ0;
-       }
-
-       /* Command latch cycle */
-       if (command != NAND_CMD_NONE)
-               chip->cmd_ctrl(mtd, command,
-                              NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-
-       if (column != -1 || page_addr != -1) {
-               int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
-
-               /* Serially input address */
-               if (column != -1) {
-                       /* Adjust columns for 16 bit buswidth */
-                       if (chip->options & NAND_BUSWIDTH_16 &&
-                                       !nand_opcode_8bits(command))
-                               column >>= 1;
-                       chip->cmd_ctrl(mtd, column, ctrl);
-                       ctrl &= ~NAND_CTRL_CHANGE;
-
-                       /* Only output a single addr cycle for 8bits opcodes. */
-                       if (!nand_opcode_8bits(command))
-                               chip->cmd_ctrl(mtd, column >> 8, ctrl);
-               }
-               if (page_addr != -1) {
-                       chip->cmd_ctrl(mtd, page_addr, ctrl);
-                       chip->cmd_ctrl(mtd, page_addr >> 8,
-                                      NAND_NCE | NAND_ALE);
-                       if (chip->options & NAND_ROW_ADDR_3)
-                               chip->cmd_ctrl(mtd, page_addr >> 16,
-                                              NAND_NCE | NAND_ALE);
-               }
-       }
-       chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
-       /*
-        * Program and erase have their own busy handlers status, sequential
-        * in and status need no delay.
-        */
-       switch (command) {
-
-       case NAND_CMD_NONE:
-       case NAND_CMD_CACHEDPROG:
-       case NAND_CMD_PAGEPROG:
-       case NAND_CMD_ERASE1:
-       case NAND_CMD_ERASE2:
-       case NAND_CMD_SEQIN:
-       case NAND_CMD_STATUS:
-       case NAND_CMD_READID:
-       case NAND_CMD_SET_FEATURES:
-               return;
-
-       case NAND_CMD_RNDIN:
-               nand_ccs_delay(chip);
-               return;
-
-       case NAND_CMD_RESET:
-               if (chip->dev_ready)
-                       break;
-               udelay(chip->chip_delay);
-               chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
-                              NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-               chip->cmd_ctrl(mtd, NAND_CMD_NONE,
-                              NAND_NCE | NAND_CTRL_CHANGE);
-               /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
-               nand_wait_status_ready(mtd, 250);
-               return;
-
-       case NAND_CMD_RNDOUT:
-               /* No ready / busy check necessary */
-               chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
-                              NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-               chip->cmd_ctrl(mtd, NAND_CMD_NONE,
-                              NAND_NCE | NAND_CTRL_CHANGE);
-
-               nand_ccs_delay(chip);
-               return;
-
-       case NAND_CMD_READ0:
-               /*
-                * READ0 is sometimes used to exit GET STATUS mode. When this
-                * is the case no address cycles are requested, and we can use
-                * this information to detect that READSTART should not be
-                * issued.
-                */
-               if (column == -1 && page_addr == -1)
-                       return;
-
-               chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
-                              NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-               chip->cmd_ctrl(mtd, NAND_CMD_NONE,
-                              NAND_NCE | NAND_CTRL_CHANGE);
-
-               /* This applies to read commands */
-       default:
-               /*
-                * If we don't have access to the busy pin, we apply the given
-                * command delay.
-                */
-               if (!chip->dev_ready) {
-                       udelay(chip->chip_delay);
-                       return;
-               }
-       }
-
-       /*
-        * Apply this short delay always to ensure that we do wait tWB in
-        * any case on any machine.
-        */
-       ndelay(100);
-
-       nand_wait_ready(mtd);
-}
-
 /**
  * panic_nand_get_device - [GENERIC] Get chip for selected access
  * @chip: the nand chip descriptor
@@ -1086,13 +598,12 @@ retry:
  * we are in interrupt context. May happen when in panic and trying to write
  * an oops through mtdoops.
  */
-static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
-                           unsigned long timeo)
+void panic_nand_wait(struct nand_chip *chip, unsigned long timeo)
 {
        int i;
        for (i = 0; i < timeo; i++) {
-               if (chip->dev_ready) {
-                       if (chip->dev_ready(mtd))
+               if (chip->legacy.dev_ready) {
+                       if (chip->legacy.dev_ready(chip))
                                break;
                } else {
                        int ret;
@@ -1110,60 +621,6 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
        }
 }
 
-/**
- * nand_wait - [DEFAULT] wait until the command is done
- * @mtd: MTD device structure
- * @chip: NAND chip structure
- *
- * Wait for command done. This applies to erase and program only.
- */
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-
-       unsigned long timeo = 400;
-       u8 status;
-       int ret;
-
-       /*
-        * Apply this short delay always to ensure that we do wait tWB in any
-        * case on any machine.
-        */
-       ndelay(100);
-
-       ret = nand_status_op(chip, NULL);
-       if (ret)
-               return ret;
-
-       if (in_interrupt() || oops_in_progress)
-               panic_nand_wait(mtd, chip, timeo);
-       else {
-               timeo = jiffies + msecs_to_jiffies(timeo);
-               do {
-                       if (chip->dev_ready) {
-                               if (chip->dev_ready(mtd))
-                                       break;
-                       } else {
-                               ret = nand_read_data_op(chip, &status,
-                                                       sizeof(status), true);
-                               if (ret)
-                                       return ret;
-
-                               if (status & NAND_STATUS_READY)
-                                       break;
-                       }
-                       cond_resched();
-               } while (time_before(jiffies, timeo));
-       }
-
-       ret = nand_read_data_op(chip, &status, sizeof(status), true);
-       if (ret)
-               return ret;
-
-       /* This can happen if in case of timeout or buggy dev_ready */
-       WARN_ON(!(status & NAND_STATUS_READY));
-       return status;
-}
-
 static bool nand_supports_get_features(struct nand_chip *chip, int addr)
 {
        return (chip->parameters.supports_set_get_features &&
@@ -1176,48 +633,6 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr)
                test_bit(addr, chip->parameters.set_feature_list));
 }
 
-/**
- * nand_get_features - wrapper to perform a GET_FEATURE
- * @chip: NAND chip info structure
- * @addr: feature address
- * @subfeature_param: the subfeature parameters, a four bytes array
- *
- * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
- * operation cannot be handled.
- */
-int nand_get_features(struct nand_chip *chip, int addr,
-                     u8 *subfeature_param)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
-       if (!nand_supports_get_features(chip, addr))
-               return -ENOTSUPP;
-
-       return chip->get_features(mtd, chip, addr, subfeature_param);
-}
-EXPORT_SYMBOL_GPL(nand_get_features);
-
-/**
- * nand_set_features - wrapper to perform a SET_FEATURE
- * @chip: NAND chip info structure
- * @addr: feature address
- * @subfeature_param: the subfeature parameters, a four bytes array
- *
- * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
- * operation cannot be handled.
- */
-int nand_set_features(struct nand_chip *chip, int addr,
-                     u8 *subfeature_param)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
-       if (!nand_supports_set_features(chip, addr))
-               return -ENOTSUPP;
-
-       return chip->set_features(mtd, chip, addr, subfeature_param);
-}
-EXPORT_SYMBOL_GPL(nand_set_features);
-
 /**
  * nand_reset_data_interface - Reset data interface and timings
  * @chip: The NAND chip
@@ -1229,7 +644,6 @@ EXPORT_SYMBOL_GPL(nand_set_features);
  */
 static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
        if (!chip->setup_data_interface)
@@ -1250,7 +664,7 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
         */
 
        onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
-       ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
+       ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface);
        if (ret)
                pr_err("Failed to configure data interface to SDR timing mode 0\n");
 
@@ -1272,7 +686,6 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
  */
 static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
                chip->onfi_timing_mode_default,
        };
@@ -1283,16 +696,16 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
 
        /* Change the mode on the chip side (if supported by the NAND chip) */
        if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
-               chip->select_chip(mtd, chipnr);
+               chip->select_chip(chip, chipnr);
                ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
                                        tmode_param);
-               chip->select_chip(mtd, -1);
+               chip->select_chip(chip, -1);
                if (ret)
                        return ret;
        }
 
        /* Change the mode on the controller side */
-       ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
+       ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface);
        if (ret)
                return ret;
 
@@ -1301,10 +714,10 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
                return 0;
 
        memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
        ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
                                tmode_param);
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
        if (ret)
                goto err_reset_chip;
 
@@ -1322,9 +735,9 @@ err_reset_chip:
         * timing mode.
         */
        nand_reset_data_interface(chip, chipnr);
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
        nand_reset_op(chip);
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
 
        return ret;
 }
@@ -1345,7 +758,6 @@ err_reset_chip:
  */
 static int nand_init_data_interface(struct nand_chip *chip)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        int modes, mode, ret;
 
        if (!chip->setup_data_interface)
@@ -1356,15 +768,15 @@ static int nand_init_data_interface(struct nand_chip *chip)
         * if the NAND does not support ONFI, fallback to the default ONFI
         * timing mode.
         */
-       modes = onfi_get_async_timing_mode(chip);
-       if (modes == ONFI_TIMING_MODE_UNKNOWN) {
+       if (chip->parameters.onfi) {
+               modes = chip->parameters.onfi->async_timing_mode;
+       } else {
                if (!chip->onfi_timing_mode_default)
                        return 0;
 
                modes = GENMASK(chip->onfi_timing_mode_default, 0);
        }
 
-
        for (mode = fls(modes) - 1; mode >= 0; mode--) {
                ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode);
                if (ret)
@@ -1374,7 +786,7 @@ static int nand_init_data_interface(struct nand_chip *chip)
                 * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the
                 * controller supports the requested timings.
                 */
-               ret = chip->setup_data_interface(mtd,
+               ret = chip->setup_data_interface(chip,
                                                 NAND_DATA_IFACE_CHECK_ONLY,
                                                 &chip->data_interface);
                if (!ret) {
@@ -1554,9 +966,9 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page,
                                                 buf, len);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_READ0, offset_in_page, page);
+       chip->legacy.cmdfunc(chip, NAND_CMD_READ0, offset_in_page, page);
        if (len)
-               chip->read_buf(mtd, buf, len);
+               chip->legacy.read_buf(chip, buf, len);
 
        return 0;
 }
@@ -1574,10 +986,9 @@ EXPORT_SYMBOL_GPL(nand_read_page_op);
  *
  * Returns 0 on success, a negative error code otherwise.
  */
-static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
-                                  unsigned int len)
+int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
+                           unsigned int len)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        unsigned int i;
        u8 *p = buf;
 
@@ -1603,9 +1014,9 @@ static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_PARAM, page, -1);
+       chip->legacy.cmdfunc(chip, NAND_CMD_PARAM, page, -1);
        for (i = 0; i < len; i++)
-               p[i] = chip->read_byte(mtd);
+               p[i] = chip->legacy.read_byte(chip);
 
        return 0;
 }
@@ -1666,9 +1077,9 @@ int nand_change_read_column_op(struct nand_chip *chip,
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset_in_page, -1);
+       chip->legacy.cmdfunc(chip, NAND_CMD_RNDOUT, offset_in_page, -1);
        if (len)
-               chip->read_buf(mtd, buf, len);
+               chip->legacy.read_buf(chip, buf, len);
 
        return 0;
 }
@@ -1703,9 +1114,9 @@ int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
                                         mtd->writesize + offset_in_oob,
                                         buf, len);
 
-       chip->cmdfunc(mtd, NAND_CMD_READOOB, offset_in_oob, page);
+       chip->legacy.cmdfunc(chip, NAND_CMD_READOOB, offset_in_oob, page);
        if (len)
-               chip->read_buf(mtd, buf, len);
+               chip->legacy.read_buf(chip, buf, len);
 
        return 0;
 }
@@ -1815,10 +1226,10 @@ int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
                return nand_exec_prog_page_op(chip, page, offset_in_page, buf,
                                              len, false);
 
-       chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
+       chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page, page);
 
        if (buf)
-               chip->write_buf(mtd, buf, len);
+               chip->legacy.write_buf(chip, buf, len);
 
        return 0;
 }
@@ -1835,7 +1246,6 @@ EXPORT_SYMBOL_GPL(nand_prog_page_begin_op);
  */
 int nand_prog_page_end_op(struct nand_chip *chip)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
        u8 status;
 
@@ -1857,8 +1267,8 @@ int nand_prog_page_end_op(struct nand_chip *chip)
                if (ret)
                        return ret;
        } else {
-               chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-               ret = chip->waitfunc(mtd, chip);
+               chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+               ret = chip->legacy.waitfunc(chip);
                if (ret < 0)
                        return ret;
 
@@ -1902,10 +1312,11 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
                status = nand_exec_prog_page_op(chip, page, offset_in_page, buf,
                                                len, true);
        } else {
-               chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
-               chip->write_buf(mtd, buf, len);
-               chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-               status = chip->waitfunc(mtd, chip);
+               chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page,
+                                    page);
+               chip->legacy.write_buf(chip, buf, len);
+               chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+               status = chip->legacy.waitfunc(chip);
        }
 
        if (status & NAND_STATUS_FAIL)
@@ -1970,9 +1381,9 @@ int nand_change_write_column_op(struct nand_chip *chip,
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset_in_page, -1);
+       chip->legacy.cmdfunc(chip, NAND_CMD_RNDIN, offset_in_page, -1);
        if (len)
-               chip->write_buf(mtd, buf, len);
+               chip->legacy.write_buf(chip, buf, len);
 
        return 0;
 }
@@ -1994,7 +1405,6 @@ EXPORT_SYMBOL_GPL(nand_change_write_column_op);
 int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
                   unsigned int len)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        unsigned int i;
        u8 *id = buf;
 
@@ -2018,10 +1428,10 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_READID, addr, -1);
+       chip->legacy.cmdfunc(chip, NAND_CMD_READID, addr, -1);
 
        for (i = 0; i < len; i++)
-               id[i] = chip->read_byte(mtd);
+               id[i] = chip->legacy.read_byte(chip);
 
        return 0;
 }
@@ -2040,8 +1450,6 @@ EXPORT_SYMBOL_GPL(nand_readid_op);
  */
 int nand_status_op(struct nand_chip *chip, u8 *status)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
        if (chip->exec_op) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
@@ -2058,9 +1466,9 @@ int nand_status_op(struct nand_chip *chip, u8 *status)
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+       chip->legacy.cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
        if (status)
-               *status = chip->read_byte(mtd);
+               *status = chip->legacy.read_byte(chip);
 
        return 0;
 }
@@ -2079,8 +1487,6 @@ EXPORT_SYMBOL_GPL(nand_status_op);
  */
 int nand_exit_status_op(struct nand_chip *chip)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
        if (chip->exec_op) {
                struct nand_op_instr instrs[] = {
                        NAND_OP_CMD(NAND_CMD_READ0, 0),
@@ -2090,11 +1496,10 @@ int nand_exit_status_op(struct nand_chip *chip)
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
+       chip->legacy.cmdfunc(chip, NAND_CMD_READ0, -1, -1);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(nand_exit_status_op);
 
 /**
  * nand_erase_op - Do an erase operation
@@ -2109,7 +1514,6 @@ EXPORT_SYMBOL_GPL(nand_exit_status_op);
  */
 int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        unsigned int page = eraseblock <<
                            (chip->phys_erase_shift - chip->page_shift);
        int ret;
@@ -2139,10 +1543,10 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
                if (ret)
                        return ret;
        } else {
-               chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
-               chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+               chip->legacy.cmdfunc(chip, NAND_CMD_ERASE1, -1, page);
+               chip->legacy.cmdfunc(chip, NAND_CMD_ERASE2, -1, -1);
 
-               ret = chip->waitfunc(mtd, chip);
+               ret = chip->legacy.waitfunc(chip);
                if (ret < 0)
                        return ret;
 
@@ -2171,7 +1575,6 @@ EXPORT_SYMBOL_GPL(nand_erase_op);
 static int nand_set_features_op(struct nand_chip *chip, u8 feature,
                                const void *data)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        const u8 *params = data;
        int i, ret;
 
@@ -2190,11 +1593,11 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, feature, -1);
+       chip->legacy.cmdfunc(chip, NAND_CMD_SET_FEATURES, feature, -1);
        for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-               chip->write_byte(mtd, params[i]);
+               chip->legacy.write_byte(chip, params[i]);
 
-       ret = chip->waitfunc(mtd, chip);
+       ret = chip->legacy.waitfunc(chip);
        if (ret < 0)
                return ret;
 
@@ -2219,7 +1622,6 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
 static int nand_get_features_op(struct nand_chip *chip, u8 feature,
                                void *data)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        u8 *params = data;
        int i;
 
@@ -2239,9 +1641,31 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, feature, -1);
+       chip->legacy.cmdfunc(chip, NAND_CMD_GET_FEATURES, feature, -1);
        for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
-               params[i] = chip->read_byte(mtd);
+               params[i] = chip->legacy.read_byte(chip);
+
+       return 0;
+}
+
+static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms,
+                           unsigned int delay_ns)
+{
+       if (chip->exec_op) {
+               struct nand_op_instr instrs[] = {
+                       NAND_OP_WAIT_RDY(PSEC_TO_MSEC(timeout_ms),
+                                        PSEC_TO_NSEC(delay_ns)),
+               };
+               struct nand_operation op = NAND_OPERATION(instrs);
+
+               return nand_exec_op(chip, &op);
+       }
+
+       /* Apply delay or wait for ready/busy pin */
+       if (!chip->legacy.dev_ready)
+               udelay(chip->legacy.chip_delay);
+       else
+               nand_wait_ready(chip);
 
        return 0;
 }
@@ -2258,8 +1682,6 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
  */
 int nand_reset_op(struct nand_chip *chip)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
        if (chip->exec_op) {
                const struct nand_sdr_timings *sdr =
                        nand_get_sdr_timings(&chip->data_interface);
@@ -2272,7 +1694,7 @@ int nand_reset_op(struct nand_chip *chip)
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+       chip->legacy.cmdfunc(chip, NAND_CMD_RESET, -1, -1);
 
        return 0;
 }
@@ -2294,8 +1716,6 @@ EXPORT_SYMBOL_GPL(nand_reset_op);
 int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
                      bool force_8bit)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
        if (!len || !buf)
                return -EINVAL;
 
@@ -2315,9 +1735,9 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
                unsigned int i;
 
                for (i = 0; i < len; i++)
-                       p[i] = chip->read_byte(mtd);
+                       p[i] = chip->legacy.read_byte(chip);
        } else {
-               chip->read_buf(mtd, buf, len);
+               chip->legacy.read_buf(chip, buf, len);
        }
 
        return 0;
@@ -2340,8 +1760,6 @@ EXPORT_SYMBOL_GPL(nand_read_data_op);
 int nand_write_data_op(struct nand_chip *chip, const void *buf,
                       unsigned int len, bool force_8bit)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
        if (!len || !buf)
                return -EINVAL;
 
@@ -2361,9 +1779,9 @@ int nand_write_data_op(struct nand_chip *chip, const void *buf,
                unsigned int i;
 
                for (i = 0; i < len; i++)
-                       chip->write_byte(mtd, p[i]);
+                       chip->legacy.write_byte(chip, p[i]);
        } else {
-               chip->write_buf(mtd, buf, len);
+               chip->legacy.write_buf(chip, buf, len);
        }
 
        return 0;
@@ -2798,7 +2216,6 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len);
  */
 int nand_reset(struct nand_chip *chip, int chipnr)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_data_interface saved_data_intf = chip->data_interface;
        int ret;
 
@@ -2810,9 +2227,9 @@ int nand_reset(struct nand_chip *chip, int chipnr)
         * The CS line has to be released before we can apply the new NAND
         * interface settings, hence this weird ->select_chip() dance.
         */
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
        ret = nand_reset_op(chip);
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
        if (ret)
                return ret;
 
@@ -2835,6 +2252,48 @@ int nand_reset(struct nand_chip *chip, int chipnr)
 }
 EXPORT_SYMBOL_GPL(nand_reset);
 
+/**
+ * nand_get_features - wrapper to perform a GET_FEATURE
+ * @chip: NAND chip info structure
+ * @addr: feature address
+ * @subfeature_param: the subfeature parameters, a four bytes array
+ *
+ * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
+ * operation cannot be handled.
+ */
+int nand_get_features(struct nand_chip *chip, int addr,
+                     u8 *subfeature_param)
+{
+       if (!nand_supports_get_features(chip, addr))
+               return -ENOTSUPP;
+
+       if (chip->legacy.get_features)
+               return chip->legacy.get_features(chip, addr, subfeature_param);
+
+       return nand_get_features_op(chip, addr, subfeature_param);
+}
+
+/**
+ * nand_set_features - wrapper to perform a SET_FEATURE
+ * @chip: NAND chip info structure
+ * @addr: feature address
+ * @subfeature_param: the subfeature parameters, a four bytes array
+ *
+ * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
+ * operation cannot be handled.
+ */
+int nand_set_features(struct nand_chip *chip, int addr,
+                     u8 *subfeature_param)
+{
+       if (!nand_supports_set_features(chip, addr))
+               return -ENOTSUPP;
+
+       if (chip->legacy.set_features)
+               return chip->legacy.set_features(chip, addr, subfeature_param);
+
+       return nand_set_features_op(chip, addr, subfeature_param);
+}
+
 /**
  * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
  * @buf: buffer to test
@@ -2968,7 +2427,6 @@ 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
@@ -2976,16 +2434,14 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
  *
  * Returns -ENOTSUPP unconditionally.
  */
-int nand_read_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
-                              u8 *buf, int oob_required, int page)
+int nand_read_page_raw_notsupp(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
  * @chip: nand chip info structure
  * @buf: buffer to store read data
  * @oob_required: caller requires OOB data read to chip->oob_poi
@@ -2993,9 +2449,10 @@ EXPORT_SYMBOL(nand_read_page_raw_notsupp);
  *
  * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
-int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                      uint8_t *buf, int oob_required, int page)
+int nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required,
+                      int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
        ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize);
@@ -3015,7 +2472,6 @@ EXPORT_SYMBOL(nand_read_page_raw);
 
 /**
  * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
- * @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
@@ -3023,10 +2479,10 @@ EXPORT_SYMBOL(nand_read_page_raw);
  *
  * We need a special oob layout and handling even when OOB isn't used.
  */
-static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
-                                      struct nand_chip *chip, uint8_t *buf,
+static int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf,
                                       int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
        uint8_t *oob = chip->oob_poi;
@@ -3080,15 +2536,15 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
 
 /**
  * nand_read_page_swecc - [REPLACEABLE] software ECC based page read 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
  */
-static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int oob_required, int page)
+static int nand_read_page_swecc(struct nand_chip *chip, uint8_t *buf,
+                               int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int i, eccsize = chip->ecc.size, ret;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
@@ -3097,10 +2553,10 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        uint8_t *ecc_code = chip->ecc.code_buf;
        unsigned int max_bitflips = 0;
 
-       chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
+       chip->ecc.read_page_raw(chip, buf, 1, page);
 
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-               chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+               chip->ecc.calculate(chip, p, &ecc_calc[i]);
 
        ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
                                         chip->ecc.total);
@@ -3113,7 +2569,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
                int stat;
 
-               stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+               stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
                if (stat < 0) {
                        mtd->ecc_stats.failed++;
                } else {
@@ -3126,17 +2582,16 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 
 /**
  * nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
- * @mtd: mtd info structure
  * @chip: nand chip info structure
  * @data_offs: offset of requested data within the page
  * @readlen: data length
  * @bufpoi: buffer to store read data
  * @page: page number to read
  */
-static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
-                       int page)
+static int nand_read_subpage(struct nand_chip *chip, uint32_t data_offs,
+                            uint32_t readlen, uint8_t *bufpoi, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int start_step, end_step, num_steps, ret;
        uint8_t *p;
        int data_col_addr, i, gaps = 0;
@@ -3165,7 +2620,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 
        /* Calculate ECC */
        for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
-               chip->ecc.calculate(mtd, p, &chip->ecc.calc_buf[i]);
+               chip->ecc.calculate(chip, p, &chip->ecc.calc_buf[i]);
 
        /*
         * The performance is faster if we position offsets according to
@@ -3214,7 +2669,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
                int stat;
 
-               stat = chip->ecc.correct(mtd, p, &chip->ecc.code_buf[i],
+               stat = chip->ecc.correct(chip, p, &chip->ecc.code_buf[i],
                                         &chip->ecc.calc_buf[i]);
                if (stat == -EBADMSG &&
                    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
@@ -3238,7 +2693,6 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
 
 /**
  * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read 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
@@ -3246,9 +2700,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
  *
  * Not for syndrome calculating ECC controllers which need a special oob layout.
  */
-static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int oob_required, int page)
+static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+                               int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int i, eccsize = chip->ecc.size, ret;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
@@ -3262,13 +2717,13 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                return ret;
 
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-               chip->ecc.hwctl(mtd, NAND_ECC_READ);
+               chip->ecc.hwctl(chip, NAND_ECC_READ);
 
                ret = nand_read_data_op(chip, p, eccsize, false);
                if (ret)
                        return ret;
 
-               chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+               chip->ecc.calculate(chip, p, &ecc_calc[i]);
        }
 
        ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
@@ -3286,7 +2741,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
                int stat;
 
-               stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+               stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
                if (stat == -EBADMSG &&
                    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
                        /* check for empty pages with bitflips */
@@ -3308,7 +2763,6 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 
 /**
  * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
- * @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
@@ -3320,9 +2774,10 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
  * the data area, by overwriting the NAND manufacturer bad block markings.
  */
-static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
-       struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+static int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf,
+                                         int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int i, eccsize = chip->ecc.size, ret;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
@@ -3348,15 +2803,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
                int stat;
 
-               chip->ecc.hwctl(mtd, NAND_ECC_READ);
+               chip->ecc.hwctl(chip, NAND_ECC_READ);
 
                ret = nand_read_data_op(chip, p, eccsize, false);
                if (ret)
                        return ret;
 
-               chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+               chip->ecc.calculate(chip, p, &ecc_calc[i]);
 
-               stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
+               stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL);
                if (stat == -EBADMSG &&
                    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
                        /* check for empty pages with bitflips */
@@ -3378,7 +2833,6 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
 
 /**
  * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
- * @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
@@ -3387,9 +2841,10 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
  * The hw generator calculates the error syndrome automatically. Therefore we
  * need a special oob layout and handling.
  */
-static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-                                  uint8_t *buf, int oob_required, int page)
+static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
+                                  int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret, i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
@@ -3405,7 +2860,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
                int stat;
 
-               chip->ecc.hwctl(mtd, NAND_ECC_READ);
+               chip->ecc.hwctl(chip, NAND_ECC_READ);
 
                ret = nand_read_data_op(chip, p, eccsize, false);
                if (ret)
@@ -3420,13 +2875,13 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
                        oob += chip->ecc.prepad;
                }
 
-               chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
+               chip->ecc.hwctl(chip, NAND_ECC_READSYN);
 
                ret = nand_read_data_op(chip, oob, eccbytes, false);
                if (ret)
                        return ret;
 
-               stat = chip->ecc.correct(mtd, p, oob, NULL);
+               stat = chip->ecc.correct(chip, p, oob, NULL);
 
                oob += eccbytes;
 
@@ -3502,17 +2957,15 @@ static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
 
 /**
  * nand_setup_read_retry - [INTERN] Set the READ RETRY mode
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @retry_mode: the retry mode to use
  *
  * Some vendors supply a special command to shift the Vt threshold, to be used
  * when there are too many bitflips in a page (i.e., ECC error). After setting
  * a new threshold, the host should retry reading the page.
  */
-static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        pr_debug("setting READ RETRY mode %d\n", retry_mode);
 
        if (retry_mode >= chip->read_retries)
@@ -3521,7 +2974,18 @@ static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
        if (!chip->setup_read_retry)
                return -EOPNOTSUPP;
 
-       return chip->setup_read_retry(mtd, retry_mode);
+       return chip->setup_read_retry(chip, retry_mode);
+}
+
+static void nand_wait_readrdy(struct nand_chip *chip)
+{
+       const struct nand_sdr_timings *sdr;
+
+       if (!(chip->options & NAND_NEED_READRDY))
+               return;
+
+       sdr = nand_get_sdr_timings(&chip->data_interface);
+       WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0));
 }
 
 /**
@@ -3549,7 +3013,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        bool ecc_fail = false;
 
        chipnr = (int)(from >> chip->chip_shift);
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
 
        realpage = (int)(from >> chip->page_shift);
        page = realpage & chip->pagemask;
@@ -3589,16 +3053,15 @@ read_retry:
                         * the read methods return max bitflips per ecc step.
                         */
                        if (unlikely(ops->mode == MTD_OPS_RAW))
-                               ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
+                               ret = chip->ecc.read_page_raw(chip, bufpoi,
                                                              oob_required,
                                                              page);
                        else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
                                 !oob)
-                               ret = chip->ecc.read_subpage(mtd, chip,
-                                                       col, bytes, bufpoi,
-                                                       page);
+                               ret = chip->ecc.read_subpage(chip, col, bytes,
+                                                            bufpoi, page);
                        else
-                               ret = chip->ecc.read_page(mtd, chip, bufpoi,
+                               ret = chip->ecc.read_page(chip, bufpoi,
                                                          oob_required, page);
                        if (ret < 0) {
                                if (use_bufpoi)
@@ -3631,18 +3094,12 @@ read_retry:
                                }
                        }
 
-                       if (chip->options & NAND_NEED_READRDY) {
-                               /* Apply delay or wait for ready/busy pin */
-                               if (!chip->dev_ready)
-                                       udelay(chip->chip_delay);
-                               else
-                                       nand_wait_ready(mtd);
-                       }
+                       nand_wait_readrdy(chip);
 
                        if (mtd->ecc_stats.failed - ecc_failures) {
                                if (retry_mode + 1 < chip->read_retries) {
                                        retry_mode++;
-                                       ret = nand_setup_read_retry(mtd,
+                                       ret = nand_setup_read_retry(chip,
                                                        retry_mode);
                                        if (ret < 0)
                                                break;
@@ -3669,7 +3126,7 @@ read_retry:
 
                /* Reset to retry mode 0 */
                if (retry_mode) {
-                       ret = nand_setup_read_retry(mtd, 0);
+                       ret = nand_setup_read_retry(chip, 0);
                        if (ret < 0)
                                break;
                        retry_mode = 0;
@@ -3687,11 +3144,11 @@ read_retry:
                /* Check, if we cross a chip boundary */
                if (!page) {
                        chipnr++;
-                       chip->select_chip(mtd, -1);
-                       chip->select_chip(mtd, chipnr);
+                       chip->select_chip(chip, -1);
+                       chip->select_chip(chip, chipnr);
                }
        }
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
 
        ops->retlen = ops->len - (size_t) readlen;
        if (oob)
@@ -3708,12 +3165,13 @@ read_retry:
 
 /**
  * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
- * @mtd: mtd info structure
  * @chip: nand chip info structure
  * @page: page number to read
  */
-int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+int nand_read_oob_std(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
 }
 EXPORT_SYMBOL(nand_read_oob_std);
@@ -3721,13 +3179,12 @@ EXPORT_SYMBOL(nand_read_oob_std);
 /**
  * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
  *                         with syndromes
- * @mtd: mtd info structure
  * @chip: nand chip info structure
  * @page: page number to read
  */
-int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-                          int page)
+static int nand_read_oob_syndrome(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int length = mtd->oobsize;
        int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
        int eccsize = chip->ecc.size;
@@ -3772,16 +3229,16 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 
        return 0;
 }
-EXPORT_SYMBOL(nand_read_oob_syndrome);
 
 /**
  * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
- * @mtd: mtd info structure
  * @chip: nand chip info structure
  * @page: page number to write
  */
-int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+int nand_write_oob_std(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
                                 mtd->oobsize);
 }
@@ -3790,13 +3247,12 @@ EXPORT_SYMBOL(nand_write_oob_std);
 /**
  * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
  *                          with syndrome - only for large page flash
- * @mtd: mtd info structure
  * @chip: nand chip info structure
  * @page: page number to write
  */
-int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-                           int page)
+static int nand_write_oob_syndrome(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
        int eccsize = chip->ecc.size, length = mtd->oobsize;
        int ret, i, len, pos, sndcmd = 0, steps = chip->ecc.steps;
@@ -3860,7 +3316,6 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 
        return nand_prog_page_end_op(chip);
 }
-EXPORT_SYMBOL(nand_write_oob_syndrome);
 
 /**
  * nand_do_read_oob - [INTERN] NAND read out-of-band
@@ -3890,7 +3345,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
        len = mtd_oobavail(mtd, ops);
 
        chipnr = (int)(from >> chip->chip_shift);
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
 
        /* Shift to get page */
        realpage = (int)(from >> chip->page_shift);
@@ -3898,9 +3353,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 
        while (1) {
                if (ops->mode == MTD_OPS_RAW)
-                       ret = chip->ecc.read_oob_raw(mtd, chip, page);
+                       ret = chip->ecc.read_oob_raw(chip, page);
                else
-                       ret = chip->ecc.read_oob(mtd, chip, page);
+                       ret = chip->ecc.read_oob(chip, page);
 
                if (ret < 0)
                        break;
@@ -3908,13 +3363,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                len = min(len, readlen);
                buf = nand_transfer_oob(mtd, buf, ops, len);
 
-               if (chip->options & NAND_NEED_READRDY) {
-                       /* Apply delay or wait for ready/busy pin */
-                       if (!chip->dev_ready)
-                               udelay(chip->chip_delay);
-                       else
-                               nand_wait_ready(mtd);
-               }
+               nand_wait_readrdy(chip);
 
                max_bitflips = max_t(unsigned int, max_bitflips, ret);
 
@@ -3929,11 +3378,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                /* Check, if we cross a chip boundary */
                if (!page) {
                        chipnr++;
-                       chip->select_chip(mtd, -1);
-                       chip->select_chip(mtd, chipnr);
+                       chip->select_chip(chip, -1);
+                       chip->select_chip(chip, chipnr);
                }
        }
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
 
        ops->oobretlen = ops->ooblen - readlen;
 
@@ -3979,7 +3428,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
 
 /**
  * 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
@@ -3987,16 +3435,14 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
  *
  * 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)
+int nand_write_page_raw_notsupp(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
- * @mtd: mtd info structure
  * @chip: nand chip info structure
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
@@ -4004,9 +3450,10 @@ EXPORT_SYMBOL(nand_write_page_raw_notsupp);
  *
  * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
-int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                       const uint8_t *buf, int oob_required, int page)
+int nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+                       int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
        ret = nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
@@ -4026,7 +3473,6 @@ EXPORT_SYMBOL(nand_write_page_raw);
 
 /**
  * nand_write_page_raw_syndrome - [INTERN] 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
@@ -4034,11 +3480,11 @@ EXPORT_SYMBOL(nand_write_page_raw);
  *
  * We need a special oob layout and handling even when ECC isn't checked.
  */
-static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
-                                       struct nand_chip *chip,
+static int nand_write_page_raw_syndrome(struct nand_chip *chip,
                                        const uint8_t *buf, int oob_required,
                                        int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
        uint8_t *oob = chip->oob_poi;
@@ -4091,16 +3537,15 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
 }
 /**
  * nand_write_page_swecc - [REPLACEABLE] software ECC based 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
  */
-static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                const uint8_t *buf, int oob_required,
-                                int page)
+static int nand_write_page_swecc(struct nand_chip *chip, const uint8_t *buf,
+                                int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int i, eccsize = chip->ecc.size, ret;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
@@ -4109,28 +3554,27 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 
        /* Software ECC calculation */
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-               chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+               chip->ecc.calculate(chip, p, &ecc_calc[i]);
 
        ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
                                         chip->ecc.total);
        if (ret)
                return ret;
 
-       return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
+       return chip->ecc.write_page_raw(chip, buf, 1, page);
 }
 
 /**
  * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based 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
  */
-static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                 const uint8_t *buf, int oob_required,
-                                 int page)
+static int nand_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf,
+                                int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int i, eccsize = chip->ecc.size, ret;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
@@ -4142,13 +3586,13 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                return ret;
 
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-               chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+               chip->ecc.hwctl(chip, NAND_ECC_WRITE);
 
                ret = nand_write_data_op(chip, p, eccsize, false);
                if (ret)
                        return ret;
 
-               chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+               chip->ecc.calculate(chip, p, &ecc_calc[i]);
        }
 
        ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
@@ -4166,7 +3610,6 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 
 /**
  * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write
- * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @offset:    column address of subpage within the page
  * @data_len:  data length
@@ -4174,11 +3617,11 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * @oob_required: must write chip->oob_poi to OOB
  * @page: page number to write
  */
-static int nand_write_subpage_hwecc(struct mtd_info *mtd,
-                               struct nand_chip *chip, uint32_t offset,
-                               uint32_t data_len, const uint8_t *buf,
-                               int oob_required, int page)
+static int nand_write_subpage_hwecc(struct nand_chip *chip, uint32_t offset,
+                                   uint32_t data_len, const uint8_t *buf,
+                                   int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        uint8_t *oob_buf  = chip->oob_poi;
        uint8_t *ecc_calc = chip->ecc.calc_buf;
        int ecc_size      = chip->ecc.size;
@@ -4195,7 +3638,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 
        for (step = 0; step < ecc_steps; step++) {
                /* configure controller for WRITE access */
-               chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+               chip->ecc.hwctl(chip, NAND_ECC_WRITE);
 
                /* write data (untouched subpages already masked by 0xFF) */
                ret = nand_write_data_op(chip, buf, ecc_size, false);
@@ -4206,7 +3649,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
                if ((step < start_step) || (step > end_step))
                        memset(ecc_calc, 0xff, ecc_bytes);
                else
-                       chip->ecc.calculate(mtd, buf, ecc_calc);
+                       chip->ecc.calculate(chip, buf, ecc_calc);
 
                /* mask OOB of un-touched subpages by padding 0xFF */
                /* if oob_required, preserve OOB metadata of written subpage */
@@ -4237,7 +3680,6 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
 
 /**
  * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
- * @mtd: mtd info structure
  * @chip: nand chip info structure
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
@@ -4246,11 +3688,10 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
  * The hw generator calculates the error syndrome automatically. Therefore we
  * need a special oob layout and handling.
  */
-static int nand_write_page_syndrome(struct mtd_info *mtd,
-                                   struct nand_chip *chip,
-                                   const uint8_t *buf, int oob_required,
-                                   int page)
+static int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf,
+                                   int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
        int eccsteps = chip->ecc.steps;
@@ -4263,7 +3704,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
                return ret;
 
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-               chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+               chip->ecc.hwctl(chip, NAND_ECC_WRITE);
 
                ret = nand_write_data_op(chip, p, eccsize, false);
                if (ret)
@@ -4278,7 +3719,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
                        oob += chip->ecc.prepad;
                }
 
-               chip->ecc.calculate(mtd, p, oob);
+               chip->ecc.calculate(chip, p, oob);
 
                ret = nand_write_data_op(chip, oob, eccbytes, false);
                if (ret)
@@ -4331,14 +3772,13 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                subpage = 0;
 
        if (unlikely(raw))
-               status = chip->ecc.write_page_raw(mtd, chip, buf,
-                                                 oob_required, page);
+               status = chip->ecc.write_page_raw(chip, buf, oob_required,
+                                                 page);
        else if (subpage)
-               status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
-                                                buf, oob_required, page);
+               status = chip->ecc.write_subpage(chip, offset, data_len, buf,
+                                                oob_required, page);
        else
-               status = chip->ecc.write_page(mtd, chip, buf, oob_required,
-                                             page);
+               status = chip->ecc.write_page(chip, buf, oob_required, page);
 
        if (status < 0)
                return status;
@@ -4423,7 +3863,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        column = to & (mtd->writesize - 1);
 
        chipnr = (int)(to >> chip->chip_shift);
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
@@ -4499,8 +3939,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                /* Check, if we cross a chip boundary */
                if (!page) {
                        chipnr++;
-                       chip->select_chip(mtd, -1);
-                       chip->select_chip(mtd, chipnr);
+                       chip->select_chip(chip, -1);
+                       chip->select_chip(chip, chipnr);
                }
        }
 
@@ -4509,7 +3949,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                ops->oobretlen = ops->ooblen;
 
 err_out:
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
        return ret;
 }
 
@@ -4535,10 +3975,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
        /* Grab the device */
        panic_nand_get_device(chip, mtd, FL_WRITING);
 
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
 
        /* Wait for the device to get ready */
-       panic_nand_wait(mtd, chip, 400);
+       panic_nand_wait(chip, 400);
 
        memset(&ops, 0, sizeof(ops));
        ops.len = len;
@@ -4587,14 +4027,14 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
         */
        nand_reset(chip, chipnr);
 
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
 
        /* Shift to get page */
        page = (int)(to >> chip->page_shift);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
-               chip->select_chip(mtd, -1);
+               chip->select_chip(chip, -1);
                return -EROFS;
        }
 
@@ -4605,11 +4045,11 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
 
        if (ops->mode == MTD_OPS_RAW)
-               status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
+               status = chip->ecc.write_oob_raw(chip, page & chip->pagemask);
        else
-               status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
+               status = chip->ecc.write_oob(chip, page & chip->pagemask);
 
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
 
        if (status)
                return status;
@@ -4656,14 +4096,13 @@ out:
 
 /**
  * single_erase - [GENERIC] NAND standard block erase command function
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @page: the page address of the block which will be erased
  *
  * Standard erase command for NAND chips. Returns NAND status.
  */
-static int single_erase(struct mtd_info *mtd, int page)
+static int single_erase(struct nand_chip *chip, int page)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        unsigned int eraseblock;
 
        /* Send commands to erase a block */
@@ -4681,22 +4120,22 @@ static int single_erase(struct mtd_info *mtd, int page)
  */
 static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-       return nand_erase_nand(mtd, instr, 0);
+       return nand_erase_nand(mtd_to_nand(mtd), instr, 0);
 }
 
 /**
  * nand_erase_nand - [INTERN] erase block(s)
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @instr: erase instruction
  * @allowbbt: allow erasing the bbt area
  *
  * Erase one ore more blocks.
  */
-int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
                    int allowbbt)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int page, status, pages_per_block, ret, chipnr;
-       struct nand_chip *chip = mtd_to_nand(mtd);
        loff_t len;
 
        pr_debug("%s: start = 0x%012llx, len = %llu\n",
@@ -4717,7 +4156,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
        pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
 
        /* Select the NAND device */
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
@@ -4748,7 +4187,11 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                    (page + pages_per_block))
                        chip->pagebuf = -1;
 
-               status = chip->erase(mtd, page & chip->pagemask);
+               if (chip->legacy.erase)
+                       status = chip->legacy.erase(chip,
+                                                   page & chip->pagemask);
+               else
+                       status = single_erase(chip, page & chip->pagemask);
 
                /* See if block erase succeeded */
                if (status) {
@@ -4767,8 +4210,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                /* Check, if we cross a chip boundary */
                if (len && !(page & chip->pagemask)) {
                        chipnr++;
-                       chip->select_chip(mtd, -1);
-                       chip->select_chip(mtd, chipnr);
+                       chip->select_chip(chip, -1);
+                       chip->select_chip(chip, chipnr);
                }
        }
 
@@ -4776,7 +4219,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 erase_exit:
 
        /* Deselect and wake up anyone waiting on the device */
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
        nand_release_device(mtd);
 
        /* Return more or less happy */
@@ -4812,11 +4255,11 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 
        /* Select the NAND device */
        nand_get_device(mtd, FL_READING);
-       chip->select_chip(mtd, chipnr);
+       chip->select_chip(chip, chipnr);
 
        ret = nand_block_checkbad(mtd, offs, 0);
 
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
        nand_release_device(mtd);
 
        return ret;
@@ -4878,51 +4321,6 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
        return chip->max_bb_per_die * (part_end_die - part_start_die + 1);
 }
 
-/**
- * nand_default_set_features- [REPLACEABLE] set NAND chip features
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- */
-static int nand_default_set_features(struct mtd_info *mtd,
-                                    struct nand_chip *chip, int addr,
-                                    uint8_t *subfeature_param)
-{
-       return nand_set_features_op(chip, addr, subfeature_param);
-}
-
-/**
- * nand_default_get_features- [REPLACEABLE] get NAND chip features
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- */
-static int nand_default_get_features(struct mtd_info *mtd,
-                                    struct nand_chip *chip, int addr,
-                                    uint8_t *subfeature_param)
-{
-       return nand_get_features_op(chip, addr, subfeature_param);
-}
-
-/**
- * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- *
- * Should be used by NAND controller drivers that do not support the SET/GET
- * FEATURES operations.
- */
-int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
-                                 int addr, u8 *subfeature_param)
-{
-       return -ENOTSUPP;
-}
-EXPORT_SYMBOL(nand_get_set_features_notsupp);
-
 /**
  * nand_suspend - [MTD Interface] Suspend the NAND flash
  * @mtd: MTD device structure
@@ -4960,44 +4358,7 @@ static void nand_shutdown(struct mtd_info *mtd)
 /* Set default functions */
 static void nand_set_defaults(struct nand_chip *chip)
 {
-       unsigned int busw = chip->options & NAND_BUSWIDTH_16;
-
-       /* check for proper chip_delay setup, set 20us if not */
-       if (!chip->chip_delay)
-               chip->chip_delay = 20;
-
-       /* check, if a user supplied command function given */
-       if (!chip->cmdfunc && !chip->exec_op)
-               chip->cmdfunc = nand_command;
-
-       /* check, if a user supplied wait function given */
-       if (chip->waitfunc == NULL)
-               chip->waitfunc = nand_wait;
-
-       if (!chip->select_chip)
-               chip->select_chip = nand_select_chip;
-
-       /* set for ONFI nand */
-       if (!chip->set_features)
-               chip->set_features = nand_default_set_features;
-       if (!chip->get_features)
-               chip->get_features = nand_default_get_features;
-
-       /* If called twice, pointers that depend on busw may need to be reset */
-       if (!chip->read_byte || chip->read_byte == nand_read_byte)
-               chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
-       if (!chip->read_word)
-               chip->read_word = nand_read_word;
-       if (!chip->block_bad)
-               chip->block_bad = nand_block_bad;
-       if (!chip->block_markbad)
-               chip->block_markbad = nand_default_block_markbad;
-       if (!chip->write_buf || chip->write_buf == nand_write_buf)
-               chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
-       if (!chip->write_byte || chip->write_byte == nand_write_byte)
-               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;
+       nand_legacy_set_defaults(chip);
 
        if (!chip->controller) {
                chip->controller = &chip->dummy_controller;
@@ -5009,7 +4370,7 @@ static void nand_set_defaults(struct nand_chip *chip)
 }
 
 /* Sanitize ONFI strings so we can safely print them */
-static void sanitize_string(uint8_t *s, size_t len)
+void sanitize_string(uint8_t *s, size_t len)
 {
        ssize_t i;
 
@@ -5026,390 +4387,6 @@ static void sanitize_string(uint8_t *s, size_t len)
        strim(s);
 }
 
-static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
-{
-       int i;
-       while (len--) {
-               crc ^= *p++ << 8;
-               for (i = 0; i < 8; i++)
-                       crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
-       }
-
-       return crc;
-}
-
-/* Parse the Extended Parameter Page. */
-static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
-                                           struct nand_onfi_params *p)
-{
-       struct onfi_ext_param_page *ep;
-       struct onfi_ext_section *s;
-       struct onfi_ext_ecc_info *ecc;
-       uint8_t *cursor;
-       int ret;
-       int len;
-       int i;
-
-       len = le16_to_cpu(p->ext_param_page_length) * 16;
-       ep = kmalloc(len, GFP_KERNEL);
-       if (!ep)
-               return -ENOMEM;
-
-       /* Send our own NAND_CMD_PARAM. */
-       ret = nand_read_param_page_op(chip, 0, NULL, 0);
-       if (ret)
-               goto ext_out;
-
-       /* Use the Change Read Column command to skip the ONFI param pages. */
-       ret = nand_change_read_column_op(chip,
-                                        sizeof(*p) * p->num_of_param_pages,
-                                        ep, len, true);
-       if (ret)
-               goto ext_out;
-
-       ret = -EINVAL;
-       if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
-               != le16_to_cpu(ep->crc))) {
-               pr_debug("fail in the CRC.\n");
-               goto ext_out;
-       }
-
-       /*
-        * Check the signature.
-        * Do not strictly follow the ONFI spec, maybe changed in future.
-        */
-       if (strncmp(ep->sig, "EPPS", 4)) {
-               pr_debug("The signature is invalid.\n");
-               goto ext_out;
-       }
-
-       /* find the ECC section. */
-       cursor = (uint8_t *)(ep + 1);
-       for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
-               s = ep->sections + i;
-               if (s->type == ONFI_SECTION_TYPE_2)
-                       break;
-               cursor += s->length * 16;
-       }
-       if (i == ONFI_EXT_SECTION_MAX) {
-               pr_debug("We can not find the ECC section.\n");
-               goto ext_out;
-       }
-
-       /* get the info we want. */
-       ecc = (struct onfi_ext_ecc_info *)cursor;
-
-       if (!ecc->codeword_size) {
-               pr_debug("Invalid codeword size\n");
-               goto ext_out;
-       }
-
-       chip->ecc_strength_ds = ecc->ecc_bits;
-       chip->ecc_step_ds = 1 << ecc->codeword_size;
-       ret = 0;
-
-ext_out:
-       kfree(ep);
-       return ret;
-}
-
-/*
- * Recover data with bit-wise majority
- */
-static void nand_bit_wise_majority(const void **srcbufs,
-                                  unsigned int nsrcbufs,
-                                  void *dstbuf,
-                                  unsigned int bufsize)
-{
-       int i, j, k;
-
-       for (i = 0; i < bufsize; i++) {
-               u8 val = 0;
-
-               for (j = 0; j < 8; j++) {
-                       unsigned int cnt = 0;
-
-                       for (k = 0; k < nsrcbufs; k++) {
-                               const u8 *srcbuf = srcbufs[k];
-
-                               if (srcbuf[i] & BIT(j))
-                                       cnt++;
-                       }
-
-                       if (cnt > nsrcbufs / 2)
-                               val |= BIT(j);
-               }
-
-               ((u8 *)dstbuf)[i] = val;
-       }
-}
-
-/*
- * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
- */
-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;
-
-       /* Try ONFI for unknown chip or LP */
-       ret = nand_readid_op(chip, 0x20, id, sizeof(id));
-       if (ret || strncmp(id, "ONFI", 4))
-               return 0;
-
-       /* ONFI chip: allocate a buffer to hold its parameter page */
-       p = kzalloc((sizeof(*p) * 3), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-
-       ret = nand_read_param_page_op(chip, 0, NULL, 0);
-       if (ret) {
-               ret = 0;
-               goto free_onfi_param_page;
-       }
-
-       for (i = 0; i < 3; i++) {
-               ret = nand_read_data_op(chip, &p[i], sizeof(*p), true);
-               if (ret) {
-                       ret = 0;
-                       goto free_onfi_param_page;
-               }
-
-               if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) ==
-                               le16_to_cpu(p->crc)) {
-                       if (i)
-                               memcpy(p, &p[i], sizeof(*p));
-                       break;
-               }
-       }
-
-       if (i == 3) {
-               const void *srcbufs[3] = {p, p + 1, p + 2};
-
-               pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n");
-               nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p,
-                                      sizeof(*p));
-
-               if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) !=
-                               le16_to_cpu(p->crc)) {
-                       pr_err("ONFI parameter recovery failed, aborting\n");
-                       goto free_onfi_param_page;
-               }
-       }
-
-       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 & 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;
-       }
-
-       sanitize_string(p->manufacturer, sizeof(p->manufacturer));
-       sanitize_string(p->model, sizeof(p->model));
-       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);
-
-       /*
-        * pages_per_block and blocks_per_lun may not be a power-of-2 size
-        * (don't ask me who thought of this...). MTD assumes that these
-        * dimensions will be power-of-2, so just truncate the remaining area.
-        */
-       mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
-       mtd->erasesize *= mtd->writesize;
-
-       mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
-
-       /* See erasesize comment */
-       chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
-       chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
-       chip->bits_per_cell = p->bits_per_cell;
-
-       chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
-       chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
-
-       if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
-               chip->options |= NAND_BUSWIDTH_16;
-
-       if (p->ecc_bits != 0xff) {
-               chip->ecc_strength_ds = p->ecc_bits;
-               chip->ecc_step_ds = 512;
-       } else if (onfi_version >= 21 &&
-               (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
-
-               /*
-                * The nand_flash_detect_ext_param_page() uses the
-                * Change Read Column command which maybe not supported
-                * by the chip->cmdfunc. So try to update the chip->cmdfunc
-                * now. We do not replace user supplied command function.
-                */
-               if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
-                       chip->cmdfunc = nand_command_lp;
-
-               /* The Extended Parameter Page is supported since ONFI 2.1. */
-               if (nand_flash_detect_ext_param_page(chip, p))
-                       pr_warn("Failed to detect ONFI extended param page\n");
-       } else {
-               pr_warn("Could not retrieve ONFI ECC requirements\n");
-       }
-
-       /* Save some parameters from the parameter page for future use */
-       if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
-               chip->parameters.supports_set_get_features = true;
-               bitmap_set(chip->parameters.get_feature_list,
-                          ONFI_FEATURE_ADDR_TIMING_MODE, 1);
-               bitmap_set(chip->parameters.set_feature_list,
-                          ONFI_FEATURE_ADDR_TIMING_MODE, 1);
-       }
-
-       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;
-}
-
-/*
- * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
- */
-static int nand_flash_detect_jedec(struct nand_chip *chip)
-{
-       struct mtd_info *mtd = nand_to_mtd(chip);
-       struct nand_jedec_params *p;
-       struct jedec_ecc_info *ecc;
-       int jedec_version = 0;
-       char id[5];
-       int i, val, ret;
-
-       /* Try JEDEC for unknown chip or LP */
-       ret = nand_readid_op(chip, 0x40, id, sizeof(id));
-       if (ret || strncmp(id, "JEDEC", sizeof(id)))
-               return 0;
-
-       /* JEDEC chip: allocate a buffer to hold its parameter page */
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-
-       ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
-       if (ret) {
-               ret = 0;
-               goto free_jedec_param_page;
-       }
-
-       for (i = 0; i < 3; i++) {
-               ret = nand_read_data_op(chip, p, sizeof(*p), true);
-               if (ret) {
-                       ret = 0;
-                       goto free_jedec_param_page;
-               }
-
-               if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
-                               le16_to_cpu(p->crc))
-                       break;
-       }
-
-       if (i == 3) {
-               pr_err("Could not find valid JEDEC parameter page; aborting\n");
-               goto free_jedec_param_page;
-       }
-
-       /* Check version */
-       val = le16_to_cpu(p->revision);
-       if (val & (1 << 2))
-               jedec_version = 10;
-       else if (val & (1 << 1))
-               jedec_version = 1; /* vendor specific version */
-
-       if (!jedec_version) {
-               pr_info("unsupported JEDEC version: %d\n", val);
-               goto free_jedec_param_page;
-       }
-
-       sanitize_string(p->manufacturer, sizeof(p->manufacturer));
-       sanitize_string(p->model, sizeof(p->model));
-       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);
-
-       /* Please reference to the comment for nand_flash_detect_onfi. */
-       mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
-       mtd->erasesize *= mtd->writesize;
-
-       mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
-
-       /* Please reference to the comment for nand_flash_detect_onfi. */
-       chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
-       chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
-       chip->bits_per_cell = p->bits_per_cell;
-
-       if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
-               chip->options |= NAND_BUSWIDTH_16;
-
-       /* ECC info */
-       ecc = &p->ecc_info[0];
-
-       if (ecc->codeword_size >= 9) {
-               chip->ecc_strength_ds = ecc->ecc_bits;
-               chip->ecc_step_ds = 1 << ecc->codeword_size;
-       } else {
-               pr_warn("Invalid codeword size\n");
-       }
-
-free_jedec_param_page:
-       kfree(p);
-       return ret;
-}
-
 /*
  * nand_id_has_period - Check if an ID string has a given wraparound period
  * @id_data: the ID string
@@ -5625,6 +4602,12 @@ static void nand_manufacturer_cleanup(struct nand_chip *chip)
                chip->manufacturer.desc->ops->cleanup(chip);
 }
 
+static const char *
+nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
+{
+       return manufacturer ? manufacturer->name : "Unknown";
+}
+
 /*
  * Get the flash and manufacturer id and lookup if the type is supported.
  */
@@ -5645,7 +4628,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
                return ret;
 
        /* Select the device */
-       chip->select_chip(mtd, 0);
+       chip->select_chip(chip, 0);
 
        /* Send the command for reading device ID */
        ret = nand_readid_op(chip, 0, id_data, 2);
@@ -5709,14 +4692,14 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
 
        if (!type->name || !type->pagesize) {
                /* Check if the chip is ONFI compliant */
-               ret = nand_flash_detect_onfi(chip);
+               ret = nand_onfi_detect(chip);
                if (ret < 0)
                        return ret;
                else if (ret)
                        goto ident_done;
 
                /* Check if the chip is JEDEC compliant */
-               ret = nand_flash_detect_jedec(chip);
+               ret = nand_jedec_detect(chip);
                if (ret < 0)
                        return ret;
                else if (ret)
@@ -5783,11 +4766,8 @@ ident_done:
                chip->options |= NAND_ROW_ADDR_3;
 
        chip->badblockbits = 8;
-       chip->erase = single_erase;
 
-       /* Do not replace user supplied command function! */
-       if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
-               chip->cmdfunc = nand_command_lp;
+       nand_legacy_adjust_cmdfunc(chip);
 
        pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
                maf_id, dev_id);
@@ -5953,7 +4933,7 @@ static int nand_dt_init(struct nand_chip *chip)
 
 /**
  * nand_scan_ident - Scan for the NAND device
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @maxchips: number of chips to scan for
  * @table: alternative NAND ID table
  *
@@ -5965,11 +4945,12 @@ static int nand_dt_init(struct nand_chip *chip)
  * prevented dynamic allocations during this phase which was unconvenient and
  * as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks.
  */
-static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
                           struct nand_flash_dev *table)
 {
-       int i, nand_maf_id, nand_dev_id;
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int nand_maf_id, nand_dev_id;
+       unsigned int i;
        int ret;
 
        /* Enforce the right timings for reset/detection */
@@ -5982,21 +4963,15 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        if (!mtd->name && mtd->dev.parent)
                mtd->name = dev_name(mtd->dev.parent);
 
-       /*
-        * ->cmdfunc() is legacy and will only be used if ->exec_op() is not
-        * populated.
-        */
-       if (!chip->exec_op) {
-               /*
-                * Default functions assigned for ->cmdfunc() and
-                * ->select_chip() both expect ->cmd_ctrl() to be populated.
-                */
-               if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
-                       pr_err("->cmd_ctrl() should be provided\n");
-                       return -EINVAL;
-               }
+       if (chip->exec_op && !chip->select_chip) {
+               pr_err("->select_chip() is mandatory when implementing ->exec_op()\n");
+               return -EINVAL;
        }
 
+       ret = nand_legacy_check_hooks(chip);
+       if (ret)
+               return ret;
+
        /* Set the default functions */
        nand_set_defaults(chip);
 
@@ -6005,14 +4980,14 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
        if (ret) {
                if (!(chip->options & NAND_SCAN_SILENT_NODEV))
                        pr_warn("No NAND device found\n");
-               chip->select_chip(mtd, -1);
+               chip->select_chip(chip, -1);
                return ret;
        }
 
        nand_maf_id = chip->id.data[0];
        nand_dev_id = chip->id.data[1];
 
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
 
        /* Check for a chip array */
        for (i = 1; i < maxchips; i++) {
@@ -6021,15 +4996,15 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                /* See comment in nand_get_flash_type for reset */
                nand_reset(chip, i);
 
-               chip->select_chip(mtd, i);
+               chip->select_chip(chip, i);
                /* Send the command for reading device ID */
                nand_readid_op(chip, 0, id, sizeof(id));
                /* Read manufacturer and device IDs */
                if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
-                       chip->select_chip(mtd, -1);
+                       chip->select_chip(chip, -1);
                        break;
                }
-               chip->select_chip(mtd, -1);
+               chip->select_chip(chip, -1);
        }
        if (i > 1)
                pr_info("%d chips detected\n", i);
@@ -6070,6 +5045,10 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
                        ecc->size = 256;
                ecc->bytes = 3;
                ecc->strength = 1;
+
+               if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC))
+                       ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
                return 0;
        case NAND_ECC_BCH:
                if (!mtd_nand_has_bch()) {
@@ -6423,15 +5402,15 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
 
 /**
  * nand_scan_tail - Scan for the NAND device
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  *
  * 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.
  */
-static int nand_scan_tail(struct mtd_info *mtd)
+static int nand_scan_tail(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        int ret, i;
 
@@ -6451,9 +5430,9 @@ static int nand_scan_tail(struct mtd_info *mtd)
         * to explictly select the relevant die when interacting with the NAND
         * chip.
         */
-       chip->select_chip(mtd, 0);
+       chip->select_chip(chip, 0);
        ret = nand_manufacturer_init(chip);
-       chip->select_chip(mtd, -1);
+       chip->select_chip(chip, -1);
        if (ret)
                goto err_free_buf;
 
@@ -6770,33 +5749,31 @@ static void nand_detach(struct nand_chip *chip)
 
 /**
  * nand_scan_with_ids - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- * @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).
+ * @chip: NAND chip object
+ * @maxchips: number of chips to scan for.
  * @ids: optional flash IDs table
  *
  * This fills out all the uninitialized function pointers with the defaults.
  * The flash ID is read and the mtd/chip structures are filled with the
  * appropriate values.
  */
-int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
+int nand_scan_with_ids(struct nand_chip *chip, unsigned int maxchips,
                       struct nand_flash_dev *ids)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        int ret;
 
-       if (maxchips) {
-               ret = nand_scan_ident(mtd, maxchips, ids);
-               if (ret)
-                       return ret;
-       }
+       if (!maxchips)
+               return -EINVAL;
+
+       ret = nand_scan_ident(chip, maxchips, ids);
+       if (ret)
+               return ret;
 
        ret = nand_attach(chip);
        if (ret)
                goto cleanup_ident;
 
-       ret = nand_scan_tail(mtd);
+       ret = nand_scan_tail(chip);
        if (ret)
                goto detach_chip;
 
@@ -6847,12 +5824,12 @@ EXPORT_SYMBOL_GPL(nand_cleanup);
 /**
  * nand_release - [NAND Interface] Unregister the MTD device and free resources
  *               held by the NAND device
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  */
-void nand_release(struct mtd_info *mtd)
+void nand_release(struct nand_chip *chip)
 {
-       mtd_device_unregister(mtd);
-       nand_cleanup(mtd_to_nand(mtd));
+       mtd_device_unregister(nand_to_mtd(chip));
+       nand_cleanup(chip);
 }
 EXPORT_SYMBOL_GPL(nand_release);
 
index 39db352f8757b77d50c4638505270af69677f9be..98a826838b609c0912cbacb1fb9997ca302727a4 100644 (file)
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/bbm.h>
-#include <linux/mtd/rawnand.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/vmalloc.h>
 #include <linux/export.h>
 #include <linux/string.h>
 
+#include "internals.h"
+
 #define BBT_BLOCK_GOOD         0x00
 #define BBT_BLOCK_WORN         0x01
 #define BBT_BLOCK_RESERVED     0x02
@@ -683,14 +684,13 @@ static void mark_bbt_block_bad(struct nand_chip *this,
                               struct nand_bbt_descr *td,
                               int chip, int block)
 {
-       struct mtd_info *mtd = nand_to_mtd(this);
        loff_t to;
        int res;
 
        bbt_mark_entry(this, block, BBT_BLOCK_WORN);
 
        to = (loff_t)block << this->bbt_erase_shift;
-       res = this->block_markbad(mtd, to);
+       res = nand_markbad_bbm(this, to);
        if (res)
                pr_warn("nand_bbt: error %d while marking block %d bad\n",
                        res, block);
@@ -854,7 +854,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                memset(&einfo, 0, sizeof(einfo));
                einfo.addr = to;
                einfo.len = 1 << this->bbt_erase_shift;
-               res = nand_erase_nand(mtd, &einfo, 1);
+               res = nand_erase_nand(this, &einfo, 1);
                if (res < 0) {
                        pr_warn("nand_bbt: error while erasing BBT block %d\n",
                                res);
@@ -1388,12 +1388,11 @@ EXPORT_SYMBOL(nand_create_bbt);
 
 /**
  * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @offs: offset in the device
  */
-int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_isreserved_bbt(struct nand_chip *this, loff_t offs)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        int block;
 
        block = (int)(offs >> this->bbt_erase_shift);
@@ -1402,13 +1401,12 @@ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
 
 /**
  * nand_isbad_bbt - [NAND Interface] Check if a block is bad
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @offs: offset in the device
  * @allowbbt: allow access to bad block table region
  */
-int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
        int block, res;
 
        block = (int)(offs >> this->bbt_erase_shift);
@@ -1430,12 +1428,12 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
 
 /**
  * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
- * @mtd: MTD device structure
+ * @this: NAND chip object
  * @offs: offset of the bad block
  */
-int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_markbad_bbt(struct nand_chip *this, loff_t offs)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(this);
        int block, ret = 0;
 
        block = (int)(offs >> this->bbt_erase_shift);
index b7387ace567a4b249b14ad2ae5f28a2db53e442f..574c0ca16160c0c0e841ff0a71dcdb88fe321a54 100644 (file)
@@ -43,14 +43,13 @@ struct nand_bch_control {
 
 /**
  * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
- * @mtd:       MTD block structure
+ * @chip:      NAND chip object
  * @buf:       input buffer with raw data
  * @code:      output buffer with ECC
  */
-int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+int nand_bch_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
                           unsigned char *code)
 {
-       const struct nand_chip *chip = mtd_to_nand(mtd);
        struct nand_bch_control *nbc = chip->ecc.priv;
        unsigned int i;
 
@@ -67,17 +66,16 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc);
 
 /**
  * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @mtd:       MTD block structure
+ * @chip:      NAND chip object
  * @buf:       raw data read from the chip
  * @read_ecc:  ECC from the chip
  * @calc_ecc:  the ECC calculated from raw data
  *
  * Detect and correct bit errors for a data byte block
  */
-int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+int nand_bch_correct_data(struct nand_chip *chip, unsigned char *buf,
                          unsigned char *read_ecc, unsigned char *calc_ecc)
 {
-       const struct nand_chip *chip = mtd_to_nand(mtd);
        struct nand_bch_control *nbc = chip->ecc.priv;
        unsigned int *errloc = nbc->errloc;
        int i, count;
index 8e132edbc5ce96c7f1e1e90658db450a830145e8..4f434753305865d672c79a703219d56a953557b6 100644 (file)
@@ -132,9 +132,10 @@ static const char addressbits[256] = {
  * @buf:       input buffer with raw data
  * @eccsize:   data bytes per ECC step (256 or 512)
  * @code:      output buffer with ECC
+ * @sm_order:  Smart Media byte ordering
  */
 void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
-                      unsigned char *code)
+                         unsigned char *code, bool sm_order)
 {
        int i;
        const uint32_t *bp = (uint32_t *)buf;
@@ -330,45 +331,26 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
         * possible, but benchmarks showed that on the system this is developed
         * the code below is the fastest
         */
-#ifdef CONFIG_MTD_NAND_ECC_SMC
-       code[0] =
-           (invparity[rp7] << 7) |
-           (invparity[rp6] << 6) |
-           (invparity[rp5] << 5) |
-           (invparity[rp4] << 4) |
-           (invparity[rp3] << 3) |
-           (invparity[rp2] << 2) |
-           (invparity[rp1] << 1) |
-           (invparity[rp0]);
-       code[1] =
-           (invparity[rp15] << 7) |
-           (invparity[rp14] << 6) |
-           (invparity[rp13] << 5) |
-           (invparity[rp12] << 4) |
-           (invparity[rp11] << 3) |
-           (invparity[rp10] << 2) |
-           (invparity[rp9] << 1)  |
-           (invparity[rp8]);
-#else
-       code[1] =
-           (invparity[rp7] << 7) |
-           (invparity[rp6] << 6) |
-           (invparity[rp5] << 5) |
-           (invparity[rp4] << 4) |
-           (invparity[rp3] << 3) |
-           (invparity[rp2] << 2) |
-           (invparity[rp1] << 1) |
-           (invparity[rp0]);
-       code[0] =
-           (invparity[rp15] << 7) |
-           (invparity[rp14] << 6) |
-           (invparity[rp13] << 5) |
-           (invparity[rp12] << 4) |
-           (invparity[rp11] << 3) |
-           (invparity[rp10] << 2) |
-           (invparity[rp9] << 1)  |
-           (invparity[rp8]);
-#endif
+       if (sm_order) {
+               code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
+                         (invparity[rp5] << 5) | (invparity[rp4] << 4) |
+                         (invparity[rp3] << 3) | (invparity[rp2] << 2) |
+                         (invparity[rp1] << 1) | (invparity[rp0]);
+               code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
+                         (invparity[rp13] << 5) | (invparity[rp12] << 4) |
+                         (invparity[rp11] << 3) | (invparity[rp10] << 2) |
+                         (invparity[rp9] << 1) | (invparity[rp8]);
+       } else {
+               code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
+                         (invparity[rp5] << 5) | (invparity[rp4] << 4) |
+                         (invparity[rp3] << 3) | (invparity[rp2] << 2) |
+                         (invparity[rp1] << 1) | (invparity[rp0]);
+               code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
+                         (invparity[rp13] << 5) | (invparity[rp12] << 4) |
+                         (invparity[rp11] << 3) | (invparity[rp10] << 2) |
+                         (invparity[rp9] << 1) | (invparity[rp8]);
+       }
+
        if (eccsize_mult == 1)
                code[2] =
                    (invparity[par & 0xf0] << 7) |
@@ -394,15 +376,16 @@ EXPORT_SYMBOL(__nand_calculate_ecc);
 /**
  * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
  *                      block
- * @mtd:       MTD block structure
+ * @chip:      NAND chip object
  * @buf:       input buffer with raw data
  * @code:      output buffer with ECC
  */
-int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
                       unsigned char *code)
 {
-       __nand_calculate_ecc(buf,
-                       mtd_to_nand(mtd)->ecc.size, code);
+       bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
+       __nand_calculate_ecc(buf, chip->ecc.size, code, sm_order);
 
        return 0;
 }
@@ -414,12 +397,13 @@ EXPORT_SYMBOL(nand_calculate_ecc);
  * @read_ecc:  ECC from the chip
  * @calc_ecc:  the ECC calculated from raw data
  * @eccsize:   data bytes per ECC step (256 or 512)
+ * @sm_order:  Smart Media byte order
  *
  * Detect and correct a 1 bit error for eccsize byte block
  */
 int __nand_correct_data(unsigned char *buf,
                        unsigned char *read_ecc, unsigned char *calc_ecc,
-                       unsigned int eccsize)
+                       unsigned int eccsize, bool sm_order)
 {
        unsigned char b0, b1, b2, bit_addr;
        unsigned int byte_addr;
@@ -431,13 +415,14 @@ int __nand_correct_data(unsigned char *buf,
         * we might need the xor result  more than once,
         * so keep them in a local var
        */
-#ifdef CONFIG_MTD_NAND_ECC_SMC
-       b0 = read_ecc[0] ^ calc_ecc[0];
-       b1 = read_ecc[1] ^ calc_ecc[1];
-#else
-       b0 = read_ecc[1] ^ calc_ecc[1];
-       b1 = read_ecc[0] ^ calc_ecc[0];
-#endif
+       if (sm_order) {
+               b0 = read_ecc[0] ^ calc_ecc[0];
+               b1 = read_ecc[1] ^ calc_ecc[1];
+       } else {
+               b0 = read_ecc[1] ^ calc_ecc[1];
+               b1 = read_ecc[0] ^ calc_ecc[0];
+       }
+
        b2 = read_ecc[2] ^ calc_ecc[2];
 
        /* check if there are any bitfaults */
@@ -491,18 +476,20 @@ EXPORT_SYMBOL(__nand_correct_data);
 
 /**
  * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @mtd:       MTD block structure
+ * @chip:      NAND chip object
  * @buf:       raw data read from the chip
  * @read_ecc:  ECC from the chip
  * @calc_ecc:  the ECC calculated from raw data
  *
  * Detect and correct a 1 bit error for 256/512 byte block
  */
-int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
+int nand_correct_data(struct nand_chip *chip, unsigned char *buf,
                      unsigned char *read_ecc, unsigned char *calc_ecc)
 {
-       return __nand_correct_data(buf, read_ecc, calc_ecc,
-                                  mtd_to_nand(mtd)->ecc.size);
+       bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
+       return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size,
+                                  sm_order);
 }
 EXPORT_SYMBOL(nand_correct_data);
 
diff --git a/drivers/mtd/nand/raw/nand_esmt.c b/drivers/mtd/nand/raw/nand_esmt.c
new file mode 100644 (file)
index 0000000..96f039a
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Toradex AG
+ *
+ * Author: Marcel Ziswiler <marcel.ziswiler@toradex.com>
+ */
+
+#include <linux/mtd/rawnand.h>
+#include "internals.h"
+
+static void esmt_nand_decode_id(struct nand_chip *chip)
+{
+       nand_decode_ext_id(chip);
+
+       /* Extract ECC requirements from 5th id byte. */
+       if (chip->id.len >= 5 && nand_is_slc(chip)) {
+               chip->ecc_step_ds = 512;
+               switch (chip->id.data[4] & 0x3) {
+               case 0x0:
+                       chip->ecc_strength_ds = 4;
+                       break;
+               case 0x1:
+                       chip->ecc_strength_ds = 2;
+                       break;
+               case 0x2:
+                       chip->ecc_strength_ds = 1;
+                       break;
+               default:
+                       WARN(1, "Could not get ECC info");
+                       chip->ecc_step_ds = 0;
+                       break;
+               }
+       }
+}
+
+static int esmt_nand_init(struct nand_chip *chip)
+{
+       if (nand_is_slc(chip))
+               chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+       return 0;
+}
+
+const struct nand_manufacturer_ops esmt_nand_manuf_ops = {
+       .detect = esmt_nand_decode_id,
+       .init = esmt_nand_init,
+};
index 4ffbb26e76d6dad05be6418c2ac31c091eae1b36..ac1b5c1039684f56d1a23cdeec00c022fd61ba7c 100644 (file)
  * GNU General Public License for more details.
  */
 
-#include <linux/mtd/rawnand.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
 
+#include "internals.h"
+
 #define NAND_HYNIX_CMD_SET_PARAMS      0x36
 #define NAND_HYNIX_CMD_APPLY_PARAMS    0x16
 
@@ -79,8 +80,6 @@ static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
 
 static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
        if (chip->exec_op) {
                struct nand_op_instr instrs[] = {
                        NAND_OP_CMD(cmd, 0),
@@ -90,14 +89,13 @@ static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, cmd, -1, -1);
+       chip->legacy.cmdfunc(chip, cmd, -1, -1);
 
        return 0;
 }
 
 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) {
@@ -110,15 +108,14 @@ static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
                return nand_exec_op(chip, &op);
        }
 
-       chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
-       chip->write_byte(mtd, val);
+       chip->legacy.cmdfunc(chip, NAND_CMD_NONE, column, -1);
+       chip->legacy.write_byte(chip, val);
 
        return 0;
 }
 
-static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+static int hynix_nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
        const u8 *values;
        int i, ret;
index 5423c3bb388e560b4746f9581a622956ff53c14f..ea5a342cd91e5376a2693cef5583e0f7364f0131 100644 (file)
@@ -6,9 +6,11 @@
  * published by the Free Software Foundation.
  *
  */
-#include <linux/mtd/rawnand.h>
+
 #include <linux/sizes.h>
 
+#include "internals.h"
+
 #define LP_OPTIONS 0
 #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
 
@@ -169,21 +171,21 @@ struct nand_flash_dev nand_flash_ids[] = {
 
 /* Manufacturer IDs */
 static const struct nand_manufacturer nand_manufacturers[] = {
-       {NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
-       {NAND_MFR_ESMT, "ESMT"},
-       {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
+       {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
+       {NAND_MFR_ATO, "ATO"},
+       {NAND_MFR_EON, "Eon"},
+       {NAND_MFR_ESMT, "ESMT", &esmt_nand_manuf_ops},
        {NAND_MFR_FUJITSU, "Fujitsu"},
-       {NAND_MFR_NATIONAL, "National"},
-       {NAND_MFR_RENESAS, "Renesas"},
-       {NAND_MFR_STMICRO, "ST Micro"},
        {NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
-       {NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
-       {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
+       {NAND_MFR_INTEL, "Intel"},
        {NAND_MFR_MACRONIX, "Macronix", &macronix_nand_manuf_ops},
-       {NAND_MFR_EON, "Eon"},
+       {NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
+       {NAND_MFR_NATIONAL, "National"},
+       {NAND_MFR_RENESAS, "Renesas"},
+       {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
        {NAND_MFR_SANDISK, "SanDisk"},
-       {NAND_MFR_INTEL, "Intel"},
-       {NAND_MFR_ATO, "ATO"},
+       {NAND_MFR_STMICRO, "ST Micro"},
+       {NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
        {NAND_MFR_WINBOND, "Winbond"},
 };
 
diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c
new file mode 100644 (file)
index 0000000..5c26492
--- /dev/null
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ *               2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *  Credits:
+ *     David Woodhouse for adding multichip support
+ *
+ *     Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ *     rework for 2K page size chips
+ *
+ * This file contains all ONFI helpers.
+ */
+
+#include <linux/slab.h>
+
+#include "internals.h"
+
+/*
+ * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
+ */
+int nand_jedec_detect(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       struct nand_jedec_params *p;
+       struct jedec_ecc_info *ecc;
+       int jedec_version = 0;
+       char id[5];
+       int i, val, ret;
+
+       /* Try JEDEC for unknown chip or LP */
+       ret = nand_readid_op(chip, 0x40, id, sizeof(id));
+       if (ret || strncmp(id, "JEDEC", sizeof(id)))
+               return 0;
+
+       /* JEDEC chip: allocate a buffer to hold its parameter page */
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
+       if (ret) {
+               ret = 0;
+               goto free_jedec_param_page;
+       }
+
+       for (i = 0; i < 3; i++) {
+               ret = nand_read_data_op(chip, p, sizeof(*p), true);
+               if (ret) {
+                       ret = 0;
+                       goto free_jedec_param_page;
+               }
+
+               if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
+                               le16_to_cpu(p->crc))
+                       break;
+       }
+
+       if (i == 3) {
+               pr_err("Could not find valid JEDEC parameter page; aborting\n");
+               goto free_jedec_param_page;
+       }
+
+       /* Check version */
+       val = le16_to_cpu(p->revision);
+       if (val & (1 << 2))
+               jedec_version = 10;
+       else if (val & (1 << 1))
+               jedec_version = 1; /* vendor specific version */
+
+       if (!jedec_version) {
+               pr_info("unsupported JEDEC version: %d\n", val);
+               goto free_jedec_param_page;
+       }
+
+       sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+       sanitize_string(p->model, sizeof(p->model));
+       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);
+
+       /* Please reference to the comment for nand_flash_detect_onfi. */
+       mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+       mtd->erasesize *= mtd->writesize;
+
+       mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+       /* Please reference to the comment for nand_flash_detect_onfi. */
+       chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+       chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+       chip->bits_per_cell = p->bits_per_cell;
+
+       if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
+               chip->options |= NAND_BUSWIDTH_16;
+
+       /* ECC info */
+       ecc = &p->ecc_info[0];
+
+       if (ecc->codeword_size >= 9) {
+               chip->ecc_strength_ds = ecc->ecc_bits;
+               chip->ecc_step_ds = 1 << ecc->codeword_size;
+       } else {
+               pr_warn("Invalid codeword size\n");
+       }
+
+free_jedec_param_page:
+       kfree(p);
+       return ret;
+}
diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c
new file mode 100644 (file)
index 0000000..c5ddc86
--- /dev/null
@@ -0,0 +1,642 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ *               2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *  Credits:
+ *     David Woodhouse for adding multichip support
+ *
+ *     Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ *     rework for 2K page size chips
+ *
+ * This file contains all legacy helpers/code that should be removed
+ * at some point.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/nmi.h>
+
+#include "internals.h"
+
+/**
+ * nand_read_byte - [DEFAULT] read one byte from the chip
+ * @chip: NAND chip object
+ *
+ * Default read function for 8bit buswidth
+ */
+static uint8_t nand_read_byte(struct nand_chip *chip)
+{
+       return readb(chip->legacy.IO_ADDR_R);
+}
+
+/**
+ * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
+ * @chip: NAND chip object
+ *
+ * Default read function for 16bit buswidth with endianness conversion.
+ *
+ */
+static uint8_t nand_read_byte16(struct nand_chip *chip)
+{
+       return (uint8_t) cpu_to_le16(readw(chip->legacy.IO_ADDR_R));
+}
+
+/**
+ * nand_select_chip - [DEFAULT] control CE line
+ * @chip: NAND chip object
+ * @chipnr: chipnumber to select, -1 for deselect
+ *
+ * Default select function for 1 chip devices.
+ */
+static void nand_select_chip(struct nand_chip *chip, int chipnr)
+{
+       switch (chipnr) {
+       case -1:
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+                                     0 | NAND_CTRL_CHANGE);
+               break;
+       case 0:
+               break;
+
+       default:
+               BUG();
+       }
+}
+
+/**
+ * nand_write_byte - [DEFAULT] write single byte to chip
+ * @chip: NAND chip object
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0]
+ */
+static void nand_write_byte(struct nand_chip *chip, uint8_t byte)
+{
+       chip->legacy.write_buf(chip, &byte, 1);
+}
+
+/**
+ * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
+ * @chip: NAND chip object
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
+ */
+static void nand_write_byte16(struct nand_chip *chip, uint8_t byte)
+{
+       uint16_t word = byte;
+
+       /*
+        * It's not entirely clear what should happen to I/O[15:8] when writing
+        * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
+        *
+        *    When the host supports a 16-bit bus width, only data is
+        *    transferred at the 16-bit width. All address and command line
+        *    transfers shall use only the lower 8-bits of the data bus. During
+        *    command transfers, the host may place any value on the upper
+        *    8-bits of the data bus. During address transfers, the host shall
+        *    set the upper 8-bits of the data bus to 00h.
+        *
+        * One user of the write_byte callback is nand_set_features. The
+        * four parameters are specified to be written to I/O[7:0], but this is
+        * neither an address nor a command transfer. Let's assume a 0 on the
+        * upper I/O lines is OK.
+        */
+       chip->legacy.write_buf(chip, (uint8_t *)&word, 2);
+}
+
+/**
+ * nand_write_buf - [DEFAULT] write buffer to chip
+ * @chip: NAND chip object
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 8bit buswidth.
+ */
+static void nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
+{
+       iowrite8_rep(chip->legacy.IO_ADDR_W, buf, len);
+}
+
+/**
+ * nand_read_buf - [DEFAULT] read chip data into buffer
+ * @chip: NAND chip object
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ *
+ * Default read function for 8bit buswidth.
+ */
+static void nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
+{
+       ioread8_rep(chip->legacy.IO_ADDR_R, buf, len);
+}
+
+/**
+ * nand_write_buf16 - [DEFAULT] write buffer to chip
+ * @chip: NAND chip object
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 16bit buswidth.
+ */
+static void nand_write_buf16(struct nand_chip *chip, const uint8_t *buf,
+                            int len)
+{
+       u16 *p = (u16 *) buf;
+
+       iowrite16_rep(chip->legacy.IO_ADDR_W, p, len >> 1);
+}
+
+/**
+ * nand_read_buf16 - [DEFAULT] read chip data into buffer
+ * @chip: NAND chip object
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ *
+ * Default read function for 16bit buswidth.
+ */
+static void nand_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
+{
+       u16 *p = (u16 *) buf;
+
+       ioread16_rep(chip->legacy.IO_ADDR_R, p, len >> 1);
+}
+
+/**
+ * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+ * @mtd: MTD device structure
+ * @timeo: Timeout
+ *
+ * Helper function for nand_wait_ready used when needing to wait in interrupt
+ * context.
+ */
+static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       int i;
+
+       /* Wait for the device to get ready */
+       for (i = 0; i < timeo; i++) {
+               if (chip->legacy.dev_ready(chip))
+                       break;
+               touch_softlockup_watchdog();
+               mdelay(1);
+       }
+}
+
+/**
+ * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+ * @chip: NAND chip object
+ *
+ * Wait for the ready pin after a command, and warn if a timeout occurs.
+ */
+void nand_wait_ready(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       unsigned long timeo = 400;
+
+       if (in_interrupt() || oops_in_progress)
+               return panic_nand_wait_ready(mtd, timeo);
+
+       /* Wait until command is processed or timeout occurs */
+       timeo = jiffies + msecs_to_jiffies(timeo);
+       do {
+               if (chip->legacy.dev_ready(chip))
+                       return;
+               cond_resched();
+       } while (time_before(jiffies, timeo));
+
+       if (!chip->legacy.dev_ready(chip))
+               pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
+}
+EXPORT_SYMBOL_GPL(nand_wait_ready);
+
+/**
+ * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
+ * @mtd: MTD device structure
+ * @timeo: Timeout in ms
+ *
+ * Wait for status ready (i.e. command done) or timeout.
+ */
+static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
+{
+       register struct nand_chip *chip = mtd_to_nand(mtd);
+       int ret;
+
+       timeo = jiffies + msecs_to_jiffies(timeo);
+       do {
+               u8 status;
+
+               ret = nand_read_data_op(chip, &status, sizeof(status), true);
+               if (ret)
+                       return;
+
+               if (status & NAND_STATUS_READY)
+                       break;
+               touch_softlockup_watchdog();
+       } while (time_before(jiffies, timeo));
+};
+
+/**
+ * nand_command - [DEFAULT] Send command to NAND device
+ * @chip: NAND chip object
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This function is used for small page devices
+ * (512 Bytes per page).
+ */
+static void nand_command(struct nand_chip *chip, unsigned int command,
+                        int column, int page_addr)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
+
+       /* Write out the command to the device */
+       if (command == NAND_CMD_SEQIN) {
+               int readcmd;
+
+               if (column >= mtd->writesize) {
+                       /* OOB area */
+                       column -= mtd->writesize;
+                       readcmd = NAND_CMD_READOOB;
+               } else if (column < 256) {
+                       /* First 256 bytes --> READ0 */
+                       readcmd = NAND_CMD_READ0;
+               } else {
+                       column -= 256;
+                       readcmd = NAND_CMD_READ1;
+               }
+               chip->legacy.cmd_ctrl(chip, readcmd, ctrl);
+               ctrl &= ~NAND_CTRL_CHANGE;
+       }
+       if (command != NAND_CMD_NONE)
+               chip->legacy.cmd_ctrl(chip, command, ctrl);
+
+       /* Address cycle, when necessary */
+       ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
+       /* Serially input address */
+       if (column != -1) {
+               /* Adjust columns for 16 bit buswidth */
+               if (chip->options & NAND_BUSWIDTH_16 &&
+                               !nand_opcode_8bits(command))
+                       column >>= 1;
+               chip->legacy.cmd_ctrl(chip, column, ctrl);
+               ctrl &= ~NAND_CTRL_CHANGE;
+       }
+       if (page_addr != -1) {
+               chip->legacy.cmd_ctrl(chip, page_addr, ctrl);
+               ctrl &= ~NAND_CTRL_CHANGE;
+               chip->legacy.cmd_ctrl(chip, page_addr >> 8, ctrl);
+               if (chip->options & NAND_ROW_ADDR_3)
+                       chip->legacy.cmd_ctrl(chip, page_addr >> 16, ctrl);
+       }
+       chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+                             NAND_NCE | NAND_CTRL_CHANGE);
+
+       /*
+        * Program and erase have their own busy handlers status and sequential
+        * in needs no delay
+        */
+       switch (command) {
+
+       case NAND_CMD_NONE:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_ERASE1:
+       case NAND_CMD_ERASE2:
+       case NAND_CMD_SEQIN:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_READID:
+       case NAND_CMD_SET_FEATURES:
+               return;
+
+       case NAND_CMD_RESET:
+               if (chip->legacy.dev_ready)
+                       break;
+               udelay(chip->legacy.chip_delay);
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS,
+                                     NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+                                     NAND_NCE | NAND_CTRL_CHANGE);
+               /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+               nand_wait_status_ready(mtd, 250);
+               return;
+
+               /* This applies to read commands */
+       case NAND_CMD_READ0:
+               /*
+                * READ0 is sometimes used to exit GET STATUS mode. When this
+                * is the case no address cycles are requested, and we can use
+                * this information to detect that we should not wait for the
+                * device to be ready.
+                */
+               if (column == -1 && page_addr == -1)
+                       return;
+
+       default:
+               /*
+                * If we don't have access to the busy pin, we apply the given
+                * command delay
+                */
+               if (!chip->legacy.dev_ready) {
+                       udelay(chip->legacy.chip_delay);
+                       return;
+               }
+       }
+       /*
+        * Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine.
+        */
+       ndelay(100);
+
+       nand_wait_ready(chip);
+}
+
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+       /*
+        * The controller already takes care of waiting for tCCS when the RNDIN
+        * or RNDOUT command is sent, return directly.
+        */
+       if (!(chip->options & NAND_WAIT_TCCS))
+               return;
+
+       /*
+        * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+        * (which should be safe for all NANDs).
+        */
+       if (chip->setup_data_interface)
+               ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
+       else
+               ndelay(500);
+}
+
+/**
+ * nand_command_lp - [DEFAULT] Send command to NAND large page device
+ * @chip: NAND chip object
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This is the version for the new large page
+ * devices. We don't have the separate regions as we have in the small page
+ * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
+ */
+static void nand_command_lp(struct nand_chip *chip, unsigned int command,
+                           int column, int page_addr)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
+       /* Emulate NAND_CMD_READOOB */
+       if (command == NAND_CMD_READOOB) {
+               column += mtd->writesize;
+               command = NAND_CMD_READ0;
+       }
+
+       /* Command latch cycle */
+       if (command != NAND_CMD_NONE)
+               chip->legacy.cmd_ctrl(chip, command,
+                                     NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+       if (column != -1 || page_addr != -1) {
+               int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+               /* Serially input address */
+               if (column != -1) {
+                       /* Adjust columns for 16 bit buswidth */
+                       if (chip->options & NAND_BUSWIDTH_16 &&
+                                       !nand_opcode_8bits(command))
+                               column >>= 1;
+                       chip->legacy.cmd_ctrl(chip, column, ctrl);
+                       ctrl &= ~NAND_CTRL_CHANGE;
+
+                       /* Only output a single addr cycle for 8bits opcodes. */
+                       if (!nand_opcode_8bits(command))
+                               chip->legacy.cmd_ctrl(chip, column >> 8, ctrl);
+               }
+               if (page_addr != -1) {
+                       chip->legacy.cmd_ctrl(chip, page_addr, ctrl);
+                       chip->legacy.cmd_ctrl(chip, page_addr >> 8,
+                                            NAND_NCE | NAND_ALE);
+                       if (chip->options & NAND_ROW_ADDR_3)
+                               chip->legacy.cmd_ctrl(chip, page_addr >> 16,
+                                                     NAND_NCE | NAND_ALE);
+               }
+       }
+       chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+                             NAND_NCE | NAND_CTRL_CHANGE);
+
+       /*
+        * Program and erase have their own busy handlers status, sequential
+        * in and status need no delay.
+        */
+       switch (command) {
+
+       case NAND_CMD_NONE:
+       case NAND_CMD_CACHEDPROG:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_ERASE1:
+       case NAND_CMD_ERASE2:
+       case NAND_CMD_SEQIN:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_READID:
+       case NAND_CMD_SET_FEATURES:
+               return;
+
+       case NAND_CMD_RNDIN:
+               nand_ccs_delay(chip);
+               return;
+
+       case NAND_CMD_RESET:
+               if (chip->legacy.dev_ready)
+                       break;
+               udelay(chip->legacy.chip_delay);
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS,
+                                     NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+                                     NAND_NCE | NAND_CTRL_CHANGE);
+               /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+               nand_wait_status_ready(mtd, 250);
+               return;
+
+       case NAND_CMD_RNDOUT:
+               /* No ready / busy check necessary */
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_RNDOUTSTART,
+                                     NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+                                     NAND_NCE | NAND_CTRL_CHANGE);
+
+               nand_ccs_delay(chip);
+               return;
+
+       case NAND_CMD_READ0:
+               /*
+                * READ0 is sometimes used to exit GET STATUS mode. When this
+                * is the case no address cycles are requested, and we can use
+                * this information to detect that READSTART should not be
+                * issued.
+                */
+               if (column == -1 && page_addr == -1)
+                       return;
+
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_READSTART,
+                                     NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+               chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+                                     NAND_NCE | NAND_CTRL_CHANGE);
+
+               /* This applies to read commands */
+       default:
+               /*
+                * If we don't have access to the busy pin, we apply the given
+                * command delay.
+                */
+               if (!chip->legacy.dev_ready) {
+                       udelay(chip->legacy.chip_delay);
+                       return;
+               }
+       }
+
+       /*
+        * Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine.
+        */
+       ndelay(100);
+
+       nand_wait_ready(chip);
+}
+
+/**
+ * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ *
+ * Should be used by NAND controller drivers that do not support the SET/GET
+ * FEATURES operations.
+ */
+int nand_get_set_features_notsupp(struct nand_chip *chip, int addr,
+                                 u8 *subfeature_param)
+{
+       return -ENOTSUPP;
+}
+EXPORT_SYMBOL(nand_get_set_features_notsupp);
+
+/**
+ * nand_wait - [DEFAULT] wait until the command is done
+ * @mtd: MTD device structure
+ * @chip: NAND chip structure
+ *
+ * Wait for command done. This applies to erase and program only.
+ */
+static int nand_wait(struct nand_chip *chip)
+{
+
+       unsigned long timeo = 400;
+       u8 status;
+       int ret;
+
+       /*
+        * Apply this short delay always to ensure that we do wait tWB in any
+        * case on any machine.
+        */
+       ndelay(100);
+
+       ret = nand_status_op(chip, NULL);
+       if (ret)
+               return ret;
+
+       if (in_interrupt() || oops_in_progress)
+               panic_nand_wait(chip, timeo);
+       else {
+               timeo = jiffies + msecs_to_jiffies(timeo);
+               do {
+                       if (chip->legacy.dev_ready) {
+                               if (chip->legacy.dev_ready(chip))
+                                       break;
+                       } else {
+                               ret = nand_read_data_op(chip, &status,
+                                                       sizeof(status), true);
+                               if (ret)
+                                       return ret;
+
+                               if (status & NAND_STATUS_READY)
+                                       break;
+                       }
+                       cond_resched();
+               } while (time_before(jiffies, timeo));
+       }
+
+       ret = nand_read_data_op(chip, &status, sizeof(status), true);
+       if (ret)
+               return ret;
+
+       /* This can happen if in case of timeout or buggy dev_ready */
+       WARN_ON(!(status & NAND_STATUS_READY));
+       return status;
+}
+
+void nand_legacy_set_defaults(struct nand_chip *chip)
+{
+       unsigned int busw = chip->options & NAND_BUSWIDTH_16;
+
+       if (chip->exec_op)
+               return;
+
+       /* check for proper chip_delay setup, set 20us if not */
+       if (!chip->legacy.chip_delay)
+               chip->legacy.chip_delay = 20;
+
+       /* check, if a user supplied command function given */
+       if (!chip->legacy.cmdfunc && !chip->exec_op)
+               chip->legacy.cmdfunc = nand_command;
+
+       /* check, if a user supplied wait function given */
+       if (chip->legacy.waitfunc == NULL)
+               chip->legacy.waitfunc = nand_wait;
+
+       if (!chip->select_chip)
+               chip->select_chip = nand_select_chip;
+
+       /* If called twice, pointers that depend on busw may need to be reset */
+       if (!chip->legacy.read_byte || chip->legacy.read_byte == nand_read_byte)
+               chip->legacy.read_byte = busw ? nand_read_byte16 : nand_read_byte;
+       if (!chip->legacy.write_buf || chip->legacy.write_buf == nand_write_buf)
+               chip->legacy.write_buf = busw ? nand_write_buf16 : nand_write_buf;
+       if (!chip->legacy.write_byte || chip->legacy.write_byte == nand_write_byte)
+               chip->legacy.write_byte = busw ? nand_write_byte16 : nand_write_byte;
+       if (!chip->legacy.read_buf || chip->legacy.read_buf == nand_read_buf)
+               chip->legacy.read_buf = busw ? nand_read_buf16 : nand_read_buf;
+}
+
+void nand_legacy_adjust_cmdfunc(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
+       /* Do not replace user supplied command function! */
+       if (mtd->writesize > 512 && chip->legacy.cmdfunc == nand_command)
+               chip->legacy.cmdfunc = nand_command_lp;
+}
+
+int nand_legacy_check_hooks(struct nand_chip *chip)
+{
+       /*
+        * ->legacy.cmdfunc() is legacy and will only be used if ->exec_op() is
+        * not populated.
+        */
+       if (chip->exec_op)
+               return 0;
+
+       /*
+        * Default functions assigned for ->legacy.cmdfunc() and
+        * ->select_chip() both expect ->legacy.cmd_ctrl() to be populated.
+        */
+       if ((!chip->legacy.cmdfunc || !chip->select_chip) &&
+           !chip->legacy.cmd_ctrl) {
+               pr_err("->legacy.cmd_ctrl() should be provided\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
index 49c546c97c6f9a370ff64636deaf778bce2c3ce0..358dcc957bb20c1d1600f2819661f9f35ccbb706 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
 
 /*
  * Macronix AC series does not support using SET/GET_FEATURES to change
index f5dc0a7a2456325a92142ce0f4b537a7dcbbe79d..b85e1c13b79e0fa9a0a82e5ad8bf9461bd6f8652 100644 (file)
  * GNU General Public License for more details.
  */
 
-#include <linux/mtd/rawnand.h>
 #include <linux/slab.h>
 
+#include "internals.h"
+
 /*
  * Special Micron status bit 3 indicates that the block has been
  * corrected by on-die ECC and should be rewritten.
@@ -74,9 +75,8 @@ struct micron_nand {
        struct micron_on_die_ecc ecc;
 };
 
-static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+static int micron_nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
 
        return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature);
@@ -290,10 +290,10 @@ static int micron_nand_on_die_ecc_status_8(struct nand_chip *chip, u8 status)
 }
 
 static int
-micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                uint8_t *buf, int oob_required,
-                                int page)
+micron_nand_read_page_on_die_ecc(struct nand_chip *chip, uint8_t *buf,
+                                int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        u8 status;
        int ret, max_bitflips = 0;
 
@@ -332,9 +332,8 @@ out:
 }
 
 static int
-micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                 const uint8_t *buf, int oob_required,
-                                 int page)
+micron_nand_write_page_on_die_ecc(struct nand_chip *chip, const uint8_t *buf,
+                                 int oob_required, int page)
 {
        int ret;
 
@@ -342,7 +341,7 @@ micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
        if (ret)
                return ret;
 
-       ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
+       ret = nand_write_page_raw(chip, buf, oob_required, page);
        micron_nand_on_die_ecc_setup(chip, false);
 
        return ret;
diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c
new file mode 100644 (file)
index 0000000..d8184cf
--- /dev/null
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ *               2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *  Credits:
+ *     David Woodhouse for adding multichip support
+ *
+ *     Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ *     rework for 2K page size chips
+ *
+ * This file contains all ONFI helpers.
+ */
+
+#include <linux/slab.h>
+
+#include "internals.h"
+
+u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
+{
+       int i;
+       while (len--) {
+               crc ^= *p++ << 8;
+               for (i = 0; i < 8; i++)
+                       crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
+       }
+
+       return crc;
+}
+
+/* Parse the Extended Parameter Page. */
+static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
+                                           struct nand_onfi_params *p)
+{
+       struct onfi_ext_param_page *ep;
+       struct onfi_ext_section *s;
+       struct onfi_ext_ecc_info *ecc;
+       uint8_t *cursor;
+       int ret;
+       int len;
+       int i;
+
+       len = le16_to_cpu(p->ext_param_page_length) * 16;
+       ep = kmalloc(len, GFP_KERNEL);
+       if (!ep)
+               return -ENOMEM;
+
+       /* Send our own NAND_CMD_PARAM. */
+       ret = nand_read_param_page_op(chip, 0, NULL, 0);
+       if (ret)
+               goto ext_out;
+
+       /* Use the Change Read Column command to skip the ONFI param pages. */
+       ret = nand_change_read_column_op(chip,
+                                        sizeof(*p) * p->num_of_param_pages,
+                                        ep, len, true);
+       if (ret)
+               goto ext_out;
+
+       ret = -EINVAL;
+       if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
+               != le16_to_cpu(ep->crc))) {
+               pr_debug("fail in the CRC.\n");
+               goto ext_out;
+       }
+
+       /*
+        * Check the signature.
+        * Do not strictly follow the ONFI spec, maybe changed in future.
+        */
+       if (strncmp(ep->sig, "EPPS", 4)) {
+               pr_debug("The signature is invalid.\n");
+               goto ext_out;
+       }
+
+       /* find the ECC section. */
+       cursor = (uint8_t *)(ep + 1);
+       for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
+               s = ep->sections + i;
+               if (s->type == ONFI_SECTION_TYPE_2)
+                       break;
+               cursor += s->length * 16;
+       }
+       if (i == ONFI_EXT_SECTION_MAX) {
+               pr_debug("We can not find the ECC section.\n");
+               goto ext_out;
+       }
+
+       /* get the info we want. */
+       ecc = (struct onfi_ext_ecc_info *)cursor;
+
+       if (!ecc->codeword_size) {
+               pr_debug("Invalid codeword size\n");
+               goto ext_out;
+       }
+
+       chip->ecc_strength_ds = ecc->ecc_bits;
+       chip->ecc_step_ds = 1 << ecc->codeword_size;
+       ret = 0;
+
+ext_out:
+       kfree(ep);
+       return ret;
+}
+
+/*
+ * Recover data with bit-wise majority
+ */
+static void nand_bit_wise_majority(const void **srcbufs,
+                                  unsigned int nsrcbufs,
+                                  void *dstbuf,
+                                  unsigned int bufsize)
+{
+       int i, j, k;
+
+       for (i = 0; i < bufsize; i++) {
+               u8 val = 0;
+
+               for (j = 0; j < 8; j++) {
+                       unsigned int cnt = 0;
+
+                       for (k = 0; k < nsrcbufs; k++) {
+                               const u8 *srcbuf = srcbufs[k];
+
+                               if (srcbuf[i] & BIT(j))
+                                       cnt++;
+                       }
+
+                       if (cnt > nsrcbufs / 2)
+                               val |= BIT(j);
+               }
+
+               ((u8 *)dstbuf)[i] = val;
+       }
+}
+
+/*
+ * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
+ */
+int nand_onfi_detect(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;
+
+       /* Try ONFI for unknown chip or LP */
+       ret = nand_readid_op(chip, 0x20, id, sizeof(id));
+       if (ret || strncmp(id, "ONFI", 4))
+               return 0;
+
+       /* ONFI chip: allocate a buffer to hold its parameter page */
+       p = kzalloc((sizeof(*p) * 3), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       ret = nand_read_param_page_op(chip, 0, NULL, 0);
+       if (ret) {
+               ret = 0;
+               goto free_onfi_param_page;
+       }
+
+       for (i = 0; i < 3; i++) {
+               ret = nand_read_data_op(chip, &p[i], sizeof(*p), true);
+               if (ret) {
+                       ret = 0;
+                       goto free_onfi_param_page;
+               }
+
+               if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) ==
+                               le16_to_cpu(p->crc)) {
+                       if (i)
+                               memcpy(p, &p[i], sizeof(*p));
+                       break;
+               }
+       }
+
+       if (i == 3) {
+               const void *srcbufs[3] = {p, p + 1, p + 2};
+
+               pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n");
+               nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p,
+                                      sizeof(*p));
+
+               if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) !=
+                               le16_to_cpu(p->crc)) {
+                       pr_err("ONFI parameter recovery failed, aborting\n");
+                       goto free_onfi_param_page;
+               }
+       }
+
+       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 & 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;
+       }
+
+       sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+       sanitize_string(p->model, sizeof(p->model));
+       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);
+
+       /*
+        * pages_per_block and blocks_per_lun may not be a power-of-2 size
+        * (don't ask me who thought of this...). MTD assumes that these
+        * dimensions will be power-of-2, so just truncate the remaining area.
+        */
+       mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+       mtd->erasesize *= mtd->writesize;
+
+       mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+       /* See erasesize comment */
+       chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+       chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+       chip->bits_per_cell = p->bits_per_cell;
+
+       chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
+       chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
+
+       if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
+               chip->options |= NAND_BUSWIDTH_16;
+
+       if (p->ecc_bits != 0xff) {
+               chip->ecc_strength_ds = p->ecc_bits;
+               chip->ecc_step_ds = 512;
+       } else if (onfi_version >= 21 &&
+               (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
+
+               /*
+                * The nand_flash_detect_ext_param_page() uses the
+                * Change Read Column command which maybe not supported
+                * by the chip->legacy.cmdfunc. So try to update the
+                * chip->legacy.cmdfunc now. We do not replace user supplied
+                * command function.
+                */
+               nand_legacy_adjust_cmdfunc(chip);
+
+               /* The Extended Parameter Page is supported since ONFI 2.1. */
+               if (nand_flash_detect_ext_param_page(chip, p))
+                       pr_warn("Failed to detect ONFI extended param page\n");
+       } else {
+               pr_warn("Could not retrieve ONFI ECC requirements\n");
+       }
+
+       /* Save some parameters from the parameter page for future use */
+       if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
+               chip->parameters.supports_set_get_features = true;
+               bitmap_set(chip->parameters.get_feature_list,
+                          ONFI_FEATURE_ADDR_TIMING_MODE, 1);
+               bitmap_set(chip->parameters.set_feature_list,
+                          ONFI_FEATURE_ADDR_TIMING_MODE, 1);
+       }
+
+       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;
+}
index ef022f62f74c18b612025732dc2eae13c9078d59..e46d4c492ad81ab7fc44ab7d0d9d22aeec56bdfc 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
 
 static void samsung_nand_decode_id(struct nand_chip *chip)
 {
index ebc7b5f76f77b26f3971047f378e319de9749d43..bea3062d71d6f9e9220798173e47fed6f556d39e 100644 (file)
@@ -11,7 +11,8 @@
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/export.h>
-#include <linux/mtd/rawnand.h>
+
+#include "internals.h"
 
 #define ONFI_DYN_TIMING_MAX U16_MAX
 
@@ -270,20 +271,6 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
        },
 };
 
-/**
- * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
- * timings according to the given ONFI timing mode
- * @mode: ONFI timing mode
- */
-const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
-{
-       if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
-               return ERR_PTR(-EINVAL);
-
-       return &onfi_sdr_timings[mode].timings.sdr;
-}
-EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
-
 /**
  * onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
  * given ONFI mode
@@ -339,4 +326,3 @@ int onfi_fill_data_interface(struct nand_chip *chip,
 
        return 0;
 }
-EXPORT_SYMBOL(onfi_fill_data_interface);
index ab43f027cd2311381bf195dcf5b83ac58873792e..d068163b64b3ff1755f5a66d6b3227d627603b93 100644 (file)
  * GNU General Public License for more details.
  */
 
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
+
+/* Bit for detecting BENAND */
+#define TOSHIBA_NAND_ID4_IS_BENAND             BIT(7)
+
+/* Recommended to rewrite for BENAND */
+#define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED        BIT(3)
+
+static int toshiba_nand_benand_eccstatus(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+       int ret;
+       unsigned int max_bitflips = 0;
+       u8 status;
+
+       /* Check Status */
+       ret = nand_status_op(chip, &status);
+       if (ret)
+               return ret;
+
+       if (status & NAND_STATUS_FAIL) {
+               /* uncorrected */
+               mtd->ecc_stats.failed++;
+       } else if (status & TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED) {
+               /* corrected */
+               max_bitflips = mtd->bitflip_threshold;
+               mtd->ecc_stats.corrected += max_bitflips;
+       }
+
+       return max_bitflips;
+}
+
+static int
+toshiba_nand_read_page_benand(struct nand_chip *chip, uint8_t *buf,
+                             int oob_required, int page)
+{
+       int ret;
+
+       ret = nand_read_page_raw(chip, buf, oob_required, page);
+       if (ret)
+               return ret;
+
+       return toshiba_nand_benand_eccstatus(chip);
+}
+
+static int
+toshiba_nand_read_subpage_benand(struct nand_chip *chip, uint32_t data_offs,
+                                uint32_t readlen, uint8_t *bufpoi, int page)
+{
+       int ret;
+
+       ret = nand_read_page_op(chip, page, data_offs,
+                               bufpoi + data_offs, readlen);
+       if (ret)
+               return ret;
+
+       return toshiba_nand_benand_eccstatus(chip);
+}
+
+static void toshiba_nand_benand_init(struct nand_chip *chip)
+{
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
+       /*
+        * On BENAND, the entire OOB region can be used by the MTD user.
+        * The calculated ECC bytes are stored into other isolated
+        * area which is not accessible to users.
+        * This is why chip->ecc.bytes = 0.
+        */
+       chip->ecc.bytes = 0;
+       chip->ecc.size = 512;
+       chip->ecc.strength = 8;
+       chip->ecc.read_page = toshiba_nand_read_page_benand;
+       chip->ecc.read_subpage = toshiba_nand_read_subpage_benand;
+       chip->ecc.write_page = nand_write_page_raw;
+       chip->ecc.read_page_raw = nand_read_page_raw_notsupp;
+       chip->ecc.write_page_raw = nand_write_page_raw_notsupp;
+
+       chip->options |= NAND_SUBPAGE_READ;
+
+       mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+}
 
 static void toshiba_nand_decode_id(struct nand_chip *chip)
 {
@@ -68,6 +149,11 @@ static int toshiba_nand_init(struct nand_chip *chip)
        if (nand_is_slc(chip))
                chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
 
+       /* Check that chip is BENAND and ECC mode is on-die */
+       if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE &&
+           chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND)
+               toshiba_nand_benand_init(chip);
+
        return 0;
 }
 
index 71ac034aee9c2fbfc5d06686f66f6db4a7f6b766..c452819f612372d56ca5b4316d6afe8cbcb73e1d 100644 (file)
@@ -656,7 +656,7 @@ static int __init init_nandsim(struct mtd_info *mtd)
        }
 
        /* Force mtd to not do delays */
-       chip->chip_delay = 0;
+       chip->legacy.chip_delay = 0;
 
        /* Initialize the NAND flash parameters */
        ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
@@ -1872,9 +1872,8 @@ static void switch_state(struct nandsim *ns)
        }
 }
 
-static u_char ns_nand_read_byte(struct mtd_info *mtd)
+static u_char ns_nand_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct nandsim *ns = nand_get_controller_data(chip);
        u_char outb = 0x00;
 
@@ -1934,9 +1933,8 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
        return outb;
 }
 
-static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+static void ns_nand_write_byte(struct nand_chip *chip, u_char byte)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct nandsim *ns = nand_get_controller_data(chip);
 
        /* Sanity and correctness checks */
@@ -2089,9 +2087,8 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
        return;
 }
 
-static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
+static void ns_hwcontrol(struct nand_chip *chip, int cmd, unsigned int bitmask)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct nandsim *ns = nand_get_controller_data(chip);
 
        ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
@@ -2099,27 +2096,18 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
        ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
 
        if (cmd != NAND_CMD_NONE)
-               ns_nand_write_byte(mtd, cmd);
+               ns_nand_write_byte(chip, cmd);
 }
 
-static int ns_device_ready(struct mtd_info *mtd)
+static int ns_device_ready(struct nand_chip *chip)
 {
        NS_DBG("device_ready\n");
        return 1;
 }
 
-static uint16_t ns_nand_read_word(struct mtd_info *mtd)
+static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf,
+                             int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
-       NS_DBG("read_word\n");
-
-       return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
-}
-
-static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct nandsim *ns = nand_get_controller_data(chip);
 
        /* Check that chip is expecting data input */
@@ -2145,9 +2133,8 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
        }
 }
 
-static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct nandsim *ns = nand_get_controller_data(chip);
 
        /* Sanity and correctness checks */
@@ -2169,7 +2156,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
                int i;
 
                for (i = 0; i < len; i++)
-                       buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
+                       buf[i] = chip->legacy.read_byte(chip);
 
                return;
        }
@@ -2262,12 +2249,11 @@ static int __init ns_init_module(void)
        /*
         * Register simulator's callbacks.
         */
-       chip->cmd_ctrl   = ns_hwcontrol;
-       chip->read_byte  = ns_nand_read_byte;
-       chip->dev_ready  = ns_device_ready;
-       chip->write_buf  = ns_nand_write_buf;
-       chip->read_buf   = ns_nand_read_buf;
-       chip->read_word  = ns_nand_read_word;
+       chip->legacy.cmd_ctrl    = ns_hwcontrol;
+       chip->legacy.read_byte  = ns_nand_read_byte;
+       chip->legacy.dev_ready  = ns_device_ready;
+       chip->legacy.write_buf  = ns_nand_write_buf;
+       chip->legacy.read_buf   = ns_nand_read_buf;
        chip->ecc.mode   = NAND_ECC_SOFT;
        chip->ecc.algo   = NAND_ECC_HAMMING;
        /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
@@ -2319,7 +2305,7 @@ static int __init ns_init_module(void)
                goto error;
 
        chip->dummy_controller.ops = &ns_controller_ops;
-       retval = nand_scan(nsmtd, 1);
+       retval = nand_scan(chip, 1);
        if (retval) {
                NS_ERR("Could not scan NAND Simulator device\n");
                goto error;
@@ -2364,7 +2350,7 @@ static int __init ns_init_module(void)
 
 err_exit:
        free_nandsim(nand);
-       nand_release(nsmtd);
+       nand_release(chip);
        for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
                kfree(nand->partitions[i].name);
 error:
@@ -2386,7 +2372,7 @@ static void __exit ns_cleanup_module(void)
        int i;
 
        free_nandsim(ns);    /* Free nandsim private resources */
-       nand_release(nsmtd); /* Unregister driver */
+       nand_release(chip); /* Unregister driver */
        for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
                kfree(ns->partitions[i].name);
        kfree(mtd_to_nand(nsmtd));        /* Free other structures */
index 540fa1a0ea24ec5605231bb2946cd782c71fab1b..d49a7a17146c84e17f917eae0db3da4bb3dad564 100644 (file)
@@ -44,10 +44,9 @@ struct ndfc_controller {
 
 static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
 
-static void ndfc_select_chip(struct mtd_info *mtd, int chip)
+static void ndfc_select_chip(struct nand_chip *nchip, int chip)
 {
        uint32_t ccr;
-       struct nand_chip *nchip = mtd_to_nand(mtd);
        struct ndfc_controller *ndfc = nand_get_controller_data(nchip);
 
        ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
@@ -59,9 +58,8 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
        out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
 }
 
-static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void ndfc_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct ndfc_controller *ndfc = nand_get_controller_data(chip);
 
        if (cmd == NAND_CMD_NONE)
@@ -73,18 +71,16 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
                writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
 }
 
-static int ndfc_ready(struct mtd_info *mtd)
+static int ndfc_ready(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct ndfc_controller *ndfc = nand_get_controller_data(chip);
 
        return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
 }
 
-static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
+static void ndfc_enable_hwecc(struct nand_chip *chip, int mode)
 {
        uint32_t ccr;
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct ndfc_controller *ndfc = nand_get_controller_data(chip);
 
        ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
@@ -93,10 +89,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
        wmb();
 }
 
-static int ndfc_calculate_ecc(struct mtd_info *mtd,
+static int ndfc_calculate_ecc(struct nand_chip *chip,
                              const u_char *dat, u_char *ecc_code)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct ndfc_controller *ndfc = nand_get_controller_data(chip);
        uint32_t ecc;
        uint8_t *p = (uint8_t *)&ecc;
@@ -118,9 +113,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
  * functions. No further checking, as nand_base will always read/write
  * page aligned.
  */
-static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void ndfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct ndfc_controller *ndfc = nand_get_controller_data(chip);
        uint32_t *p = (uint32_t *) buf;
 
@@ -128,9 +122,8 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
                *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
 }
 
-static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct ndfc_controller *ndfc = nand_get_controller_data(chip);
        uint32_t *p = (uint32_t *) buf;
 
@@ -149,15 +142,15 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
        struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
-       chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
-       chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
-       chip->cmd_ctrl = ndfc_hwcontrol;
-       chip->dev_ready = ndfc_ready;
+       chip->legacy.IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
+       chip->legacy.IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
+       chip->legacy.cmd_ctrl = ndfc_hwcontrol;
+       chip->legacy.dev_ready = ndfc_ready;
        chip->select_chip = ndfc_select_chip;
-       chip->chip_delay = 50;
+       chip->legacy.chip_delay = 50;
        chip->controller = &ndfc->ndfc_control;
-       chip->read_buf = ndfc_read_buf;
-       chip->write_buf = ndfc_write_buf;
+       chip->legacy.read_buf = ndfc_read_buf;
+       chip->legacy.write_buf = ndfc_write_buf;
        chip->ecc.correct = nand_correct_data;
        chip->ecc.hwctl = ndfc_enable_hwecc;
        chip->ecc.calculate = ndfc_calculate_ecc;
@@ -174,14 +167,14 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
                return -ENODEV;
        nand_set_flash_node(chip, flash_np);
 
-       mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev),
-                             flash_np->name);
+       mtd->name = kasprintf(GFP_KERNEL, "%s.%pOFn", dev_name(&ndfc->ofdev->dev),
+                             flash_np);
        if (!mtd->name) {
                ret = -ENOMEM;
                goto err;
        }
 
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(chip, 1);
        if (ret)
                goto err;
 
@@ -258,7 +251,7 @@ static int ndfc_remove(struct platform_device *ofdev)
        struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
        struct mtd_info *mtd = nand_to_mtd(&ndfc->chip);
 
-       nand_release(mtd);
+       nand_release(&ndfc->chip);
        kfree(mtd->name);
 
        return 0;
index af5b32c9a791dc18934b916cec03573995bf307a..38b1994e7ed3bd66babf350c035c3a5a0f9f2153 100644 (file)
@@ -79,31 +79,31 @@ static const struct mtd_partition partitions[] = {
        }
 };
 
-static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd)
+static unsigned char nuc900_nand_read_byte(struct nand_chip *chip)
 {
        unsigned char ret;
-       struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+       struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
 
        ret = (unsigned char)read_data_reg(nand);
 
        return ret;
 }
 
-static void nuc900_nand_read_buf(struct mtd_info *mtd,
+static void nuc900_nand_read_buf(struct nand_chip *chip,
                                 unsigned char *buf, int len)
 {
        int i;
-       struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+       struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
 
        for (i = 0; i < len; i++)
                buf[i] = (unsigned char)read_data_reg(nand);
 }
 
-static void nuc900_nand_write_buf(struct mtd_info *mtd,
+static void nuc900_nand_write_buf(struct nand_chip *chip,
                                  const unsigned char *buf, int len)
 {
        int i;
-       struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+       struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
 
        for (i = 0; i < len; i++)
                write_data_reg(nand, buf[i]);
@@ -120,19 +120,20 @@ static int nuc900_check_rb(struct nuc900_nand *nand)
        return val;
 }
 
-static int nuc900_nand_devready(struct mtd_info *mtd)
+static int nuc900_nand_devready(struct nand_chip *chip)
 {
-       struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+       struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
        int ready;
 
        ready = (nuc900_check_rb(nand)) ? 1 : 0;
        return ready;
 }
 
-static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
+static void nuc900_nand_command_lp(struct nand_chip *chip,
+                                  unsigned int command,
                                   int column, int page_addr)
 {
-       register struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nuc900_nand *nand = mtd_to_nuc900(mtd);
 
        if (command == NAND_CMD_READOOB) {
@@ -174,9 +175,9 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
                return;
 
        case NAND_CMD_RESET:
-               if (chip->dev_ready)
+               if (chip->legacy.dev_ready)
                        break;
-               udelay(chip->chip_delay);
+               udelay(chip->legacy.chip_delay);
 
                write_cmd_reg(nand, NAND_CMD_STATUS);
                write_cmd_reg(nand, command);
@@ -195,8 +196,8 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
                write_cmd_reg(nand, NAND_CMD_READSTART);
        default:
 
-               if (!chip->dev_ready) {
-                       udelay(chip->chip_delay);
+               if (!chip->legacy.dev_ready) {
+                       udelay(chip->legacy.chip_delay);
                        return;
                }
        }
@@ -205,7 +206,7 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
         * any case on any machine. */
        ndelay(100);
 
-       while (!chip->dev_ready(mtd))
+       while (!chip->legacy.dev_ready(chip))
                ;
 }
 
@@ -253,12 +254,12 @@ static int nuc900_nand_probe(struct platform_device *pdev)
                return -ENOENT;
        clk_enable(nuc900_nand->clk);
 
-       chip->cmdfunc           = nuc900_nand_command_lp;
-       chip->dev_ready         = nuc900_nand_devready;
-       chip->read_byte         = nuc900_nand_read_byte;
-       chip->write_buf         = nuc900_nand_write_buf;
-       chip->read_buf          = nuc900_nand_read_buf;
-       chip->chip_delay        = 50;
+       chip->legacy.cmdfunc    = nuc900_nand_command_lp;
+       chip->legacy.dev_ready  = nuc900_nand_devready;
+       chip->legacy.read_byte  = nuc900_nand_read_byte;
+       chip->legacy.write_buf  = nuc900_nand_write_buf;
+       chip->legacy.read_buf   = nuc900_nand_read_buf;
+       chip->legacy.chip_delay = 50;
        chip->options           = 0;
        chip->ecc.mode          = NAND_ECC_SOFT;
        chip->ecc.algo          = NAND_ECC_HAMMING;
@@ -270,7 +271,7 @@ static int nuc900_nand_probe(struct platform_device *pdev)
 
        nuc900_nand_enable(nuc900_nand);
 
-       if (nand_scan(mtd, 1))
+       if (nand_scan(chip, 1))
                return -ENXIO;
 
        mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
@@ -284,7 +285,7 @@ static int nuc900_nand_remove(struct platform_device *pdev)
 {
        struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
 
-       nand_release(nand_to_mtd(&nuc900_nand->chip));
+       nand_release(&nuc900_nand->chip);
        clk_disable(nuc900_nand->clk);
 
        return 0;
index 4546ac0bed4a0eb7435c8806c2323170327f61f3..886d05c391efe20b08b78bdb2fb145f3f859b752 100644 (file)
@@ -240,7 +240,7 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
 
 /**
  * omap_hwcontrol - hardware specific access to control-lines
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @cmd: command to device
  * @ctrl:
  * NAND_NCE: bit 0 -> don't care
@@ -249,9 +249,9 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
  *
  * NOTE: boards may use different bits for these!!
  */
-static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void omap_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
 {
-       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
 
        if (cmd != NAND_CMD_NONE) {
                if (ctrl & NAND_CLE)
@@ -275,7 +275,7 @@ static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
 
-       ioread8_rep(nand->IO_ADDR_R, buf, len);
+       ioread8_rep(nand->legacy.IO_ADDR_R, buf, len);
 }
 
 /**
@@ -291,7 +291,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
        bool status;
 
        while (len--) {
-               iowrite8(*p++, info->nand.IO_ADDR_W);
+               iowrite8(*p++, info->nand.legacy.IO_ADDR_W);
                /* wait until buffer is available for write */
                do {
                        status = info->ops->nand_writebuffer_empty();
@@ -309,7 +309,7 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
 
-       ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
+       ioread16_rep(nand->legacy.IO_ADDR_R, buf, len / 2);
 }
 
 /**
@@ -327,7 +327,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
        len >>= 1;
 
        while (len--) {
-               iowrite16(*p++, info->nand.IO_ADDR_W);
+               iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
                /* wait until buffer is available for write */
                do {
                        status = info->ops->nand_writebuffer_empty();
@@ -337,12 +337,13 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
 
 /**
  * omap_read_buf_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @buf: buffer to store date
  * @len: number of bytes to read
  */
-static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+static void omap_read_buf_pref(struct nand_chip *chip, u_char *buf, int len)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct omap_nand_info *info = mtd_to_omap(mtd);
        uint32_t r_count = 0;
        int ret = 0;
@@ -372,7 +373,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
                        r_count = readl(info->reg.gpmc_prefetch_status);
                        r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
                        r_count = r_count >> 2;
-                       ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
+                       ioread32_rep(info->nand.legacy.IO_ADDR_R, p, r_count);
                        p += r_count;
                        len -= r_count << 2;
                } while (len);
@@ -383,13 +384,14 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
 
 /**
  * omap_write_buf_pref - write buffer to NAND controller
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @buf: data buffer
  * @len: number of bytes to write
  */
-static void omap_write_buf_pref(struct mtd_info *mtd,
-                                       const u_char *buf, int len)
+static void omap_write_buf_pref(struct nand_chip *chip, const u_char *buf,
+                               int len)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct omap_nand_info *info = mtd_to_omap(mtd);
        uint32_t w_count = 0;
        int i = 0, ret = 0;
@@ -399,7 +401,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
 
        /* take care of subpage writes */
        if (len % 2 != 0) {
-               writeb(*buf, info->nand.IO_ADDR_W);
+               writeb(*buf, info->nand.legacy.IO_ADDR_W);
                p = (u16 *)(buf + 1);
                len--;
        }
@@ -419,7 +421,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
                        w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
                        w_count = w_count >> 1;
                        for (i = 0; (i < w_count) && len; i++, len -= 2)
-                               iowrite16(*p++, info->nand.IO_ADDR_W);
+                               iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
                }
                /* wait for data to flushed-out before reset the prefetch */
                tim = 0;
@@ -528,14 +530,17 @@ out_copy:
 
 /**
  * omap_read_buf_dma_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @buf: buffer to store date
  * @len: number of bytes to read
  */
-static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
+static void omap_read_buf_dma_pref(struct nand_chip *chip, u_char *buf,
+                                  int len)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        if (len <= mtd->oobsize)
-               omap_read_buf_pref(mtd, buf, len);
+               omap_read_buf_pref(chip, buf, len);
        else
                /* start transfer in DMA mode */
                omap_nand_dma_transfer(mtd, buf, len, 0x0);
@@ -543,18 +548,20 @@ static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
 
 /**
  * omap_write_buf_dma_pref - write buffer to NAND controller
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @buf: data buffer
  * @len: number of bytes to write
  */
-static void omap_write_buf_dma_pref(struct mtd_info *mtd,
-                                       const u_char *buf, int len)
+static void omap_write_buf_dma_pref(struct nand_chip *chip, const u_char *buf,
+                                   int len)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        if (len <= mtd->oobsize)
-               omap_write_buf_pref(mtd, buf, len);
+               omap_write_buf_pref(chip, buf, len);
        else
                /* start transfer in DMA mode */
-               omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
+               omap_nand_dma_transfer(mtd, (u_char *)buf, len, 0x1);
 }
 
 /*
@@ -578,14 +585,14 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
                        bytes = info->buf_len;
                else if (!info->buf_len)
                        bytes = 0;
-               iowrite32_rep(info->nand.IO_ADDR_W,
-                                               (u32 *)info->buf, bytes >> 2);
+               iowrite32_rep(info->nand.legacy.IO_ADDR_W, (u32 *)info->buf,
+                             bytes >> 2);
                info->buf = info->buf + bytes;
                info->buf_len -= bytes;
 
        } else {
-               ioread32_rep(info->nand.IO_ADDR_R,
-                                               (u32 *)info->buf, bytes >> 2);
+               ioread32_rep(info->nand.legacy.IO_ADDR_R, (u32 *)info->buf,
+                            bytes >> 2);
                info->buf = info->buf + bytes;
 
                if (this_irq == info->gpmc_irq_count)
@@ -605,17 +612,19 @@ done:
 
 /*
  * omap_read_buf_irq_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @buf: buffer to store date
  * @len: number of bytes to read
  */
-static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
+static void omap_read_buf_irq_pref(struct nand_chip *chip, u_char *buf,
+                                  int len)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct omap_nand_info *info = mtd_to_omap(mtd);
        int ret = 0;
 
        if (len <= mtd->oobsize) {
-               omap_read_buf_pref(mtd, buf, len);
+               omap_read_buf_pref(chip, buf, len);
                return;
        }
 
@@ -651,20 +660,21 @@ out_copy:
 
 /*
  * omap_write_buf_irq_pref - write buffer to NAND controller
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @buf: data buffer
  * @len: number of bytes to write
  */
-static void omap_write_buf_irq_pref(struct mtd_info *mtd,
-                                       const u_char *buf, int len)
+static void omap_write_buf_irq_pref(struct nand_chip *chip, const u_char *buf,
+                                   int len)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct omap_nand_info *info = mtd_to_omap(mtd);
        int ret = 0;
        unsigned long tim, limit;
        u32 val;
 
        if (len <= mtd->oobsize) {
-               omap_write_buf_pref(mtd, buf, len);
+               omap_write_buf_pref(chip, buf, len);
                return;
        }
 
@@ -857,7 +867,7 @@ static int omap_compare_ecc(u8 *ecc_data1,  /* read from NAND memory */
 
 /**
  * omap_correct_data - Compares the ECC read with HW generated ECC
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @dat: page data
  * @read_ecc: ecc read from nand flash
  * @calc_ecc: ecc read from HW ECC registers
@@ -869,10 +879,10 @@ static int omap_compare_ecc(u8 *ecc_data1,        /* read from NAND memory */
  * corrected errors is returned. If uncorrectable errors exist, %-1 is
  * returned.
  */
-static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
-                               u_char *read_ecc, u_char *calc_ecc)
+static int omap_correct_data(struct nand_chip *chip, u_char *dat,
+                            u_char *read_ecc, u_char *calc_ecc)
 {
-       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
        int blockCnt = 0, i = 0, ret = 0;
        int stat = 0;
 
@@ -900,7 +910,7 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
 
 /**
  * omap_calcuate_ecc - Generate non-inverted ECC bytes.
- * @mtd: MTD device structure
+ * @chip: NAND chip object
  * @dat: The pointer to data on which ecc is computed
  * @ecc_code: The ecc_code buffer
  *
@@ -910,10 +920,10 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
  * an erased page will produce an ECC mismatch between generated and read
  * ECC bytes that has to be dealt with separately.
  */
-static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-                               u_char *ecc_code)
+static int omap_calculate_ecc(struct nand_chip *chip, const u_char *dat,
+                             u_char *ecc_code)
 {
-       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
        u32 val;
 
        val = readl(info->reg.gpmc_ecc_config);
@@ -935,10 +945,9 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
  * @mtd: MTD device structure
  * @mode: Read/Write mode
  */
-static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
+static void omap_enable_hwecc(struct nand_chip *chip, int mode)
 {
-       struct omap_nand_info *info = mtd_to_omap(mtd);
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
        unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
        u32 val;
 
@@ -972,8 +981,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
 
 /**
  * omap_wait - wait until the command is done
- * @mtd: MTD device structure
- * @chip: NAND Chip structure
+ * @this: NAND Chip structure
  *
  * Wait function is called during Program and erase operations and
  * the way it is called from MTD layer, we should wait till the NAND
@@ -982,10 +990,9 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
  * Erase can take up to 400ms and program up to 20ms according to
  * general NAND and SmartMedia specs
  */
-static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int omap_wait(struct nand_chip *this)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this));
        unsigned long timeo = jiffies;
        int status, state = this->state;
 
@@ -1012,9 +1019,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
  *
  * Returns true if ready and false if busy.
  */
-static int omap_dev_ready(struct mtd_info *mtd)
+static int omap_dev_ready(struct nand_chip *chip)
 {
-       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
 
        return gpiod_get_value(info->ready_gpiod);
 }
@@ -1030,13 +1037,13 @@ static int omap_dev_ready(struct mtd_info *mtd)
  * eccsize0 = 0  (no additional protected byte in spare area)
  * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
  */
-static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
+static void __maybe_unused omap_enable_hwecc_bch(struct nand_chip *chip,
+                                                int mode)
 {
        unsigned int bch_type;
        unsigned int dev_width, nsectors;
-       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
        enum omap_ecc ecc_opt = info->ecc_opt;
-       struct nand_chip *chip = mtd_to_nand(mtd);
        u32 val, wr_mode;
        unsigned int ecc_size1, ecc_size0;
 
@@ -1256,7 +1263,7 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
 
 /**
  * omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction
- * @mtd:       MTD device structure
+ * @chip:      NAND chip object
  * @dat:       The pointer to data on which ecc is computed
  * @ecc_code:  The ecc_code buffer
  *
@@ -1264,10 +1271,10 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
  * when SW based correction is required as ECC is required for one sector
  * at a time.
  */
-static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd,
+static int omap_calculate_ecc_bch_sw(struct nand_chip *chip,
                                     const u_char *dat, u_char *ecc_calc)
 {
-       return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
+       return _omap_calculate_ecc_bch(nand_to_mtd(chip), dat, ecc_calc, 0);
 }
 
 /**
@@ -1339,7 +1346,7 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
 
 /**
  * omap_elm_correct_data - corrects page data area in case error reported
- * @mtd:       MTD device structure
+ * @chip:      NAND chip object
  * @data:      page data
  * @read_ecc:  ecc read from nand flash
  * @calc_ecc:  ecc read from HW ECC registers
@@ -1348,10 +1355,10 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
  * In case of non-zero ecc vector, first filter out erased-pages, and
  * then process data via ELM to detect bit-flips.
  */
-static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
-                               u_char *read_ecc, u_char *calc_ecc)
+static int omap_elm_correct_data(struct nand_chip *chip, u_char *data,
+                                u_char *read_ecc, u_char *calc_ecc)
 {
-       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
        struct nand_ecc_ctrl *ecc = &info->nand.ecc;
        int eccsteps = info->nand.ecc.steps;
        int i , j, stat = 0;
@@ -1512,7 +1519,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
 
 /**
  * omap_write_page_bch - BCH ecc based write page function for entire page
- * @mtd:               mtd info structure
  * @chip:              nand chip info structure
  * @buf:               data buffer
  * @oob_required:      must write chip->oob_poi to OOB
@@ -1520,19 +1526,20 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
  *
  * Custom write page method evolved to support multi sector writing in one shot
  */
-static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
-                              const uint8_t *buf, int oob_required, int page)
+static int omap_write_page_bch(struct nand_chip *chip, const uint8_t *buf,
+                              int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
        uint8_t *ecc_calc = chip->ecc.calc_buf;
 
        nand_prog_page_begin_op(chip, page, 0, NULL, 0);
 
        /* Enable GPMC ecc engine */
-       chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+       chip->ecc.hwctl(chip, NAND_ECC_WRITE);
 
        /* Write data */
-       chip->write_buf(mtd, buf, mtd->writesize);
+       chip->legacy.write_buf(chip, buf, mtd->writesize);
 
        /* Update ecc vector from GPMC result registers */
        omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
@@ -1543,14 +1550,13 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
                return ret;
 
        /* Write ecc vector to OOB area */
-       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        return nand_prog_page_end_op(chip);
 }
 
 /**
  * omap_write_subpage_bch - BCH hardware ECC based subpage write
- * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @offset:    column address of subpage within the page
  * @data_len:  data length
@@ -1560,11 +1566,11 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
  *
  * OMAP optimized subpage write method.
  */
-static int omap_write_subpage_bch(struct mtd_info *mtd,
-                                 struct nand_chip *chip, u32 offset,
+static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
                                  u32 data_len, const u8 *buf,
                                  int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        u8 *ecc_calc = chip->ecc.calc_buf;
        int ecc_size      = chip->ecc.size;
        int ecc_bytes     = chip->ecc.bytes;
@@ -1582,10 +1588,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
        nand_prog_page_begin_op(chip, page, 0, NULL, 0);
 
        /* Enable GPMC ECC engine */
-       chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+       chip->ecc.hwctl(chip, NAND_ECC_WRITE);
 
        /* Write data */
-       chip->write_buf(mtd, buf, mtd->writesize);
+       chip->legacy.write_buf(chip, buf, mtd->writesize);
 
        for (step = 0; step < ecc_steps; step++) {
                /* mask ECC of un-touched subpages by padding 0xFF */
@@ -1610,14 +1616,13 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
                return ret;
 
        /* write OOB buffer to NAND device */
-       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
 
        return nand_prog_page_end_op(chip);
 }
 
 /**
  * omap_read_page_bch - BCH ecc based page read function for entire page
- * @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
@@ -1630,9 +1635,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
  * ecc engine enabled. ecc vector updated after read of OOB data.
  * For non error pages ecc vector reported as zero.
  */
-static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int oob_required, int page)
+static int omap_read_page_bch(struct nand_chip *chip, uint8_t *buf,
+                             int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        uint8_t *ecc_calc = chip->ecc.calc_buf;
        uint8_t *ecc_code = chip->ecc.code_buf;
        int stat, ret;
@@ -1641,10 +1647,10 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
        nand_read_page_op(chip, page, 0, NULL, 0);
 
        /* Enable GPMC ecc engine */
-       chip->ecc.hwctl(mtd, NAND_ECC_READ);
+       chip->ecc.hwctl(chip, NAND_ECC_READ);
 
        /* Read data */
-       chip->read_buf(mtd, buf, mtd->writesize);
+       chip->legacy.read_buf(chip, buf, mtd->writesize);
 
        /* Read oob bytes */
        nand_change_read_column_op(chip,
@@ -1660,7 +1666,7 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
        if (ret)
                return ret;
 
-       stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
+       stat = chip->ecc.correct(chip, buf, ecc_code, ecc_calc);
 
        if (stat < 0) {
                mtd->ecc_stats.failed++;
@@ -1927,8 +1933,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
        /* Re-populate low-level callbacks based on xfer modes */
        switch (info->xfer_type) {
        case NAND_OMAP_PREFETCH_POLLED:
-               chip->read_buf = omap_read_buf_pref;
-               chip->write_buf = omap_write_buf_pref;
+               chip->legacy.read_buf = omap_read_buf_pref;
+               chip->legacy.write_buf = omap_write_buf_pref;
                break;
 
        case NAND_OMAP_POLLED:
@@ -1960,8 +1966,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
                                        err);
                                return err;
                        }
-                       chip->read_buf = omap_read_buf_dma_pref;
-                       chip->write_buf = omap_write_buf_dma_pref;
+                       chip->legacy.read_buf = omap_read_buf_dma_pref;
+                       chip->legacy.write_buf = omap_write_buf_dma_pref;
                }
                break;
 
@@ -1996,8 +2002,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
                        return err;
                }
 
-               chip->read_buf = omap_read_buf_irq_pref;
-               chip->write_buf = omap_write_buf_irq_pref;
+               chip->legacy.read_buf = omap_read_buf_irq_pref;
+               chip->legacy.write_buf = omap_write_buf_irq_pref;
 
                break;
 
@@ -2215,16 +2221,16 @@ static int omap_nand_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(nand_chip->IO_ADDR_R))
-               return PTR_ERR(nand_chip->IO_ADDR_R);
+       nand_chip->legacy.IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nand_chip->legacy.IO_ADDR_R))
+               return PTR_ERR(nand_chip->legacy.IO_ADDR_R);
 
        info->phys_base = res->start;
 
        nand_chip->controller = &omap_gpmc_controller;
 
-       nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
-       nand_chip->cmd_ctrl  = omap_hwcontrol;
+       nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R;
+       nand_chip->legacy.cmd_ctrl  = omap_hwcontrol;
 
        info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
                                                    GPIOD_IN);
@@ -2241,11 +2247,11 @@ static int omap_nand_probe(struct platform_device *pdev)
         * device and read status register until you get a failure or success
         */
        if (info->ready_gpiod) {
-               nand_chip->dev_ready = omap_dev_ready;
-               nand_chip->chip_delay = 0;
+               nand_chip->legacy.dev_ready = omap_dev_ready;
+               nand_chip->legacy.chip_delay = 0;
        } else {
-               nand_chip->waitfunc = omap_wait;
-               nand_chip->chip_delay = 50;
+               nand_chip->legacy.waitfunc = omap_wait;
+               nand_chip->legacy.chip_delay = 50;
        }
 
        if (info->flash_bbt)
@@ -2254,7 +2260,7 @@ static int omap_nand_probe(struct platform_device *pdev)
        /* scan NAND device connected to chip controller */
        nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
 
-       err = nand_scan(mtd, 1);
+       err = nand_scan(nand_chip, 1);
        if (err)
                goto return_error;
 
@@ -2290,7 +2296,7 @@ static int omap_nand_remove(struct platform_device *pdev)
        }
        if (info->dma)
                dma_release_channel(info->dma);
-       nand_release(mtd);
+       nand_release(nand_chip);
        return 0;
 }
 
index 52d435285a3f393aa752838ff826415f0c1d154f..d27b39a7223c02a2410345815dd20529f8978124 100644 (file)
@@ -26,9 +26,9 @@ struct orion_nand_info {
        struct clk *clk;
 };
 
-static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void orion_nand_cmd_ctrl(struct nand_chip *nc, int cmd,
+                               unsigned int ctrl)
 {
-       struct nand_chip *nc = mtd_to_nand(mtd);
        struct orion_nand_data *board = nand_get_controller_data(nc);
        u32 offs;
 
@@ -45,13 +45,12 @@ static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl
        if (nc->options & NAND_BUSWIDTH_16)
                offs <<= 1;
 
-       writeb(cmd, nc->IO_ADDR_W + offs);
+       writeb(cmd, nc->legacy.IO_ADDR_W + offs);
 }
 
-static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void orion_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       void __iomem *io_base = chip->IO_ADDR_R;
+       void __iomem *io_base = chip->legacy.IO_ADDR_R;
 #if defined(__LINUX_ARM_ARCH__) && __LINUX_ARM_ARCH__ >= 5
        uint64_t *buf64;
 #endif
@@ -137,14 +136,14 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 
        nand_set_controller_data(nc, board);
        nand_set_flash_node(nc, pdev->dev.of_node);
-       nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
-       nc->cmd_ctrl = orion_nand_cmd_ctrl;
-       nc->read_buf = orion_nand_read_buf;
+       nc->legacy.IO_ADDR_R = nc->legacy.IO_ADDR_W = io_base;
+       nc->legacy.cmd_ctrl = orion_nand_cmd_ctrl;
+       nc->legacy.read_buf = orion_nand_read_buf;
        nc->ecc.mode = NAND_ECC_SOFT;
        nc->ecc.algo = NAND_ECC_HAMMING;
 
        if (board->chip_delay)
-               nc->chip_delay = board->chip_delay;
+               nc->legacy.chip_delay = board->chip_delay;
 
        WARN(board->width > 16,
                "%d bit bus width out of range",
@@ -174,14 +173,14 @@ static int __init orion_nand_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(nc, 1);
        if (ret)
                goto no_dev;
 
        mtd->name = "orion_nand";
        ret = mtd_device_register(mtd, board->parts, board->nr_parts);
        if (ret) {
-               nand_release(mtd);
+               nand_release(nc);
                goto no_dev;
        }
 
@@ -196,9 +195,8 @@ static int orion_nand_remove(struct platform_device *pdev)
 {
        struct orion_nand_info *info = platform_get_drvdata(pdev);
        struct nand_chip *chip = &info->chip;
-       struct mtd_info *mtd = nand_to_mtd(chip);
 
-       nand_release(mtd);
+       nand_release(chip);
 
        clk_disable_unprepare(info->clk);
 
index 01b00bb69c1e60889af64aaa8b461f085b447347..0e52dc29141c42fa820c71f931690331c794b4e5 100644 (file)
@@ -38,35 +38,32 @@ struct oxnas_nand_ctrl {
        struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
 };
 
-static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+static uint8_t oxnas_nand_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
 
        return readb(oxnas->io_base);
 }
 
-static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void oxnas_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
 
        ioread8_rep(oxnas->io_base, buf, len);
 }
 
-static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void oxnas_nand_write_buf(struct nand_chip *chip, const u8 *buf,
+                                int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
 
        iowrite8_rep(oxnas->io_base, buf, len);
 }
 
 /* Single CS command control */
-static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void oxnas_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
                                unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
 
        if (ctrl & NAND_CLE)
@@ -135,20 +132,20 @@ static int oxnas_nand_probe(struct platform_device *pdev)
                mtd->dev.parent = &pdev->dev;
                mtd->priv = chip;
 
-               chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
-               chip->read_buf = oxnas_nand_read_buf;
-               chip->read_byte = oxnas_nand_read_byte;
-               chip->write_buf = oxnas_nand_write_buf;
-               chip->chip_delay = 30;
+               chip->legacy.cmd_ctrl = oxnas_nand_cmd_ctrl;
+               chip->legacy.read_buf = oxnas_nand_read_buf;
+               chip->legacy.read_byte = oxnas_nand_read_byte;
+               chip->legacy.write_buf = oxnas_nand_write_buf;
+               chip->legacy.chip_delay = 30;
 
                /* Scan to find existence of the device */
-               err = nand_scan(mtd, 1);
+               err = nand_scan(chip, 1);
                if (err)
                        goto err_clk_unprepare;
 
                err = mtd_device_register(mtd, NULL, 0);
                if (err) {
-                       nand_release(mtd);
+                       nand_release(chip);
                        goto err_clk_unprepare;
                }
 
@@ -176,7 +173,7 @@ static int oxnas_nand_remove(struct platform_device *pdev)
        struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
 
        if (oxnas->chips[0])
-               nand_release(nand_to_mtd(oxnas->chips[0]));
+               nand_release(oxnas->chips[0]);
 
        clk_disable_unprepare(oxnas->clk);
 
index a47a7e4bd25aeba4a67ebe6e057278721299d2e5..643cd22af0093c07e4e6eb6cda70bf1261fddecd 100644 (file)
@@ -43,49 +43,44 @@ static unsigned int lpcctl;
 static struct mtd_info *pasemi_nand_mtd;
 static const char driver_name[] = "pasemi-nand";
 
-static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        while (len > 0x800) {
-               memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
+               memcpy_fromio(buf, chip->legacy.IO_ADDR_R, 0x800);
                buf += 0x800;
                len -= 0x800;
        }
-       memcpy_fromio(buf, chip->IO_ADDR_R, len);
+       memcpy_fromio(buf, chip->legacy.IO_ADDR_R, len);
 }
 
-static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void pasemi_write_buf(struct nand_chip *chip, const u_char *buf,
+                            int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        while (len > 0x800) {
-               memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
+               memcpy_toio(chip->legacy.IO_ADDR_R, buf, 0x800);
                buf += 0x800;
                len -= 0x800;
        }
-       memcpy_toio(chip->IO_ADDR_R, buf, len);
+       memcpy_toio(chip->legacy.IO_ADDR_R, buf, len);
 }
 
-static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
+static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
                             unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
-
        if (cmd == NAND_CMD_NONE)
                return;
 
        if (ctrl & NAND_CLE)
-               out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
+               out_8(chip->legacy.IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
        else
-               out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
+               out_8(chip->legacy.IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
 
        /* Push out posted writes */
        eieio();
        inl(lpcctl);
 }
 
-int pasemi_device_ready(struct mtd_info *mtd)
+int pasemi_device_ready(struct nand_chip *chip)
 {
        return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
 }
@@ -122,10 +117,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
        /* Link the private data with the MTD structure */
        pasemi_nand_mtd->dev.parent = dev;
 
-       chip->IO_ADDR_R = of_iomap(np, 0);
-       chip->IO_ADDR_W = chip->IO_ADDR_R;
+       chip->legacy.IO_ADDR_R = of_iomap(np, 0);
+       chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
 
-       if (!chip->IO_ADDR_R) {
+       if (!chip->legacy.IO_ADDR_R) {
                err = -EIO;
                goto out_mtd;
        }
@@ -144,11 +139,11 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
                goto out_ior;
        }
 
-       chip->cmd_ctrl = pasemi_hwcontrol;
-       chip->dev_ready = pasemi_device_ready;
-       chip->read_buf = pasemi_read_buf;
-       chip->write_buf = pasemi_write_buf;
-       chip->chip_delay = 0;
+       chip->legacy.cmd_ctrl = pasemi_hwcontrol;
+       chip->legacy.dev_ready = pasemi_device_ready;
+       chip->legacy.read_buf = pasemi_read_buf;
+       chip->legacy.write_buf = pasemi_write_buf;
+       chip->legacy.chip_delay = 0;
        chip->ecc.mode = NAND_ECC_SOFT;
        chip->ecc.algo = NAND_ECC_HAMMING;
 
@@ -156,7 +151,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
        chip->bbt_options = NAND_BBT_USE_FLASH;
 
        /* Scan to find existence of the device */
-       err = nand_scan(pasemi_nand_mtd, 1);
+       err = nand_scan(chip, 1);
        if (err)
                goto out_lpc;
 
@@ -174,7 +169,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
  out_lpc:
        release_region(lpcctl, 4);
  out_ior:
-       iounmap(chip->IO_ADDR_R);
+       iounmap(chip->legacy.IO_ADDR_R);
  out_mtd:
        kfree(chip);
  out:
@@ -191,11 +186,11 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
        chip = mtd_to_nand(pasemi_nand_mtd);
 
        /* Release resources, unregister device */
-       nand_release(pasemi_nand_mtd);
+       nand_release(chip);
 
        release_region(lpcctl, 4);
 
-       iounmap(chip->IO_ADDR_R);
+       iounmap(chip->legacy.IO_ADDR_R);
 
        /* Free the MTD device structure */
        kfree(chip);
index 222626df4b96d396a3b7e23da144cc2bf7661ebe..86c536ddaf248d5a99105f89af2d5dd01871a64d 100644 (file)
@@ -15,8 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
 
 struct plat_nand_data {
        struct nand_chip        chip;
@@ -60,14 +59,14 @@ static int plat_nand_probe(struct platform_device *pdev)
        mtd = nand_to_mtd(&data->chip);
        mtd->dev.parent = &pdev->dev;
 
-       data->chip.IO_ADDR_R = data->io_base;
-       data->chip.IO_ADDR_W = data->io_base;
-       data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
-       data->chip.dev_ready = pdata->ctrl.dev_ready;
+       data->chip.legacy.IO_ADDR_R = data->io_base;
+       data->chip.legacy.IO_ADDR_W = data->io_base;
+       data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl;
+       data->chip.legacy.dev_ready = pdata->ctrl.dev_ready;
        data->chip.select_chip = pdata->ctrl.select_chip;
-       data->chip.write_buf = pdata->ctrl.write_buf;
-       data->chip.read_buf = pdata->ctrl.read_buf;
-       data->chip.chip_delay = pdata->chip.chip_delay;
+       data->chip.legacy.write_buf = pdata->ctrl.write_buf;
+       data->chip.legacy.read_buf = pdata->ctrl.read_buf;
+       data->chip.legacy.chip_delay = pdata->chip.chip_delay;
        data->chip.options |= pdata->chip.options;
        data->chip.bbt_options |= pdata->chip.bbt_options;
 
@@ -84,7 +83,7 @@ static int plat_nand_probe(struct platform_device *pdev)
        }
 
        /* Scan to find existence of the device */
-       err = nand_scan(mtd, pdata->chip.nr_chips);
+       err = nand_scan(&data->chip, pdata->chip.nr_chips);
        if (err)
                goto out;
 
@@ -97,7 +96,7 @@ static int plat_nand_probe(struct platform_device *pdev)
        if (!err)
                return err;
 
-       nand_release(mtd);
+       nand_release(&data->chip);
 out:
        if (pdata->ctrl.remove)
                pdata->ctrl.remove(pdev);
@@ -112,7 +111,7 @@ static int plat_nand_remove(struct platform_device *pdev)
        struct plat_nand_data *data = platform_get_drvdata(pdev);
        struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
 
-       nand_release(nand_to_mtd(&data->chip));
+       nand_release(&data->chip);
        if (pdata->ctrl.remove)
                pdata->ctrl.remove(pdev);
 
index d1d470bb32e422ca6597fb6bdcbff3dadca32e07..ef75dfa62a4f816f49d6008dcc3bbd7561293530 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/of_device.h>
 #include <linux/delay.h>
 #include <linux/dma/qcom_bam_dma.h>
-#include <linux/dma-direct.h> /* XXX: drivers shall never use this directly! */
 
 /* NANDc reg offsets */
 #define        NAND_FLASH_CMD                  0x00
@@ -350,7 +349,8 @@ struct nandc_regs {
  * @data_buffer:               our local DMA buffer for page read/writes,
  *                             used when we can't use the buffer provided
  *                             by upper layers directly
- * @buf_size/count/start:      markers for chip->read_buf/write_buf functions
+ * @buf_size/count/start:      markers for chip->legacy.read_buf/write_buf
+ *                             functions
  * @reg_read_buf:              local buffer for reading back registers via DMA
  * @reg_read_dma:              contains dma address for register read buffer
  * @reg_read_pos:              marker for data read in reg_read_buf
@@ -1155,8 +1155,8 @@ static void config_nand_cw_write(struct qcom_nand_controller *nandc)
 }
 
 /*
- * the following functions are used within chip->cmdfunc() to perform different
- * NAND_CMD_* commands
+ * the following functions are used within chip->legacy.cmdfunc() to
+ * perform different NAND_CMD_* commands
  */
 
 /* sets up descriptors for NAND_CMD_PARAM */
@@ -1436,15 +1436,14 @@ static void post_command(struct qcom_nand_host *host, int command)
 }
 
 /*
- * Implements chip->cmdfunc. It's  only used for a limited set of commands.
- * The rest of the commands wouldn't be called by upper layers. For example,
- * NAND_CMD_READOOB would never be called because we have our own versions
- * of read_oob ops for nand_ecc_ctrl.
+ * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
+ * commands. The rest of the commands wouldn't be called by upper layers.
+ * For example, NAND_CMD_READOOB would never be called because we have our own
+ * versions of read_oob ops for nand_ecc_ctrl.
  */
-static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
+static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
                               int column, int page_addr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -1949,8 +1948,8 @@ static int copy_last_cw(struct qcom_nand_host *host, int page)
 }
 
 /* implements ecc->read_page() */
-static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int oob_required, int page)
+static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
+                               int oob_required, int page)
 {
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -1966,10 +1965,10 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /* implements ecc->read_page_raw() */
-static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
-                                   struct nand_chip *chip, uint8_t *buf,
+static int qcom_nandc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
                                    int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        int cw, ret;
@@ -1989,8 +1988,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
 }
 
 /* implements ecc->read_oob() */
-static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                              int page)
+static int qcom_nandc_read_oob(struct nand_chip *chip, int page)
 {
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -2007,8 +2005,8 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /* implements ecc->write_page() */
-static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                                const uint8_t *buf, int oob_required, int page)
+static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf,
+                                int oob_required, int page)
 {
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -2077,10 +2075,11 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /* implements ecc->write_page_raw() */
-static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
-                                    struct nand_chip *chip, const uint8_t *buf,
-                                    int oob_required, int page)
+static int qcom_nandc_write_page_raw(struct nand_chip *chip,
+                                    const uint8_t *buf, int oob_required,
+                                    int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2155,9 +2154,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
  * since ECC is calculated for the combined codeword. So update the OOB from
  * chip->oob_poi, and pad the data area with OxFF before writing.
  */
-static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                               int page)
+static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2197,9 +2196,9 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
        return nand_prog_page_end_op(chip);
 }
 
-static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2235,9 +2234,8 @@ err:
        return bad;
 }
 
-static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2278,14 +2276,13 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
 }
 
 /*
- * the three functions below implement chip->read_byte(), chip->read_buf()
- * and chip->write_buf() respectively. these aren't used for
- * reading/writing page data, they are used for smaller data like reading
- * id, status etc
+ * the three functions below implement chip->legacy.read_byte(),
+ * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
+ * aren't used for reading/writing page data, they are used for smaller data
+ * like reading        id, status etc
  */
-static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
+static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct qcom_nand_host *host = to_qcom_nand_host(chip);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
        u8 *buf = nandc->data_buffer;
@@ -2305,9 +2302,8 @@ static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
        return ret;
 }
 
-static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
        int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
 
@@ -2315,10 +2311,9 @@ static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
        nandc->buf_start += real_len;
 }
 
-static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
                                 int len)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
        int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
 
@@ -2328,9 +2323,8 @@ static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 }
 
 /* we support only one external chip for now */
-static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
+static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 
        if (chipnr <= 0)
@@ -2809,13 +2803,13 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
        mtd->owner = THIS_MODULE;
        mtd->dev.parent = dev;
 
-       chip->cmdfunc           = qcom_nandc_command;
+       chip->legacy.cmdfunc    = qcom_nandc_command;
        chip->select_chip       = qcom_nandc_select_chip;
-       chip->read_byte         = qcom_nandc_read_byte;
-       chip->read_buf          = qcom_nandc_read_buf;
-       chip->write_buf         = qcom_nandc_write_buf;
-       chip->set_features      = nand_get_set_features_notsupp;
-       chip->get_features      = nand_get_set_features_notsupp;
+       chip->legacy.read_byte  = qcom_nandc_read_byte;
+       chip->legacy.read_buf   = qcom_nandc_read_buf;
+       chip->legacy.write_buf  = qcom_nandc_write_buf;
+       chip->legacy.set_features       = nand_get_set_features_notsupp;
+       chip->legacy.get_features       = nand_get_set_features_notsupp;
 
        /*
         * the bad block marker is readable only when we read the last codeword
@@ -2825,8 +2819,8 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
         * and block_markbad helpers until we permanently switch to using
         * MTD_OPS_RAW for all drivers (with the help of badblockbits)
         */
-       chip->block_bad         = qcom_nandc_block_bad;
-       chip->block_markbad     = qcom_nandc_block_markbad;
+       chip->legacy.block_bad          = qcom_nandc_block_bad;
+       chip->legacy.block_markbad      = qcom_nandc_block_markbad;
 
        chip->controller = &nandc->controller;
        chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
@@ -2835,7 +2829,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
        /* set up initial status value */
        host->status = NAND_STATUS_READY | NAND_STATUS_WP;
 
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(chip, 1);
        if (ret)
                return ret;
 
@@ -3000,7 +2994,7 @@ static int qcom_nandc_remove(struct platform_device *pdev)
        struct qcom_nand_host *host;
 
        list_for_each_entry(host, &nandc->host_list, node)
-               nand_release(nand_to_mtd(&host->chip));
+               nand_release(&host->chip);
 
 
        qcom_nandc_unalloc(nandc);
index dcdeb0660e5e394b02c4cb5e3b207fb33470878a..39be65b35ac251dde3e0f4d500b703fabc2ef3c9 100644 (file)
@@ -232,9 +232,9 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
 /*
  * Program data lines of the nand chip to send data to it
  */
-static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void r852_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
 {
-       struct r852_device *dev = r852_get_dev(mtd);
+       struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
        uint32_t reg;
 
        /* Don't allow any access to hardware if we suspect card removal */
@@ -266,9 +266,9 @@ static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 /*
  * Read data lines of the nand chip to retrieve data
  */
-static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void r852_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct r852_device *dev = r852_get_dev(mtd);
+       struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
        uint32_t reg;
 
        if (dev->card_unstable) {
@@ -303,9 +303,9 @@ static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 /*
  * Read one byte from nand chip
  */
-static uint8_t r852_read_byte(struct mtd_info *mtd)
+static uint8_t r852_read_byte(struct nand_chip *chip)
 {
-       struct r852_device *dev = r852_get_dev(mtd);
+       struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
 
        /* Same problem as in r852_read_buf.... */
        if (dev->card_unstable)
@@ -317,9 +317,9 @@ static uint8_t r852_read_byte(struct mtd_info *mtd)
 /*
  * Control several chip lines & send commands
  */
-static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void r852_cmdctl(struct nand_chip *chip, int dat, unsigned int ctrl)
 {
-       struct r852_device *dev = r852_get_dev(mtd);
+       struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
 
        if (dev->card_unstable)
                return;
@@ -362,7 +362,7 @@ static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
  * Wait till card is ready.
  * based on nand_wait, but returns errors on DMA error
  */
-static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int r852_wait(struct nand_chip *chip)
 {
        struct r852_device *dev = nand_get_controller_data(chip);
 
@@ -373,7 +373,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
                msecs_to_jiffies(400) : msecs_to_jiffies(20));
 
        while (time_before(jiffies, timeout))
-               if (chip->dev_ready(mtd))
+               if (chip->legacy.dev_ready(chip))
                        break;
 
        nand_status_op(chip, &status);
@@ -390,9 +390,9 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
  * Check if card is ready
  */
 
-static int r852_ready(struct mtd_info *mtd)
+static int r852_ready(struct nand_chip *chip)
 {
-       struct r852_device *dev = r852_get_dev(mtd);
+       struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
        return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
 }
 
@@ -401,9 +401,9 @@ static int r852_ready(struct mtd_info *mtd)
  * Set ECC engine mode
 */
 
-static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
+static void r852_ecc_hwctl(struct nand_chip *chip, int mode)
 {
-       struct r852_device *dev = r852_get_dev(mtd);
+       struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
 
        if (dev->card_unstable)
                return;
@@ -433,10 +433,10 @@ static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
  * Calculate ECC, only used for writes
  */
 
-static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
-                                                       uint8_t *ecc_code)
+static int r852_ecc_calculate(struct nand_chip *chip, const uint8_t *dat,
+                             uint8_t *ecc_code)
 {
-       struct r852_device *dev = r852_get_dev(mtd);
+       struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
        struct sm_oob *oob = (struct sm_oob *)ecc_code;
        uint32_t ecc1, ecc2;
 
@@ -465,14 +465,14 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
  * Correct the data using ECC, hw did almost everything for us
  */
 
-static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
-                               uint8_t *read_ecc, uint8_t *calc_ecc)
+static int r852_ecc_correct(struct nand_chip *chip, uint8_t *dat,
+                           uint8_t *read_ecc, uint8_t *calc_ecc)
 {
        uint32_t ecc_reg;
        uint8_t ecc_status, err_byte;
        int i, error = 0;
 
-       struct r852_device *dev = r852_get_dev(mtd);
+       struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
 
        if (dev->card_unstable)
                return 0;
@@ -521,9 +521,10 @@ exit:
  * This is copy of nand_read_oob_std
  * nand_read_oob_syndrome assumes we can send column address - we can't
  */
-static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                            int page)
+static int r852_read_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
 }
 
@@ -636,7 +637,7 @@ static int r852_register_nand_device(struct r852_device *dev)
 {
        struct mtd_info *mtd = nand_to_mtd(dev->chip);
 
-       WARN_ON(dev->card_registred);
+       WARN_ON(dev->card_registered);
 
        mtd->dev.parent = &dev->pci_dev->dev;
 
@@ -653,10 +654,10 @@ static int r852_register_nand_device(struct r852_device *dev)
                goto error3;
        }
 
-       dev->card_registred = 1;
+       dev->card_registered = 1;
        return 0;
 error3:
-       nand_release(mtd);
+       nand_release(dev->chip);
 error1:
        /* Force card redetect */
        dev->card_detected = 0;
@@ -671,13 +672,13 @@ static void r852_unregister_nand_device(struct r852_device *dev)
 {
        struct mtd_info *mtd = nand_to_mtd(dev->chip);
 
-       if (!dev->card_registred)
+       if (!dev->card_registered)
                return;
 
        device_remove_file(&mtd->dev, &dev_attr_media_type);
-       nand_release(mtd);
+       nand_release(dev->chip);
        r852_engine_disable(dev);
-       dev->card_registred = 0;
+       dev->card_registered = 0;
 }
 
 /* Card state updater */
@@ -691,7 +692,7 @@ static void r852_card_detect_work(struct work_struct *work)
        dev->card_unstable = 0;
 
        /* False alarm */
-       if (dev->card_detected == dev->card_registred)
+       if (dev->card_detected == dev->card_registered)
                goto exit;
 
        /* Read media properties */
@@ -852,14 +853,14 @@ static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
                goto error4;
 
        /* commands */
-       chip->cmd_ctrl = r852_cmdctl;
-       chip->waitfunc = r852_wait;
-       chip->dev_ready = r852_ready;
+       chip->legacy.cmd_ctrl = r852_cmdctl;
+       chip->legacy.waitfunc = r852_wait;
+       chip->legacy.dev_ready = r852_ready;
 
        /* I/O */
-       chip->read_byte = r852_read_byte;
-       chip->read_buf = r852_read_buf;
-       chip->write_buf = r852_write_buf;
+       chip->legacy.read_byte = r852_read_byte;
+       chip->legacy.read_buf = r852_read_buf;
+       chip->legacy.write_buf = r852_write_buf;
 
        /* ecc */
        chip->ecc.mode = NAND_ECC_HW_SYNDROME;
@@ -1025,7 +1026,6 @@ static int r852_suspend(struct device *device)
 static int r852_resume(struct device *device)
 {
        struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
-       struct mtd_info *mtd = nand_to_mtd(dev->chip);
 
        r852_disable_irqs(dev);
        r852_card_update_present(dev);
@@ -1033,7 +1033,7 @@ static int r852_resume(struct device *device)
 
 
        /* If card status changed, just do the work */
-       if (dev->card_detected != dev->card_registred) {
+       if (dev->card_detected != dev->card_registered) {
                dbg("card was %s during low power state",
                        dev->card_detected ? "added" : "removed");
 
@@ -1043,11 +1043,11 @@ static int r852_resume(struct device *device)
        }
 
        /* Otherwise, initialize the card */
-       if (dev->card_registred) {
+       if (dev->card_registered) {
                r852_engine_enable(dev);
-               dev->chip->select_chip(mtd, 0);
+               dev->chip->select_chip(dev->chip, 0);
                nand_reset_op(dev->chip);
-               dev->chip->select_chip(mtd, -1);
+               dev->chip->select_chip(dev->chip, -1);
        }
 
        /* Program card detection IRQ */
index 1eed2fc2fa4275648c089aafd0de44188788a8a6..bc67f5bf67e8d07d5f2b2cec24d6817e62a81b2b 100644 (file)
@@ -129,7 +129,7 @@ struct r852_device {
        /* card status area */
        struct delayed_work card_detect_work;
        struct workqueue_struct *card_workqueue;
-       int card_registred;             /* card registered with mtd */
+       int card_registered;            /* card registered with mtd */
        int card_detected;              /* card detected in slot */
        int card_unstable;              /* whenever the card is inserted,
                                           is not known yet */
index c21e8892394a3d9f2be39070c5dd9a44ec676fd6..d2e42e9d0e8c15cfca6b235bb8ea5a96e733545b 100644 (file)
@@ -404,7 +404,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
 
 /**
  * s3c2410_nand_select_chip - select the given nand chip
- * @mtd: The MTD instance for this chip.
+ * @this: NAND chip object.
  * @chip: The chip number.
  *
  * This is called by the MTD layer to either select a given chip for the
@@ -415,11 +415,10 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
  * platform specific selection code is called to route nFCE to the specific
  * chip.
  */
-static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
+static void s3c2410_nand_select_chip(struct nand_chip *this, int chip)
 {
        struct s3c2410_nand_info *info;
        struct s3c2410_nand_mtd *nmtd;
-       struct nand_chip *this = mtd_to_nand(mtd);
        unsigned long cur;
 
        nmtd = nand_get_controller_data(this);
@@ -457,9 +456,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
  * Issue command and address cycles to the chip
 */
 
-static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd,
                                   unsigned int ctrl)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
 
        if (cmd == NAND_CMD_NONE)
@@ -473,9 +473,10 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
 
 /* command and control functions */
 
-static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd,
                                   unsigned int ctrl)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
 
        if (cmd == NAND_CMD_NONE)
@@ -492,29 +493,33 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
  * returns 0 if the nand is busy, 1 if it is ready
 */
 
-static int s3c2410_nand_devready(struct mtd_info *mtd)
+static int s3c2410_nand_devready(struct nand_chip *chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
        return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
 }
 
-static int s3c2440_nand_devready(struct mtd_info *mtd)
+static int s3c2440_nand_devready(struct nand_chip *chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
        return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
 }
 
-static int s3c2412_nand_devready(struct mtd_info *mtd)
+static int s3c2412_nand_devready(struct nand_chip *chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
        return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
 }
 
 /* ECC handling functions */
 
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat,
                                     u_char *read_ecc, u_char *calc_ecc)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
        unsigned int diff0, diff1, diff2;
        unsigned int bit, byte;
@@ -591,38 +596,42 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
  * generator block to ECC the data as it passes through]
 */
 
-static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode)
 {
-       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       struct s3c2410_nand_info *info;
        unsigned long ctrl;
 
+       info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
        ctrl = readl(info->regs + S3C2410_NFCONF);
        ctrl |= S3C2410_NFCONF_INITECC;
        writel(ctrl, info->regs + S3C2410_NFCONF);
 }
 
-static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode)
 {
-       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       struct s3c2410_nand_info *info;
        unsigned long ctrl;
 
+       info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
        ctrl = readl(info->regs + S3C2440_NFCONT);
        writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
               info->regs + S3C2440_NFCONT);
 }
 
-static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode)
 {
-       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       struct s3c2410_nand_info *info;
        unsigned long ctrl;
 
+       info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
        ctrl = readl(info->regs + S3C2440_NFCONT);
        writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
 }
 
-static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-                                     u_char *ecc_code)
+static int s3c2410_nand_calculate_ecc(struct nand_chip *chip,
+                                     const u_char *dat, u_char *ecc_code)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
 
        ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
@@ -634,9 +643,10 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
        return 0;
 }
 
-static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-                                     u_char *ecc_code)
+static int s3c2412_nand_calculate_ecc(struct nand_chip *chip,
+                                     const u_char *dat, u_char *ecc_code)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
        unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
 
@@ -649,9 +659,10 @@ static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
        return 0;
 }
 
-static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-                                     u_char *ecc_code)
+static int s3c2440_nand_calculate_ecc(struct nand_chip *chip,
+                                     const u_char *dat, u_char *ecc_code)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
        unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
 
@@ -668,14 +679,14 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
  * use read/write block to move the data buffers to/from the controller
 */
 
-static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       readsb(this->IO_ADDR_R, buf, len);
+       readsb(this->legacy.IO_ADDR_R, buf, len);
 }
 
-static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
 {
+       struct mtd_info *mtd = nand_to_mtd(this);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
 
        readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
@@ -689,16 +700,16 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
        }
 }
 
-static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf,
                                   int len)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       writesb(this->IO_ADDR_W, buf, len);
+       writesb(this->legacy.IO_ADDR_W, buf, len);
 }
 
-static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,
                                   int len)
 {
+       struct mtd_info *mtd = nand_to_mtd(this);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
 
        writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
@@ -781,7 +792,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
 
                for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
                        pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
-                       nand_release(nand_to_mtd(&ptr->chip));
+                       nand_release(&ptr->chip);
                }
        }
 
@@ -809,9 +820,10 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
        return -ENODEV;
 }
 
-static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+static int s3c2410_nand_setup_data_interface(struct nand_chip *chip, int csline,
                                        const struct nand_data_interface *conf)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
        struct s3c2410_platform_nand *pdata = info->platform;
        const struct nand_sdr_timings *timings;
@@ -852,10 +864,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 
        nand_set_flash_node(chip, set->of_node);
 
-       chip->write_buf    = s3c2410_nand_write_buf;
-       chip->read_buf     = s3c2410_nand_read_buf;
+       chip->legacy.write_buf    = s3c2410_nand_write_buf;
+       chip->legacy.read_buf     = s3c2410_nand_read_buf;
        chip->select_chip  = s3c2410_nand_select_chip;
-       chip->chip_delay   = 50;
+       chip->legacy.chip_delay   = 50;
        nand_set_controller_data(chip, nmtd);
        chip->options      = set->options;
        chip->controller   = &info->controller;
@@ -869,29 +881,29 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 
        switch (info->cpu_type) {
        case TYPE_S3C2410:
-               chip->IO_ADDR_W = regs + S3C2410_NFDATA;
+               chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA;
                info->sel_reg   = regs + S3C2410_NFCONF;
                info->sel_bit   = S3C2410_NFCONF_nFCE;
-               chip->cmd_ctrl  = s3c2410_nand_hwcontrol;
-               chip->dev_ready = s3c2410_nand_devready;
+               chip->legacy.cmd_ctrl  = s3c2410_nand_hwcontrol;
+               chip->legacy.dev_ready = s3c2410_nand_devready;
                break;
 
        case TYPE_S3C2440:
-               chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+               chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
                info->sel_reg   = regs + S3C2440_NFCONT;
                info->sel_bit   = S3C2440_NFCONT_nFCE;
-               chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
-               chip->dev_ready = s3c2440_nand_devready;
-               chip->read_buf  = s3c2440_nand_read_buf;
-               chip->write_buf = s3c2440_nand_write_buf;
+               chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;
+               chip->legacy.dev_ready = s3c2440_nand_devready;
+               chip->legacy.read_buf  = s3c2440_nand_read_buf;
+               chip->legacy.write_buf  = s3c2440_nand_write_buf;
                break;
 
        case TYPE_S3C2412:
-               chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+               chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
                info->sel_reg   = regs + S3C2440_NFCONT;
                info->sel_bit   = S3C2412_NFCONT_nFCE0;
-               chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
-               chip->dev_ready = s3c2412_nand_devready;
+               chip->legacy.cmd_ctrl  = s3c2440_nand_hwcontrol;
+               chip->legacy.dev_ready = s3c2412_nand_devready;
 
                if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
                        dev_info(info->device, "System booted from NAND\n");
@@ -899,7 +911,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
                break;
        }
 
-       chip->IO_ADDR_R = chip->IO_ADDR_W;
+       chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W;
 
        nmtd->info         = info;
        nmtd->set          = set;
@@ -1170,7 +1182,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
                mtd->dev.parent = &pdev->dev;
                s3c2410_nand_init_chip(info, nmtd, sets);
 
-               err = nand_scan(mtd, sets ? sets->nr_chips : 1);
+               err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1);
                if (err)
                        goto exit_error;
 
index bb8866e05ff76cc2be9bb1d24f2f5eaadb3799bc..4d20d033de7b32559f1f9606b4693b1067601a11 100644 (file)
@@ -480,7 +480,7 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
 
        /* initiate DMA transfer */
        if (flctl->chan_fifo0_rx && rlen >= 32 &&
-               flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
+               flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE) > 0)
                        goto convert;   /* DMA success */
 
        /* do polling transfer */
@@ -539,7 +539,7 @@ static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
 
        /* initiate DMA transfer */
        if (flctl->chan_fifo0_tx && rlen >= 32 &&
-               flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
+               flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE) > 0)
                        return; /* DMA success */
 
        /* do polling transfer */
@@ -611,21 +611,24 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
        writel(flcmcdr_val, FLCMCDR(flctl));
 }
 
-static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int oob_required, int page)
+static int flctl_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+                                int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        nand_read_page_op(chip, page, 0, buf, mtd->writesize);
        if (oob_required)
-               chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+               chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
        return 0;
 }
 
-static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                 const uint8_t *buf, int oob_required,
-                                 int page)
+static int flctl_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf,
+                                 int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
-       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
        return nand_prog_page_end_op(chip);
 }
 
@@ -747,9 +750,10 @@ static void execmd_write_oob(struct mtd_info *mtd)
        }
 }
 
-static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
+static void flctl_cmdfunc(struct nand_chip *chip, unsigned int command,
                        int column, int page_addr)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
        uint32_t read_cmd = 0;
 
@@ -923,9 +927,9 @@ runtime_exit:
        return;
 }
 
-static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
+static void flctl_select_chip(struct nand_chip *chip, int chipnr)
 {
-       struct sh_flctl *flctl = mtd_to_flctl(mtd);
+       struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
        int ret;
 
        switch (chipnr) {
@@ -967,17 +971,17 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
        }
 }
 
-static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void flctl_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
 {
-       struct sh_flctl *flctl = mtd_to_flctl(mtd);
+       struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
 
        memcpy(&flctl->done_buff[flctl->index], buf, len);
        flctl->index += len;
 }
 
-static uint8_t flctl_read_byte(struct mtd_info *mtd)
+static uint8_t flctl_read_byte(struct nand_chip *chip)
 {
-       struct sh_flctl *flctl = mtd_to_flctl(mtd);
+       struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
        uint8_t data;
 
        data = flctl->done_buff[flctl->index];
@@ -985,18 +989,9 @@ static uint8_t flctl_read_byte(struct mtd_info *mtd)
        return data;
 }
 
-static uint16_t flctl_read_word(struct mtd_info *mtd)
+static void flctl_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
-
-       flctl->index += 2;
-       return *buf;
-}
-
-static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-       struct sh_flctl *flctl = mtd_to_flctl(mtd);
+       struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
 
        memcpy(buf, &flctl->done_buff[flctl->index], len);
        flctl->index += len;
@@ -1183,16 +1178,15 @@ static int flctl_probe(struct platform_device *pdev)
 
        /* Set address of hardware control function */
        /* 20 us command delay time */
-       nand->chip_delay = 20;
+       nand->legacy.chip_delay = 20;
 
-       nand->read_byte = flctl_read_byte;
-       nand->read_word = flctl_read_word;
-       nand->write_buf = flctl_write_buf;
-       nand->read_buf = flctl_read_buf;
+       nand->legacy.read_byte = flctl_read_byte;
+       nand->legacy.write_buf = flctl_write_buf;
+       nand->legacy.read_buf = flctl_read_buf;
        nand->select_chip = flctl_select_chip;
-       nand->cmdfunc = flctl_cmdfunc;
-       nand->set_features = nand_get_set_features_notsupp;
-       nand->get_features = nand_get_set_features_notsupp;
+       nand->legacy.cmdfunc = flctl_cmdfunc;
+       nand->legacy.set_features = nand_get_set_features_notsupp;
+       nand->legacy.get_features = nand_get_set_features_notsupp;
 
        if (pdata->flcmncr_val & SEL_16BIT)
                nand->options |= NAND_BUSWIDTH_16;
@@ -1203,7 +1197,7 @@ static int flctl_probe(struct platform_device *pdev)
        flctl_setup_dma(flctl);
 
        nand->dummy_controller.ops = &flctl_nand_controller_ops;
-       ret = nand_scan(flctl_mtd, 1);
+       ret = nand_scan(nand, 1);
        if (ret)
                goto err_chip;
 
@@ -1226,7 +1220,7 @@ static int flctl_remove(struct platform_device *pdev)
        struct sh_flctl *flctl = platform_get_drvdata(pdev);
 
        flctl_release_dma(flctl);
-       nand_release(nand_to_mtd(&flctl->chip));
+       nand_release(&flctl->chip);
        pm_runtime_disable(&pdev->dev);
 
        return 0;
index fc171b17a39b8dce93587ba8315120162bc8012f..c82f26c8b58cb06ecc036cfd3e403559ef75b504 100644 (file)
@@ -59,11 +59,10 @@ static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
  *     NAND_ALE: bit 2 -> bit 2
  *
  */
-static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+static void sharpsl_nand_hwcontrol(struct nand_chip *chip, int cmd,
                                   unsigned int ctrl)
 {
-       struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
 
        if (ctrl & NAND_CTRL_CHANGE) {
                unsigned char bits = ctrl & 0x07;
@@ -76,24 +75,25 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
        }
 
        if (cmd != NAND_CMD_NONE)
-               writeb(cmd, chip->IO_ADDR_W);
+               writeb(cmd, chip->legacy.IO_ADDR_W);
 }
 
-static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
+static int sharpsl_nand_dev_ready(struct nand_chip *chip)
 {
-       struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+       struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
        return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
 }
 
-static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void sharpsl_nand_enable_hwecc(struct nand_chip *chip, int mode)
 {
-       struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+       struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
        writeb(0, sharpsl->io + ECCCLRR);
 }
 
-static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
+static int sharpsl_nand_calculate_ecc(struct nand_chip *chip,
+                                     const u_char * dat, u_char * ecc_code)
 {
-       struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+       struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
        ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
        ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
        ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
@@ -153,13 +153,13 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
        writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
 
        /* Set address of NAND IO lines */
-       this->IO_ADDR_R = sharpsl->io + FLASHIO;
-       this->IO_ADDR_W = sharpsl->io + FLASHIO;
+       this->legacy.IO_ADDR_R = sharpsl->io + FLASHIO;
+       this->legacy.IO_ADDR_W = sharpsl->io + FLASHIO;
        /* Set address of hardware control function */
-       this->cmd_ctrl = sharpsl_nand_hwcontrol;
-       this->dev_ready = sharpsl_nand_dev_ready;
+       this->legacy.cmd_ctrl = sharpsl_nand_hwcontrol;
+       this->legacy.dev_ready = sharpsl_nand_dev_ready;
        /* 15 us command delay time */
-       this->chip_delay = 15;
+       this->legacy.chip_delay = 15;
        /* set eccmode using hardware ECC */
        this->ecc.mode = NAND_ECC_HW;
        this->ecc.size = 256;
@@ -171,7 +171,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
        this->ecc.correct = nand_correct_data;
 
        /* Scan to find existence of the device */
-       err = nand_scan(mtd, 1);
+       err = nand_scan(this, 1);
        if (err)
                goto err_scan;
 
@@ -187,7 +187,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
        return 0;
 
 err_add:
-       nand_release(mtd);
+       nand_release(this);
 
 err_scan:
        iounmap(sharpsl->io);
@@ -205,7 +205,7 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
        struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
 
        /* Release resources, unregister device */
-       nand_release(nand_to_mtd(&sharpsl->chip));
+       nand_release(&sharpsl->chip);
 
        iounmap(sharpsl->io);
 
index 73aafe8c3ef34944db18e47bcffb49fec6995635..6f063ef576405f089622be656fba11ea3ca86745 100644 (file)
@@ -99,8 +99,9 @@ static const struct mtd_ooblayout_ops oob_sm_small_ops = {
        .free = oob_sm_small_ooblayout_free,
 };
 
-static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int sm_block_markbad(struct nand_chip *chip, loff_t ofs)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct mtd_oob_ops ops;
        struct sm_oob oob;
        int ret;
@@ -167,7 +168,7 @@ static int sm_attach_chip(struct nand_chip *chip)
        /* Bad block marker position */
        chip->badblockpos = 0x05;
        chip->badblockbits = 7;
-       chip->block_markbad = sm_block_markbad;
+       chip->legacy.block_markbad = sm_block_markbad;
 
        /* ECC layout */
        if (mtd->writesize == SM_SECTOR_SIZE)
@@ -195,7 +196,7 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
        /* Scan for card properties */
        chip->dummy_controller.ops = &sm_controller_ops;
        flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
-       ret = nand_scan_with_ids(mtd, 1, flash_ids);
+       ret = nand_scan_with_ids(chip, 1, flash_ids);
        if (ret)
                return ret;
 
index 9824a9923583c453906ae499e18992b8fd096904..8be9a50c78804956a21022536d9120262680ccde 100644 (file)
@@ -34,15 +34,14 @@ struct socrates_nand_host {
 
 /**
  * socrates_nand_write_buf -  write buffer to chip
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  * @buf:       data buffer
  * @len:       number of bytes to write
  */
-static void socrates_nand_write_buf(struct mtd_info *mtd,
-               const uint8_t *buf, int len)
+static void socrates_nand_write_buf(struct nand_chip *this, const uint8_t *buf,
+                                   int len)
 {
        int i;
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct socrates_nand_host *host = nand_get_controller_data(this);
 
        for (i = 0; i < len; i++) {
@@ -54,14 +53,14 @@ static void socrates_nand_write_buf(struct mtd_info *mtd,
 
 /**
  * socrates_nand_read_buf -  read chip data into buffer
- * @mtd:       MTD device structure
+ * @this:      NAND chip object
  * @buf:       buffer to store date
  * @len:       number of bytes to read
  */
-static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void socrates_nand_read_buf(struct nand_chip *this, uint8_t *buf,
+                                  int len)
 {
        int i;
-       struct nand_chip *this = mtd_to_nand(mtd);
        struct socrates_nand_host *host = nand_get_controller_data(this);
        uint32_t val;
 
@@ -78,31 +77,19 @@ static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
  * socrates_nand_read_byte -  read one byte from the chip
  * @mtd:       MTD device structure
  */
-static uint8_t socrates_nand_read_byte(struct mtd_info *mtd)
+static uint8_t socrates_nand_read_byte(struct nand_chip *this)
 {
        uint8_t byte;
-       socrates_nand_read_buf(mtd, &byte, sizeof(byte));
+       socrates_nand_read_buf(this, &byte, sizeof(byte));
        return byte;
 }
 
-/**
- * socrates_nand_read_word -  read one word from the chip
- * @mtd:       MTD device structure
- */
-static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
-{
-       uint16_t word;
-       socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word));
-       return word;
-}
-
 /*
  * Hardware specific access to control-lines
  */
-static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
-               unsigned int ctrl)
+static void socrates_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
+                                  unsigned int ctrl)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
        uint32_t val;
 
@@ -125,9 +112,8 @@ static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
 /*
  * Read the Device Ready pin.
  */
-static int socrates_nand_device_ready(struct mtd_info *mtd)
+static int socrates_nand_device_ready(struct nand_chip *nand_chip)
 {
-       struct nand_chip *nand_chip = mtd_to_nand(mtd);
        struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
 
        if (in_be32(host->io_base) & FPGA_NAND_BUSY)
@@ -166,26 +152,21 @@ static int socrates_nand_probe(struct platform_device *ofdev)
        mtd->name = "socrates_nand";
        mtd->dev.parent = &ofdev->dev;
 
-       /*should never be accessed directly */
-       nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
-       nand_chip->IO_ADDR_W = (void *)0xdeadbeef;
-
-       nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl;
-       nand_chip->read_byte = socrates_nand_read_byte;
-       nand_chip->read_word = socrates_nand_read_word;
-       nand_chip->write_buf = socrates_nand_write_buf;
-       nand_chip->read_buf = socrates_nand_read_buf;
-       nand_chip->dev_ready = socrates_nand_device_ready;
+       nand_chip->legacy.cmd_ctrl = socrates_nand_cmd_ctrl;
+       nand_chip->legacy.read_byte = socrates_nand_read_byte;
+       nand_chip->legacy.write_buf = socrates_nand_write_buf;
+       nand_chip->legacy.read_buf = socrates_nand_read_buf;
+       nand_chip->legacy.dev_ready = socrates_nand_device_ready;
 
        nand_chip->ecc.mode = NAND_ECC_SOFT;    /* enable ECC */
        nand_chip->ecc.algo = NAND_ECC_HAMMING;
 
        /* TODO: I have no idea what real delay is. */
-       nand_chip->chip_delay = 20;             /* 20us command delay time */
+       nand_chip->legacy.chip_delay = 20;      /* 20us command delay time */
 
        dev_set_drvdata(&ofdev->dev, host);
 
-       res = nand_scan(mtd, 1);
+       res = nand_scan(nand_chip, 1);
        if (res)
                goto out;
 
@@ -193,7 +174,7 @@ static int socrates_nand_probe(struct platform_device *ofdev)
        if (!res)
                return res;
 
-       nand_release(mtd);
+       nand_release(nand_chip);
 
 out:
        iounmap(host->io_base);
@@ -206,9 +187,8 @@ out:
 static int socrates_nand_remove(struct platform_device *ofdev)
 {
        struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
-       struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
 
-       nand_release(mtd);
+       nand_release(&host->nand_chip);
 
        iounmap(host->io_base);
 
index 1f0b7ee38df5627acf1d0f675fc5d85abb7aea67..51b1a548064b60bc263396efde767786550fac00 100644 (file)
@@ -400,9 +400,8 @@ static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
               nfc->regs + NFC_REG_CTL);
 }
 
-static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
+static int sunxi_nfc_dev_ready(struct nand_chip *nand)
 {
-       struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
        struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
        u32 mask;
@@ -420,9 +419,9 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
        return !!(readl(nfc->regs + NFC_REG_ST) & mask);
 }
 
-static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void sunxi_nfc_select_chip(struct nand_chip *nand, int chip)
 {
-       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(nand);
        struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
        struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
        struct sunxi_nand_chip_sel *sel;
@@ -443,9 +442,9 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
                ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
                       NFC_PAGE_SHIFT(nand->page_shift);
                if (sel->rb < 0) {
-                       nand->dev_ready = NULL;
+                       nand->legacy.dev_ready = NULL;
                } else {
-                       nand->dev_ready = sunxi_nfc_dev_ready;
+                       nand->legacy.dev_ready = sunxi_nfc_dev_ready;
                        ctl |= NFC_RB_SEL(sel->rb);
                }
 
@@ -464,9 +463,8 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
        sunxi_nand->selected = chip;
 }
 
-static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
 {
-       struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
        struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
        int ret;
@@ -502,10 +500,9 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
        }
 }
 
-static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
                                int len)
 {
-       struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
        struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
        int ret;
@@ -540,19 +537,18 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
        }
 }
 
-static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
+static uint8_t sunxi_nfc_read_byte(struct nand_chip *nand)
 {
        uint8_t ret = 0;
 
-       sunxi_nfc_read_buf(mtd, &ret, 1);
+       sunxi_nfc_read_buf(nand, &ret, 1);
 
        return ret;
 }
 
-static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
+static void sunxi_nfc_cmd_ctrl(struct nand_chip *nand, int dat,
                               unsigned int ctrl)
 {
-       struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
        struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
        int ret;
@@ -761,7 +757,7 @@ static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
 {
        sunxi_nfc_randomizer_config(mtd, page, ecc);
        sunxi_nfc_randomizer_enable(mtd);
-       sunxi_nfc_write_buf(mtd, buf, len);
+       sunxi_nfc_write_buf(mtd_to_nand(mtd), buf, len);
        sunxi_nfc_randomizer_disable(mtd);
 }
 
@@ -770,7 +766,7 @@ static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
 {
        sunxi_nfc_randomizer_config(mtd, page, ecc);
        sunxi_nfc_randomizer_enable(mtd);
-       sunxi_nfc_read_buf(mtd, buf, len);
+       sunxi_nfc_read_buf(mtd_to_nand(mtd), buf, len);
        sunxi_nfc_randomizer_disable(mtd);
 }
 
@@ -995,7 +991,7 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
                                           false);
 
        if (!randomize)
-               sunxi_nfc_read_buf(mtd, oob + offset, len);
+               sunxi_nfc_read_buf(nand, oob + offset, len);
        else
                sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
                                              false, page);
@@ -1189,10 +1185,10 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
                *cur_off = mtd->oobsize + mtd->writesize;
 }
 
-static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
-                                     struct nand_chip *chip, uint8_t *buf,
+static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
                                      int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        unsigned int max_bitflips = 0;
        int ret, i, cur_off = 0;
@@ -1227,10 +1223,10 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
        return max_bitflips;
 }
 
-static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
-                                         struct nand_chip *chip, u8 *buf,
+static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *chip, u8 *buf,
                                          int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
        nand_read_page_op(chip, page, 0, NULL, 0);
@@ -1241,14 +1237,14 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
                return ret;
 
        /* Fallback to PIO mode */
-       return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
+       return sunxi_nfc_hw_ecc_read_page(chip, buf, oob_required, page);
 }
 
-static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
-                                        struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *chip,
                                         u32 data_offs, u32 readlen,
                                         u8 *bufpoi, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        int ret, i, cur_off = 0;
        unsigned int max_bitflips = 0;
@@ -1278,11 +1274,11 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
        return max_bitflips;
 }
 
-static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
-                                            struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *chip,
                                             u32 data_offs, u32 readlen,
                                             u8 *buf, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
        int ret;
 
@@ -1293,15 +1289,15 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
                return ret;
 
        /* Fallback to PIO mode */
-       return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
+       return sunxi_nfc_hw_ecc_read_subpage(chip, data_offs, readlen,
                                             buf, page);
 }
 
-static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
-                                      struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *chip,
                                       const uint8_t *buf, int oob_required,
                                       int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        int ret, i, cur_off = 0;
 
@@ -1331,12 +1327,12 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
        return nand_prog_page_end_op(chip);
 }
 
-static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
-                                         struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *chip,
                                          u32 data_offs, u32 data_len,
                                          const u8 *buf, int oob_required,
                                          int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        int ret, i, cur_off = 0;
 
@@ -1363,12 +1359,12 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
        return nand_prog_page_end_op(chip);
 }
 
-static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
-                                          struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *chip,
                                           const u8 *buf,
                                           int oob_required,
                                           int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
        struct nand_ecc_ctrl *ecc = &nand->ecc;
@@ -1425,28 +1421,25 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
        return nand_prog_page_end_op(chip);
 
 pio_fallback:
-       return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
+       return sunxi_nfc_hw_ecc_write_page(chip, buf, oob_required, page);
 }
 
-static int sunxi_nfc_hw_ecc_read_oob(struct mtd_info *mtd,
-                                    struct nand_chip *chip,
-                                    int page)
+static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *chip, int page)
 {
        chip->pagebuf = -1;
 
-       return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page);
+       return chip->ecc.read_page(chip, chip->data_buf, 1, page);
 }
 
-static int sunxi_nfc_hw_ecc_write_oob(struct mtd_info *mtd,
-                                     struct nand_chip *chip,
-                                     int page)
+static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
 
        chip->pagebuf = -1;
 
        memset(chip->data_buf, 0xff, mtd->writesize);
-       ret = chip->ecc.write_page(mtd, chip, chip->data_buf, 1, page);
+       ret = chip->ecc.write_page(chip, chip->data_buf, 1, page);
        if (ret)
                return ret;
 
@@ -1475,10 +1468,9 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
 #define sunxi_nand_lookup_timing(l, p, c) \
                        _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
 
-static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+static int sunxi_nfc_setup_data_interface(struct nand_chip *nand, int csline,
                                        const struct nand_data_interface *conf)
 {
-       struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
        struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
        const struct nand_sdr_timings *timings;
@@ -1920,7 +1912,7 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
 
        nand = &chip->nand;
        /* Default tR value specified in the ONFI spec (chapter 4.15.1) */
-       nand->chip_delay = 200;
+       nand->legacy.chip_delay = 200;
        nand->controller = &nfc->controller;
        nand->controller->ops = &sunxi_nand_controller_ops;
 
@@ -1931,23 +1923,23 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
        nand->ecc.mode = NAND_ECC_HW;
        nand_set_flash_node(nand, np);
        nand->select_chip = sunxi_nfc_select_chip;
-       nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
-       nand->read_buf = sunxi_nfc_read_buf;
-       nand->write_buf = sunxi_nfc_write_buf;
-       nand->read_byte = sunxi_nfc_read_byte;
+       nand->legacy.cmd_ctrl = sunxi_nfc_cmd_ctrl;
+       nand->legacy.read_buf = sunxi_nfc_read_buf;
+       nand->legacy.write_buf = sunxi_nfc_write_buf;
+       nand->legacy.read_byte = sunxi_nfc_read_byte;
        nand->setup_data_interface = sunxi_nfc_setup_data_interface;
 
        mtd = nand_to_mtd(nand);
        mtd->dev.parent = dev;
 
-       ret = nand_scan(mtd, nsels);
+       ret = nand_scan(nand, nsels);
        if (ret)
                return ret;
 
        ret = mtd_device_register(mtd, NULL, 0);
        if (ret) {
                dev_err(dev, "failed to register mtd device: %d\n", ret);
-               nand_release(mtd);
+               nand_release(nand);
                return ret;
        }
 
@@ -1986,7 +1978,7 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
        while (!list_empty(&nfc->chips)) {
                chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
                                        node);
-               nand_release(nand_to_mtd(&chip->nand));
+               nand_release(&chip->nand);
                sunxi_nand_ecc_cleanup(&chip->nand.ecc);
                list_del(&chip->node);
        }
index 72698691727d607d42ad960630788d6f23dfbbf5..8818f893f300f1ca26939beb5aff8c5ba00d34ff 100644 (file)
@@ -116,9 +116,9 @@ struct tango_chip {
 
 #define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
 
-static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void tango_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
 {
-       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+       struct tango_chip *tchip = to_tango_chip(chip);
 
        if (ctrl & NAND_CLE)
                writeb_relaxed(dat, tchip->base + PBUS_CMD);
@@ -127,38 +127,36 @@ static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
                writeb_relaxed(dat, tchip->base + PBUS_ADDR);
 }
 
-static int tango_dev_ready(struct mtd_info *mtd)
+static int tango_dev_ready(struct nand_chip *chip)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct tango_nfc *nfc = to_tango_nfc(chip->controller);
 
        return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
 }
 
-static u8 tango_read_byte(struct mtd_info *mtd)
+static u8 tango_read_byte(struct nand_chip *chip)
 {
-       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+       struct tango_chip *tchip = to_tango_chip(chip);
 
        return readb_relaxed(tchip->base + PBUS_DATA);
 }
 
-static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void tango_read_buf(struct nand_chip *chip, u8 *buf, int len)
 {
-       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+       struct tango_chip *tchip = to_tango_chip(chip);
 
        ioread8_rep(tchip->base + PBUS_DATA, buf, len);
 }
 
-static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void tango_write_buf(struct nand_chip *chip, const u8 *buf, int len)
 {
-       struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+       struct tango_chip *tchip = to_tango_chip(chip);
 
        iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
 }
 
-static void tango_select_chip(struct mtd_info *mtd, int idx)
+static void tango_select_chip(struct nand_chip *chip, int idx)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct tango_nfc *nfc = to_tango_nfc(chip->controller);
        struct tango_chip *tchip = to_tango_chip(chip);
 
@@ -277,14 +275,15 @@ dma_unmap:
        return err;
 }
 
-static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                          u8 *buf, int oob_required, int page)
+static int tango_read_page(struct nand_chip *chip, u8 *buf,
+                          int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct tango_nfc *nfc = to_tango_nfc(chip->controller);
        int err, res, len = mtd->writesize;
 
        if (oob_required)
-               chip->ecc.read_oob(mtd, chip, page);
+               chip->ecc.read_oob(chip, page);
 
        err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
        if (err)
@@ -292,16 +291,17 @@ static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        res = decode_error_report(chip);
        if (res < 0) {
-               chip->ecc.read_oob_raw(mtd, chip, page);
+               chip->ecc.read_oob_raw(chip, page);
                res = check_erased_page(chip, buf);
        }
 
        return res;
 }
 
-static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                           const u8 *buf, int oob_required, int page)
+static int tango_write_page(struct nand_chip *chip, const u8 *buf,
+                           int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct tango_nfc *nfc = to_tango_nfc(chip->controller);
        int err, status, len = mtd->writesize;
 
@@ -314,7 +314,7 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        if (err)
                return err;
 
-       status = chip->waitfunc(mtd, chip);
+       status = chip->legacy.waitfunc(chip);
        if (status & NAND_STATUS_FAIL)
                return -EIO;
 
@@ -323,30 +323,26 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
        *pos += len;
 
        if (!*buf) {
                /* skip over "len" bytes */
                nand_change_read_column_op(chip, *pos, NULL, 0, false);
        } else {
-               tango_read_buf(mtd, *buf, len);
+               tango_read_buf(chip, *buf, len);
                *buf += len;
        }
 }
 
 static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
 {
-       struct mtd_info *mtd = nand_to_mtd(chip);
-
        *pos += len;
 
        if (!*buf) {
                /* skip over "len" bytes */
                nand_change_write_column_op(chip, *pos, NULL, 0, false);
        } else {
-               tango_write_buf(mtd, *buf, len);
+               tango_write_buf(chip, *buf, len);
                *buf += len;
        }
 }
@@ -424,32 +420,30 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
        aux_write(chip, &oob, ecc_size, &pos);
 }
 
-static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                              u8 *buf, int oob_required, int page)
+static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
+                              int oob_required, int page)
 {
        nand_read_page_op(chip, page, 0, NULL, 0);
        raw_read(chip, buf, chip->oob_poi);
        return 0;
 }
 
-static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                               const u8 *buf, int oob_required, int page)
+static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
+                               int oob_required, int page)
 {
        nand_prog_page_begin_op(chip, page, 0, NULL, 0);
        raw_write(chip, buf, chip->oob_poi);
        return nand_prog_page_end_op(chip);
 }
 
-static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                         int page)
+static int tango_read_oob(struct nand_chip *chip, int page)
 {
        nand_read_page_op(chip, page, 0, NULL, 0);
        raw_read(chip, NULL, chip->oob_poi);
        return 0;
 }
 
-static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                          int page)
+static int tango_write_oob(struct nand_chip *chip, int page)
 {
        nand_prog_page_begin_op(chip, page, 0, NULL, 0);
        raw_write(chip, NULL, chip->oob_poi);
@@ -485,11 +479,10 @@ static u32 to_ticks(int kHz, int ps)
        return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
 }
 
-static int tango_set_timings(struct mtd_info *mtd, int csline,
+static int tango_set_timings(struct nand_chip *chip, int csline,
                             const struct nand_data_interface *conf)
 {
        const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct tango_nfc *nfc = to_tango_nfc(chip->controller);
        struct tango_chip *tchip = to_tango_chip(chip);
        u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
@@ -571,12 +564,12 @@ static int chip_init(struct device *dev, struct device_node *np)
        ecc = &chip->ecc;
        mtd = nand_to_mtd(chip);
 
-       chip->read_byte = tango_read_byte;
-       chip->write_buf = tango_write_buf;
-       chip->read_buf = tango_read_buf;
+       chip->legacy.read_byte = tango_read_byte;
+       chip->legacy.write_buf = tango_write_buf;
+       chip->legacy.read_buf = tango_read_buf;
        chip->select_chip = tango_select_chip;
-       chip->cmd_ctrl = tango_cmd_ctrl;
-       chip->dev_ready = tango_dev_ready;
+       chip->legacy.cmd_ctrl = tango_cmd_ctrl;
+       chip->legacy.dev_ready = tango_dev_ready;
        chip->setup_data_interface = tango_set_timings;
        chip->options = NAND_USE_BOUNCE_BUFFER |
                        NAND_NO_SUBPAGE_WRITE |
@@ -588,7 +581,7 @@ static int chip_init(struct device *dev, struct device_node *np)
        mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
        mtd->dev.parent = dev;
 
-       err = nand_scan(mtd, 1);
+       err = nand_scan(chip, 1);
        if (err)
                return err;
 
@@ -617,7 +610,7 @@ static int tango_nand_remove(struct platform_device *pdev)
 
        for (cs = 0; cs < MAX_CS; ++cs) {
                if (nfc->chips[cs])
-                       nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
+                       nand_release(&nfc->chips[cs]->nand_chip);
        }
 
        return 0;
index 79da1efc88d1a98a5f33443a46e4a4348a478b2e..9767e29d74e2924b46e18fc5625ccfbce075f920 100644 (file)
@@ -462,9 +462,8 @@ static int tegra_nand_exec_op(struct nand_chip *chip,
                                      check_only);
 }
 
-static void tegra_nand_select_chip(struct mtd_info *mtd, int die_nr)
+static void tegra_nand_select_chip(struct nand_chip *chip, int die_nr)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct tegra_nand_chip *nand = to_tegra_chip(chip);
        struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
 
@@ -615,44 +614,46 @@ err_unmap_dma_page:
        return ret;
 }
 
-static int tegra_nand_read_page_raw(struct mtd_info *mtd,
-                                   struct nand_chip *chip, u8 *buf,
+static int tegra_nand_read_page_raw(struct nand_chip *chip, u8 *buf,
                                    int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        void *oob_buf = oob_required ? chip->oob_poi : NULL;
 
        return tegra_nand_page_xfer(mtd, chip, buf, oob_buf,
                                    mtd->oobsize, page, true);
 }
 
-static int tegra_nand_write_page_raw(struct mtd_info *mtd,
-                                    struct nand_chip *chip, const u8 *buf,
+static int tegra_nand_write_page_raw(struct nand_chip *chip, const u8 *buf,
                                     int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        void *oob_buf = oob_required ? chip->oob_poi : NULL;
 
        return tegra_nand_page_xfer(mtd, chip, (void *)buf, oob_buf,
                                     mtd->oobsize, page, false);
 }
 
-static int tegra_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                              int page)
+static int tegra_nand_read_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi,
                                    mtd->oobsize, page, true);
 }
 
-static int tegra_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                               int page)
+static int tegra_nand_write_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi,
                                    mtd->oobsize, page, false);
 }
 
-static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
-                                     struct nand_chip *chip, u8 *buf,
+static int tegra_nand_read_page_hwecc(struct nand_chip *chip, u8 *buf,
                                      int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
        struct tegra_nand_chip *nand = to_tegra_chip(chip);
        void *oob_buf = oob_required ? chip->oob_poi : NULL;
@@ -716,7 +717,7 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
                 * erased or if error correction just failed for all sub-
                 * pages.
                 */
-               ret = tegra_nand_read_oob(mtd, chip, page);
+               ret = tegra_nand_read_oob(chip, page);
                if (ret < 0)
                        return ret;
 
@@ -759,10 +760,10 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
        }
 }
 
-static int tegra_nand_write_page_hwecc(struct mtd_info *mtd,
-                                      struct nand_chip *chip, const u8 *buf,
+static int tegra_nand_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
                                       int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
        void *oob_buf = oob_required ? chip->oob_poi : NULL;
        int ret;
@@ -813,10 +814,9 @@ static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl,
        writel_relaxed(reg, ctrl->regs + TIMING_2);
 }
 
-static int tegra_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+static int tegra_nand_setup_data_interface(struct nand_chip *chip, int csline,
                                        const struct nand_data_interface *conf)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
        const struct nand_sdr_timings *timings;
 
@@ -1119,7 +1119,7 @@ static int tegra_nand_chips_init(struct device *dev,
        chip->select_chip = tegra_nand_select_chip;
        chip->setup_data_interface = tegra_nand_setup_data_interface;
 
-       ret = nand_scan(mtd, 1);
+       ret = nand_scan(chip, 1);
        if (ret)
                return ret;
 
index dcaa924502de33a250a98ecf1ce38a79842daf89..f3b59e649b7d040eaa8466d7503ae3281261fa6d 100644 (file)
@@ -126,11 +126,10 @@ static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
 
 /*--------------------------------------------------------------------------*/
 
-static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
-                                  unsigned int ctrl)
+static void tmio_nand_hwcontrol(struct nand_chip *chip, int cmd,
+                               unsigned int ctrl)
 {
-       struct tmio_nand *tmio = mtd_to_tmio(mtd);
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
 
        if (ctrl & NAND_CTRL_CHANGE) {
                u8 mode;
@@ -156,12 +155,12 @@ static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
        }
 
        if (cmd != NAND_CMD_NONE)
-               tmio_iowrite8(cmd, chip->IO_ADDR_W);
+               tmio_iowrite8(cmd, chip->legacy.IO_ADDR_W);
 }
 
-static int tmio_nand_dev_ready(struct mtd_info *mtd)
+static int tmio_nand_dev_ready(struct nand_chip *chip)
 {
-       struct tmio_nand *tmio = mtd_to_tmio(mtd);
+       struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
 
        return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY);
 }
@@ -187,10 +186,9 @@ static irqreturn_t tmio_irq(int irq, void *__tmio)
   *erase and write, we enable it to wake us up.  The irq handler
   *disables the interrupt.
  */
-static int
-tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
+static int tmio_nand_wait(struct nand_chip *nand_chip)
 {
-       struct tmio_nand *tmio = mtd_to_tmio(mtd);
+       struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(nand_chip));
        long timeout;
        u8 status;
 
@@ -199,10 +197,10 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
        tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
 
        timeout = wait_event_timeout(nand_chip->controller->wq,
-               tmio_nand_dev_ready(mtd),
+               tmio_nand_dev_ready(nand_chip),
                msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
 
-       if (unlikely(!tmio_nand_dev_ready(mtd))) {
+       if (unlikely(!tmio_nand_dev_ready(nand_chip))) {
                tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
                dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
                        nand_chip->state == FL_ERASING ? "erase" : "program",
@@ -225,9 +223,9 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
   *To prevent stale data from being read, tmio_nand_hwcontrol() clears
   *tmio->read_good.
  */
-static u_char tmio_nand_read_byte(struct mtd_info *mtd)
+static u_char tmio_nand_read_byte(struct nand_chip *chip)
 {
-       struct tmio_nand *tmio = mtd_to_tmio(mtd);
+       struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
        unsigned int data;
 
        if (tmio->read_good--)
@@ -245,33 +243,33 @@ static u_char tmio_nand_read_byte(struct mtd_info *mtd)
   *buffer functions.
  */
 static void
-tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+tmio_nand_write_buf(struct nand_chip *chip, const u_char *buf, int len)
 {
-       struct tmio_nand *tmio = mtd_to_tmio(mtd);
+       struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
 
        tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
 }
 
-static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void tmio_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
 {
-       struct tmio_nand *tmio = mtd_to_tmio(mtd);
+       struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
 
        tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
 }
 
-static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void tmio_nand_enable_hwecc(struct nand_chip *chip, int mode)
 {
-       struct tmio_nand *tmio = mtd_to_tmio(mtd);
+       struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
 
        tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE);
        tmio_ioread8(tmio->fcr + FCR_DATA);     /* dummy read */
        tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE);
 }
 
-static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-                                                       u_char *ecc_code)
+static int tmio_nand_calculate_ecc(struct nand_chip *chip, const u_char *dat,
+                                  u_char *ecc_code)
 {
-       struct tmio_nand *tmio = mtd_to_tmio(mtd);
+       struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
        unsigned int ecc;
 
        tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE);
@@ -290,16 +288,18 @@ static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
        return 0;
 }
 
-static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
-               unsigned char *read_ecc, unsigned char *calc_ecc)
+static int tmio_nand_correct_data(struct nand_chip *chip, unsigned char *buf,
+                                 unsigned char *read_ecc,
+                                 unsigned char *calc_ecc)
 {
        int r0, r1;
 
        /* assume ecc.size = 512 and ecc.bytes = 6 */
-       r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+       r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256, false);
        if (r0 < 0)
                return r0;
-       r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256);
+       r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256,
+                                false);
        if (r1 < 0)
                return r1;
        return r0 + r1;
@@ -400,15 +400,15 @@ static int tmio_probe(struct platform_device *dev)
                return retval;
 
        /* Set address of NAND IO lines */
-       nand_chip->IO_ADDR_R = tmio->fcr;
-       nand_chip->IO_ADDR_W = tmio->fcr;
+       nand_chip->legacy.IO_ADDR_R = tmio->fcr;
+       nand_chip->legacy.IO_ADDR_W = tmio->fcr;
 
        /* Set address of hardware control function */
-       nand_chip->cmd_ctrl = tmio_nand_hwcontrol;
-       nand_chip->dev_ready = tmio_nand_dev_ready;
-       nand_chip->read_byte = tmio_nand_read_byte;
-       nand_chip->write_buf = tmio_nand_write_buf;
-       nand_chip->read_buf = tmio_nand_read_buf;
+       nand_chip->legacy.cmd_ctrl = tmio_nand_hwcontrol;
+       nand_chip->legacy.dev_ready = tmio_nand_dev_ready;
+       nand_chip->legacy.read_byte = tmio_nand_read_byte;
+       nand_chip->legacy.write_buf = tmio_nand_write_buf;
+       nand_chip->legacy.read_buf = tmio_nand_read_buf;
 
        /* set eccmode using hardware ECC */
        nand_chip->ecc.mode = NAND_ECC_HW;
@@ -423,7 +423,7 @@ static int tmio_probe(struct platform_device *dev)
                nand_chip->badblock_pattern = data->badblock_pattern;
 
        /* 15 us command delay time */
-       nand_chip->chip_delay = 15;
+       nand_chip->legacy.chip_delay = 15;
 
        retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
                                  dev_name(&dev->dev), tmio);
@@ -433,10 +433,10 @@ static int tmio_probe(struct platform_device *dev)
        }
 
        tmio->irq = irq;
-       nand_chip->waitfunc = tmio_nand_wait;
+       nand_chip->legacy.waitfunc = tmio_nand_wait;
 
        /* Scan to find existence of the device */
-       retval = nand_scan(mtd, 1);
+       retval = nand_scan(nand_chip, 1);
        if (retval)
                goto err_irq;
 
@@ -449,7 +449,7 @@ static int tmio_probe(struct platform_device *dev)
        if (!retval)
                return retval;
 
-       nand_release(mtd);
+       nand_release(nand_chip);
 
 err_irq:
        tmio_hw_stop(dev, tmio);
@@ -460,7 +460,7 @@ static int tmio_remove(struct platform_device *dev)
 {
        struct tmio_nand *tmio = platform_get_drvdata(dev);
 
-       nand_release(nand_to_mtd(&tmio->chip));
+       nand_release(&tmio->chip);
        tmio_hw_stop(dev, tmio);
        return 0;
 }
index 4d61a14fcb65cb011fa64b020aaa0e1a6cd7df18..ddf0420c09976a39a10dddbbad9cc48edb94610b 100644 (file)
@@ -102,17 +102,17 @@ static void txx9ndfmc_write(struct platform_device *dev,
        __raw_writel(val, ndregaddr(dev, reg));
 }
 
-static uint8_t txx9ndfmc_read_byte(struct mtd_info *mtd)
+static uint8_t txx9ndfmc_read_byte(struct nand_chip *chip)
 {
-       struct platform_device *dev = mtd_to_platdev(mtd);
+       struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
 
        return txx9ndfmc_read(dev, TXX9_NDFDTR);
 }
 
-static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void txx9ndfmc_write_buf(struct nand_chip *chip, const uint8_t *buf,
                                int len)
 {
-       struct platform_device *dev = mtd_to_platdev(mtd);
+       struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
        void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
        u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
 
@@ -122,19 +122,18 @@ static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
        txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
 }
 
-static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void txx9ndfmc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
 {
-       struct platform_device *dev = mtd_to_platdev(mtd);
+       struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
        void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
 
        while (len--)
                *buf++ = __raw_readl(ndfdtr);
 }
 
-static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void txx9ndfmc_cmd_ctrl(struct nand_chip *chip, int cmd,
                               unsigned int ctrl)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
        struct platform_device *dev = txx9_priv->dev;
        struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
@@ -163,18 +162,17 @@ static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
        mmiowb();
 }
 
-static int txx9ndfmc_dev_ready(struct mtd_info *mtd)
+static int txx9ndfmc_dev_ready(struct nand_chip *chip)
 {
-       struct platform_device *dev = mtd_to_platdev(mtd);
+       struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
 
        return !(txx9ndfmc_read(dev, TXX9_NDFSR) & TXX9_NDFSR_BUSY);
 }
 
-static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
+static int txx9ndfmc_calculate_ecc(struct nand_chip *chip, const uint8_t *dat,
                                   uint8_t *ecc_code)
 {
-       struct platform_device *dev = mtd_to_platdev(mtd);
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
        int eccbytes;
        u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
 
@@ -191,16 +189,17 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
        return 0;
 }
 
-static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
-               unsigned char *read_ecc, unsigned char *calc_ecc)
+static int txx9ndfmc_correct_data(struct nand_chip *chip, unsigned char *buf,
+                                 unsigned char *read_ecc,
+                                 unsigned char *calc_ecc)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        int eccsize;
        int corrected = 0;
        int stat;
 
        for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) {
-               stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+               stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256,
+                                          false);
                if (stat < 0)
                        return stat;
                corrected += stat;
@@ -211,9 +210,9 @@ static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
        return corrected;
 }
 
-static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
+static void txx9ndfmc_enable_hwecc(struct nand_chip *chip, int mode)
 {
-       struct platform_device *dev = mtd_to_platdev(mtd);
+       struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
        u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
 
        mcr &= ~TXX9_NDFMCR_ECC_ALL;
@@ -326,17 +325,17 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
                mtd = nand_to_mtd(chip);
                mtd->dev.parent = &dev->dev;
 
-               chip->read_byte = txx9ndfmc_read_byte;
-               chip->read_buf = txx9ndfmc_read_buf;
-               chip->write_buf = txx9ndfmc_write_buf;
-               chip->cmd_ctrl = txx9ndfmc_cmd_ctrl;
-               chip->dev_ready = txx9ndfmc_dev_ready;
+               chip->legacy.read_byte = txx9ndfmc_read_byte;
+               chip->legacy.read_buf = txx9ndfmc_read_buf;
+               chip->legacy.write_buf = txx9ndfmc_write_buf;
+               chip->legacy.cmd_ctrl = txx9ndfmc_cmd_ctrl;
+               chip->legacy.dev_ready = txx9ndfmc_dev_ready;
                chip->ecc.calculate = txx9ndfmc_calculate_ecc;
                chip->ecc.correct = txx9ndfmc_correct_data;
                chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
                chip->ecc.mode = NAND_ECC_HW;
                chip->ecc.strength = 1;
-               chip->chip_delay = 100;
+               chip->legacy.chip_delay = 100;
                chip->controller = &drvdata->controller;
 
                nand_set_controller_data(chip, txx9_priv);
@@ -359,7 +358,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
                if (plat->wide_mask & (1 << i))
                        chip->options |= NAND_BUSWIDTH_16;
 
-               if (nand_scan(mtd, 1)) {
+               if (nand_scan(chip, 1)) {
                        kfree(txx9_priv->mtdname);
                        kfree(txx9_priv);
                        continue;
@@ -390,7 +389,7 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
                chip = mtd_to_nand(mtd);
                txx9_priv = nand_get_controller_data(chip);
 
-               nand_release(mtd);
+               nand_release(chip);
                kfree(txx9_priv->mtdname);
                kfree(txx9_priv);
        }
index 6f6dcbf9095b9b890943a7097bdbb86447cc5806..9814fd4a84cfd59bac00e04c50e3b48b4d0e75b2 100644 (file)
@@ -498,9 +498,9 @@ static int vf610_nfc_exec_op(struct nand_chip *chip,
 /*
  * This function supports Vybrid only (MPC5125 would have full RB and four CS)
  */
-static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void vf610_nfc_select_chip(struct nand_chip *chip, int cs)
 {
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip));
        u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
 
        /* Vybrid only (MPC5125 would have full RB and four CS) */
@@ -509,9 +509,9 @@ static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
 
        tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
 
-       if (chip >= 0) {
+       if (cs >= 0) {
                tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
-               tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
+               tmp |= BIT(cs) << ROW_ADDR_CHIP_SEL_SHIFT;
        }
 
        vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
@@ -557,9 +557,10 @@ static void vf610_nfc_fill_row(struct nand_chip *chip, int page, u32 *code,
        }
 }
 
-static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf, int oob_required, int page)
+static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf,
+                              int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        int trfr_sz = mtd->writesize + mtd->oobsize;
        u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
@@ -602,9 +603,10 @@ static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        }
 }
 
-static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf, int oob_required, int page)
+static int vf610_nfc_write_page(struct nand_chip *chip, const uint8_t *buf,
+                               int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        int trfr_sz = mtd->writesize + mtd->oobsize;
        u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
@@ -643,24 +645,24 @@ static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        return 0;
 }
 
-static int vf610_nfc_read_page_raw(struct mtd_info *mtd,
-                                  struct nand_chip *chip, u8 *buf,
+static int vf610_nfc_read_page_raw(struct nand_chip *chip, u8 *buf,
                                   int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        int ret;
 
        nfc->data_access = true;
-       ret = nand_read_page_raw(mtd, chip, buf, oob_required, page);
+       ret = nand_read_page_raw(chip, buf, oob_required, page);
        nfc->data_access = false;
 
        return ret;
 }
 
-static int vf610_nfc_write_page_raw(struct mtd_info *mtd,
-                                   struct nand_chip *chip, const u8 *buf,
+static int vf610_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
                                    int oob_required, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        int ret;
 
@@ -677,22 +679,21 @@ static int vf610_nfc_write_page_raw(struct mtd_info *mtd,
        return nand_prog_page_end_op(chip);
 }
 
-static int vf610_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                             int page)
+static int vf610_nfc_read_oob(struct nand_chip *chip, int page)
 {
-       struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+       struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip));
        int ret;
 
        nfc->data_access = true;
-       ret = nand_read_oob_std(mtd, chip, page);
+       ret = nand_read_oob_std(chip, page);
        nfc->data_access = false;
 
        return ret;
 }
 
-static int vf610_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                              int page)
+static int vf610_nfc_write_oob(struct nand_chip *chip, int page)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct vf610_nfc *nfc = mtd_to_nfc(mtd);
        int ret;
 
@@ -892,7 +893,7 @@ static int vf610_nfc_probe(struct platform_device *pdev)
 
        /* Scan the NAND chip */
        chip->dummy_controller.ops = &vf610_nfc_controller_ops;
-       err = nand_scan(mtd, 1);
+       err = nand_scan(chip, 1);
        if (err)
                goto err_disable_clk;
 
@@ -916,7 +917,7 @@ static int vf610_nfc_remove(struct platform_device *pdev)
        struct mtd_info *mtd = platform_get_drvdata(pdev);
        struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 
-       nand_release(mtd);
+       nand_release(mtd_to_nand(mtd));
        clk_disable_unprepare(nfc->clk);
        return 0;
 }
index 9926b4e3d69d014d70bb9f48941e9bc3037cce77..a234a5cb486885bb21c606ff84713b751f1bfc89 100644 (file)
@@ -85,9 +85,8 @@ static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
        writeb(value, data->nandaddr + op);
 }
 
-static void xway_select_chip(struct mtd_info *mtd, int select)
+static void xway_select_chip(struct nand_chip *chip, int select)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
        struct xway_nand_data *data = nand_get_controller_data(chip);
 
        switch (select) {
@@ -106,8 +105,10 @@ static void xway_select_chip(struct mtd_info *mtd, int select)
        }
 }
 
-static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void xway_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
+
        if (cmd == NAND_CMD_NONE)
                return;
 
@@ -120,30 +121,30 @@ static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
                ;
 }
 
-static int xway_dev_ready(struct mtd_info *mtd)
+static int xway_dev_ready(struct nand_chip *chip)
 {
        return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD;
 }
 
-static unsigned char xway_read_byte(struct mtd_info *mtd)
+static unsigned char xway_read_byte(struct nand_chip *chip)
 {
-       return xway_readb(mtd, NAND_READ_DATA);
+       return xway_readb(nand_to_mtd(chip), NAND_READ_DATA);
 }
 
-static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void xway_read_buf(struct nand_chip *chip, u_char *buf, int len)
 {
        int i;
 
        for (i = 0; i < len; i++)
-               buf[i] = xway_readb(mtd, NAND_WRITE_DATA);
+               buf[i] = xway_readb(nand_to_mtd(chip), NAND_WRITE_DATA);
 }
 
-static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void xway_write_buf(struct nand_chip *chip, const u_char *buf, int len)
 {
        int i;
 
        for (i = 0; i < len; i++)
-               xway_writeb(mtd, NAND_WRITE_DATA, buf[i]);
+               xway_writeb(nand_to_mtd(chip), NAND_WRITE_DATA, buf[i]);
 }
 
 /*
@@ -173,13 +174,13 @@ static int xway_nand_probe(struct platform_device *pdev)
        mtd = nand_to_mtd(&data->chip);
        mtd->dev.parent = &pdev->dev;
 
-       data->chip.cmd_ctrl = xway_cmd_ctrl;
-       data->chip.dev_ready = xway_dev_ready;
+       data->chip.legacy.cmd_ctrl = xway_cmd_ctrl;
+       data->chip.legacy.dev_ready = xway_dev_ready;
        data->chip.select_chip = xway_select_chip;
-       data->chip.write_buf = xway_write_buf;
-       data->chip.read_buf = xway_read_buf;
-       data->chip.read_byte = xway_read_byte;
-       data->chip.chip_delay = 30;
+       data->chip.legacy.write_buf = xway_write_buf;
+       data->chip.legacy.read_buf = xway_read_buf;
+       data->chip.legacy.read_byte = xway_read_byte;
+       data->chip.legacy.chip_delay = 30;
 
        data->chip.ecc.mode = NAND_ECC_SOFT;
        data->chip.ecc.algo = NAND_ECC_HAMMING;
@@ -205,13 +206,13 @@ static int xway_nand_probe(struct platform_device *pdev)
                    | cs_flag, EBU_NAND_CON);
 
        /* Scan to find existence of the device */
-       err = nand_scan(mtd, 1);
+       err = nand_scan(&data->chip, 1);
        if (err)
                return err;
 
        err = mtd_device_register(mtd, NULL, 0);
        if (err)
-               nand_release(mtd);
+               nand_release(&data->chip);
 
        return err;
 }
@@ -223,7 +224,7 @@ static int xway_nand_remove(struct platform_device *pdev)
 {
        struct xway_nand_data *data = platform_get_drvdata(pdev);
 
-       nand_release(nand_to_mtd(&data->chip));
+       nand_release(&data->chip);
 
        return 0;
 }
index f3bd86e136033d80e791fc996f0d9516d5e54d48..89227b1d036afd1ab8d51a26ab070f90c56687be 100644 (file)
@@ -221,14 +221,18 @@ static int sm_correct_sector(uint8_t *buffer, struct sm_oob *oob)
 {
        uint8_t ecc[3];
 
-       __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc);
-       if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE) < 0)
+       __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+       if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE,
+                               IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0)
                return -EIO;
 
        buffer += SM_SMALL_PAGE;
 
-       __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc);
-       if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE) < 0)
+       __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+       if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE,
+                               IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0)
                return -EIO;
        return 0;
 }
@@ -393,11 +397,13 @@ restart:
                }
 
                if (ftl->smallpagenand) {
-                       __nand_calculate_ecc(buf + boffset,
-                                               SM_SMALL_PAGE, oob.ecc1);
+                       __nand_calculate_ecc(buf + boffset, SM_SMALL_PAGE,
+                                       oob.ecc1,
+                                       IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
 
                        __nand_calculate_ecc(buf + boffset + SM_SMALL_PAGE,
-                                               SM_SMALL_PAGE, oob.ecc2);
+                                       SM_SMALL_PAGE, oob.ecc2,
+                                       IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
                }
                if (!sm_write_sector(ftl, zone, block, boffset,
                                                        buf + boffset, &oob))
index 8e714fbfa52123d8ae8ff4c9750d134cc648792d..e24db817154ee73ad1fc0fd9586f4e294fc2886a 100644 (file)
@@ -959,7 +959,7 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf,
                return 0;
        }
 
-       dma_dst = dma_map_single(nor->dev, buf, len, DMA_DEV_TO_MEM);
+       dma_dst = dma_map_single(nor->dev, buf, len, DMA_FROM_DEVICE);
        if (dma_mapping_error(nor->dev, dma_dst)) {
                dev_err(nor->dev, "dma mapping failed\n");
                return -ENOMEM;
@@ -994,7 +994,7 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf,
        }
 
 err_unmap:
-       dma_unmap_single(nor->dev, dma_dst, len, DMA_DEV_TO_MEM);
+       dma_unmap_single(nor->dev, dma_dst, len, DMA_FROM_DEVICE);
 
        return 0;
 }
index 7d9620c7ff6c58aa2ea74b3eb57dd63799a7b934..1ff3430f82c883bcb6bcb80ed28ecb95374a19f6 100644 (file)
@@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
 {
        switch (cmd) {
        case SPINOR_OP_READ_1_1_4:
+       case SPINOR_OP_READ_1_1_4_4B:
                return SEQID_READ;
        case SPINOR_OP_WREN:
                return SEQID_WREN;
@@ -543,6 +544,9 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
 
        /* trigger the LUT now */
        seqid = fsl_qspi_get_seqid(q, cmd);
+       if (seqid < 0)
+               return seqid;
+
        qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len,
                        base + QUADSPI_IPCR);
 
@@ -671,7 +675,7 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
  * causes the controller to clear the buffer, and use the sequence pointed
  * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
  */
-static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
+static int fsl_qspi_init_ahb_read(struct fsl_qspi *q)
 {
        void __iomem *base = q->iobase;
        int seqid;
@@ -696,8 +700,13 @@ static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
 
        /* Set the default lut sequence for AHB Read. */
        seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
+       if (seqid < 0)
+               return seqid;
+
        qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
                q->iobase + QUADSPI_BFGENCR);
+
+       return 0;
 }
 
 /* This function was used to prepare and enable QSPI clock */
@@ -805,9 +814,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
        fsl_qspi_init_lut(q);
 
        /* Init for AHB read */
-       fsl_qspi_init_ahb_read(q);
-
-       return 0;
+       return fsl_qspi_init_ahb_read(q);
 }
 
 static const struct of_device_id fsl_qspi_dt_ids[] = {
index c0976f2e3dd19925b06f155bd093176818465720..872b409226081a5933f527371c36541eafa04970 100644 (file)
@@ -65,6 +65,7 @@ static void intel_spi_pci_remove(struct pci_dev *pdev)
 static const struct pci_device_id intel_spi_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
+       { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
        { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
        { },
index f028277fb1cedb86ac4837e78341705c82f60b1b..9407ca5f9443338d56a355fe0eadfa6641a429dc 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/math64.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
+#include <linux/sort.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/of_platform.h>
@@ -260,6 +261,18 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
        nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
        nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
        nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
+
+       if (!spi_nor_has_uniform_erase(nor)) {
+               struct spi_nor_erase_map *map = &nor->erase_map;
+               struct spi_nor_erase_type *erase;
+               int i;
+
+               for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+                       erase = &map->erase_type[i];
+                       erase->opcode =
+                               spi_nor_convert_3to4_erase(erase->opcode);
+               }
+       }
 }
 
 /* Enable/disable 4-byte addressing mode. */
@@ -497,6 +510,277 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
        return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
 }
 
+/**
+ * spi_nor_div_by_erase_size() - calculate remainder and update new dividend
+ * @erase:     pointer to a structure that describes a SPI NOR erase type
+ * @dividend:  dividend value
+ * @remainder: pointer to u32 remainder (will be updated)
+ *
+ * Return: the result of the division
+ */
+static u64 spi_nor_div_by_erase_size(const struct spi_nor_erase_type *erase,
+                                    u64 dividend, u32 *remainder)
+{
+       /* JEDEC JESD216B Standard imposes erase sizes to be power of 2. */
+       *remainder = (u32)dividend & erase->size_mask;
+       return dividend >> erase->size_shift;
+}
+
+/**
+ * spi_nor_find_best_erase_type() - find the best erase type for the given
+ *                                 offset in the serial flash memory and the
+ *                                 number of bytes to erase. The region in
+ *                                 which the address fits is expected to be
+ *                                 provided.
+ * @map:       the erase map of the SPI NOR
+ * @region:    pointer to a structure that describes a SPI NOR erase region
+ * @addr:      offset in the serial flash memory
+ * @len:       number of bytes to erase
+ *
+ * Return: a pointer to the best fitted erase type, NULL otherwise.
+ */
+static const struct spi_nor_erase_type *
+spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
+                            const struct spi_nor_erase_region *region,
+                            u64 addr, u32 len)
+{
+       const struct spi_nor_erase_type *erase;
+       u32 rem;
+       int i;
+       u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
+
+       /*
+        * Erase types are ordered by size, with the biggest erase type at
+        * index 0.
+        */
+       for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
+               /* Does the erase region support the tested erase type? */
+               if (!(erase_mask & BIT(i)))
+                       continue;
+
+               erase = &map->erase_type[i];
+
+               /* Don't erase more than what the user has asked for. */
+               if (erase->size > len)
+                       continue;
+
+               /* Alignment is not mandatory for overlaid regions */
+               if (region->offset & SNOR_OVERLAID_REGION)
+                       return erase;
+
+               spi_nor_div_by_erase_size(erase, addr, &rem);
+               if (rem)
+                       continue;
+               else
+                       return erase;
+       }
+
+       return NULL;
+}
+
+/**
+ * spi_nor_region_next() - get the next spi nor region
+ * @region:    pointer to a structure that describes a SPI NOR erase region
+ *
+ * Return: the next spi nor region or NULL if last region.
+ */
+static struct spi_nor_erase_region *
+spi_nor_region_next(struct spi_nor_erase_region *region)
+{
+       if (spi_nor_region_is_last(region))
+               return NULL;
+       region++;
+       return region;
+}
+
+/**
+ * spi_nor_find_erase_region() - find the region of the serial flash memory in
+ *                              which the offset fits
+ * @map:       the erase map of the SPI NOR
+ * @addr:      offset in the serial flash memory
+ *
+ * Return: a pointer to the spi_nor_erase_region struct, ERR_PTR(-errno)
+ *        otherwise.
+ */
+static struct spi_nor_erase_region *
+spi_nor_find_erase_region(const struct spi_nor_erase_map *map, u64 addr)
+{
+       struct spi_nor_erase_region *region = map->regions;
+       u64 region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
+       u64 region_end = region_start + region->size;
+
+       while (addr < region_start || addr >= region_end) {
+               region = spi_nor_region_next(region);
+               if (!region)
+                       return ERR_PTR(-EINVAL);
+
+               region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
+               region_end = region_start + region->size;
+       }
+
+       return region;
+}
+
+/**
+ * spi_nor_init_erase_cmd() - initialize an erase command
+ * @region:    pointer to a structure that describes a SPI NOR erase region
+ * @erase:     pointer to a structure that describes a SPI NOR erase type
+ *
+ * Return: the pointer to the allocated erase command, ERR_PTR(-errno)
+ *        otherwise.
+ */
+static struct spi_nor_erase_command *
+spi_nor_init_erase_cmd(const struct spi_nor_erase_region *region,
+                      const struct spi_nor_erase_type *erase)
+{
+       struct spi_nor_erase_command *cmd;
+
+       cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&cmd->list);
+       cmd->opcode = erase->opcode;
+       cmd->count = 1;
+
+       if (region->offset & SNOR_OVERLAID_REGION)
+               cmd->size = region->size;
+       else
+               cmd->size = erase->size;
+
+       return cmd;
+}
+
+/**
+ * spi_nor_destroy_erase_cmd_list() - destroy erase command list
+ * @erase_list:        list of erase commands
+ */
+static void spi_nor_destroy_erase_cmd_list(struct list_head *erase_list)
+{
+       struct spi_nor_erase_command *cmd, *next;
+
+       list_for_each_entry_safe(cmd, next, erase_list, list) {
+               list_del(&cmd->list);
+               kfree(cmd);
+       }
+}
+
+/**
+ * spi_nor_init_erase_cmd_list() - initialize erase command list
+ * @nor:       pointer to a 'struct spi_nor'
+ * @erase_list:        list of erase commands to be executed once we validate that the
+ *             erase can be performed
+ * @addr:      offset in the serial flash memory
+ * @len:       number of bytes to erase
+ *
+ * Builds the list of best fitted erase commands and verifies if the erase can
+ * be performed.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
+                                      struct list_head *erase_list,
+                                      u64 addr, u32 len)
+{
+       const struct spi_nor_erase_map *map = &nor->erase_map;
+       const struct spi_nor_erase_type *erase, *prev_erase = NULL;
+       struct spi_nor_erase_region *region;
+       struct spi_nor_erase_command *cmd = NULL;
+       u64 region_end;
+       int ret = -EINVAL;
+
+       region = spi_nor_find_erase_region(map, addr);
+       if (IS_ERR(region))
+               return PTR_ERR(region);
+
+       region_end = spi_nor_region_end(region);
+
+       while (len) {
+               erase = spi_nor_find_best_erase_type(map, region, addr, len);
+               if (!erase)
+                       goto destroy_erase_cmd_list;
+
+               if (prev_erase != erase ||
+                   region->offset & SNOR_OVERLAID_REGION) {
+                       cmd = spi_nor_init_erase_cmd(region, erase);
+                       if (IS_ERR(cmd)) {
+                               ret = PTR_ERR(cmd);
+                               goto destroy_erase_cmd_list;
+                       }
+
+                       list_add_tail(&cmd->list, erase_list);
+               } else {
+                       cmd->count++;
+               }
+
+               addr += cmd->size;
+               len -= cmd->size;
+
+               if (len && addr >= region_end) {
+                       region = spi_nor_region_next(region);
+                       if (!region)
+                               goto destroy_erase_cmd_list;
+                       region_end = spi_nor_region_end(region);
+               }
+
+               prev_erase = erase;
+       }
+
+       return 0;
+
+destroy_erase_cmd_list:
+       spi_nor_destroy_erase_cmd_list(erase_list);
+       return ret;
+}
+
+/**
+ * spi_nor_erase_multi_sectors() - perform a non-uniform erase
+ * @nor:       pointer to a 'struct spi_nor'
+ * @addr:      offset in the serial flash memory
+ * @len:       number of bytes to erase
+ *
+ * Build a list of best fitted erase commands and execute it once we validate
+ * that the erase can be performed.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len)
+{
+       LIST_HEAD(erase_list);
+       struct spi_nor_erase_command *cmd, *next;
+       int ret;
+
+       ret = spi_nor_init_erase_cmd_list(nor, &erase_list, addr, len);
+       if (ret)
+               return ret;
+
+       list_for_each_entry_safe(cmd, next, &erase_list, list) {
+               nor->erase_opcode = cmd->opcode;
+               while (cmd->count) {
+                       write_enable(nor);
+
+                       ret = spi_nor_erase_sector(nor, addr);
+                       if (ret)
+                               goto destroy_erase_cmd_list;
+
+                       addr += cmd->size;
+                       cmd->count--;
+
+                       ret = spi_nor_wait_till_ready(nor);
+                       if (ret)
+                               goto destroy_erase_cmd_list;
+               }
+               list_del(&cmd->list);
+               kfree(cmd);
+       }
+
+       return 0;
+
+destroy_erase_cmd_list:
+       spi_nor_destroy_erase_cmd_list(&erase_list);
+       return ret;
+}
+
 /*
  * Erase an address range on the nor chip.  The address range may extend
  * one or more erase sectors.  Return an error is there is a problem erasing.
@@ -511,9 +795,11 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
        dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
                        (long long)instr->len);
 
-       div_u64_rem(instr->len, mtd->erasesize, &rem);
-       if (rem)
-               return -EINVAL;
+       if (spi_nor_has_uniform_erase(nor)) {
+               div_u64_rem(instr->len, mtd->erasesize, &rem);
+               if (rem)
+                       return -EINVAL;
+       }
 
        addr = instr->addr;
        len = instr->len;
@@ -552,7 +838,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
         */
 
        /* "sector"-at-a-time erase */
-       } else {
+       } else if (spi_nor_has_uniform_erase(nor)) {
                while (len) {
                        write_enable(nor);
 
@@ -567,6 +853,12 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
                        if (ret)
                                goto erase_err;
                }
+
+       /* erase multiple sectors */
+       } else {
+               ret = spi_nor_erase_multi_sectors(nor, addr, len);
+               if (ret)
+                       goto erase_err;
        }
 
        write_disable(nor);
@@ -1464,13 +1756,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
                        goto write_err;
                *retlen += written;
                i += written;
-               if (written != page_remain) {
-                       dev_err(nor->dev,
-                               "While writing %zu bytes written %zd bytes\n",
-                               page_remain, written);
-                       ret = -EIO;
-                       goto write_err;
-               }
        }
 
 write_err:
@@ -1863,6 +2148,36 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
  * Serial Flash Discoverable Parameters (SFDP) parsing.
  */
 
+/**
+ * spi_nor_read_raw() - raw read of serial flash memory. read_opcode,
+ *                     addr_width and read_dummy members of the struct spi_nor
+ *                     should be previously
+ * set.
+ * @nor:       pointer to a 'struct spi_nor'
+ * @addr:      offset in the serial flash memory
+ * @len:       number of bytes to read
+ * @buf:       buffer where the data is copied into
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_read_raw(struct spi_nor *nor, u32 addr, size_t len, u8 *buf)
+{
+       int ret;
+
+       while (len) {
+               ret = nor->read(nor, addr, len, buf);
+               if (!ret || ret > len)
+                       return -EIO;
+               if (ret < 0)
+                       return ret;
+
+               buf += ret;
+               addr += ret;
+               len -= ret;
+       }
+       return 0;
+}
+
 /**
  * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters.
  * @nor:       pointer to a 'struct spi_nor'
@@ -1890,22 +2205,8 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
        nor->addr_width = 3;
        nor->read_dummy = 8;
 
-       while (len) {
-               ret = nor->read(nor, addr, len, (u8 *)buf);
-               if (!ret || ret > len) {
-                       ret = -EIO;
-                       goto read_err;
-               }
-               if (ret < 0)
-                       goto read_err;
-
-               buf += ret;
-               addr += ret;
-               len -= ret;
-       }
-       ret = 0;
+       ret = spi_nor_read_raw(nor, addr, len, buf);
 
-read_err:
        nor->read_opcode = read_opcode;
        nor->addr_width = addr_width;
        nor->read_dummy = read_dummy;
@@ -2165,6 +2466,116 @@ static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
 
 static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
 
+/**
+ * spi_nor_set_erase_type() - set a SPI NOR erase type
+ * @erase:     pointer to a structure that describes a SPI NOR erase type
+ * @size:      the size of the sector/block erased by the erase type
+ * @opcode:    the SPI command op code to erase the sector/block
+ */
+static void spi_nor_set_erase_type(struct spi_nor_erase_type *erase,
+                                  u32 size, u8 opcode)
+{
+       erase->size = size;
+       erase->opcode = opcode;
+       /* JEDEC JESD216B Standard imposes erase sizes to be power of 2. */
+       erase->size_shift = ffs(erase->size) - 1;
+       erase->size_mask = (1 << erase->size_shift) - 1;
+}
+
+/**
+ * spi_nor_set_erase_settings_from_bfpt() - set erase type settings from BFPT
+ * @erase:     pointer to a structure that describes a SPI NOR erase type
+ * @size:      the size of the sector/block erased by the erase type
+ * @opcode:    the SPI command op code to erase the sector/block
+ * @i:         erase type index as sorted in the Basic Flash Parameter Table
+ *
+ * The supported Erase Types will be sorted at init in ascending order, with
+ * the smallest Erase Type size being the first member in the erase_type array
+ * of the spi_nor_erase_map structure. Save the Erase Type index as sorted in
+ * the Basic Flash Parameter Table since it will be used later on to
+ * synchronize with the supported Erase Types defined in SFDP optional tables.
+ */
+static void
+spi_nor_set_erase_settings_from_bfpt(struct spi_nor_erase_type *erase,
+                                    u32 size, u8 opcode, u8 i)
+{
+       erase->idx = i;
+       spi_nor_set_erase_type(erase, size, opcode);
+}
+
+/**
+ * spi_nor_map_cmp_erase_type() - compare the map's erase types by size
+ * @l: member in the left half of the map's erase_type array
+ * @r: member in the right half of the map's erase_type array
+ *
+ * Comparison function used in the sort() call to sort in ascending order the
+ * map's erase types, the smallest erase type size being the first member in the
+ * sorted erase_type array.
+ *
+ * Return: the result of @l->size - @r->size
+ */
+static int spi_nor_map_cmp_erase_type(const void *l, const void *r)
+{
+       const struct spi_nor_erase_type *left = l, *right = r;
+
+       return left->size - right->size;
+}
+
+/**
+ * spi_nor_regions_sort_erase_types() - sort erase types in each region
+ * @map:       the erase map of the SPI NOR
+ *
+ * Function assumes that the erase types defined in the erase map are already
+ * sorted in ascending order, with the smallest erase type size being the first
+ * member in the erase_type array. It replicates the sort done for the map's
+ * erase types. Each region's erase bitmask will indicate which erase types are
+ * supported from the sorted erase types defined in the erase map.
+ * Sort the all region's erase type at init in order to speed up the process of
+ * finding the best erase command at runtime.
+ */
+static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map)
+{
+       struct spi_nor_erase_region *region = map->regions;
+       struct spi_nor_erase_type *erase_type = map->erase_type;
+       int i;
+       u8 region_erase_mask, sorted_erase_mask;
+
+       while (region) {
+               region_erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
+
+               /* Replicate the sort done for the map's erase types. */
+               sorted_erase_mask = 0;
+               for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
+                       if (erase_type[i].size &&
+                           region_erase_mask & BIT(erase_type[i].idx))
+                               sorted_erase_mask |= BIT(i);
+
+               /* Overwrite erase mask. */
+               region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) |
+                                sorted_erase_mask;
+
+               region = spi_nor_region_next(region);
+       }
+}
+
+/**
+ * spi_nor_init_uniform_erase_map() - Initialize uniform erase map
+ * @map:               the erase map of the SPI NOR
+ * @erase_mask:                bitmask encoding erase types that can erase the entire
+ *                     flash memory
+ * @flash_size:                the spi nor flash memory size
+ */
+static void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
+                                          u8 erase_mask, u64 flash_size)
+{
+       /* Offset 0 with erase_mask and SNOR_LAST_REGION bit set */
+       map->uniform_region.offset = (erase_mask & SNOR_ERASE_TYPE_MASK) |
+                                    SNOR_LAST_REGION;
+       map->uniform_region.size = flash_size;
+       map->regions = &map->uniform_region;
+       map->uniform_erase_type = erase_mask;
+}
+
 /**
  * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
  * @nor:               pointer to a 'struct spi_nor'
@@ -2199,12 +2610,14 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
                              const struct sfdp_parameter_header *bfpt_header,
                              struct spi_nor_flash_parameter *params)
 {
-       struct mtd_info *mtd = &nor->mtd;
+       struct spi_nor_erase_map *map = &nor->erase_map;
+       struct spi_nor_erase_type *erase_type = map->erase_type;
        struct sfdp_bfpt bfpt;
        size_t len;
        int i, cmd, err;
        u32 addr;
        u16 half;
+       u8 erase_mask;
 
        /* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
        if (bfpt_header->length < BFPT_DWORD_MAX_JESD216)
@@ -2273,7 +2686,12 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
                spi_nor_set_read_settings_from_bfpt(read, half, rd->proto);
        }
 
-       /* Sector Erase settings. */
+       /*
+        * Sector Erase settings. Reinitialize the uniform erase map using the
+        * Erase Types defined in the bfpt table.
+        */
+       erase_mask = 0;
+       memset(&nor->erase_map, 0, sizeof(nor->erase_map));
        for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) {
                const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i];
                u32 erasesize;
@@ -2288,18 +2706,25 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 
                erasesize = 1U << erasesize;
                opcode = (half >> 8) & 0xff;
-#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
-               if (erasesize == SZ_4K) {
-                       nor->erase_opcode = opcode;
-                       mtd->erasesize = erasesize;
-                       break;
-               }
-#endif
-               if (!mtd->erasesize || mtd->erasesize < erasesize) {
-                       nor->erase_opcode = opcode;
-                       mtd->erasesize = erasesize;
-               }
+               erase_mask |= BIT(i);
+               spi_nor_set_erase_settings_from_bfpt(&erase_type[i], erasesize,
+                                                    opcode, i);
        }
+       spi_nor_init_uniform_erase_map(map, erase_mask, params->size);
+       /*
+        * Sort all the map's Erase Types in ascending order with the smallest
+        * erase size being the first member in the erase_type array.
+        */
+       sort(erase_type, SNOR_ERASE_TYPE_MAX, sizeof(erase_type[0]),
+            spi_nor_map_cmp_erase_type, NULL);
+       /*
+        * Sort the erase types in the uniform region in order to update the
+        * uniform_erase_type bitmask. The bitmask will be used later on when
+        * selecting the uniform erase.
+        */
+       spi_nor_regions_sort_erase_types(map);
+       map->uniform_erase_type = map->uniform_region.offset &
+                                 SNOR_ERASE_TYPE_MASK;
 
        /* Stop here if not JESD216 rev A or later. */
        if (bfpt_header->length < BFPT_DWORD_MAX)
@@ -2341,6 +2766,277 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
        return 0;
 }
 
+#define SMPT_CMD_ADDRESS_LEN_MASK              GENMASK(23, 22)
+#define SMPT_CMD_ADDRESS_LEN_0                 (0x0UL << 22)
+#define SMPT_CMD_ADDRESS_LEN_3                 (0x1UL << 22)
+#define SMPT_CMD_ADDRESS_LEN_4                 (0x2UL << 22)
+#define SMPT_CMD_ADDRESS_LEN_USE_CURRENT       (0x3UL << 22)
+
+#define SMPT_CMD_READ_DUMMY_MASK               GENMASK(19, 16)
+#define SMPT_CMD_READ_DUMMY_SHIFT              16
+#define SMPT_CMD_READ_DUMMY(_cmd) \
+       (((_cmd) & SMPT_CMD_READ_DUMMY_MASK) >> SMPT_CMD_READ_DUMMY_SHIFT)
+#define SMPT_CMD_READ_DUMMY_IS_VARIABLE                0xfUL
+
+#define SMPT_CMD_READ_DATA_MASK                        GENMASK(31, 24)
+#define SMPT_CMD_READ_DATA_SHIFT               24
+#define SMPT_CMD_READ_DATA(_cmd) \
+       (((_cmd) & SMPT_CMD_READ_DATA_MASK) >> SMPT_CMD_READ_DATA_SHIFT)
+
+#define SMPT_CMD_OPCODE_MASK                   GENMASK(15, 8)
+#define SMPT_CMD_OPCODE_SHIFT                  8
+#define SMPT_CMD_OPCODE(_cmd) \
+       (((_cmd) & SMPT_CMD_OPCODE_MASK) >> SMPT_CMD_OPCODE_SHIFT)
+
+#define SMPT_MAP_REGION_COUNT_MASK             GENMASK(23, 16)
+#define SMPT_MAP_REGION_COUNT_SHIFT            16
+#define SMPT_MAP_REGION_COUNT(_header) \
+       ((((_header) & SMPT_MAP_REGION_COUNT_MASK) >> \
+         SMPT_MAP_REGION_COUNT_SHIFT) + 1)
+
+#define SMPT_MAP_ID_MASK                       GENMASK(15, 8)
+#define SMPT_MAP_ID_SHIFT                      8
+#define SMPT_MAP_ID(_header) \
+       (((_header) & SMPT_MAP_ID_MASK) >> SMPT_MAP_ID_SHIFT)
+
+#define SMPT_MAP_REGION_SIZE_MASK              GENMASK(31, 8)
+#define SMPT_MAP_REGION_SIZE_SHIFT             8
+#define SMPT_MAP_REGION_SIZE(_region) \
+       (((((_region) & SMPT_MAP_REGION_SIZE_MASK) >> \
+          SMPT_MAP_REGION_SIZE_SHIFT) + 1) * 256)
+
+#define SMPT_MAP_REGION_ERASE_TYPE_MASK                GENMASK(3, 0)
+#define SMPT_MAP_REGION_ERASE_TYPE(_region) \
+       ((_region) & SMPT_MAP_REGION_ERASE_TYPE_MASK)
+
+#define SMPT_DESC_TYPE_MAP                     BIT(1)
+#define SMPT_DESC_END                          BIT(0)
+
+/**
+ * spi_nor_smpt_addr_width() - return the address width used in the
+ *                            configuration detection command.
+ * @nor:       pointer to a 'struct spi_nor'
+ * @settings:  configuration detection command descriptor, dword1
+ */
+static u8 spi_nor_smpt_addr_width(const struct spi_nor *nor, const u32 settings)
+{
+       switch (settings & SMPT_CMD_ADDRESS_LEN_MASK) {
+       case SMPT_CMD_ADDRESS_LEN_0:
+               return 0;
+       case SMPT_CMD_ADDRESS_LEN_3:
+               return 3;
+       case SMPT_CMD_ADDRESS_LEN_4:
+               return 4;
+       case SMPT_CMD_ADDRESS_LEN_USE_CURRENT:
+               /* fall through */
+       default:
+               return nor->addr_width;
+       }
+}
+
+/**
+ * spi_nor_smpt_read_dummy() - return the configuration detection command read
+ *                            latency, in clock cycles.
+ * @nor:       pointer to a 'struct spi_nor'
+ * @settings:  configuration detection command descriptor, dword1
+ *
+ * Return: the number of dummy cycles for an SMPT read
+ */
+static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings)
+{
+       u8 read_dummy = SMPT_CMD_READ_DUMMY(settings);
+
+       if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE)
+               return nor->read_dummy;
+       return read_dummy;
+}
+
+/**
+ * spi_nor_get_map_in_use() - get the configuration map in use
+ * @nor:       pointer to a 'struct spi_nor'
+ * @smpt:      pointer to the sector map parameter table
+ */
+static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt)
+{
+       const u32 *ret = NULL;
+       u32 i, addr;
+       int err;
+       u8 addr_width, read_opcode, read_dummy;
+       u8 read_data_mask, data_byte, map_id;
+
+       addr_width = nor->addr_width;
+       read_dummy = nor->read_dummy;
+       read_opcode = nor->read_opcode;
+
+       map_id = 0;
+       i = 0;
+       /* Determine if there are any optional Detection Command Descriptors */
+       while (!(smpt[i] & SMPT_DESC_TYPE_MAP)) {
+               read_data_mask = SMPT_CMD_READ_DATA(smpt[i]);
+               nor->addr_width = spi_nor_smpt_addr_width(nor, smpt[i]);
+               nor->read_dummy = spi_nor_smpt_read_dummy(nor, smpt[i]);
+               nor->read_opcode = SMPT_CMD_OPCODE(smpt[i]);
+               addr = smpt[i + 1];
+
+               err = spi_nor_read_raw(nor, addr, 1, &data_byte);
+               if (err)
+                       goto out;
+
+               /*
+                * Build an index value that is used to select the Sector Map
+                * Configuration that is currently in use.
+                */
+               map_id = map_id << 1 | !!(data_byte & read_data_mask);
+               i = i + 2;
+       }
+
+       /* Find the matching configuration map */
+       while (SMPT_MAP_ID(smpt[i]) != map_id) {
+               if (smpt[i] & SMPT_DESC_END)
+                       goto out;
+               /* increment the table index to the next map */
+               i += SMPT_MAP_REGION_COUNT(smpt[i]) + 1;
+       }
+
+       ret = smpt + i;
+       /* fall through */
+out:
+       nor->addr_width = addr_width;
+       nor->read_dummy = read_dummy;
+       nor->read_opcode = read_opcode;
+       return ret;
+}
+
+/**
+ * spi_nor_region_check_overlay() - set overlay bit when the region is overlaid
+ * @region:    pointer to a structure that describes a SPI NOR erase region
+ * @erase:     pointer to a structure that describes a SPI NOR erase type
+ * @erase_type:        erase type bitmask
+ */
+static void
+spi_nor_region_check_overlay(struct spi_nor_erase_region *region,
+                            const struct spi_nor_erase_type *erase,
+                            const u8 erase_type)
+{
+       int i;
+
+       for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+               if (!(erase_type & BIT(i)))
+                       continue;
+               if (region->size & erase[i].size_mask) {
+                       spi_nor_region_mark_overlay(region);
+                       return;
+               }
+       }
+}
+
+/**
+ * spi_nor_init_non_uniform_erase_map() - initialize the non-uniform erase map
+ * @nor:       pointer to a 'struct spi_nor'
+ * @smpt:      pointer to the sector map parameter table
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
+                                             const u32 *smpt)
+{
+       struct spi_nor_erase_map *map = &nor->erase_map;
+       const struct spi_nor_erase_type *erase = map->erase_type;
+       struct spi_nor_erase_region *region;
+       u64 offset;
+       u32 region_count;
+       int i, j;
+       u8 erase_type;
+
+       region_count = SMPT_MAP_REGION_COUNT(*smpt);
+       /*
+        * The regions will be freed when the driver detaches from the
+        * device.
+        */
+       region = devm_kcalloc(nor->dev, region_count, sizeof(*region),
+                             GFP_KERNEL);
+       if (!region)
+               return -ENOMEM;
+       map->regions = region;
+
+       map->uniform_erase_type = 0xff;
+       offset = 0;
+       /* Populate regions. */
+       for (i = 0; i < region_count; i++) {
+               j = i + 1; /* index for the region dword */
+               region[i].size = SMPT_MAP_REGION_SIZE(smpt[j]);
+               erase_type = SMPT_MAP_REGION_ERASE_TYPE(smpt[j]);
+               region[i].offset = offset | erase_type;
+
+               spi_nor_region_check_overlay(&region[i], erase, erase_type);
+
+               /*
+                * Save the erase types that are supported in all regions and
+                * can erase the entire flash memory.
+                */
+               map->uniform_erase_type &= erase_type;
+
+               offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) +
+                        region[i].size;
+       }
+
+       spi_nor_region_mark_end(&region[i - 1]);
+
+       return 0;
+}
+
+/**
+ * spi_nor_parse_smpt() - parse Sector Map Parameter Table
+ * @nor:               pointer to a 'struct spi_nor'
+ * @smpt_header:       sector map parameter table header
+ *
+ * This table is optional, but when available, we parse it to identify the
+ * location and size of sectors within the main data array of the flash memory
+ * device and to identify which Erase Types are supported by each sector.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_smpt(struct spi_nor *nor,
+                             const struct sfdp_parameter_header *smpt_header)
+{
+       const u32 *sector_map;
+       u32 *smpt;
+       size_t len;
+       u32 addr;
+       int i, ret;
+
+       /* Read the Sector Map Parameter Table. */
+       len = smpt_header->length * sizeof(*smpt);
+       smpt = kzalloc(len, GFP_KERNEL);
+       if (!smpt)
+               return -ENOMEM;
+
+       addr = SFDP_PARAM_HEADER_PTP(smpt_header);
+       ret = spi_nor_read_sfdp(nor, addr, len, smpt);
+       if (ret)
+               goto out;
+
+       /* Fix endianness of the SMPT DWORDs. */
+       for (i = 0; i < smpt_header->length; i++)
+               smpt[i] = le32_to_cpu(smpt[i]);
+
+       sector_map = spi_nor_get_map_in_use(nor, smpt);
+       if (!sector_map) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = spi_nor_init_non_uniform_erase_map(nor, sector_map);
+       if (ret)
+               goto out;
+
+       spi_nor_regions_sort_erase_types(&nor->erase_map);
+       /* fall through */
+out:
+       kfree(smpt);
+       return ret;
+}
+
 /**
  * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
  * @nor:               pointer to a 'struct spi_nor'
@@ -2435,7 +3131,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
 
                switch (SFDP_PARAM_HEADER_ID(param_header)) {
                case SFDP_SECTOR_MAP_ID:
-                       dev_info(dev, "non-uniform erase sector maps are not supported yet.\n");
+                       err = spi_nor_parse_smpt(nor, param_header);
                        break;
 
                default:
@@ -2455,6 +3151,9 @@ static int spi_nor_init_params(struct spi_nor *nor,
                               const struct flash_info *info,
                               struct spi_nor_flash_parameter *params)
 {
+       struct spi_nor_erase_map *map = &nor->erase_map;
+       u8 i, erase_mask;
+
        /* Set legacy flash parameters as default. */
        memset(params, 0, sizeof(*params));
 
@@ -2494,6 +3193,28 @@ static int spi_nor_init_params(struct spi_nor *nor,
        spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
                                SPINOR_OP_PP, SNOR_PROTO_1_1_1);
 
+       /*
+        * Sector Erase settings. Sort Erase Types in ascending order, with the
+        * smallest erase size starting at BIT(0).
+        */
+       erase_mask = 0;
+       i = 0;
+       if (info->flags & SECT_4K_PMC) {
+               erase_mask |= BIT(i);
+               spi_nor_set_erase_type(&map->erase_type[i], 4096u,
+                                      SPINOR_OP_BE_4K_PMC);
+               i++;
+       } else if (info->flags & SECT_4K) {
+               erase_mask |= BIT(i);
+               spi_nor_set_erase_type(&map->erase_type[i], 4096u,
+                                      SPINOR_OP_BE_4K);
+               i++;
+       }
+       erase_mask |= BIT(i);
+       spi_nor_set_erase_type(&map->erase_type[i], info->sector_size,
+                              SPINOR_OP_SE);
+       spi_nor_init_uniform_erase_map(map, erase_mask, params->size);
+
        /* Select the procedure to set the Quad Enable bit. */
        if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD |
                                   SNOR_HWCAPS_PP_QUAD)) {
@@ -2521,20 +3242,20 @@ static int spi_nor_init_params(struct spi_nor *nor,
                        params->quad_enable = info->quad_enable;
        }
 
-       /* Override the parameters with data read from SFDP tables. */
-       nor->addr_width = 0;
-       nor->mtd.erasesize = 0;
        if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) &&
            !(info->flags & SPI_NOR_SKIP_SFDP)) {
                struct spi_nor_flash_parameter sfdp_params;
+               struct spi_nor_erase_map prev_map;
 
                memcpy(&sfdp_params, params, sizeof(sfdp_params));
-               if (spi_nor_parse_sfdp(nor, &sfdp_params)) {
-                       nor->addr_width = 0;
-                       nor->mtd.erasesize = 0;
-               } else {
+               memcpy(&prev_map, &nor->erase_map, sizeof(prev_map));
+
+               if (spi_nor_parse_sfdp(nor, &sfdp_params))
+                       /* restore previous erase map */
+                       memcpy(&nor->erase_map, &prev_map,
+                              sizeof(nor->erase_map));
+               else
                        memcpy(params, &sfdp_params, sizeof(*params));
-               }
        }
 
        return 0;
@@ -2643,29 +3364,103 @@ static int spi_nor_select_pp(struct spi_nor *nor,
        return 0;
 }
 
-static int spi_nor_select_erase(struct spi_nor *nor,
-                               const struct flash_info *info)
+/**
+ * spi_nor_select_uniform_erase() - select optimum uniform erase type
+ * @map:               the erase map of the SPI NOR
+ * @wanted_size:       the erase type size to search for. Contains the value of
+ *                     info->sector_size or of the "small sector" size in case
+ *                     CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined.
+ *
+ * Once the optimum uniform sector erase command is found, disable all the
+ * other.
+ *
+ * Return: pointer to erase type on success, NULL otherwise.
+ */
+static const struct spi_nor_erase_type *
+spi_nor_select_uniform_erase(struct spi_nor_erase_map *map,
+                            const u32 wanted_size)
 {
-       struct mtd_info *mtd = &nor->mtd;
+       const struct spi_nor_erase_type *tested_erase, *erase = NULL;
+       int i;
+       u8 uniform_erase_type = map->uniform_erase_type;
 
-       /* Do nothing if already configured from SFDP. */
-       if (mtd->erasesize)
-               return 0;
+       for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
+               if (!(uniform_erase_type & BIT(i)))
+                       continue;
+
+               tested_erase = &map->erase_type[i];
+
+               /*
+                * If the current erase size is the one, stop here:
+                * we have found the right uniform Sector Erase command.
+                */
+               if (tested_erase->size == wanted_size) {
+                       erase = tested_erase;
+                       break;
+               }
+
+               /*
+                * Otherwise, the current erase size is still a valid canditate.
+                * Select the biggest valid candidate.
+                */
+               if (!erase && tested_erase->size)
+                       erase = tested_erase;
+                       /* keep iterating to find the wanted_size */
+       }
+
+       if (!erase)
+               return NULL;
 
+       /* Disable all other Sector Erase commands. */
+       map->uniform_erase_type &= ~SNOR_ERASE_TYPE_MASK;
+       map->uniform_erase_type |= BIT(erase - map->erase_type);
+       return erase;
+}
+
+static int spi_nor_select_erase(struct spi_nor *nor, u32 wanted_size)
+{
+       struct spi_nor_erase_map *map = &nor->erase_map;
+       const struct spi_nor_erase_type *erase = NULL;
+       struct mtd_info *mtd = &nor->mtd;
+       int i;
+
+       /*
+        * The previous implementation handling Sector Erase commands assumed
+        * that the SPI flash memory has an uniform layout then used only one
+        * of the supported erase sizes for all Sector Erase commands.
+        * So to be backward compatible, the new implementation also tries to
+        * manage the SPI flash memory as uniform with a single erase sector
+        * size, when possible.
+        */
 #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
        /* prefer "small sector" erase if possible */
-       if (info->flags & SECT_4K) {
-               nor->erase_opcode = SPINOR_OP_BE_4K;
-               mtd->erasesize = 4096;
-       } else if (info->flags & SECT_4K_PMC) {
-               nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
-               mtd->erasesize = 4096;
-       } else
+       wanted_size = 4096u;
 #endif
-       {
-               nor->erase_opcode = SPINOR_OP_SE;
-               mtd->erasesize = info->sector_size;
+
+       if (spi_nor_has_uniform_erase(nor)) {
+               erase = spi_nor_select_uniform_erase(map, wanted_size);
+               if (!erase)
+                       return -EINVAL;
+               nor->erase_opcode = erase->opcode;
+               mtd->erasesize = erase->size;
+               return 0;
        }
+
+       /*
+        * For non-uniform SPI flash memory, set mtd->erasesize to the
+        * maximum erase sector size. No need to set nor->erase_opcode.
+        */
+       for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
+               if (map->erase_type[i].size) {
+                       erase = &map->erase_type[i];
+                       break;
+               }
+       }
+
+       if (!erase)
+               return -EINVAL;
+
+       mtd->erasesize = erase->size;
        return 0;
 }
 
@@ -2712,7 +3507,7 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
        }
 
        /* Select the Sector Erase command. */
-       err = spi_nor_select_erase(nor, info);
+       err = spi_nor_select_erase(nor, info->sector_size);
        if (err) {
                dev_err(nor->dev,
                        "can't select erase settings supported by both the SPI controller and memory.\n");
index 88b6c81cebbe68123da96775b3a42c3f96da4a11..c71523e945806c1e2f9147a6971b67679932be70 100644 (file)
@@ -121,8 +121,10 @@ static int no_bit_error_verify(void *error_data, void *error_ecc,
        unsigned char calc_ecc[3];
        int ret;
 
-       __nand_calculate_ecc(error_data, size, calc_ecc);
-       ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+       __nand_calculate_ecc(error_data, size, calc_ecc,
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+       ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
+                                 IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
        if (ret == 0 && !memcmp(correct_data, error_data, size))
                return 0;
 
@@ -149,8 +151,10 @@ static int single_bit_error_correct(void *error_data, void *error_ecc,
        unsigned char calc_ecc[3];
        int ret;
 
-       __nand_calculate_ecc(error_data, size, calc_ecc);
-       ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+       __nand_calculate_ecc(error_data, size, calc_ecc,
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+       ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
+                                 IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
        if (ret == 1 && !memcmp(correct_data, error_data, size))
                return 0;
 
@@ -184,8 +188,10 @@ static int double_bit_error_detect(void *error_data, void *error_ecc,
        unsigned char calc_ecc[3];
        int ret;
 
-       __nand_calculate_ecc(error_data, size, calc_ecc);
-       ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+       __nand_calculate_ecc(error_data, size, calc_ecc,
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+       ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
+                                 IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
 
        return (ret == -EBADMSG) ? 0 : -EINVAL;
 }
@@ -259,7 +265,8 @@ static int nand_ecc_test_run(const size_t size)
        }
 
        prandom_bytes(correct_data, size);
-       __nand_calculate_ecc(correct_data, size, correct_ecc);
+       __nand_calculate_ecc(correct_data, size, correct_ecc,
+                            IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
 
        for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) {
                nand_ecc_test[i].prepare(error_data, error_ecc,
index 448478451c4c4563cadc90106836f07567255871..def8a1f57d1cf2ba547405d22ff4040a85152a38 100644 (file)
@@ -630,8 +630,7 @@ static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id)
 }
 
 #ifdef CONFIG_MTD_SPINAND_ONDIEECC
-static int spinand_write_page_hwecc(struct mtd_info *mtd,
-                                   struct nand_chip *chip,
+static int spinand_write_page_hwecc(struct nand_chip *chip,
                                    const u8 *buf, int oob_required,
                                    int page)
 {
@@ -643,21 +642,22 @@ static int spinand_write_page_hwecc(struct mtd_info *mtd,
        return nand_prog_page_op(chip, page, 0, p, eccsize * eccsteps);
 }
 
-static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                                  u8 *buf, int oob_required, int page)
+static int spinand_read_page_hwecc(struct nand_chip *chip, u8 *buf,
+                                  int oob_required, int page)
 {
        int retval;
        u8 status;
        u8 *p = buf;
        int eccsize = chip->ecc.size;
        int eccsteps = chip->ecc.steps;
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct spinand_info *info = nand_get_controller_data(chip);
 
        enable_read_hw_ecc = 1;
 
        nand_read_page_op(chip, page, 0, p, eccsize * eccsteps);
        if (oob_required)
-               chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+               chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
 
        while (1) {
                retval = spinand_read_status(info->spi, &status);
@@ -681,13 +681,13 @@ static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 #endif
 
-static void spinand_select_chip(struct mtd_info *mtd, int dev)
+static void spinand_select_chip(struct nand_chip *chip, int dev)
 {
 }
 
-static u8 spinand_read_byte(struct mtd_info *mtd)
+static u8 spinand_read_byte(struct nand_chip *chip)
 {
-       struct spinand_state *state = mtd_to_state(mtd);
+       struct spinand_state *state = mtd_to_state(nand_to_mtd(chip));
        u8 data;
 
        data = state->buf[state->buf_ptr];
@@ -695,8 +695,9 @@ static u8 spinand_read_byte(struct mtd_info *mtd)
        return data;
 }
 
-static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int spinand_wait(struct nand_chip *chip)
 {
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct spinand_info *info = nand_get_controller_data(chip);
 
        unsigned long timeo = jiffies;
@@ -724,17 +725,17 @@ static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip)
        return 0;
 }
 
-static void spinand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void spinand_write_buf(struct nand_chip *chip, const u8 *buf, int len)
 {
-       struct spinand_state *state = mtd_to_state(mtd);
+       struct spinand_state *state = mtd_to_state(nand_to_mtd(chip));
 
        memcpy(state->buf + state->buf_ptr, buf, len);
        state->buf_ptr += len;
 }
 
-static void spinand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void spinand_read_buf(struct nand_chip *chip, u8 *buf, int len)
 {
-       struct spinand_state *state = mtd_to_state(mtd);
+       struct spinand_state *state = mtd_to_state(nand_to_mtd(chip));
 
        memcpy(buf, state->buf + state->buf_ptr, len);
        state->buf_ptr += len;
@@ -759,10 +760,10 @@ static void spinand_reset(struct spi_device *spi_nand)
                dev_err(&spi_nand->dev, "wait timedout!\n");
 }
 
-static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command,
+static void spinand_cmdfunc(struct nand_chip *chip, unsigned int command,
                            int column, int page)
 {
-       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtd_info *mtd = nand_to_mtd(chip);
        struct spinand_info *info = nand_get_controller_data(chip);
        struct spinand_state *state = info->priv;
 
@@ -914,15 +915,15 @@ static int spinand_probe(struct spi_device *spi_nand)
 
        nand_set_flash_node(chip, spi_nand->dev.of_node);
        nand_set_controller_data(chip, info);
-       chip->read_buf  = spinand_read_buf;
-       chip->write_buf = spinand_write_buf;
-       chip->read_byte = spinand_read_byte;
-       chip->cmdfunc   = spinand_cmdfunc;
-       chip->waitfunc  = spinand_wait;
+       chip->legacy.read_buf   = spinand_read_buf;
+       chip->legacy.write_buf  = spinand_write_buf;
+       chip->legacy.read_byte  = spinand_read_byte;
+       chip->legacy.cmdfunc    = spinand_cmdfunc;
+       chip->legacy.waitfunc   = spinand_wait;
        chip->options   |= NAND_CACHEPRG;
        chip->select_chip = spinand_select_chip;
-       chip->set_features = nand_get_set_features_notsupp;
-       chip->get_features = nand_get_set_features_notsupp;
+       chip->legacy.set_features = nand_get_set_features_notsupp;
+       chip->legacy.get_features = nand_get_set_features_notsupp;
 
        mtd = nand_to_mtd(chip);
 
@@ -934,7 +935,7 @@ static int spinand_probe(struct spi_device *spi_nand)
        mtd_set_ooblayout(mtd, &spinand_oob_64_ops);
 #endif
 
-       if (nand_scan(mtd, 1))
+       if (nand_scan(chip, 1))
                return -ENXIO;
 
        return mtd_device_register(mtd, NULL, 0);
index 87bdf0f4cba117fc7c987080b9b901d7614ebfd3..902a7dd10e5c45fbc496cfbb4a9c39f1ca4bb417 100644 (file)
@@ -285,10 +285,8 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_fs_info = c;
 
        ret = jffs2_parse_options(c, data);
-       if (ret) {
-               kfree(c);
+       if (ret)
                return -EINVAL;
-       }
 
        /* Initialize JFFS2 superblock locks, the further initialization will
         * be done later */
index 3fdfede2f0f3e9d7f66cd498f2ac51d00a012d58..5f343b796ad957307373ad0e765c21d5e06475ab 100644 (file)
  */
 /* Auto Boot Mode */
 #define IFC_NAND_NCFGR_BOOT            0x80000000
+/* SRAM Initialization */
+#define IFC_NAND_NCFGR_SRAM_INIT_EN    0x20000000
 /* Addressing Mode-ROW0+n/COL0 */
 #define IFC_NAND_NCFGR_ADDR_MODE_RC0   0x00000000
 /* Addressing Mode-ROW0+n/COL0+n */
diff --git a/include/linux/mtd/jedec.h b/include/linux/mtd/jedec.h
new file mode 100644 (file)
index 0000000..0b6b59f
--- /dev/null
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright Â© 2000-2010 David Woodhouse <dwmw2@infradead.org>
+ *                      Steven J. Hill <sjhill@realitydiluted.com>
+ *                      Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Contains all JEDEC related definitions
+ */
+
+#ifndef __LINUX_MTD_JEDEC_H
+#define __LINUX_MTD_JEDEC_H
+
+struct jedec_ecc_info {
+       u8 ecc_bits;
+       u8 codeword_size;
+       __le16 bb_per_lun;
+       __le16 block_endurance;
+       u8 reserved[2];
+} __packed;
+
+/* JEDEC features */
+#define JEDEC_FEATURE_16_BIT_BUS       (1 << 0)
+
+struct nand_jedec_params {
+       /* rev info and features block */
+       /* 'J' 'E' 'S' 'D'  */
+       u8 sig[4];
+       __le16 revision;
+       __le16 features;
+       u8 opt_cmd[3];
+       __le16 sec_cmd;
+       u8 num_of_param_pages;
+       u8 reserved0[18];
+
+       /* manufacturer information block */
+       char manufacturer[12];
+       char model[20];
+       u8 jedec_id[6];
+       u8 reserved1[10];
+
+       /* memory organization block */
+       __le32 byte_per_page;
+       __le16 spare_bytes_per_page;
+       u8 reserved2[6];
+       __le32 pages_per_block;
+       __le32 blocks_per_lun;
+       u8 lun_count;
+       u8 addr_cycles;
+       u8 bits_per_cell;
+       u8 programs_per_page;
+       u8 multi_plane_addr;
+       u8 multi_plane_op_attr;
+       u8 reserved3[38];
+
+       /* electrical parameter block */
+       __le16 async_sdr_speed_grade;
+       __le16 toggle_ddr_speed_grade;
+       __le16 sync_ddr_speed_grade;
+       u8 async_sdr_features;
+       u8 toggle_ddr_features;
+       u8 sync_ddr_features;
+       __le16 t_prog;
+       __le16 t_bers;
+       __le16 t_r;
+       __le16 t_r_multi_plane;
+       __le16 t_ccs;
+       __le16 io_pin_capacitance_typ;
+       __le16 input_pin_capacitance_typ;
+       __le16 clk_pin_capacitance_typ;
+       u8 driver_strength_support;
+       __le16 t_adl;
+       u8 reserved4[36];
+
+       /* ECC and endurance block */
+       u8 guaranteed_good_blocks;
+       __le16 guaranteed_block_endurance;
+       struct jedec_ecc_info ecc_info[4];
+       u8 reserved5[29];
+
+       /* reserved */
+       u8 reserved6[148];
+
+       /* vendor */
+       __le16 vendor_rev_num;
+       u8 reserved7[88];
+
+       /* CRC for Parameter Page */
+       __le16 crc;
+} __packed;
+
+#endif /* __LINUX_MTD_JEDEC_H */
index 98f20ef05d60723ad10e6e552a506b3a783b4fba..b8106651f80799cfdb7236018d82c77328a2f8b2 100644 (file)
@@ -12,6 +12,7 @@
 #define __MTD_NAND_BCH_H__
 
 struct mtd_info;
+struct nand_chip;
 struct nand_bch_control;
 
 #if defined(CONFIG_MTD_NAND_ECC_BCH)
@@ -21,14 +22,14 @@ static inline int mtd_nand_has_bch(void) { return 1; }
 /*
  * Calculate BCH ecc code
  */
-int nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+int nand_bch_calculate_ecc(struct nand_chip *chip, const u_char *dat,
                           u_char *ecc_code);
 
 /*
  * Detect and correct bit errors
  */
-int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
-                         u_char *calc_ecc);
+int nand_bch_correct_data(struct nand_chip *chip, u_char *dat,
+                         u_char *read_ecc, u_char *calc_ecc);
 /*
  * Initialize BCH encoder/decoder
  */
@@ -43,14 +44,14 @@ void nand_bch_free(struct nand_bch_control *nbc);
 static inline int mtd_nand_has_bch(void) { return 0; }
 
 static inline int
-nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+nand_bch_calculate_ecc(struct nand_chip *chip, const u_char *dat,
                       u_char *ecc_code)
 {
        return -1;
 }
 
 static inline int
-nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+nand_bch_correct_data(struct nand_chip *chip, unsigned char *buf,
                      unsigned char *read_ecc, unsigned char *calc_ecc)
 {
        return -ENOTSUPP;
index 8a2decf7462c646618d73b2a35556853edd4d73f..0b3bb156c3446ee0dd33234156848a311235bf64 100644 (file)
 #ifndef __MTD_NAND_ECC_H__
 #define __MTD_NAND_ECC_H__
 
-struct mtd_info;
+struct nand_chip;
 
 /*
  * Calculate 3 byte ECC code for eccsize byte block
  */
 void __nand_calculate_ecc(const u_char *dat, unsigned int eccsize,
-                               u_char *ecc_code);
+                         u_char *ecc_code, bool sm_order);
 
 /*
  * Calculate 3 byte ECC code for 256/512 byte block
  */
-int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
+int nand_calculate_ecc(struct nand_chip *chip, const u_char *dat,
+                      u_char *ecc_code);
 
 /*
  * Detect and correct a 1 bit error for eccsize byte block
  */
 int __nand_correct_data(u_char *dat, u_char *read_ecc, u_char *calc_ecc,
-                       unsigned int eccsize);
+                       unsigned int eccsize, bool sm_order);
 
 /*
  * Detect and correct a 1 bit error for 256/512 byte block
  */
-int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+int nand_correct_data(struct nand_chip *chip, u_char *dat, u_char *read_ecc,
+                     u_char *calc_ecc);
 
 #endif /* __MTD_NAND_ECC_H__ */
diff --git a/include/linux/mtd/onfi.h b/include/linux/mtd/onfi.h
new file mode 100644 (file)
index 0000000..339ac79
--- /dev/null
@@ -0,0 +1,178 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright Â© 2000-2010 David Woodhouse <dwmw2@infradead.org>
+ *                      Steven J. Hill <sjhill@realitydiluted.com>
+ *                      Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Contains all ONFI related definitions
+ */
+
+#ifndef __LINUX_MTD_ONFI_H
+#define __LINUX_MTD_ONFI_H
+
+#include <linux/types.h>
+
+/* ONFI version bits */
+#define ONFI_VERSION_1_0               BIT(1)
+#define ONFI_VERSION_2_0               BIT(2)
+#define ONFI_VERSION_2_1               BIT(3)
+#define ONFI_VERSION_2_2               BIT(4)
+#define ONFI_VERSION_2_3               BIT(5)
+#define ONFI_VERSION_3_0               BIT(6)
+#define ONFI_VERSION_3_1               BIT(7)
+#define ONFI_VERSION_3_2               BIT(8)
+#define ONFI_VERSION_4_0               BIT(9)
+
+/* ONFI features */
+#define ONFI_FEATURE_16_BIT_BUS                (1 << 0)
+#define ONFI_FEATURE_EXT_PARAM_PAGE    (1 << 7)
+
+/* ONFI timing mode, used in both asynchronous and synchronous mode */
+#define ONFI_TIMING_MODE_0             (1 << 0)
+#define ONFI_TIMING_MODE_1             (1 << 1)
+#define ONFI_TIMING_MODE_2             (1 << 2)
+#define ONFI_TIMING_MODE_3             (1 << 3)
+#define ONFI_TIMING_MODE_4             (1 << 4)
+#define ONFI_TIMING_MODE_5             (1 << 5)
+#define ONFI_TIMING_MODE_UNKNOWN       (1 << 6)
+
+/* ONFI feature number/address */
+#define ONFI_FEATURE_NUMBER            256
+#define ONFI_FEATURE_ADDR_TIMING_MODE  0x1
+
+/* Vendor-specific feature address (Micron) */
+#define ONFI_FEATURE_ADDR_READ_RETRY   0x89
+#define ONFI_FEATURE_ON_DIE_ECC                0x90
+#define   ONFI_FEATURE_ON_DIE_ECC_EN   BIT(3)
+
+/* ONFI subfeature parameters length */
+#define ONFI_SUBFEATURE_PARAM_LEN      4
+
+/* ONFI optional commands SET/GET FEATURES supported? */
+#define ONFI_OPT_CMD_SET_GET_FEATURES  (1 << 2)
+
+struct nand_onfi_params {
+       /* rev info and features block */
+       /* 'O' 'N' 'F' 'I'  */
+       u8 sig[4];
+       __le16 revision;
+       __le16 features;
+       __le16 opt_cmd;
+       u8 reserved0[2];
+       __le16 ext_param_page_length; /* since ONFI 2.1 */
+       u8 num_of_param_pages;        /* since ONFI 2.1 */
+       u8 reserved1[17];
+
+       /* manufacturer information block */
+       char manufacturer[12];
+       char model[20];
+       u8 jedec_id;
+       __le16 date_code;
+       u8 reserved2[13];
+
+       /* memory organization block */
+       __le32 byte_per_page;
+       __le16 spare_bytes_per_page;
+       __le32 data_bytes_per_ppage;
+       __le16 spare_bytes_per_ppage;
+       __le32 pages_per_block;
+       __le32 blocks_per_lun;
+       u8 lun_count;
+       u8 addr_cycles;
+       u8 bits_per_cell;
+       __le16 bb_per_lun;
+       __le16 block_endurance;
+       u8 guaranteed_good_blocks;
+       __le16 guaranteed_block_endurance;
+       u8 programs_per_page;
+       u8 ppage_attr;
+       u8 ecc_bits;
+       u8 interleaved_bits;
+       u8 interleaved_ops;
+       u8 reserved3[13];
+
+       /* electrical parameter block */
+       u8 io_pin_capacitance_max;
+       __le16 async_timing_mode;
+       __le16 program_cache_timing_mode;
+       __le16 t_prog;
+       __le16 t_bers;
+       __le16 t_r;
+       __le16 t_ccs;
+       __le16 src_sync_timing_mode;
+       u8 src_ssync_features;
+       __le16 clk_pin_capacitance_typ;
+       __le16 io_pin_capacitance_typ;
+       __le16 input_pin_capacitance_typ;
+       u8 input_pin_capacitance_max;
+       u8 driver_strength_support;
+       __le16 t_int_r;
+       __le16 t_adl;
+       u8 reserved4[8];
+
+       /* vendor */
+       __le16 vendor_revision;
+       u8 vendor[88];
+
+       __le16 crc;
+} __packed;
+
+#define ONFI_CRC_BASE  0x4F4E
+
+/* Extended ECC information Block Definition (since ONFI 2.1) */
+struct onfi_ext_ecc_info {
+       u8 ecc_bits;
+       u8 codeword_size;
+       __le16 bb_per_lun;
+       __le16 block_endurance;
+       u8 reserved[2];
+} __packed;
+
+#define ONFI_SECTION_TYPE_0    0       /* Unused section. */
+#define ONFI_SECTION_TYPE_1    1       /* for additional sections. */
+#define ONFI_SECTION_TYPE_2    2       /* for ECC information. */
+struct onfi_ext_section {
+       u8 type;
+       u8 length;
+} __packed;
+
+#define ONFI_EXT_SECTION_MAX 8
+
+/* Extended Parameter Page Definition (since ONFI 2.1) */
+struct onfi_ext_param_page {
+       __le16 crc;
+       u8 sig[4];             /* 'E' 'P' 'P' 'S' */
+       u8 reserved0[10];
+       struct onfi_ext_section sections[ONFI_EXT_SECTION_MAX];
+
+       /*
+        * The actual size of the Extended Parameter Page is in
+        * @ext_param_page_length of nand_onfi_params{}.
+        * The following are the variable length sections.
+        * So we do not add any fields below. Please see the ONFI spec.
+        */
+} __packed;
+
+/**
+ * struct onfi_params - ONFI specific parameters that will be reused
+ * @version: ONFI version (BCD encoded), 0 if ONFI is not supported
+ * @tPROG: Page program time
+ * @tBERS: Block erase time
+ * @tR: Page read time
+ * @tCCS: Change column setup time
+ * @async_timing_mode: Supported asynchronous timing mode
+ * @vendor_revision: Vendor specific revision number
+ * @vendor: Vendor specific data
+ */
+struct onfi_params {
+       int version;
+       u16 tPROG;
+       u16 tBERS;
+       u16 tR;
+       u16 tCCS;
+       u16 async_timing_mode;
+       u16 vendor_revision;
+       u8 vendor[88];
+};
+
+#endif /* __LINUX_MTD_ONFI_H */
diff --git a/include/linux/mtd/platnand.h b/include/linux/mtd/platnand.h
new file mode 100644 (file)
index 0000000..bc11eb6
--- /dev/null
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright Â© 2000-2010 David Woodhouse <dwmw2@infradead.org>
+ *                       Steven J. Hill <sjhill@realitydiluted.com>
+ *                       Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Contains all platform NAND related definitions.
+ */
+
+#ifndef __LINUX_MTD_PLATNAND_H
+#define __LINUX_MTD_PLATNAND_H
+
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/platform_device.h>
+
+/**
+ * struct platform_nand_chip - chip level device structure
+ * @nr_chips: max. number of chips to scan for
+ * @chip_offset: chip number offset
+ * @nr_partitions: number of partitions pointed to by partitions (or zero)
+ * @partitions: mtd partition list
+ * @chip_delay: R/B delay value in us
+ * @options: Option flags, e.g. 16bit buswidth
+ * @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH
+ * @part_probe_types: NULL-terminated array of probe types
+ */
+struct platform_nand_chip {
+       int nr_chips;
+       int chip_offset;
+       int nr_partitions;
+       struct mtd_partition *partitions;
+       int chip_delay;
+       unsigned int options;
+       unsigned int bbt_options;
+       const char **part_probe_types;
+};
+
+/**
+ * struct platform_nand_ctrl - controller level device structure
+ * @probe: platform specific function to probe/setup hardware
+ * @remove: platform specific function to remove/teardown hardware
+ * @dev_ready: platform specific function to read ready/busy pin
+ * @select_chip: platform specific chip select function
+ * @cmd_ctrl: platform specific function for controlling
+ *           ALE/CLE/nCE. Also used to write command and address
+ * @write_buf: platform specific function for write buffer
+ * @read_buf: platform specific function for read buffer
+ * @priv: private data to transport driver specific settings
+ *
+ * All fields are optional and depend on the hardware driver requirements
+ */
+struct platform_nand_ctrl {
+       int (*probe)(struct platform_device *pdev);
+       void (*remove)(struct platform_device *pdev);
+       int (*dev_ready)(struct nand_chip *chip);
+       void (*select_chip)(struct nand_chip *chip, int cs);
+       void (*cmd_ctrl)(struct nand_chip *chip, int dat, unsigned int ctrl);
+       void (*write_buf)(struct nand_chip *chip, const uint8_t *buf, int len);
+       void (*read_buf)(struct nand_chip *chip, uint8_t *buf, int len);
+       void *priv;
+};
+
+/**
+ * struct platform_nand_data - container structure for platform-specific data
+ * @chip: chip level chip structure
+ * @ctrl: controller level device structure
+ */
+struct platform_nand_data {
+       struct platform_nand_chip chip;
+       struct platform_nand_ctrl ctrl;
+};
+
+#endif /* __LINUX_MTD_PLATNAND_H */
index efb2345359bbd8e09765491f1bb126803c6f2fb4..e10b126e148f0a9f8e045ffbfa9b016f9adaed17 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/flashchip.h>
 #include <linux/mtd/bbm.h>
+#include <linux/mtd/jedec.h>
+#include <linux/mtd/onfi.h>
 #include <linux/of.h>
 #include <linux/types.h>
 
-struct nand_flash_dev;
-
-/* Scan and identify a NAND device */
-int nand_scan_with_ids(struct mtd_info *mtd, int max_chips,
-                      struct nand_flash_dev *ids);
-
-static inline int nand_scan(struct mtd_info *mtd, int max_chips)
-{
-       return nand_scan_with_ids(mtd, max_chips, NULL);
-}
-
-/* Internal helper for board drivers which need to override command function */
-void nand_wait_ready(struct mtd_info *mtd);
+struct nand_chip;
 
 /* The maximum number of NAND chips in an array */
 #define NAND_MAX_CHIPS         8
@@ -131,9 +121,11 @@ enum nand_ecc_algo {
 #define NAND_ECC_GENERIC_ERASED_CHECK  BIT(0)
 #define NAND_ECC_MAXIMIZE              BIT(1)
 
-/* Bit mask for flags passed to do_nand_read_ecc */
-#define NAND_GET_DEVICE                0x80
-
+/*
+ * When using software implementation of Hamming, we can specify which byte
+ * ordering should be used.
+ */
+#define NAND_ECC_SOFT_HAMMING_SM_ORDER BIT(2)
 
 /*
  * Option constants for bizarre disfunctionality and real
@@ -175,9 +167,7 @@ enum nand_ecc_algo {
 #define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
 
 /* Macros to identify the above */
-#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
 #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
-#define NAND_HAS_SUBPAGE_WRITE(chip) !((chip)->options & NAND_NO_SUBPAGE_WRITE)
 
 /* Non chip related options */
 /* This option skips the bbt scan during initialization. */
@@ -198,10 +188,10 @@ enum nand_ecc_algo {
 #define NAND_USE_BOUNCE_BUFFER 0x00100000
 
 /*
- * In case your controller is implementing ->cmd_ctrl() and is relying on the
- * default ->cmdfunc() implementation, you may want to let the core handle the
- * tCCS delay which is required when a column change (RNDIN or RNDOUT) is
- * requested.
+ * In case your controller is implementing ->legacy.cmd_ctrl() and is relying
+ * on the default ->cmdfunc() implementation, you may want to let the core
+ * handle the tCCS delay which is required when a column change (RNDIN or
+ * RNDOUT) is requested.
  * If your controller already takes care of this delay, you don't need to set
  * this flag.
  */
@@ -222,250 +212,6 @@ enum nand_ecc_algo {
 #define NAND_CI_CELLTYPE_MSK   0x0C
 #define NAND_CI_CELLTYPE_SHIFT 2
 
-/* Keep gcc happy */
-struct nand_chip;
-
-/* ONFI version bits */
-#define ONFI_VERSION_1_0               BIT(1)
-#define ONFI_VERSION_2_0               BIT(2)
-#define ONFI_VERSION_2_1               BIT(3)
-#define ONFI_VERSION_2_2               BIT(4)
-#define ONFI_VERSION_2_3               BIT(5)
-#define ONFI_VERSION_3_0               BIT(6)
-#define ONFI_VERSION_3_1               BIT(7)
-#define ONFI_VERSION_3_2               BIT(8)
-#define ONFI_VERSION_4_0               BIT(9)
-
-/* ONFI features */
-#define ONFI_FEATURE_16_BIT_BUS                (1 << 0)
-#define ONFI_FEATURE_EXT_PARAM_PAGE    (1 << 7)
-
-/* ONFI timing mode, used in both asynchronous and synchronous mode */
-#define ONFI_TIMING_MODE_0             (1 << 0)
-#define ONFI_TIMING_MODE_1             (1 << 1)
-#define ONFI_TIMING_MODE_2             (1 << 2)
-#define ONFI_TIMING_MODE_3             (1 << 3)
-#define ONFI_TIMING_MODE_4             (1 << 4)
-#define ONFI_TIMING_MODE_5             (1 << 5)
-#define ONFI_TIMING_MODE_UNKNOWN       (1 << 6)
-
-/* ONFI feature number/address */
-#define ONFI_FEATURE_NUMBER            256
-#define ONFI_FEATURE_ADDR_TIMING_MODE  0x1
-
-/* Vendor-specific feature address (Micron) */
-#define ONFI_FEATURE_ADDR_READ_RETRY   0x89
-#define ONFI_FEATURE_ON_DIE_ECC                0x90
-#define   ONFI_FEATURE_ON_DIE_ECC_EN   BIT(3)
-
-/* ONFI subfeature parameters length */
-#define ONFI_SUBFEATURE_PARAM_LEN      4
-
-/* ONFI optional commands SET/GET FEATURES supported? */
-#define ONFI_OPT_CMD_SET_GET_FEATURES  (1 << 2)
-
-struct nand_onfi_params {
-       /* rev info and features block */
-       /* 'O' 'N' 'F' 'I'  */
-       u8 sig[4];
-       __le16 revision;
-       __le16 features;
-       __le16 opt_cmd;
-       u8 reserved0[2];
-       __le16 ext_param_page_length; /* since ONFI 2.1 */
-       u8 num_of_param_pages;        /* since ONFI 2.1 */
-       u8 reserved1[17];
-
-       /* manufacturer information block */
-       char manufacturer[12];
-       char model[20];
-       u8 jedec_id;
-       __le16 date_code;
-       u8 reserved2[13];
-
-       /* memory organization block */
-       __le32 byte_per_page;
-       __le16 spare_bytes_per_page;
-       __le32 data_bytes_per_ppage;
-       __le16 spare_bytes_per_ppage;
-       __le32 pages_per_block;
-       __le32 blocks_per_lun;
-       u8 lun_count;
-       u8 addr_cycles;
-       u8 bits_per_cell;
-       __le16 bb_per_lun;
-       __le16 block_endurance;
-       u8 guaranteed_good_blocks;
-       __le16 guaranteed_block_endurance;
-       u8 programs_per_page;
-       u8 ppage_attr;
-       u8 ecc_bits;
-       u8 interleaved_bits;
-       u8 interleaved_ops;
-       u8 reserved3[13];
-
-       /* electrical parameter block */
-       u8 io_pin_capacitance_max;
-       __le16 async_timing_mode;
-       __le16 program_cache_timing_mode;
-       __le16 t_prog;
-       __le16 t_bers;
-       __le16 t_r;
-       __le16 t_ccs;
-       __le16 src_sync_timing_mode;
-       u8 src_ssync_features;
-       __le16 clk_pin_capacitance_typ;
-       __le16 io_pin_capacitance_typ;
-       __le16 input_pin_capacitance_typ;
-       u8 input_pin_capacitance_max;
-       u8 driver_strength_support;
-       __le16 t_int_r;
-       __le16 t_adl;
-       u8 reserved4[8];
-
-       /* vendor */
-       __le16 vendor_revision;
-       u8 vendor[88];
-
-       __le16 crc;
-} __packed;
-
-#define ONFI_CRC_BASE  0x4F4E
-
-/* Extended ECC information Block Definition (since ONFI 2.1) */
-struct onfi_ext_ecc_info {
-       u8 ecc_bits;
-       u8 codeword_size;
-       __le16 bb_per_lun;
-       __le16 block_endurance;
-       u8 reserved[2];
-} __packed;
-
-#define ONFI_SECTION_TYPE_0    0       /* Unused section. */
-#define ONFI_SECTION_TYPE_1    1       /* for additional sections. */
-#define ONFI_SECTION_TYPE_2    2       /* for ECC information. */
-struct onfi_ext_section {
-       u8 type;
-       u8 length;
-} __packed;
-
-#define ONFI_EXT_SECTION_MAX 8
-
-/* Extended Parameter Page Definition (since ONFI 2.1) */
-struct onfi_ext_param_page {
-       __le16 crc;
-       u8 sig[4];             /* 'E' 'P' 'P' 'S' */
-       u8 reserved0[10];
-       struct onfi_ext_section sections[ONFI_EXT_SECTION_MAX];
-
-       /*
-        * The actual size of the Extended Parameter Page is in
-        * @ext_param_page_length of nand_onfi_params{}.
-        * The following are the variable length sections.
-        * So we do not add any fields below. Please see the ONFI spec.
-        */
-} __packed;
-
-struct jedec_ecc_info {
-       u8 ecc_bits;
-       u8 codeword_size;
-       __le16 bb_per_lun;
-       __le16 block_endurance;
-       u8 reserved[2];
-} __packed;
-
-/* JEDEC features */
-#define JEDEC_FEATURE_16_BIT_BUS       (1 << 0)
-
-struct nand_jedec_params {
-       /* rev info and features block */
-       /* 'J' 'E' 'S' 'D'  */
-       u8 sig[4];
-       __le16 revision;
-       __le16 features;
-       u8 opt_cmd[3];
-       __le16 sec_cmd;
-       u8 num_of_param_pages;
-       u8 reserved0[18];
-
-       /* manufacturer information block */
-       char manufacturer[12];
-       char model[20];
-       u8 jedec_id[6];
-       u8 reserved1[10];
-
-       /* memory organization block */
-       __le32 byte_per_page;
-       __le16 spare_bytes_per_page;
-       u8 reserved2[6];
-       __le32 pages_per_block;
-       __le32 blocks_per_lun;
-       u8 lun_count;
-       u8 addr_cycles;
-       u8 bits_per_cell;
-       u8 programs_per_page;
-       u8 multi_plane_addr;
-       u8 multi_plane_op_attr;
-       u8 reserved3[38];
-
-       /* electrical parameter block */
-       __le16 async_sdr_speed_grade;
-       __le16 toggle_ddr_speed_grade;
-       __le16 sync_ddr_speed_grade;
-       u8 async_sdr_features;
-       u8 toggle_ddr_features;
-       u8 sync_ddr_features;
-       __le16 t_prog;
-       __le16 t_bers;
-       __le16 t_r;
-       __le16 t_r_multi_plane;
-       __le16 t_ccs;
-       __le16 io_pin_capacitance_typ;
-       __le16 input_pin_capacitance_typ;
-       __le16 clk_pin_capacitance_typ;
-       u8 driver_strength_support;
-       __le16 t_adl;
-       u8 reserved4[36];
-
-       /* ECC and endurance block */
-       u8 guaranteed_good_blocks;
-       __le16 guaranteed_block_endurance;
-       struct jedec_ecc_info ecc_info[4];
-       u8 reserved5[29];
-
-       /* reserved */
-       u8 reserved6[148];
-
-       /* vendor */
-       __le16 vendor_rev_num;
-       u8 reserved7[88];
-
-       /* CRC for Parameter Page */
-       __le16 crc;
-} __packed;
-
-/**
- * struct onfi_params - ONFI specific parameters that will be reused
- * @version: ONFI version (BCD encoded), 0 if ONFI is not supported
- * @tPROG: Page program time
- * @tBERS: Block erase time
- * @tR: Page read time
- * @tCCS: Change column setup time
- * @async_timing_mode: Supported asynchronous timing mode
- * @vendor_revision: Vendor specific revision number
- * @vendor: Vendor specific data
- */
-struct onfi_params {
-       int version;
-       u16 tPROG;
-       u16 tBERS;
-       u16 tR;
-       u16 tCCS;
-       u16 async_timing_mode;
-       u16 vendor_revision;
-       u8 vendor[88];
-};
-
 /**
  * struct nand_parameters - NAND generic parameters from the parameter page
  * @model: Model name
@@ -646,31 +392,28 @@ struct nand_ecc_ctrl {
        void *priv;
        u8 *calc_buf;
        u8 *code_buf;
-       void (*hwctl)(struct mtd_info *mtd, int mode);
-       int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
-                       uint8_t *ecc_code);
-       int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,
-                       uint8_t *calc_ecc);
-       int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint8_t *buf, int oob_required, int page);
-       int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
-                       const uint8_t *buf, int oob_required, int page);
-       int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint8_t *buf, int oob_required, int page);
-       int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint32_t offs, uint32_t len, uint8_t *buf, int page);
-       int (*write_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint32_t offset, uint32_t data_len,
-                       const uint8_t *data_buf, int oob_required, int page);
-       int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
-                       const uint8_t *buf, int oob_required, int page);
-       int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
-                       int page);
-       int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
-                       int page);
-       int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page);
-       int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
-                       int page);
+       void (*hwctl)(struct nand_chip *chip, int mode);
+       int (*calculate)(struct nand_chip *chip, const uint8_t *dat,
+                        uint8_t *ecc_code);
+       int (*correct)(struct nand_chip *chip, uint8_t *dat, uint8_t *read_ecc,
+                      uint8_t *calc_ecc);
+       int (*read_page_raw)(struct nand_chip *chip, uint8_t *buf,
+                            int oob_required, int page);
+       int (*write_page_raw)(struct nand_chip *chip, const uint8_t *buf,
+                             int oob_required, int page);
+       int (*read_page)(struct nand_chip *chip, uint8_t *buf,
+                        int oob_required, int page);
+       int (*read_subpage)(struct nand_chip *chip, uint32_t offs,
+                           uint32_t len, uint8_t *buf, int page);
+       int (*write_subpage)(struct nand_chip *chip, uint32_t offset,
+                            uint32_t data_len, const uint8_t *data_buf,
+                            int oob_required, int page);
+       int (*write_page)(struct nand_chip *chip, const uint8_t *buf,
+                         int oob_required, int page);
+       int (*write_oob_raw)(struct nand_chip *chip, int page);
+       int (*read_oob_raw)(struct nand_chip *chip, int page);
+       int (*read_oob)(struct nand_chip *chip, int page);
+       int (*write_oob)(struct nand_chip *chip, int page);
 };
 
 /**
@@ -799,24 +542,6 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
        return &conf->timings.sdr;
 }
 
-/**
- * struct nand_manufacturer_ops - NAND Manufacturer operations
- * @detect: detect the NAND memory organization and capabilities
- * @init: initialize all vendor specific fields (like the ->read_retry()
- *       implementation) if any.
- * @cleanup: the ->init() function may have allocated resources, ->cleanup()
- *          is here to let vendor specific code release those resources.
- * @fixup_onfi_param_page: apply vendor specific fixups to the ONFI parameter
- *                        page. This is called after the checksum is verified.
- */
-struct nand_manufacturer_ops {
-       void (*detect)(struct nand_chip *chip);
-       int (*init)(struct nand_chip *chip);
-       void (*cleanup)(struct nand_chip *chip);
-       void (*fixup_onfi_param_page)(struct nand_chip *chip,
-                                     struct nand_onfi_params *p);
-};
-
 /**
  * struct nand_op_cmd_instr - Definition of a command instruction
  * @opcode: the command to issue in one cycle
@@ -1174,45 +899,73 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
                           const struct nand_op_parser *parser,
                           const struct nand_operation *op, bool check_only);
 
+/**
+ * struct nand_legacy - NAND chip legacy fields/hooks
+ * @IO_ADDR_R: address to read the 8 I/O lines of the flash device
+ * @IO_ADDR_W: address to write the 8 I/O lines of the flash device
+ * @read_byte: read one byte from the chip
+ * @write_byte: write a single byte to the chip on the low 8 I/O lines
+ * @write_buf: write data from the buffer to the chip
+ * @read_buf: read data from the chip into the buffer
+ * @cmd_ctrl: hardware specific function for controlling ALE/CLE/nCE. Also used
+ *           to write command and address
+ * @cmdfunc: hardware specific function for writing commands to the chip.
+ * @dev_ready: hardware specific function for accessing device ready/busy line.
+ *            If set to NULL no access to ready/busy is available and the
+ *            ready/busy information is read from the chip status register.
+ * @waitfunc: hardware specific function for wait on ready.
+ * @block_bad: check if a block is bad, using OOB markers
+ * @block_markbad: mark a block bad
+ * @erase: erase function
+ * @set_features: set the NAND chip features
+ * @get_features: get the NAND chip features
+ * @chip_delay: chip dependent delay for transferring data from array to read
+ *             regs (tR).
+ *
+ * If you look at this structure you're already wrong. These fields/hooks are
+ * all deprecated.
+ */
+struct nand_legacy {
+       void __iomem *IO_ADDR_R;
+       void __iomem *IO_ADDR_W;
+       u8 (*read_byte)(struct nand_chip *chip);
+       void (*write_byte)(struct nand_chip *chip, u8 byte);
+       void (*write_buf)(struct nand_chip *chip, const u8 *buf, int len);
+       void (*read_buf)(struct nand_chip *chip, u8 *buf, int len);
+       void (*cmd_ctrl)(struct nand_chip *chip, int dat, unsigned int ctrl);
+       void (*cmdfunc)(struct nand_chip *chip, unsigned command, int column,
+                       int page_addr);
+       int (*dev_ready)(struct nand_chip *chip);
+       int (*waitfunc)(struct nand_chip *chip);
+       int (*block_bad)(struct nand_chip *chip, loff_t ofs);
+       int (*block_markbad)(struct nand_chip *chip, loff_t ofs);
+       int (*erase)(struct nand_chip *chip, int page);
+       int (*set_features)(struct nand_chip *chip, int feature_addr,
+                           u8 *subfeature_para);
+       int (*get_features)(struct nand_chip *chip, int feature_addr,
+                           u8 *subfeature_para);
+       int chip_delay;
+};
+
 /**
  * struct nand_chip - NAND Private Flash Chip Data
  * @mtd:               MTD device registered to the MTD framework
- * @IO_ADDR_R:         [BOARDSPECIFIC] address to read the 8 I/O lines of the
- *                     flash device
- * @IO_ADDR_W:         [BOARDSPECIFIC] address to write the 8 I/O lines of the
- *                     flash device.
- * @read_byte:         [REPLACEABLE] read one byte from the chip
- * @read_word:         [REPLACEABLE] read one word from the chip
- * @write_byte:                [REPLACEABLE] write a single byte to the chip on the
- *                     low 8 I/O lines
- * @write_buf:         [REPLACEABLE] write data from the buffer to the chip
- * @read_buf:          [REPLACEABLE] read data from the chip into the buffer
+ * @legacy:            All legacy fields/hooks. If you develop a new driver,
+ *                     don't even try to use any of these fields/hooks, and if
+ *                     you're modifying an existing driver that is using those
+ *                     fields/hooks, you should consider reworking the driver
+ *                     avoid using them.
  * @select_chip:       [REPLACEABLE] select chip nr
- * @block_bad:         [REPLACEABLE] check if a block is bad, using OOB markers
- * @block_markbad:     [REPLACEABLE] mark a block bad
- * @cmd_ctrl:          [BOARDSPECIFIC] hardwarespecific function for controlling
- *                     ALE/CLE/nCE. Also used to write command and address
- * @dev_ready:         [BOARDSPECIFIC] hardwarespecific function for accessing
- *                     device ready/busy line. If set to NULL no access to
- *                     ready/busy is available and the ready/busy information
- *                     is read from the chip status register.
- * @cmdfunc:           [REPLACEABLE] hardwarespecific function for writing
- *                     commands to the chip.
- * @waitfunc:          [REPLACEABLE] hardwarespecific function for wait on
- *                     ready.
  * @exec_op:           controller specific method to execute NAND operations.
  *                     This method replaces ->cmdfunc(),
- *                     ->{read,write}_{buf,byte,word}(), ->dev_ready() and
- *                     ->waifunc().
+ *                     ->legacy.{read,write}_{buf,byte,word}(),
+ *                     ->legacy.dev_ready() and ->waifunc().
  * @setup_read_retry:  [FLASHSPECIFIC] flash (vendor) specific function for
  *                     setting the read-retry mode. Mostly needed for MLC NAND.
  * @ecc:               [BOARDSPECIFIC] ECC control structure
  * @buf_align:         minimum buffer alignment required by a platform
  * @dummy_controller:  dummy controller implementation for drivers that can
  *                     only control a single chip
- * @erase:             [REPLACEABLE] erase function
- * @chip_delay:                [BOARDSPECIFIC] chip dependent delay for transferring
- *                     data from array to read regs (tR).
  * @state:             [INTERN] the current state of the NAND device
  * @oob_poi:           "poison value buffer," used for laying out OOB data
  *                     before writing
@@ -1260,8 +1013,6 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
  * @blocks_per_die:    [INTERN] The number of PEBs in a die
  * @data_interface:    [INTERN] NAND interface timing information
  * @read_retries:      [INTERN] the number of read retry modes supported
- * @set_features:      [REPLACEABLE] set the NAND chip features
- * @get_features:      [REPLACEABLE] get the NAND chip features
  * @setup_data_interface: [OPTIONAL] setup the data interface and timing. If
  *                       chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this
  *                       means the configuration should not be applied but
@@ -1283,35 +1034,17 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
 
 struct nand_chip {
        struct mtd_info mtd;
-       void __iomem *IO_ADDR_R;
-       void __iomem *IO_ADDR_W;
 
-       uint8_t (*read_byte)(struct mtd_info *mtd);
-       u16 (*read_word)(struct mtd_info *mtd);
-       void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
-       void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
-       void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
-       void (*select_chip)(struct mtd_info *mtd, int chip);
-       int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
-       int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
-       void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
-       int (*dev_ready)(struct mtd_info *mtd);
-       void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
-                       int page_addr);
-       int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
+       struct nand_legacy legacy;
+
+       void (*select_chip)(struct nand_chip *chip, int cs);
        int (*exec_op)(struct nand_chip *chip,
                       const struct nand_operation *op,
                       bool check_only);
-       int (*erase)(struct mtd_info *mtd, int page);
-       int (*set_features)(struct mtd_info *mtd, struct nand_chip *chip,
-                           int feature_addr, uint8_t *subfeature_para);
-       int (*get_features)(struct mtd_info *mtd, struct nand_chip *chip,
-                           int feature_addr, uint8_t *subfeature_para);
-       int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
-       int (*setup_data_interface)(struct mtd_info *mtd, int chipnr,
+       int (*setup_read_retry)(struct nand_chip *chip, int retry_mode);
+       int (*setup_data_interface)(struct nand_chip *chip, int chipnr,
                                    const struct nand_data_interface *conf);
 
-       int chip_delay;
        unsigned int options;
        unsigned int bbt_options;
 
@@ -1419,27 +1152,6 @@ static inline void *nand_get_manufacturer_data(struct nand_chip *chip)
        return chip->manufacturer.priv;
 }
 
-/*
- * NAND Flash Manufacturer ID Codes
- */
-#define NAND_MFR_TOSHIBA       0x98
-#define NAND_MFR_ESMT          0xc8
-#define NAND_MFR_SAMSUNG       0xec
-#define NAND_MFR_FUJITSU       0x04
-#define NAND_MFR_NATIONAL      0x8f
-#define NAND_MFR_RENESAS       0x07
-#define NAND_MFR_STMICRO       0x20
-#define NAND_MFR_HYNIX         0xad
-#define NAND_MFR_MICRON                0x2c
-#define NAND_MFR_AMD           0x01
-#define NAND_MFR_MACRONIX      0xc2
-#define NAND_MFR_EON           0x92
-#define NAND_MFR_SANDISK       0x45
-#define NAND_MFR_INTEL         0x89
-#define NAND_MFR_ATO           0x9b
-#define NAND_MFR_WINBOND       0xef
-
-
 /*
  * A helper for defining older NAND chips where the second ID byte fully
  * defined the chip, including the geometry (chip size, eraseblock size, page
@@ -1519,114 +1231,7 @@ struct nand_flash_dev {
        int onfi_timing_mode_default;
 };
 
-/**
- * struct nand_manufacturer - NAND Flash Manufacturer structure
- * @name:      Manufacturer name
- * @id:                manufacturer ID code of device.
- * @ops:       manufacturer operations
-*/
-struct nand_manufacturer {
-       int id;
-       char *name;
-       const struct nand_manufacturer_ops *ops;
-};
-
-const struct nand_manufacturer *nand_get_manufacturer(u8 id);
-
-static inline const char *
-nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
-{
-       return manufacturer ? manufacturer->name : "Unknown";
-}
-
-extern struct nand_flash_dev nand_flash_ids[];
-
-extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
-extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
-extern const struct nand_manufacturer_ops hynix_nand_manuf_ops;
-extern const struct nand_manufacturer_ops micron_nand_manuf_ops;
-extern const struct nand_manufacturer_ops amd_nand_manuf_ops;
-extern const struct nand_manufacturer_ops macronix_nand_manuf_ops;
-
 int nand_create_bbt(struct nand_chip *chip);
-int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
-int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
-int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
-int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
-                   int allowbbt);
-
-/**
- * struct platform_nand_chip - chip level device structure
- * @nr_chips:          max. number of chips to scan for
- * @chip_offset:       chip number offset
- * @nr_partitions:     number of partitions pointed to by partitions (or zero)
- * @partitions:                mtd partition list
- * @chip_delay:                R/B delay value in us
- * @options:           Option flags, e.g. 16bit buswidth
- * @bbt_options:       BBT option flags, e.g. NAND_BBT_USE_FLASH
- * @part_probe_types:  NULL-terminated array of probe types
- */
-struct platform_nand_chip {
-       int nr_chips;
-       int chip_offset;
-       int nr_partitions;
-       struct mtd_partition *partitions;
-       int chip_delay;
-       unsigned int options;
-       unsigned int bbt_options;
-       const char **part_probe_types;
-};
-
-/* Keep gcc happy */
-struct platform_device;
-
-/**
- * struct platform_nand_ctrl - controller level device structure
- * @probe:             platform specific function to probe/setup hardware
- * @remove:            platform specific function to remove/teardown hardware
- * @dev_ready:         platform specific function to read ready/busy pin
- * @select_chip:       platform specific chip select function
- * @cmd_ctrl:          platform specific function for controlling
- *                     ALE/CLE/nCE. Also used to write command and address
- * @write_buf:         platform specific function for write buffer
- * @read_buf:          platform specific function for read buffer
- * @priv:              private data to transport driver specific settings
- *
- * All fields are optional and depend on the hardware driver requirements
- */
-struct platform_nand_ctrl {
-       int (*probe)(struct platform_device *pdev);
-       void (*remove)(struct platform_device *pdev);
-       int (*dev_ready)(struct mtd_info *mtd);
-       void (*select_chip)(struct mtd_info *mtd, int chip);
-       void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
-       void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
-       void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
-       void *priv;
-};
-
-/**
- * struct platform_nand_data - container structure for platform-specific data
- * @chip:              chip level chip structure
- * @ctrl:              controller level device structure
- */
-struct platform_nand_data {
-       struct platform_nand_chip chip;
-       struct platform_nand_ctrl ctrl;
-};
-
-/* return the supported asynchronous timing mode. */
-static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
-{
-       if (!chip->parameters.onfi)
-               return ONFI_TIMING_MODE_UNKNOWN;
-
-       return chip->parameters.onfi->async_timing_mode;
-}
-
-int onfi_fill_data_interface(struct nand_chip *chip,
-                            enum nand_data_interface_type type,
-                            int timing_mode);
 
 /*
  * Check if it is a SLC nand.
@@ -1658,9 +1263,6 @@ static inline int nand_opcode_8bits(unsigned int command)
        return 0;
 }
 
-/* get timing characteristics from ONFI timing mode. */
-const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
-
 int nand_check_erased_ecc_chunk(void *data, int datalen,
                                void *ecc, int ecclen,
                                void *extraoob, int extraooblen,
@@ -1670,37 +1272,22 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
                         const struct nand_ecc_caps *caps, int oobavail);
 
 /* Default write_oob implementation */
-int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
-
-/* Default write_oob syndrome implementation */
-int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-                           int page);
+int nand_write_oob_std(struct nand_chip *chip, int page);
 
 /* Default read_oob implementation */
-int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page);
+int nand_read_oob_std(struct nand_chip *chip, int page);
 
-/* Default read_oob syndrome implementation */
-int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-                          int page);
-
-/* Wrapper to use in order for controllers/vendors to GET/SET FEATURES */
-int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
-int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
 /* Stub used by drivers that do not support GET/SET FEATURES operations */
-int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
-                                 int addr, u8 *subfeature_param);
+int nand_get_set_features_notsupp(struct nand_chip *chip, int addr,
+                                 u8 *subfeature_param);
 
 /* Default read_page_raw implementation */
-int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                      uint8_t *buf, int oob_required, int page);
-int nand_read_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
-                              u8 *buf, int oob_required, int page);
+int nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required,
+                      int page);
 
 /* Default write_page_raw implementation */
-int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                       const uint8_t *buf, int oob_required, int page);
-int nand_write_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
-                               const u8 *buf, int oob_required, int page);
+int nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+                       int oob_required, int page);
 
 /* Reset and initialize a NAND device */
 int nand_reset(struct nand_chip *chip, int chipnr);
@@ -1710,7 +1297,6 @@ int nand_reset_op(struct nand_chip *chip);
 int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
                   unsigned int len);
 int nand_status_op(struct nand_chip *chip, u8 *status);
-int nand_exit_status_op(struct nand_chip *chip);
 int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock);
 int nand_read_page_op(struct nand_chip *chip, unsigned int page,
                      unsigned int offset_in_page, void *buf, unsigned int len);
@@ -1734,16 +1320,25 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
 int nand_write_data_op(struct nand_chip *chip, const void *buf,
                       unsigned int len, bool force_8bit);
 
+/* Scan and identify a NAND device */
+int nand_scan_with_ids(struct nand_chip *chip, unsigned int max_chips,
+                      struct nand_flash_dev *ids);
+
+static inline int nand_scan(struct nand_chip *chip, unsigned int max_chips)
+{
+       return nand_scan_with_ids(chip, max_chips, NULL);
+}
+
+/* Internal helper for board drivers which need to override command function */
+void nand_wait_ready(struct nand_chip *chip);
+
 /*
  * Free resources held by the NAND device, must be called on error after a
  * sucessful nand_scan().
  */
 void nand_cleanup(struct nand_chip *chip);
 /* Unregister the MTD device and calls nand_cleanup() */
-void nand_release(struct mtd_info *mtd);
-
-/* Default extended ID decoding function */
-void nand_decode_ext_id(struct nand_chip *chip);
+void nand_release(struct nand_chip *chip);
 
 /*
  * External helper for controller drivers that have to implement the WAITRDY
index c922e97f205a01b82a628d1d5a5d4f2c7e6c31a7..7f0c7303575e92a0f9029e6973c624c775776136 100644 (file)
@@ -238,6 +238,94 @@ enum spi_nor_option_flags {
        SNOR_F_BROKEN_RESET     = BIT(6),
 };
 
+/**
+ * struct spi_nor_erase_type - Structure to describe a SPI NOR erase type
+ * @size:              the size of the sector/block erased by the erase type.
+ *                     JEDEC JESD216B imposes erase sizes to be a power of 2.
+ * @size_shift:                @size is a power of 2, the shift is stored in
+ *                     @size_shift.
+ * @size_mask:         the size mask based on @size_shift.
+ * @opcode:            the SPI command op code to erase the sector/block.
+ * @idx:               Erase Type index as sorted in the Basic Flash Parameter
+ *                     Table. It will be used to synchronize the supported
+ *                     Erase Types with the ones identified in the SFDP
+ *                     optional tables.
+ */
+struct spi_nor_erase_type {
+       u32     size;
+       u32     size_shift;
+       u32     size_mask;
+       u8      opcode;
+       u8      idx;
+};
+
+/**
+ * struct spi_nor_erase_command - Used for non-uniform erases
+ * The structure is used to describe a list of erase commands to be executed
+ * once we validate that the erase can be performed. The elements in the list
+ * are run-length encoded.
+ * @list:              for inclusion into the list of erase commands.
+ * @count:             how many times the same erase command should be
+ *                     consecutively used.
+ * @size:              the size of the sector/block erased by the command.
+ * @opcode:            the SPI command op code to erase the sector/block.
+ */
+struct spi_nor_erase_command {
+       struct list_head        list;
+       u32                     count;
+       u32                     size;
+       u8                      opcode;
+};
+
+/**
+ * struct spi_nor_erase_region - Structure to describe a SPI NOR erase region
+ * @offset:            the offset in the data array of erase region start.
+ *                     LSB bits are used as a bitmask encoding flags to
+ *                     determine if this region is overlaid, if this region is
+ *                     the last in the SPI NOR flash memory and to indicate
+ *                     all the supported erase commands inside this region.
+ *                     The erase types are sorted in ascending order with the
+ *                     smallest Erase Type size being at BIT(0).
+ * @size:              the size of the region in bytes.
+ */
+struct spi_nor_erase_region {
+       u64             offset;
+       u64             size;
+};
+
+#define SNOR_ERASE_TYPE_MAX    4
+#define SNOR_ERASE_TYPE_MASK   GENMASK_ULL(SNOR_ERASE_TYPE_MAX - 1, 0)
+
+#define SNOR_LAST_REGION       BIT(4)
+#define SNOR_OVERLAID_REGION   BIT(5)
+
+#define SNOR_ERASE_FLAGS_MAX   6
+#define SNOR_ERASE_FLAGS_MASK  GENMASK_ULL(SNOR_ERASE_FLAGS_MAX - 1, 0)
+
+/**
+ * struct spi_nor_erase_map - Structure to describe the SPI NOR erase map
+ * @regions:           array of erase regions. The regions are consecutive in
+ *                     address space. Walking through the regions is done
+ *                     incrementally.
+ * @uniform_region:    a pre-allocated erase region for SPI NOR with a uniform
+ *                     sector size (legacy implementation).
+ * @erase_type:                an array of erase types shared by all the regions.
+ *                     The erase types are sorted in ascending order, with the
+ *                     smallest Erase Type size being the first member in the
+ *                     erase_type array.
+ * @uniform_erase_type:        bitmask encoding erase types that can erase the
+ *                     entire memory. This member is completed at init by
+ *                     uniform and non-uniform SPI NOR flash memories if they
+ *                     support at least one erase type that can erase the
+ *                     entire memory.
+ */
+struct spi_nor_erase_map {
+       struct spi_nor_erase_region     *regions;
+       struct spi_nor_erase_region     uniform_region;
+       struct spi_nor_erase_type       erase_type[SNOR_ERASE_TYPE_MAX];
+       u8                              uniform_erase_type;
+};
+
 /**
  * struct flash_info - Forward declaration of a structure used internally by
  *                    spi_nor_scan()
@@ -262,6 +350,7 @@ struct flash_info;
  * @write_proto:       the SPI protocol for write operations
  * @reg_proto          the SPI protocol for read_reg/write_reg/erase operations
  * @cmd_buf:           used by the write_reg
+ * @erase_map:         the erase map of the SPI NOR
  * @prepare:           [OPTIONAL] do some preparations for the
  *                     read/write/erase/lock/unlock operations
  * @unprepare:         [OPTIONAL] do some post work after the
@@ -297,6 +386,7 @@ struct spi_nor {
        bool                    sst_write_second;
        u32                     flags;
        u8                      cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+       struct spi_nor_erase_map        erase_map;
 
        int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
        void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
@@ -317,6 +407,35 @@ struct spi_nor {
        void *priv;
 };
 
+static u64 __maybe_unused
+spi_nor_region_is_last(const struct spi_nor_erase_region *region)
+{
+       return region->offset & SNOR_LAST_REGION;
+}
+
+static u64 __maybe_unused
+spi_nor_region_end(const struct spi_nor_erase_region *region)
+{
+       return (region->offset & ~SNOR_ERASE_FLAGS_MASK) + region->size;
+}
+
+static void __maybe_unused
+spi_nor_region_mark_end(struct spi_nor_erase_region *region)
+{
+       region->offset |= SNOR_LAST_REGION;
+}
+
+static void __maybe_unused
+spi_nor_region_mark_overlay(struct spi_nor_erase_region *region)
+{
+       region->offset |= SNOR_OVERLAID_REGION;
+}
+
+static bool __maybe_unused spi_nor_has_uniform_erase(const struct spi_nor *nor)
+{
+       return !!nor->erase_map.uniform_erase_type;
+}
+
 static inline void spi_nor_set_flash_node(struct spi_nor *nor,
                                          struct device_node *np)
 {