Merge tag 'v4.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux...
authorBoris Brezillon <boris.brezillon@bootlin.com>
Wed, 4 Apr 2018 20:13:35 +0000 (22:13 +0200)
committerBoris Brezillon <boris.brezillon@bootlin.com>
Wed, 4 Apr 2018 20:13:35 +0000 (22:13 +0200)
Backmerge v4.16-rc2 into mtd/next to resolve a conflict between Linus'
master branch and nand/for-4.17.

1  2 
MAINTAINERS
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/vf610_nfc.c

diff --cc MAINTAINERS
Simple merge
index 46b29d2,0000000..19a2b28
mode 100644,000000..100644
--- /dev/null
@@@ -1,537 -1,0 +1,537 @@@
-       depends on HAS_IOMEM
 +config MTD_NAND_ECC
 +      tristate
 +
 +config MTD_NAND_ECC_SMC
 +      bool "NAND ECC Smart Media byte order"
 +      depends on MTD_NAND_ECC
 +      default n
 +      help
 +        Software ECC according to the Smart Media Specification.
 +        The original Linux implementation had byte 0 and 1 swapped.
 +
 +
 +menuconfig MTD_NAND
 +      tristate "Raw/Parallel NAND Device Support"
 +      depends on MTD
 +      select MTD_NAND_ECC
 +      help
 +        This enables support for accessing all type of raw/parallel
 +        NAND flash devices. For further information see
 +        <http://www.linux-mtd.infradead.org/doc/nand.html>.
 +
 +if MTD_NAND
 +
 +config MTD_NAND_BCH
 +      tristate
 +      select BCH
 +      depends on MTD_NAND_ECC_BCH
 +      default MTD_NAND
 +
 +config MTD_NAND_ECC_BCH
 +      bool "Support software BCH ECC"
 +      default n
 +      help
 +        This enables support for software BCH error correction. Binary BCH
 +        codes are more powerful and cpu intensive than traditional Hamming
 +        ECC codes. They are used with NAND devices requiring more than 1 bit
 +        of error correction.
 +
 +config MTD_SM_COMMON
 +      tristate
 +      default n
 +
 +config MTD_NAND_DENALI
 +      tristate
 +
 +config MTD_NAND_DENALI_PCI
 +        tristate "Support Denali NAND controller on Intel Moorestown"
 +      select MTD_NAND_DENALI
 +      depends on HAS_DMA && PCI
 +        help
 +          Enable the driver for NAND flash on Intel Moorestown, using the
 +          Denali NAND controller core.
 +
 +config MTD_NAND_DENALI_DT
 +      tristate "Support Denali NAND controller as a DT device"
 +      select MTD_NAND_DENALI
 +      depends on HAS_DMA && HAVE_CLK && OF
 +      help
 +        Enable the driver for NAND flash on platforms using a Denali NAND
 +        controller as a DT device.
 +
 +config MTD_NAND_GPIO
 +      tristate "GPIO assisted NAND Flash driver"
 +      depends on GPIOLIB || COMPILE_TEST
 +      depends on HAS_IOMEM
 +      help
 +        This enables a NAND flash driver where control signals are
 +        connected to GPIO pins, and commands and data are communicated
 +        via a memory mapped interface.
 +
 +config MTD_NAND_AMS_DELTA
 +      tristate "NAND Flash device on Amstrad E3"
 +      depends on MACH_AMS_DELTA
 +      default y
 +      help
 +        Support for NAND flash on Amstrad E3 (Delta).
 +
 +config MTD_NAND_OMAP2
 +      tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
 +      depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
 +      help
 +          Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
 +        and Keystone platforms.
 +
 +config MTD_NAND_OMAP_BCH
 +      depends on MTD_NAND_OMAP2
 +      bool "Support hardware based BCH error correction"
 +      default n
 +      select BCH
 +      help
 +        This config enables the ELM hardware engine, which can be used to
 +        locate and correct errors when using BCH ECC scheme. This offloads
 +        the cpu from doing ECC error searching and correction. However some
 +        legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
 +        so this is optional for them.
 +
 +config MTD_NAND_OMAP_BCH_BUILD
 +      def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
 +
 +config MTD_NAND_RICOH
 +      tristate "Ricoh xD card reader"
 +      default n
 +      depends on PCI
 +      select MTD_SM_COMMON
 +      help
 +        Enable support for Ricoh R5C852 xD card reader
 +        You also need to enable ether
 +        NAND SSFDC (SmartMedia) read only translation layer' or new
 +        expermental, readwrite
 +        'SmartMedia/xD new translation layer'
 +
 +config MTD_NAND_AU1550
 +      tristate "Au1550/1200 NAND support"
 +      depends on MIPS_ALCHEMY
 +      help
 +        This enables the driver for the NAND flash controller on the
 +        AMD/Alchemy 1550 SOC.
 +
 +config MTD_NAND_S3C2410
 +      tristate "NAND Flash support for Samsung S3C SoCs"
 +      depends on ARCH_S3C24XX || ARCH_S3C64XX
 +      help
 +        This enables the NAND flash controller on the S3C24xx and S3C64xx
 +        SoCs
 +
 +        No board specific support is done by this driver, each board
 +        must advertise a platform_device for the driver to attach.
 +
 +config MTD_NAND_S3C2410_DEBUG
 +      bool "Samsung S3C NAND driver debug"
 +      depends on MTD_NAND_S3C2410
 +      help
 +        Enable debugging of the S3C NAND driver
 +
 +config MTD_NAND_NDFC
 +      tristate "NDFC NanD Flash Controller"
 +      depends on 4xx
 +      select MTD_NAND_ECC_SMC
 +      help
 +       NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
 +
 +config MTD_NAND_S3C2410_CLKSTOP
 +      bool "Samsung S3C NAND IDLE clock stop"
 +      depends on MTD_NAND_S3C2410
 +      default n
 +      help
 +        Stop the clock to the NAND controller when there is no chip
 +        selected to save power. This will mean there is a small delay
 +        when the is NAND chip selected or released, but will save
 +        approximately 5mA of power when there is nothing happening.
 +
 +config MTD_NAND_TANGO
 +      tristate "NAND Flash support for Tango chips"
 +      depends on ARCH_TANGO || COMPILE_TEST
 +      depends on HAS_DMA
 +      help
 +        Enables the NAND Flash controller on Tango chips.
 +
 +config MTD_NAND_DISKONCHIP
 +      tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
 +      depends on HAS_IOMEM
 +      select REED_SOLOMON
 +      select REED_SOLOMON_DEC16
 +      help
 +        This is a reimplementation of M-Systems DiskOnChip 2000,
 +        Millennium and Millennium Plus as a standard NAND device driver,
 +        as opposed to the earlier self-contained MTD device drivers.
 +        This should enable, among other things, proper JFFS2 operation on
 +        these devices.
 +
 +config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
 +        bool "Advanced detection options for DiskOnChip"
 +        depends on MTD_NAND_DISKONCHIP
 +        help
 +          This option allows you to specify nonstandard address at which to
 +          probe for a DiskOnChip, or to change the detection options.  You
 +          are unlikely to need any of this unless you are using LinuxBIOS.
 +          Say 'N'.
 +
 +config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
 +        hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
 +        depends on MTD_NAND_DISKONCHIP
 +        default "0"
 +        ---help---
 +        By default, the probe for DiskOnChip devices will look for a
 +        DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
 +        This option allows you to specify a single address at which to probe
 +        for the device, which is useful if you have other devices in that
 +        range which get upset when they are probed.
 +
 +        (Note that on PowerPC, the normal probe will only check at
 +        0xE4000000.)
 +
 +        Normally, you should leave this set to zero, to allow the probe at
 +        the normal addresses.
 +
 +config MTD_NAND_DISKONCHIP_PROBE_HIGH
 +        bool "Probe high addresses"
 +        depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
 +        help
 +          By default, the probe for DiskOnChip devices will look for a
 +          DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
 +          This option changes to make it probe between 0xFFFC8000 and
 +          0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
 +          useful to you.  Say 'N'.
 +
 +config MTD_NAND_DISKONCHIP_BBTWRITE
 +      bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
 +      depends on MTD_NAND_DISKONCHIP
 +      help
 +        On DiskOnChip devices shipped with the INFTL filesystem (Millennium
 +        and 2000 TSOP/Alon), Linux reserves some space at the end of the
 +        device for the Bad Block Table (BBT).  If you have existing INFTL
 +        data on your device (created by non-Linux tools such as M-Systems'
 +        DOS drivers), your data might overlap the area Linux wants to use for
 +        the BBT.  If this is a concern for you, leave this option disabled and
 +        Linux will not write BBT data into this area.
 +        The downside of leaving this option disabled is that if bad blocks
 +        are detected by Linux, they will not be recorded in the BBT, which
 +        could cause future problems.
 +        Once you enable this option, new filesystems (INFTL or others, created
 +        in Linux or other operating systems) will not use the reserved area.
 +        The only reason not to enable this option is to prevent damage to
 +        preexisting filesystems.
 +        Even if you leave this disabled, you can enable BBT writes at module
 +        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
 +
 +config MTD_NAND_CAFE
 +      tristate "NAND support for OLPC CAFÉ chip"
 +      depends on PCI
 +      select REED_SOLOMON
 +      select REED_SOLOMON_DEC16
 +      help
 +        Use NAND flash attached to the CAFÉ chip designed for the OLPC
 +        laptop.
 +
 +config MTD_NAND_CS553X
 +      tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
 +      depends on X86_32
 +      depends on !UML && HAS_IOMEM
 +      help
 +        The CS553x companion chips for the AMD Geode processor
 +        include NAND flash controllers with built-in hardware ECC
 +        capabilities; enabling this option will allow you to use
 +        these. The driver will check the MSRs to verify that the
 +        controller is enabled for NAND, and currently requires that
 +        the controller be in MMIO mode.
 +
 +        If you say "m", the module will be called cs553x_nand.
 +
 +config MTD_NAND_ATMEL
 +      tristate "Support for NAND Flash / SmartMedia on AT91"
 +      depends on ARCH_AT91
 +      select MFD_ATMEL_SMC
 +      help
 +        Enables support for NAND Flash / Smart Media Card interface
 +        on Atmel AT91 processors.
 +
 +config MTD_NAND_MARVELL
 +      tristate "NAND controller support on Marvell boards"
 +      depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
 +                 COMPILE_TEST
++      depends on HAS_IOMEM && HAS_DMA
 +      help
 +        This enables the NAND flash controller driver for Marvell boards,
 +        including:
 +        - PXA3xx processors (NFCv1)
 +        - 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2)
 +        - 64-bit Aramda platforms (7k, 8k) (NFCv2)
 +
 +config MTD_NAND_SLC_LPC32XX
 +      tristate "NXP LPC32xx SLC Controller"
 +      depends on ARCH_LPC32XX
 +      help
 +        Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
 +        chips) NAND controller. This is the default for the PHYTEC 3250
 +        reference board which contains a NAND256R3A2CZA6 chip.
 +
 +        Please check the actual NAND chip connected and its support
 +        by the SLC NAND controller.
 +
 +config MTD_NAND_MLC_LPC32XX
 +      tristate "NXP LPC32xx MLC Controller"
 +      depends on ARCH_LPC32XX
 +      help
 +        Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
 +        controller. This is the default for the WORK92105 controller
 +        board.
 +
 +        Please check the actual NAND chip connected and its support
 +        by the MLC NAND controller.
 +
 +config MTD_NAND_CM_X270
 +      tristate "Support for NAND Flash on CM-X270 modules"
 +      depends on MACH_ARMCORE
 +
 +config MTD_NAND_PASEMI
 +      tristate "NAND support for PA Semi PWRficient"
 +      depends on PPC_PASEMI
 +      help
 +        Enables support for NAND Flash interface on PA Semi PWRficient
 +        based boards
 +
 +config MTD_NAND_TMIO
 +      tristate "NAND Flash device on Toshiba Mobile IO Controller"
 +      depends on MFD_TMIO
 +      help
 +        Support for NAND flash connected to a Toshiba Mobile IO
 +        Controller in some PDAs, including the Sharp SL6000x.
 +
 +config MTD_NAND_NANDSIM
 +      tristate "Support for NAND Flash Simulator"
 +      help
 +        The simulator may simulate various NAND flash chips for the
 +        MTD nand layer.
 +
 +config MTD_NAND_GPMI_NAND
 +        tristate "GPMI NAND Flash Controller driver"
 +        depends on MTD_NAND && MXS_DMA
 +        help
 +       Enables NAND Flash support for IMX23, IMX28 or IMX6.
 +       The GPMI controller is very powerful, with the help of BCH
 +       module, it can do the hardware ECC. The GPMI supports several
 +       NAND flashs at the same time.
 +
 +config MTD_NAND_BRCMNAND
 +      tristate "Broadcom STB NAND controller"
 +      depends on ARM || ARM64 || MIPS
 +      help
 +        Enables the Broadcom NAND controller driver. The controller was
 +        originally designed for Set-Top Box but is used on various BCM7xxx,
 +        BCM3xxx, BCM63xxx, iProc/Cygnus and more.
 +
 +config MTD_NAND_BCM47XXNFLASH
 +      tristate "Support for NAND flash on BCM4706 BCMA bus"
 +      depends on BCMA_NFLASH
 +      help
 +        BCMA bus can have various flash memories attached, they are
 +        registered by bcma as platform devices. This enables driver for
 +        NAND flash memories. For now only BCM4706 is supported.
 +
 +config MTD_NAND_PLATFORM
 +      tristate "Support for generic platform NAND driver"
 +      depends on HAS_IOMEM
 +      help
 +        This implements a generic NAND driver for on-SOC platform
 +        devices. You will need to provide platform-specific functions
 +        via platform_data.
 +
 +config MTD_NAND_ORION
 +      tristate "NAND Flash support for Marvell Orion SoC"
 +      depends on PLAT_ORION
 +      help
 +        This enables the NAND flash controller on Orion machines.
 +
 +        No board specific support is done by this driver, each board
 +        must advertise a platform_device for the driver to attach.
 +
 +config MTD_NAND_OXNAS
 +      tristate "NAND Flash support for Oxford Semiconductor SoC"
 +      depends on ARCH_OXNAS || COMPILE_TEST
 +      depends on HAS_IOMEM
 +      help
 +        This enables the NAND flash controller on Oxford Semiconductor SoCs.
 +
 +config MTD_NAND_FSL_ELBC
 +      tristate "NAND support for Freescale eLBC controllers"
 +      depends on FSL_SOC
 +      select FSL_LBC
 +      help
 +        Various Freescale chips, including the 8313, include a NAND Flash
 +        Controller Module with built-in hardware ECC capabilities.
 +        Enabling this option will enable you to use this to control
 +        external NAND devices.
 +
 +config MTD_NAND_FSL_IFC
 +      tristate "NAND support for Freescale IFC controller"
 +      depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
 +      select FSL_IFC
 +      select MEMORY
 +      help
 +        Various Freescale chips e.g P1010, include a NAND Flash machine
 +        with built-in hardware ECC capabilities.
 +        Enabling this option will enable you to use this to control
 +        external NAND devices.
 +
 +config MTD_NAND_FSL_UPM
 +      tristate "Support for NAND on Freescale UPM"
 +      depends on PPC_83xx || PPC_85xx
 +      select FSL_LBC
 +      help
 +        Enables support for NAND Flash chips wired onto Freescale PowerPC
 +        processor localbus with User-Programmable Machine support.
 +
 +config MTD_NAND_MPC5121_NFC
 +      tristate "MPC5121 built-in NAND Flash Controller support"
 +      depends on PPC_MPC512x
 +      help
 +        This enables the driver for the NAND flash controller on the
 +        MPC5121 SoC.
 +
 +config MTD_NAND_VF610_NFC
 +      tristate "Support for Freescale NFC for VF610/MPC5125"
 +      depends on (SOC_VF610 || COMPILE_TEST)
 +      depends on HAS_IOMEM
 +      help
 +        Enables support for NAND Flash Controller on some Freescale
 +        processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
 +        The driver supports a maximum 2k page size. With 2k pages and
 +        64 bytes or more of OOB, hardware ECC with up to 32-bit error
 +        correction is supported. Hardware ECC is only enabled through
 +        device tree.
 +
 +config MTD_NAND_MXC
 +      tristate "MXC NAND support"
 +      depends on ARCH_MXC
 +      help
 +        This enables the driver for the NAND flash controller on the
 +        MXC processors.
 +
 +config MTD_NAND_SH_FLCTL
 +      tristate "Support for NAND on Renesas SuperH FLCTL"
 +      depends on SUPERH || COMPILE_TEST
 +      depends on HAS_IOMEM
 +      depends on HAS_DMA
 +      help
 +        Several Renesas SuperH CPU has FLCTL. This option enables support
 +        for NAND Flash using FLCTL.
 +
 +config MTD_NAND_DAVINCI
 +        tristate "Support NAND on DaVinci/Keystone SoC"
 +        depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
 +        help
 +        Enable the driver for NAND flash chips on Texas Instruments
 +        DaVinci/Keystone processors.
 +
 +config MTD_NAND_TXX9NDFMC
 +      tristate "NAND Flash support for TXx9 SoC"
 +      depends on SOC_TX4938 || SOC_TX4939
 +      help
 +        This enables the NAND flash controller on the TXx9 SoCs.
 +
 +config MTD_NAND_SOCRATES
 +      tristate "Support for NAND on Socrates board"
 +      depends on SOCRATES
 +      help
 +        Enables support for NAND Flash chips wired onto Socrates board.
 +
 +config MTD_NAND_NUC900
 +      tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
 +      depends on ARCH_W90X900
 +      help
 +        This enables the driver for the NAND Flash on evaluation board based
 +        on w90p910 / NUC9xx.
 +
 +config MTD_NAND_JZ4740
 +      tristate "Support for JZ4740 SoC NAND controller"
 +      depends on MACH_JZ4740
 +      help
 +              Enables support for NAND Flash on JZ4740 SoC based boards.
 +
 +config MTD_NAND_JZ4780
 +      tristate "Support for NAND on JZ4780 SoC"
 +      depends on MACH_JZ4780 && JZ4780_NEMC
 +      help
 +        Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
 +        based boards, using the BCH controller for hardware error correction.
 +
 +config MTD_NAND_FSMC
 +      tristate "Support for NAND on ST Micros FSMC"
 +      depends on OF
 +      depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
 +      help
 +        Enables support for NAND Flash chips on the ST Microelectronics
 +        Flexible Static Memory Controller (FSMC)
 +
 +config MTD_NAND_XWAY
 +      bool "Support for NAND on Lantiq XWAY SoC"
 +      depends on LANTIQ && SOC_TYPE_XWAY
 +      help
 +        Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
 +        to the External Bus Unit (EBU).
 +
 +config MTD_NAND_SUNXI
 +      tristate "Support for NAND on Allwinner SoCs"
 +      depends on ARCH_SUNXI
 +      help
 +        Enables support for NAND Flash chips on Allwinner SoCs.
 +
 +config MTD_NAND_HISI504
 +      tristate "Support for NAND controller on Hisilicon SoC Hip04"
 +      depends on ARCH_HISI || COMPILE_TEST
 +      depends on HAS_DMA
 +      help
 +        Enables support for NAND controller on Hisilicon SoC Hip04.
 +
 +config MTD_NAND_QCOM
 +      tristate "Support for NAND on QCOM SoCs"
 +      depends on ARCH_QCOM
 +      help
 +        Enables support for NAND flash chips on SoCs containing the EBI2 NAND
 +        controller. This controller is found on IPQ806x SoC.
 +
 +config MTD_NAND_MTK
 +      tristate "Support for NAND controller on MTK SoCs"
 +      depends on ARCH_MEDIATEK || COMPILE_TEST
 +      depends on HAS_DMA
 +      help
 +        Enables support for NAND controller on MTK SoCs.
 +        This controller is found on mt27xx, mt81xx, mt65xx SoCs.
 +
 +endif # MTD_NAND
index 7872a9e,0000000..d5a22fc
mode 100644,000000..100644
--- /dev/null
@@@ -1,964 -1,0 +1,962 @@@
-               /*
-                * mtd->ecclayout is not specified here because we're using the
-                * default large page ECC layout defined in NAND core.
-                */
 +/*
 + * Copyright 2009-2015 Freescale Semiconductor, Inc. and others
 + *
 + * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver.
 + * Jason ported to M54418TWR and MVFA5 (VF610).
 + * Authors: Stefan Agner <stefan.agner@toradex.com>
 + *          Bill Pringlemeir <bpringlemeir@nbsps.com>
 + *          Shaohui Xie <b21989@freescale.com>
 + *          Jason Jin <Jason.jin@freescale.com>
 + *
 + * Based on original driver mpc5121_nfc.c.
 + *
 + * This 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.
 + *
 + * Limitations:
 + * - Untested on MPC5125 and M54418.
 + * - DMA and pipelining not used.
 + * - 2K pages or less.
 + * - HW ECC: Only 2K page with 64+ OOB.
 + * - HW ECC: Only 24 and 32-bit error correction implemented.
 + */
 +
 +#include <linux/module.h>
 +#include <linux/bitops.h>
 +#include <linux/clk.h>
 +#include <linux/delay.h>
 +#include <linux/init.h>
 +#include <linux/interrupt.h>
 +#include <linux/io.h>
 +#include <linux/mtd/mtd.h>
 +#include <linux/mtd/rawnand.h>
 +#include <linux/mtd/partitions.h>
 +#include <linux/of_device.h>
 +#include <linux/platform_device.h>
 +#include <linux/slab.h>
 +#include <linux/swab.h>
 +
 +#define       DRV_NAME                "vf610_nfc"
 +
 +/* Register Offsets */
 +#define NFC_FLASH_CMD1                        0x3F00
 +#define NFC_FLASH_CMD2                        0x3F04
 +#define NFC_COL_ADDR                  0x3F08
 +#define NFC_ROW_ADDR                  0x3F0c
 +#define NFC_ROW_ADDR_INC              0x3F14
 +#define NFC_FLASH_STATUS1             0x3F18
 +#define NFC_FLASH_STATUS2             0x3F1c
 +#define NFC_CACHE_SWAP                        0x3F28
 +#define NFC_SECTOR_SIZE                       0x3F2c
 +#define NFC_FLASH_CONFIG              0x3F30
 +#define NFC_IRQ_STATUS                        0x3F38
 +
 +/* Addresses for NFC MAIN RAM BUFFER areas */
 +#define NFC_MAIN_AREA(n)              ((n) *  0x1000)
 +
 +#define PAGE_2K                               0x0800
 +#define OOB_64                                0x0040
 +#define OOB_MAX                               0x0100
 +
 +/* NFC_CMD2[CODE] controller cycle bit masks */
 +#define COMMAND_CMD_BYTE1             BIT(14)
 +#define COMMAND_CAR_BYTE1             BIT(13)
 +#define COMMAND_CAR_BYTE2             BIT(12)
 +#define COMMAND_RAR_BYTE1             BIT(11)
 +#define COMMAND_RAR_BYTE2             BIT(10)
 +#define COMMAND_RAR_BYTE3             BIT(9)
 +#define COMMAND_NADDR_BYTES(x)                GENMASK(13, 13 - (x) + 1)
 +#define COMMAND_WRITE_DATA            BIT(8)
 +#define COMMAND_CMD_BYTE2             BIT(7)
 +#define COMMAND_RB_HANDSHAKE          BIT(6)
 +#define COMMAND_READ_DATA             BIT(5)
 +#define COMMAND_CMD_BYTE3             BIT(4)
 +#define COMMAND_READ_STATUS           BIT(3)
 +#define COMMAND_READ_ID                       BIT(2)
 +
 +/* NFC ECC mode define */
 +#define ECC_BYPASS                    0
 +#define ECC_45_BYTE                   6
 +#define ECC_60_BYTE                   7
 +
 +/*** Register Mask and bit definitions */
 +
 +/* NFC_FLASH_CMD1 Field */
 +#define CMD_BYTE2_MASK                                0xFF000000
 +#define CMD_BYTE2_SHIFT                               24
 +
 +/* NFC_FLASH_CM2 Field */
 +#define CMD_BYTE1_MASK                                0xFF000000
 +#define CMD_BYTE1_SHIFT                               24
 +#define CMD_CODE_MASK                         0x00FFFF00
 +#define CMD_CODE_SHIFT                                8
 +#define BUFNO_MASK                            0x00000006
 +#define BUFNO_SHIFT                           1
 +#define START_BIT                             BIT(0)
 +
 +/* NFC_COL_ADDR Field */
 +#define COL_ADDR_MASK                         0x0000FFFF
 +#define COL_ADDR_SHIFT                                0
 +#define COL_ADDR(pos, val)                    (((val) & 0xFF) << (8 * (pos)))
 +
 +/* NFC_ROW_ADDR Field */
 +#define ROW_ADDR_MASK                         0x00FFFFFF
 +#define ROW_ADDR_SHIFT                                0
 +#define ROW_ADDR(pos, val)                    (((val) & 0xFF) << (8 * (pos)))
 +
 +#define ROW_ADDR_CHIP_SEL_RB_MASK             0xF0000000
 +#define ROW_ADDR_CHIP_SEL_RB_SHIFT            28
 +#define ROW_ADDR_CHIP_SEL_MASK                        0x0F000000
 +#define ROW_ADDR_CHIP_SEL_SHIFT                       24
 +
 +/* NFC_FLASH_STATUS2 Field */
 +#define STATUS_BYTE1_MASK                     0x000000FF
 +
 +/* NFC_FLASH_CONFIG Field */
 +#define CONFIG_ECC_SRAM_ADDR_MASK             0x7FC00000
 +#define CONFIG_ECC_SRAM_ADDR_SHIFT            22
 +#define CONFIG_ECC_SRAM_REQ_BIT                       BIT(21)
 +#define CONFIG_DMA_REQ_BIT                    BIT(20)
 +#define CONFIG_ECC_MODE_MASK                  0x000E0000
 +#define CONFIG_ECC_MODE_SHIFT                 17
 +#define CONFIG_FAST_FLASH_BIT                 BIT(16)
 +#define CONFIG_16BIT                          BIT(7)
 +#define CONFIG_BOOT_MODE_BIT                  BIT(6)
 +#define CONFIG_ADDR_AUTO_INCR_BIT             BIT(5)
 +#define CONFIG_BUFNO_AUTO_INCR_BIT            BIT(4)
 +#define CONFIG_PAGE_CNT_MASK                  0xF
 +#define CONFIG_PAGE_CNT_SHIFT                 0
 +
 +/* NFC_IRQ_STATUS Field */
 +#define IDLE_IRQ_BIT                          BIT(29)
 +#define IDLE_EN_BIT                           BIT(20)
 +#define CMD_DONE_CLEAR_BIT                    BIT(18)
 +#define IDLE_CLEAR_BIT                                BIT(17)
 +
 +/*
 + * ECC status - seems to consume 8 bytes (double word). The documented
 + * status byte is located in the lowest byte of the second word (which is
 + * the 4th or 7th byte depending on endianness).
 + * Calculate an offset to store the ECC status at the end of the buffer.
 + */
 +#define ECC_SRAM_ADDR         (PAGE_2K + OOB_MAX - 8)
 +
 +#define ECC_STATUS            0x4
 +#define ECC_STATUS_MASK               0x80
 +#define ECC_STATUS_ERR_COUNT  0x3F
 +
 +enum vf610_nfc_variant {
 +      NFC_VFC610 = 1,
 +};
 +
 +struct vf610_nfc {
 +      struct nand_chip chip;
 +      struct device *dev;
 +      void __iomem *regs;
 +      struct completion cmd_done;
 +      /* Status and ID are in alternate locations. */
 +      enum vf610_nfc_variant variant;
 +      struct clk *clk;
 +      /*
 +       * Indicate that user data is accessed (full page/oob). This is
 +       * useful to indicate the driver whether to swap byte endianness.
 +       * See comments in vf610_nfc_rd_from_sram/vf610_nfc_wr_to_sram.
 +       */
 +      bool data_access;
 +      u32 ecc_mode;
 +};
 +
 +static inline struct vf610_nfc *mtd_to_nfc(struct mtd_info *mtd)
 +{
 +      return container_of(mtd_to_nand(mtd), struct vf610_nfc, chip);
 +}
 +
 +static inline struct vf610_nfc *chip_to_nfc(struct nand_chip *chip)
 +{
 +      return container_of(chip, struct vf610_nfc, chip);
 +}
 +
 +static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
 +{
 +      return readl(nfc->regs + reg);
 +}
 +
 +static inline void vf610_nfc_write(struct vf610_nfc *nfc, uint reg, u32 val)
 +{
 +      writel(val, nfc->regs + reg);
 +}
 +
 +static inline void vf610_nfc_set(struct vf610_nfc *nfc, uint reg, u32 bits)
 +{
 +      vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) | bits);
 +}
 +
 +static inline void vf610_nfc_clear(struct vf610_nfc *nfc, uint reg, u32 bits)
 +{
 +      vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) & ~bits);
 +}
 +
 +static inline void vf610_nfc_set_field(struct vf610_nfc *nfc, u32 reg,
 +                                     u32 mask, u32 shift, u32 val)
 +{
 +      vf610_nfc_write(nfc, reg,
 +                      (vf610_nfc_read(nfc, reg) & (~mask)) | val << shift);
 +}
 +
 +static inline bool vf610_nfc_kernel_is_little_endian(void)
 +{
 +#ifdef __LITTLE_ENDIAN
 +      return true;
 +#else
 +      return false;
 +#endif
 +}
 +
 +/**
 + * Read accessor for internal SRAM buffer
 + * @dst: destination address in regular memory
 + * @src: source address in SRAM buffer
 + * @len: bytes to copy
 + * @fix_endian: Fix endianness if required
 + *
 + * Use this accessor for the internal SRAM buffers. On the ARM
 + * Freescale Vybrid SoC it's known that the driver can treat
 + * the SRAM buffer as if it's memory. Other platform might need
 + * to treat the buffers differently.
 + *
 + * The controller stores bytes from the NAND chip internally in big
 + * endianness. On little endian platforms such as Vybrid this leads
 + * to reversed byte order.
 + * For performance reason (and earlier probably due to unawareness)
 + * the driver avoids correcting endianness where it has control over
 + * write and read side (e.g. page wise data access).
 + */
 +static inline void vf610_nfc_rd_from_sram(void *dst, const void __iomem *src,
 +                                        size_t len, bool fix_endian)
 +{
 +      if (vf610_nfc_kernel_is_little_endian() && fix_endian) {
 +              unsigned int i;
 +
 +              for (i = 0; i < len; i += 4) {
 +                      u32 val = swab32(__raw_readl(src + i));
 +
 +                      memcpy(dst + i, &val, min(sizeof(val), len - i));
 +              }
 +      } else {
 +              memcpy_fromio(dst, src, len);
 +      }
 +}
 +
 +/**
 + * Write accessor for internal SRAM buffer
 + * @dst: destination address in SRAM buffer
 + * @src: source address in regular memory
 + * @len: bytes to copy
 + * @fix_endian: Fix endianness if required
 + *
 + * Use this accessor for the internal SRAM buffers. On the ARM
 + * Freescale Vybrid SoC it's known that the driver can treat
 + * the SRAM buffer as if it's memory. Other platform might need
 + * to treat the buffers differently.
 + *
 + * The controller stores bytes from the NAND chip internally in big
 + * endianness. On little endian platforms such as Vybrid this leads
 + * to reversed byte order.
 + * For performance reason (and earlier probably due to unawareness)
 + * the driver avoids correcting endianness where it has control over
 + * write and read side (e.g. page wise data access).
 + */
 +static inline void vf610_nfc_wr_to_sram(void __iomem *dst, const void *src,
 +                                      size_t len, bool fix_endian)
 +{
 +      if (vf610_nfc_kernel_is_little_endian() && fix_endian) {
 +              unsigned int i;
 +
 +              for (i = 0; i < len; i += 4) {
 +                      u32 val;
 +
 +                      memcpy(&val, src + i, min(sizeof(val), len - i));
 +                      __raw_writel(swab32(val), dst + i);
 +              }
 +      } else {
 +              memcpy_toio(dst, src, len);
 +      }
 +}
 +
 +/* Clear flags for upcoming command */
 +static inline void vf610_nfc_clear_status(struct vf610_nfc *nfc)
 +{
 +      u32 tmp = vf610_nfc_read(nfc, NFC_IRQ_STATUS);
 +
 +      tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT;
 +      vf610_nfc_write(nfc, NFC_IRQ_STATUS, tmp);
 +}
 +
 +static void vf610_nfc_done(struct vf610_nfc *nfc)
 +{
 +      unsigned long timeout = msecs_to_jiffies(100);
 +
 +      /*
 +       * Barrier is needed after this write. This write need
 +       * to be done before reading the next register the first
 +       * time.
 +       * vf610_nfc_set implicates such a barrier by using writel
 +       * to write to the register.
 +       */
 +      vf610_nfc_set(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
 +      vf610_nfc_set(nfc, NFC_FLASH_CMD2, START_BIT);
 +
 +      if (!wait_for_completion_timeout(&nfc->cmd_done, timeout))
 +              dev_warn(nfc->dev, "Timeout while waiting for BUSY.\n");
 +
 +      vf610_nfc_clear_status(nfc);
 +}
 +
 +static irqreturn_t vf610_nfc_irq(int irq, void *data)
 +{
 +      struct mtd_info *mtd = data;
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +
 +      vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT);
 +      complete(&nfc->cmd_done);
 +
 +      return IRQ_HANDLED;
 +}
 +
 +static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode)
 +{
 +      vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
 +                          CONFIG_ECC_MODE_MASK,
 +                          CONFIG_ECC_MODE_SHIFT, ecc_mode);
 +}
 +
 +static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size)
 +{
 +      vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size);
 +}
 +
 +static inline void vf610_nfc_run(struct vf610_nfc *nfc, u32 col, u32 row,
 +                               u32 cmd1, u32 cmd2, u32 trfr_sz)
 +{
 +      vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK,
 +                          COL_ADDR_SHIFT, col);
 +
 +      vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK,
 +                          ROW_ADDR_SHIFT, row);
 +
 +      vf610_nfc_write(nfc, NFC_SECTOR_SIZE, trfr_sz);
 +      vf610_nfc_write(nfc, NFC_FLASH_CMD1, cmd1);
 +      vf610_nfc_write(nfc, NFC_FLASH_CMD2, cmd2);
 +
 +      dev_dbg(nfc->dev,
 +              "col 0x%04x, row 0x%08x, cmd1 0x%08x, cmd2 0x%08x, len %d\n",
 +              col, row, cmd1, cmd2, trfr_sz);
 +
 +      vf610_nfc_done(nfc);
 +}
 +
 +static inline const struct nand_op_instr *
 +vf610_get_next_instr(const struct nand_subop *subop, int *op_id)
 +{
 +      if (*op_id + 1 >= subop->ninstrs)
 +              return NULL;
 +
 +      (*op_id)++;
 +
 +      return &subop->instrs[*op_id];
 +}
 +
 +static int vf610_nfc_cmd(struct nand_chip *chip,
 +                       const struct nand_subop *subop)
 +{
 +      const struct nand_op_instr *instr;
 +      struct vf610_nfc *nfc = chip_to_nfc(chip);
 +      int op_id = -1, trfr_sz = 0, offset;
 +      u32 col = 0, row = 0, cmd1 = 0, cmd2 = 0, code = 0;
 +      bool force8bit = false;
 +
 +      /*
 +       * Some ops are optional, but the hardware requires the operations
 +       * to be in this exact order.
 +       * The op parser enforces the order and makes sure that there isn't
 +       * a read and write element in a single operation.
 +       */
 +      instr = vf610_get_next_instr(subop, &op_id);
 +      if (!instr)
 +              return -EINVAL;
 +
 +      if (instr && instr->type == NAND_OP_CMD_INSTR) {
 +              cmd2 |= instr->ctx.cmd.opcode << CMD_BYTE1_SHIFT;
 +              code |= COMMAND_CMD_BYTE1;
 +
 +              instr = vf610_get_next_instr(subop, &op_id);
 +      }
 +
 +      if (instr && instr->type == NAND_OP_ADDR_INSTR) {
 +              int naddrs = nand_subop_get_num_addr_cyc(subop, op_id);
 +              int i = nand_subop_get_addr_start_off(subop, op_id);
 +
 +              for (; i < naddrs; i++) {
 +                      u8 val = instr->ctx.addr.addrs[i];
 +
 +                      if (i < 2)
 +                              col |= COL_ADDR(i, val);
 +                      else
 +                              row |= ROW_ADDR(i - 2, val);
 +              }
 +              code |= COMMAND_NADDR_BYTES(naddrs);
 +
 +              instr = vf610_get_next_instr(subop, &op_id);
 +      }
 +
 +      if (instr && instr->type == NAND_OP_DATA_OUT_INSTR) {
 +              trfr_sz = nand_subop_get_data_len(subop, op_id);
 +              offset = nand_subop_get_data_start_off(subop, op_id);
 +              force8bit = instr->ctx.data.force_8bit;
 +
 +              /*
 +               * Don't fix endianness on page access for historical reasons.
 +               * See comment in vf610_nfc_wr_to_sram
 +               */
 +              vf610_nfc_wr_to_sram(nfc->regs + NFC_MAIN_AREA(0) + offset,
 +                                   instr->ctx.data.buf.out + offset,
 +                                   trfr_sz, !nfc->data_access);
 +              code |= COMMAND_WRITE_DATA;
 +
 +              instr = vf610_get_next_instr(subop, &op_id);
 +      }
 +
 +      if (instr && instr->type == NAND_OP_CMD_INSTR) {
 +              cmd1 |= instr->ctx.cmd.opcode << CMD_BYTE2_SHIFT;
 +              code |= COMMAND_CMD_BYTE2;
 +
 +              instr = vf610_get_next_instr(subop, &op_id);
 +      }
 +
 +      if (instr && instr->type == NAND_OP_WAITRDY_INSTR) {
 +              code |= COMMAND_RB_HANDSHAKE;
 +
 +              instr = vf610_get_next_instr(subop, &op_id);
 +      }
 +
 +      if (instr && instr->type == NAND_OP_DATA_IN_INSTR) {
 +              trfr_sz = nand_subop_get_data_len(subop, op_id);
 +              offset = nand_subop_get_data_start_off(subop, op_id);
 +              force8bit = instr->ctx.data.force_8bit;
 +
 +              code |= COMMAND_READ_DATA;
 +      }
 +
 +      if (force8bit && (chip->options & NAND_BUSWIDTH_16))
 +              vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
 +
 +      cmd2 |= code << CMD_CODE_SHIFT;
 +
 +      vf610_nfc_run(nfc, col, row, cmd1, cmd2, trfr_sz);
 +
 +      if (instr && instr->type == NAND_OP_DATA_IN_INSTR) {
 +              /*
 +               * Don't fix endianness on page access for historical reasons.
 +               * See comment in vf610_nfc_rd_from_sram
 +               */
 +              vf610_nfc_rd_from_sram(instr->ctx.data.buf.in + offset,
 +                                     nfc->regs + NFC_MAIN_AREA(0) + offset,
 +                                     trfr_sz, !nfc->data_access);
 +      }
 +
 +      if (force8bit && (chip->options & NAND_BUSWIDTH_16))
 +              vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
 +
 +      return 0;
 +}
 +
 +static const struct nand_op_parser vf610_nfc_op_parser = NAND_OP_PARSER(
 +      NAND_OP_PARSER_PATTERN(vf610_nfc_cmd,
 +              NAND_OP_PARSER_PAT_CMD_ELEM(true),
 +              NAND_OP_PARSER_PAT_ADDR_ELEM(true, 5),
 +              NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, PAGE_2K + OOB_MAX),
 +              NAND_OP_PARSER_PAT_CMD_ELEM(true),
 +              NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
 +      NAND_OP_PARSER_PATTERN(vf610_nfc_cmd,
 +              NAND_OP_PARSER_PAT_CMD_ELEM(true),
 +              NAND_OP_PARSER_PAT_ADDR_ELEM(true, 5),
 +              NAND_OP_PARSER_PAT_CMD_ELEM(true),
 +              NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
 +              NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, PAGE_2K + OOB_MAX)),
 +      );
 +
 +static int vf610_nfc_exec_op(struct nand_chip *chip,
 +                           const struct nand_operation *op,
 +                           bool check_only)
 +{
 +      return nand_op_parser_exec_op(chip, &vf610_nfc_op_parser, op,
 +                                    check_only);
 +}
 +
 +/*
 + * 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)
 +{
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +      u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
 +
 +      /* Vybrid only (MPC5125 would have full RB and four CS) */
 +      if (nfc->variant != NFC_VFC610)
 +              return;
 +
 +      tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
 +
 +      if (chip >= 0) {
 +              tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
 +              tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
 +      }
 +
 +      vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
 +}
 +
 +static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat,
 +                                       uint8_t *oob, int page)
 +{
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +      u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
 +      u8 ecc_status;
 +      u8 ecc_count;
 +      int flips_threshold = nfc->chip.ecc.strength / 2;
 +
 +      ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff;
 +      ecc_count = ecc_status & ECC_STATUS_ERR_COUNT;
 +
 +      if (!(ecc_status & ECC_STATUS_MASK))
 +              return ecc_count;
 +
 +      nfc->data_access = true;
 +      nand_read_oob_op(&nfc->chip, page, 0, oob, mtd->oobsize);
 +      nfc->data_access = false;
 +
 +      /*
 +       * On an erased page, bit count (including OOB) should be zero or
 +       * at least less then half of the ECC strength.
 +       */
 +      return nand_check_erased_ecc_chunk(dat, nfc->chip.ecc.size, oob,
 +                                         mtd->oobsize, NULL, 0,
 +                                         flips_threshold);
 +}
 +
 +static void vf610_nfc_fill_row(struct nand_chip *chip, int page, u32 *code,
 +                             u32 *row)
 +{
 +      *row = ROW_ADDR(0, page & 0xff) | ROW_ADDR(1, page >> 8);
 +      *code |= COMMAND_RAR_BYTE1 | COMMAND_RAR_BYTE2;
 +
 +      if (chip->options & NAND_ROW_ADDR_3) {
 +              *row |= ROW_ADDR(2, page >> 16);
 +              *code |= COMMAND_RAR_BYTE3;
 +      }
 +}
 +
 +static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 +                              uint8_t *buf, int oob_required, int page)
 +{
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +      int trfr_sz = mtd->writesize + mtd->oobsize;
 +      u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
 +      int stat;
 +
 +      cmd2 |= NAND_CMD_READ0 << CMD_BYTE1_SHIFT;
 +      code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2;
 +
 +      vf610_nfc_fill_row(chip, page, &code, &row);
 +
 +      cmd1 |= NAND_CMD_READSTART << CMD_BYTE2_SHIFT;
 +      code |= COMMAND_CMD_BYTE2 | COMMAND_RB_HANDSHAKE | COMMAND_READ_DATA;
 +
 +      cmd2 |= code << CMD_CODE_SHIFT;
 +
 +      vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
 +      vf610_nfc_run(nfc, 0, row, cmd1, cmd2, trfr_sz);
 +      vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
 +
 +      /*
 +       * Don't fix endianness on page access for historical reasons.
 +       * See comment in vf610_nfc_rd_from_sram
 +       */
 +      vf610_nfc_rd_from_sram(buf, nfc->regs + NFC_MAIN_AREA(0),
 +                             mtd->writesize, false);
 +      if (oob_required)
 +              vf610_nfc_rd_from_sram(chip->oob_poi,
 +                                     nfc->regs + NFC_MAIN_AREA(0) +
 +                                                 mtd->writesize,
 +                                     mtd->oobsize, false);
 +
 +      stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page);
 +
 +      if (stat < 0) {
 +              mtd->ecc_stats.failed++;
 +              return 0;
 +      } else {
 +              mtd->ecc_stats.corrected += stat;
 +              return stat;
 +      }
 +}
 +
 +static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 +                              const uint8_t *buf, int oob_required, int page)
 +{
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +      int trfr_sz = mtd->writesize + mtd->oobsize;
 +      u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
 +      u8 status;
 +      int ret;
 +
 +      cmd2 |= NAND_CMD_SEQIN << CMD_BYTE1_SHIFT;
 +      code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2;
 +
 +      vf610_nfc_fill_row(chip, page, &code, &row);
 +
 +      cmd1 |= NAND_CMD_PAGEPROG << CMD_BYTE2_SHIFT;
 +      code |= COMMAND_CMD_BYTE2 | COMMAND_WRITE_DATA;
 +
 +      /*
 +       * Don't fix endianness on page access for historical reasons.
 +       * See comment in vf610_nfc_wr_to_sram
 +       */
 +      vf610_nfc_wr_to_sram(nfc->regs + NFC_MAIN_AREA(0), buf,
 +                           mtd->writesize, false);
 +
 +      code |= COMMAND_RB_HANDSHAKE;
 +      cmd2 |= code << CMD_CODE_SHIFT;
 +
 +      vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
 +      vf610_nfc_run(nfc, 0, row, cmd1, cmd2, trfr_sz);
 +      vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
 +
 +      ret = nand_status_op(chip, &status);
 +      if (ret)
 +              return ret;
 +
 +      if (status & NAND_STATUS_FAIL)
 +              return -EIO;
 +
 +      return 0;
 +}
 +
 +static int vf610_nfc_read_page_raw(struct mtd_info *mtd,
 +                                 struct nand_chip *chip, u8 *buf,
 +                                 int oob_required, int page)
 +{
 +      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);
 +      nfc->data_access = false;
 +
 +      return ret;
 +}
 +
 +static int vf610_nfc_write_page_raw(struct mtd_info *mtd,
 +                                  struct nand_chip *chip, const u8 *buf,
 +                                  int oob_required, int page)
 +{
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +      int ret;
 +
 +      nfc->data_access = true;
 +      ret = nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
 +      if (!ret && oob_required)
 +              ret = nand_write_data_op(chip, chip->oob_poi, mtd->oobsize,
 +                                       false);
 +      nfc->data_access = false;
 +
 +      if (ret)
 +              return ret;
 +
 +      return nand_prog_page_end_op(chip);
 +}
 +
 +static int vf610_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
 +                            int page)
 +{
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +      int ret;
 +
 +      nfc->data_access = true;
 +      ret = nand_read_oob_std(mtd, chip, page);
 +      nfc->data_access = false;
 +
 +      return ret;
 +}
 +
 +static int vf610_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
 +                             int page)
 +{
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +      int ret;
 +
 +      nfc->data_access = true;
 +      ret = nand_prog_page_begin_op(chip, page, mtd->writesize,
 +                                    chip->oob_poi, mtd->oobsize);
 +      nfc->data_access = false;
 +
 +      if (ret)
 +              return ret;
 +
 +      return nand_prog_page_end_op(chip);
 +}
 +
 +static const struct of_device_id vf610_nfc_dt_ids[] = {
 +      { .compatible = "fsl,vf610-nfc", .data = (void *)NFC_VFC610 },
 +      { /* sentinel */ }
 +};
 +MODULE_DEVICE_TABLE(of, vf610_nfc_dt_ids);
 +
 +static void vf610_nfc_preinit_controller(struct vf610_nfc *nfc)
 +{
 +      vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
 +      vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
 +      vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT);
 +      vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT);
 +      vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT);
 +      vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT);
 +      vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
 +
 +      /* Disable virtual pages, only one elementary transfer unit */
 +      vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
 +                          CONFIG_PAGE_CNT_SHIFT, 1);
 +}
 +
 +static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
 +{
 +      if (nfc->chip.options & NAND_BUSWIDTH_16)
 +              vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
 +      else
 +              vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT);
 +
 +      if (nfc->chip.ecc.mode == NAND_ECC_HW) {
 +              /* Set ECC status offset in SRAM */
 +              vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
 +                                  CONFIG_ECC_SRAM_ADDR_MASK,
 +                                  CONFIG_ECC_SRAM_ADDR_SHIFT,
 +                                  ECC_SRAM_ADDR >> 3);
 +
 +              /* Enable ECC status in SRAM */
 +              vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
 +      }
 +}
 +
 +static int vf610_nfc_probe(struct platform_device *pdev)
 +{
 +      struct vf610_nfc *nfc;
 +      struct resource *res;
 +      struct mtd_info *mtd;
 +      struct nand_chip *chip;
 +      struct device_node *child;
 +      const struct of_device_id *of_id;
 +      int err;
 +      int irq;
 +
 +      nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
 +      if (!nfc)
 +              return -ENOMEM;
 +
 +      nfc->dev = &pdev->dev;
 +      chip = &nfc->chip;
 +      mtd = nand_to_mtd(chip);
 +
 +      mtd->owner = THIS_MODULE;
 +      mtd->dev.parent = nfc->dev;
 +      mtd->name = DRV_NAME;
 +
 +      irq = platform_get_irq(pdev, 0);
 +      if (irq <= 0)
 +              return -EINVAL;
 +
 +      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 +      nfc->regs = devm_ioremap_resource(nfc->dev, res);
 +      if (IS_ERR(nfc->regs))
 +              return PTR_ERR(nfc->regs);
 +
 +      nfc->clk = devm_clk_get(&pdev->dev, NULL);
 +      if (IS_ERR(nfc->clk))
 +              return PTR_ERR(nfc->clk);
 +
 +      err = clk_prepare_enable(nfc->clk);
 +      if (err) {
 +              dev_err(nfc->dev, "Unable to enable clock!\n");
 +              return err;
 +      }
 +
 +      of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
 +      nfc->variant = (enum vf610_nfc_variant)of_id->data;
 +
 +      for_each_available_child_of_node(nfc->dev->of_node, child) {
 +              if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
 +
 +                      if (nand_get_flash_node(chip)) {
 +                              dev_err(nfc->dev,
 +                                      "Only one NAND chip supported!\n");
 +                              err = -EINVAL;
 +                              goto err_disable_clk;
 +                      }
 +
 +                      nand_set_flash_node(chip, child);
 +              }
 +      }
 +
 +      if (!nand_get_flash_node(chip)) {
 +              dev_err(nfc->dev, "NAND chip sub-node missing!\n");
 +              err = -ENODEV;
 +              goto err_disable_clk;
 +      }
 +
 +      chip->exec_op = vf610_nfc_exec_op;
 +      chip->select_chip = vf610_nfc_select_chip;
 +
 +      chip->options |= NAND_NO_SUBPAGE_WRITE;
 +
 +      init_completion(&nfc->cmd_done);
 +
 +      err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd);
 +      if (err) {
 +              dev_err(nfc->dev, "Error requesting IRQ!\n");
 +              goto err_disable_clk;
 +      }
 +
 +      vf610_nfc_preinit_controller(nfc);
 +
 +      /* first scan to find the device and get the page size */
 +      err = nand_scan_ident(mtd, 1, NULL);
 +      if (err)
 +              goto err_disable_clk;
 +
 +      vf610_nfc_init_controller(nfc);
 +
 +      /* Bad block options. */
 +      if (chip->bbt_options & NAND_BBT_USE_FLASH)
 +              chip->bbt_options |= NAND_BBT_NO_OOB;
 +
 +      /* Single buffer only, max 256 OOB minus ECC status */
 +      if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
 +              dev_err(nfc->dev, "Unsupported flash page size\n");
 +              err = -ENXIO;
 +              goto err_disable_clk;
 +      }
 +
 +      if (chip->ecc.mode == NAND_ECC_HW) {
 +              if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
 +                      dev_err(nfc->dev, "Unsupported flash with hwecc\n");
 +                      err = -ENXIO;
 +                      goto err_disable_clk;
 +              }
 +
 +              if (chip->ecc.size != mtd->writesize) {
 +                      dev_err(nfc->dev, "Step size needs to be page size\n");
 +                      err = -ENXIO;
 +                      goto err_disable_clk;
 +              }
 +
 +              /* Only 64 byte ECC layouts known */
 +              if (mtd->oobsize > 64)
 +                      mtd->oobsize = 64;
 +
++              /* Use default large page ECC layout defined in NAND core */
++              mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
 +              if (chip->ecc.strength == 32) {
 +                      nfc->ecc_mode = ECC_60_BYTE;
 +                      chip->ecc.bytes = 60;
 +              } else if (chip->ecc.strength == 24) {
 +                      nfc->ecc_mode = ECC_45_BYTE;
 +                      chip->ecc.bytes = 45;
 +              } else {
 +                      dev_err(nfc->dev, "Unsupported ECC strength\n");
 +                      err = -ENXIO;
 +                      goto err_disable_clk;
 +              }
 +
 +              chip->ecc.read_page = vf610_nfc_read_page;
 +              chip->ecc.write_page = vf610_nfc_write_page;
 +              chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
 +              chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
 +              chip->ecc.read_oob = vf610_nfc_read_oob;
 +              chip->ecc.write_oob = vf610_nfc_write_oob;
 +
 +              chip->ecc.size = PAGE_2K;
 +      }
 +
 +      /* second phase scan */
 +      err = nand_scan_tail(mtd);
 +      if (err)
 +              goto err_disable_clk;
 +
 +      platform_set_drvdata(pdev, mtd);
 +
 +      /* Register device in MTD */
 +      err = mtd_device_register(mtd, NULL, 0);
 +      if (err)
 +              goto err_cleanup_nand;
 +      return 0;
 +
 +err_cleanup_nand:
 +      nand_cleanup(chip);
 +err_disable_clk:
 +      clk_disable_unprepare(nfc->clk);
 +      return err;
 +}
 +
 +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);
 +      clk_disable_unprepare(nfc->clk);
 +      return 0;
 +}
 +
 +#ifdef CONFIG_PM_SLEEP
 +static int vf610_nfc_suspend(struct device *dev)
 +{
 +      struct mtd_info *mtd = dev_get_drvdata(dev);
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +
 +      clk_disable_unprepare(nfc->clk);
 +      return 0;
 +}
 +
 +static int vf610_nfc_resume(struct device *dev)
 +{
 +      int err;
 +
 +      struct mtd_info *mtd = dev_get_drvdata(dev);
 +      struct vf610_nfc *nfc = mtd_to_nfc(mtd);
 +
 +      err = clk_prepare_enable(nfc->clk);
 +      if (err)
 +              return err;
 +
 +      vf610_nfc_preinit_controller(nfc);
 +      vf610_nfc_init_controller(nfc);
 +      return 0;
 +}
 +#endif
 +
 +static SIMPLE_DEV_PM_OPS(vf610_nfc_pm_ops, vf610_nfc_suspend, vf610_nfc_resume);
 +
 +static struct platform_driver vf610_nfc_driver = {
 +      .driver         = {
 +              .name   = DRV_NAME,
 +              .of_match_table = vf610_nfc_dt_ids,
 +              .pm     = &vf610_nfc_pm_ops,
 +      },
 +      .probe          = vf610_nfc_probe,
 +      .remove         = vf610_nfc_remove,
 +};
 +
 +module_platform_driver(vf610_nfc_driver);
 +
 +MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
 +MODULE_DESCRIPTION("Freescale VF610/MPC5125 NFC MTD NAND driver");
 +MODULE_LICENSE("GPL");