From: Miquel Raynal Date: Thu, 16 Aug 2018 15:30:07 +0000 (+0200) Subject: mtd: move NAND files into a raw/ subdirectory X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=a430fa06a4ac50e785fdbfb7f43c3cb14b35619c;p=project%2Fbcm63xx%2Fu-boot.git mtd: move NAND files into a raw/ subdirectory NAND flavors, like serial and parallel, have a lot in common and would benefit to share code. Let's move raw (parallel) NAND specific code in a raw/ subdirectory, to ease the addition of a core file in nand/ and the introduction of a spi/ subdirectory specific to SPI NANDs. Signed-off-by: Miquel Raynal --- diff --git a/MAINTAINERS b/MAINTAINERS index 64fb41ece7..20a0a5e12b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -298,7 +298,7 @@ F: drivers/i2c/i2c-cdns.c F: drivers/i2c/muxes/pca954x.c F: drivers/i2c/zynq_i2c.c F: drivers/mmc/zynq_sdhci.c -F: drivers/mtd/nand/zynq_nand.c +F: drivers/mtd/nand/raw/zynq_nand.c F: drivers/net/phy/xilinx_phy.c F: drivers/net/zynq_gem.c F: drivers/serial/serial_zynq.c @@ -322,7 +322,7 @@ F: drivers/i2c/i2c-cdns.c F: drivers/i2c/muxes/pca954x.c F: drivers/i2c/zynq_i2c.c F: drivers/mmc/zynq_sdhci.c -F: drivers/mtd/nand/zynq_nand.c +F: drivers/mtd/nand/raw/zynq_nand.c F: drivers/net/phy/xilinx_phy.c F: drivers/net/zynq_gem.c F: drivers/serial/serial_zynq.c @@ -467,7 +467,7 @@ NAND FLASH #M: Scott Wood S: Orphaned (Since 2018-07) T: git git://git.denx.de/u-boot-nand-flash.git -F: drivers/mtd/nand/ +F: drivers/mtd/nand/raw/ NDS32 M: Macpaul Lin diff --git a/Makefile b/Makefile index e38966edba..807e803f99 100644 --- a/Makefile +++ b/Makefile @@ -689,7 +689,7 @@ libs-y += drivers/dma/ libs-y += drivers/gpio/ libs-y += drivers/i2c/ libs-y += drivers/mtd/ -libs-$(CONFIG_CMD_NAND) += drivers/mtd/nand/ +libs-$(CONFIG_CMD_NAND) += drivers/mtd/nand/raw/ libs-y += drivers/mtd/onenand/ libs-$(CONFIG_CMD_UBI) += drivers/mtd/ubi/ libs-y += drivers/mtd/spi/ diff --git a/README b/README index 09822a317d..35305a61a3 100644 --- a/README +++ b/README @@ -3256,8 +3256,8 @@ Low Level (hardware related) configuration options: a 16 bit bus. Not all NAND drivers use this symbol. Example of drivers that use it: - - drivers/mtd/nand/ndfc.c - - drivers/mtd/nand/mxc_nand.c + - drivers/mtd/nand/raw/ndfc.c + - drivers/mtd/nand/raw/mxc_nand.c - CONFIG_SYS_NDFC_EBC0_CFG Sets the EBC0_CFG register for the NDFC. If not defined @@ -3374,7 +3374,7 @@ Low Level (hardware related) configuration options: - CONFIG_SYS_NAND_NO_SUBPAGE_WRITE Option to disable subpage write in NAND driver driver that uses this: - drivers/mtd/nand/davinci_nand.c + drivers/mtd/nand/raw/davinci_nand.c Freescale QE/FMAN Firmware Support: ----------------------------------- diff --git a/arch/arm/mach-uniphier/board_late_init.c b/arch/arm/mach-uniphier/board_late_init.c index 8ffb9a8d3c..1b871c62ce 100644 --- a/arch/arm/mach-uniphier/board_late_init.c +++ b/arch/arm/mach-uniphier/board_late_init.c @@ -12,7 +12,7 @@ #include #include #include -#include <../drivers/mtd/nand/denali.h> +#include <../drivers/mtd/nand/raw/denali.h> #include "init.h" diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 280496fbe0..18dbc238bf 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -487,7 +487,7 @@ config SPL_NAND_SUPPORT help Enable support for NAND (Negative AND) flash in SPL. NAND flash can be used to allow SPL to load U-Boot from supported devices. - This enables the drivers in drivers/mtd/nand as part of an SPL + This enables the drivers in drivers/mtd/nand/raw as part of an SPL build. config SPL_NET_SUPPORT diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c index ba60a3a3c5..0016d49739 100644 --- a/common/spl/spl_spi.c +++ b/common/spl/spl_spi.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2011 OMICRON electronics GmbH * - * based on drivers/mtd/nand/nand_spl_load.c + * based on drivers/mtd/nand/raw/nand_spl_load.c * * Copyright (C) 2011 * Heiko Schocher, DENX Software Engineering, hs@denx.de. diff --git a/doc/README.SPL b/doc/README.SPL index 3ba313caa8..fc1ca1ad4f 100644 --- a/doc/README.SPL +++ b/doc/README.SPL @@ -57,11 +57,11 @@ CONFIG_SPL_FAT_SUPPORT (fs/fat/libfat.o) CONFIG_SPL_EXT_SUPPORT CONFIG_SPL_LIBGENERIC_SUPPORT (lib/libgeneric.o) CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o) -CONFIG_SPL_NAND_SUPPORT (drivers/mtd/nand/libnand.o) +CONFIG_SPL_NAND_SUPPORT (drivers/mtd/nand/raw/libnand.o) CONFIG_SPL_DRIVERS_MISC_SUPPORT (drivers/misc) CONFIG_SPL_DMA_SUPPORT (drivers/dma/libdma.o) CONFIG_SPL_POST_MEM_SUPPORT (post/drivers/memory.o) -CONFIG_SPL_NAND_LOAD (drivers/mtd/nand/nand_spl_load.o) +CONFIG_SPL_NAND_LOAD (drivers/mtd/nand/raw/nand_spl_load.o) CONFIG_SPL_SPI_LOAD (drivers/mtd/spi/spi_spl_load.o) CONFIG_SPL_RAM_DEVICE (common/spl/spl.c) CONFIG_SPL_WATCHDOG_SUPPORT (drivers/watchdog/libwatchdog.o) diff --git a/doc/README.arm-relocation b/doc/README.arm-relocation index 645b3746c8..d2a7e8122e 100644 --- a/doc/README.arm-relocation +++ b/doc/README.arm-relocation @@ -84,7 +84,7 @@ Relocation with SPL (example for the tx25 booting from NAND Flash): - cpu copies the first page from NAND to 0xbb000000 (IMX_NFC_BASE) and start with code execution on this address. -- The First page contains u-boot code from drivers/mtd/nand/mxc_nand_spl.c +- The First page contains u-boot code from drivers/mtd/nand/raw/mxc_nand_spl.c which inits the dram, cpu registers, reloacte itself to CONFIG_SPL_TEXT_BASE and loads the "real" u-boot to CONFIG_SYS_NAND_U_BOOT_DST and starts execution @CONFIG_SYS_NAND_U_BOOT_START diff --git a/doc/README.nand b/doc/README.nand index cda11b43ff..ec461b2dc9 100644 --- a/doc/README.nand +++ b/doc/README.nand @@ -116,7 +116,7 @@ Configuration Options: The maximum number of NAND chips per device to be supported. CONFIG_SYS_NAND_SELF_INIT - Traditionally, glue code in drivers/mtd/nand/nand.c has driven + Traditionally, glue code in drivers/mtd/nand/raw/nand.c has driven the initialization process -- it provides the mtd and nand structs, calls a board init function for a specific device, calls nand_scan(), and registers with mtd. @@ -125,7 +125,7 @@ Configuration Options: run code between nand_scan_ident() and nand_scan_tail(), or other deviations from the "normal" flow. - If a board defines CONFIG_SYS_NAND_SELF_INIT, drivers/mtd/nand/nand.c + If a board defines CONFIG_SYS_NAND_SELF_INIT, drivers/mtd/nand/raw/nand.c will make one call to board_nand_init(), with no arguments. That function is responsible for calling a driver init function for each NAND device on the board, that performs all initialization @@ -280,7 +280,7 @@ NOTE: ===== The Disk On Chip driver is currently broken and has been for some time. -There is a driver in drivers/mtd/nand, taken from Linux, that works with +There is a driver in drivers/mtd/nand/raw, taken from Linux, that works with the current NAND system but has not yet been adapted to the u-boot environment. diff --git a/doc/README.zynq b/doc/README.zynq index 5b0672c503..da977b2016 100644 --- a/doc/README.zynq +++ b/doc/README.zynq @@ -63,7 +63,7 @@ bootmode strings at runtime. spi - drivers/spi/zynq_spi.c qspi - drivers/spi/zynq_qspi.c i2c - drivers/i2c/zynq_i2c.c - nand - drivers/mtd/nand/zynq_nand.c + nand - drivers/mtd/nand/raw/zynq_nand.c - Done proper cleanups on board configurations - Added basic FDT support for zynq boards - d-cache support for zynq_gem.c diff --git a/drivers/Makefile b/drivers/Makefile index 23ea609b09..fe8d40dddb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_$(SPL_TPL_)DRIVERS_MISC_SUPPORT) += misc/ sysreset/ firmware/ obj-$(CONFIG_$(SPL_TPL_)I2C_SUPPORT) += i2c/ obj-$(CONFIG_$(SPL_TPL_)LED) += led/ obj-$(CONFIG_$(SPL_TPL_)MMC_SUPPORT) += mmc/ -obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += mtd/nand/ +obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += mtd/nand/raw/ obj-$(CONFIG_$(SPL_TPL_)PHY) += phy/ obj-$(CONFIG_$(SPL_TPL_)PINCTRL) += pinctrl/ obj-$(CONFIG_$(SPL_TPL_)RAM) += ram/ diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 9cec06510c..cdf515256a 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -18,3 +18,5 @@ obj-$(CONFIG_FLASH_PIC32) += pic32_flash.o obj-$(CONFIG_ST_SMI) += st_smi.o obj-$(CONFIG_STM32_FLASH) += stm32_flash.o obj-$(CONFIG_RENESAS_RPC_HF) += renesas_rpc_hf.o + +obj-y += nand/ diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 1e4ea7bdd4..6d53734718 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,297 +1 @@ - -menuconfig NAND - bool "NAND Device Support" -if NAND - -config SYS_NAND_SELF_INIT - bool - help - This option, if enabled, provides more flexible and linux-like - NAND initialization process. - -config NAND_ATMEL - bool "Support Atmel NAND controller" - imply SYS_NAND_USE_FLASH_BBT - help - Enable this driver for NAND flash platforms using an Atmel NAND - controller. - -config NAND_DAVINCI - bool "Support TI Davinci NAND controller" - help - Enable this driver for NAND flash controllers available in TI Davinci - and Keystone2 platforms - -config NAND_DENALI - bool - select SYS_NAND_SELF_INIT - imply CMD_NAND - -config NAND_DENALI_DT - bool "Support Denali NAND controller as a DT device" - select NAND_DENALI - depends on OF_CONTROL && DM - help - Enable the driver for NAND flash on platforms using a Denali NAND - controller as a DT device. - -config NAND_DENALI_SPARE_AREA_SKIP_BYTES - int "Number of bytes skipped in OOB area" - depends on NAND_DENALI - range 0 63 - help - This option specifies the number of bytes to skip from the beginning - of OOB area before last ECC sector data starts. This is potentially - used to preserve the bad block marker in the OOB area. - -config NAND_LPC32XX_SLC - bool "Support LPC32XX_SLC controller" - help - Enable the LPC32XX SLC NAND controller. - -config NAND_OMAP_GPMC - bool "Support OMAP GPMC NAND controller" - depends on ARCH_OMAP2PLUS - help - Enables omap_gpmc.c driver for OMAPx and AMxxxx platforms. - GPMC controller is used for parallel NAND flash devices, and can - do ECC calculation (not ECC error detection) for HAM1, BCH4, BCH8 - and BCH16 ECC algorithms. - -config NAND_OMAP_GPMC_PREFETCH - bool "Enable GPMC Prefetch" - depends on NAND_OMAP_GPMC - default y - help - On OMAP platforms that use the GPMC controller - (CONFIG_NAND_OMAP_GPMC_PREFETCH), this options enables the code that - uses the prefetch mode to speed up read operations. - -config NAND_OMAP_ELM - bool "Enable ELM driver for OMAPxx and AMxx platforms." - depends on NAND_OMAP_GPMC && !OMAP34XX - help - ELM controller is used for ECC error detection (not ECC calculation) - of BCH4, BCH8 and BCH16 ECC algorithms. - Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine, - thus such SoC platforms need to depend on software library for ECC error - detection. However ECC calculation on such plaforms would still be - done by GPMC controller. - -config NAND_VF610_NFC - bool "Support for Freescale NFC for VF610" - select SYS_NAND_SELF_INIT - imply CMD_NAND - help - Enables support for NAND Flash Controller on some Freescale - processors like the VF610, MCF54418 or Kinetis K70. - The driver supports a maximum 2k page size. The driver - currently does not support hardware ECC. - -choice - prompt "Hardware ECC strength" - depends on NAND_VF610_NFC - default SYS_NAND_VF610_NFC_45_ECC_BYTES - help - Select the ECC strength used in the hardware BCH ECC block. - -config SYS_NAND_VF610_NFC_45_ECC_BYTES - bool "24-error correction (45 ECC bytes)" - -config SYS_NAND_VF610_NFC_60_ECC_BYTES - bool "32-error correction (60 ECC bytes)" - -endchoice - -config NAND_PXA3XX - bool "Support for NAND on PXA3xx and Armada 370/XP/38x" - select SYS_NAND_SELF_INIT - imply CMD_NAND - help - This enables the driver for the NAND flash device found on - PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2). - -config NAND_SUNXI - bool "Support for NAND on Allwinner SoCs" - default ARCH_SUNXI - depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I - select SYS_NAND_SELF_INIT - select SYS_NAND_U_BOOT_LOCATIONS - select SPL_NAND_SUPPORT - imply CMD_NAND - ---help--- - Enable support for NAND. This option enables the standard and - SPL drivers. - The SPL driver only supports reading from the NAND using DMA - transfers. - -if NAND_SUNXI - -config NAND_SUNXI_SPL_ECC_STRENGTH - int "Allwinner NAND SPL ECC Strength" - default 64 - -config NAND_SUNXI_SPL_ECC_SIZE - int "Allwinner NAND SPL ECC Step Size" - default 1024 - -config NAND_SUNXI_SPL_USABLE_PAGE_SIZE - int "Allwinner NAND SPL Usable Page Size" - default 1024 - -endif - -config NAND_ARASAN - bool "Configure Arasan Nand" - select SYS_NAND_SELF_INIT - imply CMD_NAND - help - This enables Nand driver support for Arasan nand flash - controller. This uses the hardware ECC for read and - write operations. - -config NAND_MXC - bool "MXC NAND support" - depends on CPU_ARM926EJS || CPU_ARM1136 || MX5 - imply CMD_NAND - help - This enables the NAND driver for the NAND flash controller on the - i.MX27 / i.MX31 / i.MX5 rocessors. - -config NAND_MXS - bool "MXS NAND support" - depends on MX23 || MX28 || MX6 || MX7 - select SYS_NAND_SELF_INIT - imply CMD_NAND - select APBH_DMA - select APBH_DMA_BURST if ARCH_MX6 || ARCH_MX7 - select APBH_DMA_BURST8 if ARCH_MX6 || ARCH_MX7 - help - This enables NAND driver for the NAND flash controller on the - MXS processors. - -if NAND_MXS - -config NAND_MXS_DT - bool "Support MXS NAND controller as a DT device" - depends on OF_CONTROL && MTD - help - Enable the driver for MXS NAND flash on platforms using - device tree. - -config NAND_MXS_USE_MINIMUM_ECC - bool "Use minimum ECC strength supported by the controller" - default false - -endif - -config NAND_ZYNQ - bool "Support for Zynq Nand controller" - select SYS_NAND_SELF_INIT - imply CMD_NAND - help - This enables Nand driver support for Nand flash controller - found on Zynq SoC. - -config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS - bool "Enable use of 1st stage bootloader timing for NAND" - depends on NAND_ZYNQ - help - This flag prevent U-boot reconfigure NAND flash controller and reuse - the NAND timing from 1st stage bootloader. - -comment "Generic NAND options" - -config SYS_NAND_BLOCK_SIZE - hex "NAND chip eraseblock size" - depends on ARCH_SUNXI - help - Number of data bytes in one eraseblock for the NAND chip on the - board. This is the multiple of NAND_PAGE_SIZE and the number of - pages. - -config SYS_NAND_PAGE_SIZE - hex "NAND chip page size" - depends on ARCH_SUNXI - help - Number of data bytes in one page for the NAND chip on the - board, not including the OOB area. - -config SYS_NAND_OOBSIZE - hex "NAND chip OOB size" - depends on ARCH_SUNXI - help - Number of bytes in the Out-Of-Band area for the NAND chip on - the board. - -# Enhance depends when converting drivers to Kconfig which use this config -# option (mxc_nand, ndfc, omap_gpmc). -config SYS_NAND_BUSWIDTH_16BIT - bool "Use 16-bit NAND interface" - depends on NAND_VF610_NFC || NAND_OMAP_GPMC || NAND_MXC || ARCH_DAVINCI - help - Indicates that NAND device has 16-bit wide data-bus. In absence of this - config, bus-width of NAND device is assumed to be either 8-bit and later - determined by reading ONFI params. - Above config is useful when NAND device's bus-width information cannot - be determined from on-chip ONFI params, like in following scenarios: - - SPL boot does not support reading of ONFI parameters. This is done to - keep SPL code foot-print small. - - In current U-Boot flow using nand_init(), driver initialization - happens in board_nand_init() which is called before any device probe - (nand_scan_ident + nand_scan_tail), thus device's ONFI parameters are - not available while configuring controller. So a static CONFIG_NAND_xx - is needed to know the device's bus-width in advance. - -if SPL - -config SYS_NAND_U_BOOT_LOCATIONS - bool "Define U-boot binaries locations in NAND" - help - Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig. - This option should not be enabled when compiling U-boot for boards - defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/.h - file. - -config SYS_NAND_U_BOOT_OFFS - hex "Location in NAND to read U-Boot from" - default 0x800000 if NAND_SUNXI - depends on SYS_NAND_U_BOOT_LOCATIONS - help - Set the offset from the start of the nand where u-boot should be - loaded from. - -config SYS_NAND_U_BOOT_OFFS_REDUND - hex "Location in NAND to read U-Boot from" - default SYS_NAND_U_BOOT_OFFS - depends on SYS_NAND_U_BOOT_LOCATIONS - help - Set the offset from the start of the nand where the redundant u-boot - should be loaded from. - -config SPL_NAND_AM33XX_BCH - bool "Enables SPL-NAND driver which supports ELM based" - depends on NAND_OMAP_GPMC && !OMAP34XX - default y - help - Hardware ECC correction. This is useful for platforms which have ELM - hardware engine and use NAND boot mode. - Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine, - so those platforms should use CONFIG_SPL_NAND_SIMPLE for enabling - SPL-NAND driver with software ECC correction support. - -config SPL_NAND_DENALI - bool "Support Denali NAND controller for SPL" - help - This is a small implementation of the Denali NAND controller - for use on SPL. - -config SPL_NAND_SIMPLE - bool "Use simple SPL NAND driver" - depends on !SPL_NAND_AM33XX_BCH - help - Support for NAND boot using simple NAND drivers that - expose the cmd_ctrl() interface. -endif - -endif # if NAND +source "drivers/mtd/nand/raw/Kconfig" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index c61e3f3839..69f40d1563 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,77 +1,2 @@ # SPDX-License-Identifier: GPL-2.0+ -# -# (C) Copyright 2006 -# Wolfgang Denk, DENX Software Engineering, wd@denx.de. -ifdef CONFIG_SPL_BUILD - -ifdef CONFIG_SPL_NAND_DRIVERS -NORMAL_DRIVERS=y -endif - -obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o -obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o -obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o -obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o -obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o -obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o -obj-$(CONFIG_SPL_NAND_IDENT) += nand_ids.o nand_timings.o -obj-$(CONFIG_SPL_NAND_INIT) += nand.o -ifeq ($(CONFIG_SPL_ENV_SUPPORT),y) -obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o -endif - -else # not spl - -NORMAL_DRIVERS=y - -obj-y += nand.o -obj-y += nand_bbt.o -obj-y += nand_ids.o -obj-y += nand_util.o -obj-y += nand_ecc.o -obj-y += nand_base.o -obj-y += nand_timings.o - -endif # not spl - -ifdef NORMAL_DRIVERS - -obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o - -obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o -obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o -obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o -obj-$(CONFIG_NAND_DENALI) += denali.o -obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o -obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o -obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o -obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o -obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o -obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o -obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o -obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o -obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o -obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o -obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o -obj-$(CONFIG_NAND_MXC) += mxc_nand.o -obj-$(CONFIG_NAND_MXS) += mxs_nand.o -obj-$(CONFIG_NAND_MXS_DT) += mxs_nand_dt.o -obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o -obj-$(CONFIG_NAND_SPEAR) += spr_nand.o -obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o -obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o -obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o -obj-$(CONFIG_NAND_PLAT) += nand_plat.o -obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o -obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o - -else # minimal SPL drivers - -obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o -obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o -obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o -obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o -obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o - -endif # drivers diff --git a/drivers/mtd/nand/am335x_spl_bch.c b/drivers/mtd/nand/am335x_spl_bch.c deleted file mode 100644 index ba2f33a96e..0000000000 --- a/drivers/mtd/nand/am335x_spl_bch.c +++ /dev/null @@ -1,225 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2012 - * Konstantin Kozhevnikov, Cogent Embedded - * - * based on nand_spl_simple code - * - * (C) Copyright 2006-2008 - * Stefan Roese, DENX Software Engineering, sr@denx.de. - */ - -#include -#include -#include -#include - -static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; -static struct mtd_info *mtd; -static struct nand_chip nand_chip; - -#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ - CONFIG_SYS_NAND_ECCSIZE) -#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) - - -/* - * NAND command for large page NAND devices (2k) - */ -static int nand_command(int block, int page, uint32_t offs, - u8 cmd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; - void (*hwctrl)(struct mtd_info *mtd, int cmd, - unsigned int ctrl) = this->cmd_ctrl; - - while (!this->dev_ready(mtd)) - ; - - /* Emulate NAND_CMD_READOOB */ - if (cmd == NAND_CMD_READOOB) { - offs += CONFIG_SYS_NAND_PAGE_SIZE; - cmd = NAND_CMD_READ0; - } - - /* Begin command latch cycle */ - hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - - if (cmd == NAND_CMD_RESET) { - hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Apply this short delay always to ensure that we do wait - * tWB in any case on any machine. - */ - ndelay(150); - - while (!this->dev_ready(mtd)) - ; - return 0; - } - - /* Shift the offset from byte addressing to word addressing. */ - if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) - offs >>= 1; - - /* Set ALE and clear CLE to start address cycle */ - /* Column address */ - hwctrl(mtd, offs & 0xff, - NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ - hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */ - /* Row address */ - if (cmd != NAND_CMD_RNDOUT) { - hwctrl(mtd, (page_addr & 0xff), - NAND_CTRL_ALE); /* A[19:12] */ - hwctrl(mtd, ((page_addr >> 8) & 0xff), - NAND_CTRL_ALE); /* A[27:20] */ -#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE - /* One more address cycle for devices > 128MiB */ - hwctrl(mtd, (page_addr >> 16) & 0x0f, - NAND_CTRL_ALE); /* A[31:28] */ -#endif - } - - hwctrl(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 (cmd) { - case NAND_CMD_CACHEDPROG: - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_RNDIN: - case NAND_CMD_STATUS: - return 0; - - case NAND_CMD_RNDOUT: - /* No ready / busy check necessary */ - hwctrl(mtd, NAND_CMD_RNDOUTSTART, NAND_CTRL_CLE | - NAND_CTRL_CHANGE); - hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - return 0; - - case NAND_CMD_READ0: - /* Latch in address */ - hwctrl(mtd, NAND_CMD_READSTART, - NAND_CTRL_CLE | NAND_CTRL_CHANGE); - hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - } - - /* - * Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. - */ - ndelay(150); - - while (!this->dev_ready(mtd)) - ; - - return 0; -} - -static int nand_is_bad_block(int block) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, - NAND_CMD_READOOB); - - /* - * Read one byte (or two if it's a 16 bit chip). - */ - if (this->options & NAND_BUSWIDTH_16) { - if (readw(this->IO_ADDR_R) != 0xffff) - return 1; - } else { - if (readb(this->IO_ADDR_R) != 0xff) - return 1; - } - - return 0; -} - -static int nand_read_page(int block, int page, void *dst) -{ - struct nand_chip *this = mtd_to_nand(mtd); - u_char ecc_calc[ECCTOTAL]; - u_char ecc_code[ECCTOTAL]; - u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; - int i; - int eccsize = CONFIG_SYS_NAND_ECCSIZE; - int eccbytes = CONFIG_SYS_NAND_ECCBYTES; - int eccsteps = ECCSTEPS; - uint8_t *p = dst; - uint32_t data_pos = 0; - uint8_t *oob = &oob_data[0] + nand_ecc_pos[0]; - uint32_t oob_pos = eccsize * eccsteps + nand_ecc_pos[0]; - - nand_command(block, page, 0, NAND_CMD_READ0); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - this->ecc.hwctl(mtd, NAND_ECC_READ); - nand_command(block, page, data_pos, NAND_CMD_RNDOUT); - - this->read_buf(mtd, p, eccsize); - - nand_command(block, page, oob_pos, NAND_CMD_RNDOUT); - - this->read_buf(mtd, oob, eccbytes); - this->ecc.calculate(mtd, p, &ecc_calc[i]); - - data_pos += eccsize; - oob_pos += eccbytes; - oob += eccbytes; - } - - /* Pick the ECC bytes out of the oob data */ - for (i = 0; i < ECCTOTAL; i++) - ecc_code[i] = oob_data[nand_ecc_pos[i]]; - - eccsteps = ECCSTEPS; - p = dst; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - /* No chance to do something with the possible error message - * from correct_data(). We just hope that all possible errors - * are corrected by this routine. - */ - this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - } - - return 0; -} - -/* nand_init() - initialize data to make nand usable by SPL */ -void nand_init(void) -{ - /* - * Init board specific nand support - */ - mtd = nand_to_mtd(&nand_chip); - nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = - (void __iomem *)CONFIG_SYS_NAND_BASE; - board_nand_init(&nand_chip); - - if (nand_chip.select_chip) - nand_chip.select_chip(mtd, 0); - - /* NAND chip may require reset after power-on */ - nand_command(0, 0, 0, NAND_CMD_RESET); -} - -/* Unselect after operation */ -void nand_deselect(void) -{ - if (nand_chip.select_chip) - nand_chip.select_chip(mtd, -1); -} - -#include "nand_spl_loaders.c" diff --git a/drivers/mtd/nand/arasan_nfc.c b/drivers/mtd/nand/arasan_nfc.c deleted file mode 100644 index 41db9f8bb9..0000000000 --- a/drivers/mtd/nand/arasan_nfc.c +++ /dev/null @@ -1,1270 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Arasan NAND Flash Controller Driver - * - * Copyright (C) 2014 - 2015 Xilinx, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct arasan_nand_info { - void __iomem *nand_base; - u32 page; - bool on_die_ecc_enabled; -}; - -struct nand_regs { - u32 pkt_reg; - u32 memadr_reg1; - u32 memadr_reg2; - u32 cmd_reg; - u32 pgm_reg; - u32 intsts_enr; - u32 intsig_enr; - u32 intsts_reg; - u32 rdy_busy; - u32 cms_sysadr_reg; - u32 flash_sts_reg; - u32 tmg_reg; - u32 buf_dataport; - u32 ecc_reg; - u32 ecc_errcnt_reg; - u32 ecc_sprcmd_reg; - u32 errcnt_1bitreg; - u32 errcnt_2bitreg; - u32 errcnt_3bitreg; - u32 errcnt_4bitreg; - u32 dma_sysadr0_reg; - u32 dma_bufbdry_reg; - u32 cpu_rls_reg; - u32 errcnt_5bitreg; - u32 errcnt_6bitreg; - u32 errcnt_7bitreg; - u32 errcnt_8bitreg; - u32 data_if_reg; -}; - -#define arasan_nand_base ((struct nand_regs __iomem *)ARASAN_NAND_BASEADDR) - -struct arasan_nand_command_format { - u8 cmd1; - u8 cmd2; - u8 addr_cycles; - u32 pgm; -}; - -#define ONDIE_ECC_FEATURE_ADDR 0x90 -#define ENABLE_ONDIE_ECC 0x08 - -#define ARASAN_PROG_RD_MASK 0x00000001 -#define ARASAN_PROG_BLK_ERS_MASK 0x00000004 -#define ARASAN_PROG_RD_ID_MASK 0x00000040 -#define ARASAN_PROG_RD_STS_MASK 0x00000008 -#define ARASAN_PROG_PG_PROG_MASK 0x00000010 -#define ARASAN_PROG_RD_PARAM_PG_MASK 0x00000080 -#define ARASAN_PROG_RST_MASK 0x00000100 -#define ARASAN_PROG_GET_FTRS_MASK 0x00000200 -#define ARASAN_PROG_SET_FTRS_MASK 0x00000400 -#define ARASAN_PROG_CHNG_ROWADR_END_MASK 0x00400000 - -#define ARASAN_NAND_CMD_ECC_ON_MASK 0x80000000 -#define ARASAN_NAND_CMD_CMD12_MASK 0xFFFF -#define ARASAN_NAND_CMD_PG_SIZE_MASK 0x3800000 -#define ARASAN_NAND_CMD_PG_SIZE_SHIFT 23 -#define ARASAN_NAND_CMD_CMD2_SHIFT 8 -#define ARASAN_NAND_CMD_ADDR_CYCL_MASK 0x70000000 -#define ARASAN_NAND_CMD_ADDR_CYCL_SHIFT 28 - -#define ARASAN_NAND_MEM_ADDR1_PAGE_MASK 0xFFFF0000 -#define ARASAN_NAND_MEM_ADDR1_COL_MASK 0xFFFF -#define ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT 16 -#define ARASAN_NAND_MEM_ADDR2_PAGE_MASK 0xFF -#define ARASAN_NAND_MEM_ADDR2_CS_MASK 0xC0000000 -#define ARASAN_NAND_MEM_ADDR2_BCH_MASK 0xE000000 -#define ARASAN_NAND_MEM_ADDR2_BCH_SHIFT 25 - -#define ARASAN_NAND_INT_STS_ERR_EN_MASK 0x10 -#define ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK 0x08 -#define ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK 0x02 -#define ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK 0x01 -#define ARASAN_NAND_INT_STS_XFR_CMPLT_MASK 0x04 - -#define ARASAN_NAND_PKT_REG_PKT_CNT_MASK 0xFFF000 -#define ARASAN_NAND_PKT_REG_PKT_SIZE_MASK 0x7FF -#define ARASAN_NAND_PKT_REG_PKT_CNT_SHFT 12 - -#define ARASAN_NAND_ROW_ADDR_CYCL_MASK 0x0F -#define ARASAN_NAND_COL_ADDR_CYCL_MASK 0xF0 -#define ARASAN_NAND_COL_ADDR_CYCL_SHIFT 4 - -#define ARASAN_NAND_ECC_SIZE_SHIFT 16 -#define ARASAN_NAND_ECC_BCH_SHIFT 27 - -#define ARASAN_NAND_PKTSIZE_1K 1024 -#define ARASAN_NAND_PKTSIZE_512 512 - -#define ARASAN_NAND_POLL_TIMEOUT 1000000 -#define ARASAN_NAND_INVALID_ADDR_CYCL 0xFF - -#define ERR_ADDR_CYCLE -1 -#define READ_BUFF_SIZE 0x4000 - -static struct arasan_nand_command_format *curr_cmd; - -enum addr_cycles { - NAND_ADDR_CYCL_NONE, - NAND_ADDR_CYCL_ONE, - NAND_ADDR_CYCL_ROW, - NAND_ADDR_CYCL_COL, - NAND_ADDR_CYCL_BOTH, -}; - -static struct arasan_nand_command_format arasan_nand_commands[] = { - {NAND_CMD_READ0, NAND_CMD_READSTART, NAND_ADDR_CYCL_BOTH, - ARASAN_PROG_RD_MASK}, - {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, NAND_ADDR_CYCL_COL, - ARASAN_PROG_RD_MASK}, - {NAND_CMD_READID, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, - ARASAN_PROG_RD_ID_MASK}, - {NAND_CMD_STATUS, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, - ARASAN_PROG_RD_STS_MASK}, - {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_ADDR_CYCL_BOTH, - ARASAN_PROG_PG_PROG_MASK}, - {NAND_CMD_RNDIN, NAND_CMD_NONE, NAND_ADDR_CYCL_COL, - ARASAN_PROG_CHNG_ROWADR_END_MASK}, - {NAND_CMD_ERASE1, NAND_CMD_ERASE2, NAND_ADDR_CYCL_ROW, - ARASAN_PROG_BLK_ERS_MASK}, - {NAND_CMD_RESET, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, - ARASAN_PROG_RST_MASK}, - {NAND_CMD_PARAM, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, - ARASAN_PROG_RD_PARAM_PG_MASK}, - {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, - ARASAN_PROG_GET_FTRS_MASK}, - {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, - ARASAN_PROG_SET_FTRS_MASK}, - {NAND_CMD_NONE, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, 0}, -}; - -struct arasan_ecc_matrix { - u32 pagesize; - u32 ecc_codeword_size; - u8 eccbits; - u8 bch; - u8 bchval; - u16 eccaddr; - u16 eccsize; -}; - -static const struct arasan_ecc_matrix ecc_matrix[] = { - {512, 512, 1, 0, 0, 0x20D, 0x3}, - {512, 512, 4, 1, 3, 0x209, 0x7}, - {512, 512, 8, 1, 2, 0x203, 0xD}, - /* - * 2K byte page - */ - {2048, 512, 1, 0, 0, 0x834, 0xC}, - {2048, 512, 4, 1, 3, 0x826, 0x1A}, - {2048, 512, 8, 1, 2, 0x80c, 0x34}, - {2048, 512, 12, 1, 1, 0x822, 0x4E}, - {2048, 512, 16, 1, 0, 0x808, 0x68}, - {2048, 1024, 24, 1, 4, 0x81c, 0x54}, - /* - * 4K byte page - */ - {4096, 512, 1, 0, 0, 0x1068, 0x18}, - {4096, 512, 4, 1, 3, 0x104c, 0x34}, - {4096, 512, 8, 1, 2, 0x1018, 0x68}, - {4096, 512, 12, 1, 1, 0x1044, 0x9C}, - {4096, 512, 16, 1, 0, 0x1010, 0xD0}, - {4096, 1024, 24, 1, 4, 0x1038, 0xA8}, - /* - * 8K byte page - */ - {8192, 512, 1, 0, 0, 0x20d0, 0x30}, - {8192, 512, 4, 1, 3, 0x2098, 0x68}, - {8192, 512, 8, 1, 2, 0x2030, 0xD0}, - {8192, 512, 12, 1, 1, 0x2088, 0x138}, - {8192, 512, 16, 1, 0, 0x2020, 0x1A0}, - {8192, 1024, 24, 1, 4, 0x2070, 0x150}, - /* - * 16K byte page - */ - {16384, 512, 1, 0, 0, 0x4460, 0x60}, - {16384, 512, 4, 1, 3, 0x43f0, 0xD0}, - {16384, 512, 8, 1, 2, 0x4320, 0x1A0}, - {16384, 512, 12, 1, 1, 0x4250, 0x270}, - {16384, 512, 16, 1, 0, 0x4180, 0x340}, - {16384, 1024, 24, 1, 4, 0x4220, 0x2A0} -}; - -static struct nand_ecclayout ondie_nand_oob_64 = { - .eccbytes = 32, - - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 24, 25, 26, 27, 28, 29, 30, 31, - 40, 41, 42, 43, 44, 45, 46, 47, - 56, 57, 58, 59, 60, 61, 62, 63 - }, - - .oobfree = { - { .offset = 4, .length = 4 }, - { .offset = 20, .length = 4 }, - { .offset = 36, .length = 4 }, - { .offset = 52, .length = 4 } - } -}; - -/* - * bbt decriptors for chips with on-die ECC and - * chips with 64-byte OOB - */ -static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; -static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 4, - .len = 4, - .veroffs = 20, - .maxblocks = 4, - .pattern = bbt_pattern -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 4, - .len = 4, - .veroffs = 20, - .maxblocks = 4, - .pattern = mirror_pattern -}; - -static u8 buf_data[READ_BUFF_SIZE]; -static u32 buf_index; - -static struct nand_ecclayout nand_oob; - -static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; - -static void arasan_nand_select_chip(struct mtd_info *mtd, int chip) -{ -} - -static void arasan_nand_enable_ecc(void) -{ - u32 reg_val; - - reg_val = readl(&arasan_nand_base->cmd_reg); - reg_val |= ARASAN_NAND_CMD_ECC_ON_MASK; - - writel(reg_val, &arasan_nand_base->cmd_reg); -} - -static u8 arasan_nand_get_addrcycle(struct mtd_info *mtd) -{ - u8 addrcycles; - struct nand_chip *chip = mtd_to_nand(mtd); - - switch (curr_cmd->addr_cycles) { - case NAND_ADDR_CYCL_NONE: - addrcycles = 0; - break; - case NAND_ADDR_CYCL_ONE: - addrcycles = 1; - break; - case NAND_ADDR_CYCL_ROW: - addrcycles = chip->onfi_params.addr_cycles & - ARASAN_NAND_ROW_ADDR_CYCL_MASK; - break; - case NAND_ADDR_CYCL_COL: - addrcycles = (chip->onfi_params.addr_cycles & - ARASAN_NAND_COL_ADDR_CYCL_MASK) >> - ARASAN_NAND_COL_ADDR_CYCL_SHIFT; - break; - case NAND_ADDR_CYCL_BOTH: - addrcycles = chip->onfi_params.addr_cycles & - ARASAN_NAND_ROW_ADDR_CYCL_MASK; - addrcycles += (chip->onfi_params.addr_cycles & - ARASAN_NAND_COL_ADDR_CYCL_MASK) >> - ARASAN_NAND_COL_ADDR_CYCL_SHIFT; - break; - default: - addrcycles = ARASAN_NAND_INVALID_ADDR_CYCL; - break; - } - return addrcycles; -} - -static int arasan_nand_read_page(struct mtd_info *mtd, u8 *buf, u32 size) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct arasan_nand_info *nand = nand_get_controller_data(chip); - u32 reg_val, i, pktsize, pktnum; - u32 *bufptr = (u32 *)buf; - u32 timeout; - u32 rdcount = 0; - u8 addr_cycles; - - if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K) - pktsize = ARASAN_NAND_PKTSIZE_1K; - else - pktsize = ARASAN_NAND_PKTSIZE_512; - - if (size % pktsize) - pktnum = size/pktsize + 1; - else - pktnum = size/pktsize; - - reg_val = readl(&arasan_nand_base->intsts_enr); - reg_val |= ARASAN_NAND_INT_STS_ERR_EN_MASK | - ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK; - writel(reg_val, &arasan_nand_base->intsts_enr); - - reg_val = readl(&arasan_nand_base->pkt_reg); - reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | - ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); - reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | - pktsize; - writel(reg_val, &arasan_nand_base->pkt_reg); - - if (!nand->on_die_ecc_enabled) { - arasan_nand_enable_ecc(); - addr_cycles = arasan_nand_get_addrcycle(mtd); - if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) - return ERR_ADDR_CYCLE; - - writel((NAND_CMD_RNDOUTSTART << ARASAN_NAND_CMD_CMD2_SHIFT) | - NAND_CMD_RNDOUT | (addr_cycles << - ARASAN_NAND_CMD_ADDR_CYCL_SHIFT), - &arasan_nand_base->ecc_sprcmd_reg); - } - writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); - - while (rdcount < pktnum) { - timeout = ARASAN_NAND_POLL_TIMEOUT; - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) { - udelay(1); - timeout--; - } - if (!timeout) { - puts("arasan_read_page: timedout:Buff RDY\n"); - return -ETIMEDOUT; - } - - rdcount++; - - if (pktnum == rdcount) { - reg_val = readl(&arasan_nand_base->intsts_enr); - reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; - writel(reg_val, &arasan_nand_base->intsts_enr); - } else { - reg_val = readl(&arasan_nand_base->intsts_enr); - writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, - &arasan_nand_base->intsts_enr); - } - reg_val = readl(&arasan_nand_base->intsts_reg); - writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, - &arasan_nand_base->intsts_reg); - - for (i = 0; i < pktsize/4; i++) - bufptr[i] = readl(&arasan_nand_base->buf_dataport); - - - bufptr += pktsize/4; - - if (rdcount >= pktnum) - break; - - writel(ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, - &arasan_nand_base->intsts_enr); - } - - timeout = ARASAN_NAND_POLL_TIMEOUT; - - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { - udelay(1); - timeout--; - } - if (!timeout) { - puts("arasan rd_page timedout:Xfer CMPLT\n"); - return -ETIMEDOUT; - } - - reg_val = readl(&arasan_nand_base->intsts_enr); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->intsts_reg); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_reg); - - if (!nand->on_die_ecc_enabled) { - if (readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK) { - printf("arasan rd_page:sbiterror\n"); - return -1; - } - - if (readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_ERR_EN_MASK) { - mtd->ecc_stats.failed++; - printf("arasan rd_page:multibiterror\n"); - return -1; - } - } - - return 0; -} - -static int arasan_nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, int oob_required, int page) -{ - int status; - - status = arasan_nand_read_page(mtd, buf, (mtd->writesize)); - - if (oob_required) - chip->ecc.read_oob(mtd, chip, page); - - return status; -} - -static void arasan_nand_fill_tx(const u8 *buf, int len) -{ - u32 __iomem *nand = &arasan_nand_base->buf_dataport; - - if (((unsigned long)buf & 0x3) != 0) { - if (((unsigned long)buf & 0x1) != 0) { - if (len) { - writeb(*buf, nand); - buf += 1; - len--; - } - } - - if (((unsigned long)buf & 0x3) != 0) { - if (len >= 2) { - writew(*(u16 *)buf, nand); - buf += 2; - len -= 2; - } - } - } - - while (len >= 4) { - writel(*(u32 *)buf, nand); - buf += 4; - len -= 4; - } - - if (len) { - if (len >= 2) { - writew(*(u16 *)buf, nand); - buf += 2; - len -= 2; - } - - if (len) - writeb(*buf, nand); - } -} - -static int arasan_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, int oob_required, - int page) -{ - u32 reg_val, i, pktsize, pktnum; - const u32 *bufptr = (const u32 *)buf; - u32 timeout = ARASAN_NAND_POLL_TIMEOUT; - u32 size = mtd->writesize; - u32 rdcount = 0; - u8 column_addr_cycles; - struct arasan_nand_info *nand = nand_get_controller_data(chip); - - if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K) - pktsize = ARASAN_NAND_PKTSIZE_1K; - else - pktsize = ARASAN_NAND_PKTSIZE_512; - - if (size % pktsize) - pktnum = size/pktsize + 1; - else - pktnum = size/pktsize; - - reg_val = readl(&arasan_nand_base->pkt_reg); - reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | - ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); - reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | pktsize; - writel(reg_val, &arasan_nand_base->pkt_reg); - - if (!nand->on_die_ecc_enabled) { - arasan_nand_enable_ecc(); - column_addr_cycles = (chip->onfi_params.addr_cycles & - ARASAN_NAND_COL_ADDR_CYCL_MASK) >> - ARASAN_NAND_COL_ADDR_CYCL_SHIFT; - writel((NAND_CMD_RNDIN | (column_addr_cycles << 28)), - &arasan_nand_base->ecc_sprcmd_reg); - } - writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); - - while (rdcount < pktnum) { - timeout = ARASAN_NAND_POLL_TIMEOUT; - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) { - udelay(1); - timeout--; - } - - if (!timeout) { - puts("arasan_write_page: timedout:Buff RDY\n"); - return -ETIMEDOUT; - } - - rdcount++; - - if (pktnum == rdcount) { - reg_val = readl(&arasan_nand_base->intsts_enr); - reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; - writel(reg_val, &arasan_nand_base->intsts_enr); - } else { - reg_val = readl(&arasan_nand_base->intsts_enr); - writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, - &arasan_nand_base->intsts_enr); - } - - reg_val = readl(&arasan_nand_base->intsts_reg); - writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, - &arasan_nand_base->intsts_reg); - - for (i = 0; i < pktsize/4; i++) - writel(bufptr[i], &arasan_nand_base->buf_dataport); - - bufptr += pktsize/4; - - if (rdcount >= pktnum) - break; - - writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, - &arasan_nand_base->intsts_enr); - } - - timeout = ARASAN_NAND_POLL_TIMEOUT; - - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { - udelay(1); - timeout--; - } - if (!timeout) { - puts("arasan write_page timedout:Xfer CMPLT\n"); - return -ETIMEDOUT; - } - - reg_val = readl(&arasan_nand_base->intsts_enr); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->intsts_reg); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_reg); - - if (oob_required) - chip->ecc.write_oob(mtd, chip, nand->page); - - return 0; -} - -static int arasan_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, (mtd->oobsize)); - - return 0; -} - -static int arasan_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - int status = 0; - const u8 *buf = chip->oob_poi; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - chip->write_buf(mtd, buf, mtd->oobsize); - - return status; -} - -static int arasan_nand_reset(struct arasan_nand_command_format *curr_cmd) -{ - u32 timeout = ARASAN_NAND_POLL_TIMEOUT; - u32 cmd_reg = 0; - - writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - cmd_reg = readl(&arasan_nand_base->cmd_reg); - cmd_reg &= ~ARASAN_NAND_CMD_CMD12_MASK; - - cmd_reg |= curr_cmd->cmd1 | - (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); - writel(cmd_reg, &arasan_nand_base->cmd_reg); - writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); - - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { - udelay(1); - timeout--; - } - if (!timeout) { - printf("ERROR:%s timedout\n", __func__); - return -ETIMEDOUT; - } - - writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - - writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_reg); - - return 0; -} - -static u8 arasan_nand_page(struct mtd_info *mtd) -{ - u8 page_val = 0; - - switch (mtd->writesize) { - case 512: - page_val = 0; - break; - case 2048: - page_val = 1; - break; - case 4096: - page_val = 2; - break; - case 8192: - page_val = 3; - break; - case 16384: - page_val = 4; - break; - case 1024: - page_val = 5; - break; - default: - printf("%s:Pagesize>16K\n", __func__); - break; - } - - return page_val; -} - -static int arasan_nand_send_wrcmd(struct arasan_nand_command_format *curr_cmd, - int column, int page_addr, struct mtd_info *mtd) -{ - u32 reg_val, page; - u8 page_val, addr_cycles; - - writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->cmd_reg); - reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; - reg_val |= curr_cmd->cmd1 | - (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); - if (curr_cmd->cmd1 == NAND_CMD_SEQIN) { - reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK; - page_val = arasan_nand_page(mtd); - reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT); - } - - reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; - addr_cycles = arasan_nand_get_addrcycle(mtd); - - if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) - return ERR_ADDR_CYCLE; - - reg_val |= (addr_cycles << - ARASAN_NAND_CMD_ADDR_CYCL_SHIFT); - writel(reg_val, &arasan_nand_base->cmd_reg); - - if (page_addr == -1) - page_addr = 0; - - page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) & - ARASAN_NAND_MEM_ADDR1_PAGE_MASK; - column &= ARASAN_NAND_MEM_ADDR1_COL_MASK; - writel(page|column, &arasan_nand_base->memadr_reg1); - - reg_val = readl(&arasan_nand_base->memadr_reg2); - reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK; - reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT); - writel(reg_val, &arasan_nand_base->memadr_reg2); - reg_val = readl(&arasan_nand_base->memadr_reg2); - reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; - writel(reg_val, &arasan_nand_base->memadr_reg2); - - return 0; -} - -static void arasan_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) -{ - u32 reg_val; - u32 timeout = ARASAN_NAND_POLL_TIMEOUT; - - reg_val = readl(&arasan_nand_base->pkt_reg); - reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | - ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); - - reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | len; - writel(reg_val, &arasan_nand_base->pkt_reg); - writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); - - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) { - udelay(1); - timeout--; - } - - if (!timeout) - puts("ERROR:arasan_nand_write_buf timedout:Buff RDY\n"); - - reg_val = readl(&arasan_nand_base->intsts_enr); - reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; - writel(reg_val, &arasan_nand_base->intsts_enr); - writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->intsts_reg); - writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, - &arasan_nand_base->intsts_reg); - - arasan_nand_fill_tx(buf, len); - - timeout = ARASAN_NAND_POLL_TIMEOUT; - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { - udelay(1); - timeout--; - } - if (!timeout) - puts("ERROR:arasan_nand_write_buf timedout:Xfer CMPLT\n"); - - writel(readl(&arasan_nand_base->intsts_enr) | - ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - writel(readl(&arasan_nand_base->intsts_reg) | - ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_reg); -} - -static int arasan_nand_erase(struct arasan_nand_command_format *curr_cmd, - int column, int page_addr, struct mtd_info *mtd) -{ - u32 reg_val, page; - u32 timeout = ARASAN_NAND_POLL_TIMEOUT; - u8 row_addr_cycles; - - writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->cmd_reg); - reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; - reg_val |= curr_cmd->cmd1 | - (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); - row_addr_cycles = arasan_nand_get_addrcycle(mtd); - - if (row_addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) - return ERR_ADDR_CYCLE; - - reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; - reg_val |= (row_addr_cycles << - ARASAN_NAND_CMD_ADDR_CYCL_SHIFT); - - writel(reg_val, &arasan_nand_base->cmd_reg); - - page = (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) & - ARASAN_NAND_MEM_ADDR1_COL_MASK; - column = page_addr & ARASAN_NAND_MEM_ADDR1_COL_MASK; - writel(column | (page << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT), - &arasan_nand_base->memadr_reg1); - - reg_val = readl(&arasan_nand_base->memadr_reg2); - reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK; - reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT); - writel(reg_val, &arasan_nand_base->memadr_reg2); - reg_val = readl(&arasan_nand_base->memadr_reg2); - reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; - writel(reg_val, &arasan_nand_base->memadr_reg2); - writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); - - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { - udelay(1); - timeout--; - } - if (!timeout) { - printf("ERROR:%s timedout:Xfer CMPLT\n", __func__); - return -ETIMEDOUT; - } - - reg_val = readl(&arasan_nand_base->intsts_enr); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->intsts_reg); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_reg); - - return 0; -} - -static int arasan_nand_read_status(struct arasan_nand_command_format *curr_cmd, - int column, int page_addr, struct mtd_info *mtd) -{ - u32 reg_val; - u32 timeout = ARASAN_NAND_POLL_TIMEOUT; - u8 addr_cycles; - - writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->cmd_reg); - reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; - reg_val |= curr_cmd->cmd1 | - (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); - addr_cycles = arasan_nand_get_addrcycle(mtd); - - if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) - return ERR_ADDR_CYCLE; - - reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; - reg_val |= (addr_cycles << - ARASAN_NAND_CMD_ADDR_CYCL_SHIFT); - - writel(reg_val, &arasan_nand_base->cmd_reg); - - reg_val = readl(&arasan_nand_base->pkt_reg); - reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | - ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); - reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | 1; - writel(reg_val, &arasan_nand_base->pkt_reg); - - reg_val = readl(&arasan_nand_base->memadr_reg2); - reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; - writel(reg_val, &arasan_nand_base->memadr_reg2); - - writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { - udelay(1); - timeout--; - } - - if (!timeout) { - printf("ERROR:%s: timedout:Xfer CMPLT\n", __func__); - return -ETIMEDOUT; - } - - reg_val = readl(&arasan_nand_base->intsts_enr); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->intsts_reg); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_reg); - - return 0; -} - -static int arasan_nand_send_rdcmd(struct arasan_nand_command_format *curr_cmd, - int column, int page_addr, struct mtd_info *mtd) -{ - u32 reg_val, addr_cycles, page; - u8 page_val; - - reg_val = readl(&arasan_nand_base->intsts_enr); - writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, - &arasan_nand_base->intsts_enr); - - reg_val = readl(&arasan_nand_base->cmd_reg); - reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; - reg_val |= curr_cmd->cmd1 | - (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); - - if (curr_cmd->cmd1 == NAND_CMD_RNDOUT || - curr_cmd->cmd1 == NAND_CMD_READ0) { - reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK; - page_val = arasan_nand_page(mtd); - reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT); - } - - reg_val &= ~ARASAN_NAND_CMD_ECC_ON_MASK; - - reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; - - addr_cycles = arasan_nand_get_addrcycle(mtd); - - if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) - return ERR_ADDR_CYCLE; - - reg_val |= (addr_cycles << 28); - writel(reg_val, &arasan_nand_base->cmd_reg); - - if (page_addr == -1) - page_addr = 0; - - page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) & - ARASAN_NAND_MEM_ADDR1_PAGE_MASK; - column &= ARASAN_NAND_MEM_ADDR1_COL_MASK; - writel(page | column, &arasan_nand_base->memadr_reg1); - - reg_val = readl(&arasan_nand_base->memadr_reg2); - reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK; - reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT); - writel(reg_val, &arasan_nand_base->memadr_reg2); - - reg_val = readl(&arasan_nand_base->memadr_reg2); - reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; - writel(reg_val, &arasan_nand_base->memadr_reg2); - buf_index = 0; - - return 0; -} - -static void arasan_nand_read_buf(struct mtd_info *mtd, u8 *buf, int size) -{ - u32 reg_val, i; - u32 *bufptr = (u32 *)buf; - u32 timeout = ARASAN_NAND_POLL_TIMEOUT; - - reg_val = readl(&arasan_nand_base->pkt_reg); - reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | - ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); - reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | size; - writel(reg_val, &arasan_nand_base->pkt_reg); - - writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); - - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) { - udelay(1); - timeout--; - } - - if (!timeout) - puts("ERROR:arasan_nand_read_buf timedout:Buff RDY\n"); - - reg_val = readl(&arasan_nand_base->intsts_enr); - reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; - writel(reg_val, &arasan_nand_base->intsts_enr); - - writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->intsts_reg); - writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, - &arasan_nand_base->intsts_reg); - - buf_index = 0; - for (i = 0; i < size / 4; i++) - bufptr[i] = readl(&arasan_nand_base->buf_dataport); - - if (size & 0x03) - bufptr[i] = readl(&arasan_nand_base->buf_dataport); - - timeout = ARASAN_NAND_POLL_TIMEOUT; - - while (!(readl(&arasan_nand_base->intsts_reg) & - ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { - udelay(1); - timeout--; - } - - if (!timeout) - puts("ERROR:arasan_nand_read_buf timedout:Xfer CMPLT\n"); - - reg_val = readl(&arasan_nand_base->intsts_enr); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - reg_val = readl(&arasan_nand_base->intsts_reg); - writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_reg); -} - -static u8 arasan_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - u32 size; - u8 val; - struct nand_onfi_params *p; - - if (buf_index == 0) { - p = &chip->onfi_params; - if (curr_cmd->cmd1 == NAND_CMD_READID) - size = 4; - else if (curr_cmd->cmd1 == NAND_CMD_PARAM) - size = sizeof(struct nand_onfi_params); - else if (curr_cmd->cmd1 == NAND_CMD_RNDOUT) - size = le16_to_cpu(p->ext_param_page_length) * 16; - else if (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) - size = 4; - else if (curr_cmd->cmd1 == NAND_CMD_STATUS) - return readb(&arasan_nand_base->flash_sts_reg); - else - size = 8; - chip->read_buf(mtd, &buf_data[0], size); - } - - val = *(&buf_data[0] + buf_index); - buf_index++; - - return val; -} - -static void arasan_nand_cmd_function(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - u32 i, ret = 0; - struct nand_chip *chip = mtd_to_nand(mtd); - struct arasan_nand_info *nand = nand_get_controller_data(chip); - - curr_cmd = NULL; - writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, - &arasan_nand_base->intsts_enr); - - if ((command == NAND_CMD_READOOB) && - (mtd->writesize > 512)) { - column += mtd->writesize; - command = NAND_CMD_READ0; - } - - /* Get the command format */ - for (i = 0; (arasan_nand_commands[i].cmd1 != NAND_CMD_NONE || - arasan_nand_commands[i].cmd2 != NAND_CMD_NONE); i++) { - if (command == arasan_nand_commands[i].cmd1) { - curr_cmd = &arasan_nand_commands[i]; - break; - } - } - - if (curr_cmd == NULL) { - printf("Unsupported Command; 0x%x\n", command); - return; - } - - if (curr_cmd->cmd1 == NAND_CMD_RESET) - ret = arasan_nand_reset(curr_cmd); - - if ((curr_cmd->cmd1 == NAND_CMD_READID) || - (curr_cmd->cmd1 == NAND_CMD_PARAM) || - (curr_cmd->cmd1 == NAND_CMD_RNDOUT) || - (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) || - (curr_cmd->cmd1 == NAND_CMD_READ0)) - ret = arasan_nand_send_rdcmd(curr_cmd, column, page_addr, mtd); - - if ((curr_cmd->cmd1 == NAND_CMD_SET_FEATURES) || - (curr_cmd->cmd1 == NAND_CMD_SEQIN)) { - nand->page = page_addr; - ret = arasan_nand_send_wrcmd(curr_cmd, column, page_addr, mtd); - } - - if (curr_cmd->cmd1 == NAND_CMD_ERASE1) - ret = arasan_nand_erase(curr_cmd, column, page_addr, mtd); - - if (curr_cmd->cmd1 == NAND_CMD_STATUS) - ret = arasan_nand_read_status(curr_cmd, column, page_addr, mtd); - - if (ret != 0) - printf("ERROR:%s:command:0x%x\n", __func__, curr_cmd->cmd1); -} - -static void arasan_check_ondie(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct arasan_nand_info *nand = nand_get_controller_data(nand_chip); - u8 maf_id, dev_id; - u8 get_feature[4]; - u8 set_feature[4] = {ENABLE_ONDIE_ECC, 0x00, 0x00, 0x00}; - u32 i; - - /* Send the command for reading device ID */ - nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0, -1); - - /* Read manufacturer and device IDs */ - maf_id = nand_chip->read_byte(mtd); - dev_id = nand_chip->read_byte(mtd); - - if ((maf_id == NAND_MFR_MICRON) && - ((dev_id == 0xf1) || (dev_id == 0xa1) || (dev_id == 0xb1) || - (dev_id == 0xaa) || (dev_id == 0xba) || (dev_id == 0xda) || - (dev_id == 0xca) || (dev_id == 0xac) || (dev_id == 0xbc) || - (dev_id == 0xdc) || (dev_id == 0xcc) || (dev_id == 0xa3) || - (dev_id == 0xb3) || (dev_id == 0xd3) || (dev_id == 0xc3))) { - nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, - ONDIE_ECC_FEATURE_ADDR, -1); - - nand_chip->write_buf(mtd, &set_feature[0], 4); - nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, - ONDIE_ECC_FEATURE_ADDR, -1); - - for (i = 0; i < 4; i++) - get_feature[i] = nand_chip->read_byte(mtd); - - if (get_feature[0] & ENABLE_ONDIE_ECC) - nand->on_die_ecc_enabled = true; - else - printf("%s: Unable to enable OnDie ECC\n", __func__); - - /* Use the BBT pattern descriptors */ - nand_chip->bbt_td = &bbt_main_descr; - nand_chip->bbt_md = &bbt_mirror_descr; - } -} - -static int arasan_nand_ecc_init(struct mtd_info *mtd) -{ - int found = -1; - u32 regval, eccpos_start, i, eccaddr; - struct nand_chip *nand_chip = mtd_to_nand(mtd); - - for (i = 0; i < ARRAY_SIZE(ecc_matrix); i++) { - if ((ecc_matrix[i].pagesize == mtd->writesize) && - (ecc_matrix[i].ecc_codeword_size >= - nand_chip->ecc_step_ds)) { - if (ecc_matrix[i].eccbits >= - nand_chip->ecc_strength_ds) { - found = i; - break; - } - found = i; - } - } - - if (found < 0) - return 1; - - eccaddr = mtd->writesize + mtd->oobsize - - ecc_matrix[found].eccsize; - - regval = eccaddr | - (ecc_matrix[found].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) | - (ecc_matrix[found].bch << ARASAN_NAND_ECC_BCH_SHIFT); - writel(regval, &arasan_nand_base->ecc_reg); - - if (ecc_matrix[found].bch) { - regval = readl(&arasan_nand_base->memadr_reg2); - regval &= ~ARASAN_NAND_MEM_ADDR2_BCH_MASK; - regval |= (ecc_matrix[found].bchval << - ARASAN_NAND_MEM_ADDR2_BCH_SHIFT); - writel(regval, &arasan_nand_base->memadr_reg2); - } - - nand_oob.eccbytes = ecc_matrix[found].eccsize; - eccpos_start = mtd->oobsize - nand_oob.eccbytes; - - for (i = 0; i < nand_oob.eccbytes; i++) - nand_oob.eccpos[i] = eccpos_start + i; - - nand_oob.oobfree[0].offset = 2; - nand_oob.oobfree[0].length = eccpos_start - 2; - - nand_chip->ecc.size = ecc_matrix[found].ecc_codeword_size; - nand_chip->ecc.strength = ecc_matrix[found].eccbits; - nand_chip->ecc.bytes = ecc_matrix[found].eccsize; - nand_chip->ecc.layout = &nand_oob; - - return 0; -} - -static int arasan_nand_init(struct nand_chip *nand_chip, int devnum) -{ - struct arasan_nand_info *nand; - struct mtd_info *mtd; - int err = -1; - - nand = calloc(1, sizeof(struct arasan_nand_info)); - if (!nand) { - printf("%s: failed to allocate\n", __func__); - return err; - } - - nand->nand_base = arasan_nand_base; - mtd = nand_to_mtd(nand_chip); - nand_set_controller_data(nand_chip, nand); - - /* Set the driver entry points for MTD */ - nand_chip->cmdfunc = arasan_nand_cmd_function; - nand_chip->select_chip = arasan_nand_select_chip; - nand_chip->read_byte = arasan_nand_read_byte; - - /* Buffer read/write routines */ - nand_chip->read_buf = arasan_nand_read_buf; - nand_chip->write_buf = arasan_nand_write_buf; - nand_chip->bbt_options = NAND_BBT_USE_FLASH; - - writel(0x0, &arasan_nand_base->cmd_reg); - writel(0x0, &arasan_nand_base->pgm_reg); - - /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1, NULL)) { - printf("%s: nand_scan_ident failed\n", __func__); - goto fail; - } - - nand_chip->ecc.mode = NAND_ECC_HW; - nand_chip->ecc.hwctl = NULL; - nand_chip->ecc.read_page = arasan_nand_read_page_hwecc; - nand_chip->ecc.write_page = arasan_nand_write_page_hwecc; - nand_chip->ecc.read_oob = arasan_nand_read_oob; - nand_chip->ecc.write_oob = arasan_nand_write_oob; - - arasan_check_ondie(mtd); - - /* - * If on die supported, then give priority to on-die ecc and use - * it instead of controller ecc. - */ - if (nand->on_die_ecc_enabled) { - nand_chip->ecc.strength = 1; - nand_chip->ecc.size = mtd->writesize; - nand_chip->ecc.bytes = 0; - nand_chip->ecc.layout = &ondie_nand_oob_64; - } else { - if (arasan_nand_ecc_init(mtd)) { - printf("%s: nand_ecc_init failed\n", __func__); - goto fail; - } - } - - if (nand_scan_tail(mtd)) { - printf("%s: nand_scan_tail failed\n", __func__); - goto fail; - } - - if (nand_register(devnum, mtd)) { - printf("Nand Register Fail\n"); - goto fail; - } - - return 0; -fail: - free(nand); - return err; -} - -void board_nand_init(void) -{ - struct nand_chip *nand = &nand_chip[0]; - - if (arasan_nand_init(nand, 0)) - puts("NAND init failed\n"); -} diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c deleted file mode 100644 index a5b76e1aa0..0000000000 --- a/drivers/mtd/nand/atmel_nand.c +++ /dev/null @@ -1,1511 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2007-2008 - * Stelian Pop - * Lead Tech Design - * - * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas - * - * Add Programmable Multibit ECC support for various AT91 SoC - * (C) Copyright 2012 ATMEL, Hong Xu - */ - -#include -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_ATMEL_NAND_HWECC - -/* Register access macros */ -#define ecc_readl(add, reg) \ - readl(add + ATMEL_ECC_##reg) -#define ecc_writel(add, reg, value) \ - writel((value), add + ATMEL_ECC_##reg) - -#include "atmel_nand_ecc.h" /* Hardware ECC registers */ - -#ifdef CONFIG_ATMEL_NAND_HW_PMECC - -#ifdef CONFIG_SPL_BUILD -#undef CONFIG_SYS_NAND_ONFI_DETECTION -#endif - -struct atmel_nand_host { - struct pmecc_regs __iomem *pmecc; - struct pmecc_errloc_regs __iomem *pmerrloc; - void __iomem *pmecc_rom_base; - - u8 pmecc_corr_cap; - u16 pmecc_sector_size; - u32 pmecc_index_table_offset; - u32 pmecc_version; - - int pmecc_bytes_per_sector; - int pmecc_sector_number; - int pmecc_degree; /* Degree of remainders */ - int pmecc_cw_len; /* Length of codeword */ - - /* lookup table for alpha_to and index_of */ - void __iomem *pmecc_alpha_to; - void __iomem *pmecc_index_of; - - /* data for pmecc computation */ - int16_t *pmecc_smu; - int16_t *pmecc_partial_syn; - int16_t *pmecc_si; - int16_t *pmecc_lmu; /* polynomal order */ - int *pmecc_mu; - int *pmecc_dmu; - int *pmecc_delta; -}; - -static struct atmel_nand_host pmecc_host; -static struct nand_ecclayout atmel_pmecc_oobinfo; - -/* - * Return number of ecc bytes per sector according to sector size and - * correction capability - * - * Following table shows what at91 PMECC supported: - * Correction Capability Sector_512_bytes Sector_1024_bytes - * ===================== ================ ================= - * 2-bits 4-bytes 4-bytes - * 4-bits 7-bytes 7-bytes - * 8-bits 13-bytes 14-bytes - * 12-bits 20-bytes 21-bytes - * 24-bits 39-bytes 42-bytes - * 32-bits 52-bytes 56-bytes - */ -static int pmecc_get_ecc_bytes(int cap, int sector_size) -{ - int m = 12 + sector_size / 512; - return (m * cap + 7) / 8; -} - -static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, - int oobsize, int ecc_len) -{ - int i; - - layout->eccbytes = ecc_len; - - /* ECC will occupy the last ecc_len bytes continuously */ - for (i = 0; i < ecc_len; i++) - layout->eccpos[i] = oobsize - ecc_len + i; - - layout->oobfree[0].offset = 2; - layout->oobfree[0].length = - oobsize - ecc_len - layout->oobfree[0].offset; -} - -static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) -{ - int table_size; - - table_size = host->pmecc_sector_size == 512 ? - PMECC_INDEX_TABLE_SIZE_512 : PMECC_INDEX_TABLE_SIZE_1024; - - /* the ALPHA lookup table is right behind the INDEX lookup table. */ - return host->pmecc_rom_base + host->pmecc_index_table_offset + - table_size * sizeof(int16_t); -} - -static void pmecc_data_free(struct atmel_nand_host *host) -{ - free(host->pmecc_partial_syn); - free(host->pmecc_si); - free(host->pmecc_lmu); - free(host->pmecc_smu); - free(host->pmecc_mu); - free(host->pmecc_dmu); - free(host->pmecc_delta); -} - -static int pmecc_data_alloc(struct atmel_nand_host *host) -{ - const int cap = host->pmecc_corr_cap; - int size; - - size = (2 * cap + 1) * sizeof(int16_t); - host->pmecc_partial_syn = malloc(size); - host->pmecc_si = malloc(size); - host->pmecc_lmu = malloc((cap + 1) * sizeof(int16_t)); - host->pmecc_smu = malloc((cap + 2) * size); - - size = (cap + 1) * sizeof(int); - host->pmecc_mu = malloc(size); - host->pmecc_dmu = malloc(size); - host->pmecc_delta = malloc(size); - - if (host->pmecc_partial_syn && - host->pmecc_si && - host->pmecc_lmu && - host->pmecc_smu && - host->pmecc_mu && - host->pmecc_dmu && - host->pmecc_delta) - return 0; - - /* error happened */ - pmecc_data_free(host); - return -ENOMEM; - -} - -static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct atmel_nand_host *host = nand_get_controller_data(nand_chip); - int i; - uint32_t value; - - /* Fill odd syndromes */ - for (i = 0; i < host->pmecc_corr_cap; i++) { - value = pmecc_readl(host->pmecc, rem_port[sector].rem[i / 2]); - if (i & 1) - value >>= 16; - value &= 0xffff; - host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value; - } -} - -static void pmecc_substitute(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct atmel_nand_host *host = nand_get_controller_data(nand_chip); - int16_t __iomem *alpha_to = host->pmecc_alpha_to; - int16_t __iomem *index_of = host->pmecc_index_of; - int16_t *partial_syn = host->pmecc_partial_syn; - const int cap = host->pmecc_corr_cap; - int16_t *si; - int i, j; - - /* si[] is a table that holds the current syndrome value, - * an element of that table belongs to the field - */ - si = host->pmecc_si; - - memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1)); - - /* Computation 2t syndromes based on S(x) */ - /* Odd syndromes */ - for (i = 1; i < 2 * cap; i += 2) { - for (j = 0; j < host->pmecc_degree; j++) { - if (partial_syn[i] & (0x1 << j)) - si[i] = readw(alpha_to + i * j) ^ si[i]; - } - } - /* Even syndrome = (Odd syndrome) ** 2 */ - for (i = 2, j = 1; j <= cap; i = ++j << 1) { - if (si[j] == 0) { - si[i] = 0; - } else { - int16_t tmp; - - tmp = readw(index_of + si[j]); - tmp = (tmp * 2) % host->pmecc_cw_len; - si[i] = readw(alpha_to + tmp); - } - } -} - -/* - * This function defines a Berlekamp iterative procedure for - * finding the value of the error location polynomial. - * The input is si[], initialize by pmecc_substitute(). - * The output is smu[][]. - * - * This function is written according to chip datasheet Chapter: - * Find the Error Location Polynomial Sigma(x) of Section: - * Programmable Multibit ECC Control (PMECC). - */ -static void pmecc_get_sigma(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct atmel_nand_host *host = nand_get_controller_data(nand_chip); - - int16_t *lmu = host->pmecc_lmu; - int16_t *si = host->pmecc_si; - int *mu = host->pmecc_mu; - int *dmu = host->pmecc_dmu; /* Discrepancy */ - int *delta = host->pmecc_delta; /* Delta order */ - int cw_len = host->pmecc_cw_len; - const int16_t cap = host->pmecc_corr_cap; - const int num = 2 * cap + 1; - int16_t __iomem *index_of = host->pmecc_index_of; - int16_t __iomem *alpha_to = host->pmecc_alpha_to; - int i, j, k; - uint32_t dmu_0_count, tmp; - int16_t *smu = host->pmecc_smu; - - /* index of largest delta */ - int ro; - int largest; - int diff; - - /* Init the Sigma(x) */ - memset(smu, 0, sizeof(int16_t) * ARRAY_SIZE(smu)); - - dmu_0_count = 0; - - /* First Row */ - - /* Mu */ - mu[0] = -1; - - smu[0] = 1; - - /* discrepancy set to 1 */ - dmu[0] = 1; - /* polynom order set to 0 */ - lmu[0] = 0; - /* delta[0] = (mu[0] * 2 - lmu[0]) >> 1; */ - delta[0] = -1; - - /* Second Row */ - - /* Mu */ - mu[1] = 0; - /* Sigma(x) set to 1 */ - smu[num] = 1; - - /* discrepancy set to S1 */ - dmu[1] = si[1]; - - /* polynom order set to 0 */ - lmu[1] = 0; - - /* delta[1] = (mu[1] * 2 - lmu[1]) >> 1; */ - delta[1] = 0; - - for (i = 1; i <= cap; i++) { - mu[i + 1] = i << 1; - /* Begin Computing Sigma (Mu+1) and L(mu) */ - /* check if discrepancy is set to 0 */ - if (dmu[i] == 0) { - dmu_0_count++; - - tmp = ((cap - (lmu[i] >> 1) - 1) / 2); - if ((cap - (lmu[i] >> 1) - 1) & 0x1) - tmp += 2; - else - tmp += 1; - - if (dmu_0_count == tmp) { - for (j = 0; j <= (lmu[i] >> 1) + 1; j++) - smu[(cap + 1) * num + j] = - smu[i * num + j]; - - lmu[cap + 1] = lmu[i]; - return; - } - - /* copy polynom */ - for (j = 0; j <= lmu[i] >> 1; j++) - smu[(i + 1) * num + j] = smu[i * num + j]; - - /* copy previous polynom order to the next */ - lmu[i + 1] = lmu[i]; - } else { - ro = 0; - largest = -1; - /* find largest delta with dmu != 0 */ - for (j = 0; j < i; j++) { - if ((dmu[j]) && (delta[j] > largest)) { - largest = delta[j]; - ro = j; - } - } - - /* compute difference */ - diff = (mu[i] - mu[ro]); - - /* Compute degree of the new smu polynomial */ - if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff)) - lmu[i + 1] = lmu[i]; - else - lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2; - - /* Init smu[i+1] with 0 */ - for (k = 0; k < num; k++) - smu[(i + 1) * num + k] = 0; - - /* Compute smu[i+1] */ - for (k = 0; k <= lmu[ro] >> 1; k++) { - int16_t a, b, c; - - if (!(smu[ro * num + k] && dmu[i])) - continue; - a = readw(index_of + dmu[i]); - b = readw(index_of + dmu[ro]); - c = readw(index_of + smu[ro * num + k]); - tmp = a + (cw_len - b) + c; - a = readw(alpha_to + tmp % cw_len); - smu[(i + 1) * num + (k + diff)] = a; - } - - for (k = 0; k <= lmu[i] >> 1; k++) - smu[(i + 1) * num + k] ^= smu[i * num + k]; - } - - /* End Computing Sigma (Mu+1) and L(mu) */ - /* In either case compute delta */ - delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1; - - /* Do not compute discrepancy for the last iteration */ - if (i >= cap) - continue; - - for (k = 0; k <= (lmu[i + 1] >> 1); k++) { - tmp = 2 * (i - 1); - if (k == 0) { - dmu[i + 1] = si[tmp + 3]; - } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) { - int16_t a, b, c; - a = readw(index_of + - smu[(i + 1) * num + k]); - b = si[2 * (i - 1) + 3 - k]; - c = readw(index_of + b); - tmp = a + c; - tmp %= cw_len; - dmu[i + 1] = readw(alpha_to + tmp) ^ - dmu[i + 1]; - } - } - } -} - -static int pmecc_err_location(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct atmel_nand_host *host = nand_get_controller_data(nand_chip); - const int cap = host->pmecc_corr_cap; - const int num = 2 * cap + 1; - int sector_size = host->pmecc_sector_size; - int err_nbr = 0; /* number of error */ - int roots_nbr; /* number of roots */ - int i; - uint32_t val; - int16_t *smu = host->pmecc_smu; - int timeout = PMECC_MAX_TIMEOUT_US; - - pmecc_writel(host->pmerrloc, eldis, PMERRLOC_DISABLE); - - for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) { - pmecc_writel(host->pmerrloc, sigma[i], - smu[(cap + 1) * num + i]); - err_nbr++; - } - - val = PMERRLOC_ELCFG_NUM_ERRORS(err_nbr - 1); - if (sector_size == 1024) - val |= PMERRLOC_ELCFG_SECTOR_1024; - - pmecc_writel(host->pmerrloc, elcfg, val); - pmecc_writel(host->pmerrloc, elen, - sector_size * 8 + host->pmecc_degree * cap); - - while (--timeout) { - if (pmecc_readl(host->pmerrloc, elisr) & PMERRLOC_CALC_DONE) - break; - WATCHDOG_RESET(); - udelay(1); - } - - if (!timeout) { - dev_err(host->dev, "atmel_nand : Timeout to calculate PMECC error location\n"); - return -1; - } - - roots_nbr = (pmecc_readl(host->pmerrloc, elisr) & PMERRLOC_ERR_NUM_MASK) - >> 8; - /* Number of roots == degree of smu hence <= cap */ - if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1) - return err_nbr - 1; - - /* Number of roots does not match the degree of smu - * unable to correct error */ - return -1; -} - -static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, - int sector_num, int extra_bytes, int err_nbr) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct atmel_nand_host *host = nand_get_controller_data(nand_chip); - int i = 0; - int byte_pos, bit_pos, sector_size, pos; - uint32_t tmp; - uint8_t err_byte; - - sector_size = host->pmecc_sector_size; - - while (err_nbr) { - tmp = pmecc_readl(host->pmerrloc, el[i]) - 1; - byte_pos = tmp / 8; - bit_pos = tmp % 8; - - if (byte_pos >= (sector_size + extra_bytes)) - BUG(); /* should never happen */ - - if (byte_pos < sector_size) { - err_byte = *(buf + byte_pos); - *(buf + byte_pos) ^= (1 << bit_pos); - - pos = sector_num * host->pmecc_sector_size + byte_pos; - dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", - pos, bit_pos, err_byte, *(buf + byte_pos)); - } else { - /* Bit flip in OOB area */ - tmp = sector_num * host->pmecc_bytes_per_sector - + (byte_pos - sector_size); - err_byte = ecc[tmp]; - ecc[tmp] ^= (1 << bit_pos); - - pos = tmp + nand_chip->ecc.layout->eccpos[0]; - dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", - pos, bit_pos, err_byte, ecc[tmp]); - } - - i++; - err_nbr--; - } - - return; -} - -static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, - u8 *ecc) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct atmel_nand_host *host = nand_get_controller_data(nand_chip); - int i, err_nbr, eccbytes; - uint8_t *buf_pos; - - /* SAMA5D4 PMECC IP can correct errors for all 0xff page */ - if (host->pmecc_version >= PMECC_VERSION_SAMA5D4) - goto normal_check; - - eccbytes = nand_chip->ecc.bytes; - for (i = 0; i < eccbytes; i++) - if (ecc[i] != 0xff) - goto normal_check; - /* Erased page, return OK */ - return 0; - -normal_check: - for (i = 0; i < host->pmecc_sector_number; i++) { - err_nbr = 0; - if (pmecc_stat & 0x1) { - buf_pos = buf + i * host->pmecc_sector_size; - - pmecc_gen_syndrome(mtd, i); - pmecc_substitute(mtd); - pmecc_get_sigma(mtd); - - err_nbr = pmecc_err_location(mtd); - if (err_nbr == -1) { - dev_err(host->dev, "PMECC: Too many errors\n"); - mtd->ecc_stats.failed++; - return -EBADMSG; - } else { - pmecc_correct_data(mtd, buf_pos, ecc, i, - host->pmecc_bytes_per_sector, err_nbr); - mtd->ecc_stats.corrected += err_nbr; - } - } - pmecc_stat >>= 1; - } - - return 0; -} - -static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -{ - struct atmel_nand_host *host = nand_get_controller_data(chip); - int eccsize = chip->ecc.size; - uint8_t *oob = chip->oob_poi; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint32_t stat; - int timeout = PMECC_MAX_TIMEOUT_US; - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_RST); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DISABLE); - pmecc_writel(host->pmecc, cfg, ((pmecc_readl(host->pmecc, cfg)) - & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE); - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_ENABLE); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DATA); - - chip->read_buf(mtd, buf, eccsize); - chip->read_buf(mtd, oob, mtd->oobsize); - - while (--timeout) { - if (!(pmecc_readl(host->pmecc, sr) & PMECC_SR_BUSY)) - break; - WATCHDOG_RESET(); - udelay(1); - } - - if (!timeout) { - dev_err(host->dev, "atmel_nand : Timeout to read PMECC page\n"); - return -1; - } - - stat = pmecc_readl(host->pmecc, isr); - if (stat != 0) - if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0) - return -EBADMSG; - - return 0; -} - -static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, - int oob_required, int page) -{ - struct atmel_nand_host *host = nand_get_controller_data(chip); - uint32_t *eccpos = chip->ecc.layout->eccpos; - int i, j; - int timeout = PMECC_MAX_TIMEOUT_US; - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_RST); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DISABLE); - - pmecc_writel(host->pmecc, cfg, (pmecc_readl(host->pmecc, cfg) | - PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE); - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_ENABLE); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DATA); - - chip->write_buf(mtd, (u8 *)buf, mtd->writesize); - - while (--timeout) { - if (!(pmecc_readl(host->pmecc, sr) & PMECC_SR_BUSY)) - break; - WATCHDOG_RESET(); - udelay(1); - } - - if (!timeout) { - dev_err(host->dev, "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n"); - goto out; - } - - for (i = 0; i < host->pmecc_sector_number; i++) { - for (j = 0; j < host->pmecc_bytes_per_sector; j++) { - int pos; - - pos = i * host->pmecc_bytes_per_sector + j; - chip->oob_poi[eccpos[pos]] = - pmecc_readb(host->pmecc, ecc_port[i].ecc[j]); - } - } - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); -out: - return 0; -} - -static void atmel_pmecc_core_init(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct atmel_nand_host *host = nand_get_controller_data(nand_chip); - uint32_t val = 0; - struct nand_ecclayout *ecc_layout; - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_RST); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DISABLE); - - switch (host->pmecc_corr_cap) { - case 2: - val = PMECC_CFG_BCH_ERR2; - break; - case 4: - val = PMECC_CFG_BCH_ERR4; - break; - case 8: - val = PMECC_CFG_BCH_ERR8; - break; - case 12: - val = PMECC_CFG_BCH_ERR12; - break; - case 24: - val = PMECC_CFG_BCH_ERR24; - break; - case 32: - val = PMECC_CFG_BCH_ERR32; - break; - } - - if (host->pmecc_sector_size == 512) - val |= PMECC_CFG_SECTOR512; - else if (host->pmecc_sector_size == 1024) - val |= PMECC_CFG_SECTOR1024; - - switch (host->pmecc_sector_number) { - case 1: - val |= PMECC_CFG_PAGE_1SECTOR; - break; - case 2: - val |= PMECC_CFG_PAGE_2SECTORS; - break; - case 4: - val |= PMECC_CFG_PAGE_4SECTORS; - break; - case 8: - val |= PMECC_CFG_PAGE_8SECTORS; - break; - } - - val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE - | PMECC_CFG_AUTO_DISABLE); - pmecc_writel(host->pmecc, cfg, val); - - ecc_layout = nand_chip->ecc.layout; - pmecc_writel(host->pmecc, sarea, mtd->oobsize - 1); - pmecc_writel(host->pmecc, saddr, ecc_layout->eccpos[0]); - pmecc_writel(host->pmecc, eaddr, - ecc_layout->eccpos[ecc_layout->eccbytes - 1]); - /* See datasheet about PMECC Clock Control Register */ - pmecc_writel(host->pmecc, clk, PMECC_CLK_133MHZ); - pmecc_writel(host->pmecc, idr, 0xff); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_ENABLE); -} - -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION -/* - * pmecc_choose_ecc - Get ecc requirement from ONFI parameters. If - * pmecc_corr_cap or pmecc_sector_size is 0, then set it as - * ONFI ECC parameters. - * @host: point to an atmel_nand_host structure. - * if host->pmecc_corr_cap is 0 then set it as the ONFI ecc_bits. - * if host->pmecc_sector_size is 0 then set it as the ONFI sector_size. - * @chip: point to an nand_chip structure. - * @cap: store the ONFI ECC correct bits capbility - * @sector_size: in how many bytes that ONFI require to correct @ecc_bits - * - * Return 0 if success. otherwise return the error code. - */ -static int pmecc_choose_ecc(struct atmel_nand_host *host, - struct nand_chip *chip, - int *cap, int *sector_size) -{ - /* Get ECC requirement from ONFI parameters */ - *cap = *sector_size = 0; - if (chip->onfi_version) { - *cap = chip->ecc_strength_ds; - *sector_size = chip->ecc_step_ds; - pr_debug("ONFI params, minimum required ECC: %d bits in %d bytes\n", - *cap, *sector_size); - } - - if (*cap == 0 && *sector_size == 0) { - /* Non-ONFI compliant */ - dev_info(host->dev, "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes\n"); - *cap = 2; - *sector_size = 512; - } - - /* If head file doesn't specify then use the one in ONFI parameters */ - if (host->pmecc_corr_cap == 0) { - /* use the most fitable ecc bits (the near bigger one ) */ - if (*cap <= 2) - host->pmecc_corr_cap = 2; - else if (*cap <= 4) - host->pmecc_corr_cap = 4; - else if (*cap <= 8) - host->pmecc_corr_cap = 8; - else if (*cap <= 12) - host->pmecc_corr_cap = 12; - else if (*cap <= 24) - host->pmecc_corr_cap = 24; - else -#ifdef CONFIG_SAMA5D2 - host->pmecc_corr_cap = 32; -#else - host->pmecc_corr_cap = 24; -#endif - } - if (host->pmecc_sector_size == 0) { - /* use the most fitable sector size (the near smaller one ) */ - if (*sector_size >= 1024) - host->pmecc_sector_size = 1024; - else if (*sector_size >= 512) - host->pmecc_sector_size = 512; - else - return -EINVAL; - } - return 0; -} -#endif - -#if defined(NO_GALOIS_TABLE_IN_ROM) -static uint16_t *pmecc_galois_table; -static inline int deg(unsigned int poly) -{ - /* polynomial degree is the most-significant bit index */ - return fls(poly) - 1; -} - -static int build_gf_tables(int mm, unsigned int poly, - int16_t *index_of, int16_t *alpha_to) -{ - unsigned int i, x = 1; - const unsigned int k = 1 << deg(poly); - unsigned int nn = (1 << mm) - 1; - - /* primitive polynomial must be of degree m */ - if (k != (1u << mm)) - return -EINVAL; - - for (i = 0; i < nn; i++) { - alpha_to[i] = x; - index_of[x] = i; - if (i && (x == 1)) - /* polynomial is not primitive (a^i=1 with 0ecc.mode = NAND_ECC_HW; - nand->ecc.calculate = NULL; - nand->ecc.correct = NULL; - nand->ecc.hwctl = NULL; - -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION - host->pmecc_corr_cap = host->pmecc_sector_size = 0; - -#ifdef CONFIG_PMECC_CAP - host->pmecc_corr_cap = CONFIG_PMECC_CAP; -#endif -#ifdef CONFIG_PMECC_SECTOR_SIZE - host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE; -#endif - /* Get ECC requirement of ONFI parameters. And if CONFIG_PMECC_CAP or - * CONFIG_PMECC_SECTOR_SIZE not defined, then use ecc_bits, sector_size - * from ONFI. - */ - if (pmecc_choose_ecc(host, nand, &cap, §or_size)) { - dev_err(host->dev, "Required ECC %d bits in %d bytes not supported!\n", - cap, sector_size); - return -EINVAL; - } - - if (cap > host->pmecc_corr_cap) - dev_info(host->dev, "WARNING: Using different ecc correct bits(%d bit) from Nand ONFI ECC reqirement (%d bit).\n", - host->pmecc_corr_cap, cap); - if (sector_size < host->pmecc_sector_size) - dev_info(host->dev, "WARNING: Using different ecc correct sector size (%d bytes) from Nand ONFI ECC reqirement (%d bytes).\n", - host->pmecc_sector_size, sector_size); -#else /* CONFIG_SYS_NAND_ONFI_DETECTION */ - host->pmecc_corr_cap = CONFIG_PMECC_CAP; - host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE; -#endif - - cap = host->pmecc_corr_cap; - sector_size = host->pmecc_sector_size; - - /* TODO: need check whether cap & sector_size is validate */ -#if defined(NO_GALOIS_TABLE_IN_ROM) - /* - * As pmecc_rom_base is the begin of the gallois field table, So the - * index offset just set as 0. - */ - host->pmecc_index_table_offset = 0; -#else - if (host->pmecc_sector_size == 512) - host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_512; - else - host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_1024; -#endif - - pr_debug("Initialize PMECC params, cap: %d, sector: %d\n", - cap, sector_size); - - host->pmecc = (struct pmecc_regs __iomem *) ATMEL_BASE_PMECC; - host->pmerrloc = (struct pmecc_errloc_regs __iomem *) - ATMEL_BASE_PMERRLOC; -#if defined(NO_GALOIS_TABLE_IN_ROM) - pmecc_galois_table = create_lookup_table(host->pmecc_sector_size); - if (!pmecc_galois_table) { - dev_err(host->dev, "out of memory\n"); - return -ENOMEM; - } - - host->pmecc_rom_base = (void __iomem *)pmecc_galois_table; -#else - host->pmecc_rom_base = (void __iomem *) ATMEL_BASE_ROM; -#endif - - /* ECC is calculated for the whole page (1 step) */ - nand->ecc.size = mtd->writesize; - - /* set ECC page size and oob layout */ - switch (mtd->writesize) { - case 2048: - case 4096: - case 8192: - host->pmecc_degree = (sector_size == 512) ? - PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; - host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; - host->pmecc_sector_number = mtd->writesize / sector_size; - host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes( - cap, sector_size); - host->pmecc_alpha_to = pmecc_get_alpha_to(host); - host->pmecc_index_of = host->pmecc_rom_base + - host->pmecc_index_table_offset; - - nand->ecc.steps = 1; - nand->ecc.bytes = host->pmecc_bytes_per_sector * - host->pmecc_sector_number; - - if (nand->ecc.bytes > MTD_MAX_ECCPOS_ENTRIES_LARGE) { - dev_err(host->dev, "too large eccpos entries. max support ecc.bytes is %d\n", - MTD_MAX_ECCPOS_ENTRIES_LARGE); - return -EINVAL; - } - - if (nand->ecc.bytes > mtd->oobsize - PMECC_OOB_RESERVED_BYTES) { - dev_err(host->dev, "No room for ECC bytes\n"); - return -EINVAL; - } - pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, - mtd->oobsize, - nand->ecc.bytes); - nand->ecc.layout = &atmel_pmecc_oobinfo; - break; - case 512: - case 1024: - /* TODO */ - dev_err(host->dev, "Unsupported page size for PMECC, use Software ECC\n"); - default: - /* page size not handled by HW ECC */ - /* switching back to soft ECC */ - nand->ecc.mode = NAND_ECC_SOFT; - nand->ecc.read_page = NULL; - nand->ecc.postpad = 0; - nand->ecc.prepad = 0; - nand->ecc.bytes = 0; - return 0; - } - - /* Allocate data for PMECC computation */ - if (pmecc_data_alloc(host)) { - dev_err(host->dev, "Cannot allocate memory for PMECC computation!\n"); - return -ENOMEM; - } - - nand->options |= NAND_NO_SUBPAGE_WRITE; - nand->ecc.read_page = atmel_nand_pmecc_read_page; - nand->ecc.write_page = atmel_nand_pmecc_write_page; - nand->ecc.strength = cap; - - /* Check the PMECC ip version */ - host->pmecc_version = pmecc_readl(host->pmerrloc, version); - dev_dbg(host->dev, "PMECC IP version is: %x\n", host->pmecc_version); - - atmel_pmecc_core_init(mtd); - - return 0; -} - -#else - -/* oob layout for large page size - * bad block info is on bytes 0 and 1 - * the bytes have to be consecutives to avoid - * several NAND_CMD_RNDOUT during read - */ -static struct nand_ecclayout atmel_oobinfo_large = { - .eccbytes = 4, - .eccpos = {60, 61, 62, 63}, - .oobfree = { - {2, 58} - }, -}; - -/* oob layout for small page size - * bad block info is on bytes 4 and 5 - * the bytes have to be consecutives to avoid - * several NAND_CMD_RNDOUT during read - */ -static struct nand_ecclayout atmel_oobinfo_small = { - .eccbytes = 4, - .eccpos = {0, 1, 2, 3}, - .oobfree = { - {6, 10} - }, -}; - -/* - * Calculate HW ECC - * - * function called after a write - * - * mtd: MTD block structure - * dat: raw data (unused) - * ecc_code: buffer for ECC - */ -static int atmel_nand_calculate(struct mtd_info *mtd, - const u_char *dat, unsigned char *ecc_code) -{ - unsigned int ecc_value; - - /* get the first 2 ECC bytes */ - ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR); - - ecc_code[0] = ecc_value & 0xFF; - ecc_code[1] = (ecc_value >> 8) & 0xFF; - - /* get the last 2 ECC bytes */ - ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, NPR) & ATMEL_ECC_NPARITY; - - ecc_code[2] = ecc_value & 0xFF; - ecc_code[3] = (ecc_value >> 8) & 0xFF; - - return 0; -} - -/* - * HW ECC read page function - * - * 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 - */ -static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - uint8_t *ecc_pos; - int stat; - - /* read the page */ - chip->read_buf(mtd, p, eccsize); - - /* move to ECC position if needed */ - if (eccpos[0] != 0) { - /* This only works on large pages - * because the ECC controller waits for - * NAND_CMD_RNDOUTSTART after the - * NAND_CMD_RNDOUT. - * anyway, for small pages, the eccpos[0] == 0 - */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, - mtd->writesize + eccpos[0], -1); - } - - /* the ECC controller needs to read the ECC just after the data */ - ecc_pos = oob + eccpos[0]; - chip->read_buf(mtd, ecc_pos, eccbytes); - - /* check if there's an error */ - stat = chip->ecc.correct(mtd, p, oob, NULL); - - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - - /* get back to oob start (end of page) */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); - - /* read the oob */ - chip->read_buf(mtd, oob, mtd->oobsize); - - return 0; -} - -/* - * HW ECC Correction - * - * function called after a read - * - * mtd: MTD block structure - * dat: raw data read from the chip - * read_ecc: ECC from the chip (unused) - * isnull: unused - * - * Detect and correct a 1 bit error for a page - */ -static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *isnull) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - unsigned int ecc_status; - unsigned int ecc_word, ecc_bit; - - /* get the status from the Status Register */ - ecc_status = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, SR); - - /* if there's no error */ - if (likely(!(ecc_status & ATMEL_ECC_RECERR))) - return 0; - - /* get error bit offset (4 bits) */ - ecc_bit = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_BITADDR; - /* get word address (12 bits) */ - ecc_word = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_WORDADDR; - ecc_word >>= 4; - - /* if there are multiple errors */ - if (ecc_status & ATMEL_ECC_MULERR) { - /* check if it is a freshly erased block - * (filled with 0xff) */ - if ((ecc_bit == ATMEL_ECC_BITADDR) - && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { - /* the block has just been erased, return OK */ - return 0; - } - /* it doesn't seems to be a freshly - * erased block. - * We can't correct so many errors */ - dev_warn(host->dev, "atmel_nand : multiple errors detected." - " Unable to correct.\n"); - return -EBADMSG; - } - - /* if there's a single bit error : we can correct it */ - if (ecc_status & ATMEL_ECC_ECCERR) { - /* there's nothing much to do here. - * the bit error is on the ECC itself. - */ - dev_warn(host->dev, "atmel_nand : one bit error on ECC code." - " Nothing to correct\n"); - return 0; - } - - dev_warn(host->dev, "atmel_nand : one bit error on data." - " (word offset in the page :" - " 0x%x bit offset : 0x%x)\n", - ecc_word, ecc_bit); - /* correct the error */ - if (nand_chip->options & NAND_BUSWIDTH_16) { - /* 16 bits words */ - ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); - } else { - /* 8 bits words */ - dat[ecc_word] ^= (1 << ecc_bit); - } - dev_warn(host->dev, "atmel_nand : error corrected\n"); - return 1; -} - -/* - * Enable HW ECC : unused on most chips - */ -static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) -{ -} - -int atmel_hwecc_nand_init_param(struct nand_chip *nand, struct mtd_info *mtd) -{ - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.calculate = atmel_nand_calculate; - nand->ecc.correct = atmel_nand_correct; - nand->ecc.hwctl = atmel_nand_hwctl; - nand->ecc.read_page = atmel_nand_read_page; - nand->ecc.bytes = 4; - nand->ecc.strength = 4; - - if (nand->ecc.mode == NAND_ECC_HW) { - /* ECC is calculated for the whole page (1 step) */ - nand->ecc.size = mtd->writesize; - - /* set ECC page size and oob layout */ - switch (mtd->writesize) { - case 512: - nand->ecc.layout = &atmel_oobinfo_small; - ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, - ATMEL_ECC_PAGESIZE_528); - break; - case 1024: - nand->ecc.layout = &atmel_oobinfo_large; - ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, - ATMEL_ECC_PAGESIZE_1056); - break; - case 2048: - nand->ecc.layout = &atmel_oobinfo_large; - ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, - ATMEL_ECC_PAGESIZE_2112); - break; - case 4096: - nand->ecc.layout = &atmel_oobinfo_large; - ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, - ATMEL_ECC_PAGESIZE_4224); - break; - default: - /* page size not handled by HW ECC */ - /* switching back to soft ECC */ - nand->ecc.mode = NAND_ECC_SOFT; - nand->ecc.calculate = NULL; - nand->ecc.correct = NULL; - nand->ecc.hwctl = NULL; - nand->ecc.read_page = NULL; - nand->ecc.postpad = 0; - nand->ecc.prepad = 0; - nand->ecc.bytes = 0; - break; - } - } - - return 0; -} - -#endif /* CONFIG_ATMEL_NAND_HW_PMECC */ - -#endif /* CONFIG_ATMEL_NAND_HWECC */ - -static void at91_nand_hwcontrol(struct mtd_info *mtd, - int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - if (ctrl & NAND_CTRL_CHANGE) { - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - IO_ADDR_W &= ~(CONFIG_SYS_NAND_MASK_ALE - | CONFIG_SYS_NAND_MASK_CLE); - - if (ctrl & NAND_CLE) - IO_ADDR_W |= CONFIG_SYS_NAND_MASK_CLE; - if (ctrl & NAND_ALE) - IO_ADDR_W |= CONFIG_SYS_NAND_MASK_ALE; - -#ifdef CONFIG_SYS_NAND_ENABLE_PIN - at91_set_gpio_value(CONFIG_SYS_NAND_ENABLE_PIN, - !(ctrl & NAND_NCE)); -#endif - this->IO_ADDR_W = (void *) IO_ADDR_W; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - -#ifdef CONFIG_SYS_NAND_READY_PIN -static int at91_nand_ready(struct mtd_info *mtd) -{ - return at91_get_gpio_value(CONFIG_SYS_NAND_READY_PIN); -} -#endif - -#ifdef CONFIG_SPL_BUILD -/* The following code is for SPL */ -static struct mtd_info *mtd; -static struct nand_chip nand_chip; - -static int nand_command(int block, int page, uint32_t offs, u8 cmd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; - void (*hwctrl)(struct mtd_info *mtd, int cmd, - unsigned int ctrl) = this->cmd_ctrl; - - while (!this->dev_ready(mtd)) - ; - - if (cmd == NAND_CMD_READOOB) { - offs += CONFIG_SYS_NAND_PAGE_SIZE; - cmd = NAND_CMD_READ0; - } - - hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - - if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) - offs >>= 1; - - hwctrl(mtd, offs & 0xff, NAND_CTRL_ALE | NAND_CTRL_CHANGE); - hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); - hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE); - hwctrl(mtd, ((page_addr >> 8) & 0xff), NAND_CTRL_ALE); -#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE - hwctrl(mtd, (page_addr >> 16) & 0x0f, NAND_CTRL_ALE); -#endif - hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - hwctrl(mtd, NAND_CMD_READSTART, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - while (!this->dev_ready(mtd)) - ; - - return 0; -} - -static int nand_is_bad_block(int block) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, NAND_CMD_READOOB); - - if (this->options & NAND_BUSWIDTH_16) { - if (readw(this->IO_ADDR_R) != 0xffff) - return 1; - } else { - if (readb(this->IO_ADDR_R) != 0xff) - return 1; - } - - return 0; -} - -#ifdef CONFIG_SPL_NAND_ECC -static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; -#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ - CONFIG_SYS_NAND_ECCSIZE) -#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) - -static int nand_read_page(int block, int page, void *dst) -{ - struct nand_chip *this = mtd_to_nand(mtd); - u_char ecc_calc[ECCTOTAL]; - u_char ecc_code[ECCTOTAL]; - u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; - int eccsize = CONFIG_SYS_NAND_ECCSIZE; - int eccbytes = CONFIG_SYS_NAND_ECCBYTES; - int eccsteps = ECCSTEPS; - int i; - uint8_t *p = dst; - nand_command(block, page, 0, NAND_CMD_READ0); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - if (this->ecc.mode != NAND_ECC_SOFT) - this->ecc.hwctl(mtd, NAND_ECC_READ); - this->read_buf(mtd, p, eccsize); - this->ecc.calculate(mtd, p, &ecc_calc[i]); - } - this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); - - for (i = 0; i < ECCTOTAL; i++) - ecc_code[i] = oob_data[nand_ecc_pos[i]]; - - eccsteps = ECCSTEPS; - p = dst; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - - return 0; -} - -int spl_nand_erase_one(int block, int page) -{ - struct nand_chip *this = mtd_to_nand(mtd); - void (*hwctrl)(struct mtd_info *mtd, int cmd, - unsigned int ctrl) = this->cmd_ctrl; - int page_addr; - - if (nand_chip.select_chip) - nand_chip.select_chip(mtd, 0); - - page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; - hwctrl(mtd, NAND_CMD_ERASE1, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - /* Row address */ - hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE | NAND_CTRL_CHANGE); - hwctrl(mtd, ((page_addr >> 8) & 0xff), - NAND_CTRL_ALE | NAND_CTRL_CHANGE); -#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE - /* One more address cycle for devices > 128MiB */ - hwctrl(mtd, (page_addr >> 16) & 0x0f, - NAND_CTRL_ALE | NAND_CTRL_CHANGE); -#endif - hwctrl(mtd, NAND_CMD_ERASE2, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - - while (!this->dev_ready(mtd)) - ; - - nand_deselect(); - - return 0; -} -#else -static int nand_read_page(int block, int page, void *dst) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - nand_command(block, page, 0, NAND_CMD_READ0); - atmel_nand_pmecc_read_page(mtd, this, dst, 0, page); - - return 0; -} -#endif /* CONFIG_SPL_NAND_ECC */ - -int at91_nand_wait_ready(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - udelay(this->chip_delay); - - return 1; -} - -int board_nand_init(struct nand_chip *nand) -{ - int ret = 0; - - nand->ecc.mode = NAND_ECC_SOFT; -#ifdef CONFIG_SYS_NAND_DBW_16 - nand->options = NAND_BUSWIDTH_16; - nand->read_buf = nand_read_buf16; -#else - nand->read_buf = nand_read_buf; -#endif - nand->cmd_ctrl = at91_nand_hwcontrol; -#ifdef CONFIG_SYS_NAND_READY_PIN - nand->dev_ready = at91_nand_ready; -#else - nand->dev_ready = at91_nand_wait_ready; -#endif - nand->chip_delay = 20; -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - nand->bbt_options |= NAND_BBT_USE_FLASH; -#endif - -#ifdef CONFIG_ATMEL_NAND_HWECC -#ifdef CONFIG_ATMEL_NAND_HW_PMECC - ret = atmel_pmecc_nand_init_params(nand, mtd); -#endif -#endif - - return ret; -} - -void nand_init(void) -{ - mtd = nand_to_mtd(&nand_chip); - mtd->writesize = CONFIG_SYS_NAND_PAGE_SIZE; - mtd->oobsize = CONFIG_SYS_NAND_OOBSIZE; - nand_chip.IO_ADDR_R = (void __iomem *)CONFIG_SYS_NAND_BASE; - nand_chip.IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE; - board_nand_init(&nand_chip); - -#ifdef CONFIG_SPL_NAND_ECC - if (nand_chip.ecc.mode == NAND_ECC_SOFT) { - nand_chip.ecc.calculate = nand_calculate_ecc; - nand_chip.ecc.correct = nand_correct_data; - } -#endif - - if (nand_chip.select_chip) - nand_chip.select_chip(mtd, 0); -} - -void nand_deselect(void) -{ - if (nand_chip.select_chip) - nand_chip.select_chip(mtd, -1); -} - -#include "nand_spl_loaders.c" - -#else - -#ifndef CONFIG_SYS_NAND_BASE_LIST -#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } -#endif -static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; -static ulong base_addr[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST; - -int atmel_nand_chip_init(int devnum, ulong base_addr) -{ - int ret; - struct nand_chip *nand = &nand_chip[devnum]; - struct mtd_info *mtd = nand_to_mtd(nand); - - nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; - -#ifdef CONFIG_NAND_ECC_BCH - nand->ecc.mode = NAND_ECC_SOFT_BCH; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif -#ifdef CONFIG_SYS_NAND_DBW_16 - nand->options = NAND_BUSWIDTH_16; -#endif - nand->cmd_ctrl = at91_nand_hwcontrol; -#ifdef CONFIG_SYS_NAND_READY_PIN - nand->dev_ready = at91_nand_ready; -#endif - nand->chip_delay = 75; -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - nand->bbt_options |= NAND_BBT_USE_FLASH; -#endif - - ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL); - if (ret) - return ret; - -#ifdef CONFIG_ATMEL_NAND_HWECC -#ifdef CONFIG_ATMEL_NAND_HW_PMECC - ret = atmel_pmecc_nand_init_params(nand, mtd); -#else - ret = atmel_hwecc_nand_init_param(nand, mtd); -#endif - if (ret) - return ret; -#endif - - ret = nand_scan_tail(mtd); - if (!ret) - nand_register(devnum, mtd); - - return ret; -} - -void board_nand_init(void) -{ - int i; - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - if (atmel_nand_chip_init(i, base_addr[i])) - dev_err(host->dev, "atmel_nand: Fail to initialize #%d chip", - i); -} -#endif /* CONFIG_SPL_BUILD */ diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h deleted file mode 100644 index 05eeedb3f8..0000000000 --- a/drivers/mtd/nand/atmel_nand_ecc.h +++ /dev/null @@ -1,203 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Error Corrected Code Controller (ECC) - System peripherals regsters. - * Based on AT91SAM9260 datasheet revision B. - */ - -#ifndef ATMEL_NAND_ECC_H -#define ATMEL_NAND_ECC_H - -#define ATMEL_ECC_CR 0x00 /* Control register */ -#define ATMEL_ECC_RST (1 << 0) /* Reset parity */ - -#define ATMEL_ECC_MR 0x04 /* Mode register */ -#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ -#define ATMEL_ECC_PAGESIZE_528 (0) -#define ATMEL_ECC_PAGESIZE_1056 (1) -#define ATMEL_ECC_PAGESIZE_2112 (2) -#define ATMEL_ECC_PAGESIZE_4224 (3) - -#define ATMEL_ECC_SR 0x08 /* Status register */ -#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ -#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ -#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ - -#define ATMEL_ECC_PR 0x0c /* Parity register */ -#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ -#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ - -#define ATMEL_ECC_NPR 0x10 /* NParity register */ -#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ - -/* Register access macros for PMECC */ -#define pmecc_readl(addr, reg) \ - readl(&addr->reg) - -#define pmecc_readb(addr, reg) \ - readb(&addr->reg) - -#define pmecc_writel(addr, reg, value) \ - writel((value), &addr->reg) - -/* PMECC Register Definitions */ -#define PMECC_MAX_SECTOR_NUM 8 -struct pmecc_regs { - u32 cfg; /* 0x00 PMECC Configuration Register */ - u32 sarea; /* 0x04 PMECC Spare Area Size Register */ - u32 saddr; /* 0x08 PMECC Start Address Register */ - u32 eaddr; /* 0x0C PMECC End Address Register */ - u32 clk; /* 0x10 PMECC Clock Control Register */ - u32 ctrl; /* 0x14 PMECC Control Register */ - u32 sr; /* 0x18 PMECC Status Register */ - u32 ier; /* 0x1C PMECC Interrupt Enable Register */ - u32 idr; /* 0x20 PMECC Interrupt Disable Register */ - u32 imr; /* 0x24 PMECC Interrupt Mask Register */ - u32 isr; /* 0x28 PMECC Interrupt Status Register */ - u32 reserved0[5]; /* 0x2C-0x3C Reserved */ - - /* 0x40 + sector_num * (0x40), Redundancy Registers */ - struct { -#ifdef CONFIG_SAMA5D2 - u8 ecc[56]; /* PMECC Generated Redundancy Byte Per Sector */ - u32 reserved1[2]; -#else - u8 ecc[44]; /* PMECC Generated Redundancy Byte Per Sector */ - u32 reserved1[5]; -#endif - } ecc_port[PMECC_MAX_SECTOR_NUM]; - - /* 0x240 + sector_num * (0x40) Remainder Registers */ - struct { -#ifdef CONFIG_SAMA5D2 - u32 rem[16]; -#else - u32 rem[12]; - u32 reserved2[4]; -#endif - } rem_port[PMECC_MAX_SECTOR_NUM]; - u32 reserved3[16]; /* 0x440-0x47C Reserved */ -}; - -/* For PMECC Configuration Register */ -#define PMECC_CFG_BCH_ERR2 (0 << 0) -#define PMECC_CFG_BCH_ERR4 (1 << 0) -#define PMECC_CFG_BCH_ERR8 (2 << 0) -#define PMECC_CFG_BCH_ERR12 (3 << 0) -#define PMECC_CFG_BCH_ERR24 (4 << 0) -#define PMECC_CFG_BCH_ERR32 (5 << 0) - -#define PMECC_CFG_SECTOR512 (0 << 4) -#define PMECC_CFG_SECTOR1024 (1 << 4) - -#define PMECC_CFG_PAGE_1SECTOR (0 << 8) -#define PMECC_CFG_PAGE_2SECTORS (1 << 8) -#define PMECC_CFG_PAGE_4SECTORS (2 << 8) -#define PMECC_CFG_PAGE_8SECTORS (3 << 8) - -#define PMECC_CFG_READ_OP (0 << 12) -#define PMECC_CFG_WRITE_OP (1 << 12) - -#define PMECC_CFG_SPARE_ENABLE (1 << 16) -#define PMECC_CFG_SPARE_DISABLE (0 << 16) - -#define PMECC_CFG_AUTO_ENABLE (1 << 20) -#define PMECC_CFG_AUTO_DISABLE (0 << 20) - -/* For PMECC Clock Control Register */ -#define PMECC_CLK_133MHZ (2 << 0) - -/* For PMECC Control Register */ -#define PMECC_CTRL_RST (1 << 0) -#define PMECC_CTRL_DATA (1 << 1) -#define PMECC_CTRL_USER (1 << 2) -#define PMECC_CTRL_ENABLE (1 << 4) -#define PMECC_CTRL_DISABLE (1 << 5) - -/* For PMECC Status Register */ -#define PMECC_SR_BUSY (1 << 0) -#define PMECC_SR_ENABLE (1 << 4) - -/* PMERRLOC Register Definitions */ -struct pmecc_errloc_regs { - u32 elcfg; /* 0x00 Error Location Configuration Register */ - u32 elprim; /* 0x04 Error Location Primitive Register */ - u32 elen; /* 0x08 Error Location Enable Register */ - u32 eldis; /* 0x0C Error Location Disable Register */ - u32 elsr; /* 0x10 Error Location Status Register */ - u32 elier; /* 0x14 Error Location Interrupt Enable Register */ - u32 elidr; /* 0x08 Error Location Interrupt Disable Register */ - u32 elimr; /* 0x0C Error Location Interrupt Mask Register */ - u32 elisr; /* 0x20 Error Location Interrupt Status Register */ - u32 reserved0; /* 0x24 Reserved */ -#ifdef CONFIG_SAMA5D2 - u32 sigma[33]; /* 0x28-0xA8 Error Location Sigma Registers */ - u32 el[32]; /* 0xAC-0x128 Error Location Registers */ - - /* - * 0x12C-0x1FC: - * Reserved for SAMA5D2. - */ - u32 reserved1[53]; -#else - u32 sigma[25]; /* 0x28-0x88 Error Location Sigma Registers */ - u32 el[24]; /* 0x8C-0xE8 Error Location Registers */ - u32 reserved1[5]; /* 0xEC-0xFC Reserved */ -#endif - - /* - * SAMA5 chip HSMC registers start here. But for 9X5 chip it is just - * reserved. - * - * Offset 0x00-0xF8: - */ - u32 reserved2[63]; - - /* - * Offset 0xFC: - * PMECC version for AT91SAM9X5, AT91SAM9N12. - * HSMC version for SAMA5D3, SAMA5D4. Can refer as PMECC version. - */ - u32 version; -}; - -/* For Error Location Configuration Register */ -#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0) -#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0) -#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16) - -/* For Error Location Disable Register */ -#define PMERRLOC_DISABLE (1 << 0) - -/* For Error Location Interrupt Status Register */ -#ifdef CONFIG_SAMA5D2 -#define PMERRLOC_ERR_NUM_MASK (0x3f << 8) -#else -#define PMERRLOC_ERR_NUM_MASK (0x1f << 8) -#endif - -#define PMERRLOC_CALC_DONE (1 << 0) - -/* PMECC IP version */ -#define PMECC_VERSION_SAMA5D2 0x210 -#define PMECC_VERSION_SAMA5D4 0x113 -#define PMECC_VERSION_SAMA5D3 0x112 -#define PMECC_VERSION_AT91SAM9N12 0x102 -#define PMECC_VERSION_AT91SAM9X5 0x101 - -/* Galois field dimension */ -#define PMECC_GF_DIMENSION_13 13 -#define PMECC_GF_DIMENSION_14 14 - -/* Primitive Polynomial used by PMECC */ -#define PMECC_GF_13_PRIMITIVE_POLY 0x201b -#define PMECC_GF_14_PRIMITIVE_POLY 0x4443 - -#define PMECC_INDEX_TABLE_SIZE_512 0x2000 -#define PMECC_INDEX_TABLE_SIZE_1024 0x4000 - -#define PMECC_MAX_TIMEOUT_US (100 * 1000) - -/* Reserved bytes in oob area */ -#define PMECC_OOB_RESERVED_BYTES 2 - -#endif diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c deleted file mode 100644 index 305e68ad49..0000000000 --- a/drivers/mtd/nand/davinci_nand.c +++ /dev/null @@ -1,833 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * NAND driver for TI DaVinci based boards. - * - * Copyright (C) 2007 Sergey Kubushyn - * - * Based on Linux DaVinci NAND driver by TI. Original copyright follows: - */ - -/* - * - * linux/drivers/mtd/nand/nand_davinci.c - * - * NAND Flash Driver - * - * Copyright (C) 2006 Texas Instruments. - * - * ---------------------------------------------------------------------------- - * - * ---------------------------------------------------------------------------- - * - * Overview: - * This is a device driver for the NAND flash device found on the - * DaVinci board which utilizes the Samsung k9k2g08 part. - * - Modifications: - ver. 1.0: Feb 2005, Vinod/Sudhakar - - - */ - -#include -#include -#include -#include - -/* Definitions for 4-bit hardware ECC */ -#define NAND_TIMEOUT 10240 -#define NAND_ECC_BUSY 0xC -#define NAND_4BITECC_MASK 0x03FF03FF -#define EMIF_NANDFSR_ECC_STATE_MASK 0x00000F00 -#define ECC_STATE_NO_ERR 0x0 -#define ECC_STATE_TOO_MANY_ERRS 0x1 -#define ECC_STATE_ERR_CORR_COMP_P 0x2 -#define ECC_STATE_ERR_CORR_COMP_N 0x3 - -/* - * Exploit the little endianness of the ARM to do multi-byte transfers - * per device read. This can perform over twice as quickly as individual - * byte transfers when buffer alignment is conducive. - * - * NOTE: This only works if the NAND is not connected to the 2 LSBs of - * the address bus. On Davinci EVM platforms this has always been true. - */ -static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - const u32 *nand = chip->IO_ADDR_R; - - /* Make sure that buf is 32 bit aligned */ - if (((int)buf & 0x3) != 0) { - if (((int)buf & 0x1) != 0) { - if (len) { - *buf = readb(nand); - buf += 1; - len--; - } - } - - if (((int)buf & 0x3) != 0) { - if (len >= 2) { - *(u16 *)buf = readw(nand); - buf += 2; - len -= 2; - } - } - } - - /* copy aligned data */ - while (len >= 4) { - *(u32 *)buf = __raw_readl(nand); - buf += 4; - len -= 4; - } - - /* mop up any remaining bytes */ - if (len) { - if (len >= 2) { - *(u16 *)buf = readw(nand); - buf += 2; - len -= 2; - } - - if (len) - *buf = readb(nand); - } -} - -static void nand_davinci_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - const u32 *nand = chip->IO_ADDR_W; - - /* Make sure that buf is 32 bit aligned */ - if (((int)buf & 0x3) != 0) { - if (((int)buf & 0x1) != 0) { - if (len) { - writeb(*buf, nand); - buf += 1; - len--; - } - } - - if (((int)buf & 0x3) != 0) { - if (len >= 2) { - writew(*(u16 *)buf, nand); - buf += 2; - len -= 2; - } - } - } - - /* copy aligned data */ - while (len >= 4) { - __raw_writel(*(u32 *)buf, nand); - buf += 4; - len -= 4; - } - - /* mop up any remaining bytes */ - if (len) { - if (len >= 2) { - writew(*(u16 *)buf, nand); - buf += 2; - len -= 2; - } - - if (len) - writeb(*buf, nand); - } -} - -static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - struct nand_chip *this = mtd_to_nand(mtd); - u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W; - - if (ctrl & NAND_CTRL_CHANGE) { - IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); - - if (ctrl & NAND_CLE) - IO_ADDR_W |= MASK_CLE; - if (ctrl & NAND_ALE) - IO_ADDR_W |= MASK_ALE; - this->IO_ADDR_W = (void __iomem *) IO_ADDR_W; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, IO_ADDR_W); -} - -#ifdef CONFIG_SYS_NAND_HW_ECC - -static u_int32_t nand_davinci_readecc(struct mtd_info *mtd) -{ - u_int32_t ecc = 0; - - ecc = __raw_readl(&(davinci_emif_regs->nandfecc[ - CONFIG_SYS_NAND_CS - 2])); - - return ecc; -} - -static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) -{ - u_int32_t val; - - /* reading the ECC result register resets the ECC calculation */ - nand_davinci_readecc(mtd); - - val = __raw_readl(&davinci_emif_regs->nandfcr); - val |= DAVINCI_NANDFCR_NAND_ENABLE(CONFIG_SYS_NAND_CS); - val |= DAVINCI_NANDFCR_1BIT_ECC_START(CONFIG_SYS_NAND_CS); - __raw_writel(val, &davinci_emif_regs->nandfcr); -} - -static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - u_int32_t tmp; - - tmp = nand_davinci_readecc(mtd); - - /* Squeeze 4 bytes ECC into 3 bytes by removing RESERVED bits - * and shifting. RESERVED bits are 31 to 28 and 15 to 12. */ - tmp = (tmp & 0x00000fff) | ((tmp & 0x0fff0000) >> 4); - - /* Invert so that erased block ECC is correct */ - tmp = ~tmp; - - *ecc_code++ = tmp; - *ecc_code++ = tmp >> 8; - *ecc_code++ = tmp >> 16; - - /* NOTE: the above code matches mainline Linux: - * .PQR.stu ==> ~PQRstu - * - * MontaVista/TI kernels encode those bytes differently, use - * complicated (and allegedly sometimes-wrong) correction code, - * and usually shipped with U-Boot that uses software ECC: - * .PQR.stu ==> PsQRtu - * - * If you need MV/TI compatible NAND I/O in U-Boot, it should - * be possible to (a) change the mangling above, (b) reverse - * that mangling in nand_davinci_correct_data() below. - */ - - return 0; -} - -static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct nand_chip *this = mtd_to_nand(mtd); - u_int32_t ecc_nand = read_ecc[0] | (read_ecc[1] << 8) | - (read_ecc[2] << 16); - u_int32_t ecc_calc = calc_ecc[0] | (calc_ecc[1] << 8) | - (calc_ecc[2] << 16); - u_int32_t diff = ecc_calc ^ ecc_nand; - - if (diff) { - if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) { - /* Correctable error */ - if ((diff >> (12 + 3)) < this->ecc.size) { - uint8_t find_bit = 1 << ((diff >> 12) & 7); - uint32_t find_byte = diff >> (12 + 3); - - dat[find_byte] ^= find_bit; - pr_debug("Correcting single " - "bit ECC error at offset: %d, bit: " - "%d\n", find_byte, find_bit); - return 1; - } else { - return -EBADMSG; - } - } else if (!(diff & (diff - 1))) { - /* Single bit ECC error in the ECC itself, - nothing to fix */ - pr_debug("Single bit ECC error in " "ECC.\n"); - return 1; - } else { - /* Uncorrectable error */ - pr_debug("ECC UNCORRECTED_ERROR 1\n"); - return -EBADMSG; - } - } - return 0; -} -#endif /* CONFIG_SYS_NAND_HW_ECC */ - -#ifdef CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST -static struct nand_ecclayout nand_davinci_4bit_layout_oobfirst = { -#if defined(CONFIG_SYS_NAND_PAGE_2K) - .eccbytes = 40, -#ifdef CONFIG_NAND_6BYTES_OOB_FREE_10BYTES_ECC - .eccpos = { - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - }, - .oobfree = { - {2, 4}, {16, 6}, {32, 6}, {48, 6}, - }, -#else - .eccpos = { - 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, - }, - .oobfree = { - {.offset = 2, .length = 22, }, - }, -#endif /* #ifdef CONFIG_NAND_6BYTES_OOB_FREE_10BYTES_ECC */ -#elif defined(CONFIG_SYS_NAND_PAGE_4K) - .eccbytes = 80, - .eccpos = { - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - }, - .oobfree = { - {.offset = 2, .length = 46, }, - }, -#endif -}; - -#if defined CONFIG_KEYSTONE_RBL_NAND -static struct nand_ecclayout nand_keystone_rbl_4bit_layout_oobfirst = { -#if defined(CONFIG_SYS_NAND_PAGE_2K) - .eccbytes = 40, - .eccpos = { - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - }, - .oobfree = { - {.offset = 2, .length = 4, }, - {.offset = 16, .length = 6, }, - {.offset = 32, .length = 6, }, - {.offset = 48, .length = 6, }, - }, -#elif defined(CONFIG_SYS_NAND_PAGE_4K) - .eccbytes = 80, - .eccpos = { - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - }, - .oobfree = { - {.offset = 2, .length = 4, }, - {.offset = 16, .length = 6, }, - {.offset = 32, .length = 6, }, - {.offset = 48, .length = 6, }, - {.offset = 64, .length = 6, }, - {.offset = 80, .length = 6, }, - {.offset = 96, .length = 6, }, - {.offset = 112, .length = 6, }, - }, -#endif -}; - -#ifdef CONFIG_SYS_NAND_PAGE_2K -#define CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE CONFIG_KEYSTONE_NAND_MAX_RBL_SIZE >> 11 -#elif defined(CONFIG_SYS_NAND_PAGE_4K) -#define CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE CONFIG_KEYSTONE_NAND_MAX_RBL_SIZE >> 12 -#endif - -/** - * nand_davinci_write_page - write one page - * @mtd: MTD device structure - * @chip: NAND chip descriptor - * @buf: the data to write - * @oob_required: must write chip->oob_poi to OOB - * @page: page number to write - * @raw: use _raw version of write_page - */ -static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, - const uint8_t *buf, int oob_required, - int page, int raw) -{ - int status; - int ret = 0; - struct nand_ecclayout *saved_ecc_layout; - - /* save current ECC layout and assign Keystone RBL ECC layout */ - if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) { - saved_ecc_layout = chip->ecc.layout; - chip->ecc.layout = &nand_keystone_rbl_4bit_layout_oobfirst; - mtd->oobavail = chip->ecc.layout->oobavail; - } - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - - if (unlikely(raw)) { - status = chip->ecc.write_page_raw(mtd, chip, buf, - oob_required, page); - } else { - status = chip->ecc.write_page(mtd, chip, buf, - oob_required, page); - } - - if (status < 0) { - ret = status; - goto err; - } - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - - if (status & NAND_STATUS_FAIL) { - ret = -EIO; - goto err; - } - -err: - /* restore ECC layout */ - if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) { - chip->ecc.layout = saved_ecc_layout; - mtd->oobavail = saved_ecc_layout->oobavail; - } - - return ret; -} - -/** - * nand_davinci_read_page_hwecc - 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 - * @page: page number to read - * - * Not for syndrome calculating ECC controllers which need a special oob layout. - */ -static int nand_davinci_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint32_t *eccpos; - uint8_t *p = buf; - uint8_t *ecc_code = chip->buffers->ecccode; - uint8_t *ecc_calc = chip->buffers->ecccalc; - struct nand_ecclayout *saved_ecc_layout = chip->ecc.layout; - - /* save current ECC layout and assign Keystone RBL ECC layout */ - if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) { - chip->ecc.layout = &nand_keystone_rbl_4bit_layout_oobfirst; - mtd->oobavail = chip->ecc.layout->oobavail; - } - - eccpos = chip->ecc.layout->eccpos; - - /* Read the OOB area first */ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - - /* restore ECC layout */ - if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) { - chip->ecc.layout = saved_ecc_layout; - mtd->oobavail = saved_ecc_layout->oobavail; - } - - return 0; -} -#endif /* CONFIG_KEYSTONE_RBL_NAND */ - -static void nand_davinci_4bit_enable_hwecc(struct mtd_info *mtd, int mode) -{ - u32 val; - - switch (mode) { - case NAND_ECC_WRITE: - case NAND_ECC_READ: - /* - * Start a new ECC calculation for reading or writing 512 bytes - * of data. - */ - val = __raw_readl(&davinci_emif_regs->nandfcr); - val &= ~DAVINCI_NANDFCR_4BIT_ECC_SEL_MASK; - val |= DAVINCI_NANDFCR_NAND_ENABLE(CONFIG_SYS_NAND_CS); - val |= DAVINCI_NANDFCR_4BIT_ECC_SEL(CONFIG_SYS_NAND_CS); - val |= DAVINCI_NANDFCR_4BIT_ECC_START; - __raw_writel(val, &davinci_emif_regs->nandfcr); - break; - case NAND_ECC_READSYN: - val = __raw_readl(&davinci_emif_regs->nand4bitecc[0]); - break; - default: - break; - } -} - -static u32 nand_davinci_4bit_readecc(struct mtd_info *mtd, unsigned int ecc[4]) -{ - int i; - - for (i = 0; i < 4; i++) { - ecc[i] = __raw_readl(&davinci_emif_regs->nand4bitecc[i]) & - NAND_4BITECC_MASK; - } - - return 0; -} - -static int nand_davinci_4bit_calculate_ecc(struct mtd_info *mtd, - const uint8_t *dat, - uint8_t *ecc_code) -{ - unsigned int hw_4ecc[4]; - unsigned int i; - - nand_davinci_4bit_readecc(mtd, hw_4ecc); - - /*Convert 10 bit ecc value to 8 bit */ - for (i = 0; i < 2; i++) { - unsigned int hw_ecc_low = hw_4ecc[i * 2]; - unsigned int hw_ecc_hi = hw_4ecc[(i * 2) + 1]; - - /* Take first 8 bits from val1 (count1=0) or val5 (count1=1) */ - *ecc_code++ = hw_ecc_low & 0xFF; - - /* - * Take 2 bits as LSB bits from val1 (count1=0) or val5 - * (count1=1) and 6 bits from val2 (count1=0) or - * val5 (count1=1) - */ - *ecc_code++ = - ((hw_ecc_low >> 8) & 0x3) | ((hw_ecc_low >> 14) & 0xFC); - - /* - * Take 4 bits from val2 (count1=0) or val5 (count1=1) and - * 4 bits from val3 (count1=0) or val6 (count1=1) - */ - *ecc_code++ = - ((hw_ecc_low >> 22) & 0xF) | ((hw_ecc_hi << 4) & 0xF0); - - /* - * Take 6 bits from val3(count1=0) or val6 (count1=1) and - * 2 bits from val4 (count1=0) or val7 (count1=1) - */ - *ecc_code++ = - ((hw_ecc_hi >> 4) & 0x3F) | ((hw_ecc_hi >> 10) & 0xC0); - - /* Take 8 bits from val4 (count1=0) or val7 (count1=1) */ - *ecc_code++ = (hw_ecc_hi >> 18) & 0xFF; - } - - return 0; -} - -static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - int i; - unsigned int hw_4ecc[4]; - unsigned int iserror; - unsigned short *ecc16; - unsigned int numerrors, erroraddress, errorvalue; - u32 val; - - /* - * Check for an ECC where all bytes are 0xFF. If this is the case, we - * will assume we are looking at an erased page and we should ignore - * the ECC. - */ - for (i = 0; i < 10; i++) { - if (read_ecc[i] != 0xFF) - break; - } - if (i == 10) - return 0; - - /* Convert 8 bit in to 10 bit */ - ecc16 = (unsigned short *)&read_ecc[0]; - - /* - * Write the parity values in the NAND Flash 4-bit ECC Load register. - * Write each parity value one at a time starting from 4bit_ecc_val8 - * to 4bit_ecc_val1. - */ - - /*Take 2 bits from 8th byte and 8 bits from 9th byte */ - __raw_writel(((ecc16[4]) >> 6) & 0x3FF, - &davinci_emif_regs->nand4biteccload); - - /* Take 4 bits from 7th byte and 6 bits from 8th byte */ - __raw_writel((((ecc16[3]) >> 12) & 0xF) | ((((ecc16[4])) << 4) & 0x3F0), - &davinci_emif_regs->nand4biteccload); - - /* Take 6 bits from 6th byte and 4 bits from 7th byte */ - __raw_writel((ecc16[3] >> 2) & 0x3FF, - &davinci_emif_regs->nand4biteccload); - - /* Take 8 bits from 5th byte and 2 bits from 6th byte */ - __raw_writel(((ecc16[2]) >> 8) | ((((ecc16[3])) << 8) & 0x300), - &davinci_emif_regs->nand4biteccload); - - /*Take 2 bits from 3rd byte and 8 bits from 4th byte */ - __raw_writel((((ecc16[1]) >> 14) & 0x3) | ((((ecc16[2])) << 2) & 0x3FC), - &davinci_emif_regs->nand4biteccload); - - /* Take 4 bits form 2nd bytes and 6 bits from 3rd bytes */ - __raw_writel(((ecc16[1]) >> 4) & 0x3FF, - &davinci_emif_regs->nand4biteccload); - - /* Take 6 bits from 1st byte and 4 bits from 2nd byte */ - __raw_writel((((ecc16[0]) >> 10) & 0x3F) | (((ecc16[1]) << 6) & 0x3C0), - &davinci_emif_regs->nand4biteccload); - - /* Take 10 bits from 0th and 1st bytes */ - __raw_writel((ecc16[0]) & 0x3FF, - &davinci_emif_regs->nand4biteccload); - - /* - * Perform a dummy read to the EMIF Revision Code and Status register. - * This is required to ensure time for syndrome calculation after - * writing the ECC values in previous step. - */ - - val = __raw_readl(&davinci_emif_regs->nandfsr); - - /* - * Read the syndrome from the NAND Flash 4-Bit ECC 1-4 registers. - * A syndrome value of 0 means no bit errors. If the syndrome is - * non-zero then go further otherwise return. - */ - nand_davinci_4bit_readecc(mtd, hw_4ecc); - - if (!(hw_4ecc[0] | hw_4ecc[1] | hw_4ecc[2] | hw_4ecc[3])) - return 0; - - /* - * Clear any previous address calculation by doing a dummy read of an - * error address register. - */ - val = __raw_readl(&davinci_emif_regs->nanderradd1); - - /* - * Set the addr_calc_st bit(bit no 13) in the NAND Flash Control - * register to 1. - */ - __raw_writel(DAVINCI_NANDFCR_4BIT_CALC_START, - &davinci_emif_regs->nandfcr); - - /* - * Wait for the corr_state field (bits 8 to 11) in the - * NAND Flash Status register to be not equal to 0x0, 0x1, 0x2, or 0x3. - * Otherwise ECC calculation has not even begun and the next loop might - * fail because of a false positive! - */ - i = NAND_TIMEOUT; - do { - val = __raw_readl(&davinci_emif_regs->nandfsr); - val &= 0xc00; - i--; - } while ((i > 0) && !val); - - /* - * Wait for the corr_state field (bits 8 to 11) in the - * NAND Flash Status register to be equal to 0x0, 0x1, 0x2, or 0x3. - */ - i = NAND_TIMEOUT; - do { - val = __raw_readl(&davinci_emif_regs->nandfsr); - val &= 0xc00; - i--; - } while ((i > 0) && val); - - iserror = __raw_readl(&davinci_emif_regs->nandfsr); - iserror &= EMIF_NANDFSR_ECC_STATE_MASK; - iserror = iserror >> 8; - - /* - * ECC_STATE_TOO_MANY_ERRS (0x1) means errors cannot be - * corrected (five or more errors). The number of errors - * calculated (err_num field) differs from the number of errors - * searched. ECC_STATE_ERR_CORR_COMP_P (0x2) means error - * correction complete (errors on bit 8 or 9). - * ECC_STATE_ERR_CORR_COMP_N (0x3) means error correction - * complete (error exists). - */ - - if (iserror == ECC_STATE_NO_ERR) { - val = __raw_readl(&davinci_emif_regs->nanderrval1); - return 0; - } else if (iserror == ECC_STATE_TOO_MANY_ERRS) { - val = __raw_readl(&davinci_emif_regs->nanderrval1); - return -EBADMSG; - } - - numerrors = ((__raw_readl(&davinci_emif_regs->nandfsr) >> 16) - & 0x3) + 1; - - /* Read the error address, error value and correct */ - for (i = 0; i < numerrors; i++) { - if (i > 1) { - erroraddress = - ((__raw_readl(&davinci_emif_regs->nanderradd2) >> - (16 * (i & 1))) & 0x3FF); - erroraddress = ((512 + 7) - erroraddress); - errorvalue = - ((__raw_readl(&davinci_emif_regs->nanderrval2) >> - (16 * (i & 1))) & 0xFF); - } else { - erroraddress = - ((__raw_readl(&davinci_emif_regs->nanderradd1) >> - (16 * (i & 1))) & 0x3FF); - erroraddress = ((512 + 7) - erroraddress); - errorvalue = - ((__raw_readl(&davinci_emif_regs->nanderrval1) >> - (16 * (i & 1))) & 0xFF); - } - /* xor the corrupt data with error value */ - if (erroraddress < 512) - dat[erroraddress] ^= errorvalue; - } - - return numerrors; -} -#endif /* CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST */ - -static int nand_davinci_dev_ready(struct mtd_info *mtd) -{ - return __raw_readl(&davinci_emif_regs->nandfsr) & 0x1; -} - -static void nand_flash_init(void) -{ - /* This is for DM6446 EVM and *very* similar. DO NOT GROW THIS! - * Instead, have your board_init() set EMIF timings, based on its - * knowledge of the clocks and what devices are hooked up ... and - * don't even do that unless no UBL handled it. - */ -#ifdef CONFIG_SOC_DM644X - u_int32_t acfg1 = 0x3ffffffc; - - /*------------------------------------------------------------------* - * NAND FLASH CHIP TIMEOUT @ 459 MHz * - * * - * AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz * - * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns * - * * - *------------------------------------------------------------------*/ - acfg1 = 0 - | (0 << 31) /* selectStrobe */ - | (0 << 30) /* extWait */ - | (1 << 26) /* writeSetup 10 ns */ - | (3 << 20) /* writeStrobe 40 ns */ - | (1 << 17) /* writeHold 10 ns */ - | (1 << 13) /* readSetup 10 ns */ - | (5 << 7) /* readStrobe 60 ns */ - | (1 << 4) /* readHold 10 ns */ - | (3 << 2) /* turnAround ?? ns */ - | (0 << 0) /* asyncSize 8-bit bus */ - ; - - __raw_writel(acfg1, &davinci_emif_regs->ab1cr); /* CS2 */ - - /* NAND flash on CS2 */ - __raw_writel(0x00000101, &davinci_emif_regs->nandfcr); -#endif -} - -void davinci_nand_init(struct nand_chip *nand) -{ -#if defined CONFIG_KEYSTONE_RBL_NAND - int i; - struct nand_ecclayout *layout; - - layout = &nand_keystone_rbl_4bit_layout_oobfirst; - layout->oobavail = 0; - for (i = 0; layout->oobfree[i].length && - i < ARRAY_SIZE(layout->oobfree); i++) - layout->oobavail += layout->oobfree[i].length; - - nand->write_page = nand_davinci_write_page; - nand->ecc.read_page = nand_davinci_read_page_hwecc; -#endif - nand->chip_delay = 0; -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - nand->bbt_options |= NAND_BBT_USE_FLASH; -#endif -#ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE - nand->options |= NAND_NO_SUBPAGE_WRITE; -#endif -#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT - nand->options |= NAND_BUSWIDTH_16; -#endif -#ifdef CONFIG_SYS_NAND_HW_ECC - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.size = 512; - nand->ecc.bytes = 3; - nand->ecc.strength = 1; - nand->ecc.calculate = nand_davinci_calculate_ecc; - nand->ecc.correct = nand_davinci_correct_data; - nand->ecc.hwctl = nand_davinci_enable_hwecc; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif /* CONFIG_SYS_NAND_HW_ECC */ -#ifdef CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST - nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; - nand->ecc.size = 512; - nand->ecc.bytes = 10; - nand->ecc.strength = 4; - nand->ecc.calculate = nand_davinci_4bit_calculate_ecc; - nand->ecc.correct = nand_davinci_4bit_correct_data; - nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc; - nand->ecc.layout = &nand_davinci_4bit_layout_oobfirst; -#endif - /* Set address of hardware control function */ - nand->cmd_ctrl = nand_davinci_hwcontrol; - - nand->read_buf = nand_davinci_read_buf; - nand->write_buf = nand_davinci_write_buf; - - nand->dev_ready = nand_davinci_dev_ready; - - nand_flash_init(); -} - -int board_nand_init(struct nand_chip *chip) __attribute__((weak)); - -int board_nand_init(struct nand_chip *chip) -{ - davinci_nand_init(chip); - return 0; -} diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c deleted file mode 100644 index d1cac063f4..0000000000 --- a/drivers/mtd/nand/denali.c +++ /dev/null @@ -1,1371 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2014 Panasonic Corporation - * Copyright (C) 2013-2014, Altera Corporation - * Copyright (C) 2009-2010, Intel Corporation and its suppliers. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "denali.h" - -static dma_addr_t dma_map_single(void *dev, void *ptr, size_t size, - enum dma_data_direction dir) -{ - unsigned long addr = (unsigned long)ptr; - - size = ALIGN(size, ARCH_DMA_MINALIGN); - - if (dir == DMA_FROM_DEVICE) - invalidate_dcache_range(addr, addr + size); - else - flush_dcache_range(addr, addr + size); - - return addr; -} - -static void dma_unmap_single(void *dev, dma_addr_t addr, size_t size, - enum dma_data_direction dir) -{ - size = ALIGN(size, ARCH_DMA_MINALIGN); - - if (dir != DMA_TO_DEVICE) - invalidate_dcache_range(addr, addr + size); -} - -static int dma_mapping_error(void *dev, dma_addr_t addr) -{ - return 0; -} - -#define DENALI_NAND_NAME "denali-nand" - -/* for Indexed Addressing */ -#define DENALI_INDEXED_CTRL 0x00 -#define DENALI_INDEXED_DATA 0x10 - -#define DENALI_MAP00 (0 << 26) /* direct access to buffer */ -#define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */ -#define DENALI_MAP10 (2 << 26) /* high-level control plane */ -#define DENALI_MAP11 (3 << 26) /* direct controller access */ - -/* MAP11 access cycle type */ -#define DENALI_MAP11_CMD ((DENALI_MAP11) | 0) /* command cycle */ -#define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) /* address cycle */ -#define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) /* data cycle */ - -/* MAP10 commands */ -#define DENALI_ERASE 0x01 - -#define DENALI_BANK(denali) ((denali)->active_bank << 24) - -#define DENALI_INVALID_BANK -1 -#define DENALI_NR_BANKS 4 - -/* - * The bus interface clock, clk_x, is phase aligned with the core clock. The - * clk_x is an integral multiple N of the core clk. The value N is configured - * at IP delivery time, and its available value is 4, 5, or 6. We need to align - * to the largest value to make it work with any possible configuration. - */ -#define DENALI_CLK_X_MULT 6 - -static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) -{ - return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand); -} - -/* - * Direct Addressing - the slave address forms the control information (command - * type, bank, block, and page address). The slave data is the actual data to - * be transferred. This mode requires 28 bits of address region allocated. - */ -static u32 denali_direct_read(struct denali_nand_info *denali, u32 addr) -{ - return ioread32(denali->host + addr); -} - -static void denali_direct_write(struct denali_nand_info *denali, u32 addr, - u32 data) -{ - iowrite32(data, denali->host + addr); -} - -/* - * Indexed Addressing - address translation module intervenes in passing the - * control information. This mode reduces the required address range. The - * control information and transferred data are latched by the registers in - * the translation module. - */ -static u32 denali_indexed_read(struct denali_nand_info *denali, u32 addr) -{ - iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); - return ioread32(denali->host + DENALI_INDEXED_DATA); -} - -static void denali_indexed_write(struct denali_nand_info *denali, u32 addr, - u32 data) -{ - iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); - iowrite32(data, denali->host + DENALI_INDEXED_DATA); -} - -/* - * Use the configuration feature register to determine the maximum number of - * banks that the hardware supports. - */ -static void denali_detect_max_banks(struct denali_nand_info *denali) -{ - uint32_t features = ioread32(denali->reg + FEATURES); - - denali->max_banks = 1 << FIELD_GET(FEATURES__N_BANKS, features); - - /* the encoding changed from rev 5.0 to 5.1 */ - if (denali->revision < 0x0501) - denali->max_banks <<= 1; -} - -static void __maybe_unused denali_enable_irq(struct denali_nand_info *denali) -{ - int i; - - for (i = 0; i < DENALI_NR_BANKS; i++) - iowrite32(U32_MAX, denali->reg + INTR_EN(i)); - iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE); -} - -static void __maybe_unused denali_disable_irq(struct denali_nand_info *denali) -{ - int i; - - for (i = 0; i < DENALI_NR_BANKS; i++) - iowrite32(0, denali->reg + INTR_EN(i)); - iowrite32(0, denali->reg + GLOBAL_INT_ENABLE); -} - -static void denali_clear_irq(struct denali_nand_info *denali, - int bank, uint32_t irq_status) -{ - /* write one to clear bits */ - iowrite32(irq_status, denali->reg + INTR_STATUS(bank)); -} - -static void denali_clear_irq_all(struct denali_nand_info *denali) -{ - int i; - - for (i = 0; i < DENALI_NR_BANKS; i++) - denali_clear_irq(denali, i, U32_MAX); -} - -static void __denali_check_irq(struct denali_nand_info *denali) -{ - uint32_t irq_status; - int i; - - for (i = 0; i < DENALI_NR_BANKS; i++) { - irq_status = ioread32(denali->reg + INTR_STATUS(i)); - denali_clear_irq(denali, i, irq_status); - - if (i != denali->active_bank) - continue; - - denali->irq_status |= irq_status; - } -} - -static void denali_reset_irq(struct denali_nand_info *denali) -{ - denali->irq_status = 0; - denali->irq_mask = 0; -} - -static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, - uint32_t irq_mask) -{ - unsigned long time_left = 1000000; - - while (time_left) { - __denali_check_irq(denali); - - if (irq_mask & denali->irq_status) - return denali->irq_status; - udelay(1); - time_left--; - } - - if (!time_left) { - dev_err(denali->dev, "timeout while waiting for irq 0x%x\n", - irq_mask); - return 0; - } - - return denali->irq_status; -} - -static uint32_t denali_check_irq(struct denali_nand_info *denali) -{ - __denali_check_irq(denali); - - return denali->irq_status; -} - -static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); - int i; - - for (i = 0; i < len; i++) - buf[i] = denali->host_read(denali, addr); -} - -static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); - int i; - - for (i = 0; i < len; i++) - denali->host_write(denali, addr, buf[i]); -} - -static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); - uint16_t *buf16 = (uint16_t *)buf; - int i; - - for (i = 0; i < len / 2; i++) - buf16[i] = denali->host_read(denali, addr); -} - -static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); - const uint16_t *buf16 = (const uint16_t *)buf; - int i; - - for (i = 0; i < len / 2; i++) - denali->host_write(denali, addr, buf16[i]); -} - -static uint8_t denali_read_byte(struct mtd_info *mtd) -{ - uint8_t byte; - - denali_read_buf(mtd, &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) -{ - uint16_t word; - - denali_read_buf16(mtd, (uint8_t *)&word, 2); - - return word; -} - -static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t type; - - if (ctrl & NAND_CLE) - type = DENALI_MAP11_CMD; - else if (ctrl & NAND_ALE) - type = DENALI_MAP11_ADDR; - else - return; - - /* - * Some commands are followed by chip->dev_ready or chip->waitfunc. - * irq_status must be cleared here to catch the R/B# interrupt later. - */ - if (ctrl & NAND_CTRL_CHANGE) - denali_reset_irq(denali); - - denali->host_write(denali, DENALI_BANK(denali) | type, dat); -} - -static int denali_dev_ready(struct mtd_info *mtd) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - - return !!(denali_check_irq(denali) & INTR__INT_ACT); -} - -static int denali_check_erased_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, - unsigned long uncor_ecc_flags, - unsigned int max_bitflips) -{ - uint8_t *ecc_code = chip->buffers->ecccode; - int ecc_steps = chip->ecc.steps; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; - int i, ret, stat; - - ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, - chip->ecc.total); - if (ret) - return ret; - - for (i = 0; i < ecc_steps; i++) { - if (!(uncor_ecc_flags & BIT(i))) - continue; - - stat = nand_check_erased_ecc_chunk(buf, ecc_size, - ecc_code, ecc_bytes, - NULL, 0, - chip->ecc.strength); - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - - buf += ecc_size; - ecc_code += ecc_bytes; - } - - return max_bitflips; -} - -static int denali_hw_ecc_fixup(struct mtd_info *mtd, - struct denali_nand_info *denali, - unsigned long *uncor_ecc_flags) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int bank = denali->active_bank; - uint32_t ecc_cor; - unsigned int max_bitflips; - - ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank)); - ecc_cor >>= ECC_COR_INFO__SHIFT(bank); - - if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) { - /* - * This flag is set when uncorrectable error occurs at least in - * one ECC sector. We can not know "how many sectors", or - * "which sector(s)". We need erase-page check for all sectors. - */ - *uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0); - return 0; - } - - max_bitflips = FIELD_GET(ECC_COR_INFO__MAX_ERRORS, ecc_cor); - - /* - * The register holds the maximum of per-sector corrected bitflips. - * This is suitable for the return value of the ->read_page() callback. - * Unfortunately, we can not know the total number of corrected bits in - * the page. Increase the stats by max_bitflips. (compromised solution) - */ - mtd->ecc_stats.corrected += max_bitflips; - - return max_bitflips; -} - -static int denali_sw_ecc_fixup(struct mtd_info *mtd, - struct denali_nand_info *denali, - unsigned long *uncor_ecc_flags, uint8_t *buf) -{ - unsigned int ecc_size = denali->nand.ecc.size; - unsigned int bitflips = 0; - unsigned int max_bitflips = 0; - uint32_t err_addr, err_cor_info; - unsigned int err_byte, err_sector, err_device; - uint8_t err_cor_value; - unsigned int prev_sector = 0; - uint32_t irq_status; - - denali_reset_irq(denali); - - do { - err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS); - err_sector = FIELD_GET(ECC_ERROR_ADDRESS__SECTOR, err_addr); - err_byte = FIELD_GET(ECC_ERROR_ADDRESS__OFFSET, err_addr); - - err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO); - err_cor_value = FIELD_GET(ERR_CORRECTION_INFO__BYTE, - err_cor_info); - err_device = FIELD_GET(ERR_CORRECTION_INFO__DEVICE, - err_cor_info); - - /* reset the bitflip counter when crossing ECC sector */ - if (err_sector != prev_sector) - bitflips = 0; - - if (err_cor_info & ERR_CORRECTION_INFO__UNCOR) { - /* - * Check later if this is a real ECC error, or - * an erased sector. - */ - *uncor_ecc_flags |= BIT(err_sector); - } else if (err_byte < ecc_size) { - /* - * If err_byte is larger than ecc_size, means error - * happened in OOB, so we ignore it. It's no need for - * us to correct it err_device is represented the NAND - * error bits are happened in if there are more than - * one NAND connected. - */ - int offset; - unsigned int flips_in_byte; - - offset = (err_sector * ecc_size + err_byte) * - denali->devs_per_cs + err_device; - - /* correct the ECC error */ - flips_in_byte = hweight8(buf[offset] ^ err_cor_value); - buf[offset] ^= err_cor_value; - mtd->ecc_stats.corrected += flips_in_byte; - bitflips += flips_in_byte; - - max_bitflips = max(max_bitflips, bitflips); - } - - prev_sector = err_sector; - } while (!(err_cor_info & ERR_CORRECTION_INFO__LAST_ERR)); - - /* - * Once handle all ECC errors, controller will trigger an - * ECC_TRANSACTION_DONE interrupt. - */ - irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE); - if (!(irq_status & INTR__ECC_TRANSACTION_DONE)) - return -EIO; - - return max_bitflips; -} - -static void denali_setup_dma64(struct denali_nand_info *denali, - dma_addr_t dma_addr, int page, int write) -{ - uint32_t mode; - const int page_count = 1; - - mode = DENALI_MAP10 | DENALI_BANK(denali) | page; - - /* DMA is a three step process */ - - /* - * 1. setup transfer type, interrupt when complete, - * burst len = 64 bytes, the number of pages - */ - denali->host_write(denali, mode, - 0x01002000 | (64 << 16) | (write << 8) | page_count); - - /* 2. set memory low address */ - denali->host_write(denali, mode, lower_32_bits(dma_addr)); - - /* 3. set memory high address */ - denali->host_write(denali, mode, upper_32_bits(dma_addr)); -} - -static void denali_setup_dma32(struct denali_nand_info *denali, - dma_addr_t dma_addr, int page, int write) -{ - uint32_t mode; - const int page_count = 1; - - mode = DENALI_MAP10 | DENALI_BANK(denali); - - /* DMA is a four step process */ - - /* 1. setup transfer type and # of pages */ - denali->host_write(denali, mode | page, - 0x2000 | (write << 8) | page_count); - - /* 2. set memory high address bits 23:8 */ - denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200); - - /* 3. set memory low address bits 23:8 */ - denali->host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); - - /* 4. interrupt when complete, burst len = 64 bytes */ - denali->host_write(denali, mode | 0x14000, 0x2400); -} - -static int denali_pio_read(struct denali_nand_info *denali, void *buf, - size_t size, int page, int raw) -{ - u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; - uint32_t *buf32 = (uint32_t *)buf; - uint32_t irq_status, ecc_err_mask; - int i; - - if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) - ecc_err_mask = INTR__ECC_UNCOR_ERR; - else - ecc_err_mask = INTR__ECC_ERR; - - denali_reset_irq(denali); - - for (i = 0; i < size / 4; i++) - *buf32++ = denali->host_read(denali, addr); - - irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC); - if (!(irq_status & INTR__PAGE_XFER_INC)) - return -EIO; - - if (irq_status & INTR__ERASED_PAGE) - memset(buf, 0xff, size); - - return irq_status & ecc_err_mask ? -EBADMSG : 0; -} - -static int denali_pio_write(struct denali_nand_info *denali, - const void *buf, size_t size, int page, int raw) -{ - u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; - const uint32_t *buf32 = (uint32_t *)buf; - uint32_t irq_status; - int i; - - denali_reset_irq(denali); - - for (i = 0; i < size / 4; i++) - denali->host_write(denali, addr, *buf32++); - - irq_status = denali_wait_for_irq(denali, - INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL); - if (!(irq_status & INTR__PROGRAM_COMP)) - return -EIO; - - return 0; -} - -static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, - size_t size, int page, int raw, int write) -{ - if (write) - return denali_pio_write(denali, buf, size, page, raw); - else - return denali_pio_read(denali, buf, size, page, raw); -} - -static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, - size_t size, int page, int raw, int write) -{ - dma_addr_t dma_addr; - uint32_t irq_mask, irq_status, ecc_err_mask; - enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; - int ret = 0; - - dma_addr = dma_map_single(denali->dev, buf, size, dir); - if (dma_mapping_error(denali->dev, dma_addr)) { - dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n"); - return denali_pio_xfer(denali, buf, size, page, raw, write); - } - - if (write) { - /* - * INTR__PROGRAM_COMP is never asserted for the DMA transfer. - * We can use INTR__DMA_CMD_COMP instead. This flag is asserted - * when the page program is completed. - */ - irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; - ecc_err_mask = 0; - } else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) { - irq_mask = INTR__DMA_CMD_COMP; - ecc_err_mask = INTR__ECC_UNCOR_ERR; - } else { - irq_mask = INTR__DMA_CMD_COMP; - ecc_err_mask = INTR__ECC_ERR; - } - - iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE); - - denali_reset_irq(denali); - denali->setup_dma(denali, dma_addr, page, write); - - irq_status = denali_wait_for_irq(denali, irq_mask); - if (!(irq_status & INTR__DMA_CMD_COMP)) - ret = -EIO; - else if (irq_status & ecc_err_mask) - ret = -EBADMSG; - - iowrite32(0, denali->reg + DMA_ENABLE); - - dma_unmap_single(denali->dev, dma_addr, size, dir); - - if (irq_status & INTR__ERASED_PAGE) - memset(buf, 0xff, size); - - return ret; -} - -static int denali_data_xfer(struct denali_nand_info *denali, void *buf, - size_t size, int page, int raw, int write) -{ - iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); - iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0, - denali->reg + TRANSFER_SPARE_REG); - - if (denali->dma_avail) - return denali_dma_xfer(denali, buf, size, page, raw, write); - else - return denali_pio_xfer(denali, buf, size, page, raw, write); -} - -static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, - int page, int write) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0; - unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT; - int writesize = mtd->writesize; - int oobsize = mtd->oobsize; - uint8_t *bufpoi = chip->oob_poi; - int ecc_steps = chip->ecc.steps; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; - int oob_skip = denali->oob_skip_bytes; - size_t size = writesize + oobsize; - int i, pos, len; - - /* BBM at the beginning of the OOB area */ - chip->cmdfunc(mtd, start_cmd, writesize, page); - if (write) - chip->write_buf(mtd, bufpoi, oob_skip); - else - chip->read_buf(mtd, bufpoi, oob_skip); - bufpoi += oob_skip; - - /* OOB ECC */ - for (i = 0; i < ecc_steps; i++) { - pos = ecc_size + i * (ecc_size + ecc_bytes); - len = ecc_bytes; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - chip->cmdfunc(mtd, rnd_cmd, pos, -1); - if (write) - chip->write_buf(mtd, bufpoi, len); - else - chip->read_buf(mtd, bufpoi, len); - bufpoi += len; - if (len < ecc_bytes) { - len = ecc_bytes - len; - chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1); - if (write) - chip->write_buf(mtd, bufpoi, len); - else - chip->read_buf(mtd, bufpoi, len); - bufpoi += len; - } - } - - /* OOB free */ - len = oobsize - (bufpoi - chip->oob_poi); - chip->cmdfunc(mtd, rnd_cmd, size - len, -1); - if (write) - chip->write_buf(mtd, bufpoi, len); - else - chip->read_buf(mtd, bufpoi, len); -} - -static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - int writesize = mtd->writesize; - int oobsize = mtd->oobsize; - int ecc_steps = chip->ecc.steps; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; - void *tmp_buf = denali->buf; - int oob_skip = denali->oob_skip_bytes; - size_t size = writesize + oobsize; - int ret, i, pos, len; - - ret = denali_data_xfer(denali, tmp_buf, size, page, 1, 0); - if (ret) - return ret; - - /* Arrange the buffer for syndrome payload/ecc layout */ - if (buf) { - for (i = 0; i < ecc_steps; i++) { - pos = i * (ecc_size + ecc_bytes); - len = ecc_size; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - memcpy(buf, tmp_buf + pos, len); - buf += len; - if (len < ecc_size) { - len = ecc_size - len; - memcpy(buf, tmp_buf + writesize + oob_skip, - len); - buf += len; - } - } - } - - if (oob_required) { - uint8_t *oob = chip->oob_poi; - - /* BBM at the beginning of the OOB area */ - memcpy(oob, tmp_buf + writesize, oob_skip); - oob += oob_skip; - - /* OOB ECC */ - for (i = 0; i < ecc_steps; i++) { - pos = ecc_size + i * (ecc_size + ecc_bytes); - len = ecc_bytes; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - memcpy(oob, tmp_buf + pos, len); - oob += len; - if (len < ecc_bytes) { - len = ecc_bytes - len; - memcpy(oob, tmp_buf + writesize + oob_skip, - len); - oob += len; - } - } - - /* OOB free */ - len = oobsize - (oob - chip->oob_poi); - memcpy(oob, tmp_buf + size - len, len); - } - - return 0; -} - -static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - denali_oob_xfer(mtd, chip, page, 0); - - return 0; -} - -static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - int status; - - denali_reset_irq(denali); - - denali_oob_xfer(mtd, chip, page, 1); - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - - return status & NAND_STATUS_FAIL ? -EIO : 0; -} - -static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - unsigned long uncor_ecc_flags = 0; - int stat = 0; - int ret; - - ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0); - if (ret && ret != -EBADMSG) - return ret; - - if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) - stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); - else if (ret == -EBADMSG) - stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf); - - if (stat < 0) - return stat; - - if (uncor_ecc_flags) { - ret = denali_read_oob(mtd, chip, page); - if (ret) - return ret; - - stat = denali_check_erased_page(mtd, chip, buf, - uncor_ecc_flags, stat); - } - - 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) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - int writesize = mtd->writesize; - int oobsize = mtd->oobsize; - int ecc_steps = chip->ecc.steps; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; - void *tmp_buf = denali->buf; - int oob_skip = denali->oob_skip_bytes; - size_t size = writesize + oobsize; - int i, pos, len; - - /* - * Fill the buffer with 0xff first except the full page transfer. - * This simplifies the logic. - */ - if (!buf || !oob_required) - memset(tmp_buf, 0xff, size); - - /* Arrange the buffer for syndrome payload/ecc layout */ - if (buf) { - for (i = 0; i < ecc_steps; i++) { - pos = i * (ecc_size + ecc_bytes); - len = ecc_size; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - memcpy(tmp_buf + pos, buf, len); - buf += len; - if (len < ecc_size) { - len = ecc_size - len; - memcpy(tmp_buf + writesize + oob_skip, buf, - len); - buf += len; - } - } - } - - if (oob_required) { - const uint8_t *oob = chip->oob_poi; - - /* BBM at the beginning of the OOB area */ - memcpy(tmp_buf + writesize, oob, oob_skip); - oob += oob_skip; - - /* OOB ECC */ - for (i = 0; i < ecc_steps; i++) { - pos = ecc_size + i * (ecc_size + ecc_bytes); - len = ecc_bytes; - - if (pos >= writesize) - pos += oob_skip; - else if (pos + len > writesize) - len = writesize - pos; - - memcpy(tmp_buf + pos, oob, len); - oob += len; - if (len < ecc_bytes) { - len = ecc_bytes - len; - memcpy(tmp_buf + writesize + oob_skip, oob, - len); - oob += len; - } - } - - /* OOB free */ - len = oobsize - (oob - chip->oob_poi); - memcpy(tmp_buf + size - len, oob, len); - } - - 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) -{ - 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) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - - denali->active_bank = chip; -} - -static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_status; - - /* R/B# pin transitioned from low to high? */ - irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); - - return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; -} - -static int denali_erase(struct mtd_info *mtd, int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_status; - - denali_reset_irq(denali); - - denali->host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page, - DENALI_ERASE); - - /* wait for erase to complete or failure to occur */ - irq_status = denali_wait_for_irq(denali, - INTR__ERASE_COMP | INTR__ERASE_FAIL); - - return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL; -} - -static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, - const struct nand_data_interface *conf) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - const struct nand_sdr_timings *timings; - unsigned long t_clk; - int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data; - int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup; - int addr_2_data_mask; - uint32_t tmp; - - timings = nand_get_sdr_timings(conf); - if (IS_ERR(timings)) - return PTR_ERR(timings); - - /* clk_x period in picoseconds */ - t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate); - if (!t_clk) - return -EINVAL; - - if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) - return 0; - - /* tREA -> ACC_CLKS */ - acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk); - acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE); - - tmp = ioread32(denali->reg + ACC_CLKS); - tmp &= ~ACC_CLKS__VALUE; - tmp |= FIELD_PREP(ACC_CLKS__VALUE, acc_clks); - iowrite32(tmp, denali->reg + ACC_CLKS); - - /* tRWH -> RE_2_WE */ - re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk); - re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE); - - tmp = ioread32(denali->reg + RE_2_WE); - tmp &= ~RE_2_WE__VALUE; - tmp |= FIELD_PREP(RE_2_WE__VALUE, re_2_we); - iowrite32(tmp, denali->reg + RE_2_WE); - - /* tRHZ -> RE_2_RE */ - re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk); - re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE); - - tmp = ioread32(denali->reg + RE_2_RE); - tmp &= ~RE_2_RE__VALUE; - tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re); - iowrite32(tmp, denali->reg + RE_2_RE); - - /* - * tCCS, tWHR -> WE_2_RE - * - * With WE_2_RE properly set, the Denali controller automatically takes - * care of the delay; the driver need not set NAND_WAIT_TCCS. - */ - we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min), - t_clk); - we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE); - - tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE); - tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE; - tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re); - iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE); - - /* tADL -> ADDR_2_DATA */ - - /* for older versions, ADDR_2_DATA is only 6 bit wide */ - addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; - if (denali->revision < 0x0501) - addr_2_data_mask >>= 1; - - addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk); - addr_2_data = min_t(int, addr_2_data, addr_2_data_mask); - - tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA); - tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; - tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, addr_2_data); - iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA); - - /* tREH, tWH -> RDWR_EN_HI_CNT */ - rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min), - t_clk); - rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE); - - tmp = ioread32(denali->reg + RDWR_EN_HI_CNT); - tmp &= ~RDWR_EN_HI_CNT__VALUE; - tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi); - iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT); - - /* tRP, tWP -> RDWR_EN_LO_CNT */ - rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), - t_clk); - rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min), - t_clk); - rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT); - rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi); - rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE); - - tmp = ioread32(denali->reg + RDWR_EN_LO_CNT); - tmp &= ~RDWR_EN_LO_CNT__VALUE; - tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo); - iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT); - - /* tCS, tCEA -> CS_SETUP_CNT */ - cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo, - (int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks, - 0); - cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE); - - tmp = ioread32(denali->reg + CS_SETUP_CNT); - tmp &= ~CS_SETUP_CNT__VALUE; - tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup); - iowrite32(tmp, denali->reg + CS_SETUP_CNT); - - return 0; -} - -static void denali_reset_banks(struct denali_nand_info *denali) -{ - u32 irq_status; - int i; - - for (i = 0; i < denali->max_banks; i++) { - denali->active_bank = i; - - denali_reset_irq(denali); - - iowrite32(DEVICE_RESET__BANK(i), - denali->reg + DEVICE_RESET); - - irq_status = denali_wait_for_irq(denali, - INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT); - if (!(irq_status & INTR__INT_ACT)) - break; - } - - dev_dbg(denali->dev, "%d chips connected\n", i); - denali->max_banks = i; -} - -static void denali_hw_init(struct denali_nand_info *denali) -{ - /* - * The REVISION register may not be reliable. Platforms are allowed to - * override it. - */ - if (!denali->revision) - denali->revision = swab16(ioread32(denali->reg + REVISION)); - - /* - * tell driver how many bit controller will skip before writing - * ECC code in OOB. This is normally used for bad block marker - */ - denali->oob_skip_bytes = CONFIG_NAND_DENALI_SPARE_AREA_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); - - iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); -} - -int denali_calc_ecc_bytes(int step_size, int strength) -{ - /* BCH code. Denali requires ecc.bytes to be multiple of 2 */ - return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2; -} -EXPORT_SYMBOL(denali_calc_ecc_bytes); - -static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip, - struct denali_nand_info *denali) -{ - int oobavail = mtd->oobsize - denali->oob_skip_bytes; - int ret; - - /* - * If .size and .strength are already set (usually by DT), - * check if they are supported by this controller. - */ - if (chip->ecc.size && chip->ecc.strength) - return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail); - - /* - * We want .size and .strength closest to the chip's requirement - * unless NAND_ECC_MAXIMIZE is requested. - */ - if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) { - ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail); - if (!ret) - return 0; - } - - /* Max ECC strength is the last thing we can do */ - return nand_maximize_ecc(chip, denali->ecc_caps, oobavail); -} - -static struct nand_ecclayout nand_oob; - -static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); - - if (section) - return -ERANGE; - - oobregion->offset = denali->oob_skip_bytes; - oobregion->length = chip->ecc.total; - - return 0; -} - -static int denali_ooblayout_free(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - struct nand_chip *chip = mtd_to_nand(mtd); - - if (section) - return -ERANGE; - - oobregion->offset = chip->ecc.total + denali->oob_skip_bytes; - oobregion->length = mtd->oobsize - oobregion->offset; - - return 0; -} - -static const struct mtd_ooblayout_ops denali_ooblayout_ops = { - .ecc = denali_ooblayout_ecc, - .free = denali_ooblayout_free, -}; - -static int denali_multidev_fixup(struct denali_nand_info *denali) -{ - struct nand_chip *chip = &denali->nand; - struct mtd_info *mtd = nand_to_mtd(chip); - - /* - * Support for multi device: - * When the IP configuration is x16 capable and two x8 chips are - * connected in parallel, DEVICES_CONNECTED should be set to 2. - * In this case, the core framework knows nothing about this fact, - * so we should tell it the _logical_ pagesize and anything necessary. - */ - denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED); - - /* - * On some SoCs, DEVICES_CONNECTED is not auto-detected. - * For those, DEVICES_CONNECTED is left to 0. Set 1 if it is the case. - */ - if (denali->devs_per_cs == 0) { - denali->devs_per_cs = 1; - iowrite32(1, denali->reg + DEVICES_CONNECTED); - } - - if (denali->devs_per_cs == 1) - return 0; - - if (denali->devs_per_cs != 2) { - dev_err(denali->dev, "unsupported number of devices %d\n", - denali->devs_per_cs); - return -EINVAL; - } - - /* 2 chips in parallel */ - mtd->size <<= 1; - mtd->erasesize <<= 1; - mtd->writesize <<= 1; - mtd->oobsize <<= 1; - chip->chipsize <<= 1; - chip->page_shift += 1; - chip->phys_erase_shift += 1; - chip->bbt_erase_shift += 1; - chip->chip_shift += 1; - chip->pagemask <<= 1; - chip->ecc.size <<= 1; - chip->ecc.bytes <<= 1; - chip->ecc.strength <<= 1; - denali->oob_skip_bytes <<= 1; - - return 0; -} - -int denali_init(struct denali_nand_info *denali) -{ - struct nand_chip *chip = &denali->nand; - struct mtd_info *mtd = nand_to_mtd(chip); - u32 features = ioread32(denali->reg + FEATURES); - int ret; - - denali_hw_init(denali); - - denali_clear_irq_all(denali); - - denali_reset_banks(denali); - - denali->active_bank = DENALI_INVALID_BANK; - - chip->flash_node = dev_of_offset(denali->dev); - /* Fallback to the default name if DT did not give "label" property */ - if (!mtd->name) - mtd->name = "denali-nand"; - - chip->select_chip = denali_select_chip; - chip->read_byte = denali_read_byte; - chip->write_byte = denali_write_byte; - chip->read_word = denali_read_word; - chip->cmd_ctrl = denali_cmd_ctrl; - chip->dev_ready = denali_dev_ready; - chip->waitfunc = denali_waitfunc; - - if (features & FEATURES__INDEX_ADDR) { - denali->host_read = denali_indexed_read; - denali->host_write = denali_indexed_write; - } else { - denali->host_read = denali_direct_read; - denali->host_write = denali_direct_write; - } - - /* clk rate info is needed for setup_data_interface */ - if (denali->clk_x_rate) - chip->setup_data_interface = denali_setup_data_interface; - - ret = nand_scan_ident(mtd, denali->max_banks, NULL); - if (ret) - return ret; - - if (ioread32(denali->reg + FEATURES) & FEATURES__DMA) - denali->dma_avail = 1; - - if (denali->dma_avail) { - chip->buf_align = ARCH_DMA_MINALIGN; - if (denali->caps & DENALI_CAP_DMA_64BIT) - denali->setup_dma = denali_setup_dma64; - else - denali->setup_dma = denali_setup_dma32; - } else { - chip->buf_align = 4; - } - - chip->options |= NAND_USE_BOUNCE_BUFFER; - chip->bbt_options |= NAND_BBT_USE_FLASH; - chip->bbt_options |= NAND_BBT_NO_OOB; - denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; - - /* no subpage writes on denali */ - chip->options |= NAND_NO_SUBPAGE_WRITE; - - ret = denali_ecc_setup(mtd, chip, denali); - if (ret) { - dev_err(denali->dev, "Failed to setup ECC settings.\n"); - return ret; - } - - dev_dbg(denali->dev, - "chosen ECC settings: step=%d, strength=%d, bytes=%d\n", - chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); - - iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) | - FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength), - denali->reg + ECC_CORRECTION); - iowrite32(mtd->erasesize / mtd->writesize, - denali->reg + PAGES_PER_BLOCK); - iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, - denali->reg + DEVICE_WIDTH); - iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG, - denali->reg + TWO_ROW_ADDR_CYCLES); - iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE); - iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE); - - iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE); - iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE); - /* chip->ecc.steps is set by nand_scan_tail(); not available here */ - iowrite32(mtd->writesize / chip->ecc.size, - denali->reg + CFG_NUM_DATA_BLOCKS); - - mtd_set_ooblayout(mtd, &denali_ooblayout_ops); - - nand_oob.eccbytes = denali->nand.ecc.bytes; - denali->nand.ecc.layout = &nand_oob; - - if (chip->options & NAND_BUSWIDTH_16) { - chip->read_buf = denali_read_buf16; - chip->write_buf = denali_write_buf16; - } else { - chip->read_buf = denali_read_buf; - chip->write_buf = denali_write_buf; - } - chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS; - chip->ecc.read_page = denali_read_page; - chip->ecc.read_page_raw = denali_read_page_raw; - chip->ecc.write_page = denali_write_page; - 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; - - ret = denali_multidev_fixup(denali); - if (ret) - return ret; - - /* - * This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not - * use devm_kmalloc() because the memory allocated by devm_ does not - * guarantee DMA-safe alignment. - */ - denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); - if (!denali->buf) - return -ENOMEM; - - ret = nand_scan_tail(mtd); - if (ret) - goto free_buf; - - ret = nand_register(0, mtd); - if (ret) { - dev_err(denali->dev, "Failed to register MTD: %d\n", ret); - goto free_buf; - } - return 0; - -free_buf: - kfree(denali->buf); - - return ret; -} diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h deleted file mode 100644 index 9b797beffa..0000000000 --- a/drivers/mtd/nand/denali.h +++ /dev/null @@ -1,325 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013-2014 Altera Corporation - * Copyright (C) 2009-2010, Intel Corporation and its suppliers. - */ - -#ifndef __DENALI_H__ -#define __DENALI_H__ - -#include -#include -#include - -#define DEVICE_RESET 0x0 -#define DEVICE_RESET__BANK(bank) BIT(bank) - -#define TRANSFER_SPARE_REG 0x10 -#define TRANSFER_SPARE_REG__FLAG BIT(0) - -#define LOAD_WAIT_CNT 0x20 -#define LOAD_WAIT_CNT__VALUE GENMASK(15, 0) - -#define PROGRAM_WAIT_CNT 0x30 -#define PROGRAM_WAIT_CNT__VALUE GENMASK(15, 0) - -#define ERASE_WAIT_CNT 0x40 -#define ERASE_WAIT_CNT__VALUE GENMASK(15, 0) - -#define INT_MON_CYCCNT 0x50 -#define INT_MON_CYCCNT__VALUE GENMASK(15, 0) - -#define RB_PIN_ENABLED 0x60 -#define RB_PIN_ENABLED__BANK(bank) BIT(bank) - -#define MULTIPLANE_OPERATION 0x70 -#define MULTIPLANE_OPERATION__FLAG BIT(0) - -#define MULTIPLANE_READ_ENABLE 0x80 -#define MULTIPLANE_READ_ENABLE__FLAG BIT(0) - -#define COPYBACK_DISABLE 0x90 -#define COPYBACK_DISABLE__FLAG BIT(0) - -#define CACHE_WRITE_ENABLE 0xa0 -#define CACHE_WRITE_ENABLE__FLAG BIT(0) - -#define CACHE_READ_ENABLE 0xb0 -#define CACHE_READ_ENABLE__FLAG BIT(0) - -#define PREFETCH_MODE 0xc0 -#define PREFETCH_MODE__PREFETCH_EN BIT(0) -#define PREFETCH_MODE__PREFETCH_BURST_LENGTH GENMASK(15, 4) - -#define CHIP_ENABLE_DONT_CARE 0xd0 -#define CHIP_EN_DONT_CARE__FLAG BIT(0) - -#define ECC_ENABLE 0xe0 -#define ECC_ENABLE__FLAG BIT(0) - -#define GLOBAL_INT_ENABLE 0xf0 -#define GLOBAL_INT_EN_FLAG BIT(0) - -#define TWHR2_AND_WE_2_RE 0x100 -#define TWHR2_AND_WE_2_RE__WE_2_RE GENMASK(5, 0) -#define TWHR2_AND_WE_2_RE__TWHR2 GENMASK(13, 8) - -#define TCWAW_AND_ADDR_2_DATA 0x110 -/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */ -#define TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA GENMASK(6, 0) -#define TCWAW_AND_ADDR_2_DATA__TCWAW GENMASK(13, 8) - -#define RE_2_WE 0x120 -#define RE_2_WE__VALUE GENMASK(5, 0) - -#define ACC_CLKS 0x130 -#define ACC_CLKS__VALUE GENMASK(3, 0) - -#define NUMBER_OF_PLANES 0x140 -#define NUMBER_OF_PLANES__VALUE GENMASK(2, 0) - -#define PAGES_PER_BLOCK 0x150 -#define PAGES_PER_BLOCK__VALUE GENMASK(15, 0) - -#define DEVICE_WIDTH 0x160 -#define DEVICE_WIDTH__VALUE GENMASK(1, 0) - -#define DEVICE_MAIN_AREA_SIZE 0x170 -#define DEVICE_MAIN_AREA_SIZE__VALUE GENMASK(15, 0) - -#define DEVICE_SPARE_AREA_SIZE 0x180 -#define DEVICE_SPARE_AREA_SIZE__VALUE GENMASK(15, 0) - -#define TWO_ROW_ADDR_CYCLES 0x190 -#define TWO_ROW_ADDR_CYCLES__FLAG BIT(0) - -#define MULTIPLANE_ADDR_RESTRICT 0x1a0 -#define MULTIPLANE_ADDR_RESTRICT__FLAG BIT(0) - -#define ECC_CORRECTION 0x1b0 -#define ECC_CORRECTION__VALUE GENMASK(4, 0) -#define ECC_CORRECTION__ERASE_THRESHOLD GENMASK(31, 16) - -#define READ_MODE 0x1c0 -#define READ_MODE__VALUE GENMASK(3, 0) - -#define WRITE_MODE 0x1d0 -#define WRITE_MODE__VALUE GENMASK(3, 0) - -#define COPYBACK_MODE 0x1e0 -#define COPYBACK_MODE__VALUE GENMASK(3, 0) - -#define RDWR_EN_LO_CNT 0x1f0 -#define RDWR_EN_LO_CNT__VALUE GENMASK(4, 0) - -#define RDWR_EN_HI_CNT 0x200 -#define RDWR_EN_HI_CNT__VALUE GENMASK(4, 0) - -#define MAX_RD_DELAY 0x210 -#define MAX_RD_DELAY__VALUE GENMASK(3, 0) - -#define CS_SETUP_CNT 0x220 -#define CS_SETUP_CNT__VALUE GENMASK(4, 0) -#define CS_SETUP_CNT__TWB GENMASK(17, 12) - -#define SPARE_AREA_SKIP_BYTES 0x230 -#define SPARE_AREA_SKIP_BYTES__VALUE GENMASK(5, 0) - -#define SPARE_AREA_MARKER 0x240 -#define SPARE_AREA_MARKER__VALUE GENMASK(15, 0) - -#define DEVICES_CONNECTED 0x250 -#define DEVICES_CONNECTED__VALUE GENMASK(2, 0) - -#define DIE_MASK 0x260 -#define DIE_MASK__VALUE GENMASK(7, 0) - -#define FIRST_BLOCK_OF_NEXT_PLANE 0x270 -#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE GENMASK(15, 0) - -#define WRITE_PROTECT 0x280 -#define WRITE_PROTECT__FLAG BIT(0) - -#define RE_2_RE 0x290 -#define RE_2_RE__VALUE GENMASK(5, 0) - -#define MANUFACTURER_ID 0x300 -#define MANUFACTURER_ID__VALUE GENMASK(7, 0) - -#define DEVICE_ID 0x310 -#define DEVICE_ID__VALUE GENMASK(7, 0) - -#define DEVICE_PARAM_0 0x320 -#define DEVICE_PARAM_0__VALUE GENMASK(7, 0) - -#define DEVICE_PARAM_1 0x330 -#define DEVICE_PARAM_1__VALUE GENMASK(7, 0) - -#define DEVICE_PARAM_2 0x340 -#define DEVICE_PARAM_2__VALUE GENMASK(7, 0) - -#define LOGICAL_PAGE_DATA_SIZE 0x350 -#define LOGICAL_PAGE_DATA_SIZE__VALUE GENMASK(15, 0) - -#define LOGICAL_PAGE_SPARE_SIZE 0x360 -#define LOGICAL_PAGE_SPARE_SIZE__VALUE GENMASK(15, 0) - -#define REVISION 0x370 -#define REVISION__VALUE GENMASK(15, 0) - -#define ONFI_DEVICE_FEATURES 0x380 -#define ONFI_DEVICE_FEATURES__VALUE GENMASK(5, 0) - -#define ONFI_OPTIONAL_COMMANDS 0x390 -#define ONFI_OPTIONAL_COMMANDS__VALUE GENMASK(5, 0) - -#define ONFI_TIMING_MODE 0x3a0 -#define ONFI_TIMING_MODE__VALUE GENMASK(5, 0) - -#define ONFI_PGM_CACHE_TIMING_MODE 0x3b0 -#define ONFI_PGM_CACHE_TIMING_MODE__VALUE GENMASK(5, 0) - -#define ONFI_DEVICE_NO_OF_LUNS 0x3c0 -#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS GENMASK(7, 0) -#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE BIT(8) - -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L 0x3d0 -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE GENMASK(15, 0) - -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U 0x3e0 -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE GENMASK(15, 0) - -#define FEATURES 0x3f0 -#define FEATURES__N_BANKS GENMASK(1, 0) -#define FEATURES__ECC_MAX_ERR GENMASK(5, 2) -#define FEATURES__DMA BIT(6) -#define FEATURES__CMD_DMA BIT(7) -#define FEATURES__PARTITION BIT(8) -#define FEATURES__XDMA_SIDEBAND BIT(9) -#define FEATURES__GPREG BIT(10) -#define FEATURES__INDEX_ADDR BIT(11) - -#define TRANSFER_MODE 0x400 -#define TRANSFER_MODE__VALUE GENMASK(1, 0) - -#define INTR_STATUS(bank) (0x410 + (bank) * 0x50) -#define INTR_EN(bank) (0x420 + (bank) * 0x50) -/* bit[1:0] is used differently depending on IP version */ -#define INTR__ECC_UNCOR_ERR BIT(0) /* new IP */ -#define INTR__ECC_TRANSACTION_DONE BIT(0) /* old IP */ -#define INTR__ECC_ERR BIT(1) /* old IP */ -#define INTR__DMA_CMD_COMP BIT(2) -#define INTR__TIME_OUT BIT(3) -#define INTR__PROGRAM_FAIL BIT(4) -#define INTR__ERASE_FAIL BIT(5) -#define INTR__LOAD_COMP BIT(6) -#define INTR__PROGRAM_COMP BIT(7) -#define INTR__ERASE_COMP BIT(8) -#define INTR__PIPE_CPYBCK_CMD_COMP BIT(9) -#define INTR__LOCKED_BLK BIT(10) -#define INTR__UNSUP_CMD BIT(11) -#define INTR__INT_ACT BIT(12) -#define INTR__RST_COMP BIT(13) -#define INTR__PIPE_CMD_ERR BIT(14) -#define INTR__PAGE_XFER_INC BIT(15) -#define INTR__ERASED_PAGE BIT(16) - -#define PAGE_CNT(bank) (0x430 + (bank) * 0x50) -#define ERR_PAGE_ADDR(bank) (0x440 + (bank) * 0x50) -#define ERR_BLOCK_ADDR(bank) (0x450 + (bank) * 0x50) - -#define ECC_THRESHOLD 0x600 -#define ECC_THRESHOLD__VALUE GENMASK(9, 0) - -#define ECC_ERROR_BLOCK_ADDRESS 0x610 -#define ECC_ERROR_BLOCK_ADDRESS__VALUE GENMASK(15, 0) - -#define ECC_ERROR_PAGE_ADDRESS 0x620 -#define ECC_ERROR_PAGE_ADDRESS__VALUE GENMASK(11, 0) -#define ECC_ERROR_PAGE_ADDRESS__BANK GENMASK(15, 12) - -#define ECC_ERROR_ADDRESS 0x630 -#define ECC_ERROR_ADDRESS__OFFSET GENMASK(11, 0) -#define ECC_ERROR_ADDRESS__SECTOR GENMASK(15, 12) - -#define ERR_CORRECTION_INFO 0x640 -#define ERR_CORRECTION_INFO__BYTE GENMASK(7, 0) -#define ERR_CORRECTION_INFO__DEVICE GENMASK(11, 8) -#define ERR_CORRECTION_INFO__UNCOR BIT(14) -#define ERR_CORRECTION_INFO__LAST_ERR BIT(15) - -#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10) -#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8) -#define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0) -#define ECC_COR_INFO__UNCOR_ERR BIT(7) - -#define CFG_DATA_BLOCK_SIZE 0x6b0 - -#define CFG_LAST_DATA_BLOCK_SIZE 0x6c0 - -#define CFG_NUM_DATA_BLOCKS 0x6d0 - -#define CFG_META_DATA_SIZE 0x6e0 - -#define DMA_ENABLE 0x700 -#define DMA_ENABLE__FLAG BIT(0) - -#define IGNORE_ECC_DONE 0x710 -#define IGNORE_ECC_DONE__FLAG BIT(0) - -#define DMA_INTR 0x720 -#define DMA_INTR_EN 0x730 -#define DMA_INTR__TARGET_ERROR BIT(0) -#define DMA_INTR__DESC_COMP_CHANNEL0 BIT(1) -#define DMA_INTR__DESC_COMP_CHANNEL1 BIT(2) -#define DMA_INTR__DESC_COMP_CHANNEL2 BIT(3) -#define DMA_INTR__DESC_COMP_CHANNEL3 BIT(4) -#define DMA_INTR__MEMCOPY_DESC_COMP BIT(5) - -#define TARGET_ERR_ADDR_LO 0x740 -#define TARGET_ERR_ADDR_LO__VALUE GENMASK(15, 0) - -#define TARGET_ERR_ADDR_HI 0x750 -#define TARGET_ERR_ADDR_HI__VALUE GENMASK(15, 0) - -#define CHNL_ACTIVE 0x760 -#define CHNL_ACTIVE__CHANNEL0 BIT(0) -#define CHNL_ACTIVE__CHANNEL1 BIT(1) -#define CHNL_ACTIVE__CHANNEL2 BIT(2) -#define CHNL_ACTIVE__CHANNEL3 BIT(3) - -struct udevice; - -struct denali_nand_info { - struct nand_chip nand; - unsigned long clk_x_rate; /* bus interface clock rate */ - int active_bank; /* currently selected bank */ - struct udevice *dev; - uint32_t page; - void __iomem *reg; /* Register Interface */ - void __iomem *host; /* Host Data/Command Interface */ - u32 irq_mask; /* interrupts we are waiting for */ - u32 irq_status; /* interrupts that have happened */ - int irq; - void *buf; /* for syndrome layout conversion */ - dma_addr_t dma_addr; - int dma_avail; /* can support DMA? */ - int devs_per_cs; /* devices connected in parallel */ - int oob_skip_bytes; /* number of bytes reserved for BBM */ - int max_banks; - unsigned int revision; /* IP revision */ - unsigned int caps; /* IP capability (or quirk) */ - const struct nand_ecc_caps *ecc_caps; - u32 (*host_read)(struct denali_nand_info *denali, u32 addr); - void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data); - void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr, - int page, int write); -}; - -#define DENALI_CAP_HW_ECC_FIXUP BIT(0) -#define DENALI_CAP_DMA_64BIT BIT(1) - -int denali_calc_ecc_bytes(int step_size, int strength); -int denali_init(struct denali_nand_info *denali); - -#endif /* __DENALI_H__ */ diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c deleted file mode 100644 index 65a7797f0f..0000000000 --- a/drivers/mtd/nand/denali_dt.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2017 Socionext Inc. - * Author: Masahiro Yamada - */ - -#include -#include -#include -#include -#include - -#include "denali.h" - -struct denali_dt_data { - unsigned int revision; - unsigned int caps; - const struct nand_ecc_caps *ecc_caps; -}; - -NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes, - 512, 8, 15); -static const struct denali_dt_data denali_socfpga_data = { - .caps = DENALI_CAP_HW_ECC_FIXUP, - .ecc_caps = &denali_socfpga_ecc_caps, -}; - -NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes, - 1024, 8, 16, 24); -static const struct denali_dt_data denali_uniphier_v5a_data = { - .caps = DENALI_CAP_HW_ECC_FIXUP | - DENALI_CAP_DMA_64BIT, - .ecc_caps = &denali_uniphier_v5a_ecc_caps, -}; - -NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes, - 1024, 8, 16); -static const struct denali_dt_data denali_uniphier_v5b_data = { - .revision = 0x0501, - .caps = DENALI_CAP_HW_ECC_FIXUP | - DENALI_CAP_DMA_64BIT, - .ecc_caps = &denali_uniphier_v5b_ecc_caps, -}; - -static const struct udevice_id denali_nand_dt_ids[] = { - { - .compatible = "altr,socfpga-denali-nand", - .data = (unsigned long)&denali_socfpga_data, - }, - { - .compatible = "socionext,uniphier-denali-nand-v5a", - .data = (unsigned long)&denali_uniphier_v5a_data, - }, - { - .compatible = "socionext,uniphier-denali-nand-v5b", - .data = (unsigned long)&denali_uniphier_v5b_data, - }, - { /* sentinel */ } -}; - -static int denali_dt_probe(struct udevice *dev) -{ - struct denali_nand_info *denali = dev_get_priv(dev); - const struct denali_dt_data *data; - struct clk clk; - struct resource res; - int ret; - - data = (void *)dev_get_driver_data(dev); - if (data) { - denali->revision = data->revision; - denali->caps = data->caps; - denali->ecc_caps = data->ecc_caps; - } - - denali->dev = dev; - - ret = dev_read_resource_byname(dev, "denali_reg", &res); - if (ret) - return ret; - - denali->reg = devm_ioremap(dev, res.start, resource_size(&res)); - - ret = dev_read_resource_byname(dev, "nand_data", &res); - if (ret) - return ret; - - denali->host = devm_ioremap(dev, res.start, resource_size(&res)); - - ret = clk_get_by_index(dev, 0, &clk); - if (ret) - return ret; - - ret = clk_enable(&clk); - if (ret) - return ret; - - denali->clk_x_rate = clk_get_rate(&clk); - - return denali_init(denali); -} - -U_BOOT_DRIVER(denali_nand_dt) = { - .name = "denali-nand-dt", - .id = UCLASS_MISC, - .of_match = denali_nand_dt_ids, - .probe = denali_dt_probe, - .priv_auto_alloc_size = sizeof(struct denali_nand_info), -}; - -void board_nand_init(void) -{ - struct udevice *dev; - int ret; - - ret = uclass_get_device_by_driver(UCLASS_MISC, - DM_GET_DRIVER(denali_nand_dt), - &dev); - if (ret && ret != -ENODEV) - pr_err("Failed to initialize Denali NAND controller. (error %d)\n", - ret); -} diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/denali_spl.c deleted file mode 100644 index dbaba3cab2..0000000000 --- a/drivers/mtd/nand/denali_spl.c +++ /dev/null @@ -1,228 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2014 Panasonic Corporation - * Copyright (C) 2014-2015 Masahiro Yamada - */ - -#include -#include -#include -#include -#include "denali.h" - -#define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */ -#define DENALI_MAP10 (2 << 26) /* high-level control plane */ - -#define INDEX_CTRL_REG 0x0 -#define INDEX_DATA_REG 0x10 - -#define SPARE_ACCESS 0x41 -#define MAIN_ACCESS 0x42 -#define PIPELINE_ACCESS 0x2000 - -#define BANK(x) ((x) << 24) - -static void __iomem *denali_flash_mem = - (void __iomem *)CONFIG_SYS_NAND_DATA_BASE; -static void __iomem *denali_flash_reg = - (void __iomem *)CONFIG_SYS_NAND_REGS_BASE; - -static const int flash_bank; -static int page_size, oob_size, pages_per_block; - -static void index_addr(uint32_t address, uint32_t data) -{ - writel(address, denali_flash_mem + INDEX_CTRL_REG); - writel(data, denali_flash_mem + INDEX_DATA_REG); -} - -static int wait_for_irq(uint32_t irq_mask) -{ - unsigned long timeout = 1000000; - uint32_t intr_status; - - do { - intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank)); - - if (intr_status & INTR__ECC_UNCOR_ERR) { - debug("Uncorrected ECC detected\n"); - return -EBADMSG; - } - - if (intr_status & irq_mask) - break; - - udelay(1); - timeout--; - } while (timeout); - - if (!timeout) { - debug("Timeout with interrupt status %08x\n", intr_status); - return -EIO; - } - - return 0; -} - -static void read_data_from_flash_mem(uint8_t *buf, int len) -{ - int i; - uint32_t *buf32; - - /* transfer the data from the flash */ - buf32 = (uint32_t *)buf; - - /* - * Let's take care of unaligned access although it rarely happens. - * Avoid put_unaligned() for the normal use cases since it leads to - * a bit performance regression. - */ - if ((unsigned long)buf32 % 4) { - for (i = 0; i < len / 4; i++) - put_unaligned(readl(denali_flash_mem + INDEX_DATA_REG), - buf32++); - } else { - for (i = 0; i < len / 4; i++) - *buf32++ = readl(denali_flash_mem + INDEX_DATA_REG); - } - - if (len % 4) { - u32 tmp; - - tmp = cpu_to_le32(readl(denali_flash_mem + INDEX_DATA_REG)); - buf = (uint8_t *)buf32; - for (i = 0; i < len % 4; i++) { - *buf++ = tmp; - tmp >>= 8; - } - } -} - -int denali_send_pipeline_cmd(int page, int ecc_en, int access_type) -{ - uint32_t addr, cmd; - static uint32_t page_count = 1; - - writel(ecc_en, denali_flash_reg + ECC_ENABLE); - - /* clear all bits of intr_status. */ - writel(0xffff, denali_flash_reg + INTR_STATUS(flash_bank)); - - addr = BANK(flash_bank) | page; - - /* setup the acccess type */ - cmd = DENALI_MAP10 | addr; - index_addr(cmd, access_type); - - /* setup the pipeline command */ - index_addr(cmd, PIPELINE_ACCESS | page_count); - - cmd = DENALI_MAP01 | addr; - writel(cmd, denali_flash_mem + INDEX_CTRL_REG); - - return wait_for_irq(INTR__LOAD_COMP); -} - -static int nand_read_oob(void *buf, int page) -{ - int ret; - - ret = denali_send_pipeline_cmd(page, 0, SPARE_ACCESS); - if (ret < 0) - return ret; - - read_data_from_flash_mem(buf, oob_size); - - return 0; -} - -static int nand_read_page(void *buf, int page) -{ - int ret; - - ret = denali_send_pipeline_cmd(page, 1, MAIN_ACCESS); - if (ret < 0) - return ret; - - read_data_from_flash_mem(buf, page_size); - - return 0; -} - -static int nand_block_isbad(void *buf, int block) -{ - int ret; - - ret = nand_read_oob(buf, block * pages_per_block); - if (ret < 0) - return ret; - - return *((uint8_t *)buf + CONFIG_SYS_NAND_BAD_BLOCK_POS) != 0xff; -} - -/* nand_init() - initialize data to make nand usable by SPL */ -void nand_init(void) -{ - /* access to main area */ - writel(0, denali_flash_reg + TRANSFER_SPARE_REG); - - /* - * These registers are expected to be already set by the hardware - * or earlier boot code. So we read these values out. - */ - page_size = readl(denali_flash_reg + DEVICE_MAIN_AREA_SIZE); - oob_size = readl(denali_flash_reg + DEVICE_SPARE_AREA_SIZE); - pages_per_block = readl(denali_flash_reg + PAGES_PER_BLOCK); -} - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - int block, page, column, readlen; - int ret; - int force_bad_block_check = 1; - - page = offs / page_size; - column = offs % page_size; - - block = page / pages_per_block; - page = page % pages_per_block; - - while (size) { - if (force_bad_block_check || page == 0) { - ret = nand_block_isbad(dst, block); - if (ret < 0) - return ret; - - if (ret) { - block++; - continue; - } - } - - force_bad_block_check = 0; - - ret = nand_read_page(dst, block * pages_per_block + page); - if (ret < 0) - return ret; - - readlen = min(page_size - column, (int)size); - - if (unlikely(column)) { - /* Partial page read */ - memmove(dst, dst + column, readlen); - column = 0; - } - - size -= readlen; - dst += readlen; - page++; - if (page == pages_per_block) { - block++; - page = 0; - } - } - - return 0; -} - -void nand_deselect(void) {} diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c deleted file mode 100644 index 263d46ec8f..0000000000 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ /dev/null @@ -1,810 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* Freescale Enhanced Local Bus Controller FCM NAND driver - * - * Copyright (c) 2006-2008 Freescale Semiconductor - * - * Authors: Nick Spence , - * Scott Wood - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#ifdef VERBOSE_DEBUG -#define DEBUG_ELBC -#define vdbg(format, arg...) printf("DEBUG: " format, ##arg) -#else -#define vdbg(format, arg...) do {} while (0) -#endif - -/* Can't use plain old DEBUG because the linux mtd - * headers define it as a macro. - */ -#ifdef DEBUG_ELBC -#define dbg(format, arg...) printf("DEBUG: " format, ##arg) -#else -#define dbg(format, arg...) do {} while (0) -#endif - -#define MAX_BANKS 8 -#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ - -#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC) - -struct fsl_elbc_ctrl; - -/* mtd information per set */ - -struct fsl_elbc_mtd { - struct nand_chip chip; - struct fsl_elbc_ctrl *ctrl; - - struct device *dev; - int bank; /* Chip select bank number */ - u8 __iomem *vbase; /* Chip select base virtual address */ - int page_size; /* NAND page size (0=512, 1=2048) */ - unsigned int fmr; /* FCM Flash Mode Register value */ -}; - -/* overview of the fsl elbc controller */ - -struct fsl_elbc_ctrl { - struct nand_hw_control controller; - struct fsl_elbc_mtd *chips[MAX_BANKS]; - - /* device info */ - fsl_lbc_t *regs; - u8 __iomem *addr; /* Address of assigned FCM buffer */ - unsigned int page; /* Last page written to / read from */ - unsigned int read_bytes; /* Number of bytes read during command */ - unsigned int column; /* Saved column from SEQIN */ - unsigned int index; /* Pointer to next byte to 'read' */ - unsigned int status; /* status read from LTESR after last op */ - unsigned int mdr; /* UPM/FCM Data Register value */ - unsigned int use_mdr; /* Non zero if the MDR is to be set */ - unsigned int oob; /* Non zero if operating on OOB data */ -}; - -/* These map to the positions used by the FCM hardware ECC generator */ - -/* Small Page FLASH with FMR[ECCM] = 0 */ -static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = { - .eccbytes = 3, - .eccpos = {6, 7, 8}, - .oobfree = { {0, 5}, {9, 7} }, -}; - -/* Small Page FLASH with FMR[ECCM] = 1 */ -static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = { - .eccbytes = 3, - .eccpos = {8, 9, 10}, - .oobfree = { {0, 5}, {6, 2}, {11, 5} }, -}; - -/* Large Page FLASH with FMR[ECCM] = 0 */ -static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = { - .eccbytes = 12, - .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, - .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, -}; - -/* Large Page FLASH with FMR[ECCM] = 1 */ -static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { - .eccbytes = 12, - .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, - .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, -}; - -/* - * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset - * 1, so we have to adjust bad block pattern. This pattern should be used for - * x8 chips only. So far hardware does not support x16 chips anyway. - */ -static u8 scan_ff_pattern[] = { 0xff, }; - -static struct nand_bbt_descr largepage_memorybased = { - .options = 0, - .offs = 0, - .len = 1, - .pattern = scan_ff_pattern, -}; - -/* - * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, - * interfere with ECC positions, that's why we implement our own descriptors. - * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. - */ -static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; -static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 11, - .len = 4, - .veroffs = 15, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 11, - .len = 4, - .veroffs = 15, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - -/*=================================*/ - -/* - * Set up the FCM hardware block and page address fields, and the fcm - * structure addr field to point to the correct FCM buffer in memory - */ -static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - int buf_num; - - ctrl->page = page_addr; - - if (priv->page_size) { - out_be32(&lbc->fbar, page_addr >> 6); - out_be32(&lbc->fpar, - ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) | - (oob ? FPAR_LP_MS : 0) | column); - buf_num = (page_addr & 1) << 2; - } else { - out_be32(&lbc->fbar, page_addr >> 5); - out_be32(&lbc->fpar, - ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) | - (oob ? FPAR_SP_MS : 0) | column); - buf_num = page_addr & 7; - } - - ctrl->addr = priv->vbase + buf_num * 1024; - ctrl->index = column; - - /* for OOB data point to the second half of the buffer */ - if (oob) - ctrl->index += priv->page_size ? 2048 : 512; - - vdbg("set_addr: bank=%d, ctrl->addr=0x%p (0x%p), " - "index %x, pes %d ps %d\n", - buf_num, ctrl->addr, priv->vbase, ctrl->index, - chip->phys_erase_shift, chip->page_shift); -} - -/* - * execute FCM command and wait for it to complete - */ -static int fsl_elbc_run_command(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - u32 timeo = (CONFIG_SYS_HZ * 10) / 1000; - u32 time_start; - u32 ltesr; - - /* Setup the FMR[OP] to execute without write protection */ - out_be32(&lbc->fmr, priv->fmr | 3); - if (ctrl->use_mdr) - out_be32(&lbc->mdr, ctrl->mdr); - - vdbg("fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n", - in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr)); - vdbg("fsl_elbc_run_command: fbar=%08x fpar=%08x " - "fbcr=%08x bank=%d\n", - in_be32(&lbc->fbar), in_be32(&lbc->fpar), - in_be32(&lbc->fbcr), priv->bank); - - /* execute special operation */ - out_be32(&lbc->lsor, priv->bank); - - /* wait for FCM complete flag or timeout */ - time_start = get_timer(0); - - ltesr = 0; - while (get_timer(time_start) < timeo) { - ltesr = in_be32(&lbc->ltesr); - if (ltesr & LTESR_CC) - break; - } - - ctrl->status = ltesr & LTESR_NAND_MASK; - out_be32(&lbc->ltesr, ctrl->status); - out_be32(&lbc->lteatr, 0); - - /* store mdr value in case it was needed */ - if (ctrl->use_mdr) - ctrl->mdr = in_be32(&lbc->mdr); - - ctrl->use_mdr = 0; - - vdbg("fsl_elbc_run_command: stat=%08x mdr=%08x fmr=%08x\n", - ctrl->status, ctrl->mdr, in_be32(&lbc->fmr)); - - /* returns 0 on success otherwise non-zero) */ - return ctrl->status == LTESR_CC ? 0 : -EIO; -} - -static void fsl_elbc_do_read(struct nand_chip *chip, int oob) -{ - struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - - if (priv->page_size) { - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_CW1 << FIR_OP3_SHIFT) | - (FIR_OP_RBW << FIR_OP4_SHIFT)); - - out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | - (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); - } else { - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_RBW << FIR_OP3_SHIFT)); - - if (oob) - out_be32(&lbc->fcr, - NAND_CMD_READOOB << FCR_CMD0_SHIFT); - else - out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); - } -} - -/* cmdfunc send commands to the FCM */ -static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - - ctrl->use_mdr = 0; - - /* clear the read buffer */ - ctrl->read_bytes = 0; - if (command != NAND_CMD_PAGEPROG) - ctrl->index = 0; - - switch (command) { - /* READ0 and READ1 read the entire buffer to use hardware ECC. */ - case NAND_CMD_READ1: - column += 256; - - /* fall-through */ - case NAND_CMD_READ0: - vdbg("fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" - " 0x%x, column: 0x%x.\n", page_addr, column); - - out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */ - set_addr(mtd, 0, page_addr, 0); - - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - ctrl->index += column; - - fsl_elbc_do_read(chip, 0); - fsl_elbc_run_command(mtd); - return; - - /* READOOB reads only the OOB because no ECC is performed. */ - case NAND_CMD_READOOB: - vdbg("fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" - " 0x%x, column: 0x%x.\n", page_addr, column); - - out_be32(&lbc->fbcr, mtd->oobsize - column); - set_addr(mtd, column, page_addr, 1); - - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - - fsl_elbc_do_read(chip, 1); - fsl_elbc_run_command(mtd); - - return; - - /* READID must read all 5 possible bytes while CEB is active */ - case NAND_CMD_READID: - case NAND_CMD_PARAM: - vdbg("fsl_elbc_cmdfunc: NAND_CMD 0x%x.\n", command); - - out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_UA << FIR_OP1_SHIFT) | - (FIR_OP_RBW << FIR_OP2_SHIFT)); - out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT); - /* - * although currently it's 8 bytes for READID, we always read - * the maximum 256 bytes(for PARAM) - */ - out_be32(&lbc->fbcr, 256); - ctrl->read_bytes = 256; - ctrl->use_mdr = 1; - ctrl->mdr = column; - set_addr(mtd, 0, 0, 0); - fsl_elbc_run_command(mtd); - return; - - /* ERASE1 stores the block and page address */ - case NAND_CMD_ERASE1: - vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE1, " - "page_addr: 0x%x.\n", page_addr); - set_addr(mtd, 0, page_addr, 0); - return; - - /* ERASE2 uses the block and page address from ERASE1 */ - case NAND_CMD_ERASE2: - vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); - - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_PA << FIR_OP1_SHIFT) | - (FIR_OP_CM1 << FIR_OP2_SHIFT)); - - out_be32(&lbc->fcr, - (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) | - (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT)); - - out_be32(&lbc->fbcr, 0); - ctrl->read_bytes = 0; - - fsl_elbc_run_command(mtd); - return; - - /* SEQIN sets up the addr buffer and all registers except the length */ - case NAND_CMD_SEQIN: { - u32 fcr; - vdbg("fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " - "page_addr: 0x%x, column: 0x%x.\n", - page_addr, column); - - ctrl->column = column; - ctrl->oob = 0; - - if (priv->page_size) { - fcr = (NAND_CMD_SEQIN << FCR_CMD0_SHIFT) | - (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT); - - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_WB << FIR_OP3_SHIFT) | - (FIR_OP_CW1 << FIR_OP4_SHIFT)); - } else { - fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) | - (NAND_CMD_SEQIN << FCR_CMD2_SHIFT); - - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CM2 << FIR_OP1_SHIFT) | - (FIR_OP_CA << FIR_OP2_SHIFT) | - (FIR_OP_PA << FIR_OP3_SHIFT) | - (FIR_OP_WB << FIR_OP4_SHIFT) | - (FIR_OP_CW1 << FIR_OP5_SHIFT)); - - if (column >= mtd->writesize) { - /* OOB area --> READOOB */ - column -= mtd->writesize; - fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT; - ctrl->oob = 1; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT; - } else { - /* Second 256 bytes --> READ1 */ - fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT; - } - } - - out_be32(&lbc->fcr, fcr); - set_addr(mtd, column, page_addr, ctrl->oob); - return; - } - - /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ - case NAND_CMD_PAGEPROG: { - vdbg("fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " - "writing %d bytes.\n", ctrl->index); - - /* if the write did not start at 0 or is not a full page - * then set the exact length, otherwise use a full page - * write so the HW generates the ECC. - */ - if (ctrl->oob || ctrl->column != 0 || - ctrl->index != mtd->writesize + mtd->oobsize) - out_be32(&lbc->fbcr, ctrl->index); - else - out_be32(&lbc->fbcr, 0); - - fsl_elbc_run_command(mtd); - - return; - } - - /* CMD_STATUS must read the status byte while CEB is active */ - /* Note - it does not wait for the ready line */ - case NAND_CMD_STATUS: - out_be32(&lbc->fir, - (FIR_OP_CM0 << FIR_OP0_SHIFT) | - (FIR_OP_RBW << FIR_OP1_SHIFT)); - out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); - out_be32(&lbc->fbcr, 1); - set_addr(mtd, 0, 0, 0); - ctrl->read_bytes = 1; - - fsl_elbc_run_command(mtd); - - /* The chip always seems to report that it is - * write-protected, even when it is not. - */ - out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); - return; - - /* RESET without waiting for the ready line */ - case NAND_CMD_RESET: - dbg("fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); - out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT); - out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT); - fsl_elbc_run_command(mtd); - return; - - default: - printf("fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", - command); - } -} - -static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip) -{ - /* The hardware does not seem to support multiple - * chips per bank. - */ -} - -/* - * Write buf to the FCM Controller Data Buffer - */ -static void fsl_elbc_write_buf(struct mtd_info *mtd, const 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_ctrl *ctrl = priv->ctrl; - unsigned int bufsize = mtd->writesize + mtd->oobsize; - - if (len <= 0) { - printf("write_buf of %d bytes", len); - ctrl->status = 0; - return; - } - - if ((unsigned int)len > bufsize - ctrl->index) { - printf("write_buf beyond end of buffer " - "(%d requested, %u available)\n", - len, bufsize - ctrl->index); - len = bufsize - ctrl->index; - } - - memcpy_toio(&ctrl->addr[ctrl->index], buf, len); - /* - * This is workaround for the weird elbc hangs during nand write, - * Scott Wood says: "...perhaps difference in how long it takes a - * write to make it through the localbus compared to a write to IMMR - * is causing problems, and sync isn't helping for some reason." - * Reading back the last byte helps though. - */ - in_8(&ctrl->addr[ctrl->index] + len - 1); - - ctrl->index += 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) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - - /* If there are still bytes in the FCM, then use the next byte. */ - if (ctrl->index < ctrl->read_bytes) - return in_8(&ctrl->addr[ctrl->index++]); - - printf("read_byte beyond end of buffer\n"); - return ERR_BYTE; -} - -/* - * Read from the FCM Controller Data Buffer - */ -static void fsl_elbc_read_buf(struct mtd_info *mtd, 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_ctrl *ctrl = priv->ctrl; - int avail; - - if (len < 0) - return; - - avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); - memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail); - ctrl->index += avail; - - if (len > avail) - printf("read_buf beyond end of buffer " - "(%d requested, %d available)\n", - len, avail); -} - -/* 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) -{ - struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - - if (ctrl->status != LTESR_CC) - return NAND_STATUS_FAIL; - - /* Use READ_STATUS command, but wait for the device to be ready */ - ctrl->use_mdr = 0; - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_RBW << FIR_OP1_SHIFT)); - out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); - out_be32(&lbc->fbcr, 1); - set_addr(mtd, 0, 0, 0); - ctrl->read_bytes = 1; - - fsl_elbc_run_command(mtd); - - if (ctrl->status != LTESR_CC) - return NAND_STATUS_FAIL; - - /* The chip always seems to report that it is - * write-protected, even when it is not. - */ - out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); - return fsl_elbc_read_byte(mtd); -} - -static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - fsl_elbc_read_buf(mtd, buf, mtd->writesize); - fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); - - if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL) - mtd->ecc_stats.failed++; - - return 0; -} - -/* 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) -{ - fsl_elbc_write_buf(mtd, buf, mtd->writesize); - fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -static struct fsl_elbc_ctrl *elbc_ctrl; - -/* 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) -{ - fsl_elbc_write_buf(mtd, buf, mtd->writesize); - fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -static void fsl_elbc_ctrl_init(void) -{ - elbc_ctrl = kzalloc(sizeof(*elbc_ctrl), GFP_KERNEL); - if (!elbc_ctrl) - return; - - elbc_ctrl->regs = LBC_BASE_ADDR; - - /* clear event registers */ - out_be32(&elbc_ctrl->regs->ltesr, LTESR_NAND_MASK); - out_be32(&elbc_ctrl->regs->lteatr, 0); - - /* Enable interrupts for any detected events */ - out_be32(&elbc_ctrl->regs->lteir, LTESR_NAND_MASK); - - elbc_ctrl->read_bytes = 0; - elbc_ctrl->index = 0; - elbc_ctrl->addr = NULL; -} - -static int fsl_elbc_chip_init(int devnum, u8 *addr) -{ - struct mtd_info *mtd; - struct nand_chip *nand; - struct fsl_elbc_mtd *priv; - uint32_t br = 0, or = 0; - int ret; - - if (!elbc_ctrl) { - fsl_elbc_ctrl_init(); - if (!elbc_ctrl) - return -1; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->ctrl = elbc_ctrl; - priv->vbase = addr; - - /* Find which chip select it is connected to. It'd be nice - * if we could pass more than one datum to the NAND driver... - */ - for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { - phys_addr_t phys_addr = virt_to_phys(addr); - - br = in_be32(&elbc_ctrl->regs->bank[priv->bank].br); - or = in_be32(&elbc_ctrl->regs->bank[priv->bank].or); - - if ((br & BR_V) && (br & BR_MSEL) == BR_MS_FCM && - (br & or & BR_BA) == BR_PHYS_ADDR(phys_addr)) - break; - } - - if (priv->bank >= MAX_BANKS) { - printf("fsl_elbc_nand: address did not match any " - "chip selects\n"); - kfree(priv); - return -ENODEV; - } - - nand = &priv->chip; - mtd = nand_to_mtd(nand); - - elbc_ctrl->chips[priv->bank] = priv; - - /* fill in nand_chip structure */ - /* set up function call table */ - nand->read_byte = fsl_elbc_read_byte; - nand->write_buf = fsl_elbc_write_buf; - nand->read_buf = fsl_elbc_read_buf; - nand->select_chip = fsl_elbc_select_chip; - nand->cmdfunc = fsl_elbc_cmdfunc; - nand->waitfunc = fsl_elbc_wait; - - /* set up nand options */ - nand->bbt_td = &bbt_main_descr; - nand->bbt_md = &bbt_mirror_descr; - - /* set up nand options */ - nand->options = NAND_NO_SUBPAGE_WRITE; - nand->bbt_options = NAND_BBT_USE_FLASH; - - nand->controller = &elbc_ctrl->controller; - nand_set_controller_data(nand, priv); - - nand->ecc.read_page = fsl_elbc_read_page; - nand->ecc.write_page = fsl_elbc_write_page; - nand->ecc.write_subpage = fsl_elbc_write_subpage; - - priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT); - - /* If CS Base Register selects full hardware ECC then use it */ - if ((br & BR_DECC) == BR_DECC_CHK_GEN) { - nand->ecc.mode = NAND_ECC_HW; - - nand->ecc.layout = (priv->fmr & FMR_ECCM) ? - &fsl_elbc_oob_sp_eccm1 : - &fsl_elbc_oob_sp_eccm0; - - nand->ecc.size = 512; - nand->ecc.bytes = 3; - nand->ecc.steps = 1; - nand->ecc.strength = 1; - } else { - /* otherwise fall back to software ECC */ -#if defined(CONFIG_NAND_ECC_BCH) - nand->ecc.mode = NAND_ECC_SOFT_BCH; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif - } - - ret = nand_scan_ident(mtd, 1, NULL); - if (ret) - return ret; - - /* Large-page-specific setup */ - if (mtd->writesize == 2048) { - setbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, - OR_FCM_PGS); - in_be32(&elbc_ctrl->regs->bank[priv->bank].or); - - priv->page_size = 1; - nand->badblock_pattern = &largepage_memorybased; - - /* - * Hardware expects small page has ECCM0, large page has - * ECCM1 when booting from NAND, and we follow that even - * when not booting from NAND. - */ - priv->fmr |= FMR_ECCM; - - /* adjust ecc setup if needed */ - if ((br & BR_DECC) == BR_DECC_CHK_GEN) { - nand->ecc.steps = 4; - nand->ecc.layout = (priv->fmr & FMR_ECCM) ? - &fsl_elbc_oob_lp_eccm1 : - &fsl_elbc_oob_lp_eccm0; - } - } else if (mtd->writesize == 512) { - clrbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, - OR_FCM_PGS); - in_be32(&elbc_ctrl->regs->bank[priv->bank].or); - } else { - return -ENODEV; - } - - ret = nand_scan_tail(mtd); - if (ret) - return ret; - - ret = nand_register(devnum, mtd); - if (ret) - return ret; - - return 0; -} - -#ifndef CONFIG_SYS_NAND_BASE_LIST -#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } -#endif - -static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] = - CONFIG_SYS_NAND_BASE_LIST; - -void board_nand_init(void) -{ - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - fsl_elbc_chip_init(i, (u8 *)base_address[i]); -} diff --git a/drivers/mtd/nand/fsl_elbc_spl.c b/drivers/mtd/nand/fsl_elbc_spl.c deleted file mode 100644 index 30c3308940..0000000000 --- a/drivers/mtd/nand/fsl_elbc_spl.c +++ /dev/null @@ -1,167 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * NAND boot for Freescale Enhanced Local Bus Controller, Flash Control Machine - * - * (C) Copyright 2006-2008 - * Stefan Roese, DENX Software Engineering, sr@denx.de. - * - * Copyright (c) 2008 Freescale Semiconductor, Inc. - * Author: Scott Wood - */ - -#include -#include -#include -#include - -#define WINDOW_SIZE 8192 - -static void nand_wait(void) -{ - fsl_lbc_t *regs = LBC_BASE_ADDR; - - for (;;) { - uint32_t status = in_be32(®s->ltesr); - - if (status == 1) - return; - - if (status & 1) { - puts("read failed (ltesr)\n"); - for (;;); - } - } -} - -#ifdef CONFIG_TPL_BUILD -int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) -#else -static int nand_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) -#endif -{ - fsl_lbc_t *regs = LBC_BASE_ADDR; - uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE; - const int large = CONFIG_SYS_NAND_OR_PRELIM & OR_FCM_PGS; - const int block_shift = large ? 17 : 14; - const int block_size = 1 << block_shift; - const int page_size = large ? 2048 : 512; - const int bad_marker = large ? page_size + 0 : page_size + 5; - int fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT) | 2; - int pos = 0; - char *dst = vdst; - - if (offs & (block_size - 1)) { - puts("bad offset\n"); - for (;;); - } - - if (large) { - fmr |= FMR_ECCM; - out_be32(®s->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | - (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); - out_be32(®s->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_CW1 << FIR_OP3_SHIFT) | - (FIR_OP_RBW << FIR_OP4_SHIFT)); - } else { - out_be32(®s->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); - out_be32(®s->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_RBW << FIR_OP3_SHIFT)); - } - - out_be32(®s->fbcr, 0); - clrsetbits_be32(®s->bank[0].br, BR_DECC, BR_DECC_CHK_GEN); - - while (pos < uboot_size) { - int i = 0; - out_be32(®s->fbar, offs >> block_shift); - - do { - int j; - unsigned int page_offs = (offs & (block_size - 1)) << 1; - - out_be32(®s->ltesr, ~0); - out_be32(®s->lteatr, 0); - out_be32(®s->fpar, page_offs); - out_be32(®s->fmr, fmr); - out_be32(®s->lsor, 0); - nand_wait(); - - page_offs %= WINDOW_SIZE; - - /* - * If either of the first two pages are marked bad, - * continue to the next block. - */ - if (i++ < 2 && buf[page_offs + bad_marker] != 0xff) { - puts("skipping\n"); - offs = (offs + block_size) & ~(block_size - 1); - pos &= ~(block_size - 1); - break; - } - - for (j = 0; j < page_size; j++) - dst[pos + j] = buf[page_offs + j]; - - pos += page_size; - offs += page_size; - } while ((offs & (block_size - 1)) && (pos < uboot_size)); - } - - return 0; -} - -/* - * Defines a static function nand_load_image() here, because non-static makes - * the code too large for certain SPLs(minimal SPL, maximum size <= 4Kbytes) - */ -#ifndef CONFIG_TPL_BUILD -#define nand_spl_load_image(offs, uboot_size, vdst) \ - nand_load_image(offs, uboot_size, vdst) -#endif - -/* - * The main entry for NAND booting. It's necessary that SDRAM is already - * configured and available since this code loads the main U-Boot image - * from NAND into SDRAM and starts it from there. - */ -void nand_boot(void) -{ - __attribute__((noreturn)) void (*uboot)(void); - /* - * Load U-Boot image from NAND into RAM - */ - nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, - CONFIG_SYS_NAND_U_BOOT_SIZE, - (void *)CONFIG_SYS_NAND_U_BOOT_DST); - -#ifdef CONFIG_NAND_ENV_DST - nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, - (void *)CONFIG_NAND_ENV_DST); - -#ifdef CONFIG_ENV_OFFSET_REDUND - nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, - (void *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); -#endif -#endif - -#ifdef CONFIG_SPL_FLUSH_IMAGE - /* - * Clean d-cache and invalidate i-cache, to - * make sure that no stale data is executed. - */ - flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); -#endif - - puts("transfering control\n"); - /* - * Jump to U-Boot image - */ - uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; - (*uboot)(); -} diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c deleted file mode 100644 index 29f30d8ccc..0000000000 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ /dev/null @@ -1,1064 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* Integrated Flash Controller NAND Machine Driver - * - * Copyright (c) 2012 Freescale Semiconductor, Inc - * - * Authors: Dipen Dudhat - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#ifndef CONFIG_SYS_FSL_IFC_BANK_COUNT -#define CONFIG_SYS_FSL_IFC_BANK_COUNT 4 -#endif - -#define MAX_BANKS CONFIG_SYS_FSL_IFC_BANK_COUNT -#define ERR_BYTE 0xFF /* Value returned for read bytes - when read failed */ - -struct fsl_ifc_ctrl; - -/* mtd information per set */ -struct fsl_ifc_mtd { - struct nand_chip chip; - struct fsl_ifc_ctrl *ctrl; - - struct device *dev; - int bank; /* Chip select bank number */ - unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */ - u8 __iomem *vbase; /* Chip select base virtual address */ -}; - -/* overview of the fsl ifc controller */ -struct fsl_ifc_ctrl { - struct nand_hw_control controller; - struct fsl_ifc_mtd *chips[MAX_BANKS]; - - /* device info */ - struct fsl_ifc regs; - void __iomem *addr; /* Address of assigned IFC buffer */ - unsigned int page; /* Last page written to / read from */ - unsigned int read_bytes; /* Number of bytes read during command */ - unsigned int column; /* Saved column from SEQIN */ - unsigned int index; /* Pointer to next byte to 'read' */ - unsigned int status; /* status read from NEESR after last op */ - unsigned int oob; /* Non zero if operating on OOB data */ - unsigned int eccread; /* Non zero for a full-page ECC read */ -}; - -static struct fsl_ifc_ctrl *ifc_ctrl; - -/* 512-byte page with 4-bit ECC, 8-bit */ -static struct nand_ecclayout oob_512_8bit_ecc4 = { - .eccbytes = 8, - .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, - .oobfree = { {0, 5}, {6, 2} }, -}; - -/* 512-byte page with 4-bit ECC, 16-bit */ -static struct nand_ecclayout oob_512_16bit_ecc4 = { - .eccbytes = 8, - .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, - .oobfree = { {2, 6}, }, -}; - -/* 2048-byte page size with 4-bit ECC */ -static struct nand_ecclayout oob_2048_ecc4 = { - .eccbytes = 32, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - }, - .oobfree = { {2, 6}, {40, 24} }, -}; - -/* 4096-byte page size with 4-bit ECC */ -static struct nand_ecclayout oob_4096_ecc4 = { - .eccbytes = 64, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - }, - .oobfree = { {2, 6}, {72, 56} }, -}; - -/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */ -static struct nand_ecclayout oob_4096_ecc8 = { - .eccbytes = 128, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, - }, - .oobfree = { {2, 6}, {136, 82} }, -}; - -/* 8192-byte page size with 4-bit ECC */ -static struct nand_ecclayout oob_8192_ecc4 = { - .eccbytes = 128, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, - }, - .oobfree = { {2, 6}, {136, 208} }, -}; - -/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */ -static struct nand_ecclayout oob_8192_ecc8 = { - .eccbytes = 256, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, - }, - .oobfree = { {2, 6}, {264, 80} }, -}; - -/* - * Generic flash bbt descriptors - */ -static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; -static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 2, /* 0 on 8-bit small page */ - .len = 4, - .veroffs = 6, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 2, /* 0 on 8-bit small page */ - .len = 4, - .veroffs = 6, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - -/* - * Set up the IFC hardware block and page address fields, and the ifc nand - * structure addr field to point to the correct IFC buffer in memory - */ -static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; - int buf_num; - - ctrl->page = page_addr; - - /* Program ROW0/COL0 */ - ifc_out32(&ifc->ifc_nand.row0, page_addr); - ifc_out32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column); - - buf_num = page_addr & priv->bufnum_mask; - - ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2); - ctrl->index = column; - - /* for OOB data point to the second half of the buffer */ - if (oob) - ctrl->index += mtd->writesize; -} - -/* returns nonzero if entire page is blank */ -static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl, - u32 eccstat, unsigned int bufnum) -{ - return (eccstat >> ((3 - bufnum % 4) * 8)) & 15; -} - -/* - * execute IFC NAND command and wait for it to complete - */ -static int fsl_ifc_run_command(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; - u32 timeo = (CONFIG_SYS_HZ * 10) / 1000; - u32 time_start; - u32 eccstat; - int i; - - /* set the chip select for NAND Transaction */ - ifc_out32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT); - - /* start read/write seq */ - ifc_out32(&ifc->ifc_nand.nandseq_strt, - IFC_NAND_SEQ_STRT_FIR_STRT); - - /* wait for NAND Machine complete flag or timeout */ - time_start = get_timer(0); - - while (get_timer(time_start) < timeo) { - ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat); - - if (ctrl->status & IFC_NAND_EVTER_STAT_OPC) - break; - } - - ifc_out32(&ifc->ifc_nand.nand_evter_stat, ctrl->status); - - if (ctrl->status & IFC_NAND_EVTER_STAT_FTOER) - printf("%s: Flash Time Out Error\n", __func__); - if (ctrl->status & IFC_NAND_EVTER_STAT_WPER) - printf("%s: Write Protect Error\n", __func__); - - if (ctrl->eccread) { - int errors; - int bufnum = ctrl->page & priv->bufnum_mask; - int sector_start = bufnum * chip->ecc.steps; - int sector_end = sector_start + chip->ecc.steps - 1; - u32 *eccstat_regs; - - eccstat_regs = ifc->ifc_nand.nand_eccstat; - eccstat = ifc_in32(&eccstat_regs[sector_start / 4]); - - for (i = sector_start; i <= sector_end; i++) { - if ((i != sector_start) && !(i % 4)) - eccstat = ifc_in32(&eccstat_regs[i / 4]); - - errors = check_read_ecc(mtd, ctrl, eccstat, i); - - if (errors == 15) { - /* - * Uncorrectable error. - * We'll check for blank pages later. - * - * We disable ECCER reporting due to erratum - * IFC-A002770 -- so report it now if we - * see an uncorrectable error in ECCSTAT. - */ - ctrl->status |= IFC_NAND_EVTER_STAT_ECCER; - continue; - } - - mtd->ecc_stats.corrected += errors; - } - - ctrl->eccread = 0; - } - - /* returns 0 on success otherwise non-zero) */ - return ctrl->status == IFC_NAND_EVTER_STAT_OPC ? 0 : -EIO; -} - -static void fsl_ifc_do_read(struct nand_chip *chip, - int oob, - struct mtd_info *mtd) -{ - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; - - /* Program FIR/IFC_NAND_FCR0 for Small/Large page */ - if (mtd->writesize > 512) { - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0); - - ifc_out32(&ifc->ifc_nand.nand_fcr0, - (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); - } else { - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT)); - - if (oob) - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT); - else - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); - } -} - -/* 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); - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; - - /* clear the read buffer */ - ctrl->read_bytes = 0; - if (command != NAND_CMD_PAGEPROG) - ctrl->index = 0; - - switch (command) { - /* READ0 read the entire buffer to use hardware ECC. */ - case NAND_CMD_READ0: { - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); - set_addr(mtd, 0, page_addr, 0); - - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - ctrl->index += column; - - if (chip->ecc.mode == NAND_ECC_HW) - ctrl->eccread = 1; - - fsl_ifc_do_read(chip, 0, mtd); - fsl_ifc_run_command(mtd); - return; - } - - /* READOOB reads only the OOB because no ECC is performed. */ - case NAND_CMD_READOOB: - ifc_out32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column); - set_addr(mtd, column, page_addr, 1); - - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - - fsl_ifc_do_read(chip, 1, mtd); - fsl_ifc_run_command(mtd); - - return; - - /* READID must read all possible bytes while CEB is active */ - case NAND_CMD_READID: - case NAND_CMD_PARAM: { - int timing = IFC_FIR_OP_RB; - if (command == NAND_CMD_PARAM) - timing = IFC_FIR_OP_RBCD; - - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | - (timing << IFC_NAND_FIR0_OP2_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fcr0, - command << IFC_NAND_FCR0_CMD0_SHIFT); - ifc_out32(&ifc->ifc_nand.row3, column); - - /* - * although currently it's 8 bytes for READID, we always read - * the maximum 256 bytes(for PARAM) - */ - ifc_out32(&ifc->ifc_nand.nand_fbcr, 256); - ctrl->read_bytes = 256; - - set_addr(mtd, 0, 0, 0); - fsl_ifc_run_command(mtd); - return; - } - - /* ERASE1 stores the block and page address */ - case NAND_CMD_ERASE1: - set_addr(mtd, 0, page_addr, 0); - return; - - /* ERASE2 uses the block and page address from ERASE1 */ - case NAND_CMD_ERASE2: - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT)); - - ifc_out32(&ifc->ifc_nand.nand_fcr0, - (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT)); - - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); - ctrl->read_bytes = 0; - fsl_ifc_run_command(mtd); - return; - - /* SEQIN sets up the addr buffer and all registers except the length */ - case NAND_CMD_SEQIN: { - u32 nand_fcr0; - ctrl->column = column; - ctrl->oob = 0; - - if (mtd->writesize > 512) { - nand_fcr0 = - (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) | - (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT); - - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_WBCD << - IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fir1, - (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) | - (IFC_FIR_OP_RDSTAT << - IFC_NAND_FIR1_OP6_SHIFT) | - (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT)); - } else { - nand_fcr0 = ((NAND_CMD_PAGEPROG << - IFC_NAND_FCR0_CMD1_SHIFT) | - (NAND_CMD_SEQIN << - IFC_NAND_FCR0_CMD2_SHIFT) | - (NAND_CMD_STATUS << - IFC_NAND_FCR0_CMD3_SHIFT)); - - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fir1, - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) | - (IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) | - (IFC_FIR_OP_RDSTAT << - IFC_NAND_FIR1_OP7_SHIFT) | - (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT)); - - if (column >= mtd->writesize) - nand_fcr0 |= - NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT; - else - nand_fcr0 |= - NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT; - } - - if (column >= mtd->writesize) { - /* OOB area --> READOOB */ - column -= mtd->writesize; - ctrl->oob = 1; - } - ifc_out32(&ifc->ifc_nand.nand_fcr0, nand_fcr0); - set_addr(mtd, column, page_addr, ctrl->oob); - return; - } - - /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ - case NAND_CMD_PAGEPROG: - if (ctrl->oob) - ifc_out32(&ifc->ifc_nand.nand_fbcr, - ctrl->index - ctrl->column); - else - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); - - fsl_ifc_run_command(mtd); - return; - - case NAND_CMD_STATUS: - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT); - ifc_out32(&ifc->ifc_nand.nand_fbcr, 1); - set_addr(mtd, 0, 0, 0); - ctrl->read_bytes = 1; - - fsl_ifc_run_command(mtd); - - /* - * The chip always seems to report that it is - * write-protected, even when it is not. - */ - if (chip->options & NAND_BUSWIDTH_16) - ifc_out16(ctrl->addr, - ifc_in16(ctrl->addr) | NAND_STATUS_WP); - else - out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); - return; - - case NAND_CMD_RESET: - ifc_out32(&ifc->ifc_nand.nand_fir0, - IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT); - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT); - fsl_ifc_run_command(mtd); - return; - - default: - printf("%s: error, unsupported command 0x%x.\n", - __func__, command); - } -} - -/* - * Write buf to the IFC NAND Controller Data Buffer - */ -static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - unsigned int bufsize = mtd->writesize + mtd->oobsize; - - if (len <= 0) { - printf("%s of %d bytes", __func__, len); - ctrl->status = 0; - return; - } - - if ((unsigned int)len > bufsize - ctrl->index) { - printf("%s beyond end of buffer " - "(%d requested, %u available)\n", - __func__, len, bufsize - ctrl->index); - len = bufsize - ctrl->index; - } - - memcpy_toio(ctrl->addr + ctrl->index, buf, len); - ctrl->index += len; -} - -/* - * read a byte from either the IFC hardware buffer if it has any data left - * otherwise issue a command to read a single byte. - */ -static u8 fsl_ifc_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - unsigned int offset; - - /* - * If there are still bytes in the IFC buffer, then use the - * next byte. - */ - if (ctrl->index < ctrl->read_bytes) { - offset = ctrl->index++; - return in_8(ctrl->addr + offset); - } - - printf("%s beyond end of buffer\n", __func__); - return ERR_BYTE; -} - -/* - * 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) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - uint16_t data; - - /* - * If there are still bytes in the IFC buffer, then use the - * next byte. - */ - if (ctrl->index < ctrl->read_bytes) { - data = ifc_in16(ctrl->addr + ctrl->index); - ctrl->index += 2; - return (uint8_t)data; - } - - printf("%s beyond end of buffer\n", __func__); - return ERR_BYTE; -} - -/* - * Read from the IFC Controller Data Buffer - */ -static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - int avail; - - if (len < 0) - return; - - avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); - memcpy_fromio(buf, ctrl->addr + ctrl->index, avail); - ctrl->index += avail; - - if (len > avail) - printf("%s beyond end of buffer " - "(%d requested, %d available)\n", - __func__, len, avail); -} - -/* 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) -{ - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; - u32 nand_fsr; - int status; - - if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) - return NAND_STATUS_FAIL; - - /* Use READ_STATUS command, but wait for the device to be ready */ - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS << - IFC_NAND_FCR0_CMD0_SHIFT); - ifc_out32(&ifc->ifc_nand.nand_fbcr, 1); - set_addr(mtd, 0, 0, 0); - ctrl->read_bytes = 1; - - fsl_ifc_run_command(mtd); - - if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) - return NAND_STATUS_FAIL; - - nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr); - status = nand_fsr >> 24; - - /* Chip sometimes reporting write protect even when it's not */ - return status | NAND_STATUS_WP; -} - -/* - * The controller does not check for bitflips in erased pages, - * therefore software must check instead. - */ -static int -check_erased_page(struct nand_chip *chip, u8 *buf, struct mtd_info *mtd) -{ - u8 *ecc = chip->oob_poi; - const int ecc_size = chip->ecc.bytes; - const int pkt_size = chip->ecc.size; - int i, res, bitflips; - - /* IFC starts ecc bytes at offset 8 in the spare area. */ - ecc += 8; - bitflips = 0; - for (i = 0; i < chip->ecc.steps; i++) { - res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size, - NULL, 0, chip->ecc.strength); - - if (res < 0) { - printf("fsl-ifc: NAND Flash ECC Uncorrectable Error\n"); - mtd->ecc_stats.failed++; - } else if (res > 0) { - mtd->ecc_stats.corrected += res; - } - bitflips = max(res, bitflips); - buf += pkt_size; - ecc += ecc_size; - } - - return bitflips; -} - -static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - - fsl_ifc_read_buf(mtd, buf, mtd->writesize); - fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); - - if (ctrl->status & IFC_NAND_EVTER_STAT_ECCER) - return check_erased_page(chip, buf, mtd); - - if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) - mtd->ecc_stats.failed++; - - return 0; -} - -/* 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) -{ - fsl_ifc_write_buf(mtd, buf, mtd->writesize); - fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -static void fsl_ifc_ctrl_init(void) -{ - uint32_t ver = 0; - ifc_ctrl = kzalloc(sizeof(*ifc_ctrl), GFP_KERNEL); - if (!ifc_ctrl) - return; - - ifc_ctrl->regs.gregs = IFC_FCM_BASE_ADDR; - - ver = ifc_in32(&ifc_ctrl->regs.gregs->ifc_rev); - if (ver >= FSL_IFC_V2_0_0) - ifc_ctrl->regs.rregs = - (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_64KOFFSET; - else - ifc_ctrl->regs.rregs = - (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_4KOFFSET; - - /* clear event registers */ - ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_stat, ~0U); - ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.pgrdcmpl_evt_stat, ~0U); - - /* Enable error and event for any detected errors */ - ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_en, - IFC_NAND_EVTER_EN_OPC_EN | - IFC_NAND_EVTER_EN_PGRDCMPL_EN | - IFC_NAND_EVTER_EN_FTOER_EN | - IFC_NAND_EVTER_EN_WPER_EN); - - ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.ncfgr, 0x0); -} - -static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) -{ -} - -static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv, uint32_t ver) -{ - struct fsl_ifc_runtime *ifc = ifc_ctrl->regs.rregs; - uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0; - uint32_t ncfgr = 0; - u32 timeo = (CONFIG_SYS_HZ * 10) / 1000; - u32 time_start; - - if (ver > FSL_IFC_V1_1_0) { - ncfgr = ifc_in32(&ifc->ifc_nand.ncfgr); - ifc_out32(&ifc->ifc_nand.ncfgr, ncfgr | IFC_NAND_SRAM_INIT_EN); - - /* wait for SRAM_INIT bit to be clear or timeout */ - time_start = get_timer(0); - while (get_timer(time_start) < timeo) { - ifc_ctrl->status = - ifc_in32(&ifc->ifc_nand.nand_evter_stat); - - if (!(ifc_ctrl->status & IFC_NAND_SRAM_INIT_EN)) - return 0; - } - printf("fsl-ifc: Failed to Initialise SRAM\n"); - return 1; - } - - cs = priv->bank; - - /* Save CSOR and CSOR_ext */ - csor = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor); - csor_ext = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext); - - /* chage PageSize 8K and SpareSize 1K*/ - csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000; - ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor_8k); - ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, 0x0000400); - - /* READID */ - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); - ifc_out32(&ifc->ifc_nand.row3, 0x0); - - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0x0); - - /* Program ROW0/COL0 */ - ifc_out32(&ifc->ifc_nand.row0, 0x0); - ifc_out32(&ifc->ifc_nand.col0, 0x0); - - /* set the chip select for NAND Transaction */ - ifc_out32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT); - - /* start read seq */ - ifc_out32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT); - - time_start = get_timer(0); - - while (get_timer(time_start) < timeo) { - ifc_ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat); - - if (ifc_ctrl->status & IFC_NAND_EVTER_STAT_OPC) - break; - } - - if (ifc_ctrl->status != IFC_NAND_EVTER_STAT_OPC) { - printf("fsl-ifc: Failed to Initialise SRAM\n"); - return 1; - } - - ifc_out32(&ifc->ifc_nand.nand_evter_stat, ifc_ctrl->status); - - /* Restore CSOR and CSOR_ext */ - ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor); - ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, csor_ext); - - return 0; -} - -static int fsl_ifc_chip_init(int devnum, u8 *addr) -{ - struct mtd_info *mtd; - struct nand_chip *nand; - struct fsl_ifc_mtd *priv; - struct nand_ecclayout *layout; - struct fsl_ifc_fcm *gregs = NULL; - uint32_t cspr = 0, csor = 0, ver = 0; - int ret = 0; - - if (!ifc_ctrl) { - fsl_ifc_ctrl_init(); - if (!ifc_ctrl) - return -1; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->ctrl = ifc_ctrl; - priv->vbase = addr; - gregs = ifc_ctrl->regs.gregs; - - /* Find which chip select it is connected to. - */ - for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { - phys_addr_t phys_addr = virt_to_phys(addr); - - cspr = ifc_in32(&gregs->cspr_cs[priv->bank].cspr); - csor = ifc_in32(&gregs->csor_cs[priv->bank].csor); - - if ((cspr & CSPR_V) && (cspr & CSPR_MSEL) == CSPR_MSEL_NAND && - (cspr & CSPR_BA) == CSPR_PHYS_ADDR(phys_addr)) - break; - } - - if (priv->bank >= MAX_BANKS) { - printf("%s: address did not match any " - "chip selects\n", __func__); - kfree(priv); - return -ENODEV; - } - - nand = &priv->chip; - mtd = nand_to_mtd(nand); - - ifc_ctrl->chips[priv->bank] = priv; - - /* fill in nand_chip structure */ - /* set up function call table */ - - nand->write_buf = fsl_ifc_write_buf; - nand->read_buf = fsl_ifc_read_buf; - nand->select_chip = fsl_ifc_select_chip; - nand->cmdfunc = fsl_ifc_cmdfunc; - nand->waitfunc = fsl_ifc_wait; - - /* set up nand options */ - nand->bbt_td = &bbt_main_descr; - nand->bbt_md = &bbt_mirror_descr; - - /* set up nand options */ - nand->options = NAND_NO_SUBPAGE_WRITE; - nand->bbt_options = NAND_BBT_USE_FLASH; - - if (cspr & CSPR_PORT_SIZE_16) { - nand->read_byte = fsl_ifc_read_byte16; - nand->options |= NAND_BUSWIDTH_16; - } else { - nand->read_byte = fsl_ifc_read_byte; - } - - nand->controller = &ifc_ctrl->controller; - nand_set_controller_data(nand, priv); - - nand->ecc.read_page = fsl_ifc_read_page; - nand->ecc.write_page = fsl_ifc_write_page; - - /* Hardware generates ECC per 512 Bytes */ - nand->ecc.size = 512; - nand->ecc.bytes = 8; - - switch (csor & CSOR_NAND_PGS_MASK) { - case CSOR_NAND_PGS_512: - if (nand->options & NAND_BUSWIDTH_16) { - layout = &oob_512_16bit_ecc4; - } else { - layout = &oob_512_8bit_ecc4; - - /* Avoid conflict with bad block marker */ - bbt_main_descr.offs = 0; - bbt_mirror_descr.offs = 0; - } - - nand->ecc.strength = 4; - priv->bufnum_mask = 15; - break; - - case CSOR_NAND_PGS_2K: - layout = &oob_2048_ecc4; - nand->ecc.strength = 4; - priv->bufnum_mask = 3; - break; - - case CSOR_NAND_PGS_4K: - if ((csor & CSOR_NAND_ECC_MODE_MASK) == - CSOR_NAND_ECC_MODE_4) { - layout = &oob_4096_ecc4; - nand->ecc.strength = 4; - } else { - layout = &oob_4096_ecc8; - nand->ecc.strength = 8; - nand->ecc.bytes = 16; - } - - priv->bufnum_mask = 1; - break; - - case CSOR_NAND_PGS_8K: - if ((csor & CSOR_NAND_ECC_MODE_MASK) == - CSOR_NAND_ECC_MODE_4) { - layout = &oob_8192_ecc4; - nand->ecc.strength = 4; - } else { - layout = &oob_8192_ecc8; - nand->ecc.strength = 8; - nand->ecc.bytes = 16; - } - - priv->bufnum_mask = 0; - break; - - - default: - printf("ifc nand: bad csor %#x: bad page size\n", csor); - return -ENODEV; - } - - /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */ - if (csor & CSOR_NAND_ECC_DEC_EN) { - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.layout = layout; - } else { - nand->ecc.mode = NAND_ECC_SOFT; - } - - ver = ifc_in32(&gregs->ifc_rev); - if (ver >= FSL_IFC_V1_1_0) - ret = fsl_ifc_sram_init(priv, ver); - if (ret) - return ret; - - if (ver >= FSL_IFC_V2_0_0) - priv->bufnum_mask = (priv->bufnum_mask * 2) + 1; - - ret = nand_scan_ident(mtd, 1, NULL); - if (ret) - return ret; - - ret = nand_scan_tail(mtd); - if (ret) - return ret; - - ret = nand_register(devnum, mtd); - if (ret) - return ret; - return 0; -} - -#ifndef CONFIG_SYS_NAND_BASE_LIST -#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } -#endif - -static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] = - CONFIG_SYS_NAND_BASE_LIST; - -void board_nand_init(void) -{ - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - fsl_ifc_chip_init(i, (u8 *)base_address[i]); -} diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c deleted file mode 100644 index 7137eb4108..0000000000 --- a/drivers/mtd/nand/fsl_ifc_spl.c +++ /dev/null @@ -1,306 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * NAND boot for Freescale Integrated Flash Controller, NAND FCM - * - * Copyright 2011 Freescale Semiconductor, Inc. - * Author: Dipen Dudhat - */ - -#include -#include -#include -#include -#ifdef CONFIG_CHAIN_OF_TRUST -#include -#endif - -static inline int is_blank(uchar *addr, int page_size) -{ - int i; - - for (i = 0; i < page_size; i++) { - if (__raw_readb(&addr[i]) != 0xff) - return 0; - } - - /* - * For the SPL, don't worry about uncorrectable errors - * where the main area is all FFs but shouldn't be. - */ - return 1; -} - -/* returns nonzero if entire page is blank */ -static inline int check_read_ecc(uchar *buf, u32 *eccstat, - unsigned int bufnum, int page_size) -{ - u32 reg = eccstat[bufnum / 4]; - int errors = (reg >> ((3 - bufnum % 4) * 8)) & 0xf; - - if (errors == 0xf) { /* uncorrectable */ - /* Blank pages fail hw ECC checks */ - if (is_blank(buf, page_size)) - return 1; - - puts("ecc error\n"); - for (;;) - ; - } - - return 0; -} - -static inline struct fsl_ifc_runtime *runtime_regs_address(void) -{ - struct fsl_ifc regs = {(void *)CONFIG_SYS_IFC_ADDR, NULL}; - int ver = 0; - - ver = ifc_in32(®s.gregs->ifc_rev); - if (ver >= FSL_IFC_V2_0_0) - regs.rregs = (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_64KOFFSET; - else - regs.rregs = (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_4KOFFSET; - - return regs.rregs; -} - -static inline void nand_wait(uchar *buf, int bufnum, int page_size) -{ - struct fsl_ifc_runtime *ifc = runtime_regs_address(); - u32 status; - u32 eccstat[8]; - int bufperpage = page_size / 512; - int bufnum_end, i; - - bufnum *= bufperpage; - bufnum_end = bufnum + bufperpage - 1; - - do { - status = ifc_in32(&ifc->ifc_nand.nand_evter_stat); - } while (!(status & IFC_NAND_EVTER_STAT_OPC)); - - if (status & IFC_NAND_EVTER_STAT_FTOER) { - puts("flash time out error\n"); - for (;;) - ; - } - - for (i = bufnum / 4; i <= bufnum_end / 4; i++) - eccstat[i] = ifc_in32(&ifc->ifc_nand.nand_eccstat[i]); - - for (i = bufnum; i <= bufnum_end; i++) { - if (check_read_ecc(buf, eccstat, i, page_size)) - break; - } - - ifc_out32(&ifc->ifc_nand.nand_evter_stat, status); -} - -static inline int bad_block(uchar *marker, int port_size) -{ - if (port_size == 8) - return __raw_readb(marker) != 0xff; - else - return __raw_readw((u16 *)marker) != 0xffff; -} - -int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) -{ - struct fsl_ifc_fcm *gregs = (void *)CONFIG_SYS_IFC_ADDR; - struct fsl_ifc_runtime *ifc = NULL; - uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE; - int page_size; - int port_size; - int pages_per_blk; - int blk_size; - int bad_marker = 0; - int bufnum_mask, bufnum, ver = 0; - - int csor, cspr; - int pos = 0; - int j = 0; - - int sram_addr; - int pg_no; - uchar *dst = vdst; - - ifc = runtime_regs_address(); - - /* Get NAND Flash configuration */ - csor = CONFIG_SYS_NAND_CSOR; - cspr = CONFIG_SYS_NAND_CSPR; - - port_size = (cspr & CSPR_PORT_SIZE_16) ? 16 : 8; - - if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_8K) { - page_size = 8192; - bufnum_mask = 0x0; - } else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_4K) { - page_size = 4096; - bufnum_mask = 0x1; - } else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_2K) { - page_size = 2048; - bufnum_mask = 0x3; - } else { - page_size = 512; - bufnum_mask = 0xf; - - if (port_size == 8) - bad_marker = 5; - } - - ver = ifc_in32(&gregs->ifc_rev); - if (ver >= FSL_IFC_V2_0_0) - bufnum_mask = (bufnum_mask * 2) + 1; - - pages_per_blk = - 32 << ((csor & CSOR_NAND_PB_MASK) >> CSOR_NAND_PB_SHIFT); - - blk_size = pages_per_blk * page_size; - - /* Open Full SRAM mapping for spare are access */ - ifc_out32(&ifc->ifc_nand.ncfgr, 0x0); - - /* Clear Boot events */ - ifc_out32(&ifc->ifc_nand.nand_evter_stat, 0xffffffff); - - /* Program FIR/FCR for Large/Small page */ - if (page_size > 512) { - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_BTRD << IFC_NAND_FIR0_OP4_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0); - - ifc_out32(&ifc->ifc_nand.nand_fcr0, - (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); - } else { - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_BTRD << IFC_NAND_FIR0_OP3_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0); - - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); - } - - /* Program FBCR = 0 for full page read */ - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); - - /* Read and copy u-boot on SDRAM from NAND device, In parallel - * check for Bad block if found skip it and read continue to - * next Block - */ - while (pos < uboot_size) { - int i = 0; - do { - pg_no = offs / page_size; - bufnum = pg_no & bufnum_mask; - sram_addr = bufnum * page_size * 2; - - ifc_out32(&ifc->ifc_nand.row0, pg_no); - ifc_out32(&ifc->ifc_nand.col0, 0); - /* start read */ - ifc_out32(&ifc->ifc_nand.nandseq_strt, - IFC_NAND_SEQ_STRT_FIR_STRT); - - /* wait for read to complete */ - nand_wait(&buf[sram_addr], bufnum, page_size); - - /* - * If either of the first two pages are marked bad, - * continue to the next block. - */ - if (i++ < 2 && - bad_block(&buf[sram_addr + page_size + bad_marker], - port_size)) { - puts("skipping\n"); - offs = (offs + blk_size) & ~(blk_size - 1); - pos &= ~(blk_size - 1); - break; - } - - for (j = 0; j < page_size; j++) - dst[pos + j] = __raw_readb(&buf[sram_addr + j]); - - pos += page_size; - offs += page_size; - } while ((offs & (blk_size - 1)) && (pos < uboot_size)); - } - - return 0; -} - -/* - * Main entrypoint for NAND Boot. It's necessary that SDRAM is already - * configured and available since this code loads the main U-Boot image - * from NAND into SDRAM and starts from there. - */ -void nand_boot(void) -{ - __attribute__((noreturn)) void (*uboot)(void); - /* - * Load U-Boot image from NAND into RAM - */ - nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, - CONFIG_SYS_NAND_U_BOOT_SIZE, - (uchar *)CONFIG_SYS_NAND_U_BOOT_DST); - -#ifdef CONFIG_NAND_ENV_DST - nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, - (uchar *)CONFIG_NAND_ENV_DST); - -#ifdef CONFIG_ENV_OFFSET_REDUND - nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, - (uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); -#endif -#endif - /* - * Jump to U-Boot image - */ -#ifdef CONFIG_SPL_FLUSH_IMAGE - /* - * Clean d-cache and invalidate i-cache, to - * make sure that no stale data is executed. - */ - flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); -#endif - -#ifdef CONFIG_CHAIN_OF_TRUST - /* - * U-Boot header is appended at end of U-boot image, so - * calculate U-boot header address using U-boot header size. - */ -#define CONFIG_U_BOOT_HDR_ADDR \ - ((CONFIG_SYS_NAND_U_BOOT_START + \ - CONFIG_SYS_NAND_U_BOOT_SIZE) - \ - CONFIG_U_BOOT_HDR_SIZE) - spl_validate_uboot(CONFIG_U_BOOT_HDR_ADDR, - CONFIG_SYS_NAND_U_BOOT_START); - /* - * In case of failure in validation, spl_validate_uboot would - * not return back in case of Production environment with ITS=1. - * Thus U-Boot will not start. - * In Development environment (ITS=0 and SB_EN=1), the function - * may return back in case of non-fatal failures. - */ -#endif - - uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; - uboot(); -} - -#ifndef CONFIG_SPL_NAND_INIT -void nand_init(void) -{ -} - -void nand_deselect(void) -{ -} -#endif diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c deleted file mode 100644 index dfbdbca3ae..0000000000 --- a/drivers/mtd/nand/fsl_upm.c +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * FSL UPM NAND driver - * - * Copyright (C) 2007 MontaVista Software, Inc. - * Anton Vorontsov - */ - -#include -#include -#include -#include -#include -#include -#include - -static void fsl_upm_start_pattern(struct fsl_upm *upm, u32 pat_offset) -{ - clrsetbits_be32(upm->mxmr, MxMR_MAD_MSK, MxMR_OP_RUNP | pat_offset); - (void)in_be32(upm->mxmr); -} - -static void fsl_upm_end_pattern(struct fsl_upm *upm) -{ - clrbits_be32(upm->mxmr, MxMR_OP_RUNP); - - while (in_be32(upm->mxmr) & MxMR_OP_RUNP) - eieio(); -} - -static void fsl_upm_run_pattern(struct fsl_upm *upm, int width, - void __iomem *io_addr, u32 mar) -{ - out_be32(upm->mar, mar); - (void)in_be32(upm->mar); - switch (width) { - case 8: - out_8(io_addr, 0x0); - break; - case 16: - out_be16(io_addr, 0x0); - break; - case 32: - out_be32(io_addr, 0x0); - break; - } -} - -static void fun_wait(struct fsl_upm_nand *fun) -{ - if (fun->dev_ready) { - while (!fun->dev_ready(fun->chip_nr)) - debug("unexpected busy state\n"); - } else { - /* - * If the R/B pin is not connected, - * a short delay is necessary. - */ - udelay(1); - } -} - -#if CONFIG_SYS_NAND_MAX_CHIPS > 1 -static void fun_select_chip(struct mtd_info *mtd, int chip_nr) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_upm_nand *fun = nand_get_controller_data(chip); - - if (chip_nr >= 0) { - fun->chip_nr = chip_nr; - chip->IO_ADDR_R = chip->IO_ADDR_W = - fun->upm.io_addr + fun->chip_offset * chip_nr; - } else if (chip_nr == -1) { - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); - } -} -#endif - -static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_upm_nand *fun = nand_get_controller_data(chip); - void __iomem *io_addr; - u32 mar; - - if (!(ctrl & fun->last_ctrl)) { - fsl_upm_end_pattern(&fun->upm); - - if (cmd == NAND_CMD_NONE) - return; - - fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE); - } - - if (ctrl & NAND_CTRL_CHANGE) { - if (ctrl & NAND_ALE) - fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); - else if (ctrl & NAND_CLE) - fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); - } - - mar = cmd << (32 - fun->width); - io_addr = fun->upm.io_addr; -#if CONFIG_SYS_NAND_MAX_CHIPS > 1 - if (fun->chip_nr > 0) { - io_addr += fun->chip_offset * fun->chip_nr; - if (fun->upm_mar_chip_offset) - mar |= fun->upm_mar_chip_offset * fun->chip_nr; - } -#endif - fsl_upm_run_pattern(&fun->upm, fun->width, io_addr, mar); - - /* - * Some boards/chips needs this. At least the MPC8360E-RDK - * needs it. Probably weird chip, because I don't see any - * need for this on MPC8555E + Samsung K9F1G08U0A. Usually - * here are 0-2 unexpected busy states per block read. - */ - if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN) - fun_wait(fun); -} - -static u8 upm_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - return in_8(chip->IO_ADDR_R); -} - -static void upm_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_upm_nand *fun = nand_get_controller_data(chip); - - for (i = 0; i < len; i++) { - out_8(chip->IO_ADDR_W, buf[i]); - if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE) - fun_wait(fun); - } - - if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER) - fun_wait(fun); -} - -static void upm_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - int i; - struct nand_chip *chip = mtd_to_nand(mtd); - - for (i = 0; i < len; i++) - buf[i] = in_8(chip->IO_ADDR_R); -} - -static int nand_dev_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct fsl_upm_nand *fun = nand_get_controller_data(chip); - - return fun->dev_ready(fun->chip_nr); -} - -int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun) -{ - if (fun->width != 8 && fun->width != 16 && fun->width != 32) - return -ENOSYS; - - fun->last_ctrl = NAND_CLE; - - nand_set_controller_data(chip, fun); - chip->chip_delay = fun->chip_delay; - chip->ecc.mode = NAND_ECC_SOFT; - chip->cmd_ctrl = fun_cmd_ctrl; -#if CONFIG_SYS_NAND_MAX_CHIPS > 1 - chip->select_chip = fun_select_chip; -#endif - chip->read_byte = upm_nand_read_byte; - chip->read_buf = upm_nand_read_buf; - chip->write_buf = upm_nand_write_buf; - if (fun->dev_ready) - chip->dev_ready = nand_dev_ready; - - return 0; -} diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c deleted file mode 100644 index 1f4c74f0f6..0000000000 --- a/drivers/mtd/nand/fsmc_nand.c +++ /dev/null @@ -1,518 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2010 - * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com. - * - * (C) Copyright 2012 - * Amit Virdi, ST Microelectronics, amit.virdi@st.com. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static u32 fsmc_version; -static struct fsmc_regs *const fsmc_regs_p = (struct fsmc_regs *) - CONFIG_SYS_FSMC_BASE; - -/* - * ECC4 and ECC1 have 13 bytes and 3 bytes of ecc respectively for 512 bytes of - * data. ECC4 can correct up to 8 bits in 512 bytes of data while ECC1 can - * correct 1 bit in 512 bytes - */ - -static struct nand_ecclayout fsmc_ecc4_lp_layout = { - .eccbytes = 104, - .eccpos = { 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, - 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, - 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, - 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, - 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, - 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, - 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, - 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126 - }, - .oobfree = { - {.offset = 15, .length = 3}, - {.offset = 31, .length = 3}, - {.offset = 47, .length = 3}, - {.offset = 63, .length = 3}, - {.offset = 79, .length = 3}, - {.offset = 95, .length = 3}, - {.offset = 111, .length = 3}, - {.offset = 127, .length = 1} - } -}; - -/* - * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 224 bytes. 13*8 bytes - * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 118 - * bytes are free for use. - */ -static struct nand_ecclayout fsmc_ecc4_224_layout = { - .eccbytes = 104, - .eccpos = { 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, - 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, - 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, - 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, - 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, - 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, - 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, - 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126 - }, - .oobfree = { - {.offset = 15, .length = 3}, - {.offset = 31, .length = 3}, - {.offset = 47, .length = 3}, - {.offset = 63, .length = 3}, - {.offset = 79, .length = 3}, - {.offset = 95, .length = 3}, - {.offset = 111, .length = 3}, - {.offset = 127, .length = 97} - } -}; - -/* - * ECC placement definitions in oobfree type format - * There are 13 bytes of ecc for every 512 byte block and it has to be read - * consecutively and immediately after the 512 byte data block for hardware to - * generate the error bit offsets in 512 byte data - * Managing the ecc bytes in the following way makes it easier for software to - * read ecc bytes consecutive to data bytes. This way is similar to - * oobfree structure maintained already in u-boot nand driver - */ -static struct fsmc_eccplace fsmc_eccpl_lp = { - .eccplace = { - {.offset = 2, .length = 13}, - {.offset = 18, .length = 13}, - {.offset = 34, .length = 13}, - {.offset = 50, .length = 13}, - {.offset = 66, .length = 13}, - {.offset = 82, .length = 13}, - {.offset = 98, .length = 13}, - {.offset = 114, .length = 13} - } -}; - -static struct nand_ecclayout fsmc_ecc4_sp_layout = { - .eccbytes = 13, - .eccpos = { 0, 1, 2, 3, 6, 7, 8, - 9, 10, 11, 12, 13, 14 - }, - .oobfree = { - {.offset = 15, .length = 1}, - } -}; - -static struct fsmc_eccplace fsmc_eccpl_sp = { - .eccplace = { - {.offset = 0, .length = 4}, - {.offset = 6, .length = 9} - } -}; - -static struct nand_ecclayout fsmc_ecc1_layout = { - .eccbytes = 24, - .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52, - 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116}, - .oobfree = { - {.offset = 8, .length = 8}, - {.offset = 24, .length = 8}, - {.offset = 40, .length = 8}, - {.offset = 56, .length = 8}, - {.offset = 72, .length = 8}, - {.offset = 88, .length = 8}, - {.offset = 104, .length = 8}, - {.offset = 120, .length = 8} - } -}; - -/* Count the number of 0's in buff upto a max of max_bits */ -static int count_written_bits(uint8_t *buff, int size, int max_bits) -{ - int k, written_bits = 0; - - for (k = 0; k < size; k++) { - written_bits += hweight8(~buff[k]); - if (written_bits > max_bits) - break; - } - - return written_bits; -} - -static void fsmc_nand_hwcontrol(struct mtd_info *mtd, int cmd, uint ctrl) -{ - struct nand_chip *this = mtd_to_nand(mtd); - ulong IO_ADDR_W; - - if (ctrl & NAND_CTRL_CHANGE) { - IO_ADDR_W = (ulong)this->IO_ADDR_W; - - IO_ADDR_W &= ~(CONFIG_SYS_NAND_CLE | CONFIG_SYS_NAND_ALE); - if (ctrl & NAND_CLE) - IO_ADDR_W |= CONFIG_SYS_NAND_CLE; - if (ctrl & NAND_ALE) - IO_ADDR_W |= CONFIG_SYS_NAND_ALE; - - if (ctrl & NAND_NCE) { - writel(readl(&fsmc_regs_p->pc) | - FSMC_ENABLE, &fsmc_regs_p->pc); - } else { - writel(readl(&fsmc_regs_p->pc) & - ~FSMC_ENABLE, &fsmc_regs_p->pc); - } - this->IO_ADDR_W = (void *)IO_ADDR_W; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - -static int fsmc_bch8_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - /* The calculated ecc is actually the correction index in data */ - u32 err_idx[8]; - u32 num_err, i; - u32 ecc1, ecc2, ecc3, ecc4; - - num_err = (readl(&fsmc_regs_p->sts) >> 10) & 0xF; - - if (likely(num_err == 0)) - return 0; - - if (unlikely(num_err > 8)) { - /* - * This is a temporary erase check. A newly erased page read - * would result in an ecc error because the oob data is also - * erased to FF and the calculated ecc for an FF data is not - * FF..FF. - * This is a workaround to skip performing correction in case - * data is FF..FF - * - * Logic: - * For every page, each bit written as 0 is counted until these - * number of bits are greater than 8 (the maximum correction - * capability of FSMC for each 512 + 13 bytes) - */ - - int bits_ecc = count_written_bits(read_ecc, 13, 8); - int bits_data = count_written_bits(dat, 512, 8); - - if ((bits_ecc + bits_data) <= 8) { - if (bits_data) - memset(dat, 0xff, 512); - return bits_data + bits_ecc; - } - - return -EBADMSG; - } - - ecc1 = readl(&fsmc_regs_p->ecc1); - ecc2 = readl(&fsmc_regs_p->ecc2); - ecc3 = readl(&fsmc_regs_p->ecc3); - ecc4 = readl(&fsmc_regs_p->sts); - - err_idx[0] = (ecc1 >> 0) & 0x1FFF; - err_idx[1] = (ecc1 >> 13) & 0x1FFF; - err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F); - err_idx[3] = (ecc2 >> 7) & 0x1FFF; - err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF); - err_idx[5] = (ecc3 >> 1) & 0x1FFF; - err_idx[6] = (ecc3 >> 14) & 0x1FFF; - err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F); - - i = 0; - while (i < num_err) { - err_idx[i] ^= 3; - - if (err_idx[i] < 512 * 8) - __change_bit(err_idx[i], dat); - - i++; - } - - return num_err; -} - -static int fsmc_read_hwecc(struct mtd_info *mtd, - const u_char *data, u_char *ecc) -{ - u_int ecc_tmp; - int timeout = CONFIG_SYS_HZ; - ulong start; - - switch (fsmc_version) { - case FSMC_VER8: - start = get_timer(0); - while (get_timer(start) < timeout) { - /* - * Busy waiting for ecc computation - * to finish for 512 bytes - */ - if (readl(&fsmc_regs_p->sts) & FSMC_CODE_RDY) - break; - } - - ecc_tmp = readl(&fsmc_regs_p->ecc1); - ecc[0] = (u_char) (ecc_tmp >> 0); - ecc[1] = (u_char) (ecc_tmp >> 8); - ecc[2] = (u_char) (ecc_tmp >> 16); - ecc[3] = (u_char) (ecc_tmp >> 24); - - ecc_tmp = readl(&fsmc_regs_p->ecc2); - ecc[4] = (u_char) (ecc_tmp >> 0); - ecc[5] = (u_char) (ecc_tmp >> 8); - ecc[6] = (u_char) (ecc_tmp >> 16); - ecc[7] = (u_char) (ecc_tmp >> 24); - - ecc_tmp = readl(&fsmc_regs_p->ecc3); - ecc[8] = (u_char) (ecc_tmp >> 0); - ecc[9] = (u_char) (ecc_tmp >> 8); - ecc[10] = (u_char) (ecc_tmp >> 16); - ecc[11] = (u_char) (ecc_tmp >> 24); - - ecc_tmp = readl(&fsmc_regs_p->sts); - ecc[12] = (u_char) (ecc_tmp >> 16); - break; - - default: - ecc_tmp = readl(&fsmc_regs_p->ecc1); - ecc[0] = (u_char) (ecc_tmp >> 0); - ecc[1] = (u_char) (ecc_tmp >> 8); - ecc[2] = (u_char) (ecc_tmp >> 16); - break; - } - - return 0; -} - -void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) -{ - writel(readl(&fsmc_regs_p->pc) & ~FSMC_ECCPLEN_256, - &fsmc_regs_p->pc); - writel(readl(&fsmc_regs_p->pc) & ~FSMC_ECCEN, - &fsmc_regs_p->pc); - writel(readl(&fsmc_regs_p->pc) | FSMC_ECCEN, - &fsmc_regs_p->pc); -} - -/* - * 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 - * @page: page number to read - * - * This routine is needed for fsmc verison 8 as reading from NAND chip has to be - * performed in a strict sequence as follows: - * data(512 byte) -> ecc(13 byte) - * After this read, fsmc hardware generates and reports error data bits(upto 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) -{ - struct fsmc_eccplace *fsmc_eccpl; - int i, j, s, stat, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - int off, len, group = 0; - uint8_t oob[13] __attribute__ ((aligned (2))); - - /* Differentiate between small and large page ecc place definitions */ - if (mtd->writesize == 512) - fsmc_eccpl = &fsmc_eccpl_sp; - else - fsmc_eccpl = &fsmc_eccpl_lp; - - for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { - - chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - - for (j = 0; j < eccbytes;) { - off = fsmc_eccpl->eccplace[group].offset; - len = fsmc_eccpl->eccplace[group].length; - group++; - - /* - * length is intentionally kept a higher multiple of 2 - * to read at least 13 bytes even in case of 16 bit NAND - * devices - */ - if (chip->options & NAND_BUSWIDTH_16) - len = roundup(len, 2); - chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); - chip->read_buf(mtd, oob + j, len); - j += len; - } - - memcpy(&ecc_code[i], oob, 13); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], - &ecc_calc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - - return 0; -} - -#ifndef CONFIG_SPL_BUILD -/* - * fsmc_nand_switch_ecc - switch the ECC operation between different engines - * - * @eccstrength - the number of bits that could be corrected - * (1 - HW, 4 - SW BCH4) - */ -int fsmc_nand_switch_ecc(uint32_t eccstrength) -{ - struct nand_chip *nand; - struct mtd_info *mtd; - int err; - - /* - * This functions is only called on SPEAr600 platforms, supporting - * 1 bit HW ECC. The BCH8 HW ECC (FSMC_VER8) from the ST-Ericsson - * Nomadik SoC is currently supporting this fsmc_nand_switch_ecc() - * function, as it doesn't need to switch to a different ECC layout. - */ - mtd = get_nand_dev_by_index(nand_curr_device); - nand = mtd_to_nand(mtd); - - /* Setup the ecc configurations again */ - if (eccstrength == 1) { - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.bytes = 3; - nand->ecc.strength = 1; - nand->ecc.layout = &fsmc_ecc1_layout; - nand->ecc.calculate = fsmc_read_hwecc; - nand->ecc.correct = nand_correct_data; - } else if (eccstrength == 4) { - /* - * .calculate .correct and .bytes will be set in - * nand_scan_tail() - */ - nand->ecc.mode = NAND_ECC_SOFT_BCH; - nand->ecc.strength = 4; - nand->ecc.layout = NULL; - } else { - printf("Error: ECC strength %d not supported!\n", eccstrength); - } - - /* Update NAND handling after ECC mode switch */ - err = nand_scan_tail(mtd); - - return err; -} -#endif /* CONFIG_SPL_BUILD */ - -int fsmc_nand_init(struct nand_chip *nand) -{ - static int chip_nr; - struct mtd_info *mtd; - u32 peripid2 = readl(&fsmc_regs_p->peripid2); - - fsmc_version = (peripid2 >> FSMC_REVISION_SHFT) & - FSMC_REVISION_MSK; - - writel(readl(&fsmc_regs_p->ctrl) | FSMC_WP, &fsmc_regs_p->ctrl); - -#if defined(CONFIG_SYS_FSMC_NAND_16BIT) - writel(FSMC_DEVWID_16 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON, - &fsmc_regs_p->pc); -#elif defined(CONFIG_SYS_FSMC_NAND_8BIT) - writel(FSMC_DEVWID_8 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON, - &fsmc_regs_p->pc); -#else -#error Please define CONFIG_SYS_FSMC_NAND_16BIT or CONFIG_SYS_FSMC_NAND_8BIT -#endif - writel(readl(&fsmc_regs_p->pc) | FSMC_TCLR_1 | FSMC_TAR_1, - &fsmc_regs_p->pc); - writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, - &fsmc_regs_p->comm); - writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, - &fsmc_regs_p->attrib); - - nand->options = 0; -#if defined(CONFIG_SYS_FSMC_NAND_16BIT) - nand->options |= NAND_BUSWIDTH_16; -#endif - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.size = 512; - nand->ecc.calculate = fsmc_read_hwecc; - nand->ecc.hwctl = fsmc_enable_hwecc; - nand->cmd_ctrl = fsmc_nand_hwcontrol; - nand->IO_ADDR_R = nand->IO_ADDR_W = - (void __iomem *)CONFIG_SYS_NAND_BASE; - nand->badblockbits = 7; - - mtd = nand_to_mtd(nand); - - switch (fsmc_version) { - case FSMC_VER8: - nand->ecc.bytes = 13; - nand->ecc.strength = 8; - nand->ecc.correct = fsmc_bch8_correct_data; - nand->ecc.read_page = fsmc_read_page_hwecc; - if (mtd->writesize == 512) - nand->ecc.layout = &fsmc_ecc4_sp_layout; - else { - if (mtd->oobsize == 224) - nand->ecc.layout = &fsmc_ecc4_224_layout; - else - nand->ecc.layout = &fsmc_ecc4_lp_layout; - } - - break; - default: - nand->ecc.bytes = 3; - nand->ecc.strength = 1; - nand->ecc.layout = &fsmc_ecc1_layout; - nand->ecc.correct = nand_correct_data; - break; - } - - /* Detect NAND chips */ - if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) - return -ENXIO; - - if (nand_scan_tail(mtd)) - return -ENXIO; - - if (nand_register(chip_nr++, mtd)) - return -ENXIO; - - return 0; -} diff --git a/drivers/mtd/nand/kb9202_nand.c b/drivers/mtd/nand/kb9202_nand.c deleted file mode 100644 index 0f68f1cd86..0000000000 --- a/drivers/mtd/nand/kb9202_nand.c +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2006 - * KwikByte - * - * (C) Copyright 2009 - * Matthias Kaehlcke - */ - -#include -#include -#include -#include - -#include - -/* - * hardware specific access to control-lines - */ - -#define MASK_ALE (1 << 22) /* our ALE is A22 */ -#define MASK_CLE (1 << 21) /* our CLE is A21 */ - -#define KB9202_NAND_NCE (1 << 28) /* EN* on D28 */ -#define KB9202_NAND_BUSY (1 << 29) /* RB* on D29 */ - -#define KB9202_SMC2_NWS (1 << 2) -#define KB9202_SMC2_TDF (1 << 8) -#define KB9202_SMC2_RWSETUP (1 << 24) -#define KB9202_SMC2_RWHOLD (1 << 29) - -/* - * Board-specific function to access device control signals - */ -static void kb9202_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - if (ctrl & NAND_CTRL_CHANGE) { - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - - /* clear ALE and CLE bits */ - IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); - - if (ctrl & NAND_CLE) - IO_ADDR_W |= MASK_CLE; - - if (ctrl & NAND_ALE) - IO_ADDR_W |= MASK_ALE; - - this->IO_ADDR_W = (void *) IO_ADDR_W; - - if (ctrl & NAND_NCE) - writel(KB9202_NAND_NCE, AT91C_PIOC_CODR); - else - writel(KB9202_NAND_NCE, AT91C_PIOC_SODR); - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - - -/* - * Board-specific function to access the device ready signal. - */ -static int kb9202_nand_ready(struct mtd_info *mtd) -{ - return readl(AT91C_PIOC_PDSR) & KB9202_NAND_BUSY; -} - - -/* - * Board-specific NAND init. Copied from include/linux/mtd/nand.h for reference. - * - * struct nand_chip - NAND Private Flash Chip Data - * @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 - * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines - * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing 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 - * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only - * be provided if a hardware ECC is available - * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines - * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) - * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about - * special functionality. See the defines for further explanation -*/ -/* - * This routine initializes controller and GPIOs. - */ -int board_nand_init(struct nand_chip *nand) -{ - unsigned int value; - - nand->ecc.mode = NAND_ECC_SOFT; - nand->cmd_ctrl = kb9202_nand_hwcontrol; - nand->dev_ready = kb9202_nand_ready; - - /* in case running outside of bootloader */ - writel(1 << AT91C_ID_PIOC, AT91C_PMC_PCER); - - /* setup nand flash access (allow ample margin) */ - /* 4 wait states, 1 setup, 1 hold, 1 float for 8-bit device */ - writel(AT91C_SMC2_WSEN | KB9202_SMC2_NWS | KB9202_SMC2_TDF | - AT91C_SMC2_DBW_8 | KB9202_SMC2_RWSETUP | KB9202_SMC2_RWHOLD, - AT91C_SMC_CSR3); - - /* enable internal NAND controller */ - value = readl(AT91C_EBI_CSA); - value |= AT91C_EBI_CS3A_SMC_SmartMedia; - writel(value, AT91C_EBI_CSA); - - /* enable SMOE/SMWE */ - writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_ASR); - writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_PDR); - writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_OER); - - /* set NCE to high */ - writel(KB9202_NAND_NCE, AT91C_PIOC_SODR); - - /* disable output on pin connected to the busy line of the NAND */ - writel(KB9202_NAND_BUSY, AT91C_PIOC_ODR); - - /* enable the PIO to control NCE and BUSY */ - writel(KB9202_NAND_NCE | KB9202_NAND_BUSY, AT91C_PIOC_PER); - - /* enable output for NCE */ - writel(KB9202_NAND_NCE, AT91C_PIOC_OER); - - return (0); -} diff --git a/drivers/mtd/nand/kirkwood_nand.c b/drivers/mtd/nand/kirkwood_nand.c deleted file mode 100644 index 0757fa840b..0000000000 --- a/drivers/mtd/nand/kirkwood_nand.c +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2009 - * Marvell Semiconductor - * Written-by: Prafulla Wadaskar - */ - -#include -#include -#include -#include -#include - -/* NAND Flash Soc registers */ -struct kwnandf_registers { - u32 rd_params; /* 0x10418 */ - u32 wr_param; /* 0x1041c */ - u8 pad[0x10470 - 0x1041c - 4]; - u32 ctrl; /* 0x10470 */ -}; - -static struct kwnandf_registers *nf_reg = - (struct kwnandf_registers *)KW_NANDF_BASE; - -static u32 nand_mpp_backup[9] = { 0 }; - -/* - * hardware specific access to control-lines/bits - */ -#define NAND_ACTCEBOOT_BIT 0x02 - -static void kw_nand_hwcontrol(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - struct nand_chip *nc = mtd_to_nand(mtd); - u32 offs; - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - offs = (1 << 0); /* Commands with A[1:0] == 01 */ - else if (ctrl & NAND_ALE) - offs = (1 << 1); /* Addresses with A[1:0] == 10 */ - else - return; - - writeb(cmd, nc->IO_ADDR_W + offs); -} - -void kw_nand_select_chip(struct mtd_info *mtd, int chip) -{ - u32 data; - static const u32 nand_config[] = { - MPP0_NF_IO2, - MPP1_NF_IO3, - MPP2_NF_IO4, - MPP3_NF_IO5, - MPP4_NF_IO6, - MPP5_NF_IO7, - MPP18_NF_IO0, - MPP19_NF_IO1, - 0 - }; - - if (chip >= 0) - kirkwood_mpp_conf(nand_config, nand_mpp_backup); - else - kirkwood_mpp_conf(nand_mpp_backup, NULL); - - data = readl(&nf_reg->ctrl); - data |= NAND_ACTCEBOOT_BIT; - writel(data, &nf_reg->ctrl); -} - -int board_nand_init(struct nand_chip *nand) -{ - nand->options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING; -#if defined(CONFIG_SYS_NAND_NO_SUBPAGE_WRITE) - nand->options |= NAND_NO_SUBPAGE_WRITE; -#endif -#if defined(CONFIG_NAND_ECC_BCH) - nand->ecc.mode = NAND_ECC_SOFT_BCH; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif - nand->cmd_ctrl = kw_nand_hwcontrol; - nand->chip_delay = 40; - nand->select_chip = kw_nand_select_chip; - return 0; -} diff --git a/drivers/mtd/nand/kmeter1_nand.c b/drivers/mtd/nand/kmeter1_nand.c deleted file mode 100644 index 7103300060..0000000000 --- a/drivers/mtd/nand/kmeter1_nand.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2009 - * Heiko Schocher, DENX Software Engineering, hs@denx.de - */ - -#include -#include -#include - -#define CONFIG_NAND_MODE_REG (void *)(CONFIG_SYS_NAND_BASE + 0x20000) -#define CONFIG_NAND_DATA_REG (void *)(CONFIG_SYS_NAND_BASE + 0x30000) - -#define read_mode() in_8(CONFIG_NAND_MODE_REG) -#define write_mode(val) out_8(CONFIG_NAND_MODE_REG, val) -#define read_data() in_8(CONFIG_NAND_DATA_REG) -#define write_data(val) out_8(CONFIG_NAND_DATA_REG, val) - -#define KPN_RDY2 (1 << 7) -#define KPN_RDY1 (1 << 6) -#define KPN_WPN (1 << 4) -#define KPN_CE2N (1 << 3) -#define KPN_CE1N (1 << 2) -#define KPN_ALE (1 << 1) -#define KPN_CLE (1 << 0) - -#define KPN_DEFAULT_CHIP_DELAY 50 - -static int kpn_chip_ready(void) -{ - if (read_mode() & KPN_RDY1) - return 1; - - return 0; -} - -static void kpn_wait_rdy(void) -{ - int cnt = 1000000; - - while (--cnt && !kpn_chip_ready()) - udelay(1); - - if (!cnt) - printf ("timeout while waiting for RDY\n"); -} - -static void kpn_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - u8 reg_val = read_mode(); - - if (ctrl & NAND_CTRL_CHANGE) { - reg_val = reg_val & ~(KPN_ALE + KPN_CLE); - - if (ctrl & NAND_CLE) - reg_val = reg_val | KPN_CLE; - if (ctrl & NAND_ALE) - reg_val = reg_val | KPN_ALE; - if (ctrl & NAND_NCE) - reg_val = reg_val & ~KPN_CE1N; - else - reg_val = reg_val | KPN_CE1N; - - write_mode(reg_val); - } - if (cmd != NAND_CMD_NONE) - write_data(cmd); - - /* wait until flash is ready */ - kpn_wait_rdy(); -} - -static u_char kpn_nand_read_byte(struct mtd_info *mtd) -{ - return read_data(); -} - -static void kpn_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) { - write_data(buf[i]); - kpn_wait_rdy(); - } -} - -static void kpn_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) - buf[i] = read_data(); -} - -static int kpn_nand_dev_ready(struct mtd_info *mtd) -{ - kpn_wait_rdy(); - - return 1; -} - -int board_nand_init(struct nand_chip *nand) -{ -#if defined(CONFIG_NAND_ECC_BCH) - nand->ecc.mode = NAND_ECC_SOFT_BCH; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif - - /* Reference hardware control function */ - nand->cmd_ctrl = kpn_nand_hwcontrol; - nand->read_byte = kpn_nand_read_byte; - nand->write_buf = kpn_nand_write_buf; - nand->read_buf = kpn_nand_read_buf; - nand->dev_ready = kpn_nand_dev_ready; - nand->chip_delay = KPN_DEFAULT_CHIP_DELAY; - - /* reset mode register */ - write_mode(KPN_CE1N + KPN_CE2N + KPN_WPN); - return 0; -} diff --git a/drivers/mtd/nand/lpc32xx_nand_mlc.c b/drivers/mtd/nand/lpc32xx_nand_mlc.c deleted file mode 100644 index 5d4ffea608..0000000000 --- a/drivers/mtd/nand/lpc32xx_nand_mlc.c +++ /dev/null @@ -1,761 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * LPC32xx MLC NAND flash controller driver - * - * (C) Copyright 2014 3ADEV - * Written by Albert ARIBAUD - * - * NOTE: - * - * The MLC NAND flash controller provides hardware Reed-Solomon ECC - * covering in- and out-of-band data together. Therefore, in- and out- - * of-band data must be written together in order to have a valid ECC. - * - * Consequently, pages with meaningful in-band data are written with - * blank (all-ones) out-of-band data and a valid ECC, and any later - * out-of-band data write will void the ECC. - * - * Therefore, code which reads such late-written out-of-band data - * should not rely on the ECC validity. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * MLC NAND controller registers. - */ -struct lpc32xx_nand_mlc_registers { - u8 buff[32768]; /* controller's serial data buffer */ - u8 data[32768]; /* NAND's raw data buffer */ - u32 cmd; - u32 addr; - u32 ecc_enc_reg; - u32 ecc_dec_reg; - u32 ecc_auto_enc_reg; - u32 ecc_auto_dec_reg; - u32 rpr; - u32 wpr; - u32 rubp; - u32 robp; - u32 sw_wp_add_low; - u32 sw_wp_add_hig; - u32 icr; - u32 time_reg; - u32 irq_mr; - u32 irq_sr; - u32 lock_pr; - u32 isr; - u32 ceh; -}; - -/* LOCK_PR register defines */ -#define LOCK_PR_UNLOCK_KEY 0x0000A25E /* Magic unlock value */ - -/* ICR defines */ -#define ICR_LARGE_BLOCKS 0x00000004 /* configure for 2KB blocks */ -#define ICR_ADDR4 0x00000002 /* configure for 4-word addrs */ - -/* CEH defines */ -#define CEH_NORMAL_CE 0x00000001 /* do not force CE ON */ - -/* ISR register defines */ -#define ISR_NAND_READY 0x00000001 -#define ISR_CONTROLLER_READY 0x00000002 -#define ISR_ECC_READY 0x00000004 -#define ISR_DECODER_ERRORS(s) ((((s) >> 4) & 3)+1) -#define ISR_DECODER_FAILURE 0x00000040 -#define ISR_DECODER_ERROR 0x00000008 - -/* time-out for NAND chip / controller loops, in us */ -#define LPC32X_NAND_TIMEOUT 5000 - -/* - * There is a single instance of the NAND MLC controller - */ - -static struct lpc32xx_nand_mlc_registers __iomem *lpc32xx_nand_mlc_registers - = (struct lpc32xx_nand_mlc_registers __iomem *)MLC_NAND_BASE; - -#define clkdiv(v, w, o) (((1+(clk/v)) & w) << o) - -/** - * OOB data in each small page are 6 'free' then 10 ECC bytes. - * To make things easier, when reading large pages, the four pages' - * 'free' OOB bytes are grouped in the first 24 bytes of the OOB buffer, - * while the the four ECC bytes are groupe in its last 40 bytes. - * - * The struct below represents how free vs ecc oob bytes are stored - * in the buffer. - * - * Note: the OOB bytes contain the bad block marker at offsets 0 and 1. - */ - -struct lpc32xx_oob { - struct { - uint8_t free_oob_bytes[6]; - } free[4]; - struct { - uint8_t ecc_oob_bytes[10]; - } ecc[4]; -}; - -/* - * Initialize the controller - */ - -static void lpc32xx_nand_init(void) -{ - unsigned int clk; - - /* Configure controller for no software write protection, x8 bus - width, large block device, and 4 address words */ - - /* unlock controller registers with magic key */ - writel(LOCK_PR_UNLOCK_KEY, - &lpc32xx_nand_mlc_registers->lock_pr); - - /* enable large blocks and large NANDs */ - writel(ICR_LARGE_BLOCKS | ICR_ADDR4, - &lpc32xx_nand_mlc_registers->icr); - - /* Make sure MLC interrupts are disabled */ - writel(0, &lpc32xx_nand_mlc_registers->irq_mr); - - /* Normal chip enable operation */ - writel(CEH_NORMAL_CE, - &lpc32xx_nand_mlc_registers->ceh); - - /* Setup NAND timing */ - clk = get_hclk_clk_rate(); - - writel( - clkdiv(CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY, 0x03, 24) | - clkdiv(CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY, 0x1F, 19) | - clkdiv(CONFIG_LPC32XX_NAND_MLC_NAND_TA, 0x07, 16) | - clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_HIGH, 0x0F, 12) | - clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_LOW, 0x0F, 8) | - clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_HIGH, 0x0F, 4) | - clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_LOW, 0x0F, 0), - &lpc32xx_nand_mlc_registers->time_reg); -} - -#if !defined(CONFIG_SPL_BUILD) - -/** - * lpc32xx_cmd_ctrl - write command to either cmd or data register - */ - -static void lpc32xx_cmd_ctrl(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->cmd); - else if (ctrl & NAND_ALE) - writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->addr); -} - -/** - * lpc32xx_read_byte - read a byte from the NAND - * @mtd: MTD device structure - */ - -static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) -{ - return readb(&lpc32xx_nand_mlc_registers->data); -} - -/** - * lpc32xx_dev_ready - test if NAND device (actually controller) is ready - * @mtd: MTD device structure - * @mode: mode to set the ECC HW to. - */ - -static int lpc32xx_dev_ready(struct mtd_info *mtd) -{ - /* means *controller* ready for us */ - int status = readl(&lpc32xx_nand_mlc_registers->isr); - return status & ISR_CONTROLLER_READY; -} - -/** - * ECC layout -- this is needed whatever ECC mode we are using. - * In a 2KB (4*512B) page, R/S codes occupy 40 (4*10) bytes. - * To make U-Boot's life easier, we pack 'useable' OOB at the - * front and R/S ECC at the back. - */ - -static struct nand_ecclayout lpc32xx_largepage_ecclayout = { - .eccbytes = 40, - .eccpos = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 48, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - }, - .oobfree = { - /* bytes 0 and 1 are used for the bad block marker */ - { - .offset = 2, - .length = 22 - }, - } -}; - -/** - * lpc32xx_read_page_hwecc - read in- and out-of-band data with 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 - * @page: page number to read - * - * Use large block Auto Decode Read Mode(1) as described in User Manual - * section 8.6.2.1. - * - * The initial Read Mode and Read Start commands are sent by the caller. - * - * ECC will be false if out-of-band data has been updated since in-band - * data was initially written. - */ - -static int lpc32xx_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, - int page) -{ - unsigned int i, status, timeout, err, max_bitflips = 0; - struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; - - /* go through all four small pages */ - for (i = 0; i < 4; i++) { - /* start auto decode (reads 528 NAND bytes) */ - writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg); - /* wait for controller to return to ready state */ - for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { - status = readl(&lpc32xx_nand_mlc_registers->isr); - if (status & ISR_CONTROLLER_READY) - break; - udelay(1); - } - /* if decoder failed, return failure */ - if (status & ISR_DECODER_FAILURE) - return -1; - /* keep count of maximum bitflips performed */ - if (status & ISR_DECODER_ERROR) { - err = ISR_DECODER_ERRORS(status); - if (err > max_bitflips) - max_bitflips = err; - } - /* copy first 512 bytes into buffer */ - memcpy(buf+512*i, lpc32xx_nand_mlc_registers->buff, 512); - /* copy next 6 bytes at front of OOB buffer */ - memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6); - /* copy last 10 bytes (R/S ECC) at back of OOB buffer */ - memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10); - } - return max_bitflips; -} - -/** - * lpc32xx_read_page_raw - read raw (in-band, out-of-band and ECC) data - * @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 - * - * Read NAND directly; can read pages with invalid ECC. - */ - -static int lpc32xx_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, - int page) -{ - unsigned int i, status, timeout; - struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; - - /* when we get here we've already had the Read Mode(1) */ - - /* go through all four small pages */ - for (i = 0; i < 4; i++) { - /* wait for NAND to return to ready state */ - for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { - status = readl(&lpc32xx_nand_mlc_registers->isr); - if (status & ISR_NAND_READY) - break; - udelay(1); - } - /* if NAND stalled, return failure */ - if (!(status & ISR_NAND_READY)) - return -1; - /* copy first 512 bytes into buffer */ - memcpy(buf+512*i, lpc32xx_nand_mlc_registers->data, 512); - /* copy next 6 bytes at front of OOB buffer */ - memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->data, 6); - /* copy last 10 bytes (R/S ECC) at back of OOB buffer */ - memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->data, 10); - } - return 0; -} - -/** - * lpc32xx_read_oob - read out-of-band data - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * - * Read out-of-band data. User Manual section 8.6.4 suggests using Read - * Mode(3) which the controller will turn into a Read Mode(1) internally - * but nand_base.c will turn Mode(3) into Mode(0), so let's use Mode(0) - * directly. - * - * ECC covers in- and out-of-band data and was written when out-of-band - * data was blank. Therefore, if the out-of-band being read here is not - * blank, then the ECC will be false and the read will return bitflips, - * even in case of ECC failure where we will return 5 bitflips. The - * caller should be prepared to handle this. - */ - -static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - unsigned int i, status, timeout, err, max_bitflips = 0; - struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; - - /* No command was sent before calling read_oob() so send one */ - - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - /* go through all four small pages */ - for (i = 0; i < 4; i++) { - /* start auto decode (reads 528 NAND bytes) */ - writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg); - /* wait for controller to return to ready state */ - for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { - status = readl(&lpc32xx_nand_mlc_registers->isr); - if (status & ISR_CONTROLLER_READY) - break; - udelay(1); - } - /* if decoder failure, count 'one too many' bitflips */ - if (status & ISR_DECODER_FAILURE) - max_bitflips = 5; - /* keep count of maximum bitflips performed */ - if (status & ISR_DECODER_ERROR) { - err = ISR_DECODER_ERRORS(status); - if (err > max_bitflips) - max_bitflips = err; - } - /* set read pointer to OOB area */ - writel(0, &lpc32xx_nand_mlc_registers->robp); - /* copy next 6 bytes at front of OOB buffer */ - memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6); - /* copy next 10 bytes (R/S ECC) at back of OOB buffer */ - memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10); - } - return max_bitflips; -} - -/** - * lpc32xx_write_page_hwecc - write in- and out-of-band data with ECC - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB - * - * Use large block Auto Encode as per User Manual section 8.6.4. - * - * The initial Write Serial Input and final Auto Program commands are - * sent by the caller. - */ - -static int lpc32xx_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required, - int page) -{ - unsigned int i, status, timeout; - struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; - - /* when we get here we've already had the SEQIN */ - for (i = 0; i < 4; i++) { - /* start encode (expects 518 writes to buff) */ - writel(0, &lpc32xx_nand_mlc_registers->ecc_enc_reg); - /* copy first 512 bytes from buffer */ - memcpy(&lpc32xx_nand_mlc_registers->buff, buf+512*i, 512); - /* copy next 6 bytes from OOB buffer -- excluding ECC */ - memcpy(&lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6); - /* wait for ECC to return to ready state */ - for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { - status = readl(&lpc32xx_nand_mlc_registers->isr); - if (status & ISR_ECC_READY) - break; - udelay(1); - } - /* if ECC stalled, return failure */ - if (!(status & ISR_ECC_READY)) - return -1; - /* Trigger auto encode (writes 528 bytes to NAND) */ - writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_enc_reg); - /* wait for controller to return to ready state */ - for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { - status = readl(&lpc32xx_nand_mlc_registers->isr); - if (status & ISR_CONTROLLER_READY) - break; - udelay(1); - } - /* if controller stalled, return error */ - if (!(status & ISR_CONTROLLER_READY)) - return -1; - } - return 0; -} - -/** - * lpc32xx_write_page_raw - write raw (in-band, out-of-band and ECC) data - * @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 - * - * Use large block write but without encode. - * - * The initial Write Serial Input and final Auto Program commands are - * sent by the caller. - * - * This function will write the full out-of-band data, including the - * ECC area. Therefore, it can write pages with valid *or* invalid ECC. - */ - -static int lpc32xx_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required, - int page) -{ - unsigned int i; - struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; - - /* when we get here we've already had the Read Mode(1) */ - for (i = 0; i < 4; i++) { - /* copy first 512 bytes from buffer */ - memcpy(lpc32xx_nand_mlc_registers->buff, buf+512*i, 512); - /* copy next 6 bytes into OOB buffer -- excluding ECC */ - memcpy(lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6); - /* copy next 10 bytes into OOB buffer -- that is 'ECC' */ - memcpy(lpc32xx_nand_mlc_registers->buff, &oob->ecc[i], 10); - } - return 0; -} - -/** - * lpc32xx_write_oob - write out-of-band data - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * - * Since ECC covers in- and out-of-band data, writing out-of-band data - * with ECC will render the page ECC wrong -- or, if the page was blank, - * then it will produce a good ECC but a later in-band data write will - * render it wrong. - * - * Therefore, do not compute or write any ECC, and always return success. - * - * This implies that we do four writes, since non-ECC out-of-band data - * are not contiguous in a large page. - */ - -static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - /* update oob on all 4 subpages in sequence */ - unsigned int i, status, timeout; - struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; - - for (i = 0; i < 4; i++) { - /* start data input */ - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x200+0x210*i, page); - /* copy 6 non-ECC out-of-band bytes directly into NAND */ - memcpy(lpc32xx_nand_mlc_registers->data, &oob->free[i], 6); - /* program page */ - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - /* wait for NAND to return to ready state */ - for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { - status = readl(&lpc32xx_nand_mlc_registers->isr); - if (status & ISR_NAND_READY) - break; - udelay(1); - } - /* if NAND stalled, return error */ - if (!(status & ISR_NAND_READY)) - return -1; - } - return 0; -} - -/** - * lpc32xx_waitfunc - wait until a command is done - * @mtd: MTD device structure - * @chip: NAND chip structure - * - * Wait for controller and FLASH to both be ready. - */ - -static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) -{ - int status; - unsigned int timeout; - /* wait until both controller and NAND are ready */ - for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { - status = readl(&lpc32xx_nand_mlc_registers->isr); - if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY)) - == (ISR_CONTROLLER_READY || ISR_NAND_READY)) - break; - udelay(1); - } - /* if controller or NAND stalled, return error */ - if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY)) - != (ISR_CONTROLLER_READY || ISR_NAND_READY)) - return -1; - /* write NAND status command */ - writel(NAND_CMD_STATUS, &lpc32xx_nand_mlc_registers->cmd); - /* read back status and return it */ - return readb(&lpc32xx_nand_mlc_registers->data); -} - -/* - * We are self-initializing, so we need our own chip struct - */ - -static struct nand_chip lpc32xx_chip; - -/* - * Initialize the controller - */ - -void board_nand_init(void) -{ - struct mtd_info *mtd = nand_to_mtd(&lpc32xx_chip); - int ret; - - /* Set all BOARDSPECIFIC (actually core-specific) fields */ - - lpc32xx_chip.IO_ADDR_R = &lpc32xx_nand_mlc_registers->buff; - lpc32xx_chip.IO_ADDR_W = &lpc32xx_nand_mlc_registers->buff; - lpc32xx_chip.cmd_ctrl = lpc32xx_cmd_ctrl; - /* do not set init_size: nand_base.c will read sizes from chip */ - lpc32xx_chip.dev_ready = lpc32xx_dev_ready; - /* do not set setup_read_retry: this is NAND-chip-specific */ - /* do not set chip_delay: we have dev_ready defined. */ - lpc32xx_chip.options |= NAND_NO_SUBPAGE_WRITE; - - /* Set needed ECC fields */ - - lpc32xx_chip.ecc.mode = NAND_ECC_HW; - lpc32xx_chip.ecc.layout = &lpc32xx_largepage_ecclayout; - lpc32xx_chip.ecc.size = 512; - lpc32xx_chip.ecc.bytes = 10; - lpc32xx_chip.ecc.strength = 4; - lpc32xx_chip.ecc.read_page = lpc32xx_read_page_hwecc; - lpc32xx_chip.ecc.read_page_raw = lpc32xx_read_page_raw; - lpc32xx_chip.ecc.write_page = lpc32xx_write_page_hwecc; - lpc32xx_chip.ecc.write_page_raw = lpc32xx_write_page_raw; - lpc32xx_chip.ecc.read_oob = lpc32xx_read_oob; - lpc32xx_chip.ecc.write_oob = lpc32xx_write_oob; - lpc32xx_chip.waitfunc = lpc32xx_waitfunc; - - lpc32xx_chip.read_byte = lpc32xx_read_byte; /* FIXME: NEEDED? */ - - /* BBT options: read from last two pages */ - lpc32xx_chip.bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_LASTBLOCK - | NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE - | NAND_BBT_WRITE; - - /* Initialize NAND interface */ - lpc32xx_nand_init(); - - /* identify chip */ - ret = nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL); - if (ret) { - pr_err("nand_scan_ident returned %i", ret); - return; - } - - /* finish scanning the chip */ - ret = nand_scan_tail(mtd); - if (ret) { - pr_err("nand_scan_tail returned %i", ret); - return; - } - - /* chip is good, register it */ - ret = nand_register(0, mtd); - if (ret) - pr_err("nand_register returned %i", ret); -} - -#else /* defined(CONFIG_SPL_BUILD) */ - -void nand_init(void) -{ - /* enable NAND controller */ - lpc32xx_mlc_nand_init(); - /* initialize NAND controller */ - lpc32xx_nand_init(); -} - -void nand_deselect(void) -{ - /* nothing to do, but SPL requires this function */ -} - -static int read_single_page(uint8_t *dest, int page, - struct lpc32xx_oob *oob) -{ - int status, i, timeout, err, max_bitflips = 0; - - /* enter read mode */ - writel(NAND_CMD_READ0, &lpc32xx_nand_mlc_registers->cmd); - /* send column (lsb then MSB) and page (lsb to MSB) */ - writel(0, &lpc32xx_nand_mlc_registers->addr); - writel(0, &lpc32xx_nand_mlc_registers->addr); - writel(page & 0xff, &lpc32xx_nand_mlc_registers->addr); - writel((page>>8) & 0xff, &lpc32xx_nand_mlc_registers->addr); - writel((page>>16) & 0xff, &lpc32xx_nand_mlc_registers->addr); - /* start reading */ - writel(NAND_CMD_READSTART, &lpc32xx_nand_mlc_registers->cmd); - - /* large page auto decode read */ - for (i = 0; i < 4; i++) { - /* start auto decode (reads 528 NAND bytes) */ - writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg); - /* wait for controller to return to ready state */ - for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { - status = readl(&lpc32xx_nand_mlc_registers->isr); - if (status & ISR_CONTROLLER_READY) - break; - udelay(1); - } - /* if controller stalled, return error */ - if (!(status & ISR_CONTROLLER_READY)) - return -1; - /* if decoder failure, return error */ - if (status & ISR_DECODER_FAILURE) - return -1; - /* keep count of maximum bitflips performed */ - if (status & ISR_DECODER_ERROR) { - err = ISR_DECODER_ERRORS(status); - if (err > max_bitflips) - max_bitflips = err; - } - /* copy first 512 bytes into buffer */ - memcpy(dest+i*512, lpc32xx_nand_mlc_registers->buff, 512); - /* copy next 6 bytes bytes into OOB buffer */ - memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6); - } - return max_bitflips; -} - -/* - * Load U-Boot signed image. - * This loads an image from NAND, skipping bad blocks. - * A block is declared bad if at least one of its readable pages has - * a bad block marker in its OOB at position 0. - * If all pages ion a block are unreadable, the block is considered - * bad (i.e., assumed not to be part of the image) and skipped. - * - * IMPORTANT NOTE: - * - * If the first block of the image is fully unreadable, it will be - * ignored and skipped as if it had been marked bad. If it was not - * actually marked bad at the time of writing the image, the resulting - * image loaded will lack a header and magic number. It could thus be - * considered as a raw, headerless, image and SPL might erroneously - * jump into it. - * - * In order to avoid this risk, LPC32XX-based boards which use this - * driver MUST define CONFIG_SPL_PANIC_ON_RAW_IMAGE. - */ - -#define BYTES_PER_PAGE 2048 -#define PAGES_PER_BLOCK 64 -#define BYTES_PER_BLOCK (BYTES_PER_PAGE * PAGES_PER_BLOCK) -#define PAGES_PER_CHIP_MAX 524288 - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - int bytes_left = size; - int pages_left = DIV_ROUND_UP(size, BYTES_PER_PAGE); - int blocks_left = DIV_ROUND_UP(size, BYTES_PER_BLOCK); - int block = 0; - int page = offs / BYTES_PER_PAGE; - /* perform reads block by block */ - while (blocks_left) { - /* compute first page number to read */ - void *block_page_dst = dst; - /* read at most one block, possibly less */ - int block_bytes_left = bytes_left; - if (block_bytes_left > BYTES_PER_BLOCK) - block_bytes_left = BYTES_PER_BLOCK; - /* keep track of good, failed, and "bad" pages */ - int block_pages_good = 0; - int block_pages_bad = 0; - int block_pages_err = 0; - /* we shall read a full block of pages, maybe less */ - int block_pages_left = pages_left; - if (block_pages_left > PAGES_PER_BLOCK) - block_pages_left = PAGES_PER_BLOCK; - int block_pages = block_pages_left; - int block_page = page; - /* while pages are left and the block is not known as bad */ - while ((block_pages > 0) && (block_pages_bad == 0)) { - /* we will read OOB, too, for bad block markers */ - struct lpc32xx_oob oob; - /* read page */ - int res = read_single_page(block_page_dst, block_page, - &oob); - /* count readable pages */ - if (res >= 0) { - /* this page is good */ - block_pages_good++; - /* this page is bad */ - if ((oob.free[0].free_oob_bytes[0] != 0xff) - | (oob.free[0].free_oob_bytes[1] != 0xff)) - block_pages_bad++; - } else - /* count errors */ - block_pages_err++; - /* we're done with this page */ - block_page++; - block_page_dst += BYTES_PER_PAGE; - if (block_pages) - block_pages--; - } - /* a fully unreadable block is considered bad */ - if (block_pages_good == 0) - block_pages_bad = block_pages_err; - /* errors are fatal only in good blocks */ - if ((block_pages_err > 0) && (block_pages_bad == 0)) - return -1; - /* we keep reads only of good blocks */ - if (block_pages_bad == 0) { - dst += block_bytes_left; - bytes_left -= block_bytes_left; - pages_left -= block_pages_left; - blocks_left--; - } - /* good or bad, we're done with this block */ - block++; - page += PAGES_PER_BLOCK; - } - - /* report success */ - return 0; -} - -#endif /* CONFIG_SPL_BUILD */ diff --git a/drivers/mtd/nand/lpc32xx_nand_slc.c b/drivers/mtd/nand/lpc32xx_nand_slc.c deleted file mode 100644 index 99f6e15f4e..0000000000 --- a/drivers/mtd/nand/lpc32xx_nand_slc.c +++ /dev/null @@ -1,597 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * LPC32xx SLC NAND flash controller driver - * - * (C) Copyright 2015 Vladimir Zapolskiy - * - * Hardware ECC support original source code - * Copyright (C) 2008 by NXP Semiconductors - * Author: Kevin Wells - * - * Copyright (c) 2015 Tyco Fire Protection Products. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_DMA_LPC32XX) && defined(CONFIG_SPL_BUILD) -#warning "DMA support in SPL image is not tested" -#endif - -struct lpc32xx_nand_slc_regs { - u32 data; - u32 addr; - u32 cmd; - u32 stop; - u32 ctrl; - u32 cfg; - u32 stat; - u32 int_stat; - u32 ien; - u32 isr; - u32 icr; - u32 tac; - u32 tc; - u32 ecc; - u32 dma_data; -}; - -/* CFG register */ -#define CFG_CE_LOW (1 << 5) -#define CFG_DMA_ECC (1 << 4) /* Enable DMA ECC bit */ -#define CFG_ECC_EN (1 << 3) /* ECC enable bit */ -#define CFG_DMA_BURST (1 << 2) /* DMA burst bit */ -#define CFG_DMA_DIR (1 << 1) /* DMA write(0)/read(1) bit */ - -/* CTRL register */ -#define CTRL_SW_RESET (1 << 2) -#define CTRL_ECC_CLEAR (1 << 1) /* Reset ECC bit */ -#define CTRL_DMA_START (1 << 0) /* Start DMA channel bit */ - -/* STAT register */ -#define STAT_DMA_FIFO (1 << 2) /* DMA FIFO has data bit */ -#define STAT_NAND_READY (1 << 0) - -/* INT_STAT register */ -#define INT_STAT_TC (1 << 1) -#define INT_STAT_RDY (1 << 0) - -/* TAC register bits, be aware of overflows */ -#define TAC_W_RDY(n) (max_t(uint32_t, (n), 0xF) << 28) -#define TAC_W_WIDTH(n) (max_t(uint32_t, (n), 0xF) << 24) -#define TAC_W_HOLD(n) (max_t(uint32_t, (n), 0xF) << 20) -#define TAC_W_SETUP(n) (max_t(uint32_t, (n), 0xF) << 16) -#define TAC_R_RDY(n) (max_t(uint32_t, (n), 0xF) << 12) -#define TAC_R_WIDTH(n) (max_t(uint32_t, (n), 0xF) << 8) -#define TAC_R_HOLD(n) (max_t(uint32_t, (n), 0xF) << 4) -#define TAC_R_SETUP(n) (max_t(uint32_t, (n), 0xF) << 0) - -/* NAND ECC Layout for small page NAND devices - * Note: For large page devices, the default layouts are used. */ -static struct nand_ecclayout lpc32xx_nand_oob_16 = { - .eccbytes = 6, - .eccpos = {10, 11, 12, 13, 14, 15}, - .oobfree = { - {.offset = 0, - . length = 4}, - {.offset = 6, - . length = 4} - } -}; - -#if defined(CONFIG_DMA_LPC32XX) -#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE) - -/* - * DMA Descriptors - * For Large Block: 17 descriptors = ((16 Data and ECC Read) + 1 Spare Area) - * For Small Block: 5 descriptors = ((4 Data and ECC Read) + 1 Spare Area) - */ -static struct lpc32xx_dmac_ll dmalist[ECCSTEPS * 2 + 1]; -static u32 ecc_buffer[8]; /* MAX ECC size */ -static unsigned int dmachan = (unsigned int)-1; /* Invalid channel */ - -/* - * Helper macro for the DMA client (i.e. NAND SLC): - * - to write the next DMA linked list item address - * (see arch/include/asm/arch-lpc32xx/dma.h). - * - to assign the DMA data register to DMA source or destination address. - * - to assign the ECC register to DMA source or destination address. - */ -#define lpc32xx_dmac_next_lli(x) ((u32)x) -#define lpc32xx_dmac_set_dma_data() ((u32)&lpc32xx_nand_slc_regs->dma_data) -#define lpc32xx_dmac_set_ecc() ((u32)&lpc32xx_nand_slc_regs->ecc) -#endif - -static struct lpc32xx_nand_slc_regs __iomem *lpc32xx_nand_slc_regs - = (struct lpc32xx_nand_slc_regs __iomem *)SLC_NAND_BASE; - -static void lpc32xx_nand_init(void) -{ - uint32_t hclk = get_hclk_clk_rate(); - - /* Reset SLC NAND controller */ - writel(CTRL_SW_RESET, &lpc32xx_nand_slc_regs->ctrl); - - /* 8-bit bus, no DMA, no ECC, ordinary CE signal */ - writel(0, &lpc32xx_nand_slc_regs->cfg); - - /* Interrupts disabled and cleared */ - writel(0, &lpc32xx_nand_slc_regs->ien); - writel(INT_STAT_TC | INT_STAT_RDY, - &lpc32xx_nand_slc_regs->icr); - - /* Configure NAND flash timings */ - writel(TAC_W_RDY(CONFIG_LPC32XX_NAND_SLC_WDR_CLKS) | - TAC_W_WIDTH(hclk / CONFIG_LPC32XX_NAND_SLC_WWIDTH) | - TAC_W_HOLD(hclk / CONFIG_LPC32XX_NAND_SLC_WHOLD) | - TAC_W_SETUP(hclk / CONFIG_LPC32XX_NAND_SLC_WSETUP) | - TAC_R_RDY(CONFIG_LPC32XX_NAND_SLC_RDR_CLKS) | - TAC_R_WIDTH(hclk / CONFIG_LPC32XX_NAND_SLC_RWIDTH) | - TAC_R_HOLD(hclk / CONFIG_LPC32XX_NAND_SLC_RHOLD) | - TAC_R_SETUP(hclk / CONFIG_LPC32XX_NAND_SLC_RSETUP), - &lpc32xx_nand_slc_regs->tac); -} - -static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, - int cmd, unsigned int ctrl) -{ - debug("ctrl: 0x%08x, cmd: 0x%08x\n", ctrl, cmd); - - if (ctrl & NAND_NCE) - setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_CE_LOW); - else - clrbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_CE_LOW); - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - writel(cmd & 0xFF, &lpc32xx_nand_slc_regs->cmd); - else if (ctrl & NAND_ALE) - writel(cmd & 0xFF, &lpc32xx_nand_slc_regs->addr); -} - -static int lpc32xx_nand_dev_ready(struct mtd_info *mtd) -{ - return readl(&lpc32xx_nand_slc_regs->stat) & STAT_NAND_READY; -} - -#if defined(CONFIG_DMA_LPC32XX) -/* - * Prepares DMA descriptors for NAND RD/WR operations - * If the size is < 256 Bytes then it is assumed to be - * an OOB transfer - */ -static void lpc32xx_nand_dma_configure(struct nand_chip *chip, - const u8 *buffer, int size, - int read) -{ - u32 i, dmasrc, ctrl, ecc_ctrl, oob_ctrl, dmadst; - struct lpc32xx_dmac_ll *dmalist_cur; - struct lpc32xx_dmac_ll *dmalist_cur_ecc; - - /* - * CTRL descriptor entry for reading ECC - * Copy Multiple times to sync DMA with Flash Controller - */ - ecc_ctrl = 0x5 | - DMAC_CHAN_SRC_BURST_1 | - DMAC_CHAN_DEST_BURST_1 | - DMAC_CHAN_SRC_WIDTH_32 | - DMAC_CHAN_DEST_WIDTH_32 | - DMAC_CHAN_DEST_AHB1; - - /* CTRL descriptor entry for reading/writing Data */ - ctrl = (CONFIG_SYS_NAND_ECCSIZE / 4) | - DMAC_CHAN_SRC_BURST_4 | - DMAC_CHAN_DEST_BURST_4 | - DMAC_CHAN_SRC_WIDTH_32 | - DMAC_CHAN_DEST_WIDTH_32 | - DMAC_CHAN_DEST_AHB1; - - /* CTRL descriptor entry for reading/writing Spare Area */ - oob_ctrl = (CONFIG_SYS_NAND_OOBSIZE / 4) | - DMAC_CHAN_SRC_BURST_4 | - DMAC_CHAN_DEST_BURST_4 | - DMAC_CHAN_SRC_WIDTH_32 | - DMAC_CHAN_DEST_WIDTH_32 | - DMAC_CHAN_DEST_AHB1; - - if (read) { - dmasrc = lpc32xx_dmac_set_dma_data(); - dmadst = (u32)buffer; - ctrl |= DMAC_CHAN_DEST_AUTOINC; - } else { - dmadst = lpc32xx_dmac_set_dma_data(); - dmasrc = (u32)buffer; - ctrl |= DMAC_CHAN_SRC_AUTOINC; - } - - /* - * Write Operation Sequence for Small Block NAND - * ---------------------------------------------------------- - * 1. X'fer 256 bytes of data from Memory to Flash. - * 2. Copy generated ECC data from Register to Spare Area - * 3. X'fer next 256 bytes of data from Memory to Flash. - * 4. Copy generated ECC data from Register to Spare Area. - * 5. X'fer 16 byets of Spare area from Memory to Flash. - * Read Operation Sequence for Small Block NAND - * ---------------------------------------------------------- - * 1. X'fer 256 bytes of data from Flash to Memory. - * 2. Copy generated ECC data from Register to ECC calc Buffer. - * 3. X'fer next 256 bytes of data from Flash to Memory. - * 4. Copy generated ECC data from Register to ECC calc Buffer. - * 5. X'fer 16 bytes of Spare area from Flash to Memory. - * Write Operation Sequence for Large Block NAND - * ---------------------------------------------------------- - * 1. Steps(1-4) of Write Operations repeate for four times - * which generates 16 DMA descriptors to X'fer 2048 bytes of - * data & 32 bytes of ECC data. - * 2. X'fer 64 bytes of Spare area from Memory to Flash. - * Read Operation Sequence for Large Block NAND - * ---------------------------------------------------------- - * 1. Steps(1-4) of Read Operations repeate for four times - * which generates 16 DMA descriptors to X'fer 2048 bytes of - * data & 32 bytes of ECC data. - * 2. X'fer 64 bytes of Spare area from Flash to Memory. - */ - - for (i = 0; i < size/CONFIG_SYS_NAND_ECCSIZE; i++) { - dmalist_cur = &dmalist[i * 2]; - dmalist_cur_ecc = &dmalist[(i * 2) + 1]; - - dmalist_cur->dma_src = (read ? (dmasrc) : (dmasrc + (i*256))); - dmalist_cur->dma_dest = (read ? (dmadst + (i*256)) : dmadst); - dmalist_cur->next_lli = lpc32xx_dmac_next_lli(dmalist_cur_ecc); - dmalist_cur->next_ctrl = ctrl; - - dmalist_cur_ecc->dma_src = lpc32xx_dmac_set_ecc(); - dmalist_cur_ecc->dma_dest = (u32)&ecc_buffer[i]; - dmalist_cur_ecc->next_lli = - lpc32xx_dmac_next_lli(&dmalist[(i * 2) + 2]); - dmalist_cur_ecc->next_ctrl = ecc_ctrl; - } - - if (i) { /* Data only transfer */ - dmalist_cur_ecc = &dmalist[(i * 2) - 1]; - dmalist_cur_ecc->next_lli = 0; - dmalist_cur_ecc->next_ctrl |= DMAC_CHAN_INT_TC_EN; - return; - } - - /* OOB only transfer */ - if (read) { - dmasrc = lpc32xx_dmac_set_dma_data(); - dmadst = (u32)buffer; - oob_ctrl |= DMAC_CHAN_DEST_AUTOINC; - } else { - dmadst = lpc32xx_dmac_set_dma_data(); - dmasrc = (u32)buffer; - oob_ctrl |= DMAC_CHAN_SRC_AUTOINC; - } - - /* Read/ Write Spare Area Data To/From Flash */ - dmalist_cur = &dmalist[i * 2]; - dmalist_cur->dma_src = dmasrc; - dmalist_cur->dma_dest = dmadst; - dmalist_cur->next_lli = 0; - dmalist_cur->next_ctrl = (oob_ctrl | DMAC_CHAN_INT_TC_EN); -} - -static void lpc32xx_nand_xfer(struct mtd_info *mtd, const u8 *buf, - int len, int read) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - u32 config; - int ret; - - /* DMA Channel Configuration */ - config = (read ? DMAC_CHAN_FLOW_D_P2M : DMAC_CHAN_FLOW_D_M2P) | - (read ? DMAC_DEST_PERIP(0) : DMAC_DEST_PERIP(DMA_PERID_NAND1)) | - (read ? DMAC_SRC_PERIP(DMA_PERID_NAND1) : DMAC_SRC_PERIP(0)) | - DMAC_CHAN_ENABLE; - - /* Prepare DMA descriptors */ - lpc32xx_nand_dma_configure(chip, buf, len, read); - - /* Setup SLC controller and start transfer */ - if (read) - setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_DMA_DIR); - else /* NAND_ECC_WRITE */ - clrbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_DMA_DIR); - setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_DMA_BURST); - - /* Write length for new transfers */ - if (!((readl(&lpc32xx_nand_slc_regs->stat) & STAT_DMA_FIFO) | - readl(&lpc32xx_nand_slc_regs->tc))) { - int tmp = (len != mtd->oobsize) ? mtd->oobsize : 0; - writel(len + tmp, &lpc32xx_nand_slc_regs->tc); - } - - setbits_le32(&lpc32xx_nand_slc_regs->ctrl, CTRL_DMA_START); - - /* Start DMA transfers */ - ret = lpc32xx_dma_start_xfer(dmachan, dmalist, config); - if (unlikely(ret < 0)) - BUG(); - - - /* Wait for NAND to be ready */ - while (!lpc32xx_nand_dev_ready(mtd)) - ; - - /* Wait till DMA transfer is DONE */ - if (lpc32xx_dma_wait_status(dmachan)) - pr_err("NAND DMA transfer error!\r\n"); - - /* Stop DMA & HW ECC */ - clrbits_le32(&lpc32xx_nand_slc_regs->ctrl, CTRL_DMA_START); - clrbits_le32(&lpc32xx_nand_slc_regs->cfg, - CFG_DMA_DIR | CFG_DMA_BURST | CFG_ECC_EN | CFG_DMA_ECC); -} - -static u32 slc_ecc_copy_to_buffer(u8 *spare, const u32 *ecc, int count) -{ - int i; - for (i = 0; i < (count * CONFIG_SYS_NAND_ECCBYTES); - i += CONFIG_SYS_NAND_ECCBYTES) { - u32 ce = ecc[i / CONFIG_SYS_NAND_ECCBYTES]; - ce = ~(ce << 2) & 0xFFFFFF; - spare[i+2] = (u8)(ce & 0xFF); ce >>= 8; - spare[i+1] = (u8)(ce & 0xFF); ce >>= 8; - spare[i] = (u8)(ce & 0xFF); - } - return 0; -} - -static int lpc32xx_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code) -{ - return slc_ecc_copy_to_buffer(ecc_code, ecc_buffer, ECCSTEPS); -} - -/* - * Enables and prepares SLC NAND controller - * for doing data transfers with H/W ECC enabled. - */ -static void lpc32xx_hwecc_enable(struct mtd_info *mtd, int mode) -{ - /* Clear ECC */ - writel(CTRL_ECC_CLEAR, &lpc32xx_nand_slc_regs->ctrl); - - /* Setup SLC controller for H/W ECC operations */ - setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_ECC_EN | CFG_DMA_ECC); -} - -/* - * lpc32xx_correct_data - [NAND Interface] Detect and correct bit error(s) - * mtd: MTD block structure - * dat: 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 byte block - */ -int lpc32xx_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - unsigned int i; - int ret1, ret2 = 0; - u_char *r = read_ecc; - u_char *c = calc_ecc; - u16 data_offset = 0; - - for (i = 0 ; i < ECCSTEPS ; i++) { - r += CONFIG_SYS_NAND_ECCBYTES; - c += CONFIG_SYS_NAND_ECCBYTES; - data_offset += CONFIG_SYS_NAND_ECCSIZE; - - ret1 = nand_correct_data(mtd, dat + data_offset, r, c); - if (ret1 < 0) - return -EBADMSG; - else - ret2 += ret1; - } - - return ret2; -} -#endif - -#if defined(CONFIG_DMA_LPC32XX) -static void lpc32xx_dma_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - lpc32xx_nand_xfer(mtd, buf, len, 1); -} -#else -static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - while (len-- > 0) - *buf++ = readl(&lpc32xx_nand_slc_regs->data); -} -#endif - -static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) -{ - return readl(&lpc32xx_nand_slc_regs->data); -} - -#if defined(CONFIG_DMA_LPC32XX) -static void lpc32xx_dma_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - lpc32xx_nand_xfer(mtd, buf, len, 0); -} -#else -static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - while (len-- > 0) - writel(*buf++, &lpc32xx_nand_slc_regs->data); -} -#endif - -static void lpc32xx_write_byte(struct mtd_info *mtd, uint8_t byte) -{ - writel(byte, &lpc32xx_nand_slc_regs->data); -} - -#if defined(CONFIG_DMA_LPC32XX) -/* Reuse the logic from "nand_read_page_hwecc()" */ -static int lpc32xx_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int i; - int stat; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - unsigned int max_bitflips = 0; - - /* - * As per the "LPC32x0 and LPC32x0/01 User manual" table 173 notes - * and section 9.7, the NAND SLC & DMA allowed single DMA transaction - * of a page size using DMA controller scatter/gather mode through - * linked list; the ECC read is done without any software intervention. - */ - - lpc32xx_hwecc_enable(mtd, NAND_ECC_READ); - lpc32xx_dma_read_buf(mtd, p, chip->ecc.size * chip->ecc.steps); - lpc32xx_ecc_calculate(mtd, p, &ecc_calc[0]); - lpc32xx_dma_read_buf(mtd, chip->oob_poi, mtd->oobsize); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - stat = chip->ecc.correct(mtd, p, &ecc_code[0], &ecc_calc[0]); - if (stat < 0) - mtd->ecc_stats.failed++; - else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - - return max_bitflips; -} - -/* Reuse the logic from "nand_write_page_hwecc()" */ -static int lpc32xx_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) -{ - int i; - uint8_t *ecc_calc = chip->buffers->ecccalc; - const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; - - /* - * As per the "LPC32x0 and LPC32x0/01 User manual" table 173 notes - * and section 9.7, the NAND SLC & DMA allowed single DMA transaction - * of a page size using DMA controller scatter/gather mode through - * linked list; the ECC read is done without any software intervention. - */ - - lpc32xx_hwecc_enable(mtd, NAND_ECC_WRITE); - lpc32xx_dma_write_buf(mtd, p, chip->ecc.size * chip->ecc.steps); - lpc32xx_ecc_calculate(mtd, p, &ecc_calc[0]); - - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - lpc32xx_dma_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} -#endif - -/* - * LPC32xx has only one SLC NAND controller, don't utilize - * CONFIG_SYS_NAND_SELF_INIT to be able to reuse this function - * both in SPL NAND and U-Boot images. - */ -int board_nand_init(struct nand_chip *lpc32xx_chip) -{ -#if defined(CONFIG_DMA_LPC32XX) - int ret; - - /* Acquire a channel for our use */ - ret = lpc32xx_dma_get_channel(); - if (unlikely(ret < 0)) { - pr_info("Unable to get free DMA channel for NAND transfers\n"); - return -1; - } - dmachan = (unsigned int)ret; -#endif - - lpc32xx_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; - lpc32xx_chip->dev_ready = lpc32xx_nand_dev_ready; - - /* - * The implementation of these functions is quite common, but - * they MUST be defined, because access to data register - * is strictly 32-bit aligned. - */ - lpc32xx_chip->read_byte = lpc32xx_read_byte; - lpc32xx_chip->write_byte = lpc32xx_write_byte; - -#if defined(CONFIG_DMA_LPC32XX) - /* Hardware ECC calculation is supported when DMA driver is selected */ - lpc32xx_chip->ecc.mode = NAND_ECC_HW; - - lpc32xx_chip->read_buf = lpc32xx_dma_read_buf; - lpc32xx_chip->write_buf = lpc32xx_dma_write_buf; - - lpc32xx_chip->ecc.calculate = lpc32xx_ecc_calculate; - lpc32xx_chip->ecc.correct = lpc32xx_correct_data; - lpc32xx_chip->ecc.hwctl = lpc32xx_hwecc_enable; - lpc32xx_chip->chip_delay = 2000; - - lpc32xx_chip->ecc.read_page = lpc32xx_read_page_hwecc; - lpc32xx_chip->ecc.write_page = lpc32xx_write_page_hwecc; - lpc32xx_chip->options |= NAND_NO_SUBPAGE_WRITE; -#else - /* - * Hardware ECC calculation is not supported by the driver, - * because it requires DMA support, see LPC32x0 User Manual, - * note after SLC_ECC register description (UM10326, p.198) - */ - lpc32xx_chip->ecc.mode = NAND_ECC_SOFT; - - /* - * The implementation of these functions is quite common, but - * they MUST be defined, because access to data register - * is strictly 32-bit aligned. - */ - lpc32xx_chip->read_buf = lpc32xx_read_buf; - lpc32xx_chip->write_buf = lpc32xx_write_buf; -#endif - - /* - * These values are predefined - * for both small and large page NAND flash devices. - */ - lpc32xx_chip->ecc.size = CONFIG_SYS_NAND_ECCSIZE; - lpc32xx_chip->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; - lpc32xx_chip->ecc.strength = 1; - - if (CONFIG_SYS_NAND_PAGE_SIZE != NAND_LARGE_BLOCK_PAGE_SIZE) - lpc32xx_chip->ecc.layout = &lpc32xx_nand_oob_16; - -#if defined(CONFIG_SYS_NAND_USE_FLASH_BBT) - lpc32xx_chip->bbt_options |= NAND_BBT_USE_FLASH; -#endif - - /* Initialize NAND interface */ - lpc32xx_nand_init(); - - return 0; -} diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c deleted file mode 100644 index cf97e0f74f..0000000000 --- a/drivers/mtd/nand/mxc_nand.c +++ /dev/null @@ -1,1307 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. - * Copyright 2008 Sascha Hauer, kernel@pengutronix.de - * Copyright 2009 Ilya Yanok, - */ - -#include -#include -#include -#include -#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) || \ - defined(CONFIG_MX51) || defined(CONFIG_MX53) -#include -#endif -#include "mxc_nand.h" - -#define DRIVER_NAME "mxc_nand" - -struct mxc_nand_host { - struct nand_chip *nand; - - struct mxc_nand_regs __iomem *regs; -#ifdef MXC_NFC_V3_2 - struct mxc_nand_ip_regs __iomem *ip_regs; -#endif - int spare_only; - int status_request; - int pagesize_2k; - int clk_act; - uint16_t col_addr; - unsigned int page_addr; -}; - -static struct mxc_nand_host mxc_host; -static struct mxc_nand_host *host = &mxc_host; - -/* Define delays in microsec for NAND device operations */ -#define TROP_US_DELAY 2000 -/* Macros to get byte and bit positions of ECC */ -#define COLPOS(x) ((x) >> 3) -#define BITPOS(x) ((x) & 0xf) - -/* Define single bit Error positions in Main & Spare area */ -#define MAIN_SINGLEBIT_ERROR 0x4 -#define SPARE_SINGLEBIT_ERROR 0x1 - -/* OOB placement block for use with hardware ecc generation */ -#if defined(MXC_NFC_V1) -#ifndef CONFIG_SYS_NAND_LARGEPAGE -static struct nand_ecclayout nand_hw_eccoob = { - .eccbytes = 5, - .eccpos = {6, 7, 8, 9, 10}, - .oobfree = { {0, 5}, {11, 5}, } -}; -#else -static struct nand_ecclayout nand_hw_eccoob2k = { - .eccbytes = 20, - .eccpos = { - 6, 7, 8, 9, 10, - 22, 23, 24, 25, 26, - 38, 39, 40, 41, 42, - 54, 55, 56, 57, 58, - }, - .oobfree = { {2, 4}, {11, 11}, {27, 11}, {43, 11}, {59, 5} }, -}; -#endif -#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) -#ifndef CONFIG_SYS_NAND_LARGEPAGE -static struct nand_ecclayout nand_hw_eccoob = { - .eccbytes = 9, - .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15}, - .oobfree = { {2, 5} } -}; -#else -static struct nand_ecclayout nand_hw_eccoob2k = { - .eccbytes = 36, - .eccpos = { - 7, 8, 9, 10, 11, 12, 13, 14, 15, - 23, 24, 25, 26, 27, 28, 29, 30, 31, - 39, 40, 41, 42, 43, 44, 45, 46, 47, - 55, 56, 57, 58, 59, 60, 61, 62, 63, - }, - .oobfree = { {2, 5}, {16, 7}, {32, 7}, {48, 7} }, -}; -#endif -#endif - -static int is_16bit_nand(void) -{ -#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT) - return 1; -#else - return 0; -#endif -} - -static uint32_t *mxc_nand_memcpy32(uint32_t *dest, uint32_t *source, size_t size) -{ - uint32_t *d = dest; - - size >>= 2; - while (size--) - __raw_writel(__raw_readl(source++), d++); - return dest; -} - -/* - * This function polls the NANDFC to wait for the basic operation to - * complete by checking the INT bit. - */ -static void wait_op_done(struct mxc_nand_host *host, int max_retries, - uint16_t param) -{ - uint32_t tmp; - - while (max_retries-- > 0) { -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - tmp = readnfc(&host->regs->config2); - if (tmp & NFC_V1_V2_CONFIG2_INT) { - tmp &= ~NFC_V1_V2_CONFIG2_INT; - writenfc(tmp, &host->regs->config2); -#elif defined(MXC_NFC_V3_2) - tmp = readnfc(&host->ip_regs->ipc); - if (tmp & NFC_V3_IPC_INT) { - tmp &= ~NFC_V3_IPC_INT; - writenfc(tmp, &host->ip_regs->ipc); -#endif - break; - } - udelay(1); - } - if (max_retries < 0) { - pr_debug("%s(%d): INT not set\n", - __func__, param); - } -} - -/* - * This function issues the specified command to the NAND device and - * waits for completion. - */ -static void send_cmd(struct mxc_nand_host *host, uint16_t cmd) -{ - pr_debug("send_cmd(host, 0x%x)\n", cmd); - - writenfc(cmd, &host->regs->flash_cmd); - writenfc(NFC_CMD, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, cmd); -} - -/* - * This function sends an address (or partial address) to the - * NAND device. The address is used to select the source/destination for - * a NAND command. - */ -static void send_addr(struct mxc_nand_host *host, uint16_t addr) -{ - pr_debug("send_addr(host, 0x%x)\n", addr); - - writenfc(addr, &host->regs->flash_addr); - writenfc(NFC_ADDR, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, addr); -} - -/* - * This function requests the NANDFC to initiate the transfer - * of data currently in the NANDFC RAM buffer to the NAND device. - */ -static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, - int spare_only) -{ - if (spare_only) - pr_debug("send_prog_page (%d)\n", spare_only); - - if (is_mxc_nfc_21() || is_mxc_nfc_32()) { - int i; - /* - * The controller copies the 64 bytes of spare data from - * the first 16 bytes of each of the 4 64 byte spare buffers. - * Copy the contiguous data starting in spare_area[0] to - * the four spare area buffers. - */ - for (i = 1; i < 4; i++) { - void __iomem *src = &host->regs->spare_area[0][i * 16]; - void __iomem *dst = &host->regs->spare_area[i][0]; - - mxc_nand_memcpy32(dst, src, 16); - } - } - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - writenfc(buf_id, &host->regs->buf_addr); -#elif defined(MXC_NFC_V3_2) - uint32_t tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_V3_CONFIG1_RBA_MASK; - tmp |= NFC_V3_CONFIG1_RBA(buf_id); - writenfc(tmp, &host->regs->config1); -#endif - - /* Configure spare or page+spare access */ - if (!host->pagesize_2k) { - uint32_t config1 = readnfc(&host->regs->config1); - if (spare_only) - config1 |= NFC_CONFIG1_SP_EN; - else - config1 &= ~NFC_CONFIG1_SP_EN; - writenfc(config1, &host->regs->config1); - } - - writenfc(NFC_INPUT, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, spare_only); -} - -/* - * Requests NANDFC to initiate the transfer of data from the - * NAND device into in the NANDFC ram buffer. - */ -static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, - int spare_only) -{ - pr_debug("send_read_page (%d)\n", spare_only); - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - writenfc(buf_id, &host->regs->buf_addr); -#elif defined(MXC_NFC_V3_2) - uint32_t tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_V3_CONFIG1_RBA_MASK; - tmp |= NFC_V3_CONFIG1_RBA(buf_id); - writenfc(tmp, &host->regs->config1); -#endif - - /* Configure spare or page+spare access */ - if (!host->pagesize_2k) { - uint32_t config1 = readnfc(&host->regs->config1); - if (spare_only) - config1 |= NFC_CONFIG1_SP_EN; - else - config1 &= ~NFC_CONFIG1_SP_EN; - writenfc(config1, &host->regs->config1); - } - - writenfc(NFC_OUTPUT, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, spare_only); - - if (is_mxc_nfc_21() || is_mxc_nfc_32()) { - int i; - - /* - * The controller copies the 64 bytes of spare data to - * the first 16 bytes of each of the 4 spare buffers. - * Make the data contiguous starting in spare_area[0]. - */ - for (i = 1; i < 4; i++) { - void __iomem *src = &host->regs->spare_area[i][0]; - void __iomem *dst = &host->regs->spare_area[0][i * 16]; - - mxc_nand_memcpy32(dst, src, 16); - } - } -} - -/* Request the NANDFC to perform a read of the NAND device ID. */ -static void send_read_id(struct mxc_nand_host *host) -{ - uint32_t tmp; - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - /* NANDFC buffer 0 is used for device ID output */ - writenfc(0x0, &host->regs->buf_addr); -#elif defined(MXC_NFC_V3_2) - tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_V3_CONFIG1_RBA_MASK; - writenfc(tmp, &host->regs->config1); -#endif - - /* Read ID into main buffer */ - tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_CONFIG1_SP_EN; - writenfc(tmp, &host->regs->config1); - - writenfc(NFC_ID, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, 0); -} - -/* - * This function requests the NANDFC to perform a read of the - * NAND device status and returns the current status. - */ -static uint16_t get_dev_status(struct mxc_nand_host *host) -{ -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - void __iomem *main_buf = host->regs->main_area[1]; - uint32_t store; -#endif - uint32_t ret, tmp; - /* Issue status request to NAND device */ - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - /* store the main area1 first word, later do recovery */ - store = readl(main_buf); - /* NANDFC buffer 1 is used for device status */ - writenfc(1, &host->regs->buf_addr); -#endif - - /* Read status into main buffer */ - tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_CONFIG1_SP_EN; - writenfc(tmp, &host->regs->config1); - - writenfc(NFC_STATUS, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, 0); - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - /* - * Status is placed in first word of main buffer - * get status, then recovery area 1 data - */ - ret = readw(main_buf); - writel(store, main_buf); -#elif defined(MXC_NFC_V3_2) - ret = readnfc(&host->regs->config1) >> 16; -#endif - - return ret; -} - -/* This function is used by upper layer to checks if device is ready */ -static int mxc_nand_dev_ready(struct mtd_info *mtd) -{ - /* - * NFC handles R/B internally. Therefore, this function - * always returns status as ready. - */ - return 1; -} - -static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - uint16_t tmp = readnfc(&host->regs->config1); - - if (on) - tmp |= NFC_V1_V2_CONFIG1_ECC_EN; - else - tmp &= ~NFC_V1_V2_CONFIG1_ECC_EN; - writenfc(tmp, &host->regs->config1); -#elif defined(MXC_NFC_V3_2) - uint32_t tmp = readnfc(&host->ip_regs->config2); - - if (on) - tmp |= NFC_V3_CONFIG2_ECC_EN; - else - tmp &= ~NFC_V3_CONFIG2_ECC_EN; - writenfc(tmp, &host->ip_regs->config2); -#endif -} - -#ifdef CONFIG_MXC_NAND_HWECC -static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) -{ - /* - * If HW ECC is enabled, we turn it on during init. There is - * no need to enable again here. - */ -} - -#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) -static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - int page) -{ - struct mxc_nand_host *host = nand_get_controller_data(chip); - uint8_t *buf = chip->oob_poi; - int length = mtd->oobsize; - int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; - uint8_t *bufpoi = buf; - int i, toread; - - pr_debug("%s: Reading OOB area of page %u to oob %p\n", - __func__, page, buf); - - chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); - for (i = 0; i < chip->ecc.steps; i++) { - toread = min_t(int, length, chip->ecc.prepad); - if (toread) { - chip->read_buf(mtd, bufpoi, toread); - bufpoi += toread; - length -= toread; - } - bufpoi += chip->ecc.bytes; - host->col_addr += chip->ecc.bytes; - length -= chip->ecc.bytes; - - toread = min_t(int, length, chip->ecc.postpad); - if (toread) { - chip->read_buf(mtd, bufpoi, toread); - bufpoi += toread; - length -= toread; - } - } - if (length > 0) - chip->read_buf(mtd, bufpoi, length); - - _mxc_nand_enable_hwecc(mtd, 0); - chip->cmdfunc(mtd, NAND_CMD_READOOB, - mtd->writesize + chip->ecc.prepad, page); - bufpoi = buf + chip->ecc.prepad; - length = mtd->oobsize - chip->ecc.prepad; - for (i = 0; i < chip->ecc.steps; i++) { - toread = min_t(int, length, chip->ecc.bytes); - chip->read_buf(mtd, bufpoi, toread); - bufpoi += eccpitch; - length -= eccpitch; - host->col_addr += chip->ecc.postpad + chip->ecc.prepad; - } - _mxc_nand_enable_hwecc(mtd, 1); - return 1; -} - -static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, - int oob_required, - int page) -{ - struct mxc_nand_host *host = nand_get_controller_data(chip); - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; - uint8_t *oob = chip->oob_poi; - int steps, size; - int n; - - _mxc_nand_enable_hwecc(mtd, 0); - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - - for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { - host->col_addr = n * eccsize; - chip->read_buf(mtd, buf, eccsize); - buf += eccsize; - - host->col_addr = mtd->writesize + n * eccpitch; - if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->read_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->read_buf(mtd, oob, size); - _mxc_nand_enable_hwecc(mtd, 1); - - return 0; -} - -static int mxc_nand_read_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, - int oob_required, - int page) -{ - struct mxc_nand_host *host = nand_get_controller_data(chip); - int n, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - - pr_debug("Reading page %u to buf %p oob %p\n", - page, buf, oob); - - /* first read the data area and the available portion of OOB */ - for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { - int stat; - - host->col_addr = n * eccsize; - - chip->read_buf(mtd, p, eccsize); - - host->col_addr = mtd->writesize + n * eccpitch; - - if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - stat = chip->ecc.correct(mtd, p, oob, NULL); - - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - /* Calculate remaining oob bytes */ - n = mtd->oobsize - (oob - chip->oob_poi); - if (n) - chip->read_buf(mtd, oob, n); - - /* Then switch ECC off and read the OOB area to get the ECC code */ - _mxc_nand_enable_hwecc(mtd, 0); - chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); - eccsteps = chip->ecc.steps; - oob = chip->oob_poi + chip->ecc.prepad; - for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { - host->col_addr = mtd->writesize + - n * eccpitch + - chip->ecc.prepad; - chip->read_buf(mtd, oob, eccbytes); - oob += eccbytes + chip->ecc.postpad; - } - _mxc_nand_enable_hwecc(mtd, 1); - return 0; -} - -static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, int page) -{ - struct mxc_nand_host *host = nand_get_controller_data(chip); - int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; - int length = mtd->oobsize; - int i, len, status, steps = chip->ecc.steps; - const uint8_t *bufpoi = chip->oob_poi; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - for (i = 0; i < steps; i++) { - len = min_t(int, length, eccpitch); - - chip->write_buf(mtd, bufpoi, len); - bufpoi += len; - length -= len; - host->col_addr += chip->ecc.prepad + chip->ecc.postpad; - } - if (length > 0) - chip->write_buf(mtd, bufpoi, length); - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - return status & NAND_STATUS_FAIL ? -EIO : 0; -} - -static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, - int oob_required, int page) -{ - struct mxc_nand_host *host = nand_get_controller_data(chip); - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; - uint8_t *oob = chip->oob_poi; - int steps, size; - int n; - - for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { - host->col_addr = n * eccsize; - chip->write_buf(mtd, buf, eccsize); - buf += eccsize; - - host->col_addr = mtd->writesize + n * eccpitch; - - if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - host->col_addr += eccbytes; - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->write_buf(mtd, oob, size); - return 0; -} - -static int mxc_nand_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, - int oob_required, int page) -{ - struct mxc_nand_host *host = nand_get_controller_data(chip); - int i, n, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; - int eccsteps = chip->ecc.steps; - const uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - - for (i = n = 0; - eccsteps; - n++, eccsteps--, i += eccbytes, p += eccsize) { - host->col_addr = n * eccsize; - - chip->write_buf(mtd, p, eccsize); - - host->col_addr = mtd->writesize + n * eccpitch; - - if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->write_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - /* Calculate remaining oob bytes */ - i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->write_buf(mtd, oob, i); - return 0; -} - -static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - uint32_t ecc_status = readl(&host->regs->ecc_status_result); - int subpages = mtd->writesize / nand_chip->subpagesize; - int pg2blk_shift = nand_chip->phys_erase_shift - - nand_chip->page_shift; - - do { - if ((ecc_status & 0xf) > 4) { - static int last_bad = -1; - - if (last_bad != host->page_addr >> pg2blk_shift) { - last_bad = host->page_addr >> pg2blk_shift; - printk(KERN_DEBUG - "MXC_NAND: HWECC uncorrectable ECC error" - " in block %u page %u subpage %d\n", - last_bad, host->page_addr, - mtd->writesize / nand_chip->subpagesize - - subpages); - } - return -EBADMSG; - } - ecc_status >>= 4; - subpages--; - } while (subpages > 0); - - return 0; -} -#else -#define mxc_nand_read_page_syndrome NULL -#define mxc_nand_read_page_raw_syndrome NULL -#define mxc_nand_read_oob_syndrome NULL -#define mxc_nand_write_page_syndrome NULL -#define mxc_nand_write_page_raw_syndrome NULL -#define mxc_nand_write_oob_syndrome NULL - -static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - - /* - * 1-Bit errors are automatically corrected in HW. No need for - * additional correction. 2-Bit errors cannot be corrected by - * HW ECC, so we need to return failure - */ - uint16_t ecc_status = readnfc(&host->regs->ecc_status_result); - - if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { - pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); - return -EBADMSG; - } - - return 0; -} -#endif - -static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - return 0; -} -#endif - -static u_char mxc_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - uint8_t ret = 0; - uint16_t col; - uint16_t __iomem *main_buf = - (uint16_t __iomem *)host->regs->main_area[0]; - uint16_t __iomem *spare_buf = - (uint16_t __iomem *)host->regs->spare_area[0]; - union { - uint16_t word; - uint8_t bytes[2]; - } nfc_word; - - /* Check for status request */ - if (host->status_request) - return get_dev_status(host) & 0xFF; - - /* Get column for 16-bit access */ - col = host->col_addr >> 1; - - /* If we are accessing the spare region */ - if (host->spare_only) - nfc_word.word = readw(&spare_buf[col]); - else - nfc_word.word = readw(&main_buf[col]); - - /* Pick upper/lower byte of word from RAM buffer */ - ret = nfc_word.bytes[host->col_addr & 0x1]; - - /* Update saved column address */ - if (nand_chip->options & NAND_BUSWIDTH_16) - host->col_addr += 2; - else - host->col_addr++; - - 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 col, ret; - uint16_t __iomem *p; - - pr_debug("mxc_nand_read_word(col = %d)\n", host->col_addr); - - col = host->col_addr; - /* Adjust saved column address */ - if (col < mtd->writesize && host->spare_only) - col += mtd->writesize; - - if (col < mtd->writesize) { - p = (uint16_t __iomem *)(host->regs->main_area[0] + - (col >> 1)); - } else { - p = (uint16_t __iomem *)(host->regs->spare_area[0] + - ((col - mtd->writesize) >> 1)); - } - - if (col & 1) { - union { - uint16_t word; - uint8_t bytes[2]; - } nfc_word[3]; - - nfc_word[0].word = readw(p); - nfc_word[1].word = readw(p + 1); - - nfc_word[2].bytes[0] = nfc_word[0].bytes[1]; - nfc_word[2].bytes[1] = nfc_word[1].bytes[0]; - - ret = nfc_word[2].word; - } else { - ret = readw(p); - } - - /* Update saved column address */ - host->col_addr = col + 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) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - int n, col, i = 0; - - pr_debug("mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr, - len); - - col = host->col_addr; - - /* Adjust saved column address */ - if (col < mtd->writesize && host->spare_only) - col += mtd->writesize; - - n = mtd->writesize + mtd->oobsize - col; - n = min(len, n); - - pr_debug("%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n); - - while (n > 0) { - void __iomem *p; - - if (col < mtd->writesize) { - p = host->regs->main_area[0] + (col & ~3); - } else { - p = host->regs->spare_area[0] - - mtd->writesize + (col & ~3); - } - - pr_debug("%s:%d: p = %p\n", __func__, - __LINE__, p); - - if (((col | (unsigned long)&buf[i]) & 3) || n < 4) { - union { - uint32_t word; - uint8_t bytes[4]; - } nfc_word; - - nfc_word.word = readl(p); - nfc_word.bytes[col & 3] = buf[i++]; - n--; - col++; - - writel(nfc_word.word, p); - } else { - int m = mtd->writesize - col; - - if (col >= mtd->writesize) - m += mtd->oobsize; - - m = min(n, m) & ~3; - - pr_debug("%s:%d: n = %d, m = %d, i = %d, col = %d\n", - __func__, __LINE__, n, m, i, col); - - mxc_nand_memcpy32(p, (uint32_t *)&buf[i], m); - col += m; - i += m; - n -= m; - } - } - /* Update saved column address */ - host->col_addr = col; -} - -/* - * Read the data buffer from the NAND Flash. To read the data from NAND - * 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) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - int n, col, i = 0; - - pr_debug("mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, - len); - - col = host->col_addr; - - /* Adjust saved column address */ - if (col < mtd->writesize && host->spare_only) - col += mtd->writesize; - - n = mtd->writesize + mtd->oobsize - col; - n = min(len, n); - - while (n > 0) { - void __iomem *p; - - if (col < mtd->writesize) { - p = host->regs->main_area[0] + (col & ~3); - } else { - p = host->regs->spare_area[0] - - mtd->writesize + (col & ~3); - } - - if (((col | (int)&buf[i]) & 3) || n < 4) { - union { - uint32_t word; - uint8_t bytes[4]; - } nfc_word; - - nfc_word.word = readl(p); - buf[i++] = nfc_word.bytes[col & 3]; - n--; - col++; - } else { - int m = mtd->writesize - col; - - if (col >= mtd->writesize) - m += mtd->oobsize; - - m = min(n, m) & ~3; - mxc_nand_memcpy32((uint32_t *)&buf[i], p, m); - - col += m; - i += m; - n -= m; - } - } - /* Update saved column address */ - host->col_addr = col; -} - -/* - * This function is used by upper layer for select and - * deselect of the NAND chip - */ -static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - - switch (chip) { - case -1: - /* TODO: Disable the NFC clock */ - if (host->clk_act) - host->clk_act = 0; - break; - case 0: - /* TODO: Enable the NFC clock */ - if (!host->clk_act) - host->clk_act = 1; - break; - - default: - break; - } -} - -/* - * Used by the upper layer to write command to NAND Flash for - * different operations to be carried out on NAND Flash - */ -void mxc_nand_command(struct mtd_info *mtd, unsigned command, - int column, int page_addr) -{ - struct nand_chip *nand_chip = mtd_to_nand(mtd); - struct mxc_nand_host *host = nand_get_controller_data(nand_chip); - - pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", - command, column, page_addr); - - /* Reset command state information */ - host->status_request = false; - - /* Command pre-processing step */ - switch (command) { - - case NAND_CMD_STATUS: - host->col_addr = 0; - host->status_request = true; - break; - - case NAND_CMD_READ0: - host->page_addr = page_addr; - host->col_addr = column; - host->spare_only = false; - break; - - case NAND_CMD_READOOB: - host->col_addr = column; - host->spare_only = true; - if (host->pagesize_2k) - command = NAND_CMD_READ0; /* only READ0 is valid */ - break; - - case NAND_CMD_SEQIN: - if (column >= mtd->writesize) { - /* - * before sending SEQIN command for partial write, - * we need read one page out. FSL NFC does not support - * partial write. It always sends out 512+ecc+512+ecc - * for large page nand flash. But for small page nand - * flash, it does support SPARE ONLY operation. - */ - if (host->pagesize_2k) { - /* call ourself to read a page */ - mxc_nand_command(mtd, NAND_CMD_READ0, 0, - page_addr); - } - - host->col_addr = column - mtd->writesize; - host->spare_only = true; - - /* Set program pointer to spare region */ - if (!host->pagesize_2k) - send_cmd(host, NAND_CMD_READOOB); - } else { - host->spare_only = false; - host->col_addr = column; - - /* Set program pointer to page start */ - if (!host->pagesize_2k) - send_cmd(host, NAND_CMD_READ0); - } - break; - - case NAND_CMD_PAGEPROG: - send_prog_page(host, 0, host->spare_only); - - if (host->pagesize_2k && is_mxc_nfc_1()) { - /* data in 4 areas */ - send_prog_page(host, 1, host->spare_only); - send_prog_page(host, 2, host->spare_only); - send_prog_page(host, 3, host->spare_only); - } - - break; - } - - /* Write out the command to the device. */ - send_cmd(host, command); - - /* Write out column address, if necessary */ - if (column != -1) { - /* - * MXC NANDFC can only perform full page+spare or - * spare-only read/write. When the upper layers perform - * a read/write buffer operation, we will use the saved - * column address to index into the full page. - */ - send_addr(host, 0); - if (host->pagesize_2k) - /* another col addr cycle for 2k page */ - send_addr(host, 0); - } - - /* Write out page address, if necessary */ - if (page_addr != -1) { - u32 page_mask = nand_chip->pagemask; - do { - send_addr(host, page_addr & 0xFF); - page_addr >>= 8; - page_mask >>= 8; - } while (page_mask); - } - - /* Command post-processing step */ - switch (command) { - - case NAND_CMD_RESET: - break; - - case NAND_CMD_READOOB: - case NAND_CMD_READ0: - if (host->pagesize_2k) { - /* send read confirm command */ - send_cmd(host, NAND_CMD_READSTART); - /* read for each AREA */ - send_read_page(host, 0, host->spare_only); - if (is_mxc_nfc_1()) { - send_read_page(host, 1, host->spare_only); - send_read_page(host, 2, host->spare_only); - send_read_page(host, 3, host->spare_only); - } - } else { - send_read_page(host, 0, host->spare_only); - } - break; - - case NAND_CMD_READID: - host->col_addr = 0; - send_read_id(host); - break; - - case NAND_CMD_PAGEPROG: - break; - - case NAND_CMD_STATUS: - break; - - case NAND_CMD_ERASE2: - break; - } -} - -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - -static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; -static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 0, - .len = 4, - .veroffs = 4, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 0, - .len = 4, - .veroffs = 4, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - -#endif - -int board_nand_init(struct nand_chip *this) -{ - struct mtd_info *mtd; -#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) - uint32_t tmp; -#endif - -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - this->bbt_options |= NAND_BBT_USE_FLASH; - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; -#endif - - /* structures must be linked */ - mtd = &this->mtd; - host->nand = this; - - /* 5 us command delay time */ - this->chip_delay = 5; - - nand_set_controller_data(this, host); - this->dev_ready = mxc_nand_dev_ready; - this->cmdfunc = mxc_nand_command; - this->select_chip = mxc_nand_select_chip; - 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; - - host->regs = (struct mxc_nand_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE; -#ifdef MXC_NFC_V3_2 - host->ip_regs = - (struct mxc_nand_ip_regs __iomem *)CONFIG_MXC_NAND_IP_REGS_BASE; -#endif - host->clk_act = 1; - -#ifdef CONFIG_MXC_NAND_HWECC - this->ecc.calculate = mxc_nand_calculate_ecc; - this->ecc.hwctl = mxc_nand_enable_hwecc; - this->ecc.correct = mxc_nand_correct_data; - if (is_mxc_nfc_21() || is_mxc_nfc_32()) { - this->ecc.mode = NAND_ECC_HW_SYNDROME; - this->ecc.read_page = mxc_nand_read_page_syndrome; - this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome; - this->ecc.read_oob = mxc_nand_read_oob_syndrome; - this->ecc.write_page = mxc_nand_write_page_syndrome; - this->ecc.write_page_raw = mxc_nand_write_page_raw_syndrome; - this->ecc.write_oob = mxc_nand_write_oob_syndrome; - this->ecc.bytes = 9; - this->ecc.prepad = 7; - } else { - this->ecc.mode = NAND_ECC_HW; - } - - if (is_mxc_nfc_1()) - this->ecc.strength = 1; - else - this->ecc.strength = 4; - - host->pagesize_2k = 0; - - this->ecc.size = 512; - _mxc_nand_enable_hwecc(mtd, 1); -#else - this->ecc.layout = &nand_soft_eccoob; - this->ecc.mode = NAND_ECC_SOFT; - _mxc_nand_enable_hwecc(mtd, 0); -#endif - /* Reset NAND */ - this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* NAND bus width determines access functions used by upper layer */ - if (is_16bit_nand()) - this->options |= NAND_BUSWIDTH_16; - -#ifdef CONFIG_SYS_NAND_LARGEPAGE - host->pagesize_2k = 1; - this->ecc.layout = &nand_hw_eccoob2k; -#else - host->pagesize_2k = 0; - this->ecc.layout = &nand_hw_eccoob; -#endif - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) -#ifdef MXC_NFC_V2_1 - tmp = readnfc(&host->regs->config1); - tmp |= NFC_V2_CONFIG1_ONE_CYCLE; - tmp |= NFC_V2_CONFIG1_ECC_MODE_4; - writenfc(tmp, &host->regs->config1); - if (host->pagesize_2k) - writenfc(64/2, &host->regs->spare_area_size); - else - writenfc(16/2, &host->regs->spare_area_size); -#endif - - /* - * preset operation - * Unlock the internal RAM Buffer - */ - writenfc(0x2, &host->regs->config); - - /* Blocks to be unlocked */ - writenfc(0x0, &host->regs->unlockstart_blkaddr); - /* Originally (Freescale LTIB 2.6.21) 0x4000 was written to the - * unlockend_blkaddr, but the magic 0x4000 does not always work - * when writing more than some 32 megabytes (on 2k page nands) - * However 0xFFFF doesn't seem to have this kind - * of limitation (tried it back and forth several times). - * The linux kernel driver sets this to 0xFFFF for the v2 controller - * only, but probably this was not tested there for v1. - * The very same limitation seems to apply to this kernel driver. - * This might be NAND chip specific and the i.MX31 datasheet is - * extremely vague about the semantics of this register. - */ - writenfc(0xFFFF, &host->regs->unlockend_blkaddr); - - /* Unlock Block Command for given address range */ - writenfc(0x4, &host->regs->wrprot); -#elif defined(MXC_NFC_V3_2) - writenfc(NFC_V3_CONFIG1_RBA(0), &host->regs->config1); - writenfc(NFC_V3_IPC_CREQ, &host->ip_regs->ipc); - - /* Unlock the internal RAM Buffer */ - writenfc(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK, - &host->ip_regs->wrprot); - - /* Blocks to be unlocked */ - for (tmp = 0; tmp < CONFIG_SYS_NAND_MAX_CHIPS; tmp++) - writenfc(0x0 | 0xFFFF << 16, - &host->ip_regs->wrprot_unlock_blkaddr[tmp]); - - writenfc(0, &host->ip_regs->ipc); - - tmp = readnfc(&host->ip_regs->config2); - tmp &= ~(NFC_V3_CONFIG2_SPAS_MASK | NFC_V3_CONFIG2_EDC_MASK | - NFC_V3_CONFIG2_ECC_MODE_8 | NFC_V3_CONFIG2_PS_MASK); - tmp |= NFC_V3_CONFIG2_ONE_CYCLE; - - if (host->pagesize_2k) { - tmp |= NFC_V3_CONFIG2_SPAS(64/2); - tmp |= NFC_V3_CONFIG2_PS_2048; - } else { - tmp |= NFC_V3_CONFIG2_SPAS(16/2); - tmp |= NFC_V3_CONFIG2_PS_512; - } - - writenfc(tmp, &host->ip_regs->config2); - - tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) | - NFC_V3_CONFIG3_NO_SDMA | - NFC_V3_CONFIG3_RBB_MODE | - NFC_V3_CONFIG3_SBB(6) | /* Reset default */ - NFC_V3_CONFIG3_ADD_OP(0); - - if (!(this->options & NAND_BUSWIDTH_16)) - tmp |= NFC_V3_CONFIG3_FW8; - - writenfc(tmp, &host->ip_regs->config3); - - writenfc(0, &host->ip_regs->delay_line); -#endif - - return 0; -} diff --git a/drivers/mtd/nand/mxc_nand.h b/drivers/mtd/nand/mxc_nand.h deleted file mode 100644 index 1c7f3a2e22..0000000000 --- a/drivers/mtd/nand/mxc_nand.h +++ /dev/null @@ -1,208 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * (c) 2009 Magnus Lilja - */ - -#ifndef __MXC_NAND_H -#define __MXC_NAND_H - -/* - * Register map and bit definitions for the Freescale NAND Flash Controller - * present in various i.MX devices. - * - * MX31 and MX27 have version 1, which has: - * 4 512-byte main buffers and - * 4 16-byte spare buffers - * to support up to 2K byte pagesize nand. - * Reading or writing a 2K page requires 4 FDI/FDO cycles. - * - * MX25 and MX35 have version 2.1, and MX51 and MX53 have version 3.2, which - * have: - * 8 512-byte main buffers and - * 8 64-byte spare buffers - * to support up to 4K byte pagesize nand. - * Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle. - * Also some of registers are moved and/or changed meaning as seen below. - */ -#if defined(CONFIG_MX27) || defined(CONFIG_MX31) -#define MXC_NFC_V1 -#define is_mxc_nfc_1() 1 -#define is_mxc_nfc_21() 0 -#define is_mxc_nfc_32() 0 -#elif defined(CONFIG_MX25) || defined(CONFIG_MX35) -#define MXC_NFC_V2_1 -#define is_mxc_nfc_1() 0 -#define is_mxc_nfc_21() 1 -#define is_mxc_nfc_32() 0 -#elif defined(CONFIG_MX51) || defined(CONFIG_MX53) -#define MXC_NFC_V3 -#define MXC_NFC_V3_2 -#define is_mxc_nfc_1() 0 -#define is_mxc_nfc_21() 0 -#define is_mxc_nfc_32() 1 -#else -#error "MXC NFC implementation not supported" -#endif -#define is_mxc_nfc_3() is_mxc_nfc_32() - -#if defined(MXC_NFC_V1) -#define NAND_MXC_NR_BUFS 4 -#define NAND_MXC_SPARE_BUF_SIZE 16 -#define NAND_MXC_REG_OFFSET 0xe00 -#define NAND_MXC_2K_MULTI_CYCLE -#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) -#define NAND_MXC_NR_BUFS 8 -#define NAND_MXC_SPARE_BUF_SIZE 64 -#define NAND_MXC_REG_OFFSET 0x1e00 -#endif - -struct mxc_nand_regs { - u8 main_area[NAND_MXC_NR_BUFS][0x200]; - u8 spare_area[NAND_MXC_NR_BUFS][NAND_MXC_SPARE_BUF_SIZE]; - /* - * reserved size is offset of nfc registers - * minus total main and spare sizes - */ - u8 reserved1[NAND_MXC_REG_OFFSET - - NAND_MXC_NR_BUFS * (512 + NAND_MXC_SPARE_BUF_SIZE)]; -#if defined(MXC_NFC_V1) - u16 buf_size; - u16 reserved2; - u16 buf_addr; - u16 flash_addr; - u16 flash_cmd; - u16 config; - u16 ecc_status_result; - u16 rsltmain_area; - u16 rsltspare_area; - u16 wrprot; - u16 unlockstart_blkaddr; - u16 unlockend_blkaddr; - u16 nf_wrprst; - u16 config1; - u16 config2; -#elif defined(MXC_NFC_V2_1) - u16 reserved2[2]; - u16 buf_addr; - u16 flash_addr; - u16 flash_cmd; - u16 config; - u32 ecc_status_result; - u16 spare_area_size; - u16 wrprot; - u16 reserved3[2]; - u16 nf_wrprst; - u16 config1; - u16 config2; - u16 reserved4; - u16 unlockstart_blkaddr; - u16 unlockend_blkaddr; - u16 unlockstart_blkaddr1; - u16 unlockend_blkaddr1; - u16 unlockstart_blkaddr2; - u16 unlockend_blkaddr2; - u16 unlockstart_blkaddr3; - u16 unlockend_blkaddr3; -#elif defined(MXC_NFC_V3_2) - u32 flash_cmd; - u32 flash_addr[12]; - u32 config1; - u32 ecc_status_result; - u32 status_sum; - u32 launch; -#endif -}; - -#ifdef MXC_NFC_V3_2 -struct mxc_nand_ip_regs { - u32 wrprot; - u32 wrprot_unlock_blkaddr[8]; - u32 config2; - u32 config3; - u32 ipc; - u32 err_addr; - u32 delay_line; -}; -#endif - -/* Set FCMD to 1, rest to 0 for Command operation */ -#define NFC_CMD 0x1 - -/* Set FADD to 1, rest to 0 for Address operation */ -#define NFC_ADDR 0x2 - -/* Set FDI to 1, rest to 0 for Input operation */ -#define NFC_INPUT 0x4 - -/* Set FDO to 001, rest to 0 for Data Output operation */ -#define NFC_OUTPUT 0x8 - -/* Set FDO to 010, rest to 0 for Read ID operation */ -#define NFC_ID 0x10 - -/* Set FDO to 100, rest to 0 for Read Status operation */ -#define NFC_STATUS 0x20 - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) -#define NFC_CONFIG1_SP_EN (1 << 2) -#define NFC_CONFIG1_RST (1 << 6) -#define NFC_CONFIG1_CE (1 << 7) -#elif defined(MXC_NFC_V3_2) -#define NFC_CONFIG1_SP_EN (1 << 0) -#define NFC_CONFIG1_CE (1 << 1) -#define NFC_CONFIG1_RST (1 << 2) -#endif -#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3) -#define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4) -#define NFC_V1_V2_CONFIG1_BIG (1 << 5) -#define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0) -#define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8) -#define NFC_V2_CONFIG1_FP_INT (1 << 11) -#define NFC_V3_CONFIG1_RBA_MASK (0x7 << 4) -#define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7) << 4) - -#define NFC_V1_V2_CONFIG2_INT (1 << 15) -#define NFC_V3_CONFIG2_PS_MASK (0x3 << 0) -#define NFC_V3_CONFIG2_PS_512 (0 << 0) -#define NFC_V3_CONFIG2_PS_2048 (1 << 0) -#define NFC_V3_CONFIG2_PS_4096 (2 << 0) -#define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2) -#define NFC_V3_CONFIG2_ECC_EN (1 << 3) -#define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4) -#define NFC_V3_CONFIG2_NUM_ADDR_PH0 (1 << 5) -#define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6) -#define NFC_V3_CONFIG2_PPB_MASK (0x3 << 7) -#define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7) -#define NFC_V3_CONFIG2_EDC_MASK (0x7 << 9) -#define NFC_V3_CONFIG2_EDC(x) (((x) & 0x7) << 9) -#define NFC_V3_CONFIG2_NUM_ADDR_PH1(x) (((x) & 0x3) << 12) -#define NFC_V3_CONFIG2_INT_MSK (1 << 15) -#define NFC_V3_CONFIG2_SPAS_MASK (0xff << 16) -#define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16) -#define NFC_V3_CONFIG2_ST_CMD_MASK (0xff << 24) -#define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24) - -#define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0) -#define NFC_V3_CONFIG3_FW8 (1 << 3) -#define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8) -#define NFC_V3_CONFIG3_NUM_OF_DEVS(x) (((x) & 0x7) << 12) -#define NFC_V3_CONFIG3_RBB_MODE (1 << 15) -#define NFC_V3_CONFIG3_NO_SDMA (1 << 20) - -#define NFC_V3_WRPROT_UNLOCK (1 << 2) -#define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6) - -#define NFC_V3_IPC_CREQ (1 << 0) -#define NFC_V3_IPC_INT (1 << 31) - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) -#define operation config2 -#define readnfc readw -#define writenfc writew -#elif defined(MXC_NFC_V3_2) -#define operation launch -#define readnfc readl -#define writenfc writel -#endif - -#endif /* __MXC_NAND_H */ diff --git a/drivers/mtd/nand/mxc_nand_spl.c b/drivers/mtd/nand/mxc_nand_spl.c deleted file mode 100644 index 6c03db8428..0000000000 --- a/drivers/mtd/nand/mxc_nand_spl.c +++ /dev/null @@ -1,350 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2009 - * Magnus Lilja - * - * (C) Copyright 2008 - * Maxim Artamonov, - * - * (C) Copyright 2006-2008 - * Stefan Roese, DENX Software Engineering, sr at denx.de. - */ - -#include -#include -#include -#include -#include "mxc_nand.h" - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) -static struct mxc_nand_regs *const nfc = (void *)NFC_BASE_ADDR; -#elif defined(MXC_NFC_V3_2) -static struct mxc_nand_regs *const nfc = (void *)NFC_BASE_ADDR_AXI; -static struct mxc_nand_ip_regs *const nfc_ip = (void *)NFC_BASE_ADDR; -#endif - -static void nfc_wait_ready(void) -{ - uint32_t tmp; - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - while (!(readnfc(&nfc->config2) & NFC_V1_V2_CONFIG2_INT)) - ; - - /* Reset interrupt flag */ - tmp = readnfc(&nfc->config2); - tmp &= ~NFC_V1_V2_CONFIG2_INT; - writenfc(tmp, &nfc->config2); -#elif defined(MXC_NFC_V3_2) - while (!(readnfc(&nfc_ip->ipc) & NFC_V3_IPC_INT)) - ; - - /* Reset interrupt flag */ - tmp = readnfc(&nfc_ip->ipc); - tmp &= ~NFC_V3_IPC_INT; - writenfc(tmp, &nfc_ip->ipc); -#endif -} - -static void nfc_nand_init(void) -{ -#if defined(MXC_NFC_V3_2) - int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; - int tmp; - - tmp = (readnfc(&nfc_ip->config2) & ~(NFC_V3_CONFIG2_SPAS_MASK | - NFC_V3_CONFIG2_EDC_MASK | NFC_V3_CONFIG2_PS_MASK)) | - NFC_V3_CONFIG2_SPAS(CONFIG_SYS_NAND_OOBSIZE / 2) | - NFC_V3_CONFIG2_INT_MSK | NFC_V3_CONFIG2_ECC_EN | - NFC_V3_CONFIG2_ONE_CYCLE; - if (CONFIG_SYS_NAND_PAGE_SIZE == 4096) - tmp |= NFC_V3_CONFIG2_PS_4096; - else if (CONFIG_SYS_NAND_PAGE_SIZE == 2048) - tmp |= NFC_V3_CONFIG2_PS_2048; - else if (CONFIG_SYS_NAND_PAGE_SIZE == 512) - tmp |= NFC_V3_CONFIG2_PS_512; - /* - * if spare size is larger that 16 bytes per 512 byte hunk - * then use 8 symbol correction instead of 4 - */ - if (CONFIG_SYS_NAND_OOBSIZE / ecc_per_page > 16) - tmp |= NFC_V3_CONFIG2_ECC_MODE_8; - else - tmp &= ~NFC_V3_CONFIG2_ECC_MODE_8; - writenfc(tmp, &nfc_ip->config2); - - tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) | - NFC_V3_CONFIG3_NO_SDMA | - NFC_V3_CONFIG3_RBB_MODE | - NFC_V3_CONFIG3_SBB(6) | /* Reset default */ - NFC_V3_CONFIG3_ADD_OP(0); -#ifndef CONFIG_SYS_NAND_BUSWIDTH_16 - tmp |= NFC_V3_CONFIG3_FW8; -#endif - writenfc(tmp, &nfc_ip->config3); - - writenfc(0, &nfc_ip->delay_line); -#elif defined(MXC_NFC_V2_1) - int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; - int config1; - - writenfc(CONFIG_SYS_NAND_OOBSIZE / 2, &nfc->spare_area_size); - - /* unlocking RAM Buff */ - writenfc(0x2, &nfc->config); - - /* hardware ECC checking and correct */ - config1 = readnfc(&nfc->config1) | NFC_V1_V2_CONFIG1_ECC_EN | - NFC_V1_V2_CONFIG1_INT_MSK | NFC_V2_CONFIG1_ONE_CYCLE | - NFC_V2_CONFIG1_FP_INT; - /* - * if spare size is larger that 16 bytes per 512 byte hunk - * then use 8 symbol correction instead of 4 - */ - if (CONFIG_SYS_NAND_OOBSIZE / ecc_per_page > 16) - config1 &= ~NFC_V2_CONFIG1_ECC_MODE_4; - else - config1 |= NFC_V2_CONFIG1_ECC_MODE_4; - writenfc(config1, &nfc->config1); -#elif defined(MXC_NFC_V1) - /* unlocking RAM Buff */ - writenfc(0x2, &nfc->config); - - /* hardware ECC checking and correct */ - writenfc(NFC_V1_V2_CONFIG1_ECC_EN | NFC_V1_V2_CONFIG1_INT_MSK, - &nfc->config1); -#endif -} - -static void nfc_nand_command(unsigned short command) -{ - writenfc(command, &nfc->flash_cmd); - writenfc(NFC_CMD, &nfc->operation); - nfc_wait_ready(); -} - -static void nfc_nand_address(unsigned short address) -{ - writenfc(address, &nfc->flash_addr); - writenfc(NFC_ADDR, &nfc->operation); - nfc_wait_ready(); -} - -static void nfc_nand_page_address(unsigned int page_address) -{ - unsigned int page_count; - - nfc_nand_address(0x00); - - /* code only for large page flash */ - if (CONFIG_SYS_NAND_PAGE_SIZE > 512) - nfc_nand_address(0x00); - - page_count = CONFIG_SYS_NAND_SIZE / CONFIG_SYS_NAND_PAGE_SIZE; - - if (page_address <= page_count) { - page_count--; /* transform 0x01000000 to 0x00ffffff */ - do { - nfc_nand_address(page_address & 0xff); - page_address = page_address >> 8; - page_count = page_count >> 8; - } while (page_count); - } - - nfc_nand_address(0x00); -} - -static void nfc_nand_data_output(void) -{ -#ifdef NAND_MXC_2K_MULTI_CYCLE - int i; -#endif - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - writenfc(0, &nfc->buf_addr); -#elif defined(MXC_NFC_V3_2) - int config1 = readnfc(&nfc->config1); - config1 &= ~NFC_V3_CONFIG1_RBA_MASK; - writenfc(config1, &nfc->config1); -#endif - writenfc(NFC_OUTPUT, &nfc->operation); - nfc_wait_ready(); -#ifdef NAND_MXC_2K_MULTI_CYCLE - /* - * This NAND controller requires multiple input commands - * for pages larger than 512 bytes. - */ - for (i = 1; i < CONFIG_SYS_NAND_PAGE_SIZE / 512; i++) { - writenfc(i, &nfc->buf_addr); - writenfc(NFC_OUTPUT, &nfc->operation); - nfc_wait_ready(); - } -#endif -} - -static int nfc_nand_check_ecc(void) -{ -#if defined(MXC_NFC_V1) - u16 ecc_status = readw(&nfc->ecc_status_result); - return (ecc_status & 0x3) == 2 || (ecc_status >> 2) == 2; -#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) - u32 ecc_status = readl(&nfc->ecc_status_result); - int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; - int err_limit = CONFIG_SYS_NAND_OOBSIZE / ecc_per_page > 16 ? 8 : 4; - int subpages = CONFIG_SYS_NAND_PAGE_SIZE / 512; - - do { - if ((ecc_status & 0xf) > err_limit) - return 1; - ecc_status >>= 4; - } while (--subpages); - - return 0; -#endif -} - -static void nfc_nand_read_page(unsigned int page_address) -{ - /* read in first 0 buffer */ -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - writenfc(0, &nfc->buf_addr); -#elif defined(MXC_NFC_V3_2) - int config1 = readnfc(&nfc->config1); - config1 &= ~NFC_V3_CONFIG1_RBA_MASK; - writenfc(config1, &nfc->config1); -#endif - nfc_nand_command(NAND_CMD_READ0); - nfc_nand_page_address(page_address); - - if (CONFIG_SYS_NAND_PAGE_SIZE > 512) - nfc_nand_command(NAND_CMD_READSTART); - - nfc_nand_data_output(); /* fill the main buffer 0 */ -} - -static int nfc_read_page(unsigned int page_address, unsigned char *buf) -{ - int i; - u32 *src; - u32 *dst; - - nfc_nand_read_page(page_address); - - if (nfc_nand_check_ecc()) - return -EBADMSG; - - src = (u32 *)&nfc->main_area[0][0]; - dst = (u32 *)buf; - - /* main copy loop from NAND-buffer to SDRAM memory */ - for (i = 0; i < CONFIG_SYS_NAND_PAGE_SIZE / 4; i++) { - writel(readl(src), dst); - src++; - dst++; - } - - return 0; -} - -static int is_badblock(int pagenumber) -{ - int page = pagenumber; - u32 badblock; - u32 *src; - - /* Check the first two pages for bad block markers */ - for (page = pagenumber; page < pagenumber + 2; page++) { - nfc_nand_read_page(page); - - src = (u32 *)&nfc->spare_area[0][0]; - - /* - * IMPORTANT NOTE: The nand flash controller uses a non- - * standard layout for large page devices. This can - * affect the position of the bad block marker. - */ - /* Get the bad block marker */ - badblock = readl(&src[CONFIG_SYS_NAND_BAD_BLOCK_POS / 4]); - badblock >>= 8 * (CONFIG_SYS_NAND_BAD_BLOCK_POS % 4); - badblock &= 0xff; - - /* bad block marker verify */ - if (badblock != 0xff) - return 1; /* potential bad block */ - } - - return 0; -} - -int nand_spl_load_image(uint32_t from, unsigned int size, void *buf) -{ - int i; - unsigned int page; - unsigned int maxpages = CONFIG_SYS_NAND_SIZE / - CONFIG_SYS_NAND_PAGE_SIZE; - - nfc_nand_init(); - - /* Convert to page number */ - page = from / CONFIG_SYS_NAND_PAGE_SIZE; - i = 0; - - size = roundup(size, CONFIG_SYS_NAND_PAGE_SIZE); - while (i < size / CONFIG_SYS_NAND_PAGE_SIZE) { - if (nfc_read_page(page, buf) < 0) - return -1; - - page++; - i++; - buf = buf + CONFIG_SYS_NAND_PAGE_SIZE; - - /* - * Check if we have crossed a block boundary, and if so - * check for bad block. - */ - if (!(page % CONFIG_SYS_NAND_PAGE_COUNT)) { - /* - * Yes, new block. See if this block is good. If not, - * loop until we find a good block. - */ - while (is_badblock(page)) { - page = page + CONFIG_SYS_NAND_PAGE_COUNT; - /* Check i we've reached the end of flash. */ - if (page >= maxpages) - return -1; - } - } - } - - return 0; -} - -#ifndef CONFIG_SPL_FRAMEWORK -/* - * The main entry for NAND booting. It's necessary that SDRAM is already - * configured and available since this code loads the main U-Boot image - * from NAND into SDRAM and starts it from there. - */ -void nand_boot(void) -{ - __attribute__((noreturn)) void (*uboot)(void); - - /* - * CONFIG_SYS_NAND_U_BOOT_OFFS and CONFIG_SYS_NAND_U_BOOT_SIZE must - * be aligned to full pages - */ - if (!nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, - CONFIG_SYS_NAND_U_BOOT_SIZE, - (uchar *)CONFIG_SYS_NAND_U_BOOT_DST)) { - /* Copy from NAND successful, start U-Boot */ - uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; - uboot(); - } else { - /* Unrecoverable error when copying from NAND */ - hang(); - } -} -#endif - -void nand_init(void) {} -void nand_deselect(void) {} diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c deleted file mode 100644 index e3341812a2..0000000000 --- a/drivers/mtd/nand/mxs_nand.c +++ /dev/null @@ -1,1302 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Freescale i.MX28 NAND flash driver - * - * Copyright (C) 2011 Marek Vasut - * on behalf of DENX Software Engineering GmbH - * - * Based on code from LTIB: - * Freescale GPMI NFC NAND Flash Driver - * - * Copyright (C) 2010 Freescale Semiconductor, Inc. - * Copyright (C) 2008 Embedded Alley Solutions, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mxs_nand.h" - -#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4 - -#if (defined(CONFIG_MX6) || defined(CONFIG_MX7)) -#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 2 -#else -#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 0 -#endif -#define MXS_NAND_METADATA_SIZE 10 -#define MXS_NAND_BITS_PER_ECC_LEVEL 13 - -#if !defined(CONFIG_SYS_CACHELINE_SIZE) || CONFIG_SYS_CACHELINE_SIZE < 32 -#define MXS_NAND_COMMAND_BUFFER_SIZE 32 -#else -#define MXS_NAND_COMMAND_BUFFER_SIZE CONFIG_SYS_CACHELINE_SIZE -#endif - -#define MXS_NAND_BCH_TIMEOUT 10000 - -struct nand_ecclayout fake_ecc_layout; - -/* - * Cache management functions - */ -#ifndef CONFIG_SYS_DCACHE_OFF -static void mxs_nand_flush_data_buf(struct mxs_nand_info *info) -{ - uint32_t addr = (uint32_t)info->data_buf; - - flush_dcache_range(addr, addr + info->data_buf_size); -} - -static void mxs_nand_inval_data_buf(struct mxs_nand_info *info) -{ - uint32_t addr = (uint32_t)info->data_buf; - - invalidate_dcache_range(addr, addr + info->data_buf_size); -} - -static void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info) -{ - uint32_t addr = (uint32_t)info->cmd_buf; - - flush_dcache_range(addr, addr + MXS_NAND_COMMAND_BUFFER_SIZE); -} -#else -static inline void mxs_nand_flush_data_buf(struct mxs_nand_info *info) {} -static inline void mxs_nand_inval_data_buf(struct mxs_nand_info *info) {} -static inline void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info) {} -#endif - -static struct mxs_dma_desc *mxs_nand_get_dma_desc(struct mxs_nand_info *info) -{ - struct mxs_dma_desc *desc; - - if (info->desc_index >= MXS_NAND_DMA_DESCRIPTOR_COUNT) { - printf("MXS NAND: Too many DMA descriptors requested\n"); - return NULL; - } - - desc = info->desc[info->desc_index]; - info->desc_index++; - - return desc; -} - -static void mxs_nand_return_dma_descs(struct mxs_nand_info *info) -{ - int i; - struct mxs_dma_desc *desc; - - for (i = 0; i < info->desc_index; i++) { - desc = info->desc[i]; - memset(desc, 0, sizeof(struct mxs_dma_desc)); - desc->address = (dma_addr_t)desc; - } - - info->desc_index = 0; -} - -static uint32_t mxs_nand_aux_status_offset(void) -{ - return (MXS_NAND_METADATA_SIZE + 0x3) & ~0x3; -} - -static inline int mxs_nand_calc_mark_offset(struct bch_geometry *geo, - uint32_t page_data_size) -{ - uint32_t chunk_data_size_in_bits = geo->ecc_chunk_size * 8; - uint32_t chunk_ecc_size_in_bits = geo->ecc_strength * geo->gf_len; - uint32_t chunk_total_size_in_bits; - uint32_t block_mark_chunk_number; - uint32_t block_mark_chunk_bit_offset; - uint32_t block_mark_bit_offset; - - chunk_total_size_in_bits = - chunk_data_size_in_bits + chunk_ecc_size_in_bits; - - /* Compute the bit offset of the block mark within the physical page. */ - block_mark_bit_offset = page_data_size * 8; - - /* Subtract the metadata bits. */ - block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8; - - /* - * Compute the chunk number (starting at zero) in which the block mark - * appears. - */ - block_mark_chunk_number = - block_mark_bit_offset / chunk_total_size_in_bits; - - /* - * Compute the bit offset of the block mark within its chunk, and - * validate it. - */ - block_mark_chunk_bit_offset = block_mark_bit_offset - - (block_mark_chunk_number * chunk_total_size_in_bits); - - if (block_mark_chunk_bit_offset > chunk_data_size_in_bits) - return -EINVAL; - - /* - * Now that we know the chunk number in which the block mark appears, - * we can subtract all the ECC bits that appear before it. - */ - block_mark_bit_offset -= - block_mark_chunk_number * chunk_ecc_size_in_bits; - - geo->block_mark_byte_offset = block_mark_bit_offset >> 3; - geo->block_mark_bit_offset = block_mark_bit_offset & 0x7; - - return 0; -} - -static inline int mxs_nand_calc_ecc_layout_by_info(struct bch_geometry *geo, - struct mtd_info *mtd, - unsigned int ecc_strength, - unsigned int ecc_step) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(chip); - - switch (ecc_step) { - case SZ_512: - geo->gf_len = 13; - break; - case SZ_1K: - geo->gf_len = 14; - break; - default: - return -EINVAL; - } - - geo->ecc_chunk_size = ecc_step; - geo->ecc_strength = round_up(ecc_strength, 2); - - /* Keep the C >= O */ - if (geo->ecc_chunk_size < mtd->oobsize) - return -EINVAL; - - if (geo->ecc_strength > nand_info->max_ecc_strength_supported) - return -EINVAL; - - geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size; - - return 0; -} - -static inline int mxs_nand_calc_ecc_layout(struct bch_geometry *geo, - struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(chip); - - /* The default for the length of Galois Field. */ - geo->gf_len = 13; - - /* The default for chunk size. */ - geo->ecc_chunk_size = 512; - - if (geo->ecc_chunk_size < mtd->oobsize) { - geo->gf_len = 14; - geo->ecc_chunk_size *= 2; - } - - if (mtd->oobsize > geo->ecc_chunk_size) { - printf("Not support the NAND chips whose oob size is larger then %d bytes!\n", - geo->ecc_chunk_size); - return -EINVAL; - } - - geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size; - - /* - * Determine the ECC layout with the formula: - * ECC bits per chunk = (total page spare data bits) / - * (bits per ECC level) / (chunks per page) - * where: - * total page spare data bits = - * (page oob size - meta data size) * (bits per byte) - */ - geo->ecc_strength = ((mtd->oobsize - MXS_NAND_METADATA_SIZE) * 8) - / (geo->gf_len * geo->ecc_chunk_count); - - geo->ecc_strength = min(round_down(geo->ecc_strength, 2), - nand_info->max_ecc_strength_supported); - - return 0; -} - -/* - * Wait for BCH complete IRQ and clear the IRQ - */ -static int mxs_nand_wait_for_bch_complete(struct mxs_nand_info *nand_info) -{ - int timeout = MXS_NAND_BCH_TIMEOUT; - int ret; - - ret = mxs_wait_mask_set(&nand_info->bch_regs->hw_bch_ctrl_reg, - BCH_CTRL_COMPLETE_IRQ, timeout); - - writel(BCH_CTRL_COMPLETE_IRQ, &nand_info->bch_regs->hw_bch_ctrl_clr); - - return ret; -} - -/* - * This is the function that we install in the cmd_ctrl function pointer of the - * owning struct nand_chip. The only functions in the reference implementation - * that use these functions pointers are cmdfunc and select_chip. - * - * In this driver, we implement our own select_chip, so this function will only - * be called by the reference implementation's cmdfunc. For this reason, we can - * ignore the chip enable bit and concentrate only on sending bytes to the NAND - * Flash. - */ -static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - int ret; - - /* - * If this condition is true, something is _VERY_ wrong in MTD - * subsystem! - */ - if (nand_info->cmd_queue_len == MXS_NAND_COMMAND_BUFFER_SIZE) { - printf("MXS NAND: Command queue too long\n"); - return; - } - - /* - * Every operation begins with a command byte and a series of zero or - * more address bytes. These are distinguished by either the Address - * Latch Enable (ALE) or Command Latch Enable (CLE) signals being - * asserted. When MTD is ready to execute the command, it will - * deasert both latch enables. - * - * Rather than run a separate DMA operation for every single byte, we - * queue them up and run a single DMA operation for the entire series - * of command and data bytes. - */ - if (ctrl & (NAND_ALE | NAND_CLE)) { - if (data != NAND_CMD_NONE) - nand_info->cmd_buf[nand_info->cmd_queue_len++] = data; - return; - } - - /* - * If control arrives here, MTD has deasserted both the ALE and CLE, - * which means it's ready to run an operation. Check if we have any - * bytes to send. - */ - if (nand_info->cmd_queue_len == 0) - return; - - /* Compile the DMA descriptor -- a descriptor that sends command. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_CHAIN | MXS_DMA_DESC_DEC_SEM | - MXS_DMA_DESC_WAIT4END | (3 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | - (nand_info->cmd_queue_len << MXS_DMA_DESC_BYTES_OFFSET); - - d->cmd.address = (dma_addr_t)nand_info->cmd_buf; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WRITE | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_CLE | - GPMI_CTRL0_ADDRESS_INCREMENT | - nand_info->cmd_queue_len; - - mxs_dma_desc_append(channel, d); - - /* Flush caches */ - mxs_nand_flush_cmd_buf(nand_info); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) - printf("MXS NAND: Error sending command\n"); - - mxs_nand_return_dma_descs(nand_info); - - /* Reset the command queue. */ - nand_info->cmd_queue_len = 0; -} - -/* - * Test if the NAND flash is ready. - */ -static int mxs_nand_device_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(chip); - uint32_t tmp; - - tmp = readl(&nand_info->gpmi_regs->hw_gpmi_stat); - tmp >>= (GPMI_STAT_READY_BUSY_OFFSET + nand_info->cur_chip); - - return tmp & 1; -} - -/* - * Select the NAND chip. - */ -static void mxs_nand_select_chip(struct mtd_info *mtd, int chip) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - - nand_info->cur_chip = chip; -} - -/* - * Handle block mark swapping. - * - * Note that, when this function is called, it doesn't know whether it's - * swapping the block mark, or swapping it *back* -- but it doesn't matter - * because the the operation is the same. - */ -static void mxs_nand_swap_block_mark(struct bch_geometry *geo, - uint8_t *data_buf, uint8_t *oob_buf) -{ - uint32_t bit_offset = geo->block_mark_bit_offset; - uint32_t buf_offset = geo->block_mark_byte_offset; - - uint32_t src; - uint32_t dst; - - /* - * Get the byte from the data area that overlays the block mark. Since - * the ECC engine applies its own view to the bits in the page, the - * physical block mark won't (in general) appear on a byte boundary in - * the data. - */ - src = data_buf[buf_offset] >> bit_offset; - src |= data_buf[buf_offset + 1] << (8 - bit_offset); - - dst = oob_buf[0]; - - oob_buf[0] = src; - - data_buf[buf_offset] &= ~(0xff << bit_offset); - data_buf[buf_offset + 1] &= 0xff << bit_offset; - - data_buf[buf_offset] |= dst << bit_offset; - data_buf[buf_offset + 1] |= dst >> (8 - bit_offset); -} - -/* - * Read data from NAND. - */ -static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - int ret; - - if (length > NAND_MAX_PAGESIZE) { - printf("MXS NAND: DMA buffer too big\n"); - return; - } - - if (!buf) { - printf("MXS NAND: DMA buffer is NULL\n"); - return; - } - - /* Compile the DMA descriptor - a descriptor that reads data. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_DMA_WRITE | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | - (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | - (length << MXS_DMA_DESC_BYTES_OFFSET); - - d->cmd.address = (dma_addr_t)nand_info->data_buf; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_READ | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA | - length; - - mxs_dma_desc_append(channel, d); - - /* - * A DMA descriptor that waits for the command to end and the chip to - * become ready. - * - * I think we actually should *not* be waiting for the chip to become - * ready because, after all, we don't care. I think the original code - * did that and no one has re-thought it yet. - */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_DEC_SEM | - MXS_DMA_DESC_WAIT4END | (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA; - - mxs_dma_desc_append(channel, d); - - /* Invalidate caches */ - mxs_nand_inval_data_buf(nand_info); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) { - printf("MXS NAND: DMA read error\n"); - goto rtn; - } - - /* Invalidate caches */ - mxs_nand_inval_data_buf(nand_info); - - memcpy(buf, nand_info->data_buf, length); - -rtn: - mxs_nand_return_dma_descs(nand_info); -} - -/* - * Write data to NAND. - */ -static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int length) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - int ret; - - if (length > NAND_MAX_PAGESIZE) { - printf("MXS NAND: DMA buffer too big\n"); - return; - } - - if (!buf) { - printf("MXS NAND: DMA buffer is NULL\n"); - return; - } - - memcpy(nand_info->data_buf, buf, length); - - /* Compile the DMA descriptor - a descriptor that writes data. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | - (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | - (length << MXS_DMA_DESC_BYTES_OFFSET); - - d->cmd.address = (dma_addr_t)nand_info->data_buf; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WRITE | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA | - length; - - mxs_dma_desc_append(channel, d); - - /* Flush caches */ - mxs_nand_flush_data_buf(nand_info); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) - printf("MXS NAND: DMA write error\n"); - - mxs_nand_return_dma_descs(nand_info); -} - -/* - * Read a single byte from NAND. - */ -static uint8_t mxs_nand_read_byte(struct mtd_info *mtd) -{ - uint8_t buf; - mxs_nand_read_buf(mtd, &buf, 1); - return buf; -} - -/* - * Read a page from NAND. - */ -static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int oob_required, - int page) -{ - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - struct bch_geometry *geo = &nand_info->bch_geometry; - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - uint32_t corrected = 0, failed = 0; - uint8_t *status; - int i, ret; - - /* Compile the DMA descriptor - wait for ready. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | - MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_WAIT4END | - (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA; - - mxs_dma_desc_append(channel, d); - - /* Compile the DMA descriptor - enable the BCH block and read. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | - MXS_DMA_DESC_WAIT4END | (6 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_READ | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA | - (mtd->writesize + mtd->oobsize); - d->cmd.pio_words[1] = 0; - d->cmd.pio_words[2] = - GPMI_ECCCTRL_ENABLE_ECC | - GPMI_ECCCTRL_ECC_CMD_DECODE | - GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE; - d->cmd.pio_words[3] = mtd->writesize + mtd->oobsize; - d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf; - d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf; - - mxs_dma_desc_append(channel, d); - - /* Compile the DMA descriptor - disable the BCH block. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | - MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_WAIT4END | - (3 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA | - (mtd->writesize + mtd->oobsize); - d->cmd.pio_words[1] = 0; - d->cmd.pio_words[2] = 0; - - mxs_dma_desc_append(channel, d); - - /* Compile the DMA descriptor - deassert the NAND lock and interrupt. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_DEC_SEM; - - d->cmd.address = 0; - - mxs_dma_desc_append(channel, d); - - /* Invalidate caches */ - mxs_nand_inval_data_buf(nand_info); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) { - printf("MXS NAND: DMA read error\n"); - goto rtn; - } - - ret = mxs_nand_wait_for_bch_complete(nand_info); - if (ret) { - printf("MXS NAND: BCH read timeout\n"); - goto rtn; - } - - /* Invalidate caches */ - mxs_nand_inval_data_buf(nand_info); - - /* Read DMA completed, now do the mark swapping. */ - mxs_nand_swap_block_mark(geo, nand_info->data_buf, nand_info->oob_buf); - - /* Loop over status bytes, accumulating ECC status. */ - status = nand_info->oob_buf + mxs_nand_aux_status_offset(); - for (i = 0; i < geo->ecc_chunk_count; i++) { - if (status[i] == 0x00) - continue; - - if (status[i] == 0xff) - continue; - - if (status[i] == 0xfe) { - failed++; - continue; - } - - corrected += status[i]; - } - - /* Propagate ECC status to the owning MTD. */ - mtd->ecc_stats.failed += failed; - mtd->ecc_stats.corrected += corrected; - - /* - * It's time to deliver the OOB bytes. See mxs_nand_ecc_read_oob() for - * details about our policy for delivering the OOB. - * - * We fill the caller's buffer with set bits, and then copy the block - * mark to the caller's buffer. Note that, if block mark swapping was - * necessary, it has already been done, so we can rely on the first - * byte of the auxiliary buffer to contain the block mark. - */ - memset(nand->oob_poi, 0xff, mtd->oobsize); - - nand->oob_poi[0] = nand_info->oob_buf[0]; - - memcpy(buf, nand_info->data_buf, mtd->writesize); - -rtn: - mxs_nand_return_dma_descs(nand_info); - - return ret; -} - -/* - * Write a page to NAND. - */ -static int mxs_nand_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *nand, const uint8_t *buf, - int oob_required, int page) -{ - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - struct bch_geometry *geo = &nand_info->bch_geometry; - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - int ret; - - memcpy(nand_info->data_buf, buf, mtd->writesize); - memcpy(nand_info->oob_buf, nand->oob_poi, mtd->oobsize); - - /* Handle block mark swapping. */ - mxs_nand_swap_block_mark(geo, nand_info->data_buf, nand_info->oob_buf); - - /* Compile the DMA descriptor - write data. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | - (6 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WRITE | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA; - d->cmd.pio_words[1] = 0; - d->cmd.pio_words[2] = - GPMI_ECCCTRL_ENABLE_ECC | - GPMI_ECCCTRL_ECC_CMD_ENCODE | - GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE; - d->cmd.pio_words[3] = (mtd->writesize + mtd->oobsize); - d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf; - d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf; - - mxs_dma_desc_append(channel, d); - - /* Flush caches */ - mxs_nand_flush_data_buf(nand_info); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) { - printf("MXS NAND: DMA write error\n"); - goto rtn; - } - - ret = mxs_nand_wait_for_bch_complete(nand_info); - if (ret) { - printf("MXS NAND: BCH write timeout\n"); - goto rtn; - } - -rtn: - mxs_nand_return_dma_descs(nand_info); - return 0; -} - -/* - * Read OOB from NAND. - * - * This function is a veneer that replaces the function originally installed by - * the NAND Flash MTD code. - */ -static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(chip); - int ret; - - if (ops->mode == MTD_OPS_RAW) - nand_info->raw_oob_mode = 1; - else - nand_info->raw_oob_mode = 0; - - ret = nand_info->hooked_read_oob(mtd, from, ops); - - nand_info->raw_oob_mode = 0; - - return ret; -} - -/* - * Write OOB to NAND. - * - * This function is a veneer that replaces the function originally installed by - * the NAND Flash MTD code. - */ -static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(chip); - int ret; - - if (ops->mode == MTD_OPS_RAW) - nand_info->raw_oob_mode = 1; - else - nand_info->raw_oob_mode = 0; - - ret = nand_info->hooked_write_oob(mtd, to, ops); - - nand_info->raw_oob_mode = 0; - - return ret; -} - -/* - * Mark a block bad in NAND. - * - * This function is a veneer that replaces the function originally installed by - * the NAND Flash MTD code. - */ -static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(chip); - int ret; - - nand_info->marking_block_bad = 1; - - ret = nand_info->hooked_block_markbad(mtd, ofs); - - nand_info->marking_block_bad = 0; - - return ret; -} - -/* - * There are several places in this driver where we have to handle the OOB and - * block marks. This is the function where things are the most complicated, so - * this is where we try to explain it all. All the other places refer back to - * here. - * - * These are the rules, in order of decreasing importance: - * - * 1) Nothing the caller does can be allowed to imperil the block mark, so all - * write operations take measures to protect it. - * - * 2) In read operations, the first byte of the OOB we return must reflect the - * true state of the block mark, no matter where that block mark appears in - * the physical page. - * - * 3) ECC-based read operations return an OOB full of set bits (since we never - * allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads - * return). - * - * 4) "Raw" read operations return a direct view of the physical bytes in the - * page, using the conventional definition of which bytes are data and which - * are OOB. This gives the caller a way to see the actual, physical bytes - * in the page, without the distortions applied by our ECC engine. - * - * What we do for this specific read operation depends on whether we're doing - * "raw" read, or an ECC-based read. - * - * It turns out that knowing whether we want an "ECC-based" or "raw" read is not - * easy. When reading a page, for example, the NAND Flash MTD code calls our - * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an - * 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). - * - * Since MTD assumes the OOB is not covered by ECC, there is no pair of - * ECC-based/raw functions for reading or or writing the OOB. The fact that the - * caller wants an ECC-based or raw view of the page is not propagated down to - * this driver. - * - * Since our OOB *is* covered by ECC, we need this information. So, we hook the - * ecc.read_oob and ecc.write_oob function pointers in the owning - * struct mtd_info with our own functions. These hook functions set the - * raw_oob_mode field so that, when control finally arrives here, we'll know - * what to do. - */ -static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page) -{ - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - - /* - * First, fill in the OOB buffer. If we're doing a raw read, we need to - * get the bytes from the physical page. If we're not doing a raw read, - * we need to fill the buffer with set bits. - */ - if (nand_info->raw_oob_mode) { - /* - * If control arrives here, we're doing a "raw" read. Send the - * command to read the conventional OOB and read it. - */ - nand->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); - nand->read_buf(mtd, nand->oob_poi, mtd->oobsize); - } else { - /* - * If control arrives here, we're not doing a "raw" read. Fill - * the OOB buffer with set bits and correct the block mark. - */ - memset(nand->oob_poi, 0xff, mtd->oobsize); - - nand->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); - mxs_nand_read_buf(mtd, nand->oob_poi, 1); - } - - return 0; - -} - -/* - * Write OOB data to NAND. - */ -static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page) -{ - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - uint8_t block_mark = 0; - - /* - * There are fundamental incompatibilities between the i.MX GPMI NFC and - * the NAND Flash MTD model that make it essentially impossible to write - * the out-of-band bytes. - * - * We permit *ONE* exception. If the *intent* of writing the OOB is to - * mark a block bad, we can do that. - */ - - if (!nand_info->marking_block_bad) { - printf("NXS NAND: Writing OOB isn't supported\n"); - return -EIO; - } - - /* Write the block mark. */ - nand->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - nand->write_buf(mtd, &block_mark, 1); - nand->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - - /* Check if it worked. */ - if (nand->waitfunc(mtd, nand) & NAND_STATUS_FAIL) - return -EIO; - - return 0; -} - -/* - * Claims all blocks are good. - * - * In principle, this function is *only* called when the NAND Flash MTD system - * isn't allowed to keep an in-memory bad block table, so it is forced to ask - * the driver for bad block information. - * - * In fact, we permit the NAND Flash MTD system to have an in-memory BBT, so - * this function is *only* called when we take it away. - * - * Thus, this function is only called when we want *all* blocks to look good, - * so it *always* return success. - */ -static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs) -{ - return 0; -} - -static int mxs_nand_set_geometry(struct mtd_info *mtd, struct bch_geometry *geo) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_chip *nand = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - - if (chip->ecc.strength > 0 && chip->ecc.size > 0) - return mxs_nand_calc_ecc_layout_by_info(geo, mtd, - chip->ecc.strength, chip->ecc.size); - - if (nand_info->use_minimum_ecc || - mxs_nand_calc_ecc_layout(geo, mtd)) { - if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0)) - return -EINVAL; - - return mxs_nand_calc_ecc_layout_by_info(geo, mtd, - chip->ecc_strength_ds, chip->ecc_step_ds); - } - - return 0; -} - -/* - * At this point, the physical NAND Flash chips have been identified and - * counted, so we know the physical geometry. This enables us to make some - * important configuration decisions. - * - * The return value of this function propagates directly back to this driver's - * board_nand_init(). Anything other than zero will cause this driver to - * tear everything down and declare failure. - */ -int mxs_nand_setup_ecc(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct mxs_nand_info *nand_info = nand_get_controller_data(nand); - struct bch_geometry *geo = &nand_info->bch_geometry; - struct mxs_bch_regs *bch_regs = nand_info->bch_regs; - uint32_t tmp; - int ret; - - ret = mxs_nand_set_geometry(mtd, geo); - if (ret) - return ret; - - mxs_nand_calc_mark_offset(geo, mtd->writesize); - - /* Configure BCH and set NFC geometry */ - mxs_reset_block(&bch_regs->hw_bch_ctrl_reg); - - /* Configure layout 0 */ - tmp = (geo->ecc_chunk_count - 1) << BCH_FLASHLAYOUT0_NBLOCKS_OFFSET; - tmp |= MXS_NAND_METADATA_SIZE << BCH_FLASHLAYOUT0_META_SIZE_OFFSET; - tmp |= (geo->ecc_strength >> 1) << BCH_FLASHLAYOUT0_ECC0_OFFSET; - tmp |= geo->ecc_chunk_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT; - tmp |= (geo->gf_len == 14 ? 1 : 0) << - BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET; - writel(tmp, &bch_regs->hw_bch_flash0layout0); - - tmp = (mtd->writesize + mtd->oobsize) - << BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET; - tmp |= (geo->ecc_strength >> 1) << BCH_FLASHLAYOUT1_ECCN_OFFSET; - tmp |= geo->ecc_chunk_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT; - tmp |= (geo->gf_len == 14 ? 1 : 0) << - BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET; - writel(tmp, &bch_regs->hw_bch_flash0layout1); - - /* Set *all* chip selects to use layout 0 */ - writel(0, &bch_regs->hw_bch_layoutselect); - - /* Enable BCH complete interrupt */ - writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set); - - /* Hook some operations at the MTD level. */ - if (mtd->_read_oob != mxs_nand_hook_read_oob) { - nand_info->hooked_read_oob = mtd->_read_oob; - mtd->_read_oob = mxs_nand_hook_read_oob; - } - - if (mtd->_write_oob != mxs_nand_hook_write_oob) { - nand_info->hooked_write_oob = mtd->_write_oob; - mtd->_write_oob = mxs_nand_hook_write_oob; - } - - if (mtd->_block_markbad != mxs_nand_hook_block_markbad) { - nand_info->hooked_block_markbad = mtd->_block_markbad; - mtd->_block_markbad = mxs_nand_hook_block_markbad; - } - - return 0; -} - -/* - * Allocate DMA buffers - */ -int mxs_nand_alloc_buffers(struct mxs_nand_info *nand_info) -{ - uint8_t *buf; - const int size = NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE; - - nand_info->data_buf_size = roundup(size, MXS_DMA_ALIGNMENT); - - /* DMA buffers */ - buf = memalign(MXS_DMA_ALIGNMENT, nand_info->data_buf_size); - if (!buf) { - printf("MXS NAND: Error allocating DMA buffers\n"); - return -ENOMEM; - } - - memset(buf, 0, nand_info->data_buf_size); - - nand_info->data_buf = buf; - nand_info->oob_buf = buf + NAND_MAX_PAGESIZE; - /* Command buffers */ - nand_info->cmd_buf = memalign(MXS_DMA_ALIGNMENT, - MXS_NAND_COMMAND_BUFFER_SIZE); - if (!nand_info->cmd_buf) { - free(buf); - printf("MXS NAND: Error allocating command buffers\n"); - return -ENOMEM; - } - memset(nand_info->cmd_buf, 0, MXS_NAND_COMMAND_BUFFER_SIZE); - nand_info->cmd_queue_len = 0; - - return 0; -} - -/* - * Initializes the NFC hardware. - */ -int mxs_nand_init_dma(struct mxs_nand_info *info) -{ - int i = 0, j, ret = 0; - - info->desc = malloc(sizeof(struct mxs_dma_desc *) * - MXS_NAND_DMA_DESCRIPTOR_COUNT); - if (!info->desc) { - ret = -ENOMEM; - goto err1; - } - - /* Allocate the DMA descriptors. */ - for (i = 0; i < MXS_NAND_DMA_DESCRIPTOR_COUNT; i++) { - info->desc[i] = mxs_dma_desc_alloc(); - if (!info->desc[i]) { - ret = -ENOMEM; - goto err2; - } - } - - /* Init the DMA controller. */ - mxs_dma_init(); - for (j = MXS_DMA_CHANNEL_AHB_APBH_GPMI0; - j <= MXS_DMA_CHANNEL_AHB_APBH_GPMI7; j++) { - ret = mxs_dma_init_channel(j); - if (ret) - goto err3; - } - - /* Reset the GPMI block. */ - mxs_reset_block(&info->gpmi_regs->hw_gpmi_ctrl0_reg); - mxs_reset_block(&info->bch_regs->hw_bch_ctrl_reg); - - /* - * Choose NAND mode, set IRQ polarity, disable write protection and - * select BCH ECC. - */ - clrsetbits_le32(&info->gpmi_regs->hw_gpmi_ctrl1, - GPMI_CTRL1_GPMI_MODE, - GPMI_CTRL1_ATA_IRQRDY_POLARITY | GPMI_CTRL1_DEV_RESET | - GPMI_CTRL1_BCH_MODE); - - return 0; - -err3: - for (--j; j >= MXS_DMA_CHANNEL_AHB_APBH_GPMI0; j--) - mxs_dma_release(j); -err2: - for (--i; i >= 0; i--) - mxs_dma_desc_free(info->desc[i]); - free(info->desc); -err1: - if (ret == -ENOMEM) - printf("MXS NAND: Unable to allocate DMA descriptors\n"); - return ret; -} - -int mxs_nand_init_spl(struct nand_chip *nand) -{ - struct mxs_nand_info *nand_info; - int err; - - nand_info = malloc(sizeof(struct mxs_nand_info)); - if (!nand_info) { - printf("MXS NAND: Failed to allocate private data\n"); - return -ENOMEM; - } - memset(nand_info, 0, sizeof(struct mxs_nand_info)); - - nand_info->gpmi_regs = (struct mxs_gpmi_regs *)MXS_GPMI_BASE; - nand_info->bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE; - err = mxs_nand_alloc_buffers(nand_info); - if (err) - return err; - - err = mxs_nand_init_dma(nand_info); - if (err) - return err; - - nand_set_controller_data(nand, nand_info); - - nand->options |= NAND_NO_SUBPAGE_WRITE; - - nand->cmd_ctrl = mxs_nand_cmd_ctrl; - nand->dev_ready = mxs_nand_device_ready; - nand->select_chip = mxs_nand_select_chip; - - nand->read_byte = mxs_nand_read_byte; - nand->read_buf = mxs_nand_read_buf; - - nand->ecc.read_page = mxs_nand_ecc_read_page; - - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.bytes = 9; - nand->ecc.size = 512; - nand->ecc.strength = 8; - - return 0; -} - -int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info) -{ - struct mtd_info *mtd; - struct nand_chip *nand; - int err; - - nand = &nand_info->chip; - mtd = nand_to_mtd(nand); - err = mxs_nand_alloc_buffers(nand_info); - if (err) - return err; - - err = mxs_nand_init_dma(nand_info); - if (err) - goto err_free_buffers; - - memset(&fake_ecc_layout, 0, sizeof(fake_ecc_layout)); - -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; -#endif - - nand_set_controller_data(nand, nand_info); - nand->options |= NAND_NO_SUBPAGE_WRITE; - - if (nand_info->dev) - nand->flash_node = dev_of_offset(nand_info->dev); - - nand->cmd_ctrl = mxs_nand_cmd_ctrl; - - nand->dev_ready = mxs_nand_device_ready; - nand->select_chip = mxs_nand_select_chip; - nand->block_bad = mxs_nand_block_bad; - - nand->read_byte = mxs_nand_read_byte; - - nand->read_buf = mxs_nand_read_buf; - nand->write_buf = mxs_nand_write_buf; - - /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) - goto err_free_buffers; - - if (mxs_nand_setup_ecc(mtd)) - goto err_free_buffers; - - nand->ecc.read_page = mxs_nand_ecc_read_page; - nand->ecc.write_page = mxs_nand_ecc_write_page; - nand->ecc.read_oob = mxs_nand_ecc_read_oob; - nand->ecc.write_oob = mxs_nand_ecc_write_oob; - - nand->ecc.layout = &fake_ecc_layout; - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.size = nand_info->bch_geometry.ecc_chunk_size; - nand->ecc.strength = nand_info->bch_geometry.ecc_strength; - - /* second phase scan */ - err = nand_scan_tail(mtd); - if (err) - goto err_free_buffers; - - err = nand_register(0, mtd); - if (err) - goto err_free_buffers; - - return 0; - -err_free_buffers: - free(nand_info->data_buf); - free(nand_info->cmd_buf); - - return err; -} - -#ifndef CONFIG_NAND_MXS_DT -void board_nand_init(void) -{ - struct mxs_nand_info *nand_info; - - nand_info = malloc(sizeof(struct mxs_nand_info)); - if (!nand_info) { - printf("MXS NAND: Failed to allocate private data\n"); - return; - } - memset(nand_info, 0, sizeof(struct mxs_nand_info)); - - nand_info->gpmi_regs = (struct mxs_gpmi_regs *)MXS_GPMI_BASE; - nand_info->bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE; - - /* Refer to Chapter 17 for i.MX6DQ, Chapter 18 for i.MX6SX */ - if (is_mx6sx() || is_mx7()) - nand_info->max_ecc_strength_supported = 62; - else - nand_info->max_ecc_strength_supported = 40; - -#ifdef CONFIG_NAND_MXS_USE_MINIMUM_ECC - nand_info->use_minimum_ecc = true; -#endif - - if (mxs_nand_init_ctrl(nand_info) < 0) - goto err; - - return; - -err: - free(nand_info); -} -#endif diff --git a/drivers/mtd/nand/mxs_nand.h b/drivers/mtd/nand/mxs_nand.h deleted file mode 100644 index 4bd65cded9..0000000000 --- a/drivers/mtd/nand/mxs_nand.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * NXP GPMI NAND flash driver - * - * Copyright (C) 2018 Toradex - * Authors: - * Stefan Agner - */ - -#include -#include -#include -#include - -/** - * @gf_len: The length of Galois Field. (e.g., 13 or 14) - * @ecc_strength: A number that describes the strength of the ECC - * algorithm. - * @ecc_chunk_size: The size, in bytes, of a single ECC chunk. Note - * the first chunk in the page includes both data and - * metadata, so it's a bit larger than this value. - * @ecc_chunk_count: The number of ECC chunks in the page, - * @block_mark_byte_offset: The byte offset in the ECC-based page view at - * which the underlying physical block mark appears. - * @block_mark_bit_offset: The bit offset into the ECC-based page view at - * which the underlying physical block mark appears. - */ -struct bch_geometry { - unsigned int gf_len; - unsigned int ecc_strength; - unsigned int ecc_chunk_size; - unsigned int ecc_chunk_count; - unsigned int block_mark_byte_offset; - unsigned int block_mark_bit_offset; -}; - -struct mxs_nand_info { - struct nand_chip chip; - struct udevice *dev; - unsigned int max_ecc_strength_supported; - bool use_minimum_ecc; - int cur_chip; - - uint32_t cmd_queue_len; - uint32_t data_buf_size; - struct bch_geometry bch_geometry; - - uint8_t *cmd_buf; - uint8_t *data_buf; - uint8_t *oob_buf; - - uint8_t marking_block_bad; - uint8_t raw_oob_mode; - - struct mxs_gpmi_regs *gpmi_regs; - struct mxs_bch_regs *bch_regs; - - /* Functions with altered behaviour */ - int (*hooked_read_oob)(struct mtd_info *mtd, - loff_t from, struct mtd_oob_ops *ops); - int (*hooked_write_oob)(struct mtd_info *mtd, - loff_t to, struct mtd_oob_ops *ops); - int (*hooked_block_markbad)(struct mtd_info *mtd, - loff_t ofs); - - /* DMA descriptors */ - struct mxs_dma_desc **desc; - uint32_t desc_index; -}; - -int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info); -int mxs_nand_init_spl(struct nand_chip *nand); -int mxs_nand_setup_ecc(struct mtd_info *mtd); diff --git a/drivers/mtd/nand/mxs_nand_dt.c b/drivers/mtd/nand/mxs_nand_dt.c deleted file mode 100644 index 44dec5dedf..0000000000 --- a/drivers/mtd/nand/mxs_nand_dt.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * NXP GPMI NAND flash driver (DT initialization) - * - * Copyright (C) 2018 Toradex - * Authors: - * Stefan Agner - * - * Based on denali_dt.c - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include - -#include "mxs_nand.h" - -struct mxs_nand_dt_data { - unsigned int max_ecc_strength_supported; -}; - -static const struct mxs_nand_dt_data mxs_nand_imx6q_data = { - .max_ecc_strength_supported = 40, -}; - -static const struct mxs_nand_dt_data mxs_nand_imx7d_data = { - .max_ecc_strength_supported = 62, -}; - -static const struct udevice_id mxs_nand_dt_ids[] = { - { - .compatible = "fsl,imx6q-gpmi-nand", - .data = (unsigned long)&mxs_nand_imx6q_data, - }, - { - .compatible = "fsl,imx7d-gpmi-nand", - .data = (unsigned long)&mxs_nand_imx7d_data, - }, - { /* sentinel */ } -}; - -static int mxs_nand_dt_probe(struct udevice *dev) -{ - struct mxs_nand_info *info = dev_get_priv(dev); - const struct mxs_nand_dt_data *data; - struct resource res; - int ret; - - data = (void *)dev_get_driver_data(dev); - if (data) - info->max_ecc_strength_supported = data->max_ecc_strength_supported; - - info->dev = dev; - - ret = dev_read_resource_byname(dev, "gpmi-nand", &res); - if (ret) - return ret; - - info->gpmi_regs = devm_ioremap(dev, res.start, resource_size(&res)); - - - ret = dev_read_resource_byname(dev, "bch", &res); - if (ret) - return ret; - - info->bch_regs = devm_ioremap(dev, res.start, resource_size(&res)); - - info->use_minimum_ecc = dev_read_bool(dev, "fsl,use-minimum-ecc"); - - return mxs_nand_init_ctrl(info); -} - -U_BOOT_DRIVER(mxs_nand_dt) = { - .name = "mxs-nand-dt", - .id = UCLASS_MTD, - .of_match = mxs_nand_dt_ids, - .probe = mxs_nand_dt_probe, - .priv_auto_alloc_size = sizeof(struct mxs_nand_info), -}; - -void board_nand_init(void) -{ - struct udevice *dev; - int ret; - - ret = uclass_get_device_by_driver(UCLASS_MTD, - DM_GET_DRIVER(mxs_nand_dt), - &dev); - if (ret && ret != -ENODEV) - pr_err("Failed to initialize MXS NAND controller. (error %d)\n", - ret); -} diff --git a/drivers/mtd/nand/mxs_nand_spl.c b/drivers/mtd/nand/mxs_nand_spl.c deleted file mode 100644 index 2d7bbe83cc..0000000000 --- a/drivers/mtd/nand/mxs_nand_spl.c +++ /dev/null @@ -1,264 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2014 Gateworks Corporation - * Author: Tim Harvey - */ -#include -#include -#include -#include "mxs_nand.h" - -static struct mtd_info *mtd; -static struct nand_chip nand_chip; - -static void mxs_nand_command(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - u32 timeo, time_start; - - /* write out the command to the device */ - chip->cmd_ctrl(mtd, command, NAND_CLE); - - /* Serially input address */ - if (column != -1) { - chip->cmd_ctrl(mtd, column, NAND_ALE); - chip->cmd_ctrl(mtd, column >> 8, NAND_ALE); - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, NAND_ALE); - chip->cmd_ctrl(mtd, page_addr >> 8, NAND_ALE); - /* One more address cycle for devices > 128MiB */ - if (chip->chipsize > (128 << 20)) - chip->cmd_ctrl(mtd, page_addr >> 16, NAND_ALE); - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); - - if (command == NAND_CMD_READ0) { - chip->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_CLE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); - } - - /* wait for nand ready */ - ndelay(100); - timeo = (CONFIG_SYS_HZ * 20) / 1000; - time_start = get_timer(0); - while (get_timer(time_start) < timeo) { - if (chip->dev_ready(mtd)) - break; - } -} - -#if defined (CONFIG_SPL_NAND_IDENT) - -/* Trying to detect the NAND flash using ONFi, JEDEC, and (extended) IDs */ -static int mxs_flash_full_ident(struct mtd_info *mtd) -{ - int nand_maf_id, nand_dev_id; - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_flash_dev *type; - - type = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, NULL); - - if (IS_ERR(type)) { - chip->select_chip(mtd, -1); - return PTR_ERR(type); - } - - return 0; -} - -#else - -/* Trying to detect the NAND flash using ONFi only */ -static int mxs_flash_onfi_ident(struct mtd_info *mtd) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - int i; - u8 mfg_id, dev_id; - u8 id_data[8]; - struct nand_onfi_params *p = &chip->onfi_params; - - /* Reset the chip */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* Send the command for reading device ID */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - /* Read manufacturer and device IDs */ - mfg_id = chip->read_byte(mtd); - dev_id = chip->read_byte(mtd); - - /* Try again to make sure */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - for (i = 0; i < 8; i++) - id_data[i] = chip->read_byte(mtd); - if (id_data[0] != mfg_id || id_data[1] != dev_id) { - printf("second ID read did not match"); - return -1; - } - debug("0x%02x:0x%02x ", mfg_id, dev_id); - - /* read ONFI */ - chip->onfi_version = 0; - chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); - if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || - chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') { - return -2; - } - - /* we have ONFI, probe it */ - chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); - chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); - mtd->name = p->model; - mtd->writesize = le32_to_cpu(p->byte_per_page); - mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; - mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); - chip->chipsize = le32_to_cpu(p->blocks_per_lun); - chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; - /* Calculate the address shift from the page size */ - chip->page_shift = ffs(mtd->writesize) - 1; - chip->phys_erase_shift = ffs(mtd->erasesize) - 1; - /* Convert chipsize to number of pages per chip -1 */ - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; - chip->badblockbits = 8; - - debug("erasesize=%d (>>%d)\n", mtd->erasesize, chip->phys_erase_shift); - debug("writesize=%d (>>%d)\n", mtd->writesize, chip->page_shift); - debug("oobsize=%d\n", mtd->oobsize); - debug("chipsize=%lld\n", chip->chipsize); - - return 0; -} - -#endif /* CONFIG_SPL_NAND_IDENT */ - -static int mxs_flash_ident(struct mtd_info *mtd) -{ - int ret; -#if defined (CONFIG_SPL_NAND_IDENT) - ret = mxs_flash_full_ident(mtd); -#else - ret = mxs_flash_onfi_ident(mtd); -#endif - return ret; -} - -static int mxs_read_page_ecc(struct mtd_info *mtd, void *buf, unsigned int page) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - int ret; - - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); - ret = nand_chip.ecc.read_page(mtd, chip, buf, 1, page); - if (ret < 0) { - printf("read_page failed %d\n", ret); - return -1; - } - return 0; -} - -static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - unsigned int block = offs >> chip->phys_erase_shift; - unsigned int page = offs >> chip->page_shift; - - debug("%s offs=0x%08x block:%d page:%d\n", __func__, (int)offs, block, - page); - chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); - memset(chip->oob_poi, 0, mtd->oobsize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - - return chip->oob_poi[0] != 0xff; -} - -/* setup mtd and nand structs and init mxs_nand driver */ -static int mxs_nand_init(void) -{ - /* return if already initalized */ - if (nand_chip.numchips) - return 0; - - /* init mxs nand driver */ - mxs_nand_init_spl(&nand_chip); - mtd = nand_to_mtd(&nand_chip); - /* set mtd functions */ - nand_chip.cmdfunc = mxs_nand_command; - nand_chip.numchips = 1; - - /* identify flash device */ - if (mxs_flash_ident(mtd)) { - printf("Failed to identify\n"); - return -1; - } - - /* allocate and initialize buffers */ - nand_chip.buffers = memalign(ARCH_DMA_MINALIGN, - sizeof(*nand_chip.buffers)); - nand_chip.oob_poi = nand_chip.buffers->databuf + mtd->writesize; - /* setup flash layout (does not scan as we override that) */ - mtd->size = nand_chip.chipsize; - nand_chip.scan_bbt(mtd); - - return 0; -} - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) -{ - struct nand_chip *chip; - unsigned int page; - unsigned int nand_page_per_block; - unsigned int sz = 0; - - if (mxs_nand_init()) - return -ENODEV; - chip = mtd_to_nand(mtd); - page = offs >> chip->page_shift; - nand_page_per_block = mtd->erasesize / mtd->writesize; - - debug("%s offset:0x%08x len:%d page:%d\n", __func__, offs, size, page); - - size = roundup(size, mtd->writesize); - while (sz < size) { - if (mxs_read_page_ecc(mtd, buf, page) < 0) - return -1; - sz += mtd->writesize; - offs += mtd->writesize; - page++; - buf += mtd->writesize; - - /* - * Check if we have crossed a block boundary, and if so - * check for bad block. - */ - if (!(page % nand_page_per_block)) { - /* - * Yes, new block. See if this block is good. If not, - * loop until we find a good block. - */ - while (is_badblock(mtd, offs, 1)) { - page = page + nand_page_per_block; - /* Check i we've reached the end of flash. */ - if (page >= mtd->size >> chip->page_shift) - return -ENOMEM; - } - } - } - - return 0; -} - -int nand_default_bbt(struct mtd_info *mtd) -{ - return 0; -} - -void nand_init(void) -{ -} - -void nand_deselect(void) -{ -} - diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c deleted file mode 100644 index bca51ffbf2..0000000000 --- a/drivers/mtd/nand/nand.c +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * (C) Copyright 2005 - * 2N Telekomunikace, a.s. - * Ladislav Michl - */ - -#include -#include -#include -#include - -#ifndef CONFIG_SYS_NAND_BASE_LIST -#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } -#endif - -int nand_curr_device = -1; - -static struct mtd_info *nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; - -#ifndef CONFIG_SYS_NAND_SELF_INIT -static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; -static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST; -#endif - -static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; - -static unsigned long total_nand_size; /* in kiB */ - -struct mtd_info *get_nand_dev_by_index(int dev) -{ - if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev] || - !nand_info[dev]->name) - return NULL; - - return nand_info[dev]; -} - -int nand_mtd_to_devnum(struct mtd_info *mtd) -{ - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { - if (mtd && get_nand_dev_by_index(i) == mtd) - return i; - } - - return -ENODEV; -} - -/* Register an initialized NAND mtd device with the U-Boot NAND command. */ -int nand_register(int devnum, struct mtd_info *mtd) -{ - if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE) - return -EINVAL; - - nand_info[devnum] = mtd; - - sprintf(dev_name[devnum], "nand%d", devnum); - mtd->name = dev_name[devnum]; - -#ifdef CONFIG_MTD_DEVICE - /* - * Add MTD device so that we can reference it later - * via the mtdcore infrastructure (e.g. ubi). - */ - add_mtd_device(mtd); -#endif - - total_nand_size += mtd->size / 1024; - - if (nand_curr_device == -1) - nand_curr_device = devnum; - - return 0; -} - -#ifndef CONFIG_SYS_NAND_SELF_INIT -static void nand_init_chip(int i) -{ - struct nand_chip *nand = &nand_chip[i]; - struct mtd_info *mtd = nand_to_mtd(nand); - ulong base_addr = base_address[i]; - int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; - - if (maxchips < 1) - maxchips = 1; - - nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; - - if (board_nand_init(nand)) - return; - - if (nand_scan(mtd, maxchips)) - return; - - nand_register(i, mtd); -} -#endif - -#ifdef CONFIG_MTD_CONCAT -static void create_mtd_concat(void) -{ - struct mtd_info *nand_info_list[CONFIG_SYS_MAX_NAND_DEVICE]; - int nand_devices_found = 0; - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { - struct mtd_info *mtd = get_nand_dev_by_index(i); - if (mtd != NULL) { - nand_info_list[nand_devices_found] = mtd; - nand_devices_found++; - } - } - if (nand_devices_found > 1) { - struct mtd_info *mtd; - char c_mtd_name[16]; - - /* - * We detected multiple devices. Concatenate them together. - */ - sprintf(c_mtd_name, "nand%d", nand_devices_found); - mtd = mtd_concat_create(nand_info_list, nand_devices_found, - c_mtd_name); - - if (mtd == NULL) - return; - - nand_register(nand_devices_found, mtd); - } - - return; -} -#else -static void create_mtd_concat(void) -{ -} -#endif - -unsigned long nand_size(void) -{ - return total_nand_size; -} - -void nand_init(void) -{ - static int initialized; - - /* - * Avoid initializing NAND Flash multiple times, - * otherwise it will calculate a wrong total size. - */ - if (initialized) - return; - initialized = 1; - -#ifdef CONFIG_SYS_NAND_SELF_INIT - board_nand_init(); -#else - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - nand_init_chip(i); -#endif - -#ifdef CONFIG_SYS_NAND_SELECT_DEVICE - /* - * Select the chip in the board/cpu specific driver - */ - board_nand_select_device(mtd_to_nand(get_nand_dev_by_index(nand_curr_device)), - nand_curr_device); -#endif - - create_mtd_concat(); -} diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c deleted file mode 100644 index 92daebe120..0000000000 --- a/drivers/mtd/nand/nand_base.c +++ /dev/null @@ -1,4619 +0,0 @@ -/* - * Overview: - * This is the generic MTD driver for NAND flash devices. It should be - * capable of working with almost all NAND chips currently available. - * - * Additional technical information is available on - * http://www.linux-mtd.infradead.org/doc/nand.html - * - * 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 - * - * TODO: - * Enable cached programming for 2k page size chips - * Check, if mtd->ecctype should be set to MTD_ECC_HW - * if we have HW ECC support. - * BBT table is not serialized, has to be fixed - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#if CONFIG_IS_ENABLED(OF_CONTROL) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_MTD_PARTITIONS -#include -#endif -#include -#include - -/* Define default oob placement schemes for large and small page devices */ -static struct nand_ecclayout nand_oob_8 = { - .eccbytes = 3, - .eccpos = {0, 1, 2}, - .oobfree = { - {.offset = 3, - .length = 2}, - {.offset = 6, - .length = 2} } -}; - -static struct nand_ecclayout nand_oob_16 = { - .eccbytes = 6, - .eccpos = {0, 1, 2, 3, 6, 7}, - .oobfree = { - {.offset = 8, - . length = 8} } -}; - -static struct nand_ecclayout nand_oob_64 = { - .eccbytes = 24, - .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63}, - .oobfree = { - {.offset = 2, - .length = 38} } -}; - -static struct nand_ecclayout nand_oob_128 = { - .eccbytes = 48, - .eccpos = { - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127}, - .oobfree = { - {.offset = 2, - .length = 78} } -}; - -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, - struct mtd_oob_ops *ops); - -/* - * For devices which display every fart in the system on a separate LED. Is - * compiled away when LED support is disabled. - */ -DEFINE_LED_TRIGGER(nand_led_trigger); - -static int check_offs_len(struct mtd_info *mtd, - loff_t ofs, uint64_t len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int ret = 0; - - /* Start address must align on block boundary */ - if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) { - pr_debug("%s: unaligned address\n", __func__); - ret = -EINVAL; - } - - /* Length must align on block boundary */ - if (len & ((1ULL << chip->phys_erase_shift) - 1)) { - pr_debug("%s: length not block aligned\n", __func__); - ret = -EINVAL; - } - - return ret; -} - -/** - * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure - * - * Release chip lock and wake up anyone waiting on the device. - */ -static void nand_release_device(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - /* De-select the NAND device */ - chip->select_chip(mtd, -1); -} - -/** - * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd: MTD device structure - * - * Default read function for 8bit buswidth - */ -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_onfi_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); -} - -static void iowrite8_rep(void *addr, const uint8_t *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) - writeb(buf[i], addr); -} -static void ioread8_rep(void *addr, uint8_t *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) - buf[i] = readb(addr); -} - -static void ioread16_rep(void *addr, void *buf, int len) -{ - int i; - u16 *p = (u16 *) buf; - - for (i = 0; i < len; i++) - p[i] = readw(addr); -} - -static void iowrite16_rep(void *addr, void *buf, int len) -{ - int i; - u16 *p = (u16 *) buf; - - for (i = 0; i < len; i++) - writew(p[i], addr); -} - -/** - * 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. - */ -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. - */ -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. - */ -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. - */ -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 - * @ofs: offset from device start - * - * Check, if the block is bad. - */ -static int nand_block_bad(struct mtd_info *mtd, loff_t ofs) -{ - int page, res = 0, i = 0; - struct nand_chip *chip = mtd_to_nand(mtd); - u16 bad; - - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) - ofs += mtd->erasesize - mtd->writesize; - - page = (int)(ofs >> chip->page_shift) & chip->pagemask; - - do { - if (chip->options & NAND_BUSWIDTH_16) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, - chip->badblockpos & 0xFE, page); - bad = cpu_to_le16(chip->read_word(mtd)); - if (chip->badblockpos & 0x1) - bad >>= 8; - else - bad &= 0xFF; - } else { - chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, - page); - bad = chip->read_byte(mtd); - } - - if (likely(chip->badblockbits == 8)) - res = bad != 0xFF; - else - res = hweight8(bad) < chip->badblockbits; - ofs += mtd->writesize; - page = (int)(ofs >> chip->page_shift) & chip->pagemask; - i++; - } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); - - return res; -} - -/** - * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker - * @mtd: MTD device structure - * @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) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mtd_oob_ops ops; - uint8_t buf[2] = { 0, 0 }; - int ret = 0, res, i = 0; - - memset(&ops, 0, sizeof(ops)); - ops.oobbuf = buf; - ops.ooboffs = chip->badblockpos; - if (chip->options & NAND_BUSWIDTH_16) { - ops.ooboffs &= ~0x01; - ops.len = ops.ooblen = 2; - } else { - ops.len = ops.ooblen = 1; - } - ops.mode = MTD_OPS_PLACE_OOB; - - /* Write to first/last page(s) if necessary */ - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) - ofs += mtd->erasesize - mtd->writesize; - do { - res = nand_do_write_oob(mtd, ofs, &ops); - if (!ret) - ret = res; - - i++; - ofs += mtd->writesize; - } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); - - return ret; -} - -/** - * nand_block_markbad_lowlevel - mark a block bad - * @mtd: MTD device structure - * @ofs: offset from device start - * - * This function performs the generic NAND bad block marking steps (i.e., bad - * block table(s) and/or marker(s)). We only allow the hardware driver to - * specify how to write bad block markers to OOB (chip->block_markbad). - * - * We try operations in the following order: - * (1) erase the affected block, to allow OOB marker to be written cleanly - * (2) write bad block marker to OOB area of affected block (unless flag - * NAND_BBT_NO_OOB_BBM is present) - * (3) update the BBT - * Note that we retain the first error encountered in (2) or (3), finish the - * procedures, and dump the error in the end. -*/ -static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int res, ret = 0; - - if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) { - struct erase_info einfo; - - /* Attempt erase before marking OOB */ - memset(&einfo, 0, sizeof(einfo)); - einfo.mtd = mtd; - einfo.addr = ofs; - einfo.len = 1ULL << chip->phys_erase_shift; - nand_erase_nand(mtd, &einfo, 0); - - /* Write bad block marker to OOB */ - nand_get_device(mtd, FL_WRITING); - ret = chip->block_markbad(mtd, ofs); - nand_release_device(mtd); - } - - /* Mark block bad in BBT */ - if (chip->bbt) { - res = nand_markbad_bbt(mtd, ofs); - if (!ret) - ret = res; - } - - if (!ret) - mtd->ecc_stats.badblocks++; - - return ret; -} - -/** - * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd: MTD device structure - * - * Check, if the device is write protected. The function expects, that the - * device is already selected. - */ -static int nand_check_wp(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - /* Broken xD cards report WP despite being writable */ - if (chip->options & NAND_BROKEN_XD) - return 0; - - /* Check the WP bit */ - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); - return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; -} - -/** - * nand_block_isreserved - [GENERIC] Check if a block is marked reserved. - * @mtd: MTD device structure - * @ofs: offset from device start - * - * Check if the block is marked as reserved. - */ -static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - if (!chip->bbt) - return 0; - /* Return info from the table */ - return nand_isreserved_bbt(mtd, ofs); -} - -/** - * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd: MTD device structure - * @ofs: offset from device start - * @allowbbt: 1, if its allowed to access the bbt area - * - * Check, if the block is bad. Either by reading the bad block table or - * calling of the scan function. - */ -static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - if (!(chip->options & NAND_SKIP_BBTSCAN) && - !(chip->options & NAND_BBT_SCANNED)) { - chip->options |= NAND_BBT_SCANNED; - chip->scan_bbt(mtd); - } - - if (!chip->bbt) - return chip->block_bad(mtd, ofs); - - /* Return info from the table */ - return nand_isbad_bbt(mtd, ofs, allowbbt); -} - -/** - * 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); - u32 timeo = (CONFIG_SYS_HZ * 400) / 1000; - u32 time_start; - - time_start = get_timer(0); - /* Wait until command is processed or timeout occurs */ - while (get_timer(time_start) < timeo) { - if (chip->dev_ready) - if (chip->dev_ready(mtd)) - break; - } - - if (!chip->dev_ready(mtd)) - pr_warn("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); - u32 time_start; - - timeo = (CONFIG_SYS_HZ * timeo) / 1000; - time_start = get_timer(0); - while (get_timer(time_start) < timeo) { - if ((chip->read_byte(mtd) & NAND_STATUS_READY)) - break; - WATCHDOG_RESET(); - } -}; - -/** - * 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; - } - 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_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 */ - 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); -} - -/** - * 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 */ - 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; - 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_CACHEDPROG: - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_RNDIN: - 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_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); - return; - - case NAND_CMD_READ0: - 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 - * @mtd: MTD device structure - * @new_state: the state which is requested - * - * Used when in panic, no locks are taken. - */ -static void panic_nand_get_device(struct nand_chip *chip, - struct mtd_info *mtd, int new_state) -{ - /* Hardware controller shared among independent devices */ - chip->controller->active = chip; - chip->state = new_state; -} - -/** - * nand_get_device - [GENERIC] Get chip for selected access - * @mtd: MTD device structure - * @new_state: the state which is requested - * - * Get the device and lock it for exclusive access - */ -static int -nand_get_device(struct mtd_info *mtd, int new_state) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - chip->state = new_state; - return 0; -} - -/** - * panic_nand_wait - [GENERIC] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure - * @timeo: timeout - * - * Wait for command done. This is a helper function for nand_wait used when - * 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) -{ - int i; - for (i = 0; i < timeo; i++) { - if (chip->dev_ready) { - if (chip->dev_ready(mtd)) - break; - } else { - if (chip->read_byte(mtd) & NAND_STATUS_READY) - break; - } - mdelay(1); - } -} - -/** - * 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) -{ - int status; - unsigned long timeo = 400; - - led_trigger_event(nand_led_trigger, LED_FULL); - - /* - * Apply this short delay always to ensure that we do wait tWB in any - * case on any machine. - */ - ndelay(100); - - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); - - u32 timer = (CONFIG_SYS_HZ * timeo) / 1000; - u32 time_start; - - time_start = get_timer(0); - while (get_timer(time_start) < timer) { - if (chip->dev_ready) { - if (chip->dev_ready(mtd)) - break; - } else { - if (chip->read_byte(mtd) & NAND_STATUS_READY) - break; - } - } - led_trigger_event(nand_led_trigger, LED_OFF); - - status = (int)chip->read_byte(mtd); - /* This can happen if in case of timeout or buggy dev_ready */ - WARN_ON(!(status & NAND_STATUS_READY)); - return status; -} - -/** - * nand_reset_data_interface - Reset data interface and timings - * @chip: The NAND chip - * @chipnr: Internal die id - * - * Reset the Data interface and timings to ONFI mode 0. - * - * Returns 0 for success or negative error code otherwise. - */ -static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - const struct nand_data_interface *conf; - int ret; - - if (!chip->setup_data_interface) - return 0; - - /* - * The ONFI specification says: - * " - * To transition from NV-DDR or NV-DDR2 to the SDR data - * interface, the host shall use the Reset (FFh) command - * using SDR timing mode 0. A device in any timing mode is - * required to recognize Reset (FFh) command issued in SDR - * timing mode 0. - * " - * - * Configure the data interface in SDR mode and set the - * timings to timing mode 0. - */ - - conf = nand_get_default_data_interface(); - ret = chip->setup_data_interface(mtd, chipnr, conf); - if (ret) - pr_err("Failed to configure data interface to SDR timing mode 0\n"); - - return ret; -} - -/** - * nand_setup_data_interface - Setup the best data interface and timings - * @chip: The NAND chip - * @chipnr: Internal die id - * - * Find and configure the best data interface and NAND timings supported by - * the chip and the driver. - * First tries to retrieve supported timing modes from ONFI information, - * and if the NAND chip does not support ONFI, relies on the - * ->onfi_timing_mode_default specified in the nand_ids table. - * - * Returns 0 for success or negative error code otherwise. - */ -static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - int ret; - - if (!chip->setup_data_interface || !chip->data_interface) - return 0; - - /* - * Ensure the timing mode has been changed on the chip side - * before changing timings on the controller side. - */ - if (chip->onfi_version) { - u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { - chip->onfi_timing_mode_default, - }; - - ret = chip->onfi_set_features(mtd, chip, - ONFI_FEATURE_ADDR_TIMING_MODE, - tmode_param); - if (ret) - goto err; - } - - ret = chip->setup_data_interface(mtd, chipnr, chip->data_interface); -err: - return ret; -} - -/** - * nand_init_data_interface - find the best data interface and timings - * @chip: The NAND chip - * - * Find the best data interface and NAND timings supported by the chip - * and the driver. - * First tries to retrieve supported timing modes from ONFI information, - * and if the NAND chip does not support ONFI, relies on the - * ->onfi_timing_mode_default specified in the nand_ids table. After this - * function nand_chip->data_interface is initialized with the best timing mode - * available. - * - * Returns 0 for success or negative error code otherwise. - */ -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) - return 0; - - /* - * First try to identify the best timings from ONFI parameters and - * 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->onfi_timing_mode_default) - return 0; - - modes = GENMASK(chip->onfi_timing_mode_default, 0); - } - - chip->data_interface = kzalloc(sizeof(*chip->data_interface), - GFP_KERNEL); - if (!chip->data_interface) - return -ENOMEM; - - for (mode = fls(modes) - 1; mode >= 0; mode--) { - ret = onfi_init_data_interface(chip, chip->data_interface, - NAND_SDR_IFACE, mode); - if (ret) - continue; - - /* Pass -1 to only */ - ret = chip->setup_data_interface(mtd, - NAND_DATA_IFACE_CHECK_ONLY, - chip->data_interface); - if (!ret) { - chip->onfi_timing_mode_default = mode; - break; - } - } - - return 0; -} - -static void __maybe_unused nand_release_data_interface(struct nand_chip *chip) -{ - kfree(chip->data_interface); -} - -/** - * nand_reset - Reset and initialize a NAND device - * @chip: The NAND chip - * @chipnr: Internal die id - * - * Returns 0 for success or negative error code otherwise - */ -int nand_reset(struct nand_chip *chip, int chipnr) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - int ret; - - ret = nand_reset_data_interface(chip, chipnr); - if (ret) - return ret; - - /* - * 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->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - chip->select_chip(mtd, -1); - - chip->select_chip(mtd, chipnr); - ret = nand_setup_data_interface(chip, chipnr); - chip->select_chip(mtd, -1); - if (ret) - return ret; - - return 0; -} - -/** - * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data - * @buf: buffer to test - * @len: buffer length - * @bitflips_threshold: maximum number of bitflips - * - * Check if a buffer contains only 0xff, which means the underlying region - * has been erased and is ready to be programmed. - * The bitflips_threshold specify the maximum number of bitflips before - * considering the region is not erased. - * Note: The logic of this function has been extracted from the memweight - * implementation, except that nand_check_erased_buf function exit before - * testing the whole buffer if the number of bitflips exceed the - * bitflips_threshold value. - * - * Returns a positive number of bitflips less than or equal to - * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the - * threshold. - */ -static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) -{ - const unsigned char *bitmap = buf; - int bitflips = 0; - int weight; - - for (; len && ((uintptr_t)bitmap) % sizeof(long); - len--, bitmap++) { - weight = hweight8(*bitmap); - bitflips += BITS_PER_BYTE - weight; - if (unlikely(bitflips > bitflips_threshold)) - return -EBADMSG; - } - - for (; len >= 4; len -= 4, bitmap += 4) { - weight = hweight32(*((u32 *)bitmap)); - bitflips += 32 - weight; - if (unlikely(bitflips > bitflips_threshold)) - return -EBADMSG; - } - - for (; len > 0; len--, bitmap++) { - weight = hweight8(*bitmap); - bitflips += BITS_PER_BYTE - weight; - if (unlikely(bitflips > bitflips_threshold)) - return -EBADMSG; - } - - return bitflips; -} - -/** - * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only - * 0xff data - * @data: data buffer to test - * @datalen: data length - * @ecc: ECC buffer - * @ecclen: ECC length - * @extraoob: extra OOB buffer - * @extraooblen: extra OOB length - * @bitflips_threshold: maximum number of bitflips - * - * Check if a data buffer and its associated ECC and OOB data contains only - * 0xff pattern, which means the underlying region has been erased and is - * ready to be programmed. - * The bitflips_threshold specify the maximum number of bitflips before - * considering the region as not erased. - * - * Note: - * 1/ ECC algorithms are working on pre-defined block sizes which are usually - * different from the NAND page size. When fixing bitflips, ECC engines will - * report the number of errors per chunk, and the NAND core infrastructure - * expect you to return the maximum number of bitflips for the whole page. - * This is why you should always use this function on a single chunk and - * not on the whole page. After checking each chunk you should update your - * max_bitflips value accordingly. - * 2/ When checking for bitflips in erased pages you should not only check - * the payload data but also their associated ECC data, because a user might - * have programmed almost all bits to 1 but a few. In this case, we - * shouldn't consider the chunk as erased, and checking ECC bytes prevent - * this case. - * 3/ The extraoob argument is optional, and should be used if some of your OOB - * data are protected by the ECC engine. - * It could also be used if you support subpages and want to attach some - * extra OOB data to an ECC chunk. - * - * Returns a positive number of bitflips less than or equal to - * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the - * threshold. In case of success, the passed buffers are filled with 0xff. - */ -int nand_check_erased_ecc_chunk(void *data, int datalen, - void *ecc, int ecclen, - void *extraoob, int extraooblen, - int bitflips_threshold) -{ - int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0; - - data_bitflips = nand_check_erased_buf(data, datalen, - bitflips_threshold); - if (data_bitflips < 0) - return data_bitflips; - - bitflips_threshold -= data_bitflips; - - ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold); - if (ecc_bitflips < 0) - return ecc_bitflips; - - bitflips_threshold -= ecc_bitflips; - - extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen, - bitflips_threshold); - if (extraoob_bitflips < 0) - return extraoob_bitflips; - - if (data_bitflips) - memset(data, 0xff, datalen); - - if (ecc_bitflips) - memset(ecc, 0xff, ecclen); - - if (extraoob_bitflips) - memset(extraoob, 0xff, extraooblen); - - return data_bitflips + ecc_bitflips + extraoob_bitflips; -} -EXPORT_SYMBOL(nand_check_erased_ecc_chunk); - -/** - * 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 - * @page: page number to read - * - * Not for syndrome calculating ECC controllers, which use a special oob layout. - */ -static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - chip->read_buf(mtd, buf, mtd->writesize); - if (oob_required) - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; -} - -/** - * 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 - * @page: page number to read - * - * 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, - int oob_required, int page) -{ - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - uint8_t *oob = chip->oob_poi; - int steps, size; - - for (steps = chip->ecc.steps; steps > 0; steps--) { - chip->read_buf(mtd, buf, eccsize); - buf += eccsize; - - if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->read_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->read_buf(mtd, oob, size); - - return 0; -} - -/** - * 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) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - unsigned int max_bitflips = 0; - - chip->ecc.read_page_raw(mtd, chip, buf, 1, page); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - eccsteps = chip->ecc.steps; - p = buf; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - } - return max_bitflips; -} - -/** - * 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) -{ - int start_step, end_step, num_steps; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *p; - int data_col_addr, i, gaps = 0; - int datafrag_len, eccfrag_len, aligned_len, aligned_pos; - int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; - int index; - unsigned int max_bitflips = 0; - - /* Column address within the page aligned to ECC size (256bytes) */ - start_step = data_offs / chip->ecc.size; - end_step = (data_offs + readlen - 1) / chip->ecc.size; - num_steps = end_step - start_step + 1; - index = start_step * chip->ecc.bytes; - - /* Data size aligned to ECC ecc.size */ - datafrag_len = num_steps * chip->ecc.size; - eccfrag_len = num_steps * chip->ecc.bytes; - - data_col_addr = start_step * chip->ecc.size; - /* If we read not a page aligned data */ - if (data_col_addr != 0) - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); - - p = bufpoi + data_col_addr; - chip->read_buf(mtd, p, datafrag_len); - - /* Calculate ECC */ - for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) - chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); - - /* - * The performance is faster if we position offsets according to - * ecc.pos. Let's make sure that there are no gaps in ECC positions. - */ - for (i = 0; i < eccfrag_len - 1; i++) { - if (eccpos[i + index] + 1 != eccpos[i + index + 1]) { - gaps = 1; - break; - } - } - if (gaps) { - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - } else { - /* - * Send the command to read the particular ECC bytes take care - * about buswidth alignment in read_buf. - */ - aligned_pos = eccpos[index] & ~(busw - 1); - aligned_len = eccfrag_len; - if (eccpos[index] & (busw - 1)) - aligned_len++; - if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1)) - aligned_len++; - - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, - mtd->writesize + aligned_pos, -1); - chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); - } - - for (i = 0; i < eccfrag_len; i++) - chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]]; - - p = bufpoi + data_col_addr; - for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { - int stat; - - stat = chip->ecc.correct(mtd, p, - &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); - if (stat == -EBADMSG && - (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { - /* check for empty pages with bitflips */ - stat = nand_check_erased_ecc_chunk(p, chip->ecc.size, - &chip->buffers->ecccode[i], - chip->ecc.bytes, - NULL, 0, - chip->ecc.strength); - } - - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - } - return max_bitflips; -} - -/** - * 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 - * @page: page number to read - * - * 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) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - unsigned int max_bitflips = 0; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - } - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - eccsteps = chip->ecc.steps; - p = buf; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat == -EBADMSG && - (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { - /* check for empty pages with bitflips */ - stat = nand_check_erased_ecc_chunk(p, eccsize, - &ecc_code[i], eccbytes, - NULL, 0, - chip->ecc.strength); - } - - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - } - return max_bitflips; -} - -/** - * 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 - * @page: page number to read - * - * Hardware ECC for large page chips, require OOB to be read first. For this - * ECC mode, the write_page method is re-used from ECC_HW. These methods - * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with - * 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) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *ecc_calc = chip->buffers->ecccalc; - unsigned int max_bitflips = 0; - - /* Read the OOB area first */ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); - if (stat == -EBADMSG && - (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { - /* check for empty pages with bitflips */ - stat = nand_check_erased_ecc_chunk(p, eccsize, - &ecc_code[i], eccbytes, - NULL, 0, - chip->ecc.strength); - } - - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - } - return max_bitflips; -} - -/** - * 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 - * @page: page number to read - * - * 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) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad; - uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - unsigned int max_bitflips = 0; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - - if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->ecc.hwctl(mtd, NAND_ECC_READSYN); - chip->read_buf(mtd, oob, eccbytes); - stat = chip->ecc.correct(mtd, p, oob, NULL); - - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - - if (stat == -EBADMSG && - (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { - /* check for empty pages with bitflips */ - stat = nand_check_erased_ecc_chunk(p, chip->ecc.size, - oob - eccpadbytes, - eccpadbytes, - NULL, 0, - chip->ecc.strength); - } - - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - } - - /* Calculate remaining oob bytes */ - i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->read_buf(mtd, oob, i); - - return max_bitflips; -} - -/** - * nand_transfer_oob - [INTERN] Transfer oob to client buffer - * @chip: nand chip structure - * @oob: oob destination address - * @ops: oob ops structure - * @len: size of oob to transfer - */ -static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, - struct mtd_oob_ops *ops, size_t len) -{ - switch (ops->mode) { - - case MTD_OPS_PLACE_OOB: - case MTD_OPS_RAW: - memcpy(oob, chip->oob_poi + ops->ooboffs, len); - return oob + len; - - case MTD_OPS_AUTO_OOB: { - struct nand_oobfree *free = chip->ecc.layout->oobfree; - uint32_t boffs = 0, roffs = ops->ooboffs; - size_t bytes = 0; - - for (; free->length && len; free++, len -= bytes) { - /* Read request not from offset 0? */ - if (unlikely(roffs)) { - if (roffs >= free->length) { - roffs -= free->length; - continue; - } - boffs = free->offset + roffs; - bytes = min_t(size_t, len, - (free->length - roffs)); - roffs = 0; - } else { - bytes = min_t(size_t, len, free->length); - boffs = free->offset; - } - memcpy(oob, chip->oob_poi + boffs, bytes); - oob += bytes; - } - return oob; - } - default: - BUG(); - } - return NULL; -} - -/** - * nand_setup_read_retry - [INTERN] Set the READ RETRY mode - * @mtd: MTD device structure - * @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) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - pr_debug("setting READ RETRY mode %d\n", retry_mode); - - if (retry_mode >= chip->read_retries) - return -EINVAL; - - if (!chip->setup_read_retry) - return -EOPNOTSUPP; - - return chip->setup_read_retry(mtd, retry_mode); -} - -/** - * nand_do_read_ops - [INTERN] Read data with ECC - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob ops structure - * - * Internal function. Called with chip held. - */ -static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - int chipnr, page, realpage, col, bytes, aligned, oob_required; - struct nand_chip *chip = mtd_to_nand(mtd); - int ret = 0; - uint32_t readlen = ops->len; - uint32_t oobreadlen = ops->ooblen; - uint32_t max_oobsize = mtd_oobavail(mtd, ops); - - uint8_t *bufpoi, *oob, *buf; - int use_bufpoi; - unsigned int max_bitflips = 0; - int retry_mode = 0; - bool ecc_fail = false; - - chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - realpage = (int)(from >> chip->page_shift); - page = realpage & chip->pagemask; - - col = (int)(from & (mtd->writesize - 1)); - - buf = ops->datbuf; - oob = ops->oobbuf; - oob_required = oob ? 1 : 0; - - while (1) { - unsigned int ecc_failures = mtd->ecc_stats.failed; - - WATCHDOG_RESET(); - bytes = min(mtd->writesize - col, readlen); - aligned = (bytes == mtd->writesize); - - if (!aligned) - use_bufpoi = 1; - else if (chip->options & NAND_USE_BOUNCE_BUFFER) - use_bufpoi = !IS_ALIGNED((unsigned long)buf, - chip->buf_align); - else - use_bufpoi = 0; - - /* Is the current page in the buffer? */ - if (realpage != chip->pagebuf || oob) { - bufpoi = use_bufpoi ? chip->buffers->databuf : buf; - - if (use_bufpoi && aligned) - pr_debug("%s: using read bounce buffer for buf@%p\n", - __func__, buf); - -read_retry: - if (nand_standard_page_accessors(&chip->ecc)) - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - - /* - * Now read the page into the buffer. Absent an error, - * 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, - oob_required, - page); - else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && - !oob) - ret = chip->ecc.read_subpage(mtd, chip, - col, bytes, bufpoi, - page); - else - ret = chip->ecc.read_page(mtd, chip, bufpoi, - oob_required, page); - if (ret < 0) { - if (use_bufpoi) - /* Invalidate page cache */ - chip->pagebuf = -1; - break; - } - - max_bitflips = max_t(unsigned int, max_bitflips, ret); - - /* Transfer not aligned data */ - if (use_bufpoi) { - if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && - !(mtd->ecc_stats.failed - ecc_failures) && - (ops->mode != MTD_OPS_RAW)) { - chip->pagebuf = realpage; - chip->pagebuf_bitflips = ret; - } else { - /* Invalidate page cache */ - chip->pagebuf = -1; - } - memcpy(buf, chip->buffers->databuf + col, bytes); - } - - if (unlikely(oob)) { - int toread = min(oobreadlen, max_oobsize); - - if (toread) { - oob = nand_transfer_oob(chip, - oob, ops, toread); - oobreadlen -= toread; - } - } - - 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); - } - - if (mtd->ecc_stats.failed - ecc_failures) { - if (retry_mode + 1 < chip->read_retries) { - retry_mode++; - ret = nand_setup_read_retry(mtd, - retry_mode); - if (ret < 0) - break; - - /* Reset failures; retry */ - mtd->ecc_stats.failed = ecc_failures; - goto read_retry; - } else { - /* No more retry modes; real failure */ - ecc_fail = true; - } - } - - buf += bytes; - } else { - memcpy(buf, chip->buffers->databuf + col, bytes); - buf += bytes; - max_bitflips = max_t(unsigned int, max_bitflips, - chip->pagebuf_bitflips); - } - - readlen -= bytes; - - /* Reset to retry mode 0 */ - if (retry_mode) { - ret = nand_setup_read_retry(mtd, 0); - if (ret < 0) - break; - retry_mode = 0; - } - - if (!readlen) - break; - - /* For subsequent reads align to page boundary */ - col = 0; - /* Increment page address */ - realpage++; - - page = realpage & chip->pagemask; - /* Check, if we cross a chip boundary */ - if (!page) { - chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); - } - } - chip->select_chip(mtd, -1); - - ops->retlen = ops->len - (size_t) readlen; - if (oob) - ops->oobretlen = ops->ooblen - oobreadlen; - - if (ret < 0) - return ret; - - if (ecc_fail) - return -EBADMSG; - - return max_bitflips; -} - -/** - * 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 - */ -static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; -} - -/** - * 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 - */ -static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - int length = mtd->oobsize; - int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; - int eccsize = chip->ecc.size; - uint8_t *bufpoi = chip->oob_poi; - int i, toread, sndrnd = 0, pos; - - chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page); - for (i = 0; i < chip->ecc.steps; i++) { - if (sndrnd) { - pos = eccsize + i * (eccsize + chunk); - if (mtd->writesize > 512) - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1); - else - chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page); - } else - sndrnd = 1; - toread = min_t(int, length, chunk); - chip->read_buf(mtd, bufpoi, toread); - bufpoi += toread; - length -= toread; - } - if (length > 0) - chip->read_buf(mtd, bufpoi, length); - - return 0; -} - -/** - * 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 - */ -static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - int status = 0; - const uint8_t *buf = chip->oob_poi; - int length = mtd->oobsize; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - chip->write_buf(mtd, buf, length); - /* Send command to program the OOB data */ - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - - status = chip->waitfunc(mtd, chip); - - return status & NAND_STATUS_FAIL ? -EIO : 0; -} - -/** - * 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 - */ -static int nand_write_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, int page) -{ - int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; - int eccsize = chip->ecc.size, length = mtd->oobsize; - int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps; - const uint8_t *bufpoi = chip->oob_poi; - - /* - * data-ecc-data-ecc ... ecc-oob - * or - * data-pad-ecc-pad-data-pad .... ecc-pad-oob - */ - if (!chip->ecc.prepad && !chip->ecc.postpad) { - pos = steps * (eccsize + chunk); - steps = 0; - } else - pos = eccsize; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); - for (i = 0; i < steps; i++) { - if (sndcmd) { - if (mtd->writesize <= 512) { - uint32_t fill = 0xFFFFFFFF; - - len = eccsize; - while (len > 0) { - int num = min_t(int, len, 4); - chip->write_buf(mtd, (uint8_t *)&fill, - num); - len -= num; - } - } else { - pos = eccsize + i * (eccsize + chunk); - chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1); - } - } else - sndcmd = 1; - len = min_t(int, length, chunk); - chip->write_buf(mtd, bufpoi, len); - bufpoi += len; - length -= len; - } - if (length > 0) - chip->write_buf(mtd, bufpoi, length); - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - - return status & NAND_STATUS_FAIL ? -EIO : 0; -} - -/** - * nand_do_read_oob - [INTERN] NAND read out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operations description structure - * - * NAND read out-of-band data from the spare area. - */ -static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - int page, realpage, chipnr; - struct nand_chip *chip = mtd_to_nand(mtd); - struct mtd_ecc_stats stats; - int readlen = ops->ooblen; - int len; - uint8_t *buf = ops->oobbuf; - int ret = 0; - - pr_debug("%s: from = 0x%08Lx, len = %i\n", - __func__, (unsigned long long)from, readlen); - - stats = mtd->ecc_stats; - - len = mtd_oobavail(mtd, ops); - - if (unlikely(ops->ooboffs >= len)) { - pr_debug("%s: attempt to start read outside oob\n", - __func__); - return -EINVAL; - } - - /* Do not allow reads past end of device */ - if (unlikely(from >= mtd->size || - ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - - (from >> chip->page_shift)) * len)) { - pr_debug("%s: attempt to read beyond end of device\n", - __func__); - return -EINVAL; - } - - chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* Shift to get page */ - realpage = (int)(from >> chip->page_shift); - page = realpage & chip->pagemask; - - while (1) { - WATCHDOG_RESET(); - - if (ops->mode == MTD_OPS_RAW) - ret = chip->ecc.read_oob_raw(mtd, chip, page); - else - ret = chip->ecc.read_oob(mtd, chip, page); - - if (ret < 0) - break; - - len = min(len, readlen); - buf = nand_transfer_oob(chip, 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); - } - - readlen -= len; - if (!readlen) - break; - - /* Increment page address */ - realpage++; - - page = realpage & chip->pagemask; - /* Check, if we cross a chip boundary */ - if (!page) { - chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); - } - } - chip->select_chip(mtd, -1); - - ops->oobretlen = ops->ooblen - readlen; - - if (ret < 0) - return ret; - - if (mtd->ecc_stats.failed - stats.failed) - return -EBADMSG; - - return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; -} - -/** - * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operation description structure - * - * NAND read data and/or out-of-band data. - */ -static int nand_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - int ret = -ENOTSUPP; - - ops->retlen = 0; - - /* Do not allow reads past end of device */ - if (ops->datbuf && (from + ops->len) > mtd->size) { - pr_debug("%s: attempt to read beyond end of device\n", - __func__); - return -EINVAL; - } - - nand_get_device(mtd, FL_READING); - - switch (ops->mode) { - case MTD_OPS_PLACE_OOB: - case MTD_OPS_AUTO_OOB: - case MTD_OPS_RAW: - break; - - default: - goto out; - } - - if (!ops->datbuf) - ret = nand_do_read_oob(mtd, from, ops); - else - ret = nand_do_read_ops(mtd, from, ops); - -out: - nand_release_device(mtd); - return ret; -} - - -/** - * 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 - * @page: page number to write - * - * Not for syndrome calculating ECC controllers, which use a special oob layout. - */ -static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) -{ - chip->write_buf(mtd, buf, mtd->writesize); - if (oob_required) - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -/** - * 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 - * @page: page number to write - * - * 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, - const uint8_t *buf, int oob_required, - int page) -{ - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - uint8_t *oob = chip->oob_poi; - int steps, size; - - for (steps = chip->ecc.steps; steps > 0; steps--) { - chip->write_buf(mtd, buf, eccsize); - buf += eccsize; - - if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->write_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->write_buf(mtd, oob, size); - - return 0; -} -/** - * 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) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers->ecccalc; - const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; - - /* Software ECC calculation */ - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - return chip->ecc.write_page_raw(mtd, 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) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers->ecccalc; - const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - chip->write_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - } - - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - - -/** - * 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 - * @buf: data buffer - * @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) -{ - uint8_t *oob_buf = chip->oob_poi; - uint8_t *ecc_calc = chip->buffers->ecccalc; - int ecc_size = chip->ecc.size; - int ecc_bytes = chip->ecc.bytes; - int ecc_steps = chip->ecc.steps; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint32_t start_step = offset / ecc_size; - uint32_t end_step = (offset + data_len - 1) / ecc_size; - int oob_bytes = mtd->oobsize / ecc_steps; - int step, i; - - for (step = 0; step < ecc_steps; step++) { - /* configure controller for WRITE access */ - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - - /* write data (untouched subpages already masked by 0xFF) */ - chip->write_buf(mtd, buf, ecc_size); - - /* mask ECC of un-touched subpages by padding 0xFF */ - if ((step < start_step) || (step > end_step)) - memset(ecc_calc, 0xff, ecc_bytes); - else - chip->ecc.calculate(mtd, buf, ecc_calc); - - /* mask OOB of un-touched subpages by padding 0xFF */ - /* if oob_required, preserve OOB metadata of written subpage */ - if (!oob_required || (step < start_step) || (step > end_step)) - memset(oob_buf, 0xff, oob_bytes); - - buf += ecc_size; - ecc_calc += ecc_bytes; - oob_buf += oob_bytes; - } - - /* copy calculated ECC for whole page to chip->buffer->oob */ - /* this include masked-value(0xFF) for unwritten subpages */ - ecc_calc = chip->buffers->ecccalc; - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - /* write OOB buffer to NAND device */ - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - - -/** - * 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 - * @page: page number to write - * - * 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) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - const uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - chip->write_buf(mtd, p, eccsize); - - if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->ecc.calculate(mtd, p, oob); - chip->write_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - /* Calculate remaining oob bytes */ - i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->write_buf(mtd, oob, i); - - return 0; -} - -/** - * nand_write_page - [REPLACEABLE] write one page - * @mtd: MTD device structure - * @chip: NAND chip descriptor - * @offset: address offset within the page - * @data_len: length of actual data to be written - * @buf: the data to write - * @oob_required: must write chip->oob_poi to OOB - * @page: page number to write - * @raw: use _raw version of write_page - */ -static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int raw) -{ - int status, subpage; - - if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && - chip->ecc.write_subpage) - subpage = offset || (data_len < mtd->writesize); - else - subpage = 0; - - if (nand_standard_page_accessors(&chip->ecc)) - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - - if (unlikely(raw)) - status = chip->ecc.write_page_raw(mtd, chip, buf, - oob_required, page); - else if (subpage) - status = chip->ecc.write_subpage(mtd, chip, offset, data_len, - buf, oob_required, page); - else - status = chip->ecc.write_page(mtd, chip, buf, oob_required, - page); - - if (status < 0) - return status; - - if (nand_standard_page_accessors(&chip->ecc)) { - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - - status = chip->waitfunc(mtd, chip); - if (status & NAND_STATUS_FAIL) - return -EIO; - } - - return 0; -} - -/** - * nand_fill_oob - [INTERN] Transfer client buffer to oob - * @mtd: MTD device structure - * @oob: oob data buffer - * @len: oob data write length - * @ops: oob ops structure - */ -static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - /* - * Initialise to all 0xFF, to avoid the possibility of left over OOB - * data from a previous OOB read. - */ - memset(chip->oob_poi, 0xff, mtd->oobsize); - - switch (ops->mode) { - - case MTD_OPS_PLACE_OOB: - case MTD_OPS_RAW: - memcpy(chip->oob_poi + ops->ooboffs, oob, len); - return oob + len; - - case MTD_OPS_AUTO_OOB: { - struct nand_oobfree *free = chip->ecc.layout->oobfree; - uint32_t boffs = 0, woffs = ops->ooboffs; - size_t bytes = 0; - - for (; free->length && len; free++, len -= bytes) { - /* Write request not from offset 0? */ - if (unlikely(woffs)) { - if (woffs >= free->length) { - woffs -= free->length; - continue; - } - boffs = free->offset + woffs; - bytes = min_t(size_t, len, - (free->length - woffs)); - woffs = 0; - } else { - bytes = min_t(size_t, len, free->length); - boffs = free->offset; - } - memcpy(chip->oob_poi + boffs, oob, bytes); - oob += bytes; - } - return oob; - } - default: - BUG(); - } - return NULL; -} - -#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) - -/** - * nand_do_write_ops - [INTERN] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operations description structure - * - * NAND write with ECC. - */ -static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - int chipnr, realpage, page, column; - struct nand_chip *chip = mtd_to_nand(mtd); - uint32_t writelen = ops->len; - - uint32_t oobwritelen = ops->ooblen; - uint32_t oobmaxlen = mtd_oobavail(mtd, ops); - - uint8_t *oob = ops->oobbuf; - uint8_t *buf = ops->datbuf; - int ret; - int oob_required = oob ? 1 : 0; - - ops->retlen = 0; - if (!writelen) - return 0; - - /* Reject writes, which are not page aligned */ - if (NOTALIGNED(to)) { - pr_notice("%s: attempt to write non page aligned data\n", - __func__); - return -EINVAL; - } - - column = to & (mtd->writesize - 1); - - chipnr = (int)(to >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - ret = -EIO; - goto err_out; - } - - realpage = (int)(to >> chip->page_shift); - page = realpage & chip->pagemask; - - /* Invalidate the page cache, when we write to the cached page */ - if (to <= ((loff_t)chip->pagebuf << chip->page_shift) && - ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len)) - chip->pagebuf = -1; - - /* Don't allow multipage oob writes with offset */ - if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) { - ret = -EINVAL; - goto err_out; - } - - while (1) { - int bytes = mtd->writesize; - uint8_t *wbuf = buf; - int use_bufpoi; - int part_pagewr = (column || writelen < mtd->writesize); - - if (part_pagewr) - use_bufpoi = 1; - else if (chip->options & NAND_USE_BOUNCE_BUFFER) - use_bufpoi = !IS_ALIGNED((unsigned long)buf, - chip->buf_align); - else - use_bufpoi = 0; - - WATCHDOG_RESET(); - /* Partial page write?, or need to use bounce buffer */ - if (use_bufpoi) { - pr_debug("%s: using write bounce buffer for buf@%p\n", - __func__, buf); - if (part_pagewr) - bytes = min_t(int, bytes - column, writelen); - chip->pagebuf = -1; - memset(chip->buffers->databuf, 0xff, mtd->writesize); - memcpy(&chip->buffers->databuf[column], buf, bytes); - wbuf = chip->buffers->databuf; - } - - if (unlikely(oob)) { - size_t len = min(oobwritelen, oobmaxlen); - oob = nand_fill_oob(mtd, oob, len, ops); - oobwritelen -= len; - } else { - /* We still need to erase leftover OOB data */ - memset(chip->oob_poi, 0xff, mtd->oobsize); - } - ret = chip->write_page(mtd, chip, column, bytes, wbuf, - oob_required, page, - (ops->mode == MTD_OPS_RAW)); - if (ret) - break; - - writelen -= bytes; - if (!writelen) - break; - - column = 0; - buf += bytes; - realpage++; - - page = realpage & chip->pagemask; - /* Check, if we cross a chip boundary */ - if (!page) { - chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); - } - } - - ops->retlen = ops->len - writelen; - if (unlikely(oob)) - ops->oobretlen = ops->ooblen; - -err_out: - chip->select_chip(mtd, -1); - return ret; -} - -/** - * panic_nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write - * - * NAND write with ECC. Used when performing writes in interrupt context, this - * may for example be called by mtdoops when writing an oops while in panic. - */ -static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct mtd_oob_ops ops; - int ret; - - /* Wait for the device to get ready */ - panic_nand_wait(mtd, chip, 400); - - /* Grab the device */ - panic_nand_get_device(chip, mtd, FL_WRITING); - - memset(&ops, 0, sizeof(ops)); - ops.len = len; - ops.datbuf = (uint8_t *)buf; - ops.mode = MTD_OPS_PLACE_OOB; - - ret = nand_do_write_ops(mtd, to, &ops); - - *retlen = ops.retlen; - return ret; -} - -/** - * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure - * - * NAND write out-of-band. - */ -static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - int chipnr, page, status, len; - struct nand_chip *chip = mtd_to_nand(mtd); - - pr_debug("%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int)to, (int)ops->ooblen); - - len = mtd_oobavail(mtd, ops); - - /* Do not allow write past end of page */ - if ((ops->ooboffs + ops->ooblen) > len) { - pr_debug("%s: attempt to write past end of page\n", - __func__); - return -EINVAL; - } - - if (unlikely(ops->ooboffs >= len)) { - pr_debug("%s: attempt to start write outside oob\n", - __func__); - return -EINVAL; - } - - /* Do not allow write past end of device */ - if (unlikely(to >= mtd->size || - ops->ooboffs + ops->ooblen > - ((mtd->size >> chip->page_shift) - - (to >> chip->page_shift)) * len)) { - pr_debug("%s: attempt to write beyond end of device\n", - __func__); - return -EINVAL; - } - - chipnr = (int)(to >> chip->chip_shift); - - /* - * Reset the chip. Some chips (like the Toshiba TC5832DC found in one - * of my DiskOnChip 2000 test units) will clear the whole data page too - * if we don't do this. I have no clue why, but I seem to have 'fixed' - * it in the doc2000 driver in August 1999. dwmw2. - */ - nand_reset(chip, chipnr); - - chip->select_chip(mtd, 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); - return -EROFS; - } - - /* Invalidate the page cache, if we write to the cached page */ - if (page == chip->pagebuf) - chip->pagebuf = -1; - - 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); - else - status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); - - chip->select_chip(mtd, -1); - - if (status) - return status; - - ops->oobretlen = ops->ooblen; - - return 0; -} - -/** - * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure - */ -static int nand_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - int ret = -ENOTSUPP; - - ops->retlen = 0; - - /* Do not allow writes past end of device */ - if (ops->datbuf && (to + ops->len) > mtd->size) { - pr_debug("%s: attempt to write beyond end of device\n", - __func__); - return -EINVAL; - } - - nand_get_device(mtd, FL_WRITING); - - switch (ops->mode) { - case MTD_OPS_PLACE_OOB: - case MTD_OPS_AUTO_OOB: - case MTD_OPS_RAW: - break; - - default: - goto out; - } - - if (!ops->datbuf) - ret = nand_do_write_oob(mtd, to, ops); - else - ret = nand_do_write_ops(mtd, to, ops); - -out: - nand_release_device(mtd); - return ret; -} - -/** - * single_erase - [GENERIC] NAND standard block erase command function - * @mtd: MTD device structure - * @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) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - /* Send commands to erase a block */ - chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); - chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); - - return chip->waitfunc(mtd, chip); -} - -/** - * nand_erase - [MTD Interface] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction - * - * Erase one ore more blocks. - */ -static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) -{ - return nand_erase_nand(mtd, instr, 0); -} - -/** - * nand_erase_nand - [INTERN] erase block(s) - * @mtd: MTD device structure - * @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 allowbbt) -{ - 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", - __func__, (unsigned long long)instr->addr, - (unsigned long long)instr->len); - - if (check_offs_len(mtd, instr->addr, instr->len)) - return -EINVAL; - - /* Grab the lock and see if the device is available */ - nand_get_device(mtd, FL_ERASING); - - /* Shift to get first page */ - page = (int)(instr->addr >> chip->page_shift); - chipnr = (int)(instr->addr >> chip->chip_shift); - - /* Calculate pages in each block */ - pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); - - /* Select the NAND device */ - chip->select_chip(mtd, chipnr); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - pr_debug("%s: device is write protected!\n", - __func__); - instr->state = MTD_ERASE_FAILED; - goto erase_exit; - } - - /* Loop through the pages */ - len = instr->len; - - instr->state = MTD_ERASING; - - while (len) { - WATCHDOG_RESET(); - - /* Check if we have a bad block, we do not erase bad blocks! */ - if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) << - chip->page_shift, allowbbt)) { - pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", - __func__, page); - instr->state = MTD_ERASE_FAILED; - goto erase_exit; - } - - /* - * Invalidate the page cache, if we erase the block which - * contains the current cached page. - */ - if (page <= chip->pagebuf && chip->pagebuf < - (page + pages_per_block)) - chip->pagebuf = -1; - - status = chip->erase(mtd, page & chip->pagemask); - - /* See if block erase succeeded */ - if (status & NAND_STATUS_FAIL) { - pr_debug("%s: failed erase, page 0x%08x\n", - __func__, page); - instr->state = MTD_ERASE_FAILED; - instr->fail_addr = - ((loff_t)page << chip->page_shift); - goto erase_exit; - } - - /* Increment page address and decrement length */ - len -= (1ULL << chip->phys_erase_shift); - page += pages_per_block; - - /* Check, if we cross a chip boundary */ - if (len && !(page & chip->pagemask)) { - chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); - } - } - instr->state = MTD_ERASE_DONE; - -erase_exit: - - ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; - - /* Deselect and wake up anyone waiting on the device */ - chip->select_chip(mtd, -1); - nand_release_device(mtd); - - /* Do call back function */ - if (!ret) - mtd_erase_callback(instr); - - /* Return more or less happy */ - return ret; -} - -/** - * nand_sync - [MTD Interface] sync - * @mtd: MTD device structure - * - * Sync is actually a wait for chip ready function. - */ -static void nand_sync(struct mtd_info *mtd) -{ - pr_debug("%s: called\n", __func__); - - /* Grab the lock and see if the device is available */ - nand_get_device(mtd, FL_SYNCING); - /* Release it and go back */ - nand_release_device(mtd); -} - -/** - * nand_block_isbad - [MTD Interface] Check if block at offset is bad - * @mtd: MTD device structure - * @offs: offset relative to mtd start - */ -static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int chipnr = (int)(offs >> chip->chip_shift); - int ret; - - /* Select the NAND device */ - nand_get_device(mtd, FL_READING); - chip->select_chip(mtd, chipnr); - - ret = nand_block_checkbad(mtd, offs, 0); - - chip->select_chip(mtd, -1); - nand_release_device(mtd); - - return ret; -} - -/** - * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad - * @mtd: MTD device structure - * @ofs: offset relative to mtd start - */ -static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) -{ - int ret; - - ret = nand_block_isbad(mtd, ofs); - if (ret) { - /* If it was bad already, return success and do nothing */ - if (ret > 0) - return 0; - return ret; - } - - return nand_block_markbad_lowlevel(mtd, ofs); -} - -/** - * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand - * @mtd: MTD device structure - * @chip: nand chip info structure - * @addr: feature address. - * @subfeature_param: the subfeature parameters, a four bytes array. - */ -static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, uint8_t *subfeature_param) -{ - int status; - int i; - -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION - if (!chip->onfi_version || - !(le16_to_cpu(chip->onfi_params.opt_cmd) - & ONFI_OPT_CMD_SET_GET_FEATURES)) - return -ENOTSUPP; -#endif - - chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); - for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) - chip->write_byte(mtd, subfeature_param[i]); - - status = chip->waitfunc(mtd, chip); - if (status & NAND_STATUS_FAIL) - return -EIO; - return 0; -} - -/** - * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand - * @mtd: MTD device structure - * @chip: nand chip info structure - * @addr: feature address. - * @subfeature_param: the subfeature parameters, a four bytes array. - */ -static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, uint8_t *subfeature_param) -{ - int i; - -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION - if (!chip->onfi_version || - !(le16_to_cpu(chip->onfi_params.opt_cmd) - & ONFI_OPT_CMD_SET_GET_FEATURES)) - return -ENOTSUPP; -#endif - - chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); - for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) - *subfeature_param++ = chip->read_byte(mtd); - return 0; -} - -/* Set default functions */ -static void nand_set_defaults(struct nand_chip *chip, int busw) -{ - /* 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 == NULL) - 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->onfi_set_features) - chip->onfi_set_features = nand_onfi_set_features; - if (!chip->onfi_get_features) - chip->onfi_get_features = nand_onfi_get_features; - - /* If called twice, pointers that depend on busw may need to be reset */ - if (!chip->read_byte || chip->read_byte == nand_read_byte) - chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; - 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; - if (!chip->scan_bbt) - chip->scan_bbt = nand_default_bbt; - - if (!chip->controller) { - chip->controller = &chip->hwcontrol; - spin_lock_init(&chip->controller->lock); - init_waitqueue_head(&chip->controller->wq); - } - - if (!chip->buf_align) - chip->buf_align = 1; -} - -/* Sanitize ONFI strings so we can safely print them */ -static void sanitize_string(char *s, size_t len) -{ - ssize_t i; - - /* Null terminate */ - s[len - 1] = 0; - - /* Remove non printable chars */ - for (i = 0; i < len - 1; i++) { - if (s[i] < ' ' || s[i] > 127) - s[i] = '?'; - } - - /* Remove trailing spaces */ - 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; -} - -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION -/* Parse the Extended Parameter Page. */ -static int nand_flash_detect_ext_param_page(struct mtd_info *mtd, - struct nand_chip *chip, struct nand_onfi_params *p) -{ - struct onfi_ext_param_page *ep; - struct onfi_ext_section *s; - struct onfi_ext_ecc_info *ecc; - uint8_t *cursor; - int ret = -EINVAL; - int len; - int i; - - len = le16_to_cpu(p->ext_param_page_length) * 16; - ep = kmalloc(len, GFP_KERNEL); - if (!ep) - return -ENOMEM; - - /* Send our own NAND_CMD_PARAM. */ - chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); - - /* Use the Change Read Column command to skip the ONFI param pages. */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, - sizeof(*p) * p->num_of_param_pages , -1); - - /* Read out the Extended Parameter Page. */ - chip->read_buf(mtd, (uint8_t *)ep, len); - if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2) - != le16_to_cpu(ep->crc))) { - pr_debug("fail in the CRC.\n"); - goto ext_out; - } - - /* - * Check the signature. - * Do not strictly follow the ONFI spec, maybe changed in future. - */ - if (strncmp((char *)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; -} - -static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; - - return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, - feature); -} - -/* - * Configure chip properties from Micron vendor-specific ONFI table - */ -static void nand_onfi_detect_micron(struct nand_chip *chip, - struct nand_onfi_params *p) -{ - struct nand_onfi_vendor_micron *micron = (void *)p->vendor; - - if (le16_to_cpu(p->vendor_revision) < 1) - return; - - chip->read_retries = micron->read_retry_options; - chip->setup_read_retry = nand_setup_read_retry_micron; -} - -/* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. - */ -static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, - int *busw) -{ - struct nand_onfi_params *p = &chip->onfi_params; - int i, j; - int val; - - /* Try ONFI for unknown chip or LP */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); - if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || - chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') - return 0; - - chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); - for (i = 0; i < 3; i++) { - for (j = 0; j < sizeof(*p); j++) - ((uint8_t *)p)[j] = chip->read_byte(mtd); - if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == - le16_to_cpu(p->crc)) { - break; - } - } - - if (i == 3) { - pr_err("Could not find valid ONFI parameter page; aborting\n"); - return 0; - } - - /* Check version */ - val = le16_to_cpu(p->revision); - if (val & (1 << 5)) - chip->onfi_version = 23; - else if (val & (1 << 4)) - chip->onfi_version = 22; - else if (val & (1 << 3)) - chip->onfi_version = 21; - else if (val & (1 << 2)) - chip->onfi_version = 20; - else if (val & (1 << 1)) - chip->onfi_version = 10; - - if (!chip->onfi_version) { - pr_info("unsupported ONFI version: %d\n", val); - return 0; - } - - sanitize_string(p->manufacturer, sizeof(p->manufacturer)); - sanitize_string(p->model, sizeof(p->model)); - if (!mtd->name) - mtd->name = p->model; - - 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; - - if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS) - *busw = NAND_BUSWIDTH_16; - else - *busw = 0; - - if (p->ecc_bits != 0xff) { - chip->ecc_strength_ds = p->ecc_bits; - chip->ecc_step_ds = 512; - } else if (chip->onfi_version >= 21 && - (onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) { - - /* - * The nand_flash_detect_ext_param_page() uses the - * Change Read Column command which maybe not supported - * by the chip->cmdfunc. So try to update the chip->cmdfunc - * now. We do not replace user supplied command function. - */ - if (mtd->writesize > 512 && chip->cmdfunc == nand_command) - chip->cmdfunc = nand_command_lp; - - /* The Extended Parameter Page is supported since ONFI 2.1. */ - if (nand_flash_detect_ext_param_page(mtd, chip, p)) - pr_warn("Failed to detect ONFI extended param page\n"); - } else { - pr_warn("Could not retrieve ONFI ECC requirements\n"); - } - - if (p->jedec_id == NAND_MFR_MICRON) - nand_onfi_detect_micron(chip, p); - - return 1; -} -#else -static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, - int *busw) -{ - return 0; -} -#endif - -/* - * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise. - */ -static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip, - int *busw) -{ - struct nand_jedec_params *p = &chip->jedec_params; - struct jedec_ecc_info *ecc; - int val; - int i, j; - - /* Try JEDEC for unknown chip or LP */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1); - if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' || - chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' || - chip->read_byte(mtd) != 'C') - return 0; - - chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1); - for (i = 0; i < 3; i++) { - for (j = 0; j < sizeof(*p); j++) - ((uint8_t *)p)[j] = chip->read_byte(mtd); - - 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"); - return 0; - } - - /* Check version */ - val = le16_to_cpu(p->revision); - if (val & (1 << 2)) - chip->jedec_version = 10; - else if (val & (1 << 1)) - chip->jedec_version = 1; /* vendor specific version */ - - if (!chip->jedec_version) { - pr_info("unsupported JEDEC version: %d\n", val); - return 0; - } - - sanitize_string(p->manufacturer, sizeof(p->manufacturer)); - sanitize_string(p->model, sizeof(p->model)); - if (!mtd->name) - mtd->name = p->model; - - 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 (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS) - *busw = NAND_BUSWIDTH_16; - else - *busw = 0; - - /* 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"); - } - - return 1; -} - -/* - * nand_id_has_period - Check if an ID string has a given wraparound period - * @id_data: the ID string - * @arrlen: the length of the @id_data array - * @period: the period of repitition - * - * Check if an ID string is repeated within a given sequence of bytes at - * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a - * period of 3). This is a helper function for nand_id_len(). Returns non-zero - * if the repetition has a period of @period; otherwise, returns zero. - */ -static int nand_id_has_period(u8 *id_data, int arrlen, int period) -{ - int i, j; - for (i = 0; i < period; i++) - for (j = i + period; j < arrlen; j += period) - if (id_data[i] != id_data[j]) - return 0; - return 1; -} - -/* - * nand_id_len - Get the length of an ID string returned by CMD_READID - * @id_data: the ID string - * @arrlen: the length of the @id_data array - - * Returns the length of the ID string, according to known wraparound/trailing - * zero patterns. If no pattern exists, returns the length of the array. - */ -static int nand_id_len(u8 *id_data, int arrlen) -{ - int last_nonzero, period; - - /* Find last non-zero byte */ - for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--) - if (id_data[last_nonzero]) - break; - - /* All zeros */ - if (last_nonzero < 0) - return 0; - - /* Calculate wraparound period */ - for (period = 1; period < arrlen; period++) - if (nand_id_has_period(id_data, arrlen, period)) - break; - - /* There's a repeated pattern */ - if (period < arrlen) - return period; - - /* There are trailing zeros */ - if (last_nonzero < arrlen - 1) - return last_nonzero + 1; - - /* No pattern detected */ - return arrlen; -} - -/* Extract the bits of per cell from the 3rd byte of the extended ID */ -static int nand_get_bits_per_cell(u8 cellinfo) -{ - int bits; - - bits = cellinfo & NAND_CI_CELLTYPE_MSK; - bits >>= NAND_CI_CELLTYPE_SHIFT; - return bits + 1; -} - -/* - * Many new NAND share similar device ID codes, which represent the size of the - * chip. The rest of the parameters must be decoded according to generic or - * manufacturer-specific "extended ID" decoding patterns. - */ -static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, - u8 id_data[8], int *busw) -{ - int extid, id_len; - /* The 3rd id byte holds MLC / multichip data */ - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); - /* The 4th id byte is the important one */ - extid = id_data[3]; - - id_len = nand_id_len(id_data, 8); - - /* - * Field definitions are in the following datasheets: - * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) - * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) - * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22) - * - * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung - * ID to decide what to do. - */ - if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG && - !nand_is_slc(chip) && id_data[5] != 0x00) { - /* Calc pagesize */ - mtd->writesize = 2048 << (extid & 0x03); - extid >>= 2; - /* Calc oobsize */ - switch (((extid >> 2) & 0x04) | (extid & 0x03)) { - case 1: - mtd->oobsize = 128; - break; - case 2: - mtd->oobsize = 218; - break; - case 3: - mtd->oobsize = 400; - break; - case 4: - mtd->oobsize = 436; - break; - case 5: - mtd->oobsize = 512; - break; - case 6: - mtd->oobsize = 640; - break; - case 7: - default: /* Other cases are "reserved" (unknown) */ - mtd->oobsize = 1024; - break; - } - extid >>= 2; - /* Calc blocksize */ - mtd->erasesize = (128 * 1024) << - (((extid >> 1) & 0x04) | (extid & 0x03)); - *busw = 0; - } else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX && - !nand_is_slc(chip)) { - unsigned int tmp; - - /* Calc pagesize */ - mtd->writesize = 2048 << (extid & 0x03); - extid >>= 2; - /* Calc oobsize */ - switch (((extid >> 2) & 0x04) | (extid & 0x03)) { - case 0: - mtd->oobsize = 128; - break; - case 1: - mtd->oobsize = 224; - break; - case 2: - mtd->oobsize = 448; - break; - case 3: - mtd->oobsize = 64; - break; - case 4: - mtd->oobsize = 32; - break; - case 5: - mtd->oobsize = 16; - break; - default: - mtd->oobsize = 640; - break; - } - extid >>= 2; - /* Calc blocksize */ - tmp = ((extid >> 1) & 0x04) | (extid & 0x03); - if (tmp < 0x03) - mtd->erasesize = (128 * 1024) << tmp; - else if (tmp == 0x03) - mtd->erasesize = 768 * 1024; - else - mtd->erasesize = (64 * 1024) << tmp; - *busw = 0; - } else { - /* Calc pagesize */ - mtd->writesize = 1024 << (extid & 0x03); - extid >>= 2; - /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x01)) * - (mtd->writesize >> 9); - extid >>= 2; - /* Calc blocksize. Blocksize is multiples of 64KiB */ - mtd->erasesize = (64 * 1024) << (extid & 0x03); - extid >>= 2; - /* Get buswidth information */ - *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; - - /* - * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per - * 512B page. For Toshiba SLC, we decode the 5th/6th byte as - * follows: - * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm, - * 110b -> 24nm - * - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC - */ - if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA && - nand_is_slc(chip) && - (id_data[5] & 0x7) == 0x6 /* 24nm */ && - !(id_data[4] & 0x80) /* !BENAND */) { - mtd->oobsize = 32 * mtd->writesize >> 9; - } - - } -} - -/* - * Old devices have chip data hardcoded in the device ID table. nand_decode_id - * decodes a matching ID table entry and assigns the MTD size parameters for - * the chip. - */ -static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip, - struct nand_flash_dev *type, u8 id_data[8], - int *busw) -{ - int maf_id = id_data[0]; - - mtd->erasesize = type->erasesize; - mtd->writesize = type->pagesize; - mtd->oobsize = mtd->writesize / 32; - *busw = type->options & NAND_BUSWIDTH_16; - - /* All legacy ID NAND are small-page, SLC */ - chip->bits_per_cell = 1; - - /* - * Check for Spansion/AMD ID + repeating 5th, 6th byte since - * some Spansion chips have erasesize that conflicts with size - * listed in nand_ids table. - * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) - */ - if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00 - && id_data[6] == 0x00 && id_data[7] == 0x00 - && mtd->writesize == 512) { - mtd->erasesize = 128 * 1024; - mtd->erasesize <<= ((id_data[3] & 0x03) << 1); - } -} - -/* - * Set the bad block marker/indicator (BBM/BBI) patterns according to some - * heuristic patterns using various detected parameters (e.g., manufacturer, - * page size, cell-type information). - */ -static void nand_decode_bbm_options(struct mtd_info *mtd, - struct nand_chip *chip, u8 id_data[8]) -{ - int maf_id = id_data[0]; - - /* Set the bad block position */ - if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) - chip->badblockpos = NAND_LARGE_BADBLOCK_POS; - else - chip->badblockpos = NAND_SMALL_BADBLOCK_POS; - - /* - * Bad block marker is stored in the last page of each block on Samsung - * and Hynix MLC devices; stored in first two pages of each block on - * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba, - * AMD/Spansion, and Macronix. All others scan only the first page. - */ - if (!nand_is_slc(chip) && - (maf_id == NAND_MFR_SAMSUNG || - maf_id == NAND_MFR_HYNIX)) - chip->bbt_options |= NAND_BBT_SCANLASTPAGE; - else if ((nand_is_slc(chip) && - (maf_id == NAND_MFR_SAMSUNG || - maf_id == NAND_MFR_HYNIX || - maf_id == NAND_MFR_TOSHIBA || - maf_id == NAND_MFR_AMD || - maf_id == NAND_MFR_MACRONIX)) || - (mtd->writesize == 2048 && - maf_id == NAND_MFR_MICRON)) - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; -} - -static inline bool is_full_id_nand(struct nand_flash_dev *type) -{ - return type->id_len; -} - -static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, - struct nand_flash_dev *type, u8 *id_data, int *busw) -{ - if (!strncmp((char *)type->id, (char *)id_data, type->id_len)) { - mtd->writesize = type->pagesize; - mtd->erasesize = type->erasesize; - mtd->oobsize = type->oobsize; - - chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); - chip->chipsize = (uint64_t)type->chipsize << 20; - chip->options |= type->options; - chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); - chip->ecc_step_ds = NAND_ECC_STEP(type); - chip->onfi_timing_mode_default = - type->onfi_timing_mode_default; - - *busw = type->options & NAND_BUSWIDTH_16; - - if (!mtd->name) - mtd->name = type->name; - - return true; - } - return false; -} - -/* - * Get the flash and manufacturer id and lookup if the type is supported. - */ -struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, - struct nand_chip *chip, - int *maf_id, int *dev_id, - struct nand_flash_dev *type) -{ - int busw; - int i, maf_idx; - u8 id_data[8]; - - /* - * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) - * after power-up. - */ - nand_reset(chip, 0); - - /* Select the device */ - chip->select_chip(mtd, 0); - - /* Send the command for reading device ID */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - /* Read manufacturer and device IDs */ - *maf_id = chip->read_byte(mtd); - *dev_id = chip->read_byte(mtd); - - /* - * Try again to make sure, as some systems the bus-hold or other - * interface concerns can cause random data which looks like a - * possibly credible NAND flash to appear. If the two results do - * not match, ignore the device completely. - */ - - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - /* Read entire ID string */ - for (i = 0; i < 8; i++) - id_data[i] = chip->read_byte(mtd); - - if (id_data[0] != *maf_id || id_data[1] != *dev_id) { - pr_info("second ID read did not match %02x,%02x against %02x,%02x\n", - *maf_id, *dev_id, id_data[0], id_data[1]); - return ERR_PTR(-ENODEV); - } - - if (!type) - type = nand_flash_ids; - - for (; type->name != NULL; type++) { - if (is_full_id_nand(type)) { - if (find_full_id_nand(mtd, chip, type, id_data, &busw)) - goto ident_done; - } else if (*dev_id == type->dev_id) { - break; - } - } - - chip->onfi_version = 0; - if (!type->name || !type->pagesize) { - /* Check if the chip is ONFI compliant */ - if (nand_flash_detect_onfi(mtd, chip, &busw)) - goto ident_done; - - /* Check if the chip is JEDEC compliant */ - if (nand_flash_detect_jedec(mtd, chip, &busw)) - goto ident_done; - } - - if (!type->name) - return ERR_PTR(-ENODEV); - - if (!mtd->name) - mtd->name = type->name; - - chip->chipsize = (uint64_t)type->chipsize << 20; - - if (!type->pagesize) { - /* Decode parameters from extended ID */ - nand_decode_ext_id(mtd, chip, id_data, &busw); - } else { - nand_decode_id(mtd, chip, type, id_data, &busw); - } - /* Get chip options */ - chip->options |= type->options; - - /* - * Check if chip is not a Samsung device. Do not clear the - * options for chips which do not have an extended id. - */ - if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) - chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; -ident_done: - - /* Try to identify manufacturer */ - for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { - if (nand_manuf_ids[maf_idx].id == *maf_id) - break; - } - - if (chip->options & NAND_BUSWIDTH_AUTO) { - WARN_ON(chip->options & NAND_BUSWIDTH_16); - chip->options |= busw; - nand_set_defaults(chip, busw); - } else if (busw != (chip->options & NAND_BUSWIDTH_16)) { - /* - * Check, if buswidth is correct. Hardware drivers should set - * chip correct! - */ - pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", - *maf_id, *dev_id); - pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name); - pr_warn("bus width %d instead %d bit\n", - (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); - return ERR_PTR(-EINVAL); - } - - nand_decode_bbm_options(mtd, chip, id_data); - - /* Calculate the address shift from the page size */ - chip->page_shift = ffs(mtd->writesize) - 1; - /* Convert chipsize to number of pages per chip -1 */ - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; - - chip->bbt_erase_shift = chip->phys_erase_shift = - ffs(mtd->erasesize) - 1; - if (chip->chipsize & 0xffffffff) - chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; - else { - chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); - chip->chip_shift += 32 - 1; - } - - if (chip->chip_shift - chip->page_shift > 16) - 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; - - pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", - *maf_id, *dev_id); - -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION - if (chip->onfi_version) - pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, - chip->onfi_params.model); - else if (chip->jedec_version) - pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, - chip->jedec_params.model); - else - pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, - type->name); -#else - if (chip->jedec_version) - pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, - chip->jedec_params.model); - else - pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, - type->name); - - pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, - type->name); -#endif - - pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n", - (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", - mtd->erasesize >> 10, mtd->writesize, mtd->oobsize); - return type; -} -EXPORT_SYMBOL(nand_get_flash_type); - -#if CONFIG_IS_ENABLED(OF_CONTROL) -DECLARE_GLOBAL_DATA_PTR; - -static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, int node) -{ - int ret, ecc_mode = -1, ecc_strength, ecc_step; - const void *blob = gd->fdt_blob; - const char *str; - - ret = fdtdec_get_int(blob, node, "nand-bus-width", -1); - if (ret == 16) - chip->options |= NAND_BUSWIDTH_16; - - if (fdtdec_get_bool(blob, node, "nand-on-flash-bbt")) - chip->bbt_options |= NAND_BBT_USE_FLASH; - - str = fdt_getprop(blob, node, "nand-ecc-mode", NULL); - if (str) { - if (!strcmp(str, "none")) - ecc_mode = NAND_ECC_NONE; - else if (!strcmp(str, "soft")) - ecc_mode = NAND_ECC_SOFT; - else if (!strcmp(str, "hw")) - ecc_mode = NAND_ECC_HW; - else if (!strcmp(str, "hw_syndrome")) - ecc_mode = NAND_ECC_HW_SYNDROME; - else if (!strcmp(str, "hw_oob_first")) - ecc_mode = NAND_ECC_HW_OOB_FIRST; - else if (!strcmp(str, "soft_bch")) - ecc_mode = NAND_ECC_SOFT_BCH; - } - - - ecc_strength = fdtdec_get_int(blob, node, "nand-ecc-strength", -1); - ecc_step = fdtdec_get_int(blob, node, "nand-ecc-step-size", -1); - - if ((ecc_step >= 0 && !(ecc_strength >= 0)) || - (!(ecc_step >= 0) && ecc_strength >= 0)) { - pr_err("must set both strength and step size in DT\n"); - return -EINVAL; - } - - if (ecc_mode >= 0) - chip->ecc.mode = ecc_mode; - - if (ecc_strength >= 0) - chip->ecc.strength = ecc_strength; - - if (ecc_step > 0) - chip->ecc.size = ecc_step; - - if (fdt_getprop(blob, node, "nand-ecc-maximize", NULL)) - chip->ecc.options |= NAND_ECC_MAXIMIZE; - - return 0; -} -#else -static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, int node) -{ - return 0; -} -#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ - -/** - * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: number of chips to scan for - * @table: alternative NAND ID table - * - * This is the first phase of the normal nand_scan() function. It reads the - * flash ID and sets up MTD fields accordingly. - * - */ -int nand_scan_ident(struct mtd_info *mtd, int maxchips, - struct nand_flash_dev *table) -{ - int i, nand_maf_id, nand_dev_id; - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_flash_dev *type; - int ret; - - if (chip->flash_node) { - ret = nand_dt_init(mtd, chip, chip->flash_node); - if (ret) - return ret; - } - - /* Set the default functions */ - nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16); - - /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, &nand_maf_id, - &nand_dev_id, table); - - if (IS_ERR(type)) { - if (!(chip->options & NAND_SCAN_SILENT_NODEV)) - pr_warn("No NAND device found\n"); - chip->select_chip(mtd, -1); - return PTR_ERR(type); - } - - /* Initialize the ->data_interface field. */ - ret = nand_init_data_interface(chip); - if (ret) - return ret; - - /* - * Setup the data interface correctly on the chip and controller side. - * This explicit call to nand_setup_data_interface() is only required - * for the first die, because nand_reset() has been called before - * ->data_interface and ->default_onfi_timing_mode were set. - * For the other dies, nand_reset() will automatically switch to the - * best mode for us. - */ - ret = nand_setup_data_interface(chip, 0); - if (ret) - return ret; - - chip->select_chip(mtd, -1); - - /* Check for a chip array */ - for (i = 1; i < maxchips; i++) { - /* See comment in nand_get_flash_type for reset */ - nand_reset(chip, i); - - chip->select_chip(mtd, i); - /* Send the command for reading device ID */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - /* Read manufacturer and device IDs */ - if (nand_maf_id != chip->read_byte(mtd) || - nand_dev_id != chip->read_byte(mtd)) { - chip->select_chip(mtd, -1); - break; - } - chip->select_chip(mtd, -1); - } - -#ifdef DEBUG - if (i > 1) - pr_info("%d chips detected\n", i); -#endif - - /* Store the number of chips and calc total size for mtd */ - chip->numchips = i; - mtd->size = i * chip->chipsize; - - return 0; -} -EXPORT_SYMBOL(nand_scan_ident); - -/** - * nand_check_ecc_caps - check the sanity of preset ECC settings - * @chip: nand chip info structure - * @caps: ECC caps info structure - * @oobavail: OOB size that the ECC engine can use - * - * When ECC step size and strength are already set, check if they are supported - * by the controller and the calculated ECC bytes fit within the chip's OOB. - * On success, the calculated ECC bytes is set. - */ -int nand_check_ecc_caps(struct nand_chip *chip, - const struct nand_ecc_caps *caps, int oobavail) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - const struct nand_ecc_step_info *stepinfo; - int preset_step = chip->ecc.size; - int preset_strength = chip->ecc.strength; - int nsteps, ecc_bytes; - int i, j; - - if (WARN_ON(oobavail < 0)) - return -EINVAL; - - if (!preset_step || !preset_strength) - return -ENODATA; - - nsteps = mtd->writesize / preset_step; - - for (i = 0; i < caps->nstepinfos; i++) { - stepinfo = &caps->stepinfos[i]; - - if (stepinfo->stepsize != preset_step) - continue; - - for (j = 0; j < stepinfo->nstrengths; j++) { - if (stepinfo->strengths[j] != preset_strength) - continue; - - ecc_bytes = caps->calc_ecc_bytes(preset_step, - preset_strength); - if (WARN_ON_ONCE(ecc_bytes < 0)) - return ecc_bytes; - - if (ecc_bytes * nsteps > oobavail) { - pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB", - preset_step, preset_strength); - return -ENOSPC; - } - - chip->ecc.bytes = ecc_bytes; - - return 0; - } - } - - pr_err("ECC (step, strength) = (%d, %d) not supported on this controller", - preset_step, preset_strength); - - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(nand_check_ecc_caps); - -/** - * nand_match_ecc_req - meet the chip's requirement with least ECC bytes - * @chip: nand chip info structure - * @caps: ECC engine caps info structure - * @oobavail: OOB size that the ECC engine can use - * - * If a chip's ECC requirement is provided, try to meet it with the least - * number of ECC bytes (i.e. with the largest number of OOB-free bytes). - * On success, the chosen ECC settings are set. - */ -int nand_match_ecc_req(struct nand_chip *chip, - const struct nand_ecc_caps *caps, int oobavail) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - const struct nand_ecc_step_info *stepinfo; - int req_step = chip->ecc_step_ds; - int req_strength = chip->ecc_strength_ds; - int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total; - int best_step, best_strength, best_ecc_bytes; - int best_ecc_bytes_total = INT_MAX; - int i, j; - - if (WARN_ON(oobavail < 0)) - return -EINVAL; - - /* No information provided by the NAND chip */ - if (!req_step || !req_strength) - return -ENOTSUPP; - - /* number of correctable bits the chip requires in a page */ - req_corr = mtd->writesize / req_step * req_strength; - - for (i = 0; i < caps->nstepinfos; i++) { - stepinfo = &caps->stepinfos[i]; - step_size = stepinfo->stepsize; - - for (j = 0; j < stepinfo->nstrengths; j++) { - strength = stepinfo->strengths[j]; - - /* - * If both step size and strength are smaller than the - * chip's requirement, it is not easy to compare the - * resulted reliability. - */ - if (step_size < req_step && strength < req_strength) - continue; - - if (mtd->writesize % step_size) - continue; - - nsteps = mtd->writesize / step_size; - - ecc_bytes = caps->calc_ecc_bytes(step_size, strength); - if (WARN_ON_ONCE(ecc_bytes < 0)) - continue; - ecc_bytes_total = ecc_bytes * nsteps; - - if (ecc_bytes_total > oobavail || - strength * nsteps < req_corr) - continue; - - /* - * We assume the best is to meet the chip's requrement - * with the least number of ECC bytes. - */ - if (ecc_bytes_total < best_ecc_bytes_total) { - best_ecc_bytes_total = ecc_bytes_total; - best_step = step_size; - best_strength = strength; - best_ecc_bytes = ecc_bytes; - } - } - } - - if (best_ecc_bytes_total == INT_MAX) - return -ENOTSUPP; - - chip->ecc.size = best_step; - chip->ecc.strength = best_strength; - chip->ecc.bytes = best_ecc_bytes; - - return 0; -} -EXPORT_SYMBOL_GPL(nand_match_ecc_req); - -/** - * nand_maximize_ecc - choose the max ECC strength available - * @chip: nand chip info structure - * @caps: ECC engine caps info structure - * @oobavail: OOB size that the ECC engine can use - * - * Choose the max ECC strength that is supported on the controller, and can fit - * within the chip's OOB. On success, the chosen ECC settings are set. - */ -int nand_maximize_ecc(struct nand_chip *chip, - const struct nand_ecc_caps *caps, int oobavail) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - const struct nand_ecc_step_info *stepinfo; - int step_size, strength, nsteps, ecc_bytes, corr; - int best_corr = 0; - int best_step = 0; - int best_strength, best_ecc_bytes; - int i, j; - - if (WARN_ON(oobavail < 0)) - return -EINVAL; - - for (i = 0; i < caps->nstepinfos; i++) { - stepinfo = &caps->stepinfos[i]; - step_size = stepinfo->stepsize; - - /* If chip->ecc.size is already set, respect it */ - if (chip->ecc.size && step_size != chip->ecc.size) - continue; - - for (j = 0; j < stepinfo->nstrengths; j++) { - strength = stepinfo->strengths[j]; - - if (mtd->writesize % step_size) - continue; - - nsteps = mtd->writesize / step_size; - - ecc_bytes = caps->calc_ecc_bytes(step_size, strength); - if (WARN_ON_ONCE(ecc_bytes < 0)) - continue; - - if (ecc_bytes * nsteps > oobavail) - continue; - - corr = strength * nsteps; - - /* - * If the number of correctable bits is the same, - * bigger step_size has more reliability. - */ - if (corr > best_corr || - (corr == best_corr && step_size > best_step)) { - best_corr = corr; - best_step = step_size; - best_strength = strength; - best_ecc_bytes = ecc_bytes; - } - } - } - - if (!best_corr) - return -ENOTSUPP; - - chip->ecc.size = best_step; - chip->ecc.strength = best_strength; - chip->ecc.bytes = best_ecc_bytes; - - return 0; -} -EXPORT_SYMBOL_GPL(nand_maximize_ecc); - -/* - * Check if the chip configuration meet the datasheet requirements. - - * If our configuration corrects A bits per B bytes and the minimum - * required correction level is X bits per Y bytes, then we must ensure - * both of the following are true: - * - * (1) A / B >= X / Y - * (2) A >= X - * - * Requirement (1) ensures we can correct for the required bitflip density. - * Requirement (2) ensures we can correct even when all bitflips are clumped - * in the same sector. - */ -static bool nand_ecc_strength_good(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_ecc_ctrl *ecc = &chip->ecc; - int corr, ds_corr; - - if (ecc->size == 0 || chip->ecc_step_ds == 0) - /* Not enough information */ - return true; - - /* - * We get the number of corrected bits per page to compare - * the correction density. - */ - corr = (mtd->writesize * ecc->strength) / ecc->size; - ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds; - - return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds; -} - -static bool invalid_ecc_page_accessors(struct nand_chip *chip) -{ - struct nand_ecc_ctrl *ecc = &chip->ecc; - - if (nand_standard_page_accessors(ecc)) - return false; - - /* - * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND - * controller driver implements all the page accessors because - * default helpers are not suitable when the core does not - * send the READ0/PAGEPROG commands. - */ - return (!ecc->read_page || !ecc->write_page || - !ecc->read_page_raw || !ecc->write_page_raw || - (NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) || - (NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage && - ecc->hwctl && ecc->calculate)); -} - -/** - * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * - * This is the second phase of the normal nand_scan() function. It fills out - * all the uninitialized function pointers with the defaults and scans for a - * bad block table if appropriate. - */ -int nand_scan_tail(struct mtd_info *mtd) -{ - int i; - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_ecc_ctrl *ecc = &chip->ecc; - struct nand_buffers *nbuf; - - /* New bad blocks should be marked in OOB, flash-based BBT, or both */ - BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && - !(chip->bbt_options & NAND_BBT_USE_FLASH)); - - if (invalid_ecc_page_accessors(chip)) { - pr_err("Invalid ECC page accessors setup\n"); - return -EINVAL; - } - - if (!(chip->options & NAND_OWN_BUFFERS)) { - nbuf = kzalloc(sizeof(struct nand_buffers), GFP_KERNEL); - chip->buffers = nbuf; - } else { - if (!chip->buffers) - return -ENOMEM; - } - - /* Set the internal oob buffer location, just after the page data */ - chip->oob_poi = chip->buffers->databuf + mtd->writesize; - - /* - * If no default placement scheme is given, select an appropriate one. - */ - if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) { - switch (mtd->oobsize) { - case 8: - ecc->layout = &nand_oob_8; - break; - case 16: - ecc->layout = &nand_oob_16; - break; - case 64: - ecc->layout = &nand_oob_64; - break; - case 128: - ecc->layout = &nand_oob_128; - break; - default: - pr_warn("No oob scheme defined for oobsize %d\n", - mtd->oobsize); - BUG(); - } - } - - if (!chip->write_page) - chip->write_page = nand_write_page; - - /* - * Check ECC mode, default to software if 3byte/512byte hardware ECC is - * selected and we have 256 byte pagesize fallback to software ECC - */ - - switch (ecc->mode) { - case NAND_ECC_HW_OOB_FIRST: - /* Similar to NAND_ECC_HW, but a separate read_page handle */ - if (!ecc->calculate || !ecc->correct || !ecc->hwctl) { - pr_warn("No ECC functions supplied; hardware ECC not possible\n"); - BUG(); - } - if (!ecc->read_page) - ecc->read_page = nand_read_page_hwecc_oob_first; - - case NAND_ECC_HW: - /* Use standard hwecc read page function? */ - if (!ecc->read_page) - ecc->read_page = nand_read_page_hwecc; - if (!ecc->write_page) - ecc->write_page = nand_write_page_hwecc; - if (!ecc->read_page_raw) - ecc->read_page_raw = nand_read_page_raw; - if (!ecc->write_page_raw) - ecc->write_page_raw = nand_write_page_raw; - if (!ecc->read_oob) - ecc->read_oob = nand_read_oob_std; - if (!ecc->write_oob) - ecc->write_oob = nand_write_oob_std; - if (!ecc->read_subpage) - ecc->read_subpage = nand_read_subpage; - if (!ecc->write_subpage && ecc->hwctl && ecc->calculate) - ecc->write_subpage = nand_write_subpage_hwecc; - - case NAND_ECC_HW_SYNDROME: - if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) && - (!ecc->read_page || - ecc->read_page == nand_read_page_hwecc || - !ecc->write_page || - ecc->write_page == nand_write_page_hwecc)) { - pr_warn("No ECC functions supplied; hardware ECC not possible\n"); - BUG(); - } - /* Use standard syndrome read/write page function? */ - if (!ecc->read_page) - ecc->read_page = nand_read_page_syndrome; - if (!ecc->write_page) - ecc->write_page = nand_write_page_syndrome; - if (!ecc->read_page_raw) - ecc->read_page_raw = nand_read_page_raw_syndrome; - if (!ecc->write_page_raw) - ecc->write_page_raw = nand_write_page_raw_syndrome; - if (!ecc->read_oob) - ecc->read_oob = nand_read_oob_syndrome; - if (!ecc->write_oob) - ecc->write_oob = nand_write_oob_syndrome; - - if (mtd->writesize >= ecc->size) { - if (!ecc->strength) { - pr_warn("Driver must set ecc.strength when using hardware ECC\n"); - BUG(); - } - break; - } - pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n", - ecc->size, mtd->writesize); - ecc->mode = NAND_ECC_SOFT; - - case NAND_ECC_SOFT: - ecc->calculate = nand_calculate_ecc; - ecc->correct = nand_correct_data; - ecc->read_page = nand_read_page_swecc; - ecc->read_subpage = nand_read_subpage; - ecc->write_page = nand_write_page_swecc; - ecc->read_page_raw = nand_read_page_raw; - ecc->write_page_raw = nand_write_page_raw; - ecc->read_oob = nand_read_oob_std; - ecc->write_oob = nand_write_oob_std; - if (!ecc->size) - ecc->size = 256; - ecc->bytes = 3; - ecc->strength = 1; - break; - - case NAND_ECC_SOFT_BCH: - if (!mtd_nand_has_bch()) { - pr_warn("CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - BUG(); - } - ecc->calculate = nand_bch_calculate_ecc; - ecc->correct = nand_bch_correct_data; - ecc->read_page = nand_read_page_swecc; - ecc->read_subpage = nand_read_subpage; - ecc->write_page = nand_write_page_swecc; - ecc->read_page_raw = nand_read_page_raw; - ecc->write_page_raw = nand_write_page_raw; - ecc->read_oob = nand_read_oob_std; - ecc->write_oob = nand_write_oob_std; - /* - * Board driver should supply ecc.size and ecc.strength values - * to select how many bits are correctable. Otherwise, default - * to 4 bits for large page devices. - */ - if (!ecc->size && (mtd->oobsize >= 64)) { - ecc->size = 512; - ecc->strength = 4; - } - - /* See nand_bch_init() for details. */ - ecc->bytes = 0; - ecc->priv = nand_bch_init(mtd); - if (!ecc->priv) { - pr_warn("BCH ECC initialization failed!\n"); - BUG(); - } - break; - - case NAND_ECC_NONE: - pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n"); - ecc->read_page = nand_read_page_raw; - ecc->write_page = nand_write_page_raw; - ecc->read_oob = nand_read_oob_std; - ecc->read_page_raw = nand_read_page_raw; - ecc->write_page_raw = nand_write_page_raw; - ecc->write_oob = nand_write_oob_std; - ecc->size = mtd->writesize; - ecc->bytes = 0; - ecc->strength = 0; - break; - - default: - pr_warn("Invalid NAND_ECC_MODE %d\n", ecc->mode); - BUG(); - } - - /* For many systems, the standard OOB write also works for raw */ - if (!ecc->read_oob_raw) - ecc->read_oob_raw = ecc->read_oob; - if (!ecc->write_oob_raw) - ecc->write_oob_raw = ecc->write_oob; - - /* - * The number of bytes available for a client to place data into - * the out of band area. - */ - mtd->oobavail = 0; - if (ecc->layout) { - for (i = 0; ecc->layout->oobfree[i].length; i++) - mtd->oobavail += ecc->layout->oobfree[i].length; - } - - /* ECC sanity check: warn if it's too weak */ - if (!nand_ecc_strength_good(mtd)) - pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n", - mtd->name); - - /* - * Set the number of read / write steps for one page depending on ECC - * mode. - */ - ecc->steps = mtd->writesize / ecc->size; - if (ecc->steps * ecc->size != mtd->writesize) { - pr_warn("Invalid ECC parameters\n"); - BUG(); - } - ecc->total = ecc->steps * ecc->bytes; - - /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */ - if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) { - switch (ecc->steps) { - case 2: - mtd->subpage_sft = 1; - break; - case 4: - case 8: - case 16: - mtd->subpage_sft = 2; - break; - } - } - chip->subpagesize = mtd->writesize >> mtd->subpage_sft; - - /* Initialize state */ - chip->state = FL_READY; - - /* Invalidate the pagebuffer reference */ - chip->pagebuf = -1; - - /* Large page NAND with SOFT_ECC should support subpage reads */ - switch (ecc->mode) { - case NAND_ECC_SOFT: - case NAND_ECC_SOFT_BCH: - if (chip->page_shift > 9) - chip->options |= NAND_SUBPAGE_READ; - break; - - default: - break; - } - - /* Fill in remaining MTD driver data */ - mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH; - mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : - MTD_CAP_NANDFLASH; - mtd->_erase = nand_erase; - mtd->_panic_write = panic_nand_write; - mtd->_read_oob = nand_read_oob; - mtd->_write_oob = nand_write_oob; - mtd->_sync = nand_sync; - mtd->_lock = NULL; - mtd->_unlock = NULL; - mtd->_block_isreserved = nand_block_isreserved; - mtd->_block_isbad = nand_block_isbad; - mtd->_block_markbad = nand_block_markbad; - mtd->writebufsize = mtd->writesize; - - /* propagate ecc info to mtd_info */ - mtd->ecclayout = ecc->layout; - mtd->ecc_strength = ecc->strength; - mtd->ecc_step_size = ecc->size; - /* - * Initialize bitflip_threshold to its default prior scan_bbt() call. - * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be - * properly set. - */ - if (!mtd->bitflip_threshold) - mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4); - - return 0; -} -EXPORT_SYMBOL(nand_scan_tail); - -/** - * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: number of chips to scan for - * - * 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(struct mtd_info *mtd, int maxchips) -{ - int ret; - - ret = nand_scan_ident(mtd, maxchips, NULL); - if (!ret) - ret = nand_scan_tail(mtd); - return ret; -} -EXPORT_SYMBOL(nand_scan); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill "); -MODULE_AUTHOR("Thomas Gleixner "); -MODULE_DESCRIPTION("Generic NAND flash driver code"); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c deleted file mode 100644 index ba785c5d53..0000000000 --- a/drivers/mtd/nand/nand_bbt.c +++ /dev/null @@ -1,1373 +0,0 @@ -/* - * Overview: - * Bad block table support for the NAND driver - * - * Copyright © 2004 Thomas Gleixner (tglx@linutronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Description: - * - * When nand_scan_bbt is called, then it tries to find the bad block table - * depending on the options in the BBT descriptor(s). If no flash based BBT - * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory - * marked good / bad blocks. This information is used to create a memory BBT. - * Once a new bad block is discovered then the "factory" information is updated - * on the device. - * If a flash based BBT is specified then the function first tries to find the - * BBT on flash. If a BBT is found then the contents are read and the memory - * based BBT is created. If a mirrored BBT is selected then the mirror is - * searched too and the versions are compared. If the mirror has a greater - * version number, then the mirror BBT is used to build the memory based BBT. - * If the tables are not versioned, then we "or" the bad block information. - * If one of the BBTs is out of date or does not exist it is (re)created. - * If no BBT exists at all then the device is scanned for factory marked - * good / bad blocks and the bad block tables are created. - * - * For manufacturer created BBTs like the one found on M-SYS DOC devices - * the BBT is searched and read but never created - * - * The auto generated bad block table is located in the last good blocks - * of the device. The table is mirrored, so it can be updated eventually. - * The table is marked in the OOB area with an ident pattern and a version - * number which indicates which of both tables is more up to date. If the NAND - * controller needs the complete OOB area for the ECC information then the - * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of - * course): it moves the ident pattern and the version byte into the data area - * and the OOB area will remain untouched. - * - * The table uses 2 bits per block - * 11b: block is good - * 00b: block is factory marked bad - * 01b, 10b: block is marked bad due to wear - * - * The memory bad block table uses the following scheme: - * 00b: block is good - * 01b: block is marked bad due to wear - * 10b: block is reserved (to protect the bbt area) - * 11b: block is factory marked bad - * - * Multichip devices like DOC store the bad block info per floor. - * - * Following assumptions are made: - * - bbts start at a page boundary, if autolocated on a block boundary - * - the space necessary for a bbt in FLASH does not exceed a block boundary - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define BBT_BLOCK_GOOD 0x00 -#define BBT_BLOCK_WORN 0x01 -#define BBT_BLOCK_RESERVED 0x02 -#define BBT_BLOCK_FACTORY_BAD 0x03 - -#define BBT_ENTRY_MASK 0x03 -#define BBT_ENTRY_SHIFT 2 - -static int nand_update_bbt(struct mtd_info *mtd, loff_t offs); - -static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block) -{ - uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT]; - entry >>= (block & BBT_ENTRY_MASK) * 2; - return entry & BBT_ENTRY_MASK; -} - -static inline void bbt_mark_entry(struct nand_chip *chip, int block, - uint8_t mark) -{ - uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2); - chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk; -} - -static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) -{ - if (memcmp(buf, td->pattern, td->len)) - return -1; - return 0; -} - -/** - * check_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @len: the length of buffer to search - * @paglen: the pagelength - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block tables and - * good / bad block identifiers. - */ -static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) -{ - if (td->options & NAND_BBT_NO_OOB) - return check_pattern_no_oob(buf, td); - - /* Compare the pattern */ - if (memcmp(buf + paglen + td->offs, td->pattern, td->len)) - return -1; - - return 0; -} - -/** - * check_short_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block tables and - * good / bad block identifiers. Same as check_pattern, but no optional empty - * check. - */ -static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) -{ - /* Compare the pattern */ - if (memcmp(buf + td->offs, td->pattern, td->len)) - return -1; - return 0; -} - -/** - * add_marker_len - compute the length of the marker in data area - * @td: BBT descriptor used for computation - * - * The length will be 0 if the marker is located in OOB area. - */ -static u32 add_marker_len(struct nand_bbt_descr *td) -{ - u32 len; - - if (!(td->options & NAND_BBT_NO_OOB)) - return 0; - - len = td->len; - if (td->options & NAND_BBT_VERSION) - len++; - return len; -} - -/** - * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd: MTD device structure - * @buf: temporary buffer - * @page: the starting page - * @num: the number of bbt descriptors to read - * @td: the bbt describtion table - * @offs: block number offset in the table - * - * Read the bad block table starting from page. - */ -static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, - struct nand_bbt_descr *td, int offs) -{ - int res, ret = 0, i, j, act = 0; - struct nand_chip *this = mtd_to_nand(mtd); - size_t retlen, len, totlen; - loff_t from; - int bits = td->options & NAND_BBT_NRBITS_MSK; - uint8_t msk = (uint8_t)((1 << bits) - 1); - u32 marker_len; - int reserved_block_code = td->reserved_block_code; - - totlen = (num * bits) >> 3; - marker_len = add_marker_len(td); - from = ((loff_t)page) << this->page_shift; - - while (totlen) { - len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); - if (marker_len) { - /* - * In case the BBT marker is not in the OOB area it - * will be just in the first page. - */ - len -= marker_len; - from += marker_len; - marker_len = 0; - } - res = mtd_read(mtd, from, len, &retlen, buf); - if (res < 0) { - if (mtd_is_eccerr(res)) { - pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n", - from & ~mtd->writesize); - return res; - } else if (mtd_is_bitflip(res)) { - pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n", - from & ~mtd->writesize); - ret = res; - } else { - pr_info("nand_bbt: error reading BBT\n"); - return res; - } - } - - /* Analyse data */ - for (i = 0; i < len; i++) { - uint8_t dat = buf[i]; - for (j = 0; j < 8; j += bits, act++) { - uint8_t tmp = (dat >> j) & msk; - if (tmp == msk) - continue; - if (reserved_block_code && (tmp == reserved_block_code)) { - pr_info("nand_read_bbt: reserved block at 0x%012llx\n", - (loff_t)(offs + act) << - this->bbt_erase_shift); - bbt_mark_entry(this, offs + act, - BBT_BLOCK_RESERVED); - mtd->ecc_stats.bbtblocks++; - continue; - } - /* - * Leave it for now, if it's matured we can - * move this message to pr_debug. - */ - pr_info("nand_read_bbt: bad block at 0x%012llx\n", - (loff_t)(offs + act) << - this->bbt_erase_shift); - /* Factory marked bad or worn out? */ - if (tmp == 0) - bbt_mark_entry(this, offs + act, - BBT_BLOCK_FACTORY_BAD); - else - bbt_mark_entry(this, offs + act, - BBT_BLOCK_WORN); - mtd->ecc_stats.badblocks++; - } - } - totlen -= len; - from += len; - } - return ret; -} - -/** - * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @chip: read the table for a specific chip, -1 read all chips; applies only if - * NAND_BBT_PERCHIP option is set - * - * Read the bad block table for all chips starting at a given page. We assume - * that the bbt bits are in consecutive order. - */ -static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int res = 0, i; - - if (td->options & NAND_BBT_PERCHIP) { - int offs = 0; - for (i = 0; i < this->numchips; i++) { - if (chip == -1 || chip == i) - res = read_bbt(mtd, buf, td->pages[i], - this->chipsize >> this->bbt_erase_shift, - td, offs); - if (res) - return res; - offs += this->chipsize >> this->bbt_erase_shift; - } - } else { - res = read_bbt(mtd, buf, td->pages[0], - mtd->size >> this->bbt_erase_shift, td, 0); - if (res) - return res; - } - return 0; -} - -/* BBT marker is in the first page, no OOB */ -static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - struct nand_bbt_descr *td) -{ - size_t retlen; - size_t len; - - len = td->len; - if (td->options & NAND_BBT_VERSION) - len++; - - return mtd_read(mtd, offs, len, &retlen, buf); -} - -/** - * scan_read_oob - [GENERIC] Scan data+OOB region to buffer - * @mtd: MTD device structure - * @buf: temporary buffer - * @offs: offset at which to scan - * @len: length of data region to read - * - * Scan read data from data+OOB. May traverse multiple pages, interleaving - * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest" - * ECC condition (error or bitflip). May quit on the first (non-ECC) error. - */ -static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - size_t len) -{ - struct mtd_oob_ops ops; - int res, ret = 0; - - ops.mode = MTD_OPS_PLACE_OOB; - ops.ooboffs = 0; - ops.ooblen = mtd->oobsize; - - while (len > 0) { - ops.datbuf = buf; - ops.len = min(len, (size_t)mtd->writesize); - ops.oobbuf = buf + ops.len; - - res = mtd_read_oob(mtd, offs, &ops); - if (res) { - if (!mtd_is_bitflip_or_eccerr(res)) - return res; - else if (mtd_is_eccerr(res) || !ret) - ret = res; - } - - buf += mtd->oobsize + mtd->writesize; - len -= mtd->writesize; - offs += mtd->writesize; - } - return ret; -} - -static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - size_t len, struct nand_bbt_descr *td) -{ - if (td->options & NAND_BBT_NO_OOB) - return scan_read_data(mtd, buf, offs, td); - else - return scan_read_oob(mtd, buf, offs, len); -} - -/* Scan write data with oob to flash */ -static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, - uint8_t *buf, uint8_t *oob) -{ - struct mtd_oob_ops ops; - - ops.mode = MTD_OPS_PLACE_OOB; - ops.ooboffs = 0; - ops.ooblen = mtd->oobsize; - ops.datbuf = buf; - ops.oobbuf = oob; - ops.len = len; - - return mtd_write_oob(mtd, offs, &ops); -} - -static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) -{ - u32 ver_offs = td->veroffs; - - if (!(td->options & NAND_BBT_NO_OOB)) - ver_offs += mtd->writesize; - return ver_offs; -} - -/** - * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * - * Read the bad block table(s) for all chips starting at a given page. We - * assume that the bbt bits are in consecutive order. - */ -static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - /* Read the primary version, if available */ - if (td->options & NAND_BBT_VERSION) { - scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift, - mtd->writesize, td); - td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; - pr_info("Bad block table at page %d, version 0x%02X\n", - td->pages[0], td->version[0]); - } - - /* Read the mirror version, if available */ - if (md && (md->options & NAND_BBT_VERSION)) { - scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift, - mtd->writesize, md); - md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; - pr_info("Bad block table at page %d, version 0x%02X\n", - md->pages[0], md->version[0]); - } -} - -/* Scan a given block partially */ -static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, - loff_t offs, uint8_t *buf, int numpages) -{ - struct mtd_oob_ops ops; - int j, ret; - - ops.ooblen = mtd->oobsize; - ops.oobbuf = buf; - ops.ooboffs = 0; - ops.datbuf = NULL; - ops.mode = MTD_OPS_PLACE_OOB; - - for (j = 0; j < numpages; j++) { - /* - * Read the full oob until read_oob is fixed to handle single - * byte reads for 16 bit buswidth. - */ - ret = mtd_read_oob(mtd, offs, &ops); - /* Ignore ECC errors when checking for BBM */ - if (ret && !mtd_is_bitflip_or_eccerr(ret)) - return ret; - - if (check_short_pattern(buf, bd)) - return 1; - - offs += mtd->writesize; - } - return 0; -} - -/** - * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * @chip: create the table for a specific chip, -1 read all chips; applies only - * if NAND_BBT_PERCHIP option is set - * - * Create a bad block table by scanning the device for the given good/bad block - * identify pattern. - */ -static int create_bbt(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *bd, int chip) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int i, numblocks, numpages; - int startblock; - loff_t from; - - pr_info("Scanning device for bad blocks\n"); - - if (bd->options & NAND_BBT_SCAN2NDPAGE) - numpages = 2; - else - numpages = 1; - - if (chip == -1) { - numblocks = mtd->size >> this->bbt_erase_shift; - startblock = 0; - from = 0; - } else { - if (chip >= this->numchips) { - pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", - chip + 1, this->numchips); - return -EINVAL; - } - numblocks = this->chipsize >> this->bbt_erase_shift; - startblock = chip * numblocks; - numblocks += startblock; - from = (loff_t)startblock << this->bbt_erase_shift; - } - - if (this->bbt_options & NAND_BBT_SCANLASTPAGE) - from += mtd->erasesize - (mtd->writesize * numpages); - - for (i = startblock; i < numblocks; i++) { - int ret; - - BUG_ON(bd->options & NAND_BBT_NO_OOB); - - ret = scan_block_fast(mtd, bd, from, buf, numpages); - if (ret < 0) - return ret; - - if (ret) { - bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD); - pr_warn("Bad eraseblock %d at 0x%012llx\n", - i, (unsigned long long)from); - mtd->ecc_stats.badblocks++; - } - - from += (1 << this->bbt_erase_shift); - } - return 0; -} - -/** - * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * - * Read the bad block table by searching for a given ident pattern. Search is - * preformed either from the beginning up or from the end of the device - * downwards. The search starts always at the start of a block. If the option - * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains - * the bad block information of this chip. This is necessary to provide support - * for certain DOC devices. - * - * The bbt ident pattern resides in the oob area of the first page in a block. - */ -static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int i, chips; - int startblock, block, dir; - int scanlen = mtd->writesize + mtd->oobsize; - int bbtblocks; - int blocktopage = this->bbt_erase_shift - this->page_shift; - - /* Search direction top -> down? */ - if (td->options & NAND_BBT_LASTBLOCK) { - startblock = (mtd->size >> this->bbt_erase_shift) - 1; - dir = -1; - } else { - startblock = 0; - dir = 1; - } - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; - bbtblocks = this->chipsize >> this->bbt_erase_shift; - startblock &= bbtblocks - 1; - } else { - chips = 1; - bbtblocks = mtd->size >> this->bbt_erase_shift; - } - - for (i = 0; i < chips; i++) { - /* Reset version information */ - td->version[i] = 0; - td->pages[i] = -1; - /* Scan the maximum number of blocks */ - for (block = 0; block < td->maxblocks; block++) { - - int actblock = startblock + dir * block; - loff_t offs = (loff_t)actblock << this->bbt_erase_shift; - - /* Read first page */ - scan_read(mtd, buf, offs, mtd->writesize, td); - if (!check_pattern(buf, scanlen, mtd->writesize, td)) { - td->pages[i] = actblock << blocktopage; - if (td->options & NAND_BBT_VERSION) { - offs = bbt_get_ver_offs(mtd, td); - td->version[i] = buf[offs]; - } - break; - } - } - startblock += this->chipsize >> this->bbt_erase_shift; - } - /* Check, if we found a bbt for each requested chip */ - for (i = 0; i < chips; i++) { - if (td->pages[i] == -1) - pr_warn("Bad block table not found for chip %d\n", i); - else - pr_info("Bad block table found at page %d, version 0x%02X\n", - td->pages[i], td->version[i]); - } - return 0; -} - -/** - * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * - * Search and read the bad block table(s). - */ -static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, - struct nand_bbt_descr *md) -{ - /* Search the primary table */ - search_bbt(mtd, buf, td); - - /* Search the mirror table */ - if (md) - search_bbt(mtd, buf, md); -} - -/** - * write_bbt - [GENERIC] (Re)write the bad block table - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * @chipsel: selector for a specific chip, -1 for all - * - * (Re)write the bad block table. - */ -static int write_bbt(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md, - int chipsel) -{ - struct nand_chip *this = mtd_to_nand(mtd); - struct erase_info einfo; - int i, res, chip = 0; - int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; - int nrchips, pageoffs, ooboffs; - uint8_t msk[4]; - uint8_t rcode = td->reserved_block_code; - size_t retlen, len = 0; - loff_t to; - struct mtd_oob_ops ops; - - ops.ooblen = mtd->oobsize; - ops.ooboffs = 0; - ops.datbuf = NULL; - ops.mode = MTD_OPS_PLACE_OOB; - - if (!rcode) - rcode = 0xff; - /* Write bad block table per chip rather than per device? */ - if (td->options & NAND_BBT_PERCHIP) { - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); - /* Full device write or specific chip? */ - if (chipsel == -1) { - nrchips = this->numchips; - } else { - nrchips = chipsel + 1; - chip = chipsel; - } - } else { - numblocks = (int)(mtd->size >> this->bbt_erase_shift); - nrchips = 1; - } - - /* Loop through the chips */ - for (; chip < nrchips; chip++) { - /* - * There was already a version of the table, reuse the page - * This applies for absolute placement too, as we have the - * page nr. in td->pages. - */ - if (td->pages[chip] != -1) { - page = td->pages[chip]; - goto write; - } - - /* - * Automatic placement of the bad block table. Search direction - * top -> down? - */ - if (td->options & NAND_BBT_LASTBLOCK) { - startblock = numblocks * (chip + 1) - 1; - dir = -1; - } else { - startblock = chip * numblocks; - dir = 1; - } - - for (i = 0; i < td->maxblocks; i++) { - int block = startblock + dir * i; - /* Check, if the block is bad */ - switch (bbt_get_entry(this, block)) { - case BBT_BLOCK_WORN: - case BBT_BLOCK_FACTORY_BAD: - continue; - } - page = block << - (this->bbt_erase_shift - this->page_shift); - /* Check, if the block is used by the mirror table */ - if (!md || md->pages[chip] != page) - goto write; - } - pr_err("No space left to write bad block table\n"); - return -ENOSPC; - write: - - /* Set up shift count and masks for the flash table */ - bits = td->options & NAND_BBT_NRBITS_MSK; - msk[2] = ~rcode; - switch (bits) { - case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; - msk[3] = 0x01; - break; - case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; - msk[3] = 0x03; - break; - case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; - msk[3] = 0x0f; - break; - case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; - msk[3] = 0xff; - break; - default: return -EINVAL; - } - - to = ((loff_t)page) << this->page_shift; - - /* Must we save the block contents? */ - if (td->options & NAND_BBT_SAVECONTENT) { - /* Make it block aligned */ - to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1); - len = 1 << this->bbt_erase_shift; - res = mtd_read(mtd, to, len, &retlen, buf); - if (res < 0) { - if (retlen != len) { - pr_info("nand_bbt: error reading block for writing the bad block table\n"); - return res; - } - pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n"); - } - /* Read oob data */ - ops.ooblen = (len >> this->page_shift) * mtd->oobsize; - ops.oobbuf = &buf[len]; - res = mtd_read_oob(mtd, to + mtd->writesize, &ops); - if (res < 0 || ops.oobretlen != ops.ooblen) - goto outerr; - - /* Calc the byte offset in the buffer */ - pageoffs = page - (int)(to >> this->page_shift); - offs = pageoffs << this->page_shift; - /* Preset the bbt area with 0xff */ - memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); - ooboffs = len + (pageoffs * mtd->oobsize); - - } else if (td->options & NAND_BBT_NO_OOB) { - ooboffs = 0; - offs = td->len; - /* The version byte */ - if (td->options & NAND_BBT_VERSION) - offs++; - /* Calc length */ - len = (size_t)(numblocks >> sft); - len += offs; - /* Make it page aligned! */ - len = ALIGN(len, mtd->writesize); - /* Preset the buffer with 0xff */ - memset(buf, 0xff, len); - /* Pattern is located at the begin of first page */ - memcpy(buf, td->pattern, td->len); - } else { - /* Calc length */ - len = (size_t)(numblocks >> sft); - /* Make it page aligned! */ - len = ALIGN(len, mtd->writesize); - /* Preset the buffer with 0xff */ - memset(buf, 0xff, len + - (len >> this->page_shift)* mtd->oobsize); - offs = 0; - ooboffs = len; - /* Pattern is located in oob area of first page */ - memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); - } - - if (td->options & NAND_BBT_VERSION) - buf[ooboffs + td->veroffs] = td->version[chip]; - - /* Walk through the memory table */ - for (i = 0; i < numblocks; i++) { - uint8_t dat; - int sftcnt = (i << (3 - sft)) & sftmsk; - dat = bbt_get_entry(this, chip * numblocks + i); - /* Do not store the reserved bbt blocks! */ - buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt); - } - - memset(&einfo, 0, sizeof(einfo)); - einfo.mtd = mtd; - einfo.addr = to; - einfo.len = 1 << this->bbt_erase_shift; - res = nand_erase_nand(mtd, &einfo, 1); - if (res < 0) - goto outerr; - - res = scan_write_bbt(mtd, to, len, buf, - td->options & NAND_BBT_NO_OOB ? NULL : - &buf[len]); - if (res < 0) - goto outerr; - - pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", - (unsigned long long)to, td->version[chip]); - - /* Mark it as used */ - td->pages[chip] = page; - } - return 0; - - outerr: - pr_warn("nand_bbt: error while writing bad block table %d\n", res); - return res; -} - -/** - * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern - * - * The function creates a memory based bbt by scanning the device for - * manufacturer / software marked good / bad blocks. - */ -static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - return create_bbt(mtd, this->buffers->databuf, bd, -1); -} - -/** - * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * - * The function checks the results of the previous call to read_bbt and creates - * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found - * for the chip/device. Update is necessary if one of the tables is missing or - * the version nr. of one table is less than the other. - */ -static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) -{ - int i, chips, writeops, create, chipsel, res, res2; - struct nand_chip *this = mtd_to_nand(mtd); - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - struct nand_bbt_descr *rd, *rd2; - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) - chips = this->numchips; - else - chips = 1; - - for (i = 0; i < chips; i++) { - writeops = 0; - create = 0; - rd = NULL; - rd2 = NULL; - res = res2 = 0; - /* Per chip or per device? */ - chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; - /* Mirrored table available? */ - if (md) { - if (td->pages[i] == -1 && md->pages[i] == -1) { - create = 1; - writeops = 0x03; - } else if (td->pages[i] == -1) { - rd = md; - writeops = 0x01; - } else if (md->pages[i] == -1) { - rd = td; - writeops = 0x02; - } else if (td->version[i] == md->version[i]) { - rd = td; - if (!(td->options & NAND_BBT_VERSION)) - rd2 = md; - } else if (((int8_t)(td->version[i] - md->version[i])) > 0) { - rd = td; - writeops = 0x02; - } else { - rd = md; - writeops = 0x01; - } - } else { - if (td->pages[i] == -1) { - create = 1; - writeops = 0x01; - } else { - rd = td; - } - } - - if (create) { - /* Create the bad block table by scanning the device? */ - if (!(td->options & NAND_BBT_CREATE)) - continue; - - /* Create the table in memory by scanning the chip(s) */ - if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) - create_bbt(mtd, buf, bd, chipsel); - - td->version[i] = 1; - if (md) - md->version[i] = 1; - } - - /* Read back first? */ - if (rd) { - res = read_abs_bbt(mtd, buf, rd, chipsel); - if (mtd_is_eccerr(res)) { - /* Mark table as invalid */ - rd->pages[i] = -1; - rd->version[i] = 0; - i--; - continue; - } - } - /* If they weren't versioned, read both */ - if (rd2) { - res2 = read_abs_bbt(mtd, buf, rd2, chipsel); - if (mtd_is_eccerr(res2)) { - /* Mark table as invalid */ - rd2->pages[i] = -1; - rd2->version[i] = 0; - i--; - continue; - } - } - - /* Scrub the flash table(s)? */ - if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) - writeops = 0x03; - - /* Update version numbers before writing */ - if (md) { - td->version[i] = max(td->version[i], md->version[i]); - md->version[i] = td->version[i]; - } - - /* Write the bad block table to the device? */ - if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, td, md, chipsel); - if (res < 0) - return res; - } - - /* Write the mirror bad block table to the device? */ - if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); - if (res < 0) - return res; - } - } - return 0; -} - -/** - * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd: MTD device structure - * @td: bad block table descriptor - * - * The bad block table regions are marked as "bad" to prevent accidental - * erasures / writes. The regions are identified by the mark 0x02. - */ -static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int i, j, chips, block, nrblocks, update; - uint8_t oldval; - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; - nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); - } else { - chips = 1; - nrblocks = (int)(mtd->size >> this->bbt_erase_shift); - } - - for (i = 0; i < chips; i++) { - if ((td->options & NAND_BBT_ABSPAGE) || - !(td->options & NAND_BBT_WRITE)) { - if (td->pages[i] == -1) - continue; - block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); - oldval = bbt_get_entry(this, block); - bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); - if ((oldval != BBT_BLOCK_RESERVED) && - td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)block << - this->bbt_erase_shift); - continue; - } - update = 0; - if (td->options & NAND_BBT_LASTBLOCK) - block = ((i + 1) * nrblocks) - td->maxblocks; - else - block = i * nrblocks; - for (j = 0; j < td->maxblocks; j++) { - oldval = bbt_get_entry(this, block); - bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); - if (oldval != BBT_BLOCK_RESERVED) - update = 1; - block++; - } - /* - * If we want reserved blocks to be recorded to flash, and some - * new ones have been marked, then we need to update the stored - * bbts. This should only happen once. - */ - if (update && td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)(block - 1) << - this->bbt_erase_shift); - } -} - -/** - * verify_bbt_descr - verify the bad block description - * @mtd: MTD device structure - * @bd: the table to verify - * - * This functions performs a few sanity checks on the bad block description - * table. - */ -static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - u32 pattern_len; - u32 bits; - u32 table_size; - - if (!bd) - return; - - pattern_len = bd->len; - bits = bd->options & NAND_BBT_NRBITS_MSK; - - BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && - !(this->bbt_options & NAND_BBT_USE_FLASH)); - BUG_ON(!bits); - - if (bd->options & NAND_BBT_VERSION) - pattern_len++; - - if (bd->options & NAND_BBT_NO_OOB) { - BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); - BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); - BUG_ON(bd->offs); - if (bd->options & NAND_BBT_VERSION) - BUG_ON(bd->veroffs != bd->len); - BUG_ON(bd->options & NAND_BBT_SAVECONTENT); - } - - if (bd->options & NAND_BBT_PERCHIP) - table_size = this->chipsize >> this->bbt_erase_shift; - else - table_size = mtd->size >> this->bbt_erase_shift; - table_size >>= 3; - table_size *= bits; - if (bd->options & NAND_BBT_NO_OOB) - table_size += pattern_len; - BUG_ON(table_size > (1 << this->bbt_erase_shift)); -} - -/** - * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern - * - * The function checks, if a bad block table(s) is/are already available. If - * not it scans the device for manufacturer marked good / bad blocks and writes - * the bad block table(s) to the selected place. - * - * The bad block table memory is allocated here. It must be freed by calling - * the nand_free_bbt function. - */ -static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int len, res; - uint8_t *buf; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - - len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1; - /* - * Allocate memory (2bit per block) and clear the memory bad block - * table. - */ - this->bbt = kzalloc(len, GFP_KERNEL); - if (!this->bbt) - return -ENOMEM; - - /* - * If no primary table decriptor is given, scan the device to build a - * memory based bad block table. - */ - if (!td) { - if ((res = nand_memory_bbt(mtd, bd))) { - pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); - goto err; - } - return 0; - } - verify_bbt_descr(mtd, td); - verify_bbt_descr(mtd, md); - - /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; - buf = vmalloc(len); - if (!buf) { - res = -ENOMEM; - goto err; - } - - /* Is the bbt at a given page? */ - if (td->options & NAND_BBT_ABSPAGE) { - read_abs_bbts(mtd, buf, td, md); - } else { - /* Search the bad block table using a pattern in oob */ - search_read_bbts(mtd, buf, td, md); - } - - res = check_create(mtd, buf, bd); - if (res) - goto err; - - /* Prevent the bbt regions from erasing / writing */ - mark_bbt_region(mtd, td); - if (md) - mark_bbt_region(mtd, md); - - vfree(buf); - return 0; - -err: - kfree(this->bbt); - this->bbt = NULL; - return res; -} - -/** - * nand_update_bbt - update bad block table(s) - * @mtd: MTD device structure - * @offs: the offset of the newly marked block - * - * The function updates the bad block table(s). - */ -static int nand_update_bbt(struct mtd_info *mtd, loff_t offs) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int len, res = 0; - int chip, chipsel; - uint8_t *buf; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - - if (!this->bbt || !td) - return -EINVAL; - - /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) { - chip = (int)(offs >> this->chip_shift); - chipsel = chip; - } else { - chip = 0; - chipsel = -1; - } - - td->version[chip]++; - if (md) - md->version[chip]++; - - /* Write the bad block table to the device? */ - if (td->options & NAND_BBT_WRITE) { - res = write_bbt(mtd, buf, td, md, chipsel); - if (res < 0) - goto out; - } - /* Write the mirror bad block table to the device? */ - if (md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); - } - - out: - kfree(buf); - return res; -} - -/* - * Define some generic bad / good block scan pattern which are used - * while scanning a device for factory marked good / bad blocks. - */ -static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; - -/* Generic flash bbt descriptors */ -static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; -static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, - .pattern = bbt_pattern -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, - .pattern = mirror_pattern -}; - -static struct nand_bbt_descr bbt_main_no_oob_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP - | NAND_BBT_NO_OOB, - .len = 4, - .veroffs = 4, - .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, - .pattern = bbt_pattern -}; - -static struct nand_bbt_descr bbt_mirror_no_oob_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP - | NAND_BBT_NO_OOB, - .len = 4, - .veroffs = 4, - .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, - .pattern = mirror_pattern -}; - -#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB) -/** - * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure - * @this: NAND chip to create descriptor for - * - * This function allocates and initializes a nand_bbt_descr for BBM detection - * based on the properties of @this. The new descriptor is stored in - * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when - * passed to this function. - */ -static int nand_create_badblock_pattern(struct nand_chip *this) -{ - struct nand_bbt_descr *bd; - if (this->badblock_pattern) { - pr_warn("Bad block pattern already allocated; not replacing\n"); - return -EINVAL; - } - bd = kzalloc(sizeof(*bd), GFP_KERNEL); - if (!bd) - return -ENOMEM; - bd->options = this->bbt_options & BADBLOCK_SCAN_MASK; - bd->offs = this->badblockpos; - bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; - bd->pattern = scan_ff_pattern; - bd->options |= NAND_BBT_DYNAMICSTRUCT; - this->badblock_pattern = bd; - return 0; -} - -/** - * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd: MTD device structure - * - * This function selects the default bad block table support for the device and - * calls the nand_scan_bbt function. - */ -int nand_default_bbt(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int ret; - - /* Is a flash based bad block table requested? */ - if (this->bbt_options & NAND_BBT_USE_FLASH) { - /* Use the default pattern descriptors */ - if (!this->bbt_td) { - if (this->bbt_options & NAND_BBT_NO_OOB) { - this->bbt_td = &bbt_main_no_oob_descr; - this->bbt_md = &bbt_mirror_no_oob_descr; - } else { - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; - } - } - } else { - this->bbt_td = NULL; - this->bbt_md = NULL; - } - - if (!this->badblock_pattern) { - ret = nand_create_badblock_pattern(this); - if (ret) - return ret; - } - - return nand_scan_bbt(mtd, this->badblock_pattern); -} - -/** - * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved - * @mtd: MTD device structure - * @offs: offset in the device - */ -int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int block; - - block = (int)(offs >> this->bbt_erase_shift); - return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED; -} - -/** - * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd: MTD device structure - * @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) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int block, res; - - block = (int)(offs >> this->bbt_erase_shift); - res = bbt_get_entry(this, block); - - pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, block, res); - - switch (res) { - case BBT_BLOCK_GOOD: - return 0; - case BBT_BLOCK_WORN: - return 1; - case BBT_BLOCK_RESERVED: - return allowbbt ? 0 : 1; - } - return 1; -} - -/** - * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT - * @mtd: MTD device structure - * @offs: offset of the bad block - */ -int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int block, ret = 0; - - block = (int)(offs >> this->bbt_erase_shift); - - /* Mark bad block in memory */ - bbt_mark_entry(this, block, BBT_BLOCK_WORN); - - /* Update flash-based bad block table */ - if (this->bbt_options & NAND_BBT_USE_FLASH) - ret = nand_update_bbt(mtd, offs); - - return ret; -} diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c deleted file mode 100644 index afa0418168..0000000000 --- a/drivers/mtd/nand/nand_bch.c +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * This file provides ECC correction for more than 1 bit per block of data, - * using binary BCH codes. It relies on the generic BCH library lib/bch.c. - * - * Copyright © 2011 Ivan Djelic - * - */ - -#include -/*#include */ -#include - -#include -#include -#include -#include -#include -#include - -/** - * struct nand_bch_control - private NAND BCH control structure - * @bch: BCH control structure - * @ecclayout: private ecc layout for this BCH configuration - * @errloc: error location array - * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid - */ -struct nand_bch_control { - struct bch_control *bch; - struct nand_ecclayout ecclayout; - unsigned int *errloc; - unsigned char *eccmask; -}; - -/** - * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block - * @mtd: MTD block structure - * @buf: input buffer with raw data - * @code: output buffer with ECC - */ -int nand_bch_calculate_ecc(struct mtd_info *mtd, 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; - - memset(code, 0, chip->ecc.bytes); - encode_bch(nbc->bch, buf, chip->ecc.size, code); - - /* apply mask so that an erased page is a valid codeword */ - for (i = 0; i < chip->ecc.bytes; i++) - code[i] ^= nbc->eccmask[i]; - - return 0; -} - -/** - * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) - * @mtd: MTD block structure - * @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, - 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; - - count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc, - NULL, errloc); - if (count > 0) { - for (i = 0; i < count; i++) { - if (errloc[i] < (chip->ecc.size*8)) - /* error is located in data, correct it */ - buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); - /* else error in ecc, no action needed */ - - pr_debug("%s: corrected bitflip %u\n", - __func__, errloc[i]); - } - } else if (count < 0) { - printk(KERN_ERR "ecc unrecoverable error\n"); - count = -EBADMSG; - } - return count; -} - -/** - * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction - * @mtd: MTD block structure - * - * Returns: - * a pointer to a new NAND BCH control structure, or NULL upon failure - * - * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes - * are used to compute BCH parameters m (Galois field order) and t (error - * correction capability). @eccbytes should be equal to the number of bytes - * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8. - * - * Example: to configure 4 bit correction per 512 bytes, you should pass - * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8) - * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits) - */ -struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - unsigned int m, t, eccsteps, i; - struct nand_ecclayout *layout = nand->ecc.layout; - struct nand_bch_control *nbc = NULL; - unsigned char *erased_page; - unsigned int eccsize = nand->ecc.size; - unsigned int eccbytes = nand->ecc.bytes; - unsigned int eccstrength = nand->ecc.strength; - - if (!eccbytes && eccstrength) { - eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8); - nand->ecc.bytes = eccbytes; - } - - if (!eccsize || !eccbytes) { - printk(KERN_WARNING "ecc parameters not supplied\n"); - goto fail; - } - - m = fls(1+8*eccsize); - t = (eccbytes*8)/m; - - nbc = kzalloc(sizeof(*nbc), GFP_KERNEL); - if (!nbc) - goto fail; - - nbc->bch = init_bch(m, t, 0); - if (!nbc->bch) - goto fail; - - /* verify that eccbytes has the expected value */ - if (nbc->bch->ecc_bytes != eccbytes) { - printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", - eccbytes, nbc->bch->ecc_bytes); - goto fail; - } - - eccsteps = mtd->writesize/eccsize; - - /* if no ecc placement scheme was provided, build one */ - if (!layout) { - - /* handle large page devices only */ - if (mtd->oobsize < 64) { - printk(KERN_WARNING "must provide an oob scheme for " - "oobsize %d\n", mtd->oobsize); - goto fail; - } - - layout = &nbc->ecclayout; - layout->eccbytes = eccsteps*eccbytes; - - /* reserve 2 bytes for bad block marker */ - if (layout->eccbytes+2 > mtd->oobsize) { - printk(KERN_WARNING "no suitable oob scheme available " - "for oobsize %d eccbytes %u\n", mtd->oobsize, - eccbytes); - goto fail; - } - /* put ecc bytes at oob tail */ - for (i = 0; i < layout->eccbytes; i++) - layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; - - layout->oobfree[0].offset = 2; - layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; - - nand->ecc.layout = layout; - } - - /* sanity checks */ - if (8*(eccsize+eccbytes) >= (1 << m)) { - printk(KERN_WARNING "eccsize %u is too large\n", eccsize); - goto fail; - } - if (layout->eccbytes != (eccsteps*eccbytes)) { - printk(KERN_WARNING "invalid ecc layout\n"); - goto fail; - } - - nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); - nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); - if (!nbc->eccmask || !nbc->errloc) - goto fail; - /* - * compute and store the inverted ecc of an erased ecc block - */ - erased_page = kmalloc(eccsize, GFP_KERNEL); - if (!erased_page) - goto fail; - - memset(erased_page, 0xff, eccsize); - memset(nbc->eccmask, 0, eccbytes); - encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); - kfree(erased_page); - - for (i = 0; i < eccbytes; i++) - nbc->eccmask[i] ^= 0xff; - - if (!eccstrength) - nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize); - - return nbc; -fail: - nand_bch_free(nbc); - return NULL; -} - -/** - * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources - * @nbc: NAND BCH control structure - */ -void nand_bch_free(struct nand_bch_control *nbc) -{ - if (nbc) { - free_bch(nbc->bch); - kfree(nbc->errloc); - kfree(nbc->eccmask); - kfree(nbc); - } -} diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c deleted file mode 100644 index 05e55fce9a..0000000000 --- a/drivers/mtd/nand/nand_ecc.c +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * This file contains an ECC algorithm from Toshiba that detects and - * corrects 1 bit errors in a 256 byte block of data. - * - * drivers/mtd/nand/nand_ecc.c - * - * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) - * Toshiba America Electronics Components, Inc. - * - * Copyright (C) 2006 Thomas Gleixner - * - * As a special exception, if other files instantiate templates or use - * macros or inline functions from these files, or you compile these - * files and link them with other works to produce a work based on these - * files, these files do not by themselves cause the resulting work to be - * covered by the GNU General Public License. However the source code for - * these files must still be made available in accordance with section (3) - * of the GNU General Public License. - * - * This exception does not invalidate any other reasons why a work based on - * this file might be covered by the GNU General Public License. - */ - -#include - -#include -#include -#include - -/* - * NAND-SPL has no sofware ECC for now, so don't include nand_calculate_ecc(), - * only nand_correct_data() is needed - */ - -#if !defined(CONFIG_NAND_SPL) || defined(CONFIG_SPL_NAND_SOFTECC) -/* - * Pre-calculated 256-way 1 byte column parity - */ -static const u_char nand_ecc_precalc_table[] = { - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 -}; - -/** - * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block - * @mtd: MTD block structure - * @dat: raw data - * @ecc_code: buffer for ECC - */ -int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; - int i; - - /* Initialize variables */ - reg1 = reg2 = reg3 = 0; - - /* Build up column parity */ - for(i = 0; i < 256; i++) { - /* Get CP0 - CP5 from table */ - idx = nand_ecc_precalc_table[*dat++]; - reg1 ^= (idx & 0x3f); - - /* All bit XOR = 1 ? */ - if (idx & 0x40) { - reg3 ^= (uint8_t) i; - reg2 ^= ~((uint8_t) i); - } - } - - /* Create non-inverted ECC code from line parity */ - tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ - tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ - tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ - tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ - tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ - tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ - tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ - tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ - - tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ - tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ - tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ - tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ - tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ - tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ - tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ - tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ - - /* Calculate final ECC code */ - ecc_code[0] = ~tmp1; - ecc_code[1] = ~tmp2; - ecc_code[2] = ((~reg1) << 2) | 0x03; - - return 0; -} -#endif /* CONFIG_NAND_SPL */ - -static inline int countbits(uint32_t byte) -{ - int res = 0; - - for (;byte; byte >>= 1) - res += byte & 0x01; - return res; -} - -/** - * nand_correct_data - [NAND Interface] Detect and correct bit error(s) - * @mtd: MTD block structure - * @dat: 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 byte block - */ -int nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - uint8_t s0, s1, s2; - - s1 = calc_ecc[0] ^ read_ecc[0]; - s0 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; - if ((s0 | s1 | s2) == 0) - return 0; - - /* Check for a single bit error */ - if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && - ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && - ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { - - uint32_t byteoffs, bitnum; - - byteoffs = (s1 << 0) & 0x80; - byteoffs |= (s1 << 1) & 0x40; - byteoffs |= (s1 << 2) & 0x20; - byteoffs |= (s1 << 3) & 0x10; - - byteoffs |= (s0 >> 4) & 0x08; - byteoffs |= (s0 >> 3) & 0x04; - byteoffs |= (s0 >> 2) & 0x02; - byteoffs |= (s0 >> 1) & 0x01; - - bitnum = (s2 >> 5) & 0x04; - bitnum |= (s2 >> 4) & 0x02; - bitnum |= (s2 >> 3) & 0x01; - - dat[byteoffs] ^= (1 << bitnum); - - return 1; - } - - if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) - return 1; - - return -EBADMSG; -} diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c deleted file mode 100644 index 4009d64123..0000000000 --- a/drivers/mtd/nand/nand_ids.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ -#include -#include -#include - -#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS -#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) - -#define SP_OPTIONS NAND_NEED_READRDY -#define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16) - -/* - * The chip ID list: - * name, device ID, page size, chip size in MiB, eraseblock size, options - * - * If page size and eraseblock size are 0, the sizes are taken from the - * extended chip ID. - */ -struct nand_flash_dev nand_flash_ids[] = { -#ifdef CONFIG_MTD_NAND_MUSEUM_IDS - LEGACY_ID_NAND("NAND 1MiB 5V 8-bit", 0x6e, 1, SZ_4K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 2MiB 5V 8-bit", 0x64, 2, SZ_4K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 1MiB 3,3V 8-bit", 0xe8, 1, SZ_4K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 1MiB 3,3V 8-bit", 0xec, 1, SZ_4K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 2MiB 3,3V 8-bit", 0xea, 2, SZ_4K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xd5, 4, SZ_8K, SP_OPTIONS), - - LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xe6, 8, SZ_8K, SP_OPTIONS), -#endif - /* - * Some incompatible NAND chips share device ID's and so must be - * listed by full ID. We list them first so that we can easily identify - * the most specific match. - */ - {"TC58NVG0S3E 1G 3.3V 8-bit", - { .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} }, - SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), - 2 }, - {"TC58NVG2S0F 4G 3.3V 8-bit", - { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, - SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, - {"TC58NVG2S0H 4G 3.3V 8-bit", - { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} }, - SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) }, - {"TC58NVG3S0F 8G 3.3V 8-bit", - { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} }, - SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) }, - {"TC58NVG5D2 32G 3.3V 8-bit", - { .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} }, - SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) }, - {"TC58NVG6D2 64G 3.3V 8-bit", - { .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} }, - SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) }, - {"SDTNRGAMA 64G 3.3V 8-bit", - { .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} }, - SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) }, - {"H27UCG8T2ATR-BC 64G 3.3V 8-bit", - { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, - SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640, - NAND_ECC_INFO(40, SZ_1K), 4 }, - {"H27QCG8T2E5R‐BCF 64G 3.3V 8-bit", - { .id = {0xad, 0xde, 0x14, 0xa7, 0x42, 0x4a} }, - SZ_16K, SZ_8K, SZ_4M, NAND_NEED_SCRAMBLING, 6, 1664, - NAND_ECC_INFO(56, SZ_1K), 1 }, - - LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE5, 4, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xD6, 8, SZ_8K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xE6, 8, SZ_8K, SP_OPTIONS), - - LEGACY_ID_NAND("NAND 16MiB 1,8V 8-bit", 0x33, 16, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 16MiB 3,3V 8-bit", 0x73, 16, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 16MiB 1,8V 16-bit", 0x43, 16, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 16MiB 3,3V 16-bit", 0x53, 16, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND("NAND 32MiB 1,8V 8-bit", 0x35, 32, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 32MiB 3,3V 8-bit", 0x75, 32, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 32MiB 1,8V 16-bit", 0x45, 32, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 32MiB 3,3V 16-bit", 0x55, 32, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND("NAND 64MiB 1,8V 8-bit", 0x36, 64, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 64MiB 3,3V 8-bit", 0x76, 64, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 64MiB 1,8V 16-bit", 0x46, 64, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 64MiB 3,3V 16-bit", 0x56, 64, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x78, 128, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x39, 128, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 128MiB 3,3V 8-bit", 0x79, 128, SZ_16K, SP_OPTIONS), - LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x72, 128, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x49, 128, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x74, 128, SZ_16K, SP_OPTIONS16), - LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x59, 128, SZ_16K, SP_OPTIONS16), - - LEGACY_ID_NAND("NAND 256MiB 3,3V 8-bit", 0x71, 256, SZ_16K, SP_OPTIONS), - - /* - * These are the new chips with large page size. Their page size and - * eraseblock size are determined from the extended ID bytes. - */ - - /* 512 Megabit */ - EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA2, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA0, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF2, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xD0, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF0, 64, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB2, 64, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB0, 64, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC2, 64, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC0, 64, LP_OPTIONS16), - - /* 1 Gigabit */ - EXTENDED_ID_NAND("NAND 128MiB 1,8V 8-bit", 0xA1, 128, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xF1, 128, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xD1, 128, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xB1, 128, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 128MiB 3,3V 16-bit", 0xC1, 128, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xAD, 128, LP_OPTIONS16), - - /* 2 Gigabit */ - EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit", 0xAA, 256, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit", 0xDA, 256, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16), - - /* 4 Gigabit */ - EXTENDED_ID_NAND("NAND 512MiB 1,8V 8-bit", 0xAC, 512, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 512MiB 3,3V 8-bit", 0xDC, 512, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 512MiB 1,8V 16-bit", 0xBC, 512, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 512MiB 3,3V 16-bit", 0xCC, 512, LP_OPTIONS16), - - /* 8 Gigabit */ - EXTENDED_ID_NAND("NAND 1GiB 1,8V 8-bit", 0xA3, 1024, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 1GiB 3,3V 8-bit", 0xD3, 1024, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 1GiB 1,8V 16-bit", 0xB3, 1024, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 1GiB 3,3V 16-bit", 0xC3, 1024, LP_OPTIONS16), - - /* 16 Gigabit */ - EXTENDED_ID_NAND("NAND 2GiB 1,8V 8-bit", 0xA5, 2048, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 2GiB 3,3V 8-bit", 0xD5, 2048, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 2GiB 1,8V 16-bit", 0xB5, 2048, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 2GiB 3,3V 16-bit", 0xC5, 2048, LP_OPTIONS16), - - /* 32 Gigabit */ - EXTENDED_ID_NAND("NAND 4GiB 1,8V 8-bit", 0xA7, 4096, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 4GiB 3,3V 8-bit", 0xD7, 4096, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 4GiB 1,8V 16-bit", 0xB7, 4096, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 4GiB 3,3V 16-bit", 0xC7, 4096, LP_OPTIONS16), - - /* 64 Gigabit */ - EXTENDED_ID_NAND("NAND 8GiB 1,8V 8-bit", 0xAE, 8192, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 8GiB 3,3V 8-bit", 0xDE, 8192, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 8GiB 1,8V 16-bit", 0xBE, 8192, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 8GiB 3,3V 16-bit", 0xCE, 8192, LP_OPTIONS16), - - /* 128 Gigabit */ - EXTENDED_ID_NAND("NAND 16GiB 1,8V 8-bit", 0x1A, 16384, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 16GiB 3,3V 8-bit", 0x3A, 16384, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 16GiB 1,8V 16-bit", 0x2A, 16384, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 16GiB 3,3V 16-bit", 0x4A, 16384, LP_OPTIONS16), - - /* 256 Gigabit */ - EXTENDED_ID_NAND("NAND 32GiB 1,8V 8-bit", 0x1C, 32768, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 32GiB 3,3V 8-bit", 0x3C, 32768, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 32GiB 1,8V 16-bit", 0x2C, 32768, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 32GiB 3,3V 16-bit", 0x4C, 32768, LP_OPTIONS16), - - /* 512 Gigabit */ - EXTENDED_ID_NAND("NAND 64GiB 1,8V 8-bit", 0x1E, 65536, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64GiB 3,3V 8-bit", 0x3E, 65536, LP_OPTIONS), - EXTENDED_ID_NAND("NAND 64GiB 1,8V 16-bit", 0x2E, 65536, LP_OPTIONS16), - EXTENDED_ID_NAND("NAND 64GiB 3,3V 16-bit", 0x4E, 65536, LP_OPTIONS16), - - {NULL} -}; - -/* Manufacturer IDs */ -struct nand_manufacturers nand_manuf_ids[] = { - {NAND_MFR_TOSHIBA, "Toshiba"}, - {NAND_MFR_SAMSUNG, "Samsung"}, - {NAND_MFR_FUJITSU, "Fujitsu"}, - {NAND_MFR_NATIONAL, "National"}, - {NAND_MFR_RENESAS, "Renesas"}, - {NAND_MFR_STMICRO, "ST Micro"}, - {NAND_MFR_HYNIX, "Hynix"}, - {NAND_MFR_MICRON, "Micron"}, - {NAND_MFR_AMD, "AMD/Spansion"}, - {NAND_MFR_MACRONIX, "Macronix"}, - {NAND_MFR_EON, "Eon"}, - {NAND_MFR_SANDISK, "SanDisk"}, - {NAND_MFR_INTEL, "Intel"}, - {NAND_MFR_ATO, "ATO"}, - {0x0, "Unknown"} -}; - -EXPORT_SYMBOL(nand_manuf_ids); -EXPORT_SYMBOL(nand_flash_ids); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Thomas Gleixner "); -MODULE_DESCRIPTION("Nand device & manufacturer IDs"); diff --git a/drivers/mtd/nand/nand_plat.c b/drivers/mtd/nand/nand_plat.c deleted file mode 100644 index 335c3e3471..0000000000 --- a/drivers/mtd/nand/nand_plat.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Genericish driver for memory mapped NAND devices - * - * Copyright (c) 2006-2009 Analog Devices Inc. - * Licensed under the GPL-2 or later. - */ - -/* Your board must implement the following macros: - * NAND_PLAT_WRITE_CMD(chip, cmd) - * NAND_PLAT_WRITE_ADR(chip, cmd) - * NAND_PLAT_INIT() - * - * It may also implement the following: - * NAND_PLAT_DEV_READY(chip) - */ - -#include -#include -#ifdef NAND_PLAT_GPIO_DEV_READY -# include -# define NAND_PLAT_DEV_READY(chip) gpio_get_value(NAND_PLAT_GPIO_DEV_READY) -#endif - -#include - -static void plat_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - NAND_PLAT_WRITE_CMD(this, cmd); - else - NAND_PLAT_WRITE_ADR(this, cmd); -} - -#ifdef NAND_PLAT_DEV_READY -static int plat_dev_ready(struct mtd_info *mtd) -{ - return NAND_PLAT_DEV_READY((struct nand_chip *)mtd_to_nand(mtd)); -} -#else -# define plat_dev_ready NULL -#endif - -int board_nand_init(struct nand_chip *nand) -{ -#ifdef NAND_PLAT_GPIO_DEV_READY - gpio_request(NAND_PLAT_GPIO_DEV_READY, "nand-plat"); - gpio_direction_input(NAND_PLAT_GPIO_DEV_READY); -#endif - -#ifdef NAND_PLAT_INIT - NAND_PLAT_INIT(); -#endif - - nand->cmd_ctrl = plat_cmd_ctrl; - nand->dev_ready = plat_dev_ready; - nand->ecc.mode = NAND_ECC_SOFT; - - return 0; -} diff --git a/drivers/mtd/nand/nand_spl_load.c b/drivers/mtd/nand/nand_spl_load.c deleted file mode 100644 index ecd373e054..0000000000 --- a/drivers/mtd/nand/nand_spl_load.c +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2011 - * Heiko Schocher, DENX Software Engineering, hs@denx.de. - */ - -#include -#include - -/* - * The main entry for NAND booting. It's necessary that SDRAM is already - * configured and available since this code loads the main U-Boot image - * from NAND into SDRAM and starts it from there. - */ -void nand_boot(void) -{ - __attribute__((noreturn)) void (*uboot)(void); - - /* - * Load U-Boot image from NAND into RAM - */ - nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, - CONFIG_SYS_NAND_U_BOOT_SIZE, - (void *)CONFIG_SYS_NAND_U_BOOT_DST); - -#ifdef CONFIG_NAND_ENV_DST - nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, - (void *)CONFIG_NAND_ENV_DST); - -#ifdef CONFIG_ENV_OFFSET_REDUND - nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, - (void *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); -#endif -#endif - - /* - * Jump to U-Boot image - */ - uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; - (*uboot)(); -} diff --git a/drivers/mtd/nand/nand_spl_loaders.c b/drivers/mtd/nand/nand_spl_loaders.c deleted file mode 100644 index 177c12b581..0000000000 --- a/drivers/mtd/nand/nand_spl_loaders.c +++ /dev/null @@ -1,104 +0,0 @@ -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - unsigned int block, lastblock; - unsigned int page, page_offset; - - /* offs has to be aligned to a page address! */ - block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; - lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; - page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; - page_offset = offs % CONFIG_SYS_NAND_PAGE_SIZE; - - while (block <= lastblock) { - if (!nand_is_bad_block(block)) { - /* Skip bad blocks */ - while (page < CONFIG_SYS_NAND_PAGE_COUNT) { - nand_read_page(block, page, dst); - /* - * When offs is not aligned to page address the - * extra offset is copied to dst as well. Copy - * the image such that its first byte will be - * at the dst. - */ - if (unlikely(page_offset)) { - memmove(dst, dst + page_offset, - CONFIG_SYS_NAND_PAGE_SIZE); - dst = (void *)((int)dst - page_offset); - page_offset = 0; - } - dst += CONFIG_SYS_NAND_PAGE_SIZE; - page++; - } - - page = 0; - } else { - lastblock++; - } - - block++; - } - - return 0; -} - -#ifdef CONFIG_SPL_UBI -/* - * Temporary storage for non NAND page aligned and non NAND page sized - * reads. Note: This does not support runtime detected FLASH yet, but - * that should be reasonably easy to fix by making the buffer large - * enough :) - */ -static u8 scratch_buf[CONFIG_SYS_NAND_PAGE_SIZE]; - -/** - * nand_spl_read_block - Read data from physical eraseblock into a buffer - * @block: Number of the physical eraseblock - * @offset: Data offset from the start of @peb - * @len: Data size to read - * @dst: Address of the destination buffer - * - * This could be further optimized if we'd have a subpage read - * function in the simple code. On NAND which allows subpage reads - * this would spare quite some time to readout e.g. the VID header of - * UBI. - * - * Notes: - * @offset + @len are not allowed to be larger than a physical - * erase block. No sanity check done for simplicity reasons. - * - * To support runtime detected flash this needs to be extended by - * information about the actual flash geometry, but thats beyond the - * scope of this effort and for most applications where fast boot is - * required it is not an issue anyway. - */ -int nand_spl_read_block(int block, int offset, int len, void *dst) -{ - int page, read; - - /* Calculate the page number */ - page = offset / CONFIG_SYS_NAND_PAGE_SIZE; - - /* Offset to the start of a flash page */ - offset = offset % CONFIG_SYS_NAND_PAGE_SIZE; - - while (len) { - /* - * Non page aligned reads go to the scratch buffer. - * Page aligned reads go directly to the destination. - */ - if (offset || len < CONFIG_SYS_NAND_PAGE_SIZE) { - nand_read_page(block, page, scratch_buf); - read = min(len, CONFIG_SYS_NAND_PAGE_SIZE - offset); - memcpy(dst, scratch_buf + offset, read); - offset = 0; - } else { - nand_read_page(block, page, dst); - read = CONFIG_SYS_NAND_PAGE_SIZE; - } - page++; - len -= read; - dst += read; - } - return 0; -} -#endif diff --git a/drivers/mtd/nand/nand_spl_simple.c b/drivers/mtd/nand/nand_spl_simple.c deleted file mode 100644 index 09e053541a..0000000000 --- a/drivers/mtd/nand/nand_spl_simple.c +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2006-2008 - * Stefan Roese, DENX Software Engineering, sr@denx.de. - */ - -#include -#include -#include -#include - -static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; -static struct mtd_info *mtd; -static struct nand_chip nand_chip; - -#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ - CONFIG_SYS_NAND_ECCSIZE) -#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) - - -#if (CONFIG_SYS_NAND_PAGE_SIZE <= 512) -/* - * NAND command for small page NAND devices (512) - */ -static int nand_command(int block, int page, uint32_t offs, - u8 cmd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; - - while (!this->dev_ready(mtd)) - ; - - /* Begin command latch cycle */ - this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - /* Set ALE and clear CLE to start address cycle */ - /* Column address */ - this->cmd_ctrl(mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE); - this->cmd_ctrl(mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */ - this->cmd_ctrl(mtd, (page_addr >> 8) & 0xff, - NAND_CTRL_ALE); /* A[24:17] */ -#ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE - /* One more address cycle for devices > 32MiB */ - this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f, - NAND_CTRL_ALE); /* A[28:25] */ -#endif - /* Latch in address */ - this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Wait a while for the data to be ready - */ - while (!this->dev_ready(mtd)) - ; - - return 0; -} -#else -/* - * NAND command for large page NAND devices (2k) - */ -static int nand_command(int block, int page, uint32_t offs, - u8 cmd) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; - void (*hwctrl)(struct mtd_info *mtd, int cmd, - unsigned int ctrl) = this->cmd_ctrl; - - while (!this->dev_ready(mtd)) - ; - - /* Emulate NAND_CMD_READOOB */ - if (cmd == NAND_CMD_READOOB) { - offs += CONFIG_SYS_NAND_PAGE_SIZE; - cmd = NAND_CMD_READ0; - } - - /* Shift the offset from byte addressing to word addressing. */ - if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) - offs >>= 1; - - /* Begin command latch cycle */ - hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - /* Set ALE and clear CLE to start address cycle */ - /* Column address */ - hwctrl(mtd, offs & 0xff, - NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ - hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */ - /* Row address */ - hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */ - hwctrl(mtd, ((page_addr >> 8) & 0xff), - NAND_CTRL_ALE); /* A[27:20] */ -#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE - /* One more address cycle for devices > 128MiB */ - hwctrl(mtd, (page_addr >> 16) & 0x0f, - NAND_CTRL_ALE); /* A[31:28] */ -#endif - /* Latch in address */ - hwctrl(mtd, NAND_CMD_READSTART, - NAND_CTRL_CLE | NAND_CTRL_CHANGE); - hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Wait a while for the data to be ready - */ - while (!this->dev_ready(mtd)) - ; - - return 0; -} -#endif - -static int nand_is_bad_block(int block) -{ - struct nand_chip *this = mtd_to_nand(mtd); - u_char bb_data[2]; - - nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, - NAND_CMD_READOOB); - - /* - * Read one byte (or two if it's a 16 bit chip). - */ - if (this->options & NAND_BUSWIDTH_16) { - this->read_buf(mtd, bb_data, 2); - if (bb_data[0] != 0xff || bb_data[1] != 0xff) - return 1; - } else { - this->read_buf(mtd, bb_data, 1); - if (bb_data[0] != 0xff) - return 1; - } - - return 0; -} - -#if defined(CONFIG_SYS_NAND_HW_ECC_OOBFIRST) -static int nand_read_page(int block, int page, uchar *dst) -{ - struct nand_chip *this = mtd_to_nand(mtd); - u_char ecc_calc[ECCTOTAL]; - u_char ecc_code[ECCTOTAL]; - u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; - int i; - int eccsize = CONFIG_SYS_NAND_ECCSIZE; - int eccbytes = CONFIG_SYS_NAND_ECCBYTES; - int eccsteps = ECCSTEPS; - uint8_t *p = dst; - - nand_command(block, page, 0, NAND_CMD_READOOB); - this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); - nand_command(block, page, 0, NAND_CMD_READ0); - - /* Pick the ECC bytes out of the oob data */ - for (i = 0; i < ECCTOTAL; i++) - ecc_code[i] = oob_data[nand_ecc_pos[i]]; - - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - this->ecc.hwctl(mtd, NAND_ECC_READ); - this->read_buf(mtd, p, eccsize); - this->ecc.calculate(mtd, p, &ecc_calc[i]); - this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - } - - return 0; -} -#else -static int nand_read_page(int block, int page, void *dst) -{ - struct nand_chip *this = mtd_to_nand(mtd); - u_char ecc_calc[ECCTOTAL]; - u_char ecc_code[ECCTOTAL]; - u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; - int i; - int eccsize = CONFIG_SYS_NAND_ECCSIZE; - int eccbytes = CONFIG_SYS_NAND_ECCBYTES; - int eccsteps = ECCSTEPS; - uint8_t *p = dst; - - nand_command(block, page, 0, NAND_CMD_READ0); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - if (this->ecc.mode != NAND_ECC_SOFT) - this->ecc.hwctl(mtd, NAND_ECC_READ); - this->read_buf(mtd, p, eccsize); - this->ecc.calculate(mtd, p, &ecc_calc[i]); - } - this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); - - /* Pick the ECC bytes out of the oob data */ - for (i = 0; i < ECCTOTAL; i++) - ecc_code[i] = oob_data[nand_ecc_pos[i]]; - - eccsteps = ECCSTEPS; - p = dst; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - /* No chance to do something with the possible error message - * from correct_data(). We just hope that all possible errors - * are corrected by this routine. - */ - this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - } - - return 0; -} -#endif - -/* nand_init() - initialize data to make nand usable by SPL */ -void nand_init(void) -{ - /* - * Init board specific nand support - */ - mtd = nand_to_mtd(&nand_chip); - nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = - (void __iomem *)CONFIG_SYS_NAND_BASE; - board_nand_init(&nand_chip); - -#ifdef CONFIG_SPL_NAND_SOFTECC - if (nand_chip.ecc.mode == NAND_ECC_SOFT) { - nand_chip.ecc.calculate = nand_calculate_ecc; - nand_chip.ecc.correct = nand_correct_data; - } -#endif - - if (nand_chip.select_chip) - nand_chip.select_chip(mtd, 0); -} - -/* Unselect after operation */ -void nand_deselect(void) -{ - if (nand_chip.select_chip) - nand_chip.select_chip(mtd, -1); -} - -#include "nand_spl_loaders.c" diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c deleted file mode 100644 index c0545a4fb1..0000000000 --- a/drivers/mtd/nand/nand_timings.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (C) 2014 Free Electrons - * - * Author: Boris BREZILLON - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ -#include -#include -#include - -static const struct nand_data_interface onfi_sdr_timings[] = { - /* Mode 0 */ - { - .type = NAND_SDR_IFACE, - .timings.sdr = { - .tCCS_min = 500000, - .tR_max = 200000000, - .tADL_min = 400000, - .tALH_min = 20000, - .tALS_min = 50000, - .tAR_min = 25000, - .tCEA_max = 100000, - .tCEH_min = 20000, - .tCH_min = 20000, - .tCHZ_max = 100000, - .tCLH_min = 20000, - .tCLR_min = 20000, - .tCLS_min = 50000, - .tCOH_min = 0, - .tCS_min = 70000, - .tDH_min = 20000, - .tDS_min = 40000, - .tFEAT_max = 1000000, - .tIR_min = 10000, - .tITC_max = 1000000, - .tRC_min = 100000, - .tREA_max = 40000, - .tREH_min = 30000, - .tRHOH_min = 0, - .tRHW_min = 200000, - .tRHZ_max = 200000, - .tRLOH_min = 0, - .tRP_min = 50000, - .tRR_min = 40000, - .tRST_max = 250000000000ULL, - .tWB_max = 200000, - .tWC_min = 100000, - .tWH_min = 30000, - .tWHR_min = 120000, - .tWP_min = 50000, - .tWW_min = 100000, - }, - }, - /* Mode 1 */ - { - .type = NAND_SDR_IFACE, - .timings.sdr = { - .tCCS_min = 500000, - .tR_max = 200000000, - .tADL_min = 400000, - .tALH_min = 10000, - .tALS_min = 25000, - .tAR_min = 10000, - .tCEA_max = 45000, - .tCEH_min = 20000, - .tCH_min = 10000, - .tCHZ_max = 50000, - .tCLH_min = 10000, - .tCLR_min = 10000, - .tCLS_min = 25000, - .tCOH_min = 15000, - .tCS_min = 35000, - .tDH_min = 10000, - .tDS_min = 20000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 50000, - .tREA_max = 30000, - .tREH_min = 15000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 0, - .tRP_min = 25000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 45000, - .tWH_min = 15000, - .tWHR_min = 80000, - .tWP_min = 25000, - .tWW_min = 100000, - }, - }, - /* Mode 2 */ - { - .type = NAND_SDR_IFACE, - .timings.sdr = { - .tCCS_min = 500000, - .tR_max = 200000000, - .tADL_min = 400000, - .tALH_min = 10000, - .tALS_min = 15000, - .tAR_min = 10000, - .tCEA_max = 30000, - .tCEH_min = 20000, - .tCH_min = 10000, - .tCHZ_max = 50000, - .tCLH_min = 10000, - .tCLR_min = 10000, - .tCLS_min = 15000, - .tCOH_min = 15000, - .tCS_min = 25000, - .tDH_min = 5000, - .tDS_min = 15000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 35000, - .tREA_max = 25000, - .tREH_min = 15000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 0, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tRP_min = 17000, - .tWC_min = 35000, - .tWH_min = 15000, - .tWHR_min = 80000, - .tWP_min = 17000, - .tWW_min = 100000, - }, - }, - /* Mode 3 */ - { - .type = NAND_SDR_IFACE, - .timings.sdr = { - .tCCS_min = 500000, - .tR_max = 200000000, - .tADL_min = 400000, - .tALH_min = 5000, - .tALS_min = 10000, - .tAR_min = 10000, - .tCEA_max = 25000, - .tCEH_min = 20000, - .tCH_min = 5000, - .tCHZ_max = 50000, - .tCLH_min = 5000, - .tCLR_min = 10000, - .tCLS_min = 10000, - .tCOH_min = 15000, - .tCS_min = 25000, - .tDH_min = 5000, - .tDS_min = 10000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 30000, - .tREA_max = 20000, - .tREH_min = 10000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 0, - .tRP_min = 15000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 30000, - .tWH_min = 10000, - .tWHR_min = 80000, - .tWP_min = 15000, - .tWW_min = 100000, - }, - }, - /* Mode 4 */ - { - .type = NAND_SDR_IFACE, - .timings.sdr = { - .tCCS_min = 500000, - .tR_max = 200000000, - .tADL_min = 400000, - .tALH_min = 5000, - .tALS_min = 10000, - .tAR_min = 10000, - .tCEA_max = 25000, - .tCEH_min = 20000, - .tCH_min = 5000, - .tCHZ_max = 30000, - .tCLH_min = 5000, - .tCLR_min = 10000, - .tCLS_min = 10000, - .tCOH_min = 15000, - .tCS_min = 20000, - .tDH_min = 5000, - .tDS_min = 10000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 25000, - .tREA_max = 20000, - .tREH_min = 10000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 5000, - .tRP_min = 12000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 25000, - .tWH_min = 10000, - .tWHR_min = 80000, - .tWP_min = 12000, - .tWW_min = 100000, - }, - }, - /* Mode 5 */ - { - .type = NAND_SDR_IFACE, - .timings.sdr = { - .tCCS_min = 500000, - .tR_max = 200000000, - .tADL_min = 400000, - .tALH_min = 5000, - .tALS_min = 10000, - .tAR_min = 10000, - .tCEA_max = 25000, - .tCEH_min = 20000, - .tCH_min = 5000, - .tCHZ_max = 30000, - .tCLH_min = 5000, - .tCLR_min = 10000, - .tCLS_min = 10000, - .tCOH_min = 15000, - .tCS_min = 15000, - .tDH_min = 5000, - .tDS_min = 7000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 20000, - .tREA_max = 16000, - .tREH_min = 7000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 5000, - .tRP_min = 10000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 20000, - .tWH_min = 7000, - .tWHR_min = 80000, - .tWP_min = 10000, - .tWW_min = 100000, - }, - }, -}; - -/** - * 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_init_data_interface - [NAND Interface] Initialize a data interface from - * given ONFI mode - * @iface: The data interface to be initialized - * @mode: The ONFI timing mode - */ -int onfi_init_data_interface(struct nand_chip *chip, - struct nand_data_interface *iface, - enum nand_data_interface_type type, - int timing_mode) -{ - if (type != NAND_SDR_IFACE) - return -EINVAL; - - if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings)) - return -EINVAL; - - *iface = onfi_sdr_timings[timing_mode]; - - /* - * Initialize timings that cannot be deduced from timing mode: - * tR, tPROG, tCCS, ... - * These information are part of the ONFI parameter page. - */ - if (chip->onfi_version) { - struct nand_onfi_params *params = &chip->onfi_params; - struct nand_sdr_timings *timings = &iface->timings.sdr; - - /* microseconds -> picoseconds */ - timings->tPROG_max = 1000000ULL * le16_to_cpu(params->t_prog); - timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers); - timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r); - - /* nanoseconds -> picoseconds */ - timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs); - } - - return 0; -} -EXPORT_SYMBOL(onfi_init_data_interface); - -/** - * nand_get_default_data_interface - [NAND Interface] Retrieve NAND - * data interface for mode 0. This is used as default timing after - * reset. - */ -const struct nand_data_interface *nand_get_default_data_interface(void) -{ - return &onfi_sdr_timings[0]; -} -EXPORT_SYMBOL(nand_get_default_data_interface); diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c deleted file mode 100644 index 1ded7aa920..0000000000 --- a/drivers/mtd/nand/nand_util.c +++ /dev/null @@ -1,904 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * drivers/mtd/nand/nand_util.c - * - * Copyright (C) 2006 by Weiss-Electronic GmbH. - * All rights reserved. - * - * @author: Guido Classen - * @descr: NAND Flash support - * @references: borrowed heavily from Linux mtd-utils code: - * flash_eraseall.c by Arcom Control System Ltd - * nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com) - * and Thomas Gleixner (tglx@linutronix.de) - * - * Copyright (C) 2008 Nokia Corporation: drop_ffs() function by - * Artem Bityutskiy from mtd-utils - * - * Copyright 2010 Freescale Semiconductor - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -typedef struct erase_info erase_info_t; -typedef struct mtd_info mtd_info_t; - -/* support only for native endian JFFS2 */ -#define cpu_to_je16(x) (x) -#define cpu_to_je32(x) (x) - -/** - * nand_erase_opts: - erase NAND flash with support for various options - * (jffs2 formatting) - * - * @param mtd nand mtd instance to erase - * @param opts options, @see struct nand_erase_options - * @return 0 in case of success - * - * This code is ported from flash_eraseall.c from Linux mtd utils by - * Arcom Control System Ltd. - */ -int nand_erase_opts(struct mtd_info *mtd, - const nand_erase_options_t *opts) -{ - struct jffs2_unknown_node cleanmarker; - erase_info_t erase; - unsigned long erase_length, erased_length; /* in blocks */ - int result; - int percent_complete = -1; - const char *mtd_device = mtd->name; - struct mtd_oob_ops oob_opts; - struct nand_chip *chip = mtd_to_nand(mtd); - - if ((opts->offset & (mtd->erasesize - 1)) != 0) { - printf("Attempt to erase non block-aligned data\n"); - return -1; - } - - memset(&erase, 0, sizeof(erase)); - memset(&oob_opts, 0, sizeof(oob_opts)); - - erase.mtd = mtd; - erase.len = mtd->erasesize; - erase.addr = opts->offset; - erase_length = lldiv(opts->length + mtd->erasesize - 1, - mtd->erasesize); - - cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); - cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); - cleanmarker.totlen = cpu_to_je32(8); - - /* scrub option allows to erase badblock. To prevent internal - * check from erase() method, set block check method to dummy - * and disable bad block table while erasing. - */ - if (opts->scrub) { - erase.scrub = opts->scrub; - /* - * We don't need the bad block table anymore... - * after scrub, there are no bad blocks left! - */ - if (chip->bbt) { - kfree(chip->bbt); - } - chip->bbt = NULL; - chip->options &= ~NAND_BBT_SCANNED; - } - - for (erased_length = 0; - erased_length < erase_length; - erase.addr += mtd->erasesize) { - - WATCHDOG_RESET(); - - if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) { - puts("Size of erase exceeds limit\n"); - return -EFBIG; - } - if (!opts->scrub) { - int ret = mtd_block_isbad(mtd, erase.addr); - if (ret > 0) { - if (!opts->quiet) - printf("\rSkipping bad block at " - "0x%08llx " - " \n", - erase.addr); - - if (!opts->spread) - erased_length++; - - continue; - - } else if (ret < 0) { - printf("\n%s: MTD get bad block failed: %d\n", - mtd_device, - ret); - return -1; - } - } - - erased_length++; - - result = mtd_erase(mtd, &erase); - if (result != 0) { - printf("\n%s: MTD Erase failure: %d\n", - mtd_device, result); - continue; - } - - /* format for JFFS2 ? */ - if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) { - struct mtd_oob_ops ops; - ops.ooblen = 8; - ops.datbuf = NULL; - ops.oobbuf = (uint8_t *)&cleanmarker; - ops.ooboffs = 0; - ops.mode = MTD_OPS_AUTO_OOB; - - result = mtd_write_oob(mtd, erase.addr, &ops); - if (result != 0) { - printf("\n%s: MTD writeoob failure: %d\n", - mtd_device, result); - continue; - } - } - - if (!opts->quiet) { - unsigned long long n = erased_length * 100ULL; - int percent; - - do_div(n, erase_length); - percent = (int)n; - - /* output progress message only at whole percent - * steps to reduce the number of messages printed - * on (slow) serial consoles - */ - if (percent != percent_complete) { - percent_complete = percent; - - printf("\rErasing at 0x%llx -- %3d%% complete.", - erase.addr, percent); - - if (opts->jffs2 && result == 0) - printf(" Cleanmarker written at 0x%llx.", - erase.addr); - } - } - } - if (!opts->quiet) - printf("\n"); - - return 0; -} - -#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK - -#define NAND_CMD_LOCK_TIGHT 0x2c -#define NAND_CMD_LOCK_STATUS 0x7a - -/****************************************************************************** - * Support for locking / unlocking operations of some NAND devices - *****************************************************************************/ - -/** - * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT - * state - * - * @param mtd nand mtd instance - * @param tight bring device in lock tight mode - * - * @return 0 on success, -1 in case of error - * - * The lock / lock-tight command only applies to the whole chip. To get some - * parts of the chip lock and others unlocked use the following sequence: - * - * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin) - * - Call nand_unlock() once for each consecutive area to be unlocked - * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1) - * - * If the device is in lock-tight state software can't change the - * current active lock/unlock state of all pages. nand_lock() / nand_unlock() - * calls will fail. It is only posible to leave lock-tight state by - * an hardware signal (low pulse on _WP pin) or by power down. - */ -int nand_lock(struct mtd_info *mtd, int tight) -{ - int ret = 0; - int status; - struct nand_chip *chip = mtd_to_nand(mtd); - - /* select the NAND device */ - chip->select_chip(mtd, 0); - - /* check the Lock Tight Status */ - chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, 0); - if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { - printf("nand_lock: Device is locked tight!\n"); - ret = -1; - goto out; - } - - chip->cmdfunc(mtd, - (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK), - -1, -1); - - /* call wait ready function */ - status = chip->waitfunc(mtd, chip); - - /* see if device thinks it succeeded */ - if (status & 0x01) { - ret = -1; - } - - out: - /* de-select the NAND device */ - chip->select_chip(mtd, -1); - return ret; -} - -/** - * nand_get_lock_status: - query current lock state from one page of NAND - * flash - * - * @param mtd nand mtd instance - * @param offset page address to query (must be page-aligned!) - * - * @return -1 in case of error - * >0 lock status: - * bitfield with the following combinations: - * NAND_LOCK_STATUS_TIGHT: page in tight state - * NAND_LOCK_STATUS_UNLOCK: page unlocked - * - */ -int nand_get_lock_status(struct mtd_info *mtd, loff_t offset) -{ - int ret = 0; - int chipnr; - int page; - struct nand_chip *chip = mtd_to_nand(mtd); - - /* select the NAND device */ - chipnr = (int)(offset >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - - if ((offset & (mtd->writesize - 1)) != 0) { - printf("nand_get_lock_status: " - "Start address must be beginning of " - "nand page!\n"); - ret = -1; - goto out; - } - - /* check the Lock Status */ - page = (int)(offset >> chip->page_shift); - chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); - - ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT - | NAND_LOCK_STATUS_UNLOCK); - - out: - /* de-select the NAND device */ - chip->select_chip(mtd, -1); - return ret; -} - -/** - * nand_unlock: - Unlock area of NAND pages - * only one consecutive area can be unlocked at one time! - * - * @param mtd nand mtd instance - * @param start start byte address - * @param length number of bytes to unlock (must be a multiple of - * page size mtd->writesize) - * @param allexcept if set, unlock everything not selected - * - * @return 0 on success, -1 in case of error - */ -int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, - int allexcept) -{ - int ret = 0; - int chipnr; - int status; - int page; - struct nand_chip *chip = mtd_to_nand(mtd); - - debug("nand_unlock%s: start: %08llx, length: %zd!\n", - allexcept ? " (allexcept)" : "", start, length); - - /* select the NAND device */ - chipnr = (int)(start >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* check the WP bit */ - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); - if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) { - printf("nand_unlock: Device is write protected!\n"); - ret = -1; - goto out; - } - - /* check the Lock Tight Status */ - page = (int)(start >> chip->page_shift); - chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); - if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { - printf("nand_unlock: Device is locked tight!\n"); - ret = -1; - goto out; - } - - if ((start & (mtd->erasesize - 1)) != 0) { - printf("nand_unlock: Start address must be beginning of " - "nand block!\n"); - ret = -1; - goto out; - } - - if (length == 0 || (length & (mtd->erasesize - 1)) != 0) { - printf("nand_unlock: Length must be a multiple of nand block " - "size %08x!\n", mtd->erasesize); - ret = -1; - goto out; - } - - /* - * Set length so that the last address is set to the - * starting address of the last block - */ - length -= mtd->erasesize; - - /* submit address of first page to unlock */ - chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); - - /* submit ADDRESS of LAST page to unlock */ - page += (int)(length >> chip->page_shift); - - /* - * Page addresses for unlocking are supposed to be block-aligned. - * At least some NAND chips use the low bit to indicate that the - * page range should be inverted. - */ - if (allexcept) - page |= 1; - - chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask); - - /* call wait ready function */ - status = chip->waitfunc(mtd, chip); - /* see if device thinks it succeeded */ - if (status & 0x01) { - /* there was an error */ - ret = -1; - goto out; - } - - out: - /* de-select the NAND device */ - chip->select_chip(mtd, -1); - return ret; -} -#endif - -/** - * check_skip_len - * - * Check if there are any bad blocks, and whether length including bad - * blocks fits into device - * - * @param mtd nand mtd instance - * @param offset offset in flash - * @param length image length - * @param used length of flash needed for the requested length - * @return 0 if the image fits and there are no bad blocks - * 1 if the image fits, but there are bad blocks - * -1 if the image does not fit - */ -static int check_skip_len(struct mtd_info *mtd, loff_t offset, size_t length, - size_t *used) -{ - size_t len_excl_bad = 0; - int ret = 0; - - while (len_excl_bad < length) { - size_t block_len, block_off; - loff_t block_start; - - if (offset >= mtd->size) - return -1; - - block_start = offset & ~(loff_t)(mtd->erasesize - 1); - block_off = offset & (mtd->erasesize - 1); - block_len = mtd->erasesize - block_off; - - if (!nand_block_isbad(mtd, block_start)) - len_excl_bad += block_len; - else - ret = 1; - - offset += block_len; - *used += block_len; - } - - /* If the length is not a multiple of block_len, adjust. */ - if (len_excl_bad > length) - *used -= (len_excl_bad - length); - - return ret; -} - -#ifdef CONFIG_CMD_NAND_TRIMFFS -static size_t drop_ffs(const struct mtd_info *mtd, const u_char *buf, - const size_t *len) -{ - size_t l = *len; - ssize_t i; - - for (i = l - 1; i >= 0; i--) - if (buf[i] != 0xFF) - break; - - /* The resulting length must be aligned to the minimum flash I/O size */ - l = i + 1; - l = (l + mtd->writesize - 1) / mtd->writesize; - l *= mtd->writesize; - - /* - * since the input length may be unaligned, prevent access past the end - * of the buffer - */ - return min(l, *len); -} -#endif - -/** - * nand_verify_page_oob: - * - * Verify a page of NAND flash, including the OOB. - * Reads page of NAND and verifies the contents and OOB against the - * values in ops. - * - * @param mtd nand mtd instance - * @param ops MTD operations, including data to verify - * @param ofs offset in flash - * @return 0 in case of success - */ -int nand_verify_page_oob(struct mtd_info *mtd, struct mtd_oob_ops *ops, - loff_t ofs) -{ - int rval; - struct mtd_oob_ops vops; - size_t verlen = mtd->writesize + mtd->oobsize; - - memcpy(&vops, ops, sizeof(vops)); - - vops.datbuf = memalign(ARCH_DMA_MINALIGN, verlen); - - if (!vops.datbuf) - return -ENOMEM; - - vops.oobbuf = vops.datbuf + mtd->writesize; - - rval = mtd_read_oob(mtd, ofs, &vops); - if (!rval) - rval = memcmp(ops->datbuf, vops.datbuf, vops.len); - if (!rval) - rval = memcmp(ops->oobbuf, vops.oobbuf, vops.ooblen); - - free(vops.datbuf); - - return rval ? -EIO : 0; -} - -/** - * nand_verify: - * - * Verify a region of NAND flash. - * Reads NAND in page-sized chunks and verifies the contents against - * the contents of a buffer. The offset into the NAND must be - * page-aligned, and the function doesn't handle skipping bad blocks. - * - * @param mtd nand mtd instance - * @param ofs offset in flash - * @param len buffer length - * @param buf buffer to read from - * @return 0 in case of success - */ -int nand_verify(struct mtd_info *mtd, loff_t ofs, size_t len, u_char *buf) -{ - int rval = 0; - size_t verofs; - size_t verlen = mtd->writesize; - uint8_t *verbuf = memalign(ARCH_DMA_MINALIGN, verlen); - - if (!verbuf) - return -ENOMEM; - - /* Read the NAND back in page-size groups to limit malloc size */ - for (verofs = ofs; verofs < ofs + len; - verofs += verlen, buf += verlen) { - verlen = min(mtd->writesize, (uint32_t)(ofs + len - verofs)); - rval = nand_read(mtd, verofs, &verlen, verbuf); - if (!rval || (rval == -EUCLEAN)) - rval = memcmp(buf, verbuf, verlen); - - if (rval) - break; - } - - free(verbuf); - - return rval ? -EIO : 0; -} - - - -/** - * nand_write_skip_bad: - * - * Write image to NAND flash. - * Blocks that are marked bad are skipped and the is written to the next - * block instead as long as the image is short enough to fit even after - * skipping the bad blocks. Due to bad blocks we may not be able to - * perform the requested write. In the case where the write would - * extend beyond the end of the NAND device, both length and actual (if - * not NULL) are set to 0. In the case where the write would extend - * beyond the limit we are passed, length is set to 0 and actual is set - * to the required length. - * - * @param mtd nand mtd instance - * @param offset offset in flash - * @param length buffer length - * @param actual set to size required to write length worth of - * buffer or 0 on error, if not NULL - * @param lim maximum size that actual may be in order to not - * exceed the buffer - * @param buffer buffer to read from - * @param flags flags modifying the behaviour of the write to NAND - * @return 0 in case of success - */ -int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, - size_t *actual, loff_t lim, u_char *buffer, int flags) -{ - int rval = 0, blocksize; - size_t left_to_write = *length; - size_t used_for_write = 0; - u_char *p_buffer = buffer; - int need_skip; - - if (actual) - *actual = 0; - - blocksize = mtd->erasesize; - - /* - * nand_write() handles unaligned, partial page writes. - * - * We allow length to be unaligned, for convenience in - * using the $filesize variable. - * - * However, starting at an unaligned offset makes the - * semantics of bad block skipping ambiguous (really, - * you should only start a block skipping access at a - * partition boundary). So don't try to handle that. - */ - if ((offset & (mtd->writesize - 1)) != 0) { - printf("Attempt to write non page-aligned data\n"); - *length = 0; - return -EINVAL; - } - - need_skip = check_skip_len(mtd, offset, *length, &used_for_write); - - if (actual) - *actual = used_for_write; - - if (need_skip < 0) { - printf("Attempt to write outside the flash area\n"); - *length = 0; - return -EINVAL; - } - - if (used_for_write > lim) { - puts("Size of write exceeds partition or device limit\n"); - *length = 0; - return -EFBIG; - } - - if (!need_skip && !(flags & WITH_DROP_FFS)) { - rval = nand_write(mtd, offset, length, buffer); - - if ((flags & WITH_WR_VERIFY) && !rval) - rval = nand_verify(mtd, offset, *length, buffer); - - if (rval == 0) - return 0; - - *length = 0; - printf("NAND write to offset %llx failed %d\n", - offset, rval); - return rval; - } - - while (left_to_write > 0) { - size_t block_offset = offset & (mtd->erasesize - 1); - size_t write_size, truncated_write_size; - - WATCHDOG_RESET(); - - if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) { - printf("Skip bad block 0x%08llx\n", - offset & ~(mtd->erasesize - 1)); - offset += mtd->erasesize - block_offset; - continue; - } - - if (left_to_write < (blocksize - block_offset)) - write_size = left_to_write; - else - write_size = blocksize - block_offset; - - truncated_write_size = write_size; -#ifdef CONFIG_CMD_NAND_TRIMFFS - if (flags & WITH_DROP_FFS) - truncated_write_size = drop_ffs(mtd, p_buffer, - &write_size); -#endif - - rval = nand_write(mtd, offset, &truncated_write_size, - p_buffer); - - if ((flags & WITH_WR_VERIFY) && !rval) - rval = nand_verify(mtd, offset, - truncated_write_size, p_buffer); - - offset += write_size; - p_buffer += write_size; - - if (rval != 0) { - printf("NAND write to offset %llx failed %d\n", - offset, rval); - *length -= left_to_write; - return rval; - } - - left_to_write -= write_size; - } - - return 0; -} - -/** - * nand_read_skip_bad: - * - * Read image from NAND flash. - * Blocks that are marked bad are skipped and the next block is read - * instead as long as the image is short enough to fit even after - * skipping the bad blocks. Due to bad blocks we may not be able to - * perform the requested read. In the case where the read would extend - * beyond the end of the NAND device, both length and actual (if not - * NULL) are set to 0. In the case where the read would extend beyond - * the limit we are passed, length is set to 0 and actual is set to the - * required length. - * - * @param mtd nand mtd instance - * @param offset offset in flash - * @param length buffer length, on return holds number of read bytes - * @param actual set to size required to read length worth of buffer or 0 - * on error, if not NULL - * @param lim maximum size that actual may be in order to not exceed the - * buffer - * @param buffer buffer to write to - * @return 0 in case of success - */ -int nand_read_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, - size_t *actual, loff_t lim, u_char *buffer) -{ - int rval; - size_t left_to_read = *length; - size_t used_for_read = 0; - u_char *p_buffer = buffer; - int need_skip; - - if ((offset & (mtd->writesize - 1)) != 0) { - printf("Attempt to read non page-aligned data\n"); - *length = 0; - if (actual) - *actual = 0; - return -EINVAL; - } - - need_skip = check_skip_len(mtd, offset, *length, &used_for_read); - - if (actual) - *actual = used_for_read; - - if (need_skip < 0) { - printf("Attempt to read outside the flash area\n"); - *length = 0; - return -EINVAL; - } - - if (used_for_read > lim) { - puts("Size of read exceeds partition or device limit\n"); - *length = 0; - return -EFBIG; - } - - if (!need_skip) { - rval = nand_read(mtd, offset, length, buffer); - if (!rval || rval == -EUCLEAN) - return 0; - - *length = 0; - printf("NAND read from offset %llx failed %d\n", - offset, rval); - return rval; - } - - while (left_to_read > 0) { - size_t block_offset = offset & (mtd->erasesize - 1); - size_t read_length; - - WATCHDOG_RESET(); - - if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) { - printf("Skipping bad block 0x%08llx\n", - offset & ~(mtd->erasesize - 1)); - offset += mtd->erasesize - block_offset; - continue; - } - - if (left_to_read < (mtd->erasesize - block_offset)) - read_length = left_to_read; - else - read_length = mtd->erasesize - block_offset; - - rval = nand_read(mtd, offset, &read_length, p_buffer); - if (rval && rval != -EUCLEAN) { - printf("NAND read from offset %llx failed %d\n", - offset, rval); - *length -= left_to_read; - return rval; - } - - left_to_read -= read_length; - offset += read_length; - p_buffer += read_length; - } - - return 0; -} - -#ifdef CONFIG_CMD_NAND_TORTURE - -/** - * check_pattern: - * - * Check if buffer contains only a certain byte pattern. - * - * @param buf buffer to check - * @param patt the pattern to check - * @param size buffer size in bytes - * @return 1 if there are only patt bytes in buf - * 0 if something else was found - */ -static int check_pattern(const u_char *buf, u_char patt, int size) -{ - int i; - - for (i = 0; i < size; i++) - if (buf[i] != patt) - return 0; - return 1; -} - -/** - * nand_torture: - * - * Torture a block of NAND flash. - * This is useful to determine if a block that caused a write error is still - * good or should be marked as bad. - * - * @param mtd nand mtd instance - * @param offset offset in flash - * @return 0 if the block is still good - */ -int nand_torture(struct mtd_info *mtd, loff_t offset) -{ - u_char patterns[] = {0xa5, 0x5a, 0x00}; - struct erase_info instr = { - .mtd = mtd, - .addr = offset, - .len = mtd->erasesize, - }; - size_t retlen; - int err, ret = -1, i, patt_count; - u_char *buf; - - if ((offset & (mtd->erasesize - 1)) != 0) { - puts("Attempt to torture a block at a non block-aligned offset\n"); - return -EINVAL; - } - - if (offset + mtd->erasesize > mtd->size) { - puts("Attempt to torture a block outside the flash area\n"); - return -EINVAL; - } - - patt_count = ARRAY_SIZE(patterns); - - buf = malloc_cache_aligned(mtd->erasesize); - if (buf == NULL) { - puts("Out of memory for erase block buffer\n"); - return -ENOMEM; - } - - for (i = 0; i < patt_count; i++) { - err = mtd_erase(mtd, &instr); - if (err) { - printf("%s: erase() failed for block at 0x%llx: %d\n", - mtd->name, instr.addr, err); - goto out; - } - - /* Make sure the block contains only 0xff bytes */ - err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); - if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { - printf("%s: read() failed for block at 0x%llx: %d\n", - mtd->name, instr.addr, err); - goto out; - } - - err = check_pattern(buf, 0xff, mtd->erasesize); - if (!err) { - printf("Erased block at 0x%llx, but a non-0xff byte was found\n", - offset); - ret = -EIO; - goto out; - } - - /* Write a pattern and check it */ - memset(buf, patterns[i], mtd->erasesize); - err = mtd_write(mtd, offset, mtd->erasesize, &retlen, buf); - if (err || retlen != mtd->erasesize) { - printf("%s: write() failed for block at 0x%llx: %d\n", - mtd->name, instr.addr, err); - goto out; - } - - err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); - if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { - printf("%s: read() failed for block at 0x%llx: %d\n", - mtd->name, instr.addr, err); - goto out; - } - - err = check_pattern(buf, patterns[i], mtd->erasesize); - if (!err) { - printf("Pattern 0x%.2x checking failed for block at " - "0x%llx\n", patterns[i], offset); - ret = -EIO; - goto out; - } - } - - ret = 0; - -out: - free(buf); - return ret; -} - -#endif diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c deleted file mode 100644 index 35c6dd1f1b..0000000000 --- a/drivers/mtd/nand/omap_elm.c +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2010-2011 Texas Instruments, - * Mansoor Ahamed - * - * BCH Error Location Module (ELM) support. - * - * NOTE: - * 1. Supports only continuous mode. Dont see need for page mode in uboot - * 2. Supports only syndrome polynomial 0. i.e. poly local variable is - * always set to ELM_DEFAULT_POLY. Dont see need for other polynomial - * sets in uboot - */ - -#include -#include -#include -#include -#include - -#define DRIVER_NAME "omap-elm" -#define ELM_DEFAULT_POLY (0) - -struct elm *elm_cfg; - -/** - * elm_load_syndromes - Load BCH syndromes based on bch_type selection - * @syndrome: BCH syndrome - * @bch_type: BCH4/BCH8/BCH16 - * @poly: Syndrome Polynomial set to use - */ -static void elm_load_syndromes(u8 *syndrome, enum bch_level bch_type, u8 poly) -{ - u32 *ptr; - u32 val; - - /* reg 0 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0]; - val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) | - (syndrome[3] << 24); - writel(val, ptr); - /* reg 1 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1]; - val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) | - (syndrome[7] << 24); - writel(val, ptr); - - if (bch_type == BCH_8_BIT || bch_type == BCH_16_BIT) { - /* reg 2 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2]; - val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) | - (syndrome[11] << 24); - writel(val, ptr); - /* reg 3 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[3]; - val = syndrome[12] | (syndrome[13] << 8) | - (syndrome[14] << 16) | (syndrome[15] << 24); - writel(val, ptr); - } - - if (bch_type == BCH_16_BIT) { - /* reg 4 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4]; - val = syndrome[16] | (syndrome[17] << 8) | - (syndrome[18] << 16) | (syndrome[19] << 24); - writel(val, ptr); - - /* reg 5 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[5]; - val = syndrome[20] | (syndrome[21] << 8) | - (syndrome[22] << 16) | (syndrome[23] << 24); - writel(val, ptr); - - /* reg 6 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]; - val = syndrome[24] | (syndrome[25] << 8) | - (syndrome[26] << 16) | (syndrome[27] << 24); - writel(val, ptr); - } -} - -/** - * elm_check_errors - Check for BCH errors and return error locations - * @syndrome: BCH syndrome - * @bch_type: BCH4/BCH8/BCH16 - * @error_count: Returns number of errrors in the syndrome - * @error_locations: Returns error locations (in decimal) in this array - * - * Check the provided syndrome for BCH errors and return error count - * and locations in the array passed. Returns -1 if error is not correctable, - * else returns 0 - */ -int elm_check_error(u8 *syndrome, enum bch_level bch_type, u32 *error_count, - u32 *error_locations) -{ - u8 poly = ELM_DEFAULT_POLY; - s8 i; - u32 location_status; - - elm_load_syndromes(syndrome, bch_type, poly); - - /* start processing */ - writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]) - | ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID), - &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]); - - /* wait for processing to complete */ - while ((readl(&elm_cfg->irqstatus) & (0x1 << poly)) != 0x1) - ; - /* clear status */ - writel((readl(&elm_cfg->irqstatus) | (0x1 << poly)), - &elm_cfg->irqstatus); - - /* check if correctable */ - location_status = readl(&elm_cfg->error_location[poly].location_status); - if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) { - printf("%s: uncorrectable ECC errors\n", DRIVER_NAME); - return -EBADMSG; - } - - /* get error count */ - *error_count = readl(&elm_cfg->error_location[poly].location_status) & - ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK; - - for (i = 0; i < *error_count; i++) { - error_locations[i] = - readl(&elm_cfg->error_location[poly].error_location_x[i]); - } - - return 0; -} - - -/** - * elm_config - Configure ELM module - * @level: 4 / 8 / 16 bit BCH - * - * Configure ELM module based on BCH level. - * Set mode as continuous mode. - * Currently we are using only syndrome 0 and syndromes 1 to 6 are not used. - * Also, the mode is set only for syndrome 0 - */ -int elm_config(enum bch_level level) -{ - u32 val; - u8 poly = ELM_DEFAULT_POLY; - u32 buffer_size = 0x7FF; - - /* config size and level */ - val = (u32)(level) & ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK; - val |= ((buffer_size << ELM_LOCATION_CONFIG_ECC_SIZE_POS) & - ELM_LOCATION_CONFIG_ECC_SIZE_MASK); - writel(val, &elm_cfg->location_config); - - /* config continous mode */ - /* enable interrupt generation for syndrome polynomial set */ - writel((readl(&elm_cfg->irqenable) | (0x1 << poly)), - &elm_cfg->irqenable); - /* set continuous mode for the syndrome polynomial set */ - writel((readl(&elm_cfg->page_ctrl) & ~(0x1 << poly)), - &elm_cfg->page_ctrl); - - return 0; -} - -/** - * elm_reset - Do a soft reset of ELM - * - * Perform a soft reset of ELM and return after reset is done. - */ -void elm_reset(void) -{ - /* initiate reset */ - writel((readl(&elm_cfg->sysconfig) | ELM_SYSCONFIG_SOFTRESET), - &elm_cfg->sysconfig); - - /* wait for reset complete and normal operation */ - while ((readl(&elm_cfg->sysstatus) & ELM_SYSSTATUS_RESETDONE) != - ELM_SYSSTATUS_RESETDONE) - ; -} - -/** - * elm_init - Initialize ELM module - * - * Initialize ELM support. Currently it does only base address init - * and ELM reset. - */ -void elm_init(void) -{ - elm_cfg = (struct elm *)ELM_BASE; - elm_reset(); -} diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c deleted file mode 100644 index 6a050501b0..0000000000 --- a/drivers/mtd/nand/omap_gpmc.c +++ /dev/null @@ -1,1037 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2004-2008 Texas Instruments, - * Rohit Choraria - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BADBLOCK_MARKER_LENGTH 2 -#define SECTOR_BYTES 512 -#define ECCCLEAR (0x1 << 8) -#define ECCRESULTREG1 (0x1 << 0) -/* 4 bit padding to make byte aligned, 56 = 52 + 4 */ -#define BCH4_BIT_PAD 4 - -#ifdef CONFIG_BCH -static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2, - 0x97, 0x79, 0xe5, 0x24, 0xb5}; -#endif -static uint8_t cs_next; -static __maybe_unused struct nand_ecclayout omap_ecclayout; - -#if defined(CONFIG_NAND_OMAP_GPMC_WSCFG) -static const int8_t wscfg[CONFIG_SYS_MAX_NAND_DEVICE] = - { CONFIG_NAND_OMAP_GPMC_WSCFG }; -#else -/* wscfg is preset to zero since its a static variable */ -static const int8_t wscfg[CONFIG_SYS_MAX_NAND_DEVICE]; -#endif - -/* - * Driver configurations - */ -struct omap_nand_info { - struct bch_control *control; - enum omap_ecc ecc_scheme; - uint8_t cs; - uint8_t ws; /* wait status pin (0,1) */ -}; - -/* We are wasting a bit of memory but al least we are safe */ -static struct omap_nand_info omap_nand_info[GPMC_MAX_CS]; - -/* - * omap_nand_hwcontrol - Set the address pointers corretly for the - * following address/data/command operation - */ -static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd, - uint32_t ctrl) -{ - register struct nand_chip *this = mtd_to_nand(mtd); - struct omap_nand_info *info = nand_get_controller_data(this); - int cs = info->cs; - - /* - * Point the IO_ADDR to DATA and ADDRESS registers instead - * of chip address - */ - switch (ctrl) { - case NAND_CTRL_CHANGE | NAND_CTRL_CLE: - this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; - break; - case NAND_CTRL_CHANGE | NAND_CTRL_ALE: - this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr; - break; - case NAND_CTRL_CHANGE | NAND_NCE: - this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; - break; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - -/* Check wait pin as dev ready indicator */ -static int omap_dev_ready(struct mtd_info *mtd) -{ - register struct nand_chip *this = mtd_to_nand(mtd); - struct omap_nand_info *info = nand_get_controller_data(this); - return gpmc_cfg->status & (1 << (8 + info->ws)); -} - -/* - * gen_true_ecc - This function will generate true ECC value, which - * can be used when correcting data read from NAND flash memory core - * - * @ecc_buf: buffer to store ecc code - * - * @return: re-formatted ECC value - */ -static uint32_t gen_true_ecc(uint8_t *ecc_buf) -{ - return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) | - ((ecc_buf[2] & 0x0F) << 8); -} - -/* - * omap_correct_data - Compares the ecc read from nand spare area with ECC - * registers values and corrects one bit error if it has occurred - * Further details can be had from OMAP TRM and the following selected links: - * http://en.wikipedia.org/wiki/Hamming_code - * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf - * - * @mtd: MTD device structure - * @dat: page data - * @read_ecc: ecc read from nand flash - * @calc_ecc: ecc read from ECC registers - * - * @return 0 if data is OK or corrected, else returns -1 - */ -static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - uint32_t orig_ecc, new_ecc, res, hm; - uint16_t parity_bits, byte; - uint8_t bit; - - /* Regenerate the orginal ECC */ - orig_ecc = gen_true_ecc(read_ecc); - new_ecc = gen_true_ecc(calc_ecc); - /* Get the XOR of real ecc */ - res = orig_ecc ^ new_ecc; - if (res) { - /* Get the hamming width */ - hm = hweight32(res); - /* Single bit errors can be corrected! */ - if (hm == 12) { - /* Correctable data! */ - parity_bits = res >> 16; - bit = (parity_bits & 0x7); - byte = (parity_bits >> 3) & 0x1FF; - /* Flip the bit to correct */ - dat[byte] ^= (0x1 << bit); - } else if (hm == 1) { - printf("Error: Ecc is wrong\n"); - /* ECC itself is corrupted */ - return 2; - } else { - /* - * hm distance != parity pairs OR one, could mean 2 bit - * error OR potentially be on a blank page.. - * orig_ecc: contains spare area data from nand flash. - * new_ecc: generated ecc while reading data area. - * Note: if the ecc = 0, all data bits from which it was - * generated are 0xFF. - * The 3 byte(24 bits) ecc is generated per 512byte - * chunk of a page. If orig_ecc(from spare area) - * is 0xFF && new_ecc(computed now from data area)=0x0, - * this means that data area is 0xFF and spare area is - * 0xFF. A sure sign of a erased page! - */ - if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000)) - return 0; - printf("Error: Bad compare! failed\n"); - /* detected 2 bit error */ - return -EBADMSG; - } - } - return 0; -} - -/* - * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write - * @mtd: MTD device structure - * @mode: Read/Write mode - */ -__maybe_unused -static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct omap_nand_info *info = nand_get_controller_data(nand); - unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0; - unsigned int ecc_algo = 0; - unsigned int bch_type = 0; - unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00; - u32 ecc_size_config_val = 0; - u32 ecc_config_val = 0; - int cs = info->cs; - - /* configure GPMC for specific ecc-scheme */ - switch (info->ecc_scheme) { - case OMAP_ECC_HAM1_CODE_SW: - return; - case OMAP_ECC_HAM1_CODE_HW: - ecc_algo = 0x0; - bch_type = 0x0; - bch_wrapmode = 0x00; - eccsize0 = 0xFF; - eccsize1 = 0xFF; - break; - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: - case OMAP_ECC_BCH8_CODE_HW: - ecc_algo = 0x1; - bch_type = 0x1; - if (mode == NAND_ECC_WRITE) { - bch_wrapmode = 0x01; - eccsize0 = 0; /* extra bits in nibbles per sector */ - eccsize1 = 28; /* OOB bits in nibbles per sector */ - } else { - bch_wrapmode = 0x01; - eccsize0 = 26; /* ECC bits in nibbles per sector */ - eccsize1 = 2; /* non-ECC bits in nibbles per sector */ - } - break; - case OMAP_ECC_BCH16_CODE_HW: - ecc_algo = 0x1; - bch_type = 0x2; - if (mode == NAND_ECC_WRITE) { - bch_wrapmode = 0x01; - eccsize0 = 0; /* extra bits in nibbles per sector */ - eccsize1 = 52; /* OOB bits in nibbles per sector */ - } else { - bch_wrapmode = 0x01; - eccsize0 = 52; /* ECC bits in nibbles per sector */ - eccsize1 = 0; /* non-ECC bits in nibbles per sector */ - } - break; - default: - return; - } - /* Clear ecc and enable bits */ - writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control); - /* Configure ecc size for BCH */ - ecc_size_config_val = (eccsize1 << 22) | (eccsize0 << 12); - writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config); - - /* Configure device details for BCH engine */ - ecc_config_val = ((ecc_algo << 16) | /* HAM1 | BCHx */ - (bch_type << 12) | /* BCH4/BCH8/BCH16 */ - (bch_wrapmode << 8) | /* wrap mode */ - (dev_width << 7) | /* bus width */ - (0x0 << 4) | /* number of sectors */ - (cs << 1) | /* ECC CS */ - (0x1)); /* enable ECC */ - writel(ecc_config_val, &gpmc_cfg->ecc_config); -} - -/* - * omap_calculate_ecc - Read ECC result - * @mtd: MTD structure - * @dat: unused - * @ecc_code: ecc_code buffer - * Using noninverted ECC can be considered ugly since writing a blank - * page ie. padding will clear the ECC bytes. This is no problem as - * long nobody is trying to write data on the seemingly unused page. - * Reading an erased page will produce an ECC mismatch between - * generated and read ECC bytes that has to be dealt with separately. - * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC - * is used, the result of read will be 0x0 while the ECC offsets of the - * spare area will be 0xFF which will result in an ECC mismatch. - */ -static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct omap_nand_info *info = nand_get_controller_data(chip); - const uint32_t *ptr; - uint32_t val = 0; - int8_t i = 0, j; - - switch (info->ecc_scheme) { - case OMAP_ECC_HAM1_CODE_HW: - val = readl(&gpmc_cfg->ecc1_result); - ecc_code[0] = val & 0xFF; - ecc_code[1] = (val >> 16) & 0xFF; - ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0); - break; -#ifdef CONFIG_BCH - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#endif - case OMAP_ECC_BCH8_CODE_HW: - ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3]; - val = readl(ptr); - ecc_code[i++] = (val >> 0) & 0xFF; - ptr--; - for (j = 0; j < 3; j++) { - val = readl(ptr); - ecc_code[i++] = (val >> 24) & 0xFF; - ecc_code[i++] = (val >> 16) & 0xFF; - ecc_code[i++] = (val >> 8) & 0xFF; - ecc_code[i++] = (val >> 0) & 0xFF; - ptr--; - } - break; - case OMAP_ECC_BCH16_CODE_HW: - val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]); - ecc_code[i++] = (val >> 8) & 0xFF; - ecc_code[i++] = (val >> 0) & 0xFF; - val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]); - ecc_code[i++] = (val >> 24) & 0xFF; - ecc_code[i++] = (val >> 16) & 0xFF; - ecc_code[i++] = (val >> 8) & 0xFF; - ecc_code[i++] = (val >> 0) & 0xFF; - val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]); - ecc_code[i++] = (val >> 24) & 0xFF; - ecc_code[i++] = (val >> 16) & 0xFF; - ecc_code[i++] = (val >> 8) & 0xFF; - ecc_code[i++] = (val >> 0) & 0xFF; - for (j = 3; j >= 0; j--) { - val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j] - ); - ecc_code[i++] = (val >> 24) & 0xFF; - ecc_code[i++] = (val >> 16) & 0xFF; - ecc_code[i++] = (val >> 8) & 0xFF; - ecc_code[i++] = (val >> 0) & 0xFF; - } - break; - default: - return -EINVAL; - } - /* ECC scheme specific syndrome customizations */ - switch (info->ecc_scheme) { - case OMAP_ECC_HAM1_CODE_HW: - break; -#ifdef CONFIG_BCH - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: - - for (i = 0; i < chip->ecc.bytes; i++) - *(ecc_code + i) = *(ecc_code + i) ^ - bch8_polynomial[i]; - break; -#endif - case OMAP_ECC_BCH8_CODE_HW: - ecc_code[chip->ecc.bytes - 1] = 0x00; - break; - case OMAP_ECC_BCH16_CODE_HW: - break; - default: - return -EINVAL; - } - return 0; -} - -#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH - -#define PREFETCH_CONFIG1_CS_SHIFT 24 -#define PREFETCH_FIFOTHRESHOLD_MAX 0x40 -#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8) -#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff) -#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F) -#define ENABLE_PREFETCH (1 << 7) - -/** - * omap_prefetch_enable - configures and starts prefetch transfer - * @fifo_th: fifo threshold to be used for read/ write - * @count: number of bytes to be transferred - * @is_write: prefetch read(0) or write post(1) mode - * @cs: chip select to use - */ -static int omap_prefetch_enable(int fifo_th, unsigned int count, int is_write, int cs) -{ - uint32_t val; - - if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) - return -EINVAL; - - if (readl(&gpmc_cfg->prefetch_control)) - return -EBUSY; - - /* Set the amount of bytes to be prefetched */ - writel(count, &gpmc_cfg->prefetch_config2); - - val = (cs << PREFETCH_CONFIG1_CS_SHIFT) | (is_write & 1) | - PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH; - writel(val, &gpmc_cfg->prefetch_config1); - - /* Start the prefetch engine */ - writel(1, &gpmc_cfg->prefetch_control); - - return 0; -} - -/** - * omap_prefetch_reset - disables and stops the prefetch engine - */ -static void omap_prefetch_reset(void) -{ - writel(0, &gpmc_cfg->prefetch_control); - writel(0, &gpmc_cfg->prefetch_config1); -} - -static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int len) -{ - int ret; - uint32_t cnt; - struct omap_nand_info *info = nand_get_controller_data(chip); - - ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0, info->cs); - if (ret < 0) - return ret; - - do { - int i; - - cnt = readl(&gpmc_cfg->prefetch_status); - cnt = PREFETCH_STATUS_FIFO_CNT(cnt); - - for (i = 0; i < cnt / 4; i++) { - *buf++ = readl(CONFIG_SYS_NAND_BASE); - len -= 4; - } - } while (len); - - omap_prefetch_reset(); - - return 0; -} - -static inline void omap_nand_read(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - - if (chip->options & NAND_BUSWIDTH_16) - nand_read_buf16(mtd, buf, len); - else - nand_read_buf(mtd, buf, len); -} - -static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int ret; - uint32_t head, tail; - struct nand_chip *chip = mtd_to_nand(mtd); - - /* - * If the destination buffer is unaligned, start with reading - * the overlap byte-wise. - */ - head = ((uint32_t) buf) % 4; - if (head) { - omap_nand_read(mtd, buf, head); - buf += head; - len -= head; - } - - /* - * Only transfer multiples of 4 bytes in a pre-fetched fashion. - * If there's a residue, care for it byte-wise afterwards. - */ - tail = len % 4; - - ret = __read_prefetch_aligned(chip, (uint32_t *)buf, len - tail); - if (ret < 0) { - /* fallback in case the prefetch engine is busy */ - omap_nand_read(mtd, buf, len); - } else if (tail) { - buf += len - tail; - omap_nand_read(mtd, buf, tail); - } -} -#endif /* CONFIG_NAND_OMAP_GPMC_PREFETCH */ - -#ifdef CONFIG_NAND_OMAP_ELM -/* - * omap_reverse_list - re-orders list elements in reverse order [internal] - * @list: pointer to start of list - * @length: length of list -*/ -static void omap_reverse_list(u8 *list, unsigned int length) -{ - unsigned int i, j; - unsigned int half_length = length / 2; - u8 tmp; - for (i = 0, j = length - 1; i < half_length; i++, j--) { - tmp = list[i]; - list[i] = list[j]; - list[j] = tmp; - } -} - -/* - * omap_correct_data_bch - Compares the ecc read from nand spare area - * with ECC registers values and corrects one bit error if it has occurred - * - * @mtd: MTD device structure - * @dat: page data - * @read_ecc: ecc read from nand flash (ignored) - * @calc_ecc: ecc read from ECC registers - * - * @return 0 if data is OK or corrected, else returns -1 - */ -static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct omap_nand_info *info = nand_get_controller_data(chip); - struct nand_ecc_ctrl *ecc = &chip->ecc; - uint32_t error_count = 0, error_max; - uint32_t error_loc[ELM_MAX_ERROR_COUNT]; - enum bch_level bch_type; - uint32_t i, ecc_flag = 0; - uint8_t count; - uint32_t byte_pos, bit_pos; - int err = 0; - - /* check calculated ecc */ - for (i = 0; i < ecc->bytes && !ecc_flag; i++) { - if (calc_ecc[i] != 0x00) - ecc_flag = 1; - } - if (!ecc_flag) - return 0; - - /* check for whether its a erased-page */ - ecc_flag = 0; - for (i = 0; i < ecc->bytes && !ecc_flag; i++) { - if (read_ecc[i] != 0xff) - ecc_flag = 1; - } - if (!ecc_flag) - return 0; - - /* - * while reading ECC result we read it in big endian. - * Hence while loading to ELM we have rotate to get the right endian. - */ - switch (info->ecc_scheme) { - case OMAP_ECC_BCH8_CODE_HW: - bch_type = BCH_8_BIT; - omap_reverse_list(calc_ecc, ecc->bytes - 1); - break; - case OMAP_ECC_BCH16_CODE_HW: - bch_type = BCH_16_BIT; - omap_reverse_list(calc_ecc, ecc->bytes); - break; - default: - return -EINVAL; - } - /* use elm module to check for errors */ - elm_config(bch_type); - err = elm_check_error(calc_ecc, bch_type, &error_count, error_loc); - if (err) - return err; - - /* correct bch error */ - for (count = 0; count < error_count; count++) { - switch (info->ecc_scheme) { - case OMAP_ECC_BCH8_CODE_HW: - /* 14th byte in ECC is reserved to match ROM layout */ - error_max = SECTOR_BYTES + (ecc->bytes - 1); - break; - case OMAP_ECC_BCH16_CODE_HW: - error_max = SECTOR_BYTES + ecc->bytes; - break; - default: - return -EINVAL; - } - byte_pos = error_max - (error_loc[count] / 8) - 1; - bit_pos = error_loc[count] % 8; - if (byte_pos < SECTOR_BYTES) { - dat[byte_pos] ^= 1 << bit_pos; - debug("nand: bit-flip corrected @data=%d\n", byte_pos); - } else if (byte_pos < error_max) { - read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos; - debug("nand: bit-flip corrected @oob=%d\n", byte_pos - - SECTOR_BYTES); - } else { - err = -EBADMSG; - printf("nand: error: invalid bit-flip location\n"); - } - } - return (err) ? err : error_count; -} - -/** - * omap_read_page_bch - hardware ecc based page read function - * @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 - * @page: page number to read - * - */ -static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *oob = chip->oob_poi; - uint32_t data_pos; - uint32_t oob_pos; - - data_pos = 0; - /* oob area start */ - oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0]; - oob += chip->ecc.layout->eccpos[0]; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize, - oob += eccbytes) { - chip->ecc.hwctl(mtd, NAND_ECC_READ); - /* read data */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1); - chip->read_buf(mtd, p, eccsize); - - /* read respective ecc from oob area */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1); - chip->read_buf(mtd, oob, eccbytes); - /* read syndrome */ - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - data_pos += eccsize; - oob_pos += eccbytes; - } - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - eccsteps = chip->ecc.steps; - p = buf; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} -#endif /* CONFIG_NAND_OMAP_ELM */ - -/* - * OMAP3 BCH8 support (with BCH library) - */ -#ifdef CONFIG_BCH -/** - * omap_correct_data_bch_sw - Decode received data and correct errors - * @mtd: MTD device structure - * @data: page data - * @read_ecc: ecc read from nand flash - * @calc_ecc: ecc read from HW ECC registers - */ -static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data, - u_char *read_ecc, u_char *calc_ecc) -{ - int i, count; - /* cannot correct more than 8 errors */ - unsigned int errloc[8]; - struct nand_chip *chip = mtd_to_nand(mtd); - struct omap_nand_info *info = nand_get_controller_data(chip); - - count = decode_bch(info->control, NULL, SECTOR_BYTES, - read_ecc, calc_ecc, NULL, errloc); - if (count > 0) { - /* correct errors */ - for (i = 0; i < count; i++) { - /* correct data only, not ecc bytes */ - if (errloc[i] < SECTOR_BYTES << 3) - data[errloc[i] >> 3] ^= 1 << (errloc[i] & 7); - debug("corrected bitflip %u\n", errloc[i]); -#ifdef DEBUG - puts("read_ecc: "); - /* - * BCH8 have 13 bytes of ECC; BCH4 needs adoption - * here! - */ - for (i = 0; i < 13; i++) - printf("%02x ", read_ecc[i]); - puts("\n"); - puts("calc_ecc: "); - for (i = 0; i < 13; i++) - printf("%02x ", calc_ecc[i]); - puts("\n"); -#endif - } - } else if (count < 0) { - puts("ecc unrecoverable error\n"); - } - return count; -} - -/** - * omap_free_bch - Release BCH ecc resources - * @mtd: MTD device structure - */ -static void __maybe_unused omap_free_bch(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct omap_nand_info *info = nand_get_controller_data(chip); - - if (info->control) { - free_bch(info->control); - info->control = NULL; - } -} -#endif /* CONFIG_BCH */ - -/** - * omap_select_ecc_scheme - configures driver for particular ecc-scheme - * @nand: NAND chip device structure - * @ecc_scheme: ecc scheme to configure - * @pagesize: number of main-area bytes per page of NAND device - * @oobsize: number of OOB/spare bytes per page of NAND device - */ -static int omap_select_ecc_scheme(struct nand_chip *nand, - enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) { - struct omap_nand_info *info = nand_get_controller_data(nand); - struct nand_ecclayout *ecclayout = &omap_ecclayout; - int eccsteps = pagesize / SECTOR_BYTES; - int i; - - switch (ecc_scheme) { - case OMAP_ECC_HAM1_CODE_SW: - debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n"); - /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are - * initialized in nand_scan_tail(), so just set ecc.mode */ - info->control = NULL; - nand->ecc.mode = NAND_ECC_SOFT; - nand->ecc.layout = NULL; - nand->ecc.size = 0; - break; - - case OMAP_ECC_HAM1_CODE_HW: - debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n"); - /* check ecc-scheme requirements before updating ecc info */ - if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { - printf("nand: error: insufficient OOB: require=%d\n", ( - (3 * eccsteps) + BADBLOCK_MARKER_LENGTH)); - return -EINVAL; - } - info->control = NULL; - /* populate ecc specific fields */ - memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.strength = 1; - nand->ecc.size = SECTOR_BYTES; - nand->ecc.bytes = 3; - nand->ecc.hwctl = omap_enable_hwecc; - nand->ecc.correct = omap_correct_data; - nand->ecc.calculate = omap_calculate_ecc; - /* define ecc-layout */ - ecclayout->eccbytes = nand->ecc.bytes * eccsteps; - for (i = 0; i < ecclayout->eccbytes; i++) { - if (nand->options & NAND_BUSWIDTH_16) - ecclayout->eccpos[i] = i + 2; - else - ecclayout->eccpos[i] = i + 1; - } - ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - - BADBLOCK_MARKER_LENGTH; - break; - - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#ifdef CONFIG_BCH - debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); - /* check ecc-scheme requirements before updating ecc info */ - if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { - printf("nand: error: insufficient OOB: require=%d\n", ( - (13 * eccsteps) + BADBLOCK_MARKER_LENGTH)); - return -EINVAL; - } - /* check if BCH S/W library can be used for error detection */ - info->control = init_bch(13, 8, 0x201b); - if (!info->control) { - printf("nand: error: could not init_bch()\n"); - return -ENODEV; - } - /* populate ecc specific fields */ - memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.strength = 8; - nand->ecc.size = SECTOR_BYTES; - nand->ecc.bytes = 13; - nand->ecc.hwctl = omap_enable_hwecc; - nand->ecc.correct = omap_correct_data_bch_sw; - nand->ecc.calculate = omap_calculate_ecc; - /* define ecc-layout */ - ecclayout->eccbytes = nand->ecc.bytes * eccsteps; - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - for (i = 1; i < ecclayout->eccbytes; i++) { - if (i % nand->ecc.bytes) - ecclayout->eccpos[i] = - ecclayout->eccpos[i - 1] + 1; - else - ecclayout->eccpos[i] = - ecclayout->eccpos[i - 1] + 2; - } - ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - - BADBLOCK_MARKER_LENGTH; - break; -#else - printf("nand: error: CONFIG_BCH required for ECC\n"); - return -EINVAL; -#endif - - case OMAP_ECC_BCH8_CODE_HW: -#ifdef CONFIG_NAND_OMAP_ELM - debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n"); - /* check ecc-scheme requirements before updating ecc info */ - if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { - printf("nand: error: insufficient OOB: require=%d\n", ( - (14 * eccsteps) + BADBLOCK_MARKER_LENGTH)); - return -EINVAL; - } - /* intialize ELM for ECC error detection */ - elm_init(); - info->control = NULL; - /* populate ecc specific fields */ - memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.strength = 8; - nand->ecc.size = SECTOR_BYTES; - nand->ecc.bytes = 14; - nand->ecc.hwctl = omap_enable_hwecc; - nand->ecc.correct = omap_correct_data_bch; - nand->ecc.calculate = omap_calculate_ecc; - nand->ecc.read_page = omap_read_page_bch; - /* define ecc-layout */ - ecclayout->eccbytes = nand->ecc.bytes * eccsteps; - for (i = 0; i < ecclayout->eccbytes; i++) - ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - - BADBLOCK_MARKER_LENGTH; - break; -#else - printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); - return -EINVAL; -#endif - - case OMAP_ECC_BCH16_CODE_HW: -#ifdef CONFIG_NAND_OMAP_ELM - debug("nand: using OMAP_ECC_BCH16_CODE_HW\n"); - /* check ecc-scheme requirements before updating ecc info */ - if ((26 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { - printf("nand: error: insufficient OOB: require=%d\n", ( - (26 * eccsteps) + BADBLOCK_MARKER_LENGTH)); - return -EINVAL; - } - /* intialize ELM for ECC error detection */ - elm_init(); - /* populate ecc specific fields */ - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.size = SECTOR_BYTES; - nand->ecc.bytes = 26; - nand->ecc.strength = 16; - nand->ecc.hwctl = omap_enable_hwecc; - nand->ecc.correct = omap_correct_data_bch; - nand->ecc.calculate = omap_calculate_ecc; - nand->ecc.read_page = omap_read_page_bch; - /* define ecc-layout */ - ecclayout->eccbytes = nand->ecc.bytes * eccsteps; - for (i = 0; i < ecclayout->eccbytes; i++) - ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes - - BADBLOCK_MARKER_LENGTH; - break; -#else - printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); - return -EINVAL; -#endif - default: - debug("nand: error: ecc scheme not enabled or supported\n"); - return -EINVAL; - } - - /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */ - if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW) - nand->ecc.layout = ecclayout; - - info->ecc_scheme = ecc_scheme; - return 0; -} - -#ifndef CONFIG_SPL_BUILD -/* - * omap_nand_switch_ecc - switch the ECC operation between different engines - * (h/w and s/w) and different algorithms (hamming and BCHx) - * - * @hardware - true if one of the HW engines should be used - * @eccstrength - the number of bits that could be corrected - * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16) - */ -int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength) -{ - struct nand_chip *nand; - struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device); - int err = 0; - - if (!mtd) { - printf("nand: error: no NAND devices found\n"); - return -ENODEV; - } - - nand = mtd_to_nand(mtd); - nand->options |= NAND_OWN_BUFFERS; - nand->options &= ~NAND_SUBPAGE_READ; - /* Setup the ecc configurations again */ - if (hardware) { - if (eccstrength == 1) { - err = omap_select_ecc_scheme(nand, - OMAP_ECC_HAM1_CODE_HW, - mtd->writesize, mtd->oobsize); - } else if (eccstrength == 8) { - err = omap_select_ecc_scheme(nand, - OMAP_ECC_BCH8_CODE_HW, - mtd->writesize, mtd->oobsize); - } else if (eccstrength == 16) { - err = omap_select_ecc_scheme(nand, - OMAP_ECC_BCH16_CODE_HW, - mtd->writesize, mtd->oobsize); - } else { - printf("nand: error: unsupported ECC scheme\n"); - return -EINVAL; - } - } else { - if (eccstrength == 1) { - err = omap_select_ecc_scheme(nand, - OMAP_ECC_HAM1_CODE_SW, - mtd->writesize, mtd->oobsize); - } else if (eccstrength == 8) { - err = omap_select_ecc_scheme(nand, - OMAP_ECC_BCH8_CODE_HW_DETECTION_SW, - mtd->writesize, mtd->oobsize); - } else { - printf("nand: error: unsupported ECC scheme\n"); - return -EINVAL; - } - } - - /* Update NAND handling after ECC mode switch */ - if (!err) - err = nand_scan_tail(mtd); - return err; -} -#endif /* CONFIG_SPL_BUILD */ - -/* - * Board-specific NAND initialization. The following members of the - * argument are board-specific: - * - 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 - * - cmd_ctrl: hardwarespecific function for accesing control-lines - * - waitfunc: hardwarespecific function for accesing device ready/busy line - * - ecc.hwctl: function to enable (reset) hardware ecc generator - * - ecc.mode: mode of ecc, see defines - * - chip_delay: chip dependent delay for transfering data from array to - * read regs (tR) - * - options: various chip options. They can partly be set to inform - * nand_scan about special functionality. See the defines for further - * explanation - */ -int board_nand_init(struct nand_chip *nand) -{ - int32_t gpmc_config = 0; - int cs = cs_next++; - int err = 0; - /* - * xloader/Uboot's gpmc configuration would have configured GPMC for - * nand type of memory. The following logic scans and latches on to the - * first CS with NAND type memory. - * TBD: need to make this logic generic to handle multiple CS NAND - * devices. - */ - while (cs < GPMC_MAX_CS) { - /* Check if NAND type is set */ - if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) { - /* Found it!! */ - break; - } - cs++; - } - if (cs >= GPMC_MAX_CS) { - printf("nand: error: Unable to find NAND settings in " - "GPMC Configuration - quitting\n"); - return -ENODEV; - } - - gpmc_config = readl(&gpmc_cfg->config); - /* Disable Write protect */ - gpmc_config |= 0x10; - writel(gpmc_config, &gpmc_cfg->config); - - nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; - nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; - omap_nand_info[cs].control = NULL; - omap_nand_info[cs].cs = cs; - omap_nand_info[cs].ws = wscfg[cs]; - nand_set_controller_data(nand, &omap_nand_info[cs]); - nand->cmd_ctrl = omap_nand_hwcontrol; - nand->options |= NAND_NO_PADDING | NAND_CACHEPRG; - nand->chip_delay = 100; - nand->ecc.layout = &omap_ecclayout; - - /* configure driver and controller based on NAND device bus-width */ - gpmc_config = readl(&gpmc_cfg->cs[cs].config1); -#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT) - nand->options |= NAND_BUSWIDTH_16; - writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1); -#else - nand->options &= ~NAND_BUSWIDTH_16; - writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1); -#endif - /* select ECC scheme */ -#if defined(CONFIG_NAND_OMAP_ECCSCHEME) - err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME, - CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); -#else - /* pagesize and oobsize are not required to configure sw ecc-scheme */ - err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW, - 0, 0); -#endif - if (err) - return err; - -#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH - nand->read_buf = omap_nand_read_prefetch; -#else - if (nand->options & NAND_BUSWIDTH_16) - nand->read_buf = nand_read_buf16; - else - nand->read_buf = nand_read_buf; -#endif - - nand->dev_ready = omap_dev_ready; - - return 0; -} diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c deleted file mode 100644 index 2a02a9d58e..0000000000 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ /dev/null @@ -1,1828 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * drivers/mtd/nand/pxa3xx_nand.c - * - * Copyright © 2005 Intel Corporation - * Copyright © 2006 Marvell International Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pxa3xx_nand.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define TIMEOUT_DRAIN_FIFO 5 /* in ms */ -#define CHIP_DELAY_TIMEOUT 200 -#define NAND_STOP_DELAY 40 - -/* - * Define a buffer size for the initial command that detects the flash device: - * STATUS, READID and PARAM. - * ONFI param page is 256 bytes, and there are three redundant copies - * to be read. JEDEC param page is 512 bytes, and there are also three - * redundant copies to be read. - * Hence this buffer should be at least 512 x 3. Let's pick 2048. - */ -#define INIT_BUFFER_SIZE 2048 - -/* registers and bit definitions */ -#define NDCR (0x00) /* Control register */ -#define NDTR0CS0 (0x04) /* Timing Parameter 0 for CS0 */ -#define NDTR1CS0 (0x0C) /* Timing Parameter 1 for CS0 */ -#define NDSR (0x14) /* Status Register */ -#define NDPCR (0x18) /* Page Count Register */ -#define NDBDR0 (0x1C) /* Bad Block Register 0 */ -#define NDBDR1 (0x20) /* Bad Block Register 1 */ -#define NDECCCTRL (0x28) /* ECC control */ -#define NDDB (0x40) /* Data Buffer */ -#define NDCB0 (0x48) /* Command Buffer0 */ -#define NDCB1 (0x4C) /* Command Buffer1 */ -#define NDCB2 (0x50) /* Command Buffer2 */ - -#define NDCR_SPARE_EN (0x1 << 31) -#define NDCR_ECC_EN (0x1 << 30) -#define NDCR_DMA_EN (0x1 << 29) -#define NDCR_ND_RUN (0x1 << 28) -#define NDCR_DWIDTH_C (0x1 << 27) -#define NDCR_DWIDTH_M (0x1 << 26) -#define NDCR_PAGE_SZ (0x1 << 24) -#define NDCR_NCSX (0x1 << 23) -#define NDCR_ND_MODE (0x3 << 21) -#define NDCR_NAND_MODE (0x0) -#define NDCR_CLR_PG_CNT (0x1 << 20) -#define NFCV1_NDCR_ARB_CNTL (0x1 << 19) -#define NDCR_RD_ID_CNT_MASK (0x7 << 16) -#define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK) - -#define NDCR_RA_START (0x1 << 15) -#define NDCR_PG_PER_BLK (0x1 << 14) -#define NDCR_ND_ARB_EN (0x1 << 12) -#define NDCR_INT_MASK (0xFFF) - -#define NDSR_MASK (0xfff) -#define NDSR_ERR_CNT_OFF (16) -#define NDSR_ERR_CNT_MASK (0x1f) -#define NDSR_ERR_CNT(sr) ((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK) -#define NDSR_RDY (0x1 << 12) -#define NDSR_FLASH_RDY (0x1 << 11) -#define NDSR_CS0_PAGED (0x1 << 10) -#define NDSR_CS1_PAGED (0x1 << 9) -#define NDSR_CS0_CMDD (0x1 << 8) -#define NDSR_CS1_CMDD (0x1 << 7) -#define NDSR_CS0_BBD (0x1 << 6) -#define NDSR_CS1_BBD (0x1 << 5) -#define NDSR_UNCORERR (0x1 << 4) -#define NDSR_CORERR (0x1 << 3) -#define NDSR_WRDREQ (0x1 << 2) -#define NDSR_RDDREQ (0x1 << 1) -#define NDSR_WRCMDREQ (0x1) - -#define NDCB0_LEN_OVRD (0x1 << 28) -#define NDCB0_ST_ROW_EN (0x1 << 26) -#define NDCB0_AUTO_RS (0x1 << 25) -#define NDCB0_CSEL (0x1 << 24) -#define NDCB0_EXT_CMD_TYPE_MASK (0x7 << 29) -#define NDCB0_EXT_CMD_TYPE(x) (((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK) -#define NDCB0_CMD_TYPE_MASK (0x7 << 21) -#define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK) -#define NDCB0_NC (0x1 << 20) -#define NDCB0_DBC (0x1 << 19) -#define NDCB0_ADDR_CYC_MASK (0x7 << 16) -#define NDCB0_ADDR_CYC(x) (((x) << 16) & NDCB0_ADDR_CYC_MASK) -#define NDCB0_CMD2_MASK (0xff << 8) -#define NDCB0_CMD1_MASK (0xff) -#define NDCB0_ADDR_CYC_SHIFT (16) - -#define EXT_CMD_TYPE_DISPATCH 6 /* Command dispatch */ -#define EXT_CMD_TYPE_NAKED_RW 5 /* Naked read or Naked write */ -#define EXT_CMD_TYPE_READ 4 /* Read */ -#define EXT_CMD_TYPE_DISP_WR 4 /* Command dispatch with write */ -#define EXT_CMD_TYPE_FINAL 3 /* Final command */ -#define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ -#define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */ - -/* - * This should be large enough to read 'ONFI' and 'JEDEC'. - * Let's use 7 bytes, which is the maximum ID count supported - * by the controller (see NDCR_RD_ID_CNT_MASK). - */ -#define READ_ID_BYTES 7 - -/* macros for registers read/write */ -#define nand_writel(info, off, val) \ - writel((val), (info)->mmio_base + (off)) - -#define nand_readl(info, off) \ - readl((info)->mmio_base + (off)) - -/* error code and state */ -enum { - ERR_NONE = 0, - ERR_DMABUSERR = -1, - ERR_SENDCMD = -2, - ERR_UNCORERR = -3, - ERR_BBERR = -4, - ERR_CORERR = -5, -}; - -enum { - STATE_IDLE = 0, - STATE_PREPARED, - STATE_CMD_HANDLE, - STATE_DMA_READING, - STATE_DMA_WRITING, - STATE_DMA_DONE, - STATE_PIO_READING, - STATE_PIO_WRITING, - STATE_CMD_DONE, - STATE_READY, -}; - -enum pxa3xx_nand_variant { - PXA3XX_NAND_VARIANT_PXA, - PXA3XX_NAND_VARIANT_ARMADA370, -}; - -struct pxa3xx_nand_host { - struct nand_chip chip; - void *info_data; - - /* page size of attached chip */ - int use_ecc; - int cs; - - /* calculated from pxa3xx_nand_flash data */ - unsigned int col_addr_cycles; - unsigned int row_addr_cycles; -}; - -struct pxa3xx_nand_info { - struct nand_hw_control controller; - struct pxa3xx_nand_platform_data *pdata; - - struct clk *clk; - void __iomem *mmio_base; - unsigned long mmio_phys; - int cmd_complete, dev_ready; - - unsigned int buf_start; - unsigned int buf_count; - unsigned int buf_size; - unsigned int data_buff_pos; - unsigned int oob_buff_pos; - - unsigned char *data_buff; - unsigned char *oob_buff; - - struct pxa3xx_nand_host *host[NUM_CHIP_SELECT]; - unsigned int state; - - /* - * This driver supports NFCv1 (as found in PXA SoC) - * and NFCv2 (as found in Armada 370/XP SoC). - */ - enum pxa3xx_nand_variant variant; - - int cs; - int use_ecc; /* use HW ECC ? */ - int ecc_bch; /* using BCH ECC? */ - int use_spare; /* use spare ? */ - int need_wait; - - /* Amount of real data per full chunk */ - unsigned int chunk_size; - - /* Amount of spare data per full chunk */ - unsigned int spare_size; - - /* Number of full chunks (i.e chunk_size + spare_size) */ - unsigned int nfullchunks; - - /* - * Total number of chunks. If equal to nfullchunks, then there - * are only full chunks. Otherwise, there is one last chunk of - * size (last_chunk_size + last_spare_size) - */ - unsigned int ntotalchunks; - - /* Amount of real data in the last chunk */ - unsigned int last_chunk_size; - - /* Amount of spare data in the last chunk */ - unsigned int last_spare_size; - - unsigned int ecc_size; - unsigned int ecc_err_cnt; - unsigned int max_bitflips; - int retcode; - - /* - * Variables only valid during command - * execution. step_chunk_size and step_spare_size is the - * amount of real data and spare data in the current - * chunk. cur_chunk is the current chunk being - * read/programmed. - */ - unsigned int step_chunk_size; - unsigned int step_spare_size; - unsigned int cur_chunk; - - /* cached register value */ - uint32_t reg_ndcr; - uint32_t ndtr0cs0; - uint32_t ndtr1cs0; - - /* generated NDCBx register values */ - uint32_t ndcb0; - uint32_t ndcb1; - uint32_t ndcb2; - uint32_t ndcb3; -}; - -static struct pxa3xx_nand_timing timing[] = { - /* - * tCH Enable signal hold time - * tCS Enable signal setup time - * tWH ND_nWE high duration - * tWP ND_nWE pulse time - * tRH ND_nRE high duration - * tRP ND_nRE pulse width - * tR ND_nWE high to ND_nRE low for read - * tWHR ND_nWE high to ND_nRE low for status read - * tAR ND_ALE low to ND_nRE low delay - */ - /*ch cs wh wp rh rp r whr ar */ - { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, - { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, - { 10, 25, 15, 25, 15, 30, 25000, 60, 10, }, - { 10, 35, 15, 25, 15, 25, 25000, 60, 10, }, - { 5, 20, 10, 12, 10, 12, 25000, 60, 10, }, -}; - -static struct pxa3xx_nand_flash builtin_flash_types[] = { - /* - * chip_id - * flash_width Width of Flash memory (DWIDTH_M) - * dfc_width Width of flash controller(DWIDTH_C) - * *timing - * http://www.linux-mtd.infradead.org/nand-data/nanddata.html - */ - { 0x46ec, 16, 16, &timing[1] }, - { 0xdaec, 8, 8, &timing[1] }, - { 0xd7ec, 8, 8, &timing[1] }, - { 0xa12c, 8, 8, &timing[2] }, - { 0xb12c, 16, 16, &timing[2] }, - { 0xdc2c, 8, 8, &timing[2] }, - { 0xcc2c, 16, 16, &timing[2] }, - { 0xba20, 16, 16, &timing[3] }, - { 0xda98, 8, 8, &timing[4] }, -}; - -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT -static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' }; -static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 8, - .len = 6, - .veroffs = 14, - .maxblocks = 8, /* Last 8 blocks in each chip */ - .pattern = bbt_pattern -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 8, - .len = 6, - .veroffs = 14, - .maxblocks = 8, /* Last 8 blocks in each chip */ - .pattern = bbt_mirror_pattern -}; -#endif - -static struct nand_ecclayout ecc_layout_2KB_bch4bit = { - .eccbytes = 32, - .eccpos = { - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63}, - .oobfree = { {2, 30} } -}; - -static struct nand_ecclayout ecc_layout_2KB_bch8bit = { - .eccbytes = 64, - .eccpos = { - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127}, - .oobfree = { {1, 4}, {6, 26} } -}; - -static struct nand_ecclayout ecc_layout_4KB_bch4bit = { - .eccbytes = 64, - .eccpos = { - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127}, - /* Bootrom looks in bytes 0 & 5 for bad blocks */ - .oobfree = { {6, 26}, { 64, 32} } -}; - -static struct nand_ecclayout ecc_layout_8KB_bch4bit = { - .eccbytes = 128, - .eccpos = { - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - - 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, - - 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255}, - - /* Bootrom looks in bytes 0 & 5 for bad blocks */ - .oobfree = { {1, 4}, {6, 26}, { 64, 32}, {128, 32}, {192, 32} } -}; - -static struct nand_ecclayout ecc_layout_4KB_bch8bit = { - .eccbytes = 128, - .eccpos = { - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63}, - .oobfree = { } -}; - -static struct nand_ecclayout ecc_layout_8KB_bch8bit = { - .eccbytes = 256, - .eccpos = {}, - /* HW ECC handles all ECC data and all spare area is free for OOB */ - .oobfree = {{0, 160} } -}; - -#define NDTR0_tCH(c) (min((c), 7) << 19) -#define NDTR0_tCS(c) (min((c), 7) << 16) -#define NDTR0_tWH(c) (min((c), 7) << 11) -#define NDTR0_tWP(c) (min((c), 7) << 8) -#define NDTR0_tRH(c) (min((c), 7) << 3) -#define NDTR0_tRP(c) (min((c), 7) << 0) - -#define NDTR1_tR(c) (min((c), 65535) << 16) -#define NDTR1_tWHR(c) (min((c), 15) << 4) -#define NDTR1_tAR(c) (min((c), 15) << 0) - -/* convert nano-seconds to nand flash controller clock cycles */ -#define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) - -static enum pxa3xx_nand_variant pxa3xx_nand_get_variant(void) -{ - /* We only support the Armada 370/XP/38x for now */ - return PXA3XX_NAND_VARIANT_ARMADA370; -} - -static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, - const struct pxa3xx_nand_timing *t) -{ - struct pxa3xx_nand_info *info = host->info_data; - unsigned long nand_clk = mvebu_get_nand_clock(); - uint32_t ndtr0, ndtr1; - - ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) | - NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) | - NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) | - NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) | - NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) | - NDTR0_tRP(ns2cycle(t->tRP, nand_clk)); - - ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) | - NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | - NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); - - info->ndtr0cs0 = ndtr0; - info->ndtr1cs0 = ndtr1; - nand_writel(info, NDTR0CS0, ndtr0); - nand_writel(info, NDTR1CS0, ndtr1); -} - -static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, - const struct nand_sdr_timings *t) -{ - struct pxa3xx_nand_info *info = host->info_data; - struct nand_chip *chip = &host->chip; - unsigned long nand_clk = mvebu_get_nand_clock(); - uint32_t ndtr0, ndtr1; - - u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000); - u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000); - u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000); - u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000); - u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000); - u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000); - u32 tR = chip->chip_delay * 1000; - u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000); - u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000); - - /* fallback to a default value if tR = 0 */ - if (!tR) - tR = 20000; - - ndtr0 = NDTR0_tCH(ns2cycle(tCH_min, nand_clk)) | - NDTR0_tCS(ns2cycle(tCS_min, nand_clk)) | - NDTR0_tWH(ns2cycle(tWH_min, nand_clk)) | - NDTR0_tWP(ns2cycle(tWP_min, nand_clk)) | - NDTR0_tRH(ns2cycle(tREH_min, nand_clk)) | - NDTR0_tRP(ns2cycle(tRP_min, nand_clk)); - - ndtr1 = NDTR1_tR(ns2cycle(tR, nand_clk)) | - NDTR1_tWHR(ns2cycle(tWHR_min, nand_clk)) | - NDTR1_tAR(ns2cycle(tAR_min, nand_clk)); - - info->ndtr0cs0 = ndtr0; - info->ndtr1cs0 = ndtr1; - nand_writel(info, NDTR0CS0, ndtr0); - nand_writel(info, NDTR1CS0, ndtr1); -} - -static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) -{ - const struct nand_sdr_timings *timings; - struct nand_chip *chip = &host->chip; - struct pxa3xx_nand_info *info = host->info_data; - const struct pxa3xx_nand_flash *f = NULL; - struct mtd_info *mtd = nand_to_mtd(&host->chip); - int mode, id, ntypes, i; - - mode = onfi_get_async_timing_mode(chip); - if (mode == ONFI_TIMING_MODE_UNKNOWN) { - ntypes = ARRAY_SIZE(builtin_flash_types); - - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - id = chip->read_byte(mtd); - id |= chip->read_byte(mtd) << 0x8; - - for (i = 0; i < ntypes; i++) { - f = &builtin_flash_types[i]; - - if (f->chip_id == id) - break; - } - - if (i == ntypes) { - dev_err(&info->pdev->dev, "Error: timings not found\n"); - return -EINVAL; - } - - pxa3xx_nand_set_timing(host, f->timing); - - if (f->flash_width == 16) { - info->reg_ndcr |= NDCR_DWIDTH_M; - chip->options |= NAND_BUSWIDTH_16; - } - - info->reg_ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; - } else { - mode = fls(mode) - 1; - if (mode < 0) - mode = 0; - - timings = onfi_async_timing_mode_to_sdr_timings(mode); - if (IS_ERR(timings)) - return PTR_ERR(timings); - - pxa3xx_nand_set_sdr_timing(host, timings); - } - - return 0; -} - -/** - * NOTE: it is a must to set ND_RUN first, then write - * command buffer, otherwise, it does not work. - * We enable all the interrupt at the same time, and - * let pxa3xx_nand_irq to handle all logic. - */ -static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) -{ - uint32_t ndcr; - - ndcr = info->reg_ndcr; - - if (info->use_ecc) { - ndcr |= NDCR_ECC_EN; - if (info->ecc_bch) - nand_writel(info, NDECCCTRL, 0x1); - } else { - ndcr &= ~NDCR_ECC_EN; - if (info->ecc_bch) - nand_writel(info, NDECCCTRL, 0x0); - } - - ndcr &= ~NDCR_DMA_EN; - - if (info->use_spare) - ndcr |= NDCR_SPARE_EN; - else - ndcr &= ~NDCR_SPARE_EN; - - ndcr |= NDCR_ND_RUN; - - /* clear status bits and run */ - nand_writel(info, NDSR, NDSR_MASK); - nand_writel(info, NDCR, 0); - nand_writel(info, NDCR, ndcr); -} - -static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) -{ - uint32_t ndcr; - - ndcr = nand_readl(info, NDCR); - nand_writel(info, NDCR, ndcr | int_mask); -} - -static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) -{ - if (info->ecc_bch) { - u32 ts; - - /* - * According to the datasheet, when reading from NDDB - * with BCH enabled, after each 32 bytes reads, we - * have to make sure that the NDSR.RDDREQ bit is set. - * - * Drain the FIFO 8 32 bits reads at a time, and skip - * the polling on the last read. - */ - while (len > 8) { - readsl(info->mmio_base + NDDB, data, 8); - - ts = get_timer(0); - while (!(nand_readl(info, NDSR) & NDSR_RDDREQ)) { - if (get_timer(ts) > TIMEOUT_DRAIN_FIFO) { - dev_err(&info->pdev->dev, - "Timeout on RDDREQ while draining the FIFO\n"); - return; - } - } - - data += 32; - len -= 8; - } - } - - readsl(info->mmio_base + NDDB, data, len); -} - -static void handle_data_pio(struct pxa3xx_nand_info *info) -{ - switch (info->state) { - case STATE_PIO_WRITING: - if (info->step_chunk_size) - writesl(info->mmio_base + NDDB, - info->data_buff + info->data_buff_pos, - DIV_ROUND_UP(info->step_chunk_size, 4)); - - if (info->step_spare_size) - writesl(info->mmio_base + NDDB, - info->oob_buff + info->oob_buff_pos, - DIV_ROUND_UP(info->step_spare_size, 4)); - break; - case STATE_PIO_READING: - if (info->step_chunk_size) - drain_fifo(info, - info->data_buff + info->data_buff_pos, - DIV_ROUND_UP(info->step_chunk_size, 4)); - - if (info->step_spare_size) - drain_fifo(info, - info->oob_buff + info->oob_buff_pos, - DIV_ROUND_UP(info->step_spare_size, 4)); - break; - default: - dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, - info->state); - BUG(); - } - - /* Update buffer pointers for multi-page read/write */ - info->data_buff_pos += info->step_chunk_size; - info->oob_buff_pos += info->step_spare_size; -} - -static void pxa3xx_nand_irq_thread(struct pxa3xx_nand_info *info) -{ - handle_data_pio(info); - - info->state = STATE_CMD_DONE; - nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); -} - -static irqreturn_t pxa3xx_nand_irq(struct pxa3xx_nand_info *info) -{ - unsigned int status, is_completed = 0, is_ready = 0; - unsigned int ready, cmd_done; - irqreturn_t ret = IRQ_HANDLED; - - if (info->cs == 0) { - ready = NDSR_FLASH_RDY; - cmd_done = NDSR_CS0_CMDD; - } else { - ready = NDSR_RDY; - cmd_done = NDSR_CS1_CMDD; - } - - /* TODO - find out why we need the delay during write operation. */ - ndelay(1); - - status = nand_readl(info, NDSR); - - if (status & NDSR_UNCORERR) - info->retcode = ERR_UNCORERR; - if (status & NDSR_CORERR) { - info->retcode = ERR_CORERR; - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 && - info->ecc_bch) - info->ecc_err_cnt = NDSR_ERR_CNT(status); - else - info->ecc_err_cnt = 1; - - /* - * Each chunk composing a page is corrected independently, - * and we need to store maximum number of corrected bitflips - * to return it to the MTD layer in ecc.read_page(). - */ - info->max_bitflips = max_t(unsigned int, - info->max_bitflips, - info->ecc_err_cnt); - } - if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) { - info->state = (status & NDSR_RDDREQ) ? - STATE_PIO_READING : STATE_PIO_WRITING; - /* Call the IRQ thread in U-Boot directly */ - pxa3xx_nand_irq_thread(info); - return 0; - } - if (status & cmd_done) { - info->state = STATE_CMD_DONE; - is_completed = 1; - } - if (status & ready) { - info->state = STATE_READY; - is_ready = 1; - } - - /* - * Clear all status bit before issuing the next command, which - * can and will alter the status bits and will deserve a new - * interrupt on its own. This lets the controller exit the IRQ - */ - nand_writel(info, NDSR, status); - - if (status & NDSR_WRCMDREQ) { - status &= ~NDSR_WRCMDREQ; - info->state = STATE_CMD_HANDLE; - - /* - * Command buffer registers NDCB{0-2} (and optionally NDCB3) - * must be loaded by writing directly either 12 or 16 - * bytes directly to NDCB0, four bytes at a time. - * - * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored - * but each NDCBx register can be read. - */ - nand_writel(info, NDCB0, info->ndcb0); - nand_writel(info, NDCB0, info->ndcb1); - nand_writel(info, NDCB0, info->ndcb2); - - /* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */ - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) - nand_writel(info, NDCB0, info->ndcb3); - } - - if (is_completed) - info->cmd_complete = 1; - if (is_ready) - info->dev_ready = 1; - - return ret; -} - -static inline int is_buf_blank(uint8_t *buf, size_t len) -{ - for (; len > 0; len--) - if (*buf++ != 0xff) - return 0; - return 1; -} - -static void set_command_address(struct pxa3xx_nand_info *info, - unsigned int page_size, uint16_t column, int page_addr) -{ - /* small page addr setting */ - if (page_size < info->chunk_size) { - info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) - | (column & 0xFF); - - info->ndcb2 = 0; - } else { - info->ndcb1 = ((page_addr & 0xFFFF) << 16) - | (column & 0xFFFF); - - if (page_addr & 0xFF0000) - info->ndcb2 = (page_addr & 0xFF0000) >> 16; - else - info->ndcb2 = 0; - } -} - -static void prepare_start_command(struct pxa3xx_nand_info *info, int command) -{ - struct pxa3xx_nand_host *host = info->host[info->cs]; - struct mtd_info *mtd = nand_to_mtd(&host->chip); - - /* reset data and oob column point to handle data */ - info->buf_start = 0; - info->buf_count = 0; - info->data_buff_pos = 0; - info->oob_buff_pos = 0; - info->step_chunk_size = 0; - info->step_spare_size = 0; - info->cur_chunk = 0; - info->use_ecc = 0; - info->use_spare = 1; - info->retcode = ERR_NONE; - info->ecc_err_cnt = 0; - info->ndcb3 = 0; - info->need_wait = 0; - - switch (command) { - case NAND_CMD_READ0: - case NAND_CMD_READOOB: - case NAND_CMD_PAGEPROG: - info->use_ecc = 1; - break; - case NAND_CMD_PARAM: - info->use_spare = 0; - break; - default: - info->ndcb1 = 0; - info->ndcb2 = 0; - break; - } - - /* - * If we are about to issue a read command, or about to set - * the write address, then clean the data buffer. - */ - if (command == NAND_CMD_READ0 || - command == NAND_CMD_READOOB || - command == NAND_CMD_SEQIN) { - info->buf_count = mtd->writesize + mtd->oobsize; - memset(info->data_buff, 0xFF, info->buf_count); - } -} - -static int prepare_set_command(struct pxa3xx_nand_info *info, int command, - int ext_cmd_type, uint16_t column, int page_addr) -{ - int addr_cycle, exec_cmd; - struct pxa3xx_nand_host *host; - struct mtd_info *mtd; - - host = info->host[info->cs]; - mtd = nand_to_mtd(&host->chip); - addr_cycle = 0; - exec_cmd = 1; - - if (info->cs != 0) - info->ndcb0 = NDCB0_CSEL; - else - info->ndcb0 = 0; - - if (command == NAND_CMD_SEQIN) - exec_cmd = 0; - - addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles - + host->col_addr_cycles); - - switch (command) { - case NAND_CMD_READOOB: - case NAND_CMD_READ0: - info->buf_start = column; - info->ndcb0 |= NDCB0_CMD_TYPE(0) - | addr_cycle - | NAND_CMD_READ0; - - if (command == NAND_CMD_READOOB) - info->buf_start += mtd->writesize; - - if (info->cur_chunk < info->nfullchunks) { - info->step_chunk_size = info->chunk_size; - info->step_spare_size = info->spare_size; - } else { - info->step_chunk_size = info->last_chunk_size; - info->step_spare_size = info->last_spare_size; - } - - /* - * Multiple page read needs an 'extended command type' field, - * which is either naked-read or last-read according to the - * state. - */ - if (mtd->writesize == info->chunk_size) { - info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); - } else if (mtd->writesize > info->chunk_size) { - info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) - | NDCB0_LEN_OVRD - | NDCB0_EXT_CMD_TYPE(ext_cmd_type); - info->ndcb3 = info->step_chunk_size + - info->step_spare_size; - } - - set_command_address(info, mtd->writesize, column, page_addr); - break; - - case NAND_CMD_SEQIN: - - info->buf_start = column; - set_command_address(info, mtd->writesize, 0, page_addr); - - /* - * Multiple page programming needs to execute the initial - * SEQIN command that sets the page address. - */ - if (mtd->writesize > info->chunk_size) { - info->ndcb0 |= NDCB0_CMD_TYPE(0x1) - | NDCB0_EXT_CMD_TYPE(ext_cmd_type) - | addr_cycle - | command; - exec_cmd = 1; - } - break; - - case NAND_CMD_PAGEPROG: - if (is_buf_blank(info->data_buff, - (mtd->writesize + mtd->oobsize))) { - exec_cmd = 0; - break; - } - - if (info->cur_chunk < info->nfullchunks) { - info->step_chunk_size = info->chunk_size; - info->step_spare_size = info->spare_size; - } else { - info->step_chunk_size = info->last_chunk_size; - info->step_spare_size = info->last_spare_size; - } - - /* Second command setting for large pages */ - if (mtd->writesize > info->chunk_size) { - /* - * Multiple page write uses the 'extended command' - * field. This can be used to issue a command dispatch - * or a naked-write depending on the current stage. - */ - info->ndcb0 |= NDCB0_CMD_TYPE(0x1) - | NDCB0_LEN_OVRD - | NDCB0_EXT_CMD_TYPE(ext_cmd_type); - info->ndcb3 = info->step_chunk_size + - info->step_spare_size; - - /* - * This is the command dispatch that completes a chunked - * page program operation. - */ - if (info->cur_chunk == info->ntotalchunks) { - info->ndcb0 = NDCB0_CMD_TYPE(0x1) - | NDCB0_EXT_CMD_TYPE(ext_cmd_type) - | command; - info->ndcb1 = 0; - info->ndcb2 = 0; - info->ndcb3 = 0; - } - } else { - info->ndcb0 |= NDCB0_CMD_TYPE(0x1) - | NDCB0_AUTO_RS - | NDCB0_ST_ROW_EN - | NDCB0_DBC - | (NAND_CMD_PAGEPROG << 8) - | NAND_CMD_SEQIN - | addr_cycle; - } - break; - - case NAND_CMD_PARAM: - info->buf_count = INIT_BUFFER_SIZE; - info->ndcb0 |= NDCB0_CMD_TYPE(0) - | NDCB0_ADDR_CYC(1) - | NDCB0_LEN_OVRD - | command; - info->ndcb1 = (column & 0xFF); - info->ndcb3 = INIT_BUFFER_SIZE; - info->step_chunk_size = INIT_BUFFER_SIZE; - break; - - case NAND_CMD_READID: - info->buf_count = READ_ID_BYTES; - info->ndcb0 |= NDCB0_CMD_TYPE(3) - | NDCB0_ADDR_CYC(1) - | command; - info->ndcb1 = (column & 0xFF); - - info->step_chunk_size = 8; - break; - case NAND_CMD_STATUS: - info->buf_count = 1; - info->ndcb0 |= NDCB0_CMD_TYPE(4) - | NDCB0_ADDR_CYC(1) - | command; - - info->step_chunk_size = 8; - break; - - case NAND_CMD_ERASE1: - info->ndcb0 |= NDCB0_CMD_TYPE(2) - | NDCB0_AUTO_RS - | NDCB0_ADDR_CYC(3) - | NDCB0_DBC - | (NAND_CMD_ERASE2 << 8) - | NAND_CMD_ERASE1; - info->ndcb1 = page_addr; - info->ndcb2 = 0; - - break; - case NAND_CMD_RESET: - info->ndcb0 |= NDCB0_CMD_TYPE(5) - | command; - - break; - - case NAND_CMD_ERASE2: - exec_cmd = 0; - break; - - default: - exec_cmd = 0; - dev_err(&info->pdev->dev, "non-supported command %x\n", - command); - break; - } - - return exec_cmd; -} - -static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, - int column, int page_addr) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct pxa3xx_nand_host *host = nand_get_controller_data(chip); - struct pxa3xx_nand_info *info = host->info_data; - int exec_cmd; - - /* - * if this is a x16 device ,then convert the input - * "byte" address into a "word" address appropriate - * for indexing a word-oriented device - */ - if (info->reg_ndcr & NDCR_DWIDTH_M) - column /= 2; - - /* - * There may be different NAND chip hooked to - * different chip select, so check whether - * chip select has been changed, if yes, reset the timing - */ - if (info->cs != host->cs) { - info->cs = host->cs; - nand_writel(info, NDTR0CS0, info->ndtr0cs0); - nand_writel(info, NDTR1CS0, info->ndtr1cs0); - } - - prepare_start_command(info, command); - - info->state = STATE_PREPARED; - exec_cmd = prepare_set_command(info, command, 0, column, page_addr); - - if (exec_cmd) { - u32 ts; - - info->cmd_complete = 0; - info->dev_ready = 0; - info->need_wait = 1; - pxa3xx_nand_start(info); - - ts = get_timer(0); - while (1) { - u32 status; - - status = nand_readl(info, NDSR); - if (status) - pxa3xx_nand_irq(info); - - if (info->cmd_complete) - break; - - if (get_timer(ts) > CHIP_DELAY_TIMEOUT) { - dev_err(&info->pdev->dev, "Wait timeout!!!\n"); - return; - } - } - } - info->state = STATE_IDLE; -} - -static void nand_cmdfunc_extended(struct mtd_info *mtd, - const unsigned command, - int column, int page_addr) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct pxa3xx_nand_host *host = nand_get_controller_data(chip); - struct pxa3xx_nand_info *info = host->info_data; - int exec_cmd, ext_cmd_type; - - /* - * if this is a x16 device then convert the input - * "byte" address into a "word" address appropriate - * for indexing a word-oriented device - */ - if (info->reg_ndcr & NDCR_DWIDTH_M) - column /= 2; - - /* - * There may be different NAND chip hooked to - * different chip select, so check whether - * chip select has been changed, if yes, reset the timing - */ - if (info->cs != host->cs) { - info->cs = host->cs; - nand_writel(info, NDTR0CS0, info->ndtr0cs0); - nand_writel(info, NDTR1CS0, info->ndtr1cs0); - } - - /* Select the extended command for the first command */ - switch (command) { - case NAND_CMD_READ0: - case NAND_CMD_READOOB: - ext_cmd_type = EXT_CMD_TYPE_MONO; - break; - case NAND_CMD_SEQIN: - ext_cmd_type = EXT_CMD_TYPE_DISPATCH; - break; - case NAND_CMD_PAGEPROG: - ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; - break; - default: - ext_cmd_type = 0; - break; - } - - prepare_start_command(info, command); - - /* - * Prepare the "is ready" completion before starting a command - * transaction sequence. If the command is not executed the - * completion will be completed, see below. - * - * We can do that inside the loop because the command variable - * is invariant and thus so is the exec_cmd. - */ - info->need_wait = 1; - info->dev_ready = 0; - - do { - u32 ts; - - info->state = STATE_PREPARED; - exec_cmd = prepare_set_command(info, command, ext_cmd_type, - column, page_addr); - if (!exec_cmd) { - info->need_wait = 0; - info->dev_ready = 1; - break; - } - - info->cmd_complete = 0; - pxa3xx_nand_start(info); - - ts = get_timer(0); - while (1) { - u32 status; - - status = nand_readl(info, NDSR); - if (status) - pxa3xx_nand_irq(info); - - if (info->cmd_complete) - break; - - if (get_timer(ts) > CHIP_DELAY_TIMEOUT) { - dev_err(&info->pdev->dev, "Wait timeout!!!\n"); - return; - } - } - - /* Only a few commands need several steps */ - if (command != NAND_CMD_PAGEPROG && - command != NAND_CMD_READ0 && - command != NAND_CMD_READOOB) - break; - - info->cur_chunk++; - - /* Check if the sequence is complete */ - if (info->cur_chunk == info->ntotalchunks && - command != NAND_CMD_PAGEPROG) - break; - - /* - * After a splitted program command sequence has issued - * the command dispatch, the command sequence is complete. - */ - if (info->cur_chunk == (info->ntotalchunks + 1) && - command == NAND_CMD_PAGEPROG && - ext_cmd_type == EXT_CMD_TYPE_DISPATCH) - break; - - if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) { - /* Last read: issue a 'last naked read' */ - if (info->cur_chunk == info->ntotalchunks - 1) - ext_cmd_type = EXT_CMD_TYPE_LAST_RW; - else - ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; - - /* - * If a splitted program command has no more data to transfer, - * the command dispatch must be issued to complete. - */ - } else if (command == NAND_CMD_PAGEPROG && - info->cur_chunk == info->ntotalchunks) { - ext_cmd_type = EXT_CMD_TYPE_DISPATCH; - } - } while (1); - - info->state = STATE_IDLE; -} - -static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required, - int page) -{ - chip->write_buf(mtd, buf, mtd->writesize); - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, - int page) -{ - struct pxa3xx_nand_host *host = nand_get_controller_data(chip); - struct pxa3xx_nand_info *info = host->info_data; - - chip->read_buf(mtd, buf, mtd->writesize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - - if (info->retcode == ERR_CORERR && info->use_ecc) { - mtd->ecc_stats.corrected += info->ecc_err_cnt; - - } else if (info->retcode == ERR_UNCORERR) { - /* - * for blank page (all 0xff), HW will calculate its ECC as - * 0, which is different from the ECC information within - * OOB, ignore such uncorrectable errors - */ - if (is_buf_blank(buf, mtd->writesize)) - info->retcode = ERR_NONE; - else - mtd->ecc_stats.failed++; - } - - return info->max_bitflips; -} - -static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct pxa3xx_nand_host *host = nand_get_controller_data(chip); - struct pxa3xx_nand_info *info = host->info_data; - char retval = 0xFF; - - if (info->buf_start < info->buf_count) - /* Has just send a new command? */ - retval = info->data_buff[info->buf_start++]; - - return retval; -} - -static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct pxa3xx_nand_host *host = nand_get_controller_data(chip); - struct pxa3xx_nand_info *info = host->info_data; - u16 retval = 0xFFFF; - - if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { - retval = *((u16 *)(info->data_buff+info->buf_start)); - info->buf_start += 2; - } - return retval; -} - -static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct pxa3xx_nand_host *host = nand_get_controller_data(chip); - struct pxa3xx_nand_info *info = host->info_data; - int real_len = min_t(size_t, len, info->buf_count - info->buf_start); - - memcpy(buf, info->data_buff + info->buf_start, real_len); - info->buf_start += real_len; -} - -static void pxa3xx_nand_write_buf(struct mtd_info *mtd, - const uint8_t *buf, int len) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct pxa3xx_nand_host *host = nand_get_controller_data(chip); - struct pxa3xx_nand_info *info = host->info_data; - int real_len = min_t(size_t, len, info->buf_count - info->buf_start); - - memcpy(info->data_buff + info->buf_start, buf, real_len); - info->buf_start += real_len; -} - -static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip) -{ - return; -} - -static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct pxa3xx_nand_host *host = nand_get_controller_data(chip); - struct pxa3xx_nand_info *info = host->info_data; - - if (info->need_wait) { - u32 ts; - - info->need_wait = 0; - - ts = get_timer(0); - while (1) { - u32 status; - - status = nand_readl(info, NDSR); - if (status) - pxa3xx_nand_irq(info); - - if (info->dev_ready) - break; - - if (get_timer(ts) > CHIP_DELAY_TIMEOUT) { - dev_err(&info->pdev->dev, "Ready timeout!!!\n"); - return NAND_STATUS_FAIL; - } - } - } - - /* pxa3xx_nand_send_command has waited for command complete */ - if (this->state == FL_WRITING || this->state == FL_ERASING) { - if (info->retcode == ERR_NONE) - return 0; - else - return NAND_STATUS_FAIL; - } - - return NAND_STATUS_READY; -} - -static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info) -{ - struct pxa3xx_nand_platform_data *pdata = info->pdata; - - /* Configure default flash values */ - info->reg_ndcr = 0x0; /* enable all interrupts */ - info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; - info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); - info->reg_ndcr |= NDCR_SPARE_EN; - - return 0; -} - -static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info) -{ - struct pxa3xx_nand_host *host = info->host[info->cs]; - struct mtd_info *mtd = nand_to_mtd(&info->host[info->cs]->chip); - struct nand_chip *chip = mtd_to_nand(mtd); - - info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; - info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0; - info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0; -} - -static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) -{ - struct pxa3xx_nand_platform_data *pdata = info->pdata; - uint32_t ndcr = nand_readl(info, NDCR); - - /* Set an initial chunk size */ - info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; - info->reg_ndcr = ndcr & - ~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL); - info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; - info->ndtr0cs0 = nand_readl(info, NDTR0CS0); - info->ndtr1cs0 = nand_readl(info, NDTR1CS0); -} - -static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) -{ - info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); - if (info->data_buff == NULL) - return -ENOMEM; - return 0; -} - -static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host) -{ - struct pxa3xx_nand_info *info = host->info_data; - struct pxa3xx_nand_platform_data *pdata = info->pdata; - struct mtd_info *mtd; - struct nand_chip *chip; - const struct nand_sdr_timings *timings; - int ret; - - mtd = nand_to_mtd(&info->host[info->cs]->chip); - chip = mtd_to_nand(mtd); - - /* configure default flash values */ - info->reg_ndcr = 0x0; /* enable all interrupts */ - info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; - info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); - info->reg_ndcr |= NDCR_SPARE_EN; /* enable spare by default */ - - /* use the common timing to make a try */ - timings = onfi_async_timing_mode_to_sdr_timings(0); - if (IS_ERR(timings)) - return PTR_ERR(timings); - - pxa3xx_nand_set_sdr_timing(host, timings); - - chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); - ret = chip->waitfunc(mtd, chip); - if (ret & NAND_STATUS_FAIL) - return -ENODEV; - - return 0; -} - -static int pxa_ecc_init(struct pxa3xx_nand_info *info, - struct nand_ecc_ctrl *ecc, - int strength, int ecc_stepsize, int page_size) -{ - if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) { - info->nfullchunks = 1; - info->ntotalchunks = 1; - info->chunk_size = 2048; - info->spare_size = 40; - info->ecc_size = 24; - ecc->mode = NAND_ECC_HW; - ecc->size = 512; - ecc->strength = 1; - - } else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) { - info->nfullchunks = 1; - info->ntotalchunks = 1; - info->chunk_size = 512; - info->spare_size = 8; - info->ecc_size = 8; - ecc->mode = NAND_ECC_HW; - ecc->size = 512; - ecc->strength = 1; - - /* - * Required ECC: 4-bit correction per 512 bytes - * Select: 16-bit correction per 2048 bytes - */ - } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) { - info->ecc_bch = 1; - info->nfullchunks = 1; - info->ntotalchunks = 1; - info->chunk_size = 2048; - info->spare_size = 32; - info->ecc_size = 32; - ecc->mode = NAND_ECC_HW; - ecc->size = info->chunk_size; - ecc->layout = &ecc_layout_2KB_bch4bit; - ecc->strength = 16; - - } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) { - info->ecc_bch = 1; - info->nfullchunks = 2; - info->ntotalchunks = 2; - info->chunk_size = 2048; - info->spare_size = 32; - info->ecc_size = 32; - ecc->mode = NAND_ECC_HW; - ecc->size = info->chunk_size; - ecc->layout = &ecc_layout_4KB_bch4bit; - ecc->strength = 16; - - } else if (strength == 4 && ecc_stepsize == 512 && page_size == 8192) { - info->ecc_bch = 1; - info->nfullchunks = 4; - info->ntotalchunks = 4; - info->chunk_size = 2048; - info->spare_size = 32; - info->ecc_size = 32; - ecc->mode = NAND_ECC_HW; - ecc->size = info->chunk_size; - ecc->layout = &ecc_layout_8KB_bch4bit; - ecc->strength = 16; - - /* - * Required ECC: 8-bit correction per 512 bytes - * Select: 16-bit correction per 1024 bytes - */ - } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) { - info->ecc_bch = 1; - info->nfullchunks = 1; - info->ntotalchunks = 2; - info->chunk_size = 1024; - info->spare_size = 0; - info->last_chunk_size = 1024; - info->last_spare_size = 64; - info->ecc_size = 32; - ecc->mode = NAND_ECC_HW; - ecc->size = info->chunk_size; - ecc->layout = &ecc_layout_2KB_bch8bit; - ecc->strength = 16; - - } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) { - info->ecc_bch = 1; - info->nfullchunks = 4; - info->ntotalchunks = 5; - info->chunk_size = 1024; - info->spare_size = 0; - info->last_chunk_size = 0; - info->last_spare_size = 64; - info->ecc_size = 32; - ecc->mode = NAND_ECC_HW; - ecc->size = info->chunk_size; - ecc->layout = &ecc_layout_4KB_bch8bit; - ecc->strength = 16; - - } else if (strength == 8 && ecc_stepsize == 512 && page_size == 8192) { - info->ecc_bch = 1; - info->nfullchunks = 8; - info->ntotalchunks = 9; - info->chunk_size = 1024; - info->spare_size = 0; - info->last_chunk_size = 0; - info->last_spare_size = 160; - info->ecc_size = 32; - ecc->mode = NAND_ECC_HW; - ecc->size = info->chunk_size; - ecc->layout = &ecc_layout_8KB_bch8bit; - ecc->strength = 16; - - } else { - dev_err(&info->pdev->dev, - "ECC strength %d at page size %d is not supported\n", - strength, page_size); - return -ENODEV; - } - - return 0; -} - -static int pxa3xx_nand_scan(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct pxa3xx_nand_host *host = nand_get_controller_data(chip); - struct pxa3xx_nand_info *info = host->info_data; - struct pxa3xx_nand_platform_data *pdata = info->pdata; - int ret; - uint16_t ecc_strength, ecc_step; - - if (pdata->keep_config) { - pxa3xx_nand_detect_config(info); - } else { - ret = pxa3xx_nand_config_ident(info); - if (ret) - return ret; - ret = pxa3xx_nand_sensing(host); - if (ret) { - dev_info(&info->pdev->dev, - "There is no chip on cs %d!\n", - info->cs); - return ret; - } - } - - /* Device detection must be done with ECC disabled */ - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) - nand_writel(info, NDECCCTRL, 0x0); - - if (nand_scan_ident(mtd, 1, NULL)) - return -ENODEV; - - if (!pdata->keep_config) { - ret = pxa3xx_nand_init_timings(host); - if (ret) { - dev_err(&info->pdev->dev, - "Failed to set timings: %d\n", ret); - return ret; - } - } - -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - /* - * We'll use a bad block table stored in-flash and don't - * allow writing the bad block marker to the flash. - */ - chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB_BBM; - chip->bbt_td = &bbt_main_descr; - chip->bbt_md = &bbt_mirror_descr; -#endif - - if (pdata->ecc_strength && pdata->ecc_step_size) { - ecc_strength = pdata->ecc_strength; - ecc_step = pdata->ecc_step_size; - } else { - ecc_strength = chip->ecc_strength_ds; - ecc_step = chip->ecc_step_ds; - } - - /* Set default ECC strength requirements on non-ONFI devices */ - if (ecc_strength < 1 && ecc_step < 1) { - ecc_strength = 1; - ecc_step = 512; - } - - ret = pxa_ecc_init(info, &chip->ecc, ecc_strength, - ecc_step, mtd->writesize); - if (ret) - return ret; - - /* - * If the page size is bigger than the FIFO size, let's check - * we are given the right variant and then switch to the extended - * (aka split) command handling, - */ - if (mtd->writesize > info->chunk_size) { - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) { - chip->cmdfunc = nand_cmdfunc_extended; - } else { - dev_err(&info->pdev->dev, - "unsupported page size on this variant\n"); - return -ENODEV; - } - } - - /* calculate addressing information */ - if (mtd->writesize >= 2048) - host->col_addr_cycles = 2; - else - host->col_addr_cycles = 1; - - /* release the initial buffer */ - kfree(info->data_buff); - - /* allocate the real data + oob buffer */ - info->buf_size = mtd->writesize + mtd->oobsize; - ret = pxa3xx_nand_init_buff(info); - if (ret) - return ret; - info->oob_buff = info->data_buff + mtd->writesize; - - if ((mtd->size >> chip->page_shift) > 65536) - host->row_addr_cycles = 3; - else - host->row_addr_cycles = 2; - - if (!pdata->keep_config) - pxa3xx_nand_config_tail(info); - - return nand_scan_tail(mtd); -} - -static int alloc_nand_resource(struct pxa3xx_nand_info *info) -{ - struct pxa3xx_nand_platform_data *pdata; - struct pxa3xx_nand_host *host; - struct nand_chip *chip = NULL; - struct mtd_info *mtd; - int ret, cs; - - pdata = info->pdata; - if (pdata->num_cs <= 0) - return -ENODEV; - - info->variant = pxa3xx_nand_get_variant(); - for (cs = 0; cs < pdata->num_cs; cs++) { - chip = (struct nand_chip *) - ((u8 *)&info[1] + sizeof(*host) * cs); - mtd = nand_to_mtd(chip); - host = (struct pxa3xx_nand_host *)chip; - info->host[cs] = host; - host->cs = cs; - host->info_data = info; - mtd->owner = THIS_MODULE; - - nand_set_controller_data(chip, host); - chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; - chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; - chip->controller = &info->controller; - chip->waitfunc = pxa3xx_nand_waitfunc; - chip->select_chip = pxa3xx_nand_select_chip; - chip->read_word = pxa3xx_nand_read_word; - chip->read_byte = pxa3xx_nand_read_byte; - chip->read_buf = pxa3xx_nand_read_buf; - chip->write_buf = pxa3xx_nand_write_buf; - chip->options |= NAND_NO_SUBPAGE_WRITE; - chip->cmdfunc = nand_cmdfunc; - } - - /* Allocate a buffer to allow flash detection */ - info->buf_size = INIT_BUFFER_SIZE; - info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); - if (info->data_buff == NULL) { - ret = -ENOMEM; - goto fail_disable_clk; - } - - /* initialize all interrupts to be disabled */ - disable_int(info, NDSR_MASK); - - return 0; - - kfree(info->data_buff); -fail_disable_clk: - return ret; -} - -static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) -{ - struct pxa3xx_nand_platform_data *pdata; - const void *blob = gd->fdt_blob; - int node = -1; - - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - /* Get address decoding nodes from the FDT blob */ - do { - node = fdt_node_offset_by_compatible(blob, node, - "marvell,mvebu-pxa3xx-nand"); - if (node < 0) - break; - - /* Bypass disabeld nodes */ - if (!fdtdec_get_is_enabled(blob, node)) - continue; - - /* Get the first enabled NAND controler base address */ - info->mmio_base = - (void __iomem *)fdtdec_get_addr_size_auto_noparent( - blob, node, "reg", 0, NULL, true); - - pdata->num_cs = fdtdec_get_int(blob, node, "num-cs", 1); - if (pdata->num_cs != 1) { - pr_err("pxa3xx driver supports single CS only\n"); - break; - } - - if (fdtdec_get_bool(blob, node, "nand-enable-arbiter")) - pdata->enable_arbiter = 1; - - if (fdtdec_get_bool(blob, node, "nand-keep-config")) - pdata->keep_config = 1; - - /* - * ECC parameters. - * If these are not set, they will be selected according - * to the detected flash type. - */ - /* ECC strength */ - pdata->ecc_strength = fdtdec_get_int(blob, node, - "nand-ecc-strength", 0); - - /* ECC step size */ - pdata->ecc_step_size = fdtdec_get_int(blob, node, - "nand-ecc-step-size", 0); - - info->pdata = pdata; - - /* Currently support only a single NAND controller */ - return 0; - - } while (node >= 0); - - return -EINVAL; -} - -static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info) -{ - struct pxa3xx_nand_platform_data *pdata; - int ret, cs, probe_success; - - ret = pxa3xx_nand_probe_dt(info); - if (ret) - return ret; - - pdata = info->pdata; - - ret = alloc_nand_resource(info); - if (ret) { - dev_err(&pdev->dev, "alloc nand resource failed\n"); - return ret; - } - - probe_success = 0; - for (cs = 0; cs < pdata->num_cs; cs++) { - struct mtd_info *mtd = nand_to_mtd(&info->host[cs]->chip); - - /* - * The mtd name matches the one used in 'mtdparts' kernel - * parameter. This name cannot be changed or otherwise - * user's mtd partitions configuration would get broken. - */ - mtd->name = "pxa3xx_nand-0"; - info->cs = cs; - ret = pxa3xx_nand_scan(mtd); - if (ret) { - dev_info(&pdev->dev, "failed to scan nand at cs %d\n", - cs); - continue; - } - - if (nand_register(cs, mtd)) - continue; - - probe_success = 1; - } - - if (!probe_success) - return -ENODEV; - - return 0; -} - -/* - * Main initialization routine - */ -void board_nand_init(void) -{ - struct pxa3xx_nand_info *info; - struct pxa3xx_nand_host *host; - int ret; - - info = kzalloc(sizeof(*info) + - sizeof(*host) * CONFIG_SYS_MAX_NAND_DEVICE, - GFP_KERNEL); - if (!info) - return; - - ret = pxa3xx_nand_probe(info); - if (ret) - return; -} diff --git a/drivers/mtd/nand/pxa3xx_nand.h b/drivers/mtd/nand/pxa3xx_nand.h deleted file mode 100644 index 8f24ae6d18..0000000000 --- a/drivers/mtd/nand/pxa3xx_nand.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef __ASM_ARCH_PXA3XX_NAND_H -#define __ASM_ARCH_PXA3XX_NAND_H - -#include -#include - -struct pxa3xx_nand_timing { - unsigned int tCH; /* Enable signal hold time */ - unsigned int tCS; /* Enable signal setup time */ - unsigned int tWH; /* ND_nWE high duration */ - unsigned int tWP; /* ND_nWE pulse time */ - unsigned int tRH; /* ND_nRE high duration */ - unsigned int tRP; /* ND_nRE pulse width */ - unsigned int tR; /* ND_nWE high to ND_nRE low for read */ - unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */ - unsigned int tAR; /* ND_ALE low to ND_nRE low delay */ -}; - -struct pxa3xx_nand_flash { - uint32_t chip_id; - unsigned int flash_width; /* Width of Flash memory (DWIDTH_M) */ - unsigned int dfc_width; /* Width of flash controller(DWIDTH_C) */ - struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ -}; - -/* - * Current pxa3xx_nand controller has two chip select which - * both be workable. - * - * Notice should be taken that: - * When you want to use this feature, you should not enable the - * keep configuration feature, for two chip select could be - * attached with different nand chip. The different page size - * and timing requirement make the keep configuration impossible. - */ - -/* The max num of chip select current support */ -#define NUM_CHIP_SELECT (2) -struct pxa3xx_nand_platform_data { - /* the data flash bus is shared between the Static Memory - * Controller and the Data Flash Controller, the arbiter - * controls the ownership of the bus - */ - int enable_arbiter; - - /* allow platform code to keep OBM/bootloader defined NFC config */ - int keep_config; - - /* indicate how many chip selects will be used */ - int num_cs; - - /* use an flash-based bad block table */ - bool flash_bbt; - - /* requested ECC strength and ECC step size */ - int ecc_strength, ecc_step_size; - - const struct mtd_partition *parts[NUM_CHIP_SELECT]; - unsigned int nr_parts[NUM_CHIP_SELECT]; - - const struct pxa3xx_nand_flash *flash; - size_t num_flash; -}; -#endif /* __ASM_ARCH_PXA3XX_NAND_H */ diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig new file mode 100644 index 0000000000..1e4ea7bdd4 --- /dev/null +++ b/drivers/mtd/nand/raw/Kconfig @@ -0,0 +1,297 @@ + +menuconfig NAND + bool "NAND Device Support" +if NAND + +config SYS_NAND_SELF_INIT + bool + help + This option, if enabled, provides more flexible and linux-like + NAND initialization process. + +config NAND_ATMEL + bool "Support Atmel NAND controller" + imply SYS_NAND_USE_FLASH_BBT + help + Enable this driver for NAND flash platforms using an Atmel NAND + controller. + +config NAND_DAVINCI + bool "Support TI Davinci NAND controller" + help + Enable this driver for NAND flash controllers available in TI Davinci + and Keystone2 platforms + +config NAND_DENALI + bool + select SYS_NAND_SELF_INIT + imply CMD_NAND + +config NAND_DENALI_DT + bool "Support Denali NAND controller as a DT device" + select NAND_DENALI + depends on OF_CONTROL && DM + help + Enable the driver for NAND flash on platforms using a Denali NAND + controller as a DT device. + +config NAND_DENALI_SPARE_AREA_SKIP_BYTES + int "Number of bytes skipped in OOB area" + depends on NAND_DENALI + range 0 63 + help + This option specifies the number of bytes to skip from the beginning + of OOB area before last ECC sector data starts. This is potentially + used to preserve the bad block marker in the OOB area. + +config NAND_LPC32XX_SLC + bool "Support LPC32XX_SLC controller" + help + Enable the LPC32XX SLC NAND controller. + +config NAND_OMAP_GPMC + bool "Support OMAP GPMC NAND controller" + depends on ARCH_OMAP2PLUS + help + Enables omap_gpmc.c driver for OMAPx and AMxxxx platforms. + GPMC controller is used for parallel NAND flash devices, and can + do ECC calculation (not ECC error detection) for HAM1, BCH4, BCH8 + and BCH16 ECC algorithms. + +config NAND_OMAP_GPMC_PREFETCH + bool "Enable GPMC Prefetch" + depends on NAND_OMAP_GPMC + default y + help + On OMAP platforms that use the GPMC controller + (CONFIG_NAND_OMAP_GPMC_PREFETCH), this options enables the code that + uses the prefetch mode to speed up read operations. + +config NAND_OMAP_ELM + bool "Enable ELM driver for OMAPxx and AMxx platforms." + depends on NAND_OMAP_GPMC && !OMAP34XX + help + ELM controller is used for ECC error detection (not ECC calculation) + of BCH4, BCH8 and BCH16 ECC algorithms. + Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine, + thus such SoC platforms need to depend on software library for ECC error + detection. However ECC calculation on such plaforms would still be + done by GPMC controller. + +config NAND_VF610_NFC + bool "Support for Freescale NFC for VF610" + select SYS_NAND_SELF_INIT + imply CMD_NAND + help + Enables support for NAND Flash Controller on some Freescale + processors like the VF610, MCF54418 or Kinetis K70. + The driver supports a maximum 2k page size. The driver + currently does not support hardware ECC. + +choice + prompt "Hardware ECC strength" + depends on NAND_VF610_NFC + default SYS_NAND_VF610_NFC_45_ECC_BYTES + help + Select the ECC strength used in the hardware BCH ECC block. + +config SYS_NAND_VF610_NFC_45_ECC_BYTES + bool "24-error correction (45 ECC bytes)" + +config SYS_NAND_VF610_NFC_60_ECC_BYTES + bool "32-error correction (60 ECC bytes)" + +endchoice + +config NAND_PXA3XX + bool "Support for NAND on PXA3xx and Armada 370/XP/38x" + select SYS_NAND_SELF_INIT + imply CMD_NAND + help + This enables the driver for the NAND flash device found on + PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2). + +config NAND_SUNXI + bool "Support for NAND on Allwinner SoCs" + default ARCH_SUNXI + depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I + select SYS_NAND_SELF_INIT + select SYS_NAND_U_BOOT_LOCATIONS + select SPL_NAND_SUPPORT + imply CMD_NAND + ---help--- + Enable support for NAND. This option enables the standard and + SPL drivers. + The SPL driver only supports reading from the NAND using DMA + transfers. + +if NAND_SUNXI + +config NAND_SUNXI_SPL_ECC_STRENGTH + int "Allwinner NAND SPL ECC Strength" + default 64 + +config NAND_SUNXI_SPL_ECC_SIZE + int "Allwinner NAND SPL ECC Step Size" + default 1024 + +config NAND_SUNXI_SPL_USABLE_PAGE_SIZE + int "Allwinner NAND SPL Usable Page Size" + default 1024 + +endif + +config NAND_ARASAN + bool "Configure Arasan Nand" + select SYS_NAND_SELF_INIT + imply CMD_NAND + help + This enables Nand driver support for Arasan nand flash + controller. This uses the hardware ECC for read and + write operations. + +config NAND_MXC + bool "MXC NAND support" + depends on CPU_ARM926EJS || CPU_ARM1136 || MX5 + imply CMD_NAND + help + This enables the NAND driver for the NAND flash controller on the + i.MX27 / i.MX31 / i.MX5 rocessors. + +config NAND_MXS + bool "MXS NAND support" + depends on MX23 || MX28 || MX6 || MX7 + select SYS_NAND_SELF_INIT + imply CMD_NAND + select APBH_DMA + select APBH_DMA_BURST if ARCH_MX6 || ARCH_MX7 + select APBH_DMA_BURST8 if ARCH_MX6 || ARCH_MX7 + help + This enables NAND driver for the NAND flash controller on the + MXS processors. + +if NAND_MXS + +config NAND_MXS_DT + bool "Support MXS NAND controller as a DT device" + depends on OF_CONTROL && MTD + help + Enable the driver for MXS NAND flash on platforms using + device tree. + +config NAND_MXS_USE_MINIMUM_ECC + bool "Use minimum ECC strength supported by the controller" + default false + +endif + +config NAND_ZYNQ + bool "Support for Zynq Nand controller" + select SYS_NAND_SELF_INIT + imply CMD_NAND + help + This enables Nand driver support for Nand flash controller + found on Zynq SoC. + +config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS + bool "Enable use of 1st stage bootloader timing for NAND" + depends on NAND_ZYNQ + help + This flag prevent U-boot reconfigure NAND flash controller and reuse + the NAND timing from 1st stage bootloader. + +comment "Generic NAND options" + +config SYS_NAND_BLOCK_SIZE + hex "NAND chip eraseblock size" + depends on ARCH_SUNXI + help + Number of data bytes in one eraseblock for the NAND chip on the + board. This is the multiple of NAND_PAGE_SIZE and the number of + pages. + +config SYS_NAND_PAGE_SIZE + hex "NAND chip page size" + depends on ARCH_SUNXI + help + Number of data bytes in one page for the NAND chip on the + board, not including the OOB area. + +config SYS_NAND_OOBSIZE + hex "NAND chip OOB size" + depends on ARCH_SUNXI + help + Number of bytes in the Out-Of-Band area for the NAND chip on + the board. + +# Enhance depends when converting drivers to Kconfig which use this config +# option (mxc_nand, ndfc, omap_gpmc). +config SYS_NAND_BUSWIDTH_16BIT + bool "Use 16-bit NAND interface" + depends on NAND_VF610_NFC || NAND_OMAP_GPMC || NAND_MXC || ARCH_DAVINCI + help + Indicates that NAND device has 16-bit wide data-bus. In absence of this + config, bus-width of NAND device is assumed to be either 8-bit and later + determined by reading ONFI params. + Above config is useful when NAND device's bus-width information cannot + be determined from on-chip ONFI params, like in following scenarios: + - SPL boot does not support reading of ONFI parameters. This is done to + keep SPL code foot-print small. + - In current U-Boot flow using nand_init(), driver initialization + happens in board_nand_init() which is called before any device probe + (nand_scan_ident + nand_scan_tail), thus device's ONFI parameters are + not available while configuring controller. So a static CONFIG_NAND_xx + is needed to know the device's bus-width in advance. + +if SPL + +config SYS_NAND_U_BOOT_LOCATIONS + bool "Define U-boot binaries locations in NAND" + help + Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig. + This option should not be enabled when compiling U-boot for boards + defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/.h + file. + +config SYS_NAND_U_BOOT_OFFS + hex "Location in NAND to read U-Boot from" + default 0x800000 if NAND_SUNXI + depends on SYS_NAND_U_BOOT_LOCATIONS + help + Set the offset from the start of the nand where u-boot should be + loaded from. + +config SYS_NAND_U_BOOT_OFFS_REDUND + hex "Location in NAND to read U-Boot from" + default SYS_NAND_U_BOOT_OFFS + depends on SYS_NAND_U_BOOT_LOCATIONS + help + Set the offset from the start of the nand where the redundant u-boot + should be loaded from. + +config SPL_NAND_AM33XX_BCH + bool "Enables SPL-NAND driver which supports ELM based" + depends on NAND_OMAP_GPMC && !OMAP34XX + default y + help + Hardware ECC correction. This is useful for platforms which have ELM + hardware engine and use NAND boot mode. + Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine, + so those platforms should use CONFIG_SPL_NAND_SIMPLE for enabling + SPL-NAND driver with software ECC correction support. + +config SPL_NAND_DENALI + bool "Support Denali NAND controller for SPL" + help + This is a small implementation of the Denali NAND controller + for use on SPL. + +config SPL_NAND_SIMPLE + bool "Use simple SPL NAND driver" + depends on !SPL_NAND_AM33XX_BCH + help + Support for NAND boot using simple NAND drivers that + expose the cmd_ctrl() interface. +endif + +endif # if NAND diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile new file mode 100644 index 0000000000..c61e3f3839 --- /dev/null +++ b/drivers/mtd/nand/raw/Makefile @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. + +ifdef CONFIG_SPL_BUILD + +ifdef CONFIG_SPL_NAND_DRIVERS +NORMAL_DRIVERS=y +endif + +obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o +obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o +obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o +obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o +obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o +obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o +obj-$(CONFIG_SPL_NAND_IDENT) += nand_ids.o nand_timings.o +obj-$(CONFIG_SPL_NAND_INIT) += nand.o +ifeq ($(CONFIG_SPL_ENV_SUPPORT),y) +obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o +endif + +else # not spl + +NORMAL_DRIVERS=y + +obj-y += nand.o +obj-y += nand_bbt.o +obj-y += nand_ids.o +obj-y += nand_util.o +obj-y += nand_ecc.o +obj-y += nand_base.o +obj-y += nand_timings.o + +endif # not spl + +ifdef NORMAL_DRIVERS + +obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o + +obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o +obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o +obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o +obj-$(CONFIG_NAND_DENALI) += denali.o +obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o +obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o +obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o +obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o +obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o +obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o +obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o +obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o +obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o +obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o +obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o +obj-$(CONFIG_NAND_MXC) += mxc_nand.o +obj-$(CONFIG_NAND_MXS) += mxs_nand.o +obj-$(CONFIG_NAND_MXS_DT) += mxs_nand_dt.o +obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o +obj-$(CONFIG_NAND_SPEAR) += spr_nand.o +obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o +obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o +obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o +obj-$(CONFIG_NAND_PLAT) += nand_plat.o +obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o +obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o + +else # minimal SPL drivers + +obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o +obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o +obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o +obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o +obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o + +endif # drivers diff --git a/drivers/mtd/nand/raw/am335x_spl_bch.c b/drivers/mtd/nand/raw/am335x_spl_bch.c new file mode 100644 index 0000000000..ba2f33a96e --- /dev/null +++ b/drivers/mtd/nand/raw/am335x_spl_bch.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2012 + * Konstantin Kozhevnikov, Cogent Embedded + * + * based on nand_spl_simple code + * + * (C) Copyright 2006-2008 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + */ + +#include +#include +#include +#include + +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; +static struct mtd_info *mtd; +static struct nand_chip nand_chip; + +#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ + CONFIG_SYS_NAND_ECCSIZE) +#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) + + +/* + * NAND command for large page NAND devices (2k) + */ +static int nand_command(int block, int page, uint32_t offs, + u8 cmd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; + void (*hwctrl)(struct mtd_info *mtd, int cmd, + unsigned int ctrl) = this->cmd_ctrl; + + while (!this->dev_ready(mtd)) + ; + + /* Emulate NAND_CMD_READOOB */ + if (cmd == NAND_CMD_READOOB) { + offs += CONFIG_SYS_NAND_PAGE_SIZE; + cmd = NAND_CMD_READ0; + } + + /* Begin command latch cycle */ + hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + + if (cmd == NAND_CMD_RESET) { + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Apply this short delay always to ensure that we do wait + * tWB in any case on any machine. + */ + ndelay(150); + + while (!this->dev_ready(mtd)) + ; + return 0; + } + + /* Shift the offset from byte addressing to word addressing. */ + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) + offs >>= 1; + + /* Set ALE and clear CLE to start address cycle */ + /* Column address */ + hwctrl(mtd, offs & 0xff, + NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ + hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */ + /* Row address */ + if (cmd != NAND_CMD_RNDOUT) { + hwctrl(mtd, (page_addr & 0xff), + NAND_CTRL_ALE); /* A[19:12] */ + hwctrl(mtd, ((page_addr >> 8) & 0xff), + NAND_CTRL_ALE); /* A[27:20] */ +#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE + /* One more address cycle for devices > 128MiB */ + hwctrl(mtd, (page_addr >> 16) & 0x0f, + NAND_CTRL_ALE); /* A[31:28] */ +#endif + } + + hwctrl(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 (cmd) { + case NAND_CMD_CACHEDPROG: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_RNDIN: + case NAND_CMD_STATUS: + return 0; + + case NAND_CMD_RNDOUT: + /* No ready / busy check necessary */ + hwctrl(mtd, NAND_CMD_RNDOUTSTART, NAND_CTRL_CLE | + NAND_CTRL_CHANGE); + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + return 0; + + case NAND_CMD_READ0: + /* Latch in address */ + hwctrl(mtd, NAND_CMD_READSTART, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + } + + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(150); + + while (!this->dev_ready(mtd)) + ; + + return 0; +} + +static int nand_is_bad_block(int block) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, + NAND_CMD_READOOB); + + /* + * Read one byte (or two if it's a 16 bit chip). + */ + if (this->options & NAND_BUSWIDTH_16) { + if (readw(this->IO_ADDR_R) != 0xffff) + return 1; + } else { + if (readb(this->IO_ADDR_R) != 0xff) + return 1; + } + + return 0; +} + +static int nand_read_page(int block, int page, void *dst) +{ + struct nand_chip *this = mtd_to_nand(mtd); + u_char ecc_calc[ECCTOTAL]; + u_char ecc_code[ECCTOTAL]; + u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; + int i; + int eccsize = CONFIG_SYS_NAND_ECCSIZE; + int eccbytes = CONFIG_SYS_NAND_ECCBYTES; + int eccsteps = ECCSTEPS; + uint8_t *p = dst; + uint32_t data_pos = 0; + uint8_t *oob = &oob_data[0] + nand_ecc_pos[0]; + uint32_t oob_pos = eccsize * eccsteps + nand_ecc_pos[0]; + + nand_command(block, page, 0, NAND_CMD_READ0); + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + this->ecc.hwctl(mtd, NAND_ECC_READ); + nand_command(block, page, data_pos, NAND_CMD_RNDOUT); + + this->read_buf(mtd, p, eccsize); + + nand_command(block, page, oob_pos, NAND_CMD_RNDOUT); + + this->read_buf(mtd, oob, eccbytes); + this->ecc.calculate(mtd, p, &ecc_calc[i]); + + data_pos += eccsize; + oob_pos += eccbytes; + oob += eccbytes; + } + + /* Pick the ECC bytes out of the oob data */ + for (i = 0; i < ECCTOTAL; i++) + ecc_code[i] = oob_data[nand_ecc_pos[i]]; + + eccsteps = ECCSTEPS; + p = dst; + + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + /* No chance to do something with the possible error message + * from correct_data(). We just hope that all possible errors + * are corrected by this routine. + */ + this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + } + + return 0; +} + +/* nand_init() - initialize data to make nand usable by SPL */ +void nand_init(void) +{ + /* + * Init board specific nand support + */ + mtd = nand_to_mtd(&nand_chip); + nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = + (void __iomem *)CONFIG_SYS_NAND_BASE; + board_nand_init(&nand_chip); + + if (nand_chip.select_chip) + nand_chip.select_chip(mtd, 0); + + /* NAND chip may require reset after power-on */ + nand_command(0, 0, 0, NAND_CMD_RESET); +} + +/* Unselect after operation */ +void nand_deselect(void) +{ + if (nand_chip.select_chip) + nand_chip.select_chip(mtd, -1); +} + +#include "nand_spl_loaders.c" diff --git a/drivers/mtd/nand/raw/arasan_nfc.c b/drivers/mtd/nand/raw/arasan_nfc.c new file mode 100644 index 0000000000..41db9f8bb9 --- /dev/null +++ b/drivers/mtd/nand/raw/arasan_nfc.c @@ -0,0 +1,1270 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Arasan NAND Flash Controller Driver + * + * Copyright (C) 2014 - 2015 Xilinx, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct arasan_nand_info { + void __iomem *nand_base; + u32 page; + bool on_die_ecc_enabled; +}; + +struct nand_regs { + u32 pkt_reg; + u32 memadr_reg1; + u32 memadr_reg2; + u32 cmd_reg; + u32 pgm_reg; + u32 intsts_enr; + u32 intsig_enr; + u32 intsts_reg; + u32 rdy_busy; + u32 cms_sysadr_reg; + u32 flash_sts_reg; + u32 tmg_reg; + u32 buf_dataport; + u32 ecc_reg; + u32 ecc_errcnt_reg; + u32 ecc_sprcmd_reg; + u32 errcnt_1bitreg; + u32 errcnt_2bitreg; + u32 errcnt_3bitreg; + u32 errcnt_4bitreg; + u32 dma_sysadr0_reg; + u32 dma_bufbdry_reg; + u32 cpu_rls_reg; + u32 errcnt_5bitreg; + u32 errcnt_6bitreg; + u32 errcnt_7bitreg; + u32 errcnt_8bitreg; + u32 data_if_reg; +}; + +#define arasan_nand_base ((struct nand_regs __iomem *)ARASAN_NAND_BASEADDR) + +struct arasan_nand_command_format { + u8 cmd1; + u8 cmd2; + u8 addr_cycles; + u32 pgm; +}; + +#define ONDIE_ECC_FEATURE_ADDR 0x90 +#define ENABLE_ONDIE_ECC 0x08 + +#define ARASAN_PROG_RD_MASK 0x00000001 +#define ARASAN_PROG_BLK_ERS_MASK 0x00000004 +#define ARASAN_PROG_RD_ID_MASK 0x00000040 +#define ARASAN_PROG_RD_STS_MASK 0x00000008 +#define ARASAN_PROG_PG_PROG_MASK 0x00000010 +#define ARASAN_PROG_RD_PARAM_PG_MASK 0x00000080 +#define ARASAN_PROG_RST_MASK 0x00000100 +#define ARASAN_PROG_GET_FTRS_MASK 0x00000200 +#define ARASAN_PROG_SET_FTRS_MASK 0x00000400 +#define ARASAN_PROG_CHNG_ROWADR_END_MASK 0x00400000 + +#define ARASAN_NAND_CMD_ECC_ON_MASK 0x80000000 +#define ARASAN_NAND_CMD_CMD12_MASK 0xFFFF +#define ARASAN_NAND_CMD_PG_SIZE_MASK 0x3800000 +#define ARASAN_NAND_CMD_PG_SIZE_SHIFT 23 +#define ARASAN_NAND_CMD_CMD2_SHIFT 8 +#define ARASAN_NAND_CMD_ADDR_CYCL_MASK 0x70000000 +#define ARASAN_NAND_CMD_ADDR_CYCL_SHIFT 28 + +#define ARASAN_NAND_MEM_ADDR1_PAGE_MASK 0xFFFF0000 +#define ARASAN_NAND_MEM_ADDR1_COL_MASK 0xFFFF +#define ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT 16 +#define ARASAN_NAND_MEM_ADDR2_PAGE_MASK 0xFF +#define ARASAN_NAND_MEM_ADDR2_CS_MASK 0xC0000000 +#define ARASAN_NAND_MEM_ADDR2_BCH_MASK 0xE000000 +#define ARASAN_NAND_MEM_ADDR2_BCH_SHIFT 25 + +#define ARASAN_NAND_INT_STS_ERR_EN_MASK 0x10 +#define ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK 0x08 +#define ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK 0x02 +#define ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK 0x01 +#define ARASAN_NAND_INT_STS_XFR_CMPLT_MASK 0x04 + +#define ARASAN_NAND_PKT_REG_PKT_CNT_MASK 0xFFF000 +#define ARASAN_NAND_PKT_REG_PKT_SIZE_MASK 0x7FF +#define ARASAN_NAND_PKT_REG_PKT_CNT_SHFT 12 + +#define ARASAN_NAND_ROW_ADDR_CYCL_MASK 0x0F +#define ARASAN_NAND_COL_ADDR_CYCL_MASK 0xF0 +#define ARASAN_NAND_COL_ADDR_CYCL_SHIFT 4 + +#define ARASAN_NAND_ECC_SIZE_SHIFT 16 +#define ARASAN_NAND_ECC_BCH_SHIFT 27 + +#define ARASAN_NAND_PKTSIZE_1K 1024 +#define ARASAN_NAND_PKTSIZE_512 512 + +#define ARASAN_NAND_POLL_TIMEOUT 1000000 +#define ARASAN_NAND_INVALID_ADDR_CYCL 0xFF + +#define ERR_ADDR_CYCLE -1 +#define READ_BUFF_SIZE 0x4000 + +static struct arasan_nand_command_format *curr_cmd; + +enum addr_cycles { + NAND_ADDR_CYCL_NONE, + NAND_ADDR_CYCL_ONE, + NAND_ADDR_CYCL_ROW, + NAND_ADDR_CYCL_COL, + NAND_ADDR_CYCL_BOTH, +}; + +static struct arasan_nand_command_format arasan_nand_commands[] = { + {NAND_CMD_READ0, NAND_CMD_READSTART, NAND_ADDR_CYCL_BOTH, + ARASAN_PROG_RD_MASK}, + {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, NAND_ADDR_CYCL_COL, + ARASAN_PROG_RD_MASK}, + {NAND_CMD_READID, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, + ARASAN_PROG_RD_ID_MASK}, + {NAND_CMD_STATUS, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, + ARASAN_PROG_RD_STS_MASK}, + {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_ADDR_CYCL_BOTH, + ARASAN_PROG_PG_PROG_MASK}, + {NAND_CMD_RNDIN, NAND_CMD_NONE, NAND_ADDR_CYCL_COL, + ARASAN_PROG_CHNG_ROWADR_END_MASK}, + {NAND_CMD_ERASE1, NAND_CMD_ERASE2, NAND_ADDR_CYCL_ROW, + ARASAN_PROG_BLK_ERS_MASK}, + {NAND_CMD_RESET, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, + ARASAN_PROG_RST_MASK}, + {NAND_CMD_PARAM, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, + ARASAN_PROG_RD_PARAM_PG_MASK}, + {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, + ARASAN_PROG_GET_FTRS_MASK}, + {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, + ARASAN_PROG_SET_FTRS_MASK}, + {NAND_CMD_NONE, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, 0}, +}; + +struct arasan_ecc_matrix { + u32 pagesize; + u32 ecc_codeword_size; + u8 eccbits; + u8 bch; + u8 bchval; + u16 eccaddr; + u16 eccsize; +}; + +static const struct arasan_ecc_matrix ecc_matrix[] = { + {512, 512, 1, 0, 0, 0x20D, 0x3}, + {512, 512, 4, 1, 3, 0x209, 0x7}, + {512, 512, 8, 1, 2, 0x203, 0xD}, + /* + * 2K byte page + */ + {2048, 512, 1, 0, 0, 0x834, 0xC}, + {2048, 512, 4, 1, 3, 0x826, 0x1A}, + {2048, 512, 8, 1, 2, 0x80c, 0x34}, + {2048, 512, 12, 1, 1, 0x822, 0x4E}, + {2048, 512, 16, 1, 0, 0x808, 0x68}, + {2048, 1024, 24, 1, 4, 0x81c, 0x54}, + /* + * 4K byte page + */ + {4096, 512, 1, 0, 0, 0x1068, 0x18}, + {4096, 512, 4, 1, 3, 0x104c, 0x34}, + {4096, 512, 8, 1, 2, 0x1018, 0x68}, + {4096, 512, 12, 1, 1, 0x1044, 0x9C}, + {4096, 512, 16, 1, 0, 0x1010, 0xD0}, + {4096, 1024, 24, 1, 4, 0x1038, 0xA8}, + /* + * 8K byte page + */ + {8192, 512, 1, 0, 0, 0x20d0, 0x30}, + {8192, 512, 4, 1, 3, 0x2098, 0x68}, + {8192, 512, 8, 1, 2, 0x2030, 0xD0}, + {8192, 512, 12, 1, 1, 0x2088, 0x138}, + {8192, 512, 16, 1, 0, 0x2020, 0x1A0}, + {8192, 1024, 24, 1, 4, 0x2070, 0x150}, + /* + * 16K byte page + */ + {16384, 512, 1, 0, 0, 0x4460, 0x60}, + {16384, 512, 4, 1, 3, 0x43f0, 0xD0}, + {16384, 512, 8, 1, 2, 0x4320, 0x1A0}, + {16384, 512, 12, 1, 1, 0x4250, 0x270}, + {16384, 512, 16, 1, 0, 0x4180, 0x340}, + {16384, 1024, 24, 1, 4, 0x4220, 0x2A0} +}; + +static struct nand_ecclayout ondie_nand_oob_64 = { + .eccbytes = 32, + + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 24, 25, 26, 27, 28, 29, 30, 31, + 40, 41, 42, 43, 44, 45, 46, 47, + 56, 57, 58, 59, 60, 61, 62, 63 + }, + + .oobfree = { + { .offset = 4, .length = 4 }, + { .offset = 20, .length = 4 }, + { .offset = 36, .length = 4 }, + { .offset = 52, .length = 4 } + } +}; + +/* + * bbt decriptors for chips with on-die ECC and + * chips with 64-byte OOB + */ +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = mirror_pattern +}; + +static u8 buf_data[READ_BUFF_SIZE]; +static u32 buf_index; + +static struct nand_ecclayout nand_oob; + +static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; + +static void arasan_nand_select_chip(struct mtd_info *mtd, int chip) +{ +} + +static void arasan_nand_enable_ecc(void) +{ + u32 reg_val; + + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val |= ARASAN_NAND_CMD_ECC_ON_MASK; + + writel(reg_val, &arasan_nand_base->cmd_reg); +} + +static u8 arasan_nand_get_addrcycle(struct mtd_info *mtd) +{ + u8 addrcycles; + struct nand_chip *chip = mtd_to_nand(mtd); + + switch (curr_cmd->addr_cycles) { + case NAND_ADDR_CYCL_NONE: + addrcycles = 0; + break; + case NAND_ADDR_CYCL_ONE: + addrcycles = 1; + break; + case NAND_ADDR_CYCL_ROW: + addrcycles = chip->onfi_params.addr_cycles & + ARASAN_NAND_ROW_ADDR_CYCL_MASK; + break; + case NAND_ADDR_CYCL_COL: + addrcycles = (chip->onfi_params.addr_cycles & + ARASAN_NAND_COL_ADDR_CYCL_MASK) >> + ARASAN_NAND_COL_ADDR_CYCL_SHIFT; + break; + case NAND_ADDR_CYCL_BOTH: + addrcycles = chip->onfi_params.addr_cycles & + ARASAN_NAND_ROW_ADDR_CYCL_MASK; + addrcycles += (chip->onfi_params.addr_cycles & + ARASAN_NAND_COL_ADDR_CYCL_MASK) >> + ARASAN_NAND_COL_ADDR_CYCL_SHIFT; + break; + default: + addrcycles = ARASAN_NAND_INVALID_ADDR_CYCL; + break; + } + return addrcycles; +} + +static int arasan_nand_read_page(struct mtd_info *mtd, u8 *buf, u32 size) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct arasan_nand_info *nand = nand_get_controller_data(chip); + u32 reg_val, i, pktsize, pktnum; + u32 *bufptr = (u32 *)buf; + u32 timeout; + u32 rdcount = 0; + u8 addr_cycles; + + if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K) + pktsize = ARASAN_NAND_PKTSIZE_1K; + else + pktsize = ARASAN_NAND_PKTSIZE_512; + + if (size % pktsize) + pktnum = size/pktsize + 1; + else + pktnum = size/pktsize; + + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_ERR_EN_MASK | + ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | + pktsize; + writel(reg_val, &arasan_nand_base->pkt_reg); + + if (!nand->on_die_ecc_enabled) { + arasan_nand_enable_ecc(); + addr_cycles = arasan_nand_get_addrcycle(mtd); + if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + writel((NAND_CMD_RNDOUTSTART << ARASAN_NAND_CMD_CMD2_SHIFT) | + NAND_CMD_RNDOUT | (addr_cycles << + ARASAN_NAND_CMD_ADDR_CYCL_SHIFT), + &arasan_nand_base->ecc_sprcmd_reg); + } + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (rdcount < pktnum) { + timeout = ARASAN_NAND_POLL_TIMEOUT; + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + puts("arasan_read_page: timedout:Buff RDY\n"); + return -ETIMEDOUT; + } + + rdcount++; + + if (pktnum == rdcount) { + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + } else { + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_enr); + } + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_reg); + + for (i = 0; i < pktsize/4; i++) + bufptr[i] = readl(&arasan_nand_base->buf_dataport); + + + bufptr += pktsize/4; + + if (rdcount >= pktnum) + break; + + writel(ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_enr); + } + + timeout = ARASAN_NAND_POLL_TIMEOUT; + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + puts("arasan rd_page timedout:Xfer CMPLT\n"); + return -ETIMEDOUT; + } + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + if (!nand->on_die_ecc_enabled) { + if (readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK) { + printf("arasan rd_page:sbiterror\n"); + return -1; + } + + if (readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_ERR_EN_MASK) { + mtd->ecc_stats.failed++; + printf("arasan rd_page:multibiterror\n"); + return -1; + } + } + + return 0; +} + +static int arasan_nand_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, u8 *buf, int oob_required, int page) +{ + int status; + + status = arasan_nand_read_page(mtd, buf, (mtd->writesize)); + + if (oob_required) + chip->ecc.read_oob(mtd, chip, page); + + return status; +} + +static void arasan_nand_fill_tx(const u8 *buf, int len) +{ + u32 __iomem *nand = &arasan_nand_base->buf_dataport; + + if (((unsigned long)buf & 0x3) != 0) { + if (((unsigned long)buf & 0x1) != 0) { + if (len) { + writeb(*buf, nand); + buf += 1; + len--; + } + } + + if (((unsigned long)buf & 0x3) != 0) { + if (len >= 2) { + writew(*(u16 *)buf, nand); + buf += 2; + len -= 2; + } + } + } + + while (len >= 4) { + writel(*(u32 *)buf, nand); + buf += 4; + len -= 4; + } + + if (len) { + if (len >= 2) { + writew(*(u16 *)buf, nand); + buf += 2; + len -= 2; + } + + if (len) + writeb(*buf, nand); + } +} + +static int arasan_nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const u8 *buf, int oob_required, + int page) +{ + u32 reg_val, i, pktsize, pktnum; + const u32 *bufptr = (const u32 *)buf; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + u32 size = mtd->writesize; + u32 rdcount = 0; + u8 column_addr_cycles; + struct arasan_nand_info *nand = nand_get_controller_data(chip); + + if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K) + pktsize = ARASAN_NAND_PKTSIZE_1K; + else + pktsize = ARASAN_NAND_PKTSIZE_512; + + if (size % pktsize) + pktnum = size/pktsize + 1; + else + pktnum = size/pktsize; + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | pktsize; + writel(reg_val, &arasan_nand_base->pkt_reg); + + if (!nand->on_die_ecc_enabled) { + arasan_nand_enable_ecc(); + column_addr_cycles = (chip->onfi_params.addr_cycles & + ARASAN_NAND_COL_ADDR_CYCL_MASK) >> + ARASAN_NAND_COL_ADDR_CYCL_SHIFT; + writel((NAND_CMD_RNDIN | (column_addr_cycles << 28)), + &arasan_nand_base->ecc_sprcmd_reg); + } + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (rdcount < pktnum) { + timeout = ARASAN_NAND_POLL_TIMEOUT; + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) { + puts("arasan_write_page: timedout:Buff RDY\n"); + return -ETIMEDOUT; + } + + rdcount++; + + if (pktnum == rdcount) { + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + } else { + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_enr); + } + + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_reg); + + for (i = 0; i < pktsize/4; i++) + writel(bufptr[i], &arasan_nand_base->buf_dataport); + + bufptr += pktsize/4; + + if (rdcount >= pktnum) + break; + + writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_enr); + } + + timeout = ARASAN_NAND_POLL_TIMEOUT; + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + puts("arasan write_page timedout:Xfer CMPLT\n"); + return -ETIMEDOUT; + } + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + if (oob_required) + chip->ecc.write_oob(mtd, chip, nand->page); + + return 0; +} + +static int arasan_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, (mtd->oobsize)); + + return 0; +} + +static int arasan_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + int status = 0; + const u8 *buf = chip->oob_poi; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + chip->write_buf(mtd, buf, mtd->oobsize); + + return status; +} + +static int arasan_nand_reset(struct arasan_nand_command_format *curr_cmd) +{ + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + u32 cmd_reg = 0; + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + cmd_reg = readl(&arasan_nand_base->cmd_reg); + cmd_reg &= ~ARASAN_NAND_CMD_CMD12_MASK; + + cmd_reg |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + writel(cmd_reg, &arasan_nand_base->cmd_reg); + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + printf("ERROR:%s timedout\n", __func__); + return -ETIMEDOUT; + } + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + return 0; +} + +static u8 arasan_nand_page(struct mtd_info *mtd) +{ + u8 page_val = 0; + + switch (mtd->writesize) { + case 512: + page_val = 0; + break; + case 2048: + page_val = 1; + break; + case 4096: + page_val = 2; + break; + case 8192: + page_val = 3; + break; + case 16384: + page_val = 4; + break; + case 1024: + page_val = 5; + break; + default: + printf("%s:Pagesize>16K\n", __func__); + break; + } + + return page_val; +} + +static int arasan_nand_send_wrcmd(struct arasan_nand_command_format *curr_cmd, + int column, int page_addr, struct mtd_info *mtd) +{ + u32 reg_val, page; + u8 page_val, addr_cycles; + + writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; + reg_val |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + if (curr_cmd->cmd1 == NAND_CMD_SEQIN) { + reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK; + page_val = arasan_nand_page(mtd); + reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT); + } + + reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; + addr_cycles = arasan_nand_get_addrcycle(mtd); + + if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + reg_val |= (addr_cycles << + ARASAN_NAND_CMD_ADDR_CYCL_SHIFT); + writel(reg_val, &arasan_nand_base->cmd_reg); + + if (page_addr == -1) + page_addr = 0; + + page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) & + ARASAN_NAND_MEM_ADDR1_PAGE_MASK; + column &= ARASAN_NAND_MEM_ADDR1_COL_MASK; + writel(page|column, &arasan_nand_base->memadr_reg1); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK; + reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT); + writel(reg_val, &arasan_nand_base->memadr_reg2); + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; + writel(reg_val, &arasan_nand_base->memadr_reg2); + + return 0; +} + +static void arasan_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + u32 reg_val; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + + reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | len; + writel(reg_val, &arasan_nand_base->pkt_reg); + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) + puts("ERROR:arasan_nand_write_buf timedout:Buff RDY\n"); + + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_reg); + + arasan_nand_fill_tx(buf, len); + + timeout = ARASAN_NAND_POLL_TIMEOUT; + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) + puts("ERROR:arasan_nand_write_buf timedout:Xfer CMPLT\n"); + + writel(readl(&arasan_nand_base->intsts_enr) | + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + writel(readl(&arasan_nand_base->intsts_reg) | + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); +} + +static int arasan_nand_erase(struct arasan_nand_command_format *curr_cmd, + int column, int page_addr, struct mtd_info *mtd) +{ + u32 reg_val, page; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + u8 row_addr_cycles; + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; + reg_val |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + row_addr_cycles = arasan_nand_get_addrcycle(mtd); + + if (row_addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; + reg_val |= (row_addr_cycles << + ARASAN_NAND_CMD_ADDR_CYCL_SHIFT); + + writel(reg_val, &arasan_nand_base->cmd_reg); + + page = (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) & + ARASAN_NAND_MEM_ADDR1_COL_MASK; + column = page_addr & ARASAN_NAND_MEM_ADDR1_COL_MASK; + writel(column | (page << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT), + &arasan_nand_base->memadr_reg1); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK; + reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT); + writel(reg_val, &arasan_nand_base->memadr_reg2); + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; + writel(reg_val, &arasan_nand_base->memadr_reg2); + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + printf("ERROR:%s timedout:Xfer CMPLT\n", __func__); + return -ETIMEDOUT; + } + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + return 0; +} + +static int arasan_nand_read_status(struct arasan_nand_command_format *curr_cmd, + int column, int page_addr, struct mtd_info *mtd) +{ + u32 reg_val; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + u8 addr_cycles; + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; + reg_val |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + addr_cycles = arasan_nand_get_addrcycle(mtd); + + if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; + reg_val |= (addr_cycles << + ARASAN_NAND_CMD_ADDR_CYCL_SHIFT); + + writel(reg_val, &arasan_nand_base->cmd_reg); + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | 1; + writel(reg_val, &arasan_nand_base->pkt_reg); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; + writel(reg_val, &arasan_nand_base->memadr_reg2); + + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) { + printf("ERROR:%s: timedout:Xfer CMPLT\n", __func__); + return -ETIMEDOUT; + } + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + return 0; +} + +static int arasan_nand_send_rdcmd(struct arasan_nand_command_format *curr_cmd, + int column, int page_addr, struct mtd_info *mtd) +{ + u32 reg_val, addr_cycles, page; + u8 page_val; + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_enr); + + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; + reg_val |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + + if (curr_cmd->cmd1 == NAND_CMD_RNDOUT || + curr_cmd->cmd1 == NAND_CMD_READ0) { + reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK; + page_val = arasan_nand_page(mtd); + reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT); + } + + reg_val &= ~ARASAN_NAND_CMD_ECC_ON_MASK; + + reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; + + addr_cycles = arasan_nand_get_addrcycle(mtd); + + if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + reg_val |= (addr_cycles << 28); + writel(reg_val, &arasan_nand_base->cmd_reg); + + if (page_addr == -1) + page_addr = 0; + + page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) & + ARASAN_NAND_MEM_ADDR1_PAGE_MASK; + column &= ARASAN_NAND_MEM_ADDR1_COL_MASK; + writel(page | column, &arasan_nand_base->memadr_reg1); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK; + reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT); + writel(reg_val, &arasan_nand_base->memadr_reg2); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; + writel(reg_val, &arasan_nand_base->memadr_reg2); + buf_index = 0; + + return 0; +} + +static void arasan_nand_read_buf(struct mtd_info *mtd, u8 *buf, int size) +{ + u32 reg_val, i; + u32 *bufptr = (u32 *)buf; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | size; + writel(reg_val, &arasan_nand_base->pkt_reg); + + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) + puts("ERROR:arasan_nand_read_buf timedout:Buff RDY\n"); + + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_reg); + + buf_index = 0; + for (i = 0; i < size / 4; i++) + bufptr[i] = readl(&arasan_nand_base->buf_dataport); + + if (size & 0x03) + bufptr[i] = readl(&arasan_nand_base->buf_dataport); + + timeout = ARASAN_NAND_POLL_TIMEOUT; + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) + puts("ERROR:arasan_nand_read_buf timedout:Xfer CMPLT\n"); + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); +} + +static u8 arasan_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + u32 size; + u8 val; + struct nand_onfi_params *p; + + if (buf_index == 0) { + p = &chip->onfi_params; + if (curr_cmd->cmd1 == NAND_CMD_READID) + size = 4; + else if (curr_cmd->cmd1 == NAND_CMD_PARAM) + size = sizeof(struct nand_onfi_params); + else if (curr_cmd->cmd1 == NAND_CMD_RNDOUT) + size = le16_to_cpu(p->ext_param_page_length) * 16; + else if (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) + size = 4; + else if (curr_cmd->cmd1 == NAND_CMD_STATUS) + return readb(&arasan_nand_base->flash_sts_reg); + else + size = 8; + chip->read_buf(mtd, &buf_data[0], size); + } + + val = *(&buf_data[0] + buf_index); + buf_index++; + + return val; +} + +static void arasan_nand_cmd_function(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + u32 i, ret = 0; + struct nand_chip *chip = mtd_to_nand(mtd); + struct arasan_nand_info *nand = nand_get_controller_data(chip); + + curr_cmd = NULL; + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + + if ((command == NAND_CMD_READOOB) && + (mtd->writesize > 512)) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Get the command format */ + for (i = 0; (arasan_nand_commands[i].cmd1 != NAND_CMD_NONE || + arasan_nand_commands[i].cmd2 != NAND_CMD_NONE); i++) { + if (command == arasan_nand_commands[i].cmd1) { + curr_cmd = &arasan_nand_commands[i]; + break; + } + } + + if (curr_cmd == NULL) { + printf("Unsupported Command; 0x%x\n", command); + return; + } + + if (curr_cmd->cmd1 == NAND_CMD_RESET) + ret = arasan_nand_reset(curr_cmd); + + if ((curr_cmd->cmd1 == NAND_CMD_READID) || + (curr_cmd->cmd1 == NAND_CMD_PARAM) || + (curr_cmd->cmd1 == NAND_CMD_RNDOUT) || + (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) || + (curr_cmd->cmd1 == NAND_CMD_READ0)) + ret = arasan_nand_send_rdcmd(curr_cmd, column, page_addr, mtd); + + if ((curr_cmd->cmd1 == NAND_CMD_SET_FEATURES) || + (curr_cmd->cmd1 == NAND_CMD_SEQIN)) { + nand->page = page_addr; + ret = arasan_nand_send_wrcmd(curr_cmd, column, page_addr, mtd); + } + + if (curr_cmd->cmd1 == NAND_CMD_ERASE1) + ret = arasan_nand_erase(curr_cmd, column, page_addr, mtd); + + if (curr_cmd->cmd1 == NAND_CMD_STATUS) + ret = arasan_nand_read_status(curr_cmd, column, page_addr, mtd); + + if (ret != 0) + printf("ERROR:%s:command:0x%x\n", __func__, curr_cmd->cmd1); +} + +static void arasan_check_ondie(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct arasan_nand_info *nand = nand_get_controller_data(nand_chip); + u8 maf_id, dev_id; + u8 get_feature[4]; + u8 set_feature[4] = {ENABLE_ONDIE_ECC, 0x00, 0x00, 0x00}; + u32 i; + + /* Send the command for reading device ID */ + nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0, -1); + + /* Read manufacturer and device IDs */ + maf_id = nand_chip->read_byte(mtd); + dev_id = nand_chip->read_byte(mtd); + + if ((maf_id == NAND_MFR_MICRON) && + ((dev_id == 0xf1) || (dev_id == 0xa1) || (dev_id == 0xb1) || + (dev_id == 0xaa) || (dev_id == 0xba) || (dev_id == 0xda) || + (dev_id == 0xca) || (dev_id == 0xac) || (dev_id == 0xbc) || + (dev_id == 0xdc) || (dev_id == 0xcc) || (dev_id == 0xa3) || + (dev_id == 0xb3) || (dev_id == 0xd3) || (dev_id == 0xc3))) { + nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + + nand_chip->write_buf(mtd, &set_feature[0], 4); + nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + + for (i = 0; i < 4; i++) + get_feature[i] = nand_chip->read_byte(mtd); + + if (get_feature[0] & ENABLE_ONDIE_ECC) + nand->on_die_ecc_enabled = true; + else + printf("%s: Unable to enable OnDie ECC\n", __func__); + + /* Use the BBT pattern descriptors */ + nand_chip->bbt_td = &bbt_main_descr; + nand_chip->bbt_md = &bbt_mirror_descr; + } +} + +static int arasan_nand_ecc_init(struct mtd_info *mtd) +{ + int found = -1; + u32 regval, eccpos_start, i, eccaddr; + struct nand_chip *nand_chip = mtd_to_nand(mtd); + + for (i = 0; i < ARRAY_SIZE(ecc_matrix); i++) { + if ((ecc_matrix[i].pagesize == mtd->writesize) && + (ecc_matrix[i].ecc_codeword_size >= + nand_chip->ecc_step_ds)) { + if (ecc_matrix[i].eccbits >= + nand_chip->ecc_strength_ds) { + found = i; + break; + } + found = i; + } + } + + if (found < 0) + return 1; + + eccaddr = mtd->writesize + mtd->oobsize - + ecc_matrix[found].eccsize; + + regval = eccaddr | + (ecc_matrix[found].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) | + (ecc_matrix[found].bch << ARASAN_NAND_ECC_BCH_SHIFT); + writel(regval, &arasan_nand_base->ecc_reg); + + if (ecc_matrix[found].bch) { + regval = readl(&arasan_nand_base->memadr_reg2); + regval &= ~ARASAN_NAND_MEM_ADDR2_BCH_MASK; + regval |= (ecc_matrix[found].bchval << + ARASAN_NAND_MEM_ADDR2_BCH_SHIFT); + writel(regval, &arasan_nand_base->memadr_reg2); + } + + nand_oob.eccbytes = ecc_matrix[found].eccsize; + eccpos_start = mtd->oobsize - nand_oob.eccbytes; + + for (i = 0; i < nand_oob.eccbytes; i++) + nand_oob.eccpos[i] = eccpos_start + i; + + nand_oob.oobfree[0].offset = 2; + nand_oob.oobfree[0].length = eccpos_start - 2; + + nand_chip->ecc.size = ecc_matrix[found].ecc_codeword_size; + nand_chip->ecc.strength = ecc_matrix[found].eccbits; + nand_chip->ecc.bytes = ecc_matrix[found].eccsize; + nand_chip->ecc.layout = &nand_oob; + + return 0; +} + +static int arasan_nand_init(struct nand_chip *nand_chip, int devnum) +{ + struct arasan_nand_info *nand; + struct mtd_info *mtd; + int err = -1; + + nand = calloc(1, sizeof(struct arasan_nand_info)); + if (!nand) { + printf("%s: failed to allocate\n", __func__); + return err; + } + + nand->nand_base = arasan_nand_base; + mtd = nand_to_mtd(nand_chip); + nand_set_controller_data(nand_chip, nand); + + /* Set the driver entry points for MTD */ + nand_chip->cmdfunc = arasan_nand_cmd_function; + nand_chip->select_chip = arasan_nand_select_chip; + nand_chip->read_byte = arasan_nand_read_byte; + + /* Buffer read/write routines */ + nand_chip->read_buf = arasan_nand_read_buf; + nand_chip->write_buf = arasan_nand_write_buf; + nand_chip->bbt_options = NAND_BBT_USE_FLASH; + + writel(0x0, &arasan_nand_base->cmd_reg); + writel(0x0, &arasan_nand_base->pgm_reg); + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1, NULL)) { + printf("%s: nand_scan_ident failed\n", __func__); + goto fail; + } + + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.hwctl = NULL; + nand_chip->ecc.read_page = arasan_nand_read_page_hwecc; + nand_chip->ecc.write_page = arasan_nand_write_page_hwecc; + nand_chip->ecc.read_oob = arasan_nand_read_oob; + nand_chip->ecc.write_oob = arasan_nand_write_oob; + + arasan_check_ondie(mtd); + + /* + * If on die supported, then give priority to on-die ecc and use + * it instead of controller ecc. + */ + if (nand->on_die_ecc_enabled) { + nand_chip->ecc.strength = 1; + nand_chip->ecc.size = mtd->writesize; + nand_chip->ecc.bytes = 0; + nand_chip->ecc.layout = &ondie_nand_oob_64; + } else { + if (arasan_nand_ecc_init(mtd)) { + printf("%s: nand_ecc_init failed\n", __func__); + goto fail; + } + } + + if (nand_scan_tail(mtd)) { + printf("%s: nand_scan_tail failed\n", __func__); + goto fail; + } + + if (nand_register(devnum, mtd)) { + printf("Nand Register Fail\n"); + goto fail; + } + + return 0; +fail: + free(nand); + return err; +} + +void board_nand_init(void) +{ + struct nand_chip *nand = &nand_chip[0]; + + if (arasan_nand_init(nand, 0)) + puts("NAND init failed\n"); +} diff --git a/drivers/mtd/nand/raw/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c new file mode 100644 index 0000000000..a5b76e1aa0 --- /dev/null +++ b/drivers/mtd/nand/raw/atmel_nand.c @@ -0,0 +1,1511 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2007-2008 + * Stelian Pop + * Lead Tech Design + * + * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas + * + * Add Programmable Multibit ECC support for various AT91 SoC + * (C) Copyright 2012 ATMEL, Hong Xu + */ + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_ATMEL_NAND_HWECC + +/* Register access macros */ +#define ecc_readl(add, reg) \ + readl(add + ATMEL_ECC_##reg) +#define ecc_writel(add, reg, value) \ + writel((value), add + ATMEL_ECC_##reg) + +#include "atmel_nand_ecc.h" /* Hardware ECC registers */ + +#ifdef CONFIG_ATMEL_NAND_HW_PMECC + +#ifdef CONFIG_SPL_BUILD +#undef CONFIG_SYS_NAND_ONFI_DETECTION +#endif + +struct atmel_nand_host { + struct pmecc_regs __iomem *pmecc; + struct pmecc_errloc_regs __iomem *pmerrloc; + void __iomem *pmecc_rom_base; + + u8 pmecc_corr_cap; + u16 pmecc_sector_size; + u32 pmecc_index_table_offset; + u32 pmecc_version; + + int pmecc_bytes_per_sector; + int pmecc_sector_number; + int pmecc_degree; /* Degree of remainders */ + int pmecc_cw_len; /* Length of codeword */ + + /* lookup table for alpha_to and index_of */ + void __iomem *pmecc_alpha_to; + void __iomem *pmecc_index_of; + + /* data for pmecc computation */ + int16_t *pmecc_smu; + int16_t *pmecc_partial_syn; + int16_t *pmecc_si; + int16_t *pmecc_lmu; /* polynomal order */ + int *pmecc_mu; + int *pmecc_dmu; + int *pmecc_delta; +}; + +static struct atmel_nand_host pmecc_host; +static struct nand_ecclayout atmel_pmecc_oobinfo; + +/* + * Return number of ecc bytes per sector according to sector size and + * correction capability + * + * Following table shows what at91 PMECC supported: + * Correction Capability Sector_512_bytes Sector_1024_bytes + * ===================== ================ ================= + * 2-bits 4-bytes 4-bytes + * 4-bits 7-bytes 7-bytes + * 8-bits 13-bytes 14-bytes + * 12-bits 20-bytes 21-bytes + * 24-bits 39-bytes 42-bytes + * 32-bits 52-bytes 56-bytes + */ +static int pmecc_get_ecc_bytes(int cap, int sector_size) +{ + int m = 12 + sector_size / 512; + return (m * cap + 7) / 8; +} + +static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, + int oobsize, int ecc_len) +{ + int i; + + layout->eccbytes = ecc_len; + + /* ECC will occupy the last ecc_len bytes continuously */ + for (i = 0; i < ecc_len; i++) + layout->eccpos[i] = oobsize - ecc_len + i; + + layout->oobfree[0].offset = 2; + layout->oobfree[0].length = + oobsize - ecc_len - layout->oobfree[0].offset; +} + +static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) +{ + int table_size; + + table_size = host->pmecc_sector_size == 512 ? + PMECC_INDEX_TABLE_SIZE_512 : PMECC_INDEX_TABLE_SIZE_1024; + + /* the ALPHA lookup table is right behind the INDEX lookup table. */ + return host->pmecc_rom_base + host->pmecc_index_table_offset + + table_size * sizeof(int16_t); +} + +static void pmecc_data_free(struct atmel_nand_host *host) +{ + free(host->pmecc_partial_syn); + free(host->pmecc_si); + free(host->pmecc_lmu); + free(host->pmecc_smu); + free(host->pmecc_mu); + free(host->pmecc_dmu); + free(host->pmecc_delta); +} + +static int pmecc_data_alloc(struct atmel_nand_host *host) +{ + const int cap = host->pmecc_corr_cap; + int size; + + size = (2 * cap + 1) * sizeof(int16_t); + host->pmecc_partial_syn = malloc(size); + host->pmecc_si = malloc(size); + host->pmecc_lmu = malloc((cap + 1) * sizeof(int16_t)); + host->pmecc_smu = malloc((cap + 2) * size); + + size = (cap + 1) * sizeof(int); + host->pmecc_mu = malloc(size); + host->pmecc_dmu = malloc(size); + host->pmecc_delta = malloc(size); + + if (host->pmecc_partial_syn && + host->pmecc_si && + host->pmecc_lmu && + host->pmecc_smu && + host->pmecc_mu && + host->pmecc_dmu && + host->pmecc_delta) + return 0; + + /* error happened */ + pmecc_data_free(host); + return -ENOMEM; + +} + +static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct atmel_nand_host *host = nand_get_controller_data(nand_chip); + int i; + uint32_t value; + + /* Fill odd syndromes */ + for (i = 0; i < host->pmecc_corr_cap; i++) { + value = pmecc_readl(host->pmecc, rem_port[sector].rem[i / 2]); + if (i & 1) + value >>= 16; + value &= 0xffff; + host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value; + } +} + +static void pmecc_substitute(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct atmel_nand_host *host = nand_get_controller_data(nand_chip); + int16_t __iomem *alpha_to = host->pmecc_alpha_to; + int16_t __iomem *index_of = host->pmecc_index_of; + int16_t *partial_syn = host->pmecc_partial_syn; + const int cap = host->pmecc_corr_cap; + int16_t *si; + int i, j; + + /* si[] is a table that holds the current syndrome value, + * an element of that table belongs to the field + */ + si = host->pmecc_si; + + memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1)); + + /* Computation 2t syndromes based on S(x) */ + /* Odd syndromes */ + for (i = 1; i < 2 * cap; i += 2) { + for (j = 0; j < host->pmecc_degree; j++) { + if (partial_syn[i] & (0x1 << j)) + si[i] = readw(alpha_to + i * j) ^ si[i]; + } + } + /* Even syndrome = (Odd syndrome) ** 2 */ + for (i = 2, j = 1; j <= cap; i = ++j << 1) { + if (si[j] == 0) { + si[i] = 0; + } else { + int16_t tmp; + + tmp = readw(index_of + si[j]); + tmp = (tmp * 2) % host->pmecc_cw_len; + si[i] = readw(alpha_to + tmp); + } + } +} + +/* + * This function defines a Berlekamp iterative procedure for + * finding the value of the error location polynomial. + * The input is si[], initialize by pmecc_substitute(). + * The output is smu[][]. + * + * This function is written according to chip datasheet Chapter: + * Find the Error Location Polynomial Sigma(x) of Section: + * Programmable Multibit ECC Control (PMECC). + */ +static void pmecc_get_sigma(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct atmel_nand_host *host = nand_get_controller_data(nand_chip); + + int16_t *lmu = host->pmecc_lmu; + int16_t *si = host->pmecc_si; + int *mu = host->pmecc_mu; + int *dmu = host->pmecc_dmu; /* Discrepancy */ + int *delta = host->pmecc_delta; /* Delta order */ + int cw_len = host->pmecc_cw_len; + const int16_t cap = host->pmecc_corr_cap; + const int num = 2 * cap + 1; + int16_t __iomem *index_of = host->pmecc_index_of; + int16_t __iomem *alpha_to = host->pmecc_alpha_to; + int i, j, k; + uint32_t dmu_0_count, tmp; + int16_t *smu = host->pmecc_smu; + + /* index of largest delta */ + int ro; + int largest; + int diff; + + /* Init the Sigma(x) */ + memset(smu, 0, sizeof(int16_t) * ARRAY_SIZE(smu)); + + dmu_0_count = 0; + + /* First Row */ + + /* Mu */ + mu[0] = -1; + + smu[0] = 1; + + /* discrepancy set to 1 */ + dmu[0] = 1; + /* polynom order set to 0 */ + lmu[0] = 0; + /* delta[0] = (mu[0] * 2 - lmu[0]) >> 1; */ + delta[0] = -1; + + /* Second Row */ + + /* Mu */ + mu[1] = 0; + /* Sigma(x) set to 1 */ + smu[num] = 1; + + /* discrepancy set to S1 */ + dmu[1] = si[1]; + + /* polynom order set to 0 */ + lmu[1] = 0; + + /* delta[1] = (mu[1] * 2 - lmu[1]) >> 1; */ + delta[1] = 0; + + for (i = 1; i <= cap; i++) { + mu[i + 1] = i << 1; + /* Begin Computing Sigma (Mu+1) and L(mu) */ + /* check if discrepancy is set to 0 */ + if (dmu[i] == 0) { + dmu_0_count++; + + tmp = ((cap - (lmu[i] >> 1) - 1) / 2); + if ((cap - (lmu[i] >> 1) - 1) & 0x1) + tmp += 2; + else + tmp += 1; + + if (dmu_0_count == tmp) { + for (j = 0; j <= (lmu[i] >> 1) + 1; j++) + smu[(cap + 1) * num + j] = + smu[i * num + j]; + + lmu[cap + 1] = lmu[i]; + return; + } + + /* copy polynom */ + for (j = 0; j <= lmu[i] >> 1; j++) + smu[(i + 1) * num + j] = smu[i * num + j]; + + /* copy previous polynom order to the next */ + lmu[i + 1] = lmu[i]; + } else { + ro = 0; + largest = -1; + /* find largest delta with dmu != 0 */ + for (j = 0; j < i; j++) { + if ((dmu[j]) && (delta[j] > largest)) { + largest = delta[j]; + ro = j; + } + } + + /* compute difference */ + diff = (mu[i] - mu[ro]); + + /* Compute degree of the new smu polynomial */ + if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff)) + lmu[i + 1] = lmu[i]; + else + lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2; + + /* Init smu[i+1] with 0 */ + for (k = 0; k < num; k++) + smu[(i + 1) * num + k] = 0; + + /* Compute smu[i+1] */ + for (k = 0; k <= lmu[ro] >> 1; k++) { + int16_t a, b, c; + + if (!(smu[ro * num + k] && dmu[i])) + continue; + a = readw(index_of + dmu[i]); + b = readw(index_of + dmu[ro]); + c = readw(index_of + smu[ro * num + k]); + tmp = a + (cw_len - b) + c; + a = readw(alpha_to + tmp % cw_len); + smu[(i + 1) * num + (k + diff)] = a; + } + + for (k = 0; k <= lmu[i] >> 1; k++) + smu[(i + 1) * num + k] ^= smu[i * num + k]; + } + + /* End Computing Sigma (Mu+1) and L(mu) */ + /* In either case compute delta */ + delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1; + + /* Do not compute discrepancy for the last iteration */ + if (i >= cap) + continue; + + for (k = 0; k <= (lmu[i + 1] >> 1); k++) { + tmp = 2 * (i - 1); + if (k == 0) { + dmu[i + 1] = si[tmp + 3]; + } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) { + int16_t a, b, c; + a = readw(index_of + + smu[(i + 1) * num + k]); + b = si[2 * (i - 1) + 3 - k]; + c = readw(index_of + b); + tmp = a + c; + tmp %= cw_len; + dmu[i + 1] = readw(alpha_to + tmp) ^ + dmu[i + 1]; + } + } + } +} + +static int pmecc_err_location(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct atmel_nand_host *host = nand_get_controller_data(nand_chip); + const int cap = host->pmecc_corr_cap; + const int num = 2 * cap + 1; + int sector_size = host->pmecc_sector_size; + int err_nbr = 0; /* number of error */ + int roots_nbr; /* number of roots */ + int i; + uint32_t val; + int16_t *smu = host->pmecc_smu; + int timeout = PMECC_MAX_TIMEOUT_US; + + pmecc_writel(host->pmerrloc, eldis, PMERRLOC_DISABLE); + + for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) { + pmecc_writel(host->pmerrloc, sigma[i], + smu[(cap + 1) * num + i]); + err_nbr++; + } + + val = PMERRLOC_ELCFG_NUM_ERRORS(err_nbr - 1); + if (sector_size == 1024) + val |= PMERRLOC_ELCFG_SECTOR_1024; + + pmecc_writel(host->pmerrloc, elcfg, val); + pmecc_writel(host->pmerrloc, elen, + sector_size * 8 + host->pmecc_degree * cap); + + while (--timeout) { + if (pmecc_readl(host->pmerrloc, elisr) & PMERRLOC_CALC_DONE) + break; + WATCHDOG_RESET(); + udelay(1); + } + + if (!timeout) { + dev_err(host->dev, "atmel_nand : Timeout to calculate PMECC error location\n"); + return -1; + } + + roots_nbr = (pmecc_readl(host->pmerrloc, elisr) & PMERRLOC_ERR_NUM_MASK) + >> 8; + /* Number of roots == degree of smu hence <= cap */ + if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1) + return err_nbr - 1; + + /* Number of roots does not match the degree of smu + * unable to correct error */ + return -1; +} + +static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, + int sector_num, int extra_bytes, int err_nbr) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct atmel_nand_host *host = nand_get_controller_data(nand_chip); + int i = 0; + int byte_pos, bit_pos, sector_size, pos; + uint32_t tmp; + uint8_t err_byte; + + sector_size = host->pmecc_sector_size; + + while (err_nbr) { + tmp = pmecc_readl(host->pmerrloc, el[i]) - 1; + byte_pos = tmp / 8; + bit_pos = tmp % 8; + + if (byte_pos >= (sector_size + extra_bytes)) + BUG(); /* should never happen */ + + if (byte_pos < sector_size) { + err_byte = *(buf + byte_pos); + *(buf + byte_pos) ^= (1 << bit_pos); + + pos = sector_num * host->pmecc_sector_size + byte_pos; + dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + pos, bit_pos, err_byte, *(buf + byte_pos)); + } else { + /* Bit flip in OOB area */ + tmp = sector_num * host->pmecc_bytes_per_sector + + (byte_pos - sector_size); + err_byte = ecc[tmp]; + ecc[tmp] ^= (1 << bit_pos); + + pos = tmp + nand_chip->ecc.layout->eccpos[0]; + dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + pos, bit_pos, err_byte, ecc[tmp]); + } + + i++; + err_nbr--; + } + + return; +} + +static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, + u8 *ecc) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct atmel_nand_host *host = nand_get_controller_data(nand_chip); + int i, err_nbr, eccbytes; + uint8_t *buf_pos; + + /* SAMA5D4 PMECC IP can correct errors for all 0xff page */ + if (host->pmecc_version >= PMECC_VERSION_SAMA5D4) + goto normal_check; + + eccbytes = nand_chip->ecc.bytes; + for (i = 0; i < eccbytes; i++) + if (ecc[i] != 0xff) + goto normal_check; + /* Erased page, return OK */ + return 0; + +normal_check: + for (i = 0; i < host->pmecc_sector_number; i++) { + err_nbr = 0; + if (pmecc_stat & 0x1) { + buf_pos = buf + i * host->pmecc_sector_size; + + pmecc_gen_syndrome(mtd, i); + pmecc_substitute(mtd); + pmecc_get_sigma(mtd); + + err_nbr = pmecc_err_location(mtd); + if (err_nbr == -1) { + dev_err(host->dev, "PMECC: Too many errors\n"); + mtd->ecc_stats.failed++; + return -EBADMSG; + } else { + pmecc_correct_data(mtd, buf_pos, ecc, i, + host->pmecc_bytes_per_sector, err_nbr); + mtd->ecc_stats.corrected += err_nbr; + } + } + pmecc_stat >>= 1; + } + + return 0; +} + +static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +{ + struct atmel_nand_host *host = nand_get_controller_data(chip); + int eccsize = chip->ecc.size; + uint8_t *oob = chip->oob_poi; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint32_t stat; + int timeout = PMECC_MAX_TIMEOUT_US; + + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_RST); + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DISABLE); + pmecc_writel(host->pmecc, cfg, ((pmecc_readl(host->pmecc, cfg)) + & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE); + + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_ENABLE); + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DATA); + + chip->read_buf(mtd, buf, eccsize); + chip->read_buf(mtd, oob, mtd->oobsize); + + while (--timeout) { + if (!(pmecc_readl(host->pmecc, sr) & PMECC_SR_BUSY)) + break; + WATCHDOG_RESET(); + udelay(1); + } + + if (!timeout) { + dev_err(host->dev, "atmel_nand : Timeout to read PMECC page\n"); + return -1; + } + + stat = pmecc_readl(host->pmecc, isr); + if (stat != 0) + if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0) + return -EBADMSG; + + return 0; +} + +static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) +{ + struct atmel_nand_host *host = nand_get_controller_data(chip); + uint32_t *eccpos = chip->ecc.layout->eccpos; + int i, j; + int timeout = PMECC_MAX_TIMEOUT_US; + + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_RST); + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DISABLE); + + pmecc_writel(host->pmecc, cfg, (pmecc_readl(host->pmecc, cfg) | + PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE); + + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_ENABLE); + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DATA); + + chip->write_buf(mtd, (u8 *)buf, mtd->writesize); + + while (--timeout) { + if (!(pmecc_readl(host->pmecc, sr) & PMECC_SR_BUSY)) + break; + WATCHDOG_RESET(); + udelay(1); + } + + if (!timeout) { + dev_err(host->dev, "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n"); + goto out; + } + + for (i = 0; i < host->pmecc_sector_number; i++) { + for (j = 0; j < host->pmecc_bytes_per_sector; j++) { + int pos; + + pos = i * host->pmecc_bytes_per_sector + j; + chip->oob_poi[eccpos[pos]] = + pmecc_readb(host->pmecc, ecc_port[i].ecc[j]); + } + } + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +out: + return 0; +} + +static void atmel_pmecc_core_init(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct atmel_nand_host *host = nand_get_controller_data(nand_chip); + uint32_t val = 0; + struct nand_ecclayout *ecc_layout; + + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_RST); + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DISABLE); + + switch (host->pmecc_corr_cap) { + case 2: + val = PMECC_CFG_BCH_ERR2; + break; + case 4: + val = PMECC_CFG_BCH_ERR4; + break; + case 8: + val = PMECC_CFG_BCH_ERR8; + break; + case 12: + val = PMECC_CFG_BCH_ERR12; + break; + case 24: + val = PMECC_CFG_BCH_ERR24; + break; + case 32: + val = PMECC_CFG_BCH_ERR32; + break; + } + + if (host->pmecc_sector_size == 512) + val |= PMECC_CFG_SECTOR512; + else if (host->pmecc_sector_size == 1024) + val |= PMECC_CFG_SECTOR1024; + + switch (host->pmecc_sector_number) { + case 1: + val |= PMECC_CFG_PAGE_1SECTOR; + break; + case 2: + val |= PMECC_CFG_PAGE_2SECTORS; + break; + case 4: + val |= PMECC_CFG_PAGE_4SECTORS; + break; + case 8: + val |= PMECC_CFG_PAGE_8SECTORS; + break; + } + + val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE + | PMECC_CFG_AUTO_DISABLE); + pmecc_writel(host->pmecc, cfg, val); + + ecc_layout = nand_chip->ecc.layout; + pmecc_writel(host->pmecc, sarea, mtd->oobsize - 1); + pmecc_writel(host->pmecc, saddr, ecc_layout->eccpos[0]); + pmecc_writel(host->pmecc, eaddr, + ecc_layout->eccpos[ecc_layout->eccbytes - 1]); + /* See datasheet about PMECC Clock Control Register */ + pmecc_writel(host->pmecc, clk, PMECC_CLK_133MHZ); + pmecc_writel(host->pmecc, idr, 0xff); + pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_ENABLE); +} + +#ifdef CONFIG_SYS_NAND_ONFI_DETECTION +/* + * pmecc_choose_ecc - Get ecc requirement from ONFI parameters. If + * pmecc_corr_cap or pmecc_sector_size is 0, then set it as + * ONFI ECC parameters. + * @host: point to an atmel_nand_host structure. + * if host->pmecc_corr_cap is 0 then set it as the ONFI ecc_bits. + * if host->pmecc_sector_size is 0 then set it as the ONFI sector_size. + * @chip: point to an nand_chip structure. + * @cap: store the ONFI ECC correct bits capbility + * @sector_size: in how many bytes that ONFI require to correct @ecc_bits + * + * Return 0 if success. otherwise return the error code. + */ +static int pmecc_choose_ecc(struct atmel_nand_host *host, + struct nand_chip *chip, + int *cap, int *sector_size) +{ + /* Get ECC requirement from ONFI parameters */ + *cap = *sector_size = 0; + if (chip->onfi_version) { + *cap = chip->ecc_strength_ds; + *sector_size = chip->ecc_step_ds; + pr_debug("ONFI params, minimum required ECC: %d bits in %d bytes\n", + *cap, *sector_size); + } + + if (*cap == 0 && *sector_size == 0) { + /* Non-ONFI compliant */ + dev_info(host->dev, "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes\n"); + *cap = 2; + *sector_size = 512; + } + + /* If head file doesn't specify then use the one in ONFI parameters */ + if (host->pmecc_corr_cap == 0) { + /* use the most fitable ecc bits (the near bigger one ) */ + if (*cap <= 2) + host->pmecc_corr_cap = 2; + else if (*cap <= 4) + host->pmecc_corr_cap = 4; + else if (*cap <= 8) + host->pmecc_corr_cap = 8; + else if (*cap <= 12) + host->pmecc_corr_cap = 12; + else if (*cap <= 24) + host->pmecc_corr_cap = 24; + else +#ifdef CONFIG_SAMA5D2 + host->pmecc_corr_cap = 32; +#else + host->pmecc_corr_cap = 24; +#endif + } + if (host->pmecc_sector_size == 0) { + /* use the most fitable sector size (the near smaller one ) */ + if (*sector_size >= 1024) + host->pmecc_sector_size = 1024; + else if (*sector_size >= 512) + host->pmecc_sector_size = 512; + else + return -EINVAL; + } + return 0; +} +#endif + +#if defined(NO_GALOIS_TABLE_IN_ROM) +static uint16_t *pmecc_galois_table; +static inline int deg(unsigned int poly) +{ + /* polynomial degree is the most-significant bit index */ + return fls(poly) - 1; +} + +static int build_gf_tables(int mm, unsigned int poly, + int16_t *index_of, int16_t *alpha_to) +{ + unsigned int i, x = 1; + const unsigned int k = 1 << deg(poly); + unsigned int nn = (1 << mm) - 1; + + /* primitive polynomial must be of degree m */ + if (k != (1u << mm)) + return -EINVAL; + + for (i = 0; i < nn; i++) { + alpha_to[i] = x; + index_of[x] = i; + if (i && (x == 1)) + /* polynomial is not primitive (a^i=1 with 0ecc.mode = NAND_ECC_HW; + nand->ecc.calculate = NULL; + nand->ecc.correct = NULL; + nand->ecc.hwctl = NULL; + +#ifdef CONFIG_SYS_NAND_ONFI_DETECTION + host->pmecc_corr_cap = host->pmecc_sector_size = 0; + +#ifdef CONFIG_PMECC_CAP + host->pmecc_corr_cap = CONFIG_PMECC_CAP; +#endif +#ifdef CONFIG_PMECC_SECTOR_SIZE + host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE; +#endif + /* Get ECC requirement of ONFI parameters. And if CONFIG_PMECC_CAP or + * CONFIG_PMECC_SECTOR_SIZE not defined, then use ecc_bits, sector_size + * from ONFI. + */ + if (pmecc_choose_ecc(host, nand, &cap, §or_size)) { + dev_err(host->dev, "Required ECC %d bits in %d bytes not supported!\n", + cap, sector_size); + return -EINVAL; + } + + if (cap > host->pmecc_corr_cap) + dev_info(host->dev, "WARNING: Using different ecc correct bits(%d bit) from Nand ONFI ECC reqirement (%d bit).\n", + host->pmecc_corr_cap, cap); + if (sector_size < host->pmecc_sector_size) + dev_info(host->dev, "WARNING: Using different ecc correct sector size (%d bytes) from Nand ONFI ECC reqirement (%d bytes).\n", + host->pmecc_sector_size, sector_size); +#else /* CONFIG_SYS_NAND_ONFI_DETECTION */ + host->pmecc_corr_cap = CONFIG_PMECC_CAP; + host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE; +#endif + + cap = host->pmecc_corr_cap; + sector_size = host->pmecc_sector_size; + + /* TODO: need check whether cap & sector_size is validate */ +#if defined(NO_GALOIS_TABLE_IN_ROM) + /* + * As pmecc_rom_base is the begin of the gallois field table, So the + * index offset just set as 0. + */ + host->pmecc_index_table_offset = 0; +#else + if (host->pmecc_sector_size == 512) + host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_512; + else + host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_1024; +#endif + + pr_debug("Initialize PMECC params, cap: %d, sector: %d\n", + cap, sector_size); + + host->pmecc = (struct pmecc_regs __iomem *) ATMEL_BASE_PMECC; + host->pmerrloc = (struct pmecc_errloc_regs __iomem *) + ATMEL_BASE_PMERRLOC; +#if defined(NO_GALOIS_TABLE_IN_ROM) + pmecc_galois_table = create_lookup_table(host->pmecc_sector_size); + if (!pmecc_galois_table) { + dev_err(host->dev, "out of memory\n"); + return -ENOMEM; + } + + host->pmecc_rom_base = (void __iomem *)pmecc_galois_table; +#else + host->pmecc_rom_base = (void __iomem *) ATMEL_BASE_ROM; +#endif + + /* ECC is calculated for the whole page (1 step) */ + nand->ecc.size = mtd->writesize; + + /* set ECC page size and oob layout */ + switch (mtd->writesize) { + case 2048: + case 4096: + case 8192: + host->pmecc_degree = (sector_size == 512) ? + PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; + host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; + host->pmecc_sector_number = mtd->writesize / sector_size; + host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes( + cap, sector_size); + host->pmecc_alpha_to = pmecc_get_alpha_to(host); + host->pmecc_index_of = host->pmecc_rom_base + + host->pmecc_index_table_offset; + + nand->ecc.steps = 1; + nand->ecc.bytes = host->pmecc_bytes_per_sector * + host->pmecc_sector_number; + + if (nand->ecc.bytes > MTD_MAX_ECCPOS_ENTRIES_LARGE) { + dev_err(host->dev, "too large eccpos entries. max support ecc.bytes is %d\n", + MTD_MAX_ECCPOS_ENTRIES_LARGE); + return -EINVAL; + } + + if (nand->ecc.bytes > mtd->oobsize - PMECC_OOB_RESERVED_BYTES) { + dev_err(host->dev, "No room for ECC bytes\n"); + return -EINVAL; + } + pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, + mtd->oobsize, + nand->ecc.bytes); + nand->ecc.layout = &atmel_pmecc_oobinfo; + break; + case 512: + case 1024: + /* TODO */ + dev_err(host->dev, "Unsupported page size for PMECC, use Software ECC\n"); + default: + /* page size not handled by HW ECC */ + /* switching back to soft ECC */ + nand->ecc.mode = NAND_ECC_SOFT; + nand->ecc.read_page = NULL; + nand->ecc.postpad = 0; + nand->ecc.prepad = 0; + nand->ecc.bytes = 0; + return 0; + } + + /* Allocate data for PMECC computation */ + if (pmecc_data_alloc(host)) { + dev_err(host->dev, "Cannot allocate memory for PMECC computation!\n"); + return -ENOMEM; + } + + nand->options |= NAND_NO_SUBPAGE_WRITE; + nand->ecc.read_page = atmel_nand_pmecc_read_page; + nand->ecc.write_page = atmel_nand_pmecc_write_page; + nand->ecc.strength = cap; + + /* Check the PMECC ip version */ + host->pmecc_version = pmecc_readl(host->pmerrloc, version); + dev_dbg(host->dev, "PMECC IP version is: %x\n", host->pmecc_version); + + atmel_pmecc_core_init(mtd); + + return 0; +} + +#else + +/* oob layout for large page size + * bad block info is on bytes 0 and 1 + * the bytes have to be consecutives to avoid + * several NAND_CMD_RNDOUT during read + */ +static struct nand_ecclayout atmel_oobinfo_large = { + .eccbytes = 4, + .eccpos = {60, 61, 62, 63}, + .oobfree = { + {2, 58} + }, +}; + +/* oob layout for small page size + * bad block info is on bytes 4 and 5 + * the bytes have to be consecutives to avoid + * several NAND_CMD_RNDOUT during read + */ +static struct nand_ecclayout atmel_oobinfo_small = { + .eccbytes = 4, + .eccpos = {0, 1, 2, 3}, + .oobfree = { + {6, 10} + }, +}; + +/* + * Calculate HW ECC + * + * function called after a write + * + * mtd: MTD block structure + * dat: raw data (unused) + * ecc_code: buffer for ECC + */ +static int atmel_nand_calculate(struct mtd_info *mtd, + const u_char *dat, unsigned char *ecc_code) +{ + unsigned int ecc_value; + + /* get the first 2 ECC bytes */ + ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR); + + ecc_code[0] = ecc_value & 0xFF; + ecc_code[1] = (ecc_value >> 8) & 0xFF; + + /* get the last 2 ECC bytes */ + ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, NPR) & ATMEL_ECC_NPARITY; + + ecc_code[2] = ecc_value & 0xFF; + ecc_code[3] = (ecc_value >> 8) & 0xFF; + + return 0; +} + +/* + * HW ECC read page function + * + * 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 + */ +static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + uint8_t *ecc_pos; + int stat; + + /* read the page */ + chip->read_buf(mtd, p, eccsize); + + /* move to ECC position if needed */ + if (eccpos[0] != 0) { + /* This only works on large pages + * because the ECC controller waits for + * NAND_CMD_RNDOUTSTART after the + * NAND_CMD_RNDOUT. + * anyway, for small pages, the eccpos[0] == 0 + */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, + mtd->writesize + eccpos[0], -1); + } + + /* the ECC controller needs to read the ECC just after the data */ + ecc_pos = oob + eccpos[0]; + chip->read_buf(mtd, ecc_pos, eccbytes); + + /* check if there's an error */ + stat = chip->ecc.correct(mtd, p, oob, NULL); + + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + + /* get back to oob start (end of page) */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + + /* read the oob */ + chip->read_buf(mtd, oob, mtd->oobsize); + + return 0; +} + +/* + * HW ECC Correction + * + * function called after a read + * + * mtd: MTD block structure + * dat: raw data read from the chip + * read_ecc: ECC from the chip (unused) + * isnull: unused + * + * Detect and correct a 1 bit error for a page + */ +static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *isnull) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + unsigned int ecc_status; + unsigned int ecc_word, ecc_bit; + + /* get the status from the Status Register */ + ecc_status = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, SR); + + /* if there's no error */ + if (likely(!(ecc_status & ATMEL_ECC_RECERR))) + return 0; + + /* get error bit offset (4 bits) */ + ecc_bit = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_BITADDR; + /* get word address (12 bits) */ + ecc_word = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_WORDADDR; + ecc_word >>= 4; + + /* if there are multiple errors */ + if (ecc_status & ATMEL_ECC_MULERR) { + /* check if it is a freshly erased block + * (filled with 0xff) */ + if ((ecc_bit == ATMEL_ECC_BITADDR) + && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { + /* the block has just been erased, return OK */ + return 0; + } + /* it doesn't seems to be a freshly + * erased block. + * We can't correct so many errors */ + dev_warn(host->dev, "atmel_nand : multiple errors detected." + " Unable to correct.\n"); + return -EBADMSG; + } + + /* if there's a single bit error : we can correct it */ + if (ecc_status & ATMEL_ECC_ECCERR) { + /* there's nothing much to do here. + * the bit error is on the ECC itself. + */ + dev_warn(host->dev, "atmel_nand : one bit error on ECC code." + " Nothing to correct\n"); + return 0; + } + + dev_warn(host->dev, "atmel_nand : one bit error on data." + " (word offset in the page :" + " 0x%x bit offset : 0x%x)\n", + ecc_word, ecc_bit); + /* correct the error */ + if (nand_chip->options & NAND_BUSWIDTH_16) { + /* 16 bits words */ + ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); + } else { + /* 8 bits words */ + dat[ecc_word] ^= (1 << ecc_bit); + } + dev_warn(host->dev, "atmel_nand : error corrected\n"); + return 1; +} + +/* + * Enable HW ECC : unused on most chips + */ +static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) +{ +} + +int atmel_hwecc_nand_init_param(struct nand_chip *nand, struct mtd_info *mtd) +{ + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.calculate = atmel_nand_calculate; + nand->ecc.correct = atmel_nand_correct; + nand->ecc.hwctl = atmel_nand_hwctl; + nand->ecc.read_page = atmel_nand_read_page; + nand->ecc.bytes = 4; + nand->ecc.strength = 4; + + if (nand->ecc.mode == NAND_ECC_HW) { + /* ECC is calculated for the whole page (1 step) */ + nand->ecc.size = mtd->writesize; + + /* set ECC page size and oob layout */ + switch (mtd->writesize) { + case 512: + nand->ecc.layout = &atmel_oobinfo_small; + ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, + ATMEL_ECC_PAGESIZE_528); + break; + case 1024: + nand->ecc.layout = &atmel_oobinfo_large; + ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, + ATMEL_ECC_PAGESIZE_1056); + break; + case 2048: + nand->ecc.layout = &atmel_oobinfo_large; + ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, + ATMEL_ECC_PAGESIZE_2112); + break; + case 4096: + nand->ecc.layout = &atmel_oobinfo_large; + ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, + ATMEL_ECC_PAGESIZE_4224); + break; + default: + /* page size not handled by HW ECC */ + /* switching back to soft ECC */ + nand->ecc.mode = NAND_ECC_SOFT; + nand->ecc.calculate = NULL; + nand->ecc.correct = NULL; + nand->ecc.hwctl = NULL; + nand->ecc.read_page = NULL; + nand->ecc.postpad = 0; + nand->ecc.prepad = 0; + nand->ecc.bytes = 0; + break; + } + } + + return 0; +} + +#endif /* CONFIG_ATMEL_NAND_HW_PMECC */ + +#endif /* CONFIG_ATMEL_NAND_HWECC */ + +static void at91_nand_hwcontrol(struct mtd_info *mtd, + int cmd, unsigned int ctrl) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + if (ctrl & NAND_CTRL_CHANGE) { + ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; + IO_ADDR_W &= ~(CONFIG_SYS_NAND_MASK_ALE + | CONFIG_SYS_NAND_MASK_CLE); + + if (ctrl & NAND_CLE) + IO_ADDR_W |= CONFIG_SYS_NAND_MASK_CLE; + if (ctrl & NAND_ALE) + IO_ADDR_W |= CONFIG_SYS_NAND_MASK_ALE; + +#ifdef CONFIG_SYS_NAND_ENABLE_PIN + at91_set_gpio_value(CONFIG_SYS_NAND_ENABLE_PIN, + !(ctrl & NAND_NCE)); +#endif + this->IO_ADDR_W = (void *) IO_ADDR_W; + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); +} + +#ifdef CONFIG_SYS_NAND_READY_PIN +static int at91_nand_ready(struct mtd_info *mtd) +{ + return at91_get_gpio_value(CONFIG_SYS_NAND_READY_PIN); +} +#endif + +#ifdef CONFIG_SPL_BUILD +/* The following code is for SPL */ +static struct mtd_info *mtd; +static struct nand_chip nand_chip; + +static int nand_command(int block, int page, uint32_t offs, u8 cmd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; + void (*hwctrl)(struct mtd_info *mtd, int cmd, + unsigned int ctrl) = this->cmd_ctrl; + + while (!this->dev_ready(mtd)) + ; + + if (cmd == NAND_CMD_READOOB) { + offs += CONFIG_SYS_NAND_PAGE_SIZE; + cmd = NAND_CMD_READ0; + } + + hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) + offs >>= 1; + + hwctrl(mtd, offs & 0xff, NAND_CTRL_ALE | NAND_CTRL_CHANGE); + hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); + hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE); + hwctrl(mtd, ((page_addr >> 8) & 0xff), NAND_CTRL_ALE); +#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE + hwctrl(mtd, (page_addr >> 16) & 0x0f, NAND_CTRL_ALE); +#endif + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + hwctrl(mtd, NAND_CMD_READSTART, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + while (!this->dev_ready(mtd)) + ; + + return 0; +} + +static int nand_is_bad_block(int block) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, NAND_CMD_READOOB); + + if (this->options & NAND_BUSWIDTH_16) { + if (readw(this->IO_ADDR_R) != 0xffff) + return 1; + } else { + if (readb(this->IO_ADDR_R) != 0xff) + return 1; + } + + return 0; +} + +#ifdef CONFIG_SPL_NAND_ECC +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; +#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ + CONFIG_SYS_NAND_ECCSIZE) +#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) + +static int nand_read_page(int block, int page, void *dst) +{ + struct nand_chip *this = mtd_to_nand(mtd); + u_char ecc_calc[ECCTOTAL]; + u_char ecc_code[ECCTOTAL]; + u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; + int eccsize = CONFIG_SYS_NAND_ECCSIZE; + int eccbytes = CONFIG_SYS_NAND_ECCBYTES; + int eccsteps = ECCSTEPS; + int i; + uint8_t *p = dst; + nand_command(block, page, 0, NAND_CMD_READ0); + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + if (this->ecc.mode != NAND_ECC_SOFT) + this->ecc.hwctl(mtd, NAND_ECC_READ); + this->read_buf(mtd, p, eccsize); + this->ecc.calculate(mtd, p, &ecc_calc[i]); + } + this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); + + for (i = 0; i < ECCTOTAL; i++) + ecc_code[i] = oob_data[nand_ecc_pos[i]]; + + eccsteps = ECCSTEPS; + p = dst; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + + return 0; +} + +int spl_nand_erase_one(int block, int page) +{ + struct nand_chip *this = mtd_to_nand(mtd); + void (*hwctrl)(struct mtd_info *mtd, int cmd, + unsigned int ctrl) = this->cmd_ctrl; + int page_addr; + + if (nand_chip.select_chip) + nand_chip.select_chip(mtd, 0); + + page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; + hwctrl(mtd, NAND_CMD_ERASE1, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + /* Row address */ + hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE | NAND_CTRL_CHANGE); + hwctrl(mtd, ((page_addr >> 8) & 0xff), + NAND_CTRL_ALE | NAND_CTRL_CHANGE); +#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE + /* One more address cycle for devices > 128MiB */ + hwctrl(mtd, (page_addr >> 16) & 0x0f, + NAND_CTRL_ALE | NAND_CTRL_CHANGE); +#endif + hwctrl(mtd, NAND_CMD_ERASE2, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + + while (!this->dev_ready(mtd)) + ; + + nand_deselect(); + + return 0; +} +#else +static int nand_read_page(int block, int page, void *dst) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + nand_command(block, page, 0, NAND_CMD_READ0); + atmel_nand_pmecc_read_page(mtd, this, dst, 0, page); + + return 0; +} +#endif /* CONFIG_SPL_NAND_ECC */ + +int at91_nand_wait_ready(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + udelay(this->chip_delay); + + return 1; +} + +int board_nand_init(struct nand_chip *nand) +{ + int ret = 0; + + nand->ecc.mode = NAND_ECC_SOFT; +#ifdef CONFIG_SYS_NAND_DBW_16 + nand->options = NAND_BUSWIDTH_16; + nand->read_buf = nand_read_buf16; +#else + nand->read_buf = nand_read_buf; +#endif + nand->cmd_ctrl = at91_nand_hwcontrol; +#ifdef CONFIG_SYS_NAND_READY_PIN + nand->dev_ready = at91_nand_ready; +#else + nand->dev_ready = at91_nand_wait_ready; +#endif + nand->chip_delay = 20; +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + nand->bbt_options |= NAND_BBT_USE_FLASH; +#endif + +#ifdef CONFIG_ATMEL_NAND_HWECC +#ifdef CONFIG_ATMEL_NAND_HW_PMECC + ret = atmel_pmecc_nand_init_params(nand, mtd); +#endif +#endif + + return ret; +} + +void nand_init(void) +{ + mtd = nand_to_mtd(&nand_chip); + mtd->writesize = CONFIG_SYS_NAND_PAGE_SIZE; + mtd->oobsize = CONFIG_SYS_NAND_OOBSIZE; + nand_chip.IO_ADDR_R = (void __iomem *)CONFIG_SYS_NAND_BASE; + nand_chip.IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE; + board_nand_init(&nand_chip); + +#ifdef CONFIG_SPL_NAND_ECC + if (nand_chip.ecc.mode == NAND_ECC_SOFT) { + nand_chip.ecc.calculate = nand_calculate_ecc; + nand_chip.ecc.correct = nand_correct_data; + } +#endif + + if (nand_chip.select_chip) + nand_chip.select_chip(mtd, 0); +} + +void nand_deselect(void) +{ + if (nand_chip.select_chip) + nand_chip.select_chip(mtd, -1); +} + +#include "nand_spl_loaders.c" + +#else + +#ifndef CONFIG_SYS_NAND_BASE_LIST +#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } +#endif +static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; +static ulong base_addr[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST; + +int atmel_nand_chip_init(int devnum, ulong base_addr) +{ + int ret; + struct nand_chip *nand = &nand_chip[devnum]; + struct mtd_info *mtd = nand_to_mtd(nand); + + nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; + +#ifdef CONFIG_NAND_ECC_BCH + nand->ecc.mode = NAND_ECC_SOFT_BCH; +#else + nand->ecc.mode = NAND_ECC_SOFT; +#endif +#ifdef CONFIG_SYS_NAND_DBW_16 + nand->options = NAND_BUSWIDTH_16; +#endif + nand->cmd_ctrl = at91_nand_hwcontrol; +#ifdef CONFIG_SYS_NAND_READY_PIN + nand->dev_ready = at91_nand_ready; +#endif + nand->chip_delay = 75; +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + nand->bbt_options |= NAND_BBT_USE_FLASH; +#endif + + ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL); + if (ret) + return ret; + +#ifdef CONFIG_ATMEL_NAND_HWECC +#ifdef CONFIG_ATMEL_NAND_HW_PMECC + ret = atmel_pmecc_nand_init_params(nand, mtd); +#else + ret = atmel_hwecc_nand_init_param(nand, mtd); +#endif + if (ret) + return ret; +#endif + + ret = nand_scan_tail(mtd); + if (!ret) + nand_register(devnum, mtd); + + return ret; +} + +void board_nand_init(void) +{ + int i; + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) + if (atmel_nand_chip_init(i, base_addr[i])) + dev_err(host->dev, "atmel_nand: Fail to initialize #%d chip", + i); +} +#endif /* CONFIG_SPL_BUILD */ diff --git a/drivers/mtd/nand/raw/atmel_nand_ecc.h b/drivers/mtd/nand/raw/atmel_nand_ecc.h new file mode 100644 index 0000000000..05eeedb3f8 --- /dev/null +++ b/drivers/mtd/nand/raw/atmel_nand_ecc.h @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Error Corrected Code Controller (ECC) - System peripherals regsters. + * Based on AT91SAM9260 datasheet revision B. + */ + +#ifndef ATMEL_NAND_ECC_H +#define ATMEL_NAND_ECC_H + +#define ATMEL_ECC_CR 0x00 /* Control register */ +#define ATMEL_ECC_RST (1 << 0) /* Reset parity */ + +#define ATMEL_ECC_MR 0x04 /* Mode register */ +#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ +#define ATMEL_ECC_PAGESIZE_528 (0) +#define ATMEL_ECC_PAGESIZE_1056 (1) +#define ATMEL_ECC_PAGESIZE_2112 (2) +#define ATMEL_ECC_PAGESIZE_4224 (3) + +#define ATMEL_ECC_SR 0x08 /* Status register */ +#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ +#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ +#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ + +#define ATMEL_ECC_PR 0x0c /* Parity register */ +#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ +#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ + +#define ATMEL_ECC_NPR 0x10 /* NParity register */ +#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ + +/* Register access macros for PMECC */ +#define pmecc_readl(addr, reg) \ + readl(&addr->reg) + +#define pmecc_readb(addr, reg) \ + readb(&addr->reg) + +#define pmecc_writel(addr, reg, value) \ + writel((value), &addr->reg) + +/* PMECC Register Definitions */ +#define PMECC_MAX_SECTOR_NUM 8 +struct pmecc_regs { + u32 cfg; /* 0x00 PMECC Configuration Register */ + u32 sarea; /* 0x04 PMECC Spare Area Size Register */ + u32 saddr; /* 0x08 PMECC Start Address Register */ + u32 eaddr; /* 0x0C PMECC End Address Register */ + u32 clk; /* 0x10 PMECC Clock Control Register */ + u32 ctrl; /* 0x14 PMECC Control Register */ + u32 sr; /* 0x18 PMECC Status Register */ + u32 ier; /* 0x1C PMECC Interrupt Enable Register */ + u32 idr; /* 0x20 PMECC Interrupt Disable Register */ + u32 imr; /* 0x24 PMECC Interrupt Mask Register */ + u32 isr; /* 0x28 PMECC Interrupt Status Register */ + u32 reserved0[5]; /* 0x2C-0x3C Reserved */ + + /* 0x40 + sector_num * (0x40), Redundancy Registers */ + struct { +#ifdef CONFIG_SAMA5D2 + u8 ecc[56]; /* PMECC Generated Redundancy Byte Per Sector */ + u32 reserved1[2]; +#else + u8 ecc[44]; /* PMECC Generated Redundancy Byte Per Sector */ + u32 reserved1[5]; +#endif + } ecc_port[PMECC_MAX_SECTOR_NUM]; + + /* 0x240 + sector_num * (0x40) Remainder Registers */ + struct { +#ifdef CONFIG_SAMA5D2 + u32 rem[16]; +#else + u32 rem[12]; + u32 reserved2[4]; +#endif + } rem_port[PMECC_MAX_SECTOR_NUM]; + u32 reserved3[16]; /* 0x440-0x47C Reserved */ +}; + +/* For PMECC Configuration Register */ +#define PMECC_CFG_BCH_ERR2 (0 << 0) +#define PMECC_CFG_BCH_ERR4 (1 << 0) +#define PMECC_CFG_BCH_ERR8 (2 << 0) +#define PMECC_CFG_BCH_ERR12 (3 << 0) +#define PMECC_CFG_BCH_ERR24 (4 << 0) +#define PMECC_CFG_BCH_ERR32 (5 << 0) + +#define PMECC_CFG_SECTOR512 (0 << 4) +#define PMECC_CFG_SECTOR1024 (1 << 4) + +#define PMECC_CFG_PAGE_1SECTOR (0 << 8) +#define PMECC_CFG_PAGE_2SECTORS (1 << 8) +#define PMECC_CFG_PAGE_4SECTORS (2 << 8) +#define PMECC_CFG_PAGE_8SECTORS (3 << 8) + +#define PMECC_CFG_READ_OP (0 << 12) +#define PMECC_CFG_WRITE_OP (1 << 12) + +#define PMECC_CFG_SPARE_ENABLE (1 << 16) +#define PMECC_CFG_SPARE_DISABLE (0 << 16) + +#define PMECC_CFG_AUTO_ENABLE (1 << 20) +#define PMECC_CFG_AUTO_DISABLE (0 << 20) + +/* For PMECC Clock Control Register */ +#define PMECC_CLK_133MHZ (2 << 0) + +/* For PMECC Control Register */ +#define PMECC_CTRL_RST (1 << 0) +#define PMECC_CTRL_DATA (1 << 1) +#define PMECC_CTRL_USER (1 << 2) +#define PMECC_CTRL_ENABLE (1 << 4) +#define PMECC_CTRL_DISABLE (1 << 5) + +/* For PMECC Status Register */ +#define PMECC_SR_BUSY (1 << 0) +#define PMECC_SR_ENABLE (1 << 4) + +/* PMERRLOC Register Definitions */ +struct pmecc_errloc_regs { + u32 elcfg; /* 0x00 Error Location Configuration Register */ + u32 elprim; /* 0x04 Error Location Primitive Register */ + u32 elen; /* 0x08 Error Location Enable Register */ + u32 eldis; /* 0x0C Error Location Disable Register */ + u32 elsr; /* 0x10 Error Location Status Register */ + u32 elier; /* 0x14 Error Location Interrupt Enable Register */ + u32 elidr; /* 0x08 Error Location Interrupt Disable Register */ + u32 elimr; /* 0x0C Error Location Interrupt Mask Register */ + u32 elisr; /* 0x20 Error Location Interrupt Status Register */ + u32 reserved0; /* 0x24 Reserved */ +#ifdef CONFIG_SAMA5D2 + u32 sigma[33]; /* 0x28-0xA8 Error Location Sigma Registers */ + u32 el[32]; /* 0xAC-0x128 Error Location Registers */ + + /* + * 0x12C-0x1FC: + * Reserved for SAMA5D2. + */ + u32 reserved1[53]; +#else + u32 sigma[25]; /* 0x28-0x88 Error Location Sigma Registers */ + u32 el[24]; /* 0x8C-0xE8 Error Location Registers */ + u32 reserved1[5]; /* 0xEC-0xFC Reserved */ +#endif + + /* + * SAMA5 chip HSMC registers start here. But for 9X5 chip it is just + * reserved. + * + * Offset 0x00-0xF8: + */ + u32 reserved2[63]; + + /* + * Offset 0xFC: + * PMECC version for AT91SAM9X5, AT91SAM9N12. + * HSMC version for SAMA5D3, SAMA5D4. Can refer as PMECC version. + */ + u32 version; +}; + +/* For Error Location Configuration Register */ +#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0) +#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0) +#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16) + +/* For Error Location Disable Register */ +#define PMERRLOC_DISABLE (1 << 0) + +/* For Error Location Interrupt Status Register */ +#ifdef CONFIG_SAMA5D2 +#define PMERRLOC_ERR_NUM_MASK (0x3f << 8) +#else +#define PMERRLOC_ERR_NUM_MASK (0x1f << 8) +#endif + +#define PMERRLOC_CALC_DONE (1 << 0) + +/* PMECC IP version */ +#define PMECC_VERSION_SAMA5D2 0x210 +#define PMECC_VERSION_SAMA5D4 0x113 +#define PMECC_VERSION_SAMA5D3 0x112 +#define PMECC_VERSION_AT91SAM9N12 0x102 +#define PMECC_VERSION_AT91SAM9X5 0x101 + +/* Galois field dimension */ +#define PMECC_GF_DIMENSION_13 13 +#define PMECC_GF_DIMENSION_14 14 + +/* Primitive Polynomial used by PMECC */ +#define PMECC_GF_13_PRIMITIVE_POLY 0x201b +#define PMECC_GF_14_PRIMITIVE_POLY 0x4443 + +#define PMECC_INDEX_TABLE_SIZE_512 0x2000 +#define PMECC_INDEX_TABLE_SIZE_1024 0x4000 + +#define PMECC_MAX_TIMEOUT_US (100 * 1000) + +/* Reserved bytes in oob area */ +#define PMECC_OOB_RESERVED_BYTES 2 + +#endif diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c new file mode 100644 index 0000000000..e6a84a52b4 --- /dev/null +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -0,0 +1,833 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NAND driver for TI DaVinci based boards. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * Based on Linux DaVinci NAND driver by TI. Original copyright follows: + */ + +/* + * + * linux/drivers/mtd/nand/raw/nand_davinci.c + * + * NAND Flash Driver + * + * Copyright (C) 2006 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * ---------------------------------------------------------------------------- + * + * Overview: + * This is a device driver for the NAND flash device found on the + * DaVinci board which utilizes the Samsung k9k2g08 part. + * + Modifications: + ver. 1.0: Feb 2005, Vinod/Sudhakar + - + */ + +#include +#include +#include +#include + +/* Definitions for 4-bit hardware ECC */ +#define NAND_TIMEOUT 10240 +#define NAND_ECC_BUSY 0xC +#define NAND_4BITECC_MASK 0x03FF03FF +#define EMIF_NANDFSR_ECC_STATE_MASK 0x00000F00 +#define ECC_STATE_NO_ERR 0x0 +#define ECC_STATE_TOO_MANY_ERRS 0x1 +#define ECC_STATE_ERR_CORR_COMP_P 0x2 +#define ECC_STATE_ERR_CORR_COMP_N 0x3 + +/* + * Exploit the little endianness of the ARM to do multi-byte transfers + * per device read. This can perform over twice as quickly as individual + * byte transfers when buffer alignment is conducive. + * + * NOTE: This only works if the NAND is not connected to the 2 LSBs of + * the address bus. On Davinci EVM platforms this has always been true. + */ +static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + const u32 *nand = chip->IO_ADDR_R; + + /* Make sure that buf is 32 bit aligned */ + if (((int)buf & 0x3) != 0) { + if (((int)buf & 0x1) != 0) { + if (len) { + *buf = readb(nand); + buf += 1; + len--; + } + } + + if (((int)buf & 0x3) != 0) { + if (len >= 2) { + *(u16 *)buf = readw(nand); + buf += 2; + len -= 2; + } + } + } + + /* copy aligned data */ + while (len >= 4) { + *(u32 *)buf = __raw_readl(nand); + buf += 4; + len -= 4; + } + + /* mop up any remaining bytes */ + if (len) { + if (len >= 2) { + *(u16 *)buf = readw(nand); + buf += 2; + len -= 2; + } + + if (len) + *buf = readb(nand); + } +} + +static void nand_davinci_write_buf(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + const u32 *nand = chip->IO_ADDR_W; + + /* Make sure that buf is 32 bit aligned */ + if (((int)buf & 0x3) != 0) { + if (((int)buf & 0x1) != 0) { + if (len) { + writeb(*buf, nand); + buf += 1; + len--; + } + } + + if (((int)buf & 0x3) != 0) { + if (len >= 2) { + writew(*(u16 *)buf, nand); + buf += 2; + len -= 2; + } + } + } + + /* copy aligned data */ + while (len >= 4) { + __raw_writel(*(u32 *)buf, nand); + buf += 4; + len -= 4; + } + + /* mop up any remaining bytes */ + if (len) { + if (len >= 2) { + writew(*(u16 *)buf, nand); + buf += 2; + len -= 2; + } + + if (len) + writeb(*buf, nand); + } +} + +static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *this = mtd_to_nand(mtd); + u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W; + + if (ctrl & NAND_CTRL_CHANGE) { + IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); + + if (ctrl & NAND_CLE) + IO_ADDR_W |= MASK_CLE; + if (ctrl & NAND_ALE) + IO_ADDR_W |= MASK_ALE; + this->IO_ADDR_W = (void __iomem *) IO_ADDR_W; + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, IO_ADDR_W); +} + +#ifdef CONFIG_SYS_NAND_HW_ECC + +static u_int32_t nand_davinci_readecc(struct mtd_info *mtd) +{ + u_int32_t ecc = 0; + + ecc = __raw_readl(&(davinci_emif_regs->nandfecc[ + CONFIG_SYS_NAND_CS - 2])); + + return ecc; +} + +static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) +{ + u_int32_t val; + + /* reading the ECC result register resets the ECC calculation */ + nand_davinci_readecc(mtd); + + val = __raw_readl(&davinci_emif_regs->nandfcr); + val |= DAVINCI_NANDFCR_NAND_ENABLE(CONFIG_SYS_NAND_CS); + val |= DAVINCI_NANDFCR_1BIT_ECC_START(CONFIG_SYS_NAND_CS); + __raw_writel(val, &davinci_emif_regs->nandfcr); +} + +static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + u_int32_t tmp; + + tmp = nand_davinci_readecc(mtd); + + /* Squeeze 4 bytes ECC into 3 bytes by removing RESERVED bits + * and shifting. RESERVED bits are 31 to 28 and 15 to 12. */ + tmp = (tmp & 0x00000fff) | ((tmp & 0x0fff0000) >> 4); + + /* Invert so that erased block ECC is correct */ + tmp = ~tmp; + + *ecc_code++ = tmp; + *ecc_code++ = tmp >> 8; + *ecc_code++ = tmp >> 16; + + /* NOTE: the above code matches mainline Linux: + * .PQR.stu ==> ~PQRstu + * + * MontaVista/TI kernels encode those bytes differently, use + * complicated (and allegedly sometimes-wrong) correction code, + * and usually shipped with U-Boot that uses software ECC: + * .PQR.stu ==> PsQRtu + * + * If you need MV/TI compatible NAND I/O in U-Boot, it should + * be possible to (a) change the mangling above, (b) reverse + * that mangling in nand_davinci_correct_data() below. + */ + + return 0; +} + +static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + struct nand_chip *this = mtd_to_nand(mtd); + u_int32_t ecc_nand = read_ecc[0] | (read_ecc[1] << 8) | + (read_ecc[2] << 16); + u_int32_t ecc_calc = calc_ecc[0] | (calc_ecc[1] << 8) | + (calc_ecc[2] << 16); + u_int32_t diff = ecc_calc ^ ecc_nand; + + if (diff) { + if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) { + /* Correctable error */ + if ((diff >> (12 + 3)) < this->ecc.size) { + uint8_t find_bit = 1 << ((diff >> 12) & 7); + uint32_t find_byte = diff >> (12 + 3); + + dat[find_byte] ^= find_bit; + pr_debug("Correcting single " + "bit ECC error at offset: %d, bit: " + "%d\n", find_byte, find_bit); + return 1; + } else { + return -EBADMSG; + } + } else if (!(diff & (diff - 1))) { + /* Single bit ECC error in the ECC itself, + nothing to fix */ + pr_debug("Single bit ECC error in " "ECC.\n"); + return 1; + } else { + /* Uncorrectable error */ + pr_debug("ECC UNCORRECTED_ERROR 1\n"); + return -EBADMSG; + } + } + return 0; +} +#endif /* CONFIG_SYS_NAND_HW_ECC */ + +#ifdef CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST +static struct nand_ecclayout nand_davinci_4bit_layout_oobfirst = { +#if defined(CONFIG_SYS_NAND_PAGE_2K) + .eccbytes = 40, +#ifdef CONFIG_NAND_6BYTES_OOB_FREE_10BYTES_ECC + .eccpos = { + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + }, + .oobfree = { + {2, 4}, {16, 6}, {32, 6}, {48, 6}, + }, +#else + .eccpos = { + 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, + }, + .oobfree = { + {.offset = 2, .length = 22, }, + }, +#endif /* #ifdef CONFIG_NAND_6BYTES_OOB_FREE_10BYTES_ECC */ +#elif defined(CONFIG_SYS_NAND_PAGE_4K) + .eccbytes = 80, + .eccpos = { + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + }, + .oobfree = { + {.offset = 2, .length = 46, }, + }, +#endif +}; + +#if defined CONFIG_KEYSTONE_RBL_NAND +static struct nand_ecclayout nand_keystone_rbl_4bit_layout_oobfirst = { +#if defined(CONFIG_SYS_NAND_PAGE_2K) + .eccbytes = 40, + .eccpos = { + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + }, + .oobfree = { + {.offset = 2, .length = 4, }, + {.offset = 16, .length = 6, }, + {.offset = 32, .length = 6, }, + {.offset = 48, .length = 6, }, + }, +#elif defined(CONFIG_SYS_NAND_PAGE_4K) + .eccbytes = 80, + .eccpos = { + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + }, + .oobfree = { + {.offset = 2, .length = 4, }, + {.offset = 16, .length = 6, }, + {.offset = 32, .length = 6, }, + {.offset = 48, .length = 6, }, + {.offset = 64, .length = 6, }, + {.offset = 80, .length = 6, }, + {.offset = 96, .length = 6, }, + {.offset = 112, .length = 6, }, + }, +#endif +}; + +#ifdef CONFIG_SYS_NAND_PAGE_2K +#define CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE CONFIG_KEYSTONE_NAND_MAX_RBL_SIZE >> 11 +#elif defined(CONFIG_SYS_NAND_PAGE_4K) +#define CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE CONFIG_KEYSTONE_NAND_MAX_RBL_SIZE >> 12 +#endif + +/** + * nand_davinci_write_page - write one page + * @mtd: MTD device structure + * @chip: NAND chip descriptor + * @buf: the data to write + * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write + * @raw: use _raw version of write_page + */ +static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip, + uint32_t offset, int data_len, + const uint8_t *buf, int oob_required, + int page, int raw) +{ + int status; + int ret = 0; + struct nand_ecclayout *saved_ecc_layout; + + /* save current ECC layout and assign Keystone RBL ECC layout */ + if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) { + saved_ecc_layout = chip->ecc.layout; + chip->ecc.layout = &nand_keystone_rbl_4bit_layout_oobfirst; + mtd->oobavail = chip->ecc.layout->oobavail; + } + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + + if (unlikely(raw)) { + status = chip->ecc.write_page_raw(mtd, chip, buf, + oob_required, page); + } else { + status = chip->ecc.write_page(mtd, chip, buf, + oob_required, page); + } + + if (status < 0) { + ret = status; + goto err; + } + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + if (status & NAND_STATUS_FAIL) { + ret = -EIO; + goto err; + } + +err: + /* restore ECC layout */ + if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) { + chip->ecc.layout = saved_ecc_layout; + mtd->oobavail = saved_ecc_layout->oobavail; + } + + return ret; +} + +/** + * nand_davinci_read_page_hwecc - 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 + * @page: page number to read + * + * Not for syndrome calculating ECC controllers which need a special oob layout. + */ +static int nand_davinci_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint32_t *eccpos; + uint8_t *p = buf; + uint8_t *ecc_code = chip->buffers->ecccode; + uint8_t *ecc_calc = chip->buffers->ecccalc; + struct nand_ecclayout *saved_ecc_layout = chip->ecc.layout; + + /* save current ECC layout and assign Keystone RBL ECC layout */ + if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) { + chip->ecc.layout = &nand_keystone_rbl_4bit_layout_oobfirst; + mtd->oobavail = chip->ecc.layout->oobavail; + } + + eccpos = chip->ecc.layout->eccpos; + + /* Read the OOB area first */ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, p, eccsize); + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + + /* restore ECC layout */ + if (page < CONFIG_KEYSTONE_NAND_MAX_RBL_PAGE) { + chip->ecc.layout = saved_ecc_layout; + mtd->oobavail = saved_ecc_layout->oobavail; + } + + return 0; +} +#endif /* CONFIG_KEYSTONE_RBL_NAND */ + +static void nand_davinci_4bit_enable_hwecc(struct mtd_info *mtd, int mode) +{ + u32 val; + + switch (mode) { + case NAND_ECC_WRITE: + case NAND_ECC_READ: + /* + * Start a new ECC calculation for reading or writing 512 bytes + * of data. + */ + val = __raw_readl(&davinci_emif_regs->nandfcr); + val &= ~DAVINCI_NANDFCR_4BIT_ECC_SEL_MASK; + val |= DAVINCI_NANDFCR_NAND_ENABLE(CONFIG_SYS_NAND_CS); + val |= DAVINCI_NANDFCR_4BIT_ECC_SEL(CONFIG_SYS_NAND_CS); + val |= DAVINCI_NANDFCR_4BIT_ECC_START; + __raw_writel(val, &davinci_emif_regs->nandfcr); + break; + case NAND_ECC_READSYN: + val = __raw_readl(&davinci_emif_regs->nand4bitecc[0]); + break; + default: + break; + } +} + +static u32 nand_davinci_4bit_readecc(struct mtd_info *mtd, unsigned int ecc[4]) +{ + int i; + + for (i = 0; i < 4; i++) { + ecc[i] = __raw_readl(&davinci_emif_regs->nand4bitecc[i]) & + NAND_4BITECC_MASK; + } + + return 0; +} + +static int nand_davinci_4bit_calculate_ecc(struct mtd_info *mtd, + const uint8_t *dat, + uint8_t *ecc_code) +{ + unsigned int hw_4ecc[4]; + unsigned int i; + + nand_davinci_4bit_readecc(mtd, hw_4ecc); + + /*Convert 10 bit ecc value to 8 bit */ + for (i = 0; i < 2; i++) { + unsigned int hw_ecc_low = hw_4ecc[i * 2]; + unsigned int hw_ecc_hi = hw_4ecc[(i * 2) + 1]; + + /* Take first 8 bits from val1 (count1=0) or val5 (count1=1) */ + *ecc_code++ = hw_ecc_low & 0xFF; + + /* + * Take 2 bits as LSB bits from val1 (count1=0) or val5 + * (count1=1) and 6 bits from val2 (count1=0) or + * val5 (count1=1) + */ + *ecc_code++ = + ((hw_ecc_low >> 8) & 0x3) | ((hw_ecc_low >> 14) & 0xFC); + + /* + * Take 4 bits from val2 (count1=0) or val5 (count1=1) and + * 4 bits from val3 (count1=0) or val6 (count1=1) + */ + *ecc_code++ = + ((hw_ecc_low >> 22) & 0xF) | ((hw_ecc_hi << 4) & 0xF0); + + /* + * Take 6 bits from val3(count1=0) or val6 (count1=1) and + * 2 bits from val4 (count1=0) or val7 (count1=1) + */ + *ecc_code++ = + ((hw_ecc_hi >> 4) & 0x3F) | ((hw_ecc_hi >> 10) & 0xC0); + + /* Take 8 bits from val4 (count1=0) or val7 (count1=1) */ + *ecc_code++ = (hw_ecc_hi >> 18) & 0xFF; + } + + return 0; +} + +static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + int i; + unsigned int hw_4ecc[4]; + unsigned int iserror; + unsigned short *ecc16; + unsigned int numerrors, erroraddress, errorvalue; + u32 val; + + /* + * Check for an ECC where all bytes are 0xFF. If this is the case, we + * will assume we are looking at an erased page and we should ignore + * the ECC. + */ + for (i = 0; i < 10; i++) { + if (read_ecc[i] != 0xFF) + break; + } + if (i == 10) + return 0; + + /* Convert 8 bit in to 10 bit */ + ecc16 = (unsigned short *)&read_ecc[0]; + + /* + * Write the parity values in the NAND Flash 4-bit ECC Load register. + * Write each parity value one at a time starting from 4bit_ecc_val8 + * to 4bit_ecc_val1. + */ + + /*Take 2 bits from 8th byte and 8 bits from 9th byte */ + __raw_writel(((ecc16[4]) >> 6) & 0x3FF, + &davinci_emif_regs->nand4biteccload); + + /* Take 4 bits from 7th byte and 6 bits from 8th byte */ + __raw_writel((((ecc16[3]) >> 12) & 0xF) | ((((ecc16[4])) << 4) & 0x3F0), + &davinci_emif_regs->nand4biteccload); + + /* Take 6 bits from 6th byte and 4 bits from 7th byte */ + __raw_writel((ecc16[3] >> 2) & 0x3FF, + &davinci_emif_regs->nand4biteccload); + + /* Take 8 bits from 5th byte and 2 bits from 6th byte */ + __raw_writel(((ecc16[2]) >> 8) | ((((ecc16[3])) << 8) & 0x300), + &davinci_emif_regs->nand4biteccload); + + /*Take 2 bits from 3rd byte and 8 bits from 4th byte */ + __raw_writel((((ecc16[1]) >> 14) & 0x3) | ((((ecc16[2])) << 2) & 0x3FC), + &davinci_emif_regs->nand4biteccload); + + /* Take 4 bits form 2nd bytes and 6 bits from 3rd bytes */ + __raw_writel(((ecc16[1]) >> 4) & 0x3FF, + &davinci_emif_regs->nand4biteccload); + + /* Take 6 bits from 1st byte and 4 bits from 2nd byte */ + __raw_writel((((ecc16[0]) >> 10) & 0x3F) | (((ecc16[1]) << 6) & 0x3C0), + &davinci_emif_regs->nand4biteccload); + + /* Take 10 bits from 0th and 1st bytes */ + __raw_writel((ecc16[0]) & 0x3FF, + &davinci_emif_regs->nand4biteccload); + + /* + * Perform a dummy read to the EMIF Revision Code and Status register. + * This is required to ensure time for syndrome calculation after + * writing the ECC values in previous step. + */ + + val = __raw_readl(&davinci_emif_regs->nandfsr); + + /* + * Read the syndrome from the NAND Flash 4-Bit ECC 1-4 registers. + * A syndrome value of 0 means no bit errors. If the syndrome is + * non-zero then go further otherwise return. + */ + nand_davinci_4bit_readecc(mtd, hw_4ecc); + + if (!(hw_4ecc[0] | hw_4ecc[1] | hw_4ecc[2] | hw_4ecc[3])) + return 0; + + /* + * Clear any previous address calculation by doing a dummy read of an + * error address register. + */ + val = __raw_readl(&davinci_emif_regs->nanderradd1); + + /* + * Set the addr_calc_st bit(bit no 13) in the NAND Flash Control + * register to 1. + */ + __raw_writel(DAVINCI_NANDFCR_4BIT_CALC_START, + &davinci_emif_regs->nandfcr); + + /* + * Wait for the corr_state field (bits 8 to 11) in the + * NAND Flash Status register to be not equal to 0x0, 0x1, 0x2, or 0x3. + * Otherwise ECC calculation has not even begun and the next loop might + * fail because of a false positive! + */ + i = NAND_TIMEOUT; + do { + val = __raw_readl(&davinci_emif_regs->nandfsr); + val &= 0xc00; + i--; + } while ((i > 0) && !val); + + /* + * Wait for the corr_state field (bits 8 to 11) in the + * NAND Flash Status register to be equal to 0x0, 0x1, 0x2, or 0x3. + */ + i = NAND_TIMEOUT; + do { + val = __raw_readl(&davinci_emif_regs->nandfsr); + val &= 0xc00; + i--; + } while ((i > 0) && val); + + iserror = __raw_readl(&davinci_emif_regs->nandfsr); + iserror &= EMIF_NANDFSR_ECC_STATE_MASK; + iserror = iserror >> 8; + + /* + * ECC_STATE_TOO_MANY_ERRS (0x1) means errors cannot be + * corrected (five or more errors). The number of errors + * calculated (err_num field) differs from the number of errors + * searched. ECC_STATE_ERR_CORR_COMP_P (0x2) means error + * correction complete (errors on bit 8 or 9). + * ECC_STATE_ERR_CORR_COMP_N (0x3) means error correction + * complete (error exists). + */ + + if (iserror == ECC_STATE_NO_ERR) { + val = __raw_readl(&davinci_emif_regs->nanderrval1); + return 0; + } else if (iserror == ECC_STATE_TOO_MANY_ERRS) { + val = __raw_readl(&davinci_emif_regs->nanderrval1); + return -EBADMSG; + } + + numerrors = ((__raw_readl(&davinci_emif_regs->nandfsr) >> 16) + & 0x3) + 1; + + /* Read the error address, error value and correct */ + for (i = 0; i < numerrors; i++) { + if (i > 1) { + erroraddress = + ((__raw_readl(&davinci_emif_regs->nanderradd2) >> + (16 * (i & 1))) & 0x3FF); + erroraddress = ((512 + 7) - erroraddress); + errorvalue = + ((__raw_readl(&davinci_emif_regs->nanderrval2) >> + (16 * (i & 1))) & 0xFF); + } else { + erroraddress = + ((__raw_readl(&davinci_emif_regs->nanderradd1) >> + (16 * (i & 1))) & 0x3FF); + erroraddress = ((512 + 7) - erroraddress); + errorvalue = + ((__raw_readl(&davinci_emif_regs->nanderrval1) >> + (16 * (i & 1))) & 0xFF); + } + /* xor the corrupt data with error value */ + if (erroraddress < 512) + dat[erroraddress] ^= errorvalue; + } + + return numerrors; +} +#endif /* CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST */ + +static int nand_davinci_dev_ready(struct mtd_info *mtd) +{ + return __raw_readl(&davinci_emif_regs->nandfsr) & 0x1; +} + +static void nand_flash_init(void) +{ + /* This is for DM6446 EVM and *very* similar. DO NOT GROW THIS! + * Instead, have your board_init() set EMIF timings, based on its + * knowledge of the clocks and what devices are hooked up ... and + * don't even do that unless no UBL handled it. + */ +#ifdef CONFIG_SOC_DM644X + u_int32_t acfg1 = 0x3ffffffc; + + /*------------------------------------------------------------------* + * NAND FLASH CHIP TIMEOUT @ 459 MHz * + * * + * AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz * + * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns * + * * + *------------------------------------------------------------------*/ + acfg1 = 0 + | (0 << 31) /* selectStrobe */ + | (0 << 30) /* extWait */ + | (1 << 26) /* writeSetup 10 ns */ + | (3 << 20) /* writeStrobe 40 ns */ + | (1 << 17) /* writeHold 10 ns */ + | (1 << 13) /* readSetup 10 ns */ + | (5 << 7) /* readStrobe 60 ns */ + | (1 << 4) /* readHold 10 ns */ + | (3 << 2) /* turnAround ?? ns */ + | (0 << 0) /* asyncSize 8-bit bus */ + ; + + __raw_writel(acfg1, &davinci_emif_regs->ab1cr); /* CS2 */ + + /* NAND flash on CS2 */ + __raw_writel(0x00000101, &davinci_emif_regs->nandfcr); +#endif +} + +void davinci_nand_init(struct nand_chip *nand) +{ +#if defined CONFIG_KEYSTONE_RBL_NAND + int i; + struct nand_ecclayout *layout; + + layout = &nand_keystone_rbl_4bit_layout_oobfirst; + layout->oobavail = 0; + for (i = 0; layout->oobfree[i].length && + i < ARRAY_SIZE(layout->oobfree); i++) + layout->oobavail += layout->oobfree[i].length; + + nand->write_page = nand_davinci_write_page; + nand->ecc.read_page = nand_davinci_read_page_hwecc; +#endif + nand->chip_delay = 0; +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + nand->bbt_options |= NAND_BBT_USE_FLASH; +#endif +#ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE + nand->options |= NAND_NO_SUBPAGE_WRITE; +#endif +#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT + nand->options |= NAND_BUSWIDTH_16; +#endif +#ifdef CONFIG_SYS_NAND_HW_ECC + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.size = 512; + nand->ecc.bytes = 3; + nand->ecc.strength = 1; + nand->ecc.calculate = nand_davinci_calculate_ecc; + nand->ecc.correct = nand_davinci_correct_data; + nand->ecc.hwctl = nand_davinci_enable_hwecc; +#else + nand->ecc.mode = NAND_ECC_SOFT; +#endif /* CONFIG_SYS_NAND_HW_ECC */ +#ifdef CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST + nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; + nand->ecc.size = 512; + nand->ecc.bytes = 10; + nand->ecc.strength = 4; + nand->ecc.calculate = nand_davinci_4bit_calculate_ecc; + nand->ecc.correct = nand_davinci_4bit_correct_data; + nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc; + nand->ecc.layout = &nand_davinci_4bit_layout_oobfirst; +#endif + /* Set address of hardware control function */ + nand->cmd_ctrl = nand_davinci_hwcontrol; + + nand->read_buf = nand_davinci_read_buf; + nand->write_buf = nand_davinci_write_buf; + + nand->dev_ready = nand_davinci_dev_ready; + + nand_flash_init(); +} + +int board_nand_init(struct nand_chip *chip) __attribute__((weak)); + +int board_nand_init(struct nand_chip *chip) +{ + davinci_nand_init(chip); + return 0; +} diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c new file mode 100644 index 0000000000..d1cac063f4 --- /dev/null +++ b/drivers/mtd/nand/raw/denali.c @@ -0,0 +1,1371 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Panasonic Corporation + * Copyright (C) 2013-2014, Altera Corporation + * Copyright (C) 2009-2010, Intel Corporation and its suppliers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "denali.h" + +static dma_addr_t dma_map_single(void *dev, void *ptr, size_t size, + enum dma_data_direction dir) +{ + unsigned long addr = (unsigned long)ptr; + + size = ALIGN(size, ARCH_DMA_MINALIGN); + + if (dir == DMA_FROM_DEVICE) + invalidate_dcache_range(addr, addr + size); + else + flush_dcache_range(addr, addr + size); + + return addr; +} + +static void dma_unmap_single(void *dev, dma_addr_t addr, size_t size, + enum dma_data_direction dir) +{ + size = ALIGN(size, ARCH_DMA_MINALIGN); + + if (dir != DMA_TO_DEVICE) + invalidate_dcache_range(addr, addr + size); +} + +static int dma_mapping_error(void *dev, dma_addr_t addr) +{ + return 0; +} + +#define DENALI_NAND_NAME "denali-nand" + +/* for Indexed Addressing */ +#define DENALI_INDEXED_CTRL 0x00 +#define DENALI_INDEXED_DATA 0x10 + +#define DENALI_MAP00 (0 << 26) /* direct access to buffer */ +#define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */ +#define DENALI_MAP10 (2 << 26) /* high-level control plane */ +#define DENALI_MAP11 (3 << 26) /* direct controller access */ + +/* MAP11 access cycle type */ +#define DENALI_MAP11_CMD ((DENALI_MAP11) | 0) /* command cycle */ +#define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) /* address cycle */ +#define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) /* data cycle */ + +/* MAP10 commands */ +#define DENALI_ERASE 0x01 + +#define DENALI_BANK(denali) ((denali)->active_bank << 24) + +#define DENALI_INVALID_BANK -1 +#define DENALI_NR_BANKS 4 + +/* + * The bus interface clock, clk_x, is phase aligned with the core clock. The + * clk_x is an integral multiple N of the core clk. The value N is configured + * at IP delivery time, and its available value is 4, 5, or 6. We need to align + * to the largest value to make it work with any possible configuration. + */ +#define DENALI_CLK_X_MULT 6 + +static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) +{ + return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand); +} + +/* + * Direct Addressing - the slave address forms the control information (command + * type, bank, block, and page address). The slave data is the actual data to + * be transferred. This mode requires 28 bits of address region allocated. + */ +static u32 denali_direct_read(struct denali_nand_info *denali, u32 addr) +{ + return ioread32(denali->host + addr); +} + +static void denali_direct_write(struct denali_nand_info *denali, u32 addr, + u32 data) +{ + iowrite32(data, denali->host + addr); +} + +/* + * Indexed Addressing - address translation module intervenes in passing the + * control information. This mode reduces the required address range. The + * control information and transferred data are latched by the registers in + * the translation module. + */ +static u32 denali_indexed_read(struct denali_nand_info *denali, u32 addr) +{ + iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); + return ioread32(denali->host + DENALI_INDEXED_DATA); +} + +static void denali_indexed_write(struct denali_nand_info *denali, u32 addr, + u32 data) +{ + iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); + iowrite32(data, denali->host + DENALI_INDEXED_DATA); +} + +/* + * Use the configuration feature register to determine the maximum number of + * banks that the hardware supports. + */ +static void denali_detect_max_banks(struct denali_nand_info *denali) +{ + uint32_t features = ioread32(denali->reg + FEATURES); + + denali->max_banks = 1 << FIELD_GET(FEATURES__N_BANKS, features); + + /* the encoding changed from rev 5.0 to 5.1 */ + if (denali->revision < 0x0501) + denali->max_banks <<= 1; +} + +static void __maybe_unused denali_enable_irq(struct denali_nand_info *denali) +{ + int i; + + for (i = 0; i < DENALI_NR_BANKS; i++) + iowrite32(U32_MAX, denali->reg + INTR_EN(i)); + iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE); +} + +static void __maybe_unused denali_disable_irq(struct denali_nand_info *denali) +{ + int i; + + for (i = 0; i < DENALI_NR_BANKS; i++) + iowrite32(0, denali->reg + INTR_EN(i)); + iowrite32(0, denali->reg + GLOBAL_INT_ENABLE); +} + +static void denali_clear_irq(struct denali_nand_info *denali, + int bank, uint32_t irq_status) +{ + /* write one to clear bits */ + iowrite32(irq_status, denali->reg + INTR_STATUS(bank)); +} + +static void denali_clear_irq_all(struct denali_nand_info *denali) +{ + int i; + + for (i = 0; i < DENALI_NR_BANKS; i++) + denali_clear_irq(denali, i, U32_MAX); +} + +static void __denali_check_irq(struct denali_nand_info *denali) +{ + uint32_t irq_status; + int i; + + for (i = 0; i < DENALI_NR_BANKS; i++) { + irq_status = ioread32(denali->reg + INTR_STATUS(i)); + denali_clear_irq(denali, i, irq_status); + + if (i != denali->active_bank) + continue; + + denali->irq_status |= irq_status; + } +} + +static void denali_reset_irq(struct denali_nand_info *denali) +{ + denali->irq_status = 0; + denali->irq_mask = 0; +} + +static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, + uint32_t irq_mask) +{ + unsigned long time_left = 1000000; + + while (time_left) { + __denali_check_irq(denali); + + if (irq_mask & denali->irq_status) + return denali->irq_status; + udelay(1); + time_left--; + } + + if (!time_left) { + dev_err(denali->dev, "timeout while waiting for irq 0x%x\n", + irq_mask); + return 0; + } + + return denali->irq_status; +} + +static uint32_t denali_check_irq(struct denali_nand_info *denali) +{ + __denali_check_irq(denali); + + return denali->irq_status; +} + +static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); + int i; + + for (i = 0; i < len; i++) + buf[i] = denali->host_read(denali, addr); +} + +static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); + int i; + + for (i = 0; i < len; i++) + denali->host_write(denali, addr, buf[i]); +} + +static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); + uint16_t *buf16 = (uint16_t *)buf; + int i; + + for (i = 0; i < len / 2; i++) + buf16[i] = denali->host_read(denali, addr); +} + +static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); + const uint16_t *buf16 = (const uint16_t *)buf; + int i; + + for (i = 0; i < len / 2; i++) + denali->host_write(denali, addr, buf16[i]); +} + +static uint8_t denali_read_byte(struct mtd_info *mtd) +{ + uint8_t byte; + + denali_read_buf(mtd, &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) +{ + uint16_t word; + + denali_read_buf16(mtd, (uint8_t *)&word, 2); + + return word; +} + +static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t type; + + if (ctrl & NAND_CLE) + type = DENALI_MAP11_CMD; + else if (ctrl & NAND_ALE) + type = DENALI_MAP11_ADDR; + else + return; + + /* + * Some commands are followed by chip->dev_ready or chip->waitfunc. + * irq_status must be cleared here to catch the R/B# interrupt later. + */ + if (ctrl & NAND_CTRL_CHANGE) + denali_reset_irq(denali); + + denali->host_write(denali, DENALI_BANK(denali) | type, dat); +} + +static int denali_dev_ready(struct mtd_info *mtd) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + return !!(denali_check_irq(denali) & INTR__INT_ACT); +} + +static int denali_check_erased_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + unsigned long uncor_ecc_flags, + unsigned int max_bitflips) +{ + uint8_t *ecc_code = chip->buffers->ecccode; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + int i, ret, stat; + + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; + + for (i = 0; i < ecc_steps; i++) { + if (!(uncor_ecc_flags & BIT(i))) + continue; + + stat = nand_check_erased_ecc_chunk(buf, ecc_size, + ecc_code, ecc_bytes, + NULL, 0, + chip->ecc.strength); + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } + + buf += ecc_size; + ecc_code += ecc_bytes; + } + + return max_bitflips; +} + +static int denali_hw_ecc_fixup(struct mtd_info *mtd, + struct denali_nand_info *denali, + unsigned long *uncor_ecc_flags) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int bank = denali->active_bank; + uint32_t ecc_cor; + unsigned int max_bitflips; + + ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank)); + ecc_cor >>= ECC_COR_INFO__SHIFT(bank); + + if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) { + /* + * This flag is set when uncorrectable error occurs at least in + * one ECC sector. We can not know "how many sectors", or + * "which sector(s)". We need erase-page check for all sectors. + */ + *uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0); + return 0; + } + + max_bitflips = FIELD_GET(ECC_COR_INFO__MAX_ERRORS, ecc_cor); + + /* + * The register holds the maximum of per-sector corrected bitflips. + * This is suitable for the return value of the ->read_page() callback. + * Unfortunately, we can not know the total number of corrected bits in + * the page. Increase the stats by max_bitflips. (compromised solution) + */ + mtd->ecc_stats.corrected += max_bitflips; + + return max_bitflips; +} + +static int denali_sw_ecc_fixup(struct mtd_info *mtd, + struct denali_nand_info *denali, + unsigned long *uncor_ecc_flags, uint8_t *buf) +{ + unsigned int ecc_size = denali->nand.ecc.size; + unsigned int bitflips = 0; + unsigned int max_bitflips = 0; + uint32_t err_addr, err_cor_info; + unsigned int err_byte, err_sector, err_device; + uint8_t err_cor_value; + unsigned int prev_sector = 0; + uint32_t irq_status; + + denali_reset_irq(denali); + + do { + err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS); + err_sector = FIELD_GET(ECC_ERROR_ADDRESS__SECTOR, err_addr); + err_byte = FIELD_GET(ECC_ERROR_ADDRESS__OFFSET, err_addr); + + err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO); + err_cor_value = FIELD_GET(ERR_CORRECTION_INFO__BYTE, + err_cor_info); + err_device = FIELD_GET(ERR_CORRECTION_INFO__DEVICE, + err_cor_info); + + /* reset the bitflip counter when crossing ECC sector */ + if (err_sector != prev_sector) + bitflips = 0; + + if (err_cor_info & ERR_CORRECTION_INFO__UNCOR) { + /* + * Check later if this is a real ECC error, or + * an erased sector. + */ + *uncor_ecc_flags |= BIT(err_sector); + } else if (err_byte < ecc_size) { + /* + * If err_byte is larger than ecc_size, means error + * happened in OOB, so we ignore it. It's no need for + * us to correct it err_device is represented the NAND + * error bits are happened in if there are more than + * one NAND connected. + */ + int offset; + unsigned int flips_in_byte; + + offset = (err_sector * ecc_size + err_byte) * + denali->devs_per_cs + err_device; + + /* correct the ECC error */ + flips_in_byte = hweight8(buf[offset] ^ err_cor_value); + buf[offset] ^= err_cor_value; + mtd->ecc_stats.corrected += flips_in_byte; + bitflips += flips_in_byte; + + max_bitflips = max(max_bitflips, bitflips); + } + + prev_sector = err_sector; + } while (!(err_cor_info & ERR_CORRECTION_INFO__LAST_ERR)); + + /* + * Once handle all ECC errors, controller will trigger an + * ECC_TRANSACTION_DONE interrupt. + */ + irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE); + if (!(irq_status & INTR__ECC_TRANSACTION_DONE)) + return -EIO; + + return max_bitflips; +} + +static void denali_setup_dma64(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int write) +{ + uint32_t mode; + const int page_count = 1; + + mode = DENALI_MAP10 | DENALI_BANK(denali) | page; + + /* DMA is a three step process */ + + /* + * 1. setup transfer type, interrupt when complete, + * burst len = 64 bytes, the number of pages + */ + denali->host_write(denali, mode, + 0x01002000 | (64 << 16) | (write << 8) | page_count); + + /* 2. set memory low address */ + denali->host_write(denali, mode, lower_32_bits(dma_addr)); + + /* 3. set memory high address */ + denali->host_write(denali, mode, upper_32_bits(dma_addr)); +} + +static void denali_setup_dma32(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int write) +{ + uint32_t mode; + const int page_count = 1; + + mode = DENALI_MAP10 | DENALI_BANK(denali); + + /* DMA is a four step process */ + + /* 1. setup transfer type and # of pages */ + denali->host_write(denali, mode | page, + 0x2000 | (write << 8) | page_count); + + /* 2. set memory high address bits 23:8 */ + denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200); + + /* 3. set memory low address bits 23:8 */ + denali->host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); + + /* 4. interrupt when complete, burst len = 64 bytes */ + denali->host_write(denali, mode | 0x14000, 0x2400); +} + +static int denali_pio_read(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw) +{ + u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; + uint32_t *buf32 = (uint32_t *)buf; + uint32_t irq_status, ecc_err_mask; + int i; + + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + ecc_err_mask = INTR__ECC_UNCOR_ERR; + else + ecc_err_mask = INTR__ECC_ERR; + + denali_reset_irq(denali); + + for (i = 0; i < size / 4; i++) + *buf32++ = denali->host_read(denali, addr); + + irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC); + if (!(irq_status & INTR__PAGE_XFER_INC)) + return -EIO; + + if (irq_status & INTR__ERASED_PAGE) + memset(buf, 0xff, size); + + return irq_status & ecc_err_mask ? -EBADMSG : 0; +} + +static int denali_pio_write(struct denali_nand_info *denali, + const void *buf, size_t size, int page, int raw) +{ + u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; + const uint32_t *buf32 = (uint32_t *)buf; + uint32_t irq_status; + int i; + + denali_reset_irq(denali); + + for (i = 0; i < size / 4; i++) + denali->host_write(denali, addr, *buf32++); + + irq_status = denali_wait_for_irq(denali, + INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL); + if (!(irq_status & INTR__PROGRAM_COMP)) + return -EIO; + + return 0; +} + +static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) +{ + if (write) + return denali_pio_write(denali, buf, size, page, raw); + else + return denali_pio_read(denali, buf, size, page, raw); +} + +static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) +{ + dma_addr_t dma_addr; + uint32_t irq_mask, irq_status, ecc_err_mask; + enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + int ret = 0; + + dma_addr = dma_map_single(denali->dev, buf, size, dir); + if (dma_mapping_error(denali->dev, dma_addr)) { + dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n"); + return denali_pio_xfer(denali, buf, size, page, raw, write); + } + + if (write) { + /* + * INTR__PROGRAM_COMP is never asserted for the DMA transfer. + * We can use INTR__DMA_CMD_COMP instead. This flag is asserted + * when the page program is completed. + */ + irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; + ecc_err_mask = 0; + } else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) { + irq_mask = INTR__DMA_CMD_COMP; + ecc_err_mask = INTR__ECC_UNCOR_ERR; + } else { + irq_mask = INTR__DMA_CMD_COMP; + ecc_err_mask = INTR__ECC_ERR; + } + + iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE); + + denali_reset_irq(denali); + denali->setup_dma(denali, dma_addr, page, write); + + irq_status = denali_wait_for_irq(denali, irq_mask); + if (!(irq_status & INTR__DMA_CMD_COMP)) + ret = -EIO; + else if (irq_status & ecc_err_mask) + ret = -EBADMSG; + + iowrite32(0, denali->reg + DMA_ENABLE); + + dma_unmap_single(denali->dev, dma_addr, size, dir); + + if (irq_status & INTR__ERASED_PAGE) + memset(buf, 0xff, size); + + return ret; +} + +static int denali_data_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) +{ + iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); + iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0, + denali->reg + TRANSFER_SPARE_REG); + + if (denali->dma_avail) + return denali_dma_xfer(denali, buf, size, page, raw, write); + else + return denali_pio_xfer(denali, buf, size, page, raw, write); +} + +static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, + int page, int write) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0; + unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT; + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + uint8_t *bufpoi = chip->oob_poi; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + int oob_skip = denali->oob_skip_bytes; + size_t size = writesize + oobsize; + int i, pos, len; + + /* BBM at the beginning of the OOB area */ + chip->cmdfunc(mtd, start_cmd, writesize, page); + if (write) + chip->write_buf(mtd, bufpoi, oob_skip); + else + chip->read_buf(mtd, bufpoi, oob_skip); + bufpoi += oob_skip; + + /* OOB ECC */ + for (i = 0; i < ecc_steps; i++) { + pos = ecc_size + i * (ecc_size + ecc_bytes); + len = ecc_bytes; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + chip->cmdfunc(mtd, rnd_cmd, pos, -1); + if (write) + chip->write_buf(mtd, bufpoi, len); + else + chip->read_buf(mtd, bufpoi, len); + bufpoi += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1); + if (write) + chip->write_buf(mtd, bufpoi, len); + else + chip->read_buf(mtd, bufpoi, len); + bufpoi += len; + } + } + + /* OOB free */ + len = oobsize - (bufpoi - chip->oob_poi); + chip->cmdfunc(mtd, rnd_cmd, size - len, -1); + if (write) + chip->write_buf(mtd, bufpoi, len); + else + chip->read_buf(mtd, bufpoi, len); +} + +static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + void *tmp_buf = denali->buf; + int oob_skip = denali->oob_skip_bytes; + size_t size = writesize + oobsize; + int ret, i, pos, len; + + ret = denali_data_xfer(denali, tmp_buf, size, page, 1, 0); + if (ret) + return ret; + + /* Arrange the buffer for syndrome payload/ecc layout */ + if (buf) { + for (i = 0; i < ecc_steps; i++) { + pos = i * (ecc_size + ecc_bytes); + len = ecc_size; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(buf, tmp_buf + pos, len); + buf += len; + if (len < ecc_size) { + len = ecc_size - len; + memcpy(buf, tmp_buf + writesize + oob_skip, + len); + buf += len; + } + } + } + + if (oob_required) { + uint8_t *oob = chip->oob_poi; + + /* BBM at the beginning of the OOB area */ + memcpy(oob, tmp_buf + writesize, oob_skip); + oob += oob_skip; + + /* OOB ECC */ + for (i = 0; i < ecc_steps; i++) { + pos = ecc_size + i * (ecc_size + ecc_bytes); + len = ecc_bytes; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(oob, tmp_buf + pos, len); + oob += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + memcpy(oob, tmp_buf + writesize + oob_skip, + len); + oob += len; + } + } + + /* OOB free */ + len = oobsize - (oob - chip->oob_poi); + memcpy(oob, tmp_buf + size - len, len); + } + + return 0; +} + +static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + denali_oob_xfer(mtd, chip, page, 0); + + return 0; +} + +static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + int status; + + denali_reset_irq(denali); + + denali_oob_xfer(mtd, chip, page, 1); + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + unsigned long uncor_ecc_flags = 0; + int stat = 0; + int ret; + + ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0); + if (ret && ret != -EBADMSG) + return ret; + + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); + else if (ret == -EBADMSG) + stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf); + + if (stat < 0) + return stat; + + if (uncor_ecc_flags) { + ret = denali_read_oob(mtd, chip, page); + if (ret) + return ret; + + stat = denali_check_erased_page(mtd, chip, buf, + uncor_ecc_flags, stat); + } + + 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) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + void *tmp_buf = denali->buf; + int oob_skip = denali->oob_skip_bytes; + size_t size = writesize + oobsize; + int i, pos, len; + + /* + * Fill the buffer with 0xff first except the full page transfer. + * This simplifies the logic. + */ + if (!buf || !oob_required) + memset(tmp_buf, 0xff, size); + + /* Arrange the buffer for syndrome payload/ecc layout */ + if (buf) { + for (i = 0; i < ecc_steps; i++) { + pos = i * (ecc_size + ecc_bytes); + len = ecc_size; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(tmp_buf + pos, buf, len); + buf += len; + if (len < ecc_size) { + len = ecc_size - len; + memcpy(tmp_buf + writesize + oob_skip, buf, + len); + buf += len; + } + } + } + + if (oob_required) { + const uint8_t *oob = chip->oob_poi; + + /* BBM at the beginning of the OOB area */ + memcpy(tmp_buf + writesize, oob, oob_skip); + oob += oob_skip; + + /* OOB ECC */ + for (i = 0; i < ecc_steps; i++) { + pos = ecc_size + i * (ecc_size + ecc_bytes); + len = ecc_bytes; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(tmp_buf + pos, oob, len); + oob += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + memcpy(tmp_buf + writesize + oob_skip, oob, + len); + oob += len; + } + } + + /* OOB free */ + len = oobsize - (oob - chip->oob_poi); + memcpy(tmp_buf + size - len, oob, len); + } + + 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) +{ + 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) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + denali->active_bank = chip; +} + +static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t irq_status; + + /* R/B# pin transitioned from low to high? */ + irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); + + return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; +} + +static int denali_erase(struct mtd_info *mtd, int page) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t irq_status; + + denali_reset_irq(denali); + + denali->host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page, + DENALI_ERASE); + + /* wait for erase to complete or failure to occur */ + irq_status = denali_wait_for_irq(denali, + INTR__ERASE_COMP | INTR__ERASE_FAIL); + + return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL; +} + +static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, + const struct nand_data_interface *conf) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + const struct nand_sdr_timings *timings; + unsigned long t_clk; + int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data; + int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup; + int addr_2_data_mask; + uint32_t tmp; + + timings = nand_get_sdr_timings(conf); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + /* clk_x period in picoseconds */ + t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate); + if (!t_clk) + return -EINVAL; + + if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) + return 0; + + /* tREA -> ACC_CLKS */ + acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk); + acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE); + + tmp = ioread32(denali->reg + ACC_CLKS); + tmp &= ~ACC_CLKS__VALUE; + tmp |= FIELD_PREP(ACC_CLKS__VALUE, acc_clks); + iowrite32(tmp, denali->reg + ACC_CLKS); + + /* tRWH -> RE_2_WE */ + re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk); + re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE); + + tmp = ioread32(denali->reg + RE_2_WE); + tmp &= ~RE_2_WE__VALUE; + tmp |= FIELD_PREP(RE_2_WE__VALUE, re_2_we); + iowrite32(tmp, denali->reg + RE_2_WE); + + /* tRHZ -> RE_2_RE */ + re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk); + re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE); + + tmp = ioread32(denali->reg + RE_2_RE); + tmp &= ~RE_2_RE__VALUE; + tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re); + iowrite32(tmp, denali->reg + RE_2_RE); + + /* + * tCCS, tWHR -> WE_2_RE + * + * With WE_2_RE properly set, the Denali controller automatically takes + * care of the delay; the driver need not set NAND_WAIT_TCCS. + */ + we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min), + t_clk); + we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE); + + tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE); + tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE; + tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re); + iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE); + + /* tADL -> ADDR_2_DATA */ + + /* for older versions, ADDR_2_DATA is only 6 bit wide */ + addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; + if (denali->revision < 0x0501) + addr_2_data_mask >>= 1; + + addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk); + addr_2_data = min_t(int, addr_2_data, addr_2_data_mask); + + tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA); + tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; + tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, addr_2_data); + iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA); + + /* tREH, tWH -> RDWR_EN_HI_CNT */ + rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min), + t_clk); + rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE); + + tmp = ioread32(denali->reg + RDWR_EN_HI_CNT); + tmp &= ~RDWR_EN_HI_CNT__VALUE; + tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi); + iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT); + + /* tRP, tWP -> RDWR_EN_LO_CNT */ + rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), + t_clk); + rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min), + t_clk); + rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT); + rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi); + rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE); + + tmp = ioread32(denali->reg + RDWR_EN_LO_CNT); + tmp &= ~RDWR_EN_LO_CNT__VALUE; + tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo); + iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT); + + /* tCS, tCEA -> CS_SETUP_CNT */ + cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo, + (int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks, + 0); + cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE); + + tmp = ioread32(denali->reg + CS_SETUP_CNT); + tmp &= ~CS_SETUP_CNT__VALUE; + tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup); + iowrite32(tmp, denali->reg + CS_SETUP_CNT); + + return 0; +} + +static void denali_reset_banks(struct denali_nand_info *denali) +{ + u32 irq_status; + int i; + + for (i = 0; i < denali->max_banks; i++) { + denali->active_bank = i; + + denali_reset_irq(denali); + + iowrite32(DEVICE_RESET__BANK(i), + denali->reg + DEVICE_RESET); + + irq_status = denali_wait_for_irq(denali, + INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT); + if (!(irq_status & INTR__INT_ACT)) + break; + } + + dev_dbg(denali->dev, "%d chips connected\n", i); + denali->max_banks = i; +} + +static void denali_hw_init(struct denali_nand_info *denali) +{ + /* + * The REVISION register may not be reliable. Platforms are allowed to + * override it. + */ + if (!denali->revision) + denali->revision = swab16(ioread32(denali->reg + REVISION)); + + /* + * tell driver how many bit controller will skip before writing + * ECC code in OOB. This is normally used for bad block marker + */ + denali->oob_skip_bytes = CONFIG_NAND_DENALI_SPARE_AREA_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); + + iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); +} + +int denali_calc_ecc_bytes(int step_size, int strength) +{ + /* BCH code. Denali requires ecc.bytes to be multiple of 2 */ + return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2; +} +EXPORT_SYMBOL(denali_calc_ecc_bytes); + +static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip, + struct denali_nand_info *denali) +{ + int oobavail = mtd->oobsize - denali->oob_skip_bytes; + int ret; + + /* + * If .size and .strength are already set (usually by DT), + * check if they are supported by this controller. + */ + if (chip->ecc.size && chip->ecc.strength) + return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail); + + /* + * We want .size and .strength closest to the chip's requirement + * unless NAND_ECC_MAXIMIZE is requested. + */ + if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) { + ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail); + if (!ret) + return 0; + } + + /* Max ECC strength is the last thing we can do */ + return nand_maximize_ecc(chip, denali->ecc_caps, oobavail); +} + +static struct nand_ecclayout nand_oob; + +static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + struct nand_chip *chip = mtd_to_nand(mtd); + + if (section) + return -ERANGE; + + oobregion->offset = denali->oob_skip_bytes; + oobregion->length = chip->ecc.total; + + return 0; +} + +static int denali_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + struct nand_chip *chip = mtd_to_nand(mtd); + + if (section) + return -ERANGE; + + oobregion->offset = chip->ecc.total + denali->oob_skip_bytes; + oobregion->length = mtd->oobsize - oobregion->offset; + + return 0; +} + +static const struct mtd_ooblayout_ops denali_ooblayout_ops = { + .ecc = denali_ooblayout_ecc, + .free = denali_ooblayout_free, +}; + +static int denali_multidev_fixup(struct denali_nand_info *denali) +{ + struct nand_chip *chip = &denali->nand; + struct mtd_info *mtd = nand_to_mtd(chip); + + /* + * Support for multi device: + * When the IP configuration is x16 capable and two x8 chips are + * connected in parallel, DEVICES_CONNECTED should be set to 2. + * In this case, the core framework knows nothing about this fact, + * so we should tell it the _logical_ pagesize and anything necessary. + */ + denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED); + + /* + * On some SoCs, DEVICES_CONNECTED is not auto-detected. + * For those, DEVICES_CONNECTED is left to 0. Set 1 if it is the case. + */ + if (denali->devs_per_cs == 0) { + denali->devs_per_cs = 1; + iowrite32(1, denali->reg + DEVICES_CONNECTED); + } + + if (denali->devs_per_cs == 1) + return 0; + + if (denali->devs_per_cs != 2) { + dev_err(denali->dev, "unsupported number of devices %d\n", + denali->devs_per_cs); + return -EINVAL; + } + + /* 2 chips in parallel */ + mtd->size <<= 1; + mtd->erasesize <<= 1; + mtd->writesize <<= 1; + mtd->oobsize <<= 1; + chip->chipsize <<= 1; + chip->page_shift += 1; + chip->phys_erase_shift += 1; + chip->bbt_erase_shift += 1; + chip->chip_shift += 1; + chip->pagemask <<= 1; + chip->ecc.size <<= 1; + chip->ecc.bytes <<= 1; + chip->ecc.strength <<= 1; + denali->oob_skip_bytes <<= 1; + + return 0; +} + +int denali_init(struct denali_nand_info *denali) +{ + struct nand_chip *chip = &denali->nand; + struct mtd_info *mtd = nand_to_mtd(chip); + u32 features = ioread32(denali->reg + FEATURES); + int ret; + + denali_hw_init(denali); + + denali_clear_irq_all(denali); + + denali_reset_banks(denali); + + denali->active_bank = DENALI_INVALID_BANK; + + chip->flash_node = dev_of_offset(denali->dev); + /* Fallback to the default name if DT did not give "label" property */ + if (!mtd->name) + mtd->name = "denali-nand"; + + chip->select_chip = denali_select_chip; + chip->read_byte = denali_read_byte; + chip->write_byte = denali_write_byte; + chip->read_word = denali_read_word; + chip->cmd_ctrl = denali_cmd_ctrl; + chip->dev_ready = denali_dev_ready; + chip->waitfunc = denali_waitfunc; + + if (features & FEATURES__INDEX_ADDR) { + denali->host_read = denali_indexed_read; + denali->host_write = denali_indexed_write; + } else { + denali->host_read = denali_direct_read; + denali->host_write = denali_direct_write; + } + + /* clk rate info is needed for setup_data_interface */ + if (denali->clk_x_rate) + chip->setup_data_interface = denali_setup_data_interface; + + ret = nand_scan_ident(mtd, denali->max_banks, NULL); + if (ret) + return ret; + + if (ioread32(denali->reg + FEATURES) & FEATURES__DMA) + denali->dma_avail = 1; + + if (denali->dma_avail) { + chip->buf_align = ARCH_DMA_MINALIGN; + if (denali->caps & DENALI_CAP_DMA_64BIT) + denali->setup_dma = denali_setup_dma64; + else + denali->setup_dma = denali_setup_dma32; + } else { + chip->buf_align = 4; + } + + chip->options |= NAND_USE_BOUNCE_BUFFER; + chip->bbt_options |= NAND_BBT_USE_FLASH; + chip->bbt_options |= NAND_BBT_NO_OOB; + denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; + + /* no subpage writes on denali */ + chip->options |= NAND_NO_SUBPAGE_WRITE; + + ret = denali_ecc_setup(mtd, chip, denali); + if (ret) { + dev_err(denali->dev, "Failed to setup ECC settings.\n"); + return ret; + } + + dev_dbg(denali->dev, + "chosen ECC settings: step=%d, strength=%d, bytes=%d\n", + chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); + + iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) | + FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength), + denali->reg + ECC_CORRECTION); + iowrite32(mtd->erasesize / mtd->writesize, + denali->reg + PAGES_PER_BLOCK); + iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, + denali->reg + DEVICE_WIDTH); + iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG, + denali->reg + TWO_ROW_ADDR_CYCLES); + iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE); + iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE); + + iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE); + iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE); + /* chip->ecc.steps is set by nand_scan_tail(); not available here */ + iowrite32(mtd->writesize / chip->ecc.size, + denali->reg + CFG_NUM_DATA_BLOCKS); + + mtd_set_ooblayout(mtd, &denali_ooblayout_ops); + + nand_oob.eccbytes = denali->nand.ecc.bytes; + denali->nand.ecc.layout = &nand_oob; + + if (chip->options & NAND_BUSWIDTH_16) { + chip->read_buf = denali_read_buf16; + chip->write_buf = denali_write_buf16; + } else { + chip->read_buf = denali_read_buf; + chip->write_buf = denali_write_buf; + } + chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS; + chip->ecc.read_page = denali_read_page; + chip->ecc.read_page_raw = denali_read_page_raw; + chip->ecc.write_page = denali_write_page; + 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; + + ret = denali_multidev_fixup(denali); + if (ret) + return ret; + + /* + * This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not + * use devm_kmalloc() because the memory allocated by devm_ does not + * guarantee DMA-safe alignment. + */ + denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!denali->buf) + return -ENOMEM; + + ret = nand_scan_tail(mtd); + if (ret) + goto free_buf; + + ret = nand_register(0, mtd); + if (ret) { + dev_err(denali->dev, "Failed to register MTD: %d\n", ret); + goto free_buf; + } + return 0; + +free_buf: + kfree(denali->buf); + + return ret; +} diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h new file mode 100644 index 0000000000..9b797beffa --- /dev/null +++ b/drivers/mtd/nand/raw/denali.h @@ -0,0 +1,325 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2013-2014 Altera Corporation + * Copyright (C) 2009-2010, Intel Corporation and its suppliers. + */ + +#ifndef __DENALI_H__ +#define __DENALI_H__ + +#include +#include +#include + +#define DEVICE_RESET 0x0 +#define DEVICE_RESET__BANK(bank) BIT(bank) + +#define TRANSFER_SPARE_REG 0x10 +#define TRANSFER_SPARE_REG__FLAG BIT(0) + +#define LOAD_WAIT_CNT 0x20 +#define LOAD_WAIT_CNT__VALUE GENMASK(15, 0) + +#define PROGRAM_WAIT_CNT 0x30 +#define PROGRAM_WAIT_CNT__VALUE GENMASK(15, 0) + +#define ERASE_WAIT_CNT 0x40 +#define ERASE_WAIT_CNT__VALUE GENMASK(15, 0) + +#define INT_MON_CYCCNT 0x50 +#define INT_MON_CYCCNT__VALUE GENMASK(15, 0) + +#define RB_PIN_ENABLED 0x60 +#define RB_PIN_ENABLED__BANK(bank) BIT(bank) + +#define MULTIPLANE_OPERATION 0x70 +#define MULTIPLANE_OPERATION__FLAG BIT(0) + +#define MULTIPLANE_READ_ENABLE 0x80 +#define MULTIPLANE_READ_ENABLE__FLAG BIT(0) + +#define COPYBACK_DISABLE 0x90 +#define COPYBACK_DISABLE__FLAG BIT(0) + +#define CACHE_WRITE_ENABLE 0xa0 +#define CACHE_WRITE_ENABLE__FLAG BIT(0) + +#define CACHE_READ_ENABLE 0xb0 +#define CACHE_READ_ENABLE__FLAG BIT(0) + +#define PREFETCH_MODE 0xc0 +#define PREFETCH_MODE__PREFETCH_EN BIT(0) +#define PREFETCH_MODE__PREFETCH_BURST_LENGTH GENMASK(15, 4) + +#define CHIP_ENABLE_DONT_CARE 0xd0 +#define CHIP_EN_DONT_CARE__FLAG BIT(0) + +#define ECC_ENABLE 0xe0 +#define ECC_ENABLE__FLAG BIT(0) + +#define GLOBAL_INT_ENABLE 0xf0 +#define GLOBAL_INT_EN_FLAG BIT(0) + +#define TWHR2_AND_WE_2_RE 0x100 +#define TWHR2_AND_WE_2_RE__WE_2_RE GENMASK(5, 0) +#define TWHR2_AND_WE_2_RE__TWHR2 GENMASK(13, 8) + +#define TCWAW_AND_ADDR_2_DATA 0x110 +/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */ +#define TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA GENMASK(6, 0) +#define TCWAW_AND_ADDR_2_DATA__TCWAW GENMASK(13, 8) + +#define RE_2_WE 0x120 +#define RE_2_WE__VALUE GENMASK(5, 0) + +#define ACC_CLKS 0x130 +#define ACC_CLKS__VALUE GENMASK(3, 0) + +#define NUMBER_OF_PLANES 0x140 +#define NUMBER_OF_PLANES__VALUE GENMASK(2, 0) + +#define PAGES_PER_BLOCK 0x150 +#define PAGES_PER_BLOCK__VALUE GENMASK(15, 0) + +#define DEVICE_WIDTH 0x160 +#define DEVICE_WIDTH__VALUE GENMASK(1, 0) + +#define DEVICE_MAIN_AREA_SIZE 0x170 +#define DEVICE_MAIN_AREA_SIZE__VALUE GENMASK(15, 0) + +#define DEVICE_SPARE_AREA_SIZE 0x180 +#define DEVICE_SPARE_AREA_SIZE__VALUE GENMASK(15, 0) + +#define TWO_ROW_ADDR_CYCLES 0x190 +#define TWO_ROW_ADDR_CYCLES__FLAG BIT(0) + +#define MULTIPLANE_ADDR_RESTRICT 0x1a0 +#define MULTIPLANE_ADDR_RESTRICT__FLAG BIT(0) + +#define ECC_CORRECTION 0x1b0 +#define ECC_CORRECTION__VALUE GENMASK(4, 0) +#define ECC_CORRECTION__ERASE_THRESHOLD GENMASK(31, 16) + +#define READ_MODE 0x1c0 +#define READ_MODE__VALUE GENMASK(3, 0) + +#define WRITE_MODE 0x1d0 +#define WRITE_MODE__VALUE GENMASK(3, 0) + +#define COPYBACK_MODE 0x1e0 +#define COPYBACK_MODE__VALUE GENMASK(3, 0) + +#define RDWR_EN_LO_CNT 0x1f0 +#define RDWR_EN_LO_CNT__VALUE GENMASK(4, 0) + +#define RDWR_EN_HI_CNT 0x200 +#define RDWR_EN_HI_CNT__VALUE GENMASK(4, 0) + +#define MAX_RD_DELAY 0x210 +#define MAX_RD_DELAY__VALUE GENMASK(3, 0) + +#define CS_SETUP_CNT 0x220 +#define CS_SETUP_CNT__VALUE GENMASK(4, 0) +#define CS_SETUP_CNT__TWB GENMASK(17, 12) + +#define SPARE_AREA_SKIP_BYTES 0x230 +#define SPARE_AREA_SKIP_BYTES__VALUE GENMASK(5, 0) + +#define SPARE_AREA_MARKER 0x240 +#define SPARE_AREA_MARKER__VALUE GENMASK(15, 0) + +#define DEVICES_CONNECTED 0x250 +#define DEVICES_CONNECTED__VALUE GENMASK(2, 0) + +#define DIE_MASK 0x260 +#define DIE_MASK__VALUE GENMASK(7, 0) + +#define FIRST_BLOCK_OF_NEXT_PLANE 0x270 +#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE GENMASK(15, 0) + +#define WRITE_PROTECT 0x280 +#define WRITE_PROTECT__FLAG BIT(0) + +#define RE_2_RE 0x290 +#define RE_2_RE__VALUE GENMASK(5, 0) + +#define MANUFACTURER_ID 0x300 +#define MANUFACTURER_ID__VALUE GENMASK(7, 0) + +#define DEVICE_ID 0x310 +#define DEVICE_ID__VALUE GENMASK(7, 0) + +#define DEVICE_PARAM_0 0x320 +#define DEVICE_PARAM_0__VALUE GENMASK(7, 0) + +#define DEVICE_PARAM_1 0x330 +#define DEVICE_PARAM_1__VALUE GENMASK(7, 0) + +#define DEVICE_PARAM_2 0x340 +#define DEVICE_PARAM_2__VALUE GENMASK(7, 0) + +#define LOGICAL_PAGE_DATA_SIZE 0x350 +#define LOGICAL_PAGE_DATA_SIZE__VALUE GENMASK(15, 0) + +#define LOGICAL_PAGE_SPARE_SIZE 0x360 +#define LOGICAL_PAGE_SPARE_SIZE__VALUE GENMASK(15, 0) + +#define REVISION 0x370 +#define REVISION__VALUE GENMASK(15, 0) + +#define ONFI_DEVICE_FEATURES 0x380 +#define ONFI_DEVICE_FEATURES__VALUE GENMASK(5, 0) + +#define ONFI_OPTIONAL_COMMANDS 0x390 +#define ONFI_OPTIONAL_COMMANDS__VALUE GENMASK(5, 0) + +#define ONFI_TIMING_MODE 0x3a0 +#define ONFI_TIMING_MODE__VALUE GENMASK(5, 0) + +#define ONFI_PGM_CACHE_TIMING_MODE 0x3b0 +#define ONFI_PGM_CACHE_TIMING_MODE__VALUE GENMASK(5, 0) + +#define ONFI_DEVICE_NO_OF_LUNS 0x3c0 +#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS GENMASK(7, 0) +#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE BIT(8) + +#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L 0x3d0 +#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE GENMASK(15, 0) + +#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U 0x3e0 +#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE GENMASK(15, 0) + +#define FEATURES 0x3f0 +#define FEATURES__N_BANKS GENMASK(1, 0) +#define FEATURES__ECC_MAX_ERR GENMASK(5, 2) +#define FEATURES__DMA BIT(6) +#define FEATURES__CMD_DMA BIT(7) +#define FEATURES__PARTITION BIT(8) +#define FEATURES__XDMA_SIDEBAND BIT(9) +#define FEATURES__GPREG BIT(10) +#define FEATURES__INDEX_ADDR BIT(11) + +#define TRANSFER_MODE 0x400 +#define TRANSFER_MODE__VALUE GENMASK(1, 0) + +#define INTR_STATUS(bank) (0x410 + (bank) * 0x50) +#define INTR_EN(bank) (0x420 + (bank) * 0x50) +/* bit[1:0] is used differently depending on IP version */ +#define INTR__ECC_UNCOR_ERR BIT(0) /* new IP */ +#define INTR__ECC_TRANSACTION_DONE BIT(0) /* old IP */ +#define INTR__ECC_ERR BIT(1) /* old IP */ +#define INTR__DMA_CMD_COMP BIT(2) +#define INTR__TIME_OUT BIT(3) +#define INTR__PROGRAM_FAIL BIT(4) +#define INTR__ERASE_FAIL BIT(5) +#define INTR__LOAD_COMP BIT(6) +#define INTR__PROGRAM_COMP BIT(7) +#define INTR__ERASE_COMP BIT(8) +#define INTR__PIPE_CPYBCK_CMD_COMP BIT(9) +#define INTR__LOCKED_BLK BIT(10) +#define INTR__UNSUP_CMD BIT(11) +#define INTR__INT_ACT BIT(12) +#define INTR__RST_COMP BIT(13) +#define INTR__PIPE_CMD_ERR BIT(14) +#define INTR__PAGE_XFER_INC BIT(15) +#define INTR__ERASED_PAGE BIT(16) + +#define PAGE_CNT(bank) (0x430 + (bank) * 0x50) +#define ERR_PAGE_ADDR(bank) (0x440 + (bank) * 0x50) +#define ERR_BLOCK_ADDR(bank) (0x450 + (bank) * 0x50) + +#define ECC_THRESHOLD 0x600 +#define ECC_THRESHOLD__VALUE GENMASK(9, 0) + +#define ECC_ERROR_BLOCK_ADDRESS 0x610 +#define ECC_ERROR_BLOCK_ADDRESS__VALUE GENMASK(15, 0) + +#define ECC_ERROR_PAGE_ADDRESS 0x620 +#define ECC_ERROR_PAGE_ADDRESS__VALUE GENMASK(11, 0) +#define ECC_ERROR_PAGE_ADDRESS__BANK GENMASK(15, 12) + +#define ECC_ERROR_ADDRESS 0x630 +#define ECC_ERROR_ADDRESS__OFFSET GENMASK(11, 0) +#define ECC_ERROR_ADDRESS__SECTOR GENMASK(15, 12) + +#define ERR_CORRECTION_INFO 0x640 +#define ERR_CORRECTION_INFO__BYTE GENMASK(7, 0) +#define ERR_CORRECTION_INFO__DEVICE GENMASK(11, 8) +#define ERR_CORRECTION_INFO__UNCOR BIT(14) +#define ERR_CORRECTION_INFO__LAST_ERR BIT(15) + +#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10) +#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8) +#define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0) +#define ECC_COR_INFO__UNCOR_ERR BIT(7) + +#define CFG_DATA_BLOCK_SIZE 0x6b0 + +#define CFG_LAST_DATA_BLOCK_SIZE 0x6c0 + +#define CFG_NUM_DATA_BLOCKS 0x6d0 + +#define CFG_META_DATA_SIZE 0x6e0 + +#define DMA_ENABLE 0x700 +#define DMA_ENABLE__FLAG BIT(0) + +#define IGNORE_ECC_DONE 0x710 +#define IGNORE_ECC_DONE__FLAG BIT(0) + +#define DMA_INTR 0x720 +#define DMA_INTR_EN 0x730 +#define DMA_INTR__TARGET_ERROR BIT(0) +#define DMA_INTR__DESC_COMP_CHANNEL0 BIT(1) +#define DMA_INTR__DESC_COMP_CHANNEL1 BIT(2) +#define DMA_INTR__DESC_COMP_CHANNEL2 BIT(3) +#define DMA_INTR__DESC_COMP_CHANNEL3 BIT(4) +#define DMA_INTR__MEMCOPY_DESC_COMP BIT(5) + +#define TARGET_ERR_ADDR_LO 0x740 +#define TARGET_ERR_ADDR_LO__VALUE GENMASK(15, 0) + +#define TARGET_ERR_ADDR_HI 0x750 +#define TARGET_ERR_ADDR_HI__VALUE GENMASK(15, 0) + +#define CHNL_ACTIVE 0x760 +#define CHNL_ACTIVE__CHANNEL0 BIT(0) +#define CHNL_ACTIVE__CHANNEL1 BIT(1) +#define CHNL_ACTIVE__CHANNEL2 BIT(2) +#define CHNL_ACTIVE__CHANNEL3 BIT(3) + +struct udevice; + +struct denali_nand_info { + struct nand_chip nand; + unsigned long clk_x_rate; /* bus interface clock rate */ + int active_bank; /* currently selected bank */ + struct udevice *dev; + uint32_t page; + void __iomem *reg; /* Register Interface */ + void __iomem *host; /* Host Data/Command Interface */ + u32 irq_mask; /* interrupts we are waiting for */ + u32 irq_status; /* interrupts that have happened */ + int irq; + void *buf; /* for syndrome layout conversion */ + dma_addr_t dma_addr; + int dma_avail; /* can support DMA? */ + int devs_per_cs; /* devices connected in parallel */ + int oob_skip_bytes; /* number of bytes reserved for BBM */ + int max_banks; + unsigned int revision; /* IP revision */ + unsigned int caps; /* IP capability (or quirk) */ + const struct nand_ecc_caps *ecc_caps; + u32 (*host_read)(struct denali_nand_info *denali, u32 addr); + void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data); + void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr, + int page, int write); +}; + +#define DENALI_CAP_HW_ECC_FIXUP BIT(0) +#define DENALI_CAP_DMA_64BIT BIT(1) + +int denali_calc_ecc_bytes(int step_size, int strength); +int denali_init(struct denali_nand_info *denali); + +#endif /* __DENALI_H__ */ diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c new file mode 100644 index 0000000000..65a7797f0f --- /dev/null +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017 Socionext Inc. + * Author: Masahiro Yamada + */ + +#include +#include +#include +#include +#include + +#include "denali.h" + +struct denali_dt_data { + unsigned int revision; + unsigned int caps; + const struct nand_ecc_caps *ecc_caps; +}; + +NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes, + 512, 8, 15); +static const struct denali_dt_data denali_socfpga_data = { + .caps = DENALI_CAP_HW_ECC_FIXUP, + .ecc_caps = &denali_socfpga_ecc_caps, +}; + +NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes, + 1024, 8, 16, 24); +static const struct denali_dt_data denali_uniphier_v5a_data = { + .caps = DENALI_CAP_HW_ECC_FIXUP | + DENALI_CAP_DMA_64BIT, + .ecc_caps = &denali_uniphier_v5a_ecc_caps, +}; + +NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes, + 1024, 8, 16); +static const struct denali_dt_data denali_uniphier_v5b_data = { + .revision = 0x0501, + .caps = DENALI_CAP_HW_ECC_FIXUP | + DENALI_CAP_DMA_64BIT, + .ecc_caps = &denali_uniphier_v5b_ecc_caps, +}; + +static const struct udevice_id denali_nand_dt_ids[] = { + { + .compatible = "altr,socfpga-denali-nand", + .data = (unsigned long)&denali_socfpga_data, + }, + { + .compatible = "socionext,uniphier-denali-nand-v5a", + .data = (unsigned long)&denali_uniphier_v5a_data, + }, + { + .compatible = "socionext,uniphier-denali-nand-v5b", + .data = (unsigned long)&denali_uniphier_v5b_data, + }, + { /* sentinel */ } +}; + +static int denali_dt_probe(struct udevice *dev) +{ + struct denali_nand_info *denali = dev_get_priv(dev); + const struct denali_dt_data *data; + struct clk clk; + struct resource res; + int ret; + + data = (void *)dev_get_driver_data(dev); + if (data) { + denali->revision = data->revision; + denali->caps = data->caps; + denali->ecc_caps = data->ecc_caps; + } + + denali->dev = dev; + + ret = dev_read_resource_byname(dev, "denali_reg", &res); + if (ret) + return ret; + + denali->reg = devm_ioremap(dev, res.start, resource_size(&res)); + + ret = dev_read_resource_byname(dev, "nand_data", &res); + if (ret) + return ret; + + denali->host = devm_ioremap(dev, res.start, resource_size(&res)); + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + return ret; + + denali->clk_x_rate = clk_get_rate(&clk); + + return denali_init(denali); +} + +U_BOOT_DRIVER(denali_nand_dt) = { + .name = "denali-nand-dt", + .id = UCLASS_MISC, + .of_match = denali_nand_dt_ids, + .probe = denali_dt_probe, + .priv_auto_alloc_size = sizeof(struct denali_nand_info), +}; + +void board_nand_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(denali_nand_dt), + &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize Denali NAND controller. (error %d)\n", + ret); +} diff --git a/drivers/mtd/nand/raw/denali_spl.c b/drivers/mtd/nand/raw/denali_spl.c new file mode 100644 index 0000000000..dbaba3cab2 --- /dev/null +++ b/drivers/mtd/nand/raw/denali_spl.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Panasonic Corporation + * Copyright (C) 2014-2015 Masahiro Yamada + */ + +#include +#include +#include +#include +#include "denali.h" + +#define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */ +#define DENALI_MAP10 (2 << 26) /* high-level control plane */ + +#define INDEX_CTRL_REG 0x0 +#define INDEX_DATA_REG 0x10 + +#define SPARE_ACCESS 0x41 +#define MAIN_ACCESS 0x42 +#define PIPELINE_ACCESS 0x2000 + +#define BANK(x) ((x) << 24) + +static void __iomem *denali_flash_mem = + (void __iomem *)CONFIG_SYS_NAND_DATA_BASE; +static void __iomem *denali_flash_reg = + (void __iomem *)CONFIG_SYS_NAND_REGS_BASE; + +static const int flash_bank; +static int page_size, oob_size, pages_per_block; + +static void index_addr(uint32_t address, uint32_t data) +{ + writel(address, denali_flash_mem + INDEX_CTRL_REG); + writel(data, denali_flash_mem + INDEX_DATA_REG); +} + +static int wait_for_irq(uint32_t irq_mask) +{ + unsigned long timeout = 1000000; + uint32_t intr_status; + + do { + intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank)); + + if (intr_status & INTR__ECC_UNCOR_ERR) { + debug("Uncorrected ECC detected\n"); + return -EBADMSG; + } + + if (intr_status & irq_mask) + break; + + udelay(1); + timeout--; + } while (timeout); + + if (!timeout) { + debug("Timeout with interrupt status %08x\n", intr_status); + return -EIO; + } + + return 0; +} + +static void read_data_from_flash_mem(uint8_t *buf, int len) +{ + int i; + uint32_t *buf32; + + /* transfer the data from the flash */ + buf32 = (uint32_t *)buf; + + /* + * Let's take care of unaligned access although it rarely happens. + * Avoid put_unaligned() for the normal use cases since it leads to + * a bit performance regression. + */ + if ((unsigned long)buf32 % 4) { + for (i = 0; i < len / 4; i++) + put_unaligned(readl(denali_flash_mem + INDEX_DATA_REG), + buf32++); + } else { + for (i = 0; i < len / 4; i++) + *buf32++ = readl(denali_flash_mem + INDEX_DATA_REG); + } + + if (len % 4) { + u32 tmp; + + tmp = cpu_to_le32(readl(denali_flash_mem + INDEX_DATA_REG)); + buf = (uint8_t *)buf32; + for (i = 0; i < len % 4; i++) { + *buf++ = tmp; + tmp >>= 8; + } + } +} + +int denali_send_pipeline_cmd(int page, int ecc_en, int access_type) +{ + uint32_t addr, cmd; + static uint32_t page_count = 1; + + writel(ecc_en, denali_flash_reg + ECC_ENABLE); + + /* clear all bits of intr_status. */ + writel(0xffff, denali_flash_reg + INTR_STATUS(flash_bank)); + + addr = BANK(flash_bank) | page; + + /* setup the acccess type */ + cmd = DENALI_MAP10 | addr; + index_addr(cmd, access_type); + + /* setup the pipeline command */ + index_addr(cmd, PIPELINE_ACCESS | page_count); + + cmd = DENALI_MAP01 | addr; + writel(cmd, denali_flash_mem + INDEX_CTRL_REG); + + return wait_for_irq(INTR__LOAD_COMP); +} + +static int nand_read_oob(void *buf, int page) +{ + int ret; + + ret = denali_send_pipeline_cmd(page, 0, SPARE_ACCESS); + if (ret < 0) + return ret; + + read_data_from_flash_mem(buf, oob_size); + + return 0; +} + +static int nand_read_page(void *buf, int page) +{ + int ret; + + ret = denali_send_pipeline_cmd(page, 1, MAIN_ACCESS); + if (ret < 0) + return ret; + + read_data_from_flash_mem(buf, page_size); + + return 0; +} + +static int nand_block_isbad(void *buf, int block) +{ + int ret; + + ret = nand_read_oob(buf, block * pages_per_block); + if (ret < 0) + return ret; + + return *((uint8_t *)buf + CONFIG_SYS_NAND_BAD_BLOCK_POS) != 0xff; +} + +/* nand_init() - initialize data to make nand usable by SPL */ +void nand_init(void) +{ + /* access to main area */ + writel(0, denali_flash_reg + TRANSFER_SPARE_REG); + + /* + * These registers are expected to be already set by the hardware + * or earlier boot code. So we read these values out. + */ + page_size = readl(denali_flash_reg + DEVICE_MAIN_AREA_SIZE); + oob_size = readl(denali_flash_reg + DEVICE_SPARE_AREA_SIZE); + pages_per_block = readl(denali_flash_reg + PAGES_PER_BLOCK); +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) +{ + int block, page, column, readlen; + int ret; + int force_bad_block_check = 1; + + page = offs / page_size; + column = offs % page_size; + + block = page / pages_per_block; + page = page % pages_per_block; + + while (size) { + if (force_bad_block_check || page == 0) { + ret = nand_block_isbad(dst, block); + if (ret < 0) + return ret; + + if (ret) { + block++; + continue; + } + } + + force_bad_block_check = 0; + + ret = nand_read_page(dst, block * pages_per_block + page); + if (ret < 0) + return ret; + + readlen = min(page_size - column, (int)size); + + if (unlikely(column)) { + /* Partial page read */ + memmove(dst, dst + column, readlen); + column = 0; + } + + size -= readlen; + dst += readlen; + page++; + if (page == pages_per_block) { + block++; + page = 0; + } + } + + return 0; +} + +void nand_deselect(void) {} diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c new file mode 100644 index 0000000000..263d46ec8f --- /dev/null +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -0,0 +1,810 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Freescale Enhanced Local Bus Controller FCM NAND driver + * + * Copyright (c) 2006-2008 Freescale Semiconductor + * + * Authors: Nick Spence , + * Scott Wood + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef VERBOSE_DEBUG +#define DEBUG_ELBC +#define vdbg(format, arg...) printf("DEBUG: " format, ##arg) +#else +#define vdbg(format, arg...) do {} while (0) +#endif + +/* Can't use plain old DEBUG because the linux mtd + * headers define it as a macro. + */ +#ifdef DEBUG_ELBC +#define dbg(format, arg...) printf("DEBUG: " format, ##arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif + +#define MAX_BANKS 8 +#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ + +#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC) + +struct fsl_elbc_ctrl; + +/* mtd information per set */ + +struct fsl_elbc_mtd { + struct nand_chip chip; + struct fsl_elbc_ctrl *ctrl; + + struct device *dev; + int bank; /* Chip select bank number */ + u8 __iomem *vbase; /* Chip select base virtual address */ + int page_size; /* NAND page size (0=512, 1=2048) */ + unsigned int fmr; /* FCM Flash Mode Register value */ +}; + +/* overview of the fsl elbc controller */ + +struct fsl_elbc_ctrl { + struct nand_hw_control controller; + struct fsl_elbc_mtd *chips[MAX_BANKS]; + + /* device info */ + fsl_lbc_t *regs; + u8 __iomem *addr; /* Address of assigned FCM buffer */ + unsigned int page; /* Last page written to / read from */ + unsigned int read_bytes; /* Number of bytes read during command */ + unsigned int column; /* Saved column from SEQIN */ + unsigned int index; /* Pointer to next byte to 'read' */ + unsigned int status; /* status read from LTESR after last op */ + unsigned int mdr; /* UPM/FCM Data Register value */ + unsigned int use_mdr; /* Non zero if the MDR is to be set */ + unsigned int oob; /* Non zero if operating on OOB data */ +}; + +/* These map to the positions used by the FCM hardware ECC generator */ + +/* Small Page FLASH with FMR[ECCM] = 0 */ +static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = { + .eccbytes = 3, + .eccpos = {6, 7, 8}, + .oobfree = { {0, 5}, {9, 7} }, +}; + +/* Small Page FLASH with FMR[ECCM] = 1 */ +static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = { + .eccbytes = 3, + .eccpos = {8, 9, 10}, + .oobfree = { {0, 5}, {6, 2}, {11, 5} }, +}; + +/* Large Page FLASH with FMR[ECCM] = 0 */ +static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = { + .eccbytes = 12, + .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, + .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, +}; + +/* Large Page FLASH with FMR[ECCM] = 1 */ +static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { + .eccbytes = 12, + .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, + .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, +}; + +/* + * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset + * 1, so we have to adjust bad block pattern. This pattern should be used for + * x8 chips only. So far hardware does not support x16 chips anyway. + */ +static u8 scan_ff_pattern[] = { 0xff, }; + +static struct nand_bbt_descr largepage_memorybased = { + .options = 0, + .offs = 0, + .len = 1, + .pattern = scan_ff_pattern, +}; + +/* + * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, + * interfere with ECC positions, that's why we implement our own descriptors. + * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. + */ +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 11, + .len = 4, + .veroffs = 15, + .maxblocks = 4, + .pattern = bbt_pattern, +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 11, + .len = 4, + .veroffs = 15, + .maxblocks = 4, + .pattern = mirror_pattern, +}; + +/*=================================*/ + +/* + * Set up the FCM hardware block and page address fields, and the fcm + * structure addr field to point to the correct FCM buffer in memory + */ +static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); + struct fsl_elbc_ctrl *ctrl = priv->ctrl; + fsl_lbc_t *lbc = ctrl->regs; + int buf_num; + + ctrl->page = page_addr; + + if (priv->page_size) { + out_be32(&lbc->fbar, page_addr >> 6); + out_be32(&lbc->fpar, + ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) | + (oob ? FPAR_LP_MS : 0) | column); + buf_num = (page_addr & 1) << 2; + } else { + out_be32(&lbc->fbar, page_addr >> 5); + out_be32(&lbc->fpar, + ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) | + (oob ? FPAR_SP_MS : 0) | column); + buf_num = page_addr & 7; + } + + ctrl->addr = priv->vbase + buf_num * 1024; + ctrl->index = column; + + /* for OOB data point to the second half of the buffer */ + if (oob) + ctrl->index += priv->page_size ? 2048 : 512; + + vdbg("set_addr: bank=%d, ctrl->addr=0x%p (0x%p), " + "index %x, pes %d ps %d\n", + buf_num, ctrl->addr, priv->vbase, ctrl->index, + chip->phys_erase_shift, chip->page_shift); +} + +/* + * execute FCM command and wait for it to complete + */ +static int fsl_elbc_run_command(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); + struct fsl_elbc_ctrl *ctrl = priv->ctrl; + fsl_lbc_t *lbc = ctrl->regs; + u32 timeo = (CONFIG_SYS_HZ * 10) / 1000; + u32 time_start; + u32 ltesr; + + /* Setup the FMR[OP] to execute without write protection */ + out_be32(&lbc->fmr, priv->fmr | 3); + if (ctrl->use_mdr) + out_be32(&lbc->mdr, ctrl->mdr); + + vdbg("fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n", + in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr)); + vdbg("fsl_elbc_run_command: fbar=%08x fpar=%08x " + "fbcr=%08x bank=%d\n", + in_be32(&lbc->fbar), in_be32(&lbc->fpar), + in_be32(&lbc->fbcr), priv->bank); + + /* execute special operation */ + out_be32(&lbc->lsor, priv->bank); + + /* wait for FCM complete flag or timeout */ + time_start = get_timer(0); + + ltesr = 0; + while (get_timer(time_start) < timeo) { + ltesr = in_be32(&lbc->ltesr); + if (ltesr & LTESR_CC) + break; + } + + ctrl->status = ltesr & LTESR_NAND_MASK; + out_be32(&lbc->ltesr, ctrl->status); + out_be32(&lbc->lteatr, 0); + + /* store mdr value in case it was needed */ + if (ctrl->use_mdr) + ctrl->mdr = in_be32(&lbc->mdr); + + ctrl->use_mdr = 0; + + vdbg("fsl_elbc_run_command: stat=%08x mdr=%08x fmr=%08x\n", + ctrl->status, ctrl->mdr, in_be32(&lbc->fmr)); + + /* returns 0 on success otherwise non-zero) */ + return ctrl->status == LTESR_CC ? 0 : -EIO; +} + +static void fsl_elbc_do_read(struct nand_chip *chip, int oob) +{ + struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); + struct fsl_elbc_ctrl *ctrl = priv->ctrl; + fsl_lbc_t *lbc = ctrl->regs; + + if (priv->page_size) { + out_be32(&lbc->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_CW1 << FIR_OP3_SHIFT) | + (FIR_OP_RBW << FIR_OP4_SHIFT)); + + out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | + (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); + } else { + out_be32(&lbc->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_RBW << FIR_OP3_SHIFT)); + + if (oob) + out_be32(&lbc->fcr, + NAND_CMD_READOOB << FCR_CMD0_SHIFT); + else + out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); + } +} + +/* cmdfunc send commands to the FCM */ +static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); + struct fsl_elbc_ctrl *ctrl = priv->ctrl; + fsl_lbc_t *lbc = ctrl->regs; + + ctrl->use_mdr = 0; + + /* clear the read buffer */ + ctrl->read_bytes = 0; + if (command != NAND_CMD_PAGEPROG) + ctrl->index = 0; + + switch (command) { + /* READ0 and READ1 read the entire buffer to use hardware ECC. */ + case NAND_CMD_READ1: + column += 256; + + /* fall-through */ + case NAND_CMD_READ0: + vdbg("fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" + " 0x%x, column: 0x%x.\n", page_addr, column); + + out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */ + set_addr(mtd, 0, page_addr, 0); + + ctrl->read_bytes = mtd->writesize + mtd->oobsize; + ctrl->index += column; + + fsl_elbc_do_read(chip, 0); + fsl_elbc_run_command(mtd); + return; + + /* READOOB reads only the OOB because no ECC is performed. */ + case NAND_CMD_READOOB: + vdbg("fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" + " 0x%x, column: 0x%x.\n", page_addr, column); + + out_be32(&lbc->fbcr, mtd->oobsize - column); + set_addr(mtd, column, page_addr, 1); + + ctrl->read_bytes = mtd->writesize + mtd->oobsize; + + fsl_elbc_do_read(chip, 1); + fsl_elbc_run_command(mtd); + + return; + + /* READID must read all 5 possible bytes while CEB is active */ + case NAND_CMD_READID: + case NAND_CMD_PARAM: + vdbg("fsl_elbc_cmdfunc: NAND_CMD 0x%x.\n", command); + + out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_UA << FIR_OP1_SHIFT) | + (FIR_OP_RBW << FIR_OP2_SHIFT)); + out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT); + /* + * although currently it's 8 bytes for READID, we always read + * the maximum 256 bytes(for PARAM) + */ + out_be32(&lbc->fbcr, 256); + ctrl->read_bytes = 256; + ctrl->use_mdr = 1; + ctrl->mdr = column; + set_addr(mtd, 0, 0, 0); + fsl_elbc_run_command(mtd); + return; + + /* ERASE1 stores the block and page address */ + case NAND_CMD_ERASE1: + vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE1, " + "page_addr: 0x%x.\n", page_addr); + set_addr(mtd, 0, page_addr, 0); + return; + + /* ERASE2 uses the block and page address from ERASE1 */ + case NAND_CMD_ERASE2: + vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); + + out_be32(&lbc->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_PA << FIR_OP1_SHIFT) | + (FIR_OP_CM1 << FIR_OP2_SHIFT)); + + out_be32(&lbc->fcr, + (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) | + (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT)); + + out_be32(&lbc->fbcr, 0); + ctrl->read_bytes = 0; + + fsl_elbc_run_command(mtd); + return; + + /* SEQIN sets up the addr buffer and all registers except the length */ + case NAND_CMD_SEQIN: { + u32 fcr; + vdbg("fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " + "page_addr: 0x%x, column: 0x%x.\n", + page_addr, column); + + ctrl->column = column; + ctrl->oob = 0; + + if (priv->page_size) { + fcr = (NAND_CMD_SEQIN << FCR_CMD0_SHIFT) | + (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT); + + out_be32(&lbc->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_WB << FIR_OP3_SHIFT) | + (FIR_OP_CW1 << FIR_OP4_SHIFT)); + } else { + fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) | + (NAND_CMD_SEQIN << FCR_CMD2_SHIFT); + + out_be32(&lbc->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CM2 << FIR_OP1_SHIFT) | + (FIR_OP_CA << FIR_OP2_SHIFT) | + (FIR_OP_PA << FIR_OP3_SHIFT) | + (FIR_OP_WB << FIR_OP4_SHIFT) | + (FIR_OP_CW1 << FIR_OP5_SHIFT)); + + if (column >= mtd->writesize) { + /* OOB area --> READOOB */ + column -= mtd->writesize; + fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT; + ctrl->oob = 1; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT; + } else { + /* Second 256 bytes --> READ1 */ + fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT; + } + } + + out_be32(&lbc->fcr, fcr); + set_addr(mtd, column, page_addr, ctrl->oob); + return; + } + + /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ + case NAND_CMD_PAGEPROG: { + vdbg("fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " + "writing %d bytes.\n", ctrl->index); + + /* if the write did not start at 0 or is not a full page + * then set the exact length, otherwise use a full page + * write so the HW generates the ECC. + */ + if (ctrl->oob || ctrl->column != 0 || + ctrl->index != mtd->writesize + mtd->oobsize) + out_be32(&lbc->fbcr, ctrl->index); + else + out_be32(&lbc->fbcr, 0); + + fsl_elbc_run_command(mtd); + + return; + } + + /* CMD_STATUS must read the status byte while CEB is active */ + /* Note - it does not wait for the ready line */ + case NAND_CMD_STATUS: + out_be32(&lbc->fir, + (FIR_OP_CM0 << FIR_OP0_SHIFT) | + (FIR_OP_RBW << FIR_OP1_SHIFT)); + out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); + out_be32(&lbc->fbcr, 1); + set_addr(mtd, 0, 0, 0); + ctrl->read_bytes = 1; + + fsl_elbc_run_command(mtd); + + /* The chip always seems to report that it is + * write-protected, even when it is not. + */ + out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); + return; + + /* RESET without waiting for the ready line */ + case NAND_CMD_RESET: + dbg("fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); + out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT); + out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT); + fsl_elbc_run_command(mtd); + return; + + default: + printf("fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", + command); + } +} + +static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip) +{ + /* The hardware does not seem to support multiple + * chips per bank. + */ +} + +/* + * Write buf to the FCM Controller Data Buffer + */ +static void fsl_elbc_write_buf(struct mtd_info *mtd, const 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_ctrl *ctrl = priv->ctrl; + unsigned int bufsize = mtd->writesize + mtd->oobsize; + + if (len <= 0) { + printf("write_buf of %d bytes", len); + ctrl->status = 0; + return; + } + + if ((unsigned int)len > bufsize - ctrl->index) { + printf("write_buf beyond end of buffer " + "(%d requested, %u available)\n", + len, bufsize - ctrl->index); + len = bufsize - ctrl->index; + } + + memcpy_toio(&ctrl->addr[ctrl->index], buf, len); + /* + * This is workaround for the weird elbc hangs during nand write, + * Scott Wood says: "...perhaps difference in how long it takes a + * write to make it through the localbus compared to a write to IMMR + * is causing problems, and sync isn't helping for some reason." + * Reading back the last byte helps though. + */ + in_8(&ctrl->addr[ctrl->index] + len - 1); + + ctrl->index += 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) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); + struct fsl_elbc_ctrl *ctrl = priv->ctrl; + + /* If there are still bytes in the FCM, then use the next byte. */ + if (ctrl->index < ctrl->read_bytes) + return in_8(&ctrl->addr[ctrl->index++]); + + printf("read_byte beyond end of buffer\n"); + return ERR_BYTE; +} + +/* + * Read from the FCM Controller Data Buffer + */ +static void fsl_elbc_read_buf(struct mtd_info *mtd, 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_ctrl *ctrl = priv->ctrl; + int avail; + + if (len < 0) + return; + + avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); + memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail); + ctrl->index += avail; + + if (len > avail) + printf("read_buf beyond end of buffer " + "(%d requested, %d available)\n", + len, avail); +} + +/* 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) +{ + struct fsl_elbc_mtd *priv = nand_get_controller_data(chip); + struct fsl_elbc_ctrl *ctrl = priv->ctrl; + fsl_lbc_t *lbc = ctrl->regs; + + if (ctrl->status != LTESR_CC) + return NAND_STATUS_FAIL; + + /* Use READ_STATUS command, but wait for the device to be ready */ + ctrl->use_mdr = 0; + out_be32(&lbc->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_RBW << FIR_OP1_SHIFT)); + out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); + out_be32(&lbc->fbcr, 1); + set_addr(mtd, 0, 0, 0); + ctrl->read_bytes = 1; + + fsl_elbc_run_command(mtd); + + if (ctrl->status != LTESR_CC) + return NAND_STATUS_FAIL; + + /* The chip always seems to report that it is + * write-protected, even when it is not. + */ + out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); + return fsl_elbc_read_byte(mtd); +} + +static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + fsl_elbc_read_buf(mtd, buf, mtd->writesize); + fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + + if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL) + mtd->ecc_stats.failed++; + + return 0; +} + +/* 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) +{ + fsl_elbc_write_buf(mtd, buf, mtd->writesize); + fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +static struct fsl_elbc_ctrl *elbc_ctrl; + +/* 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) +{ + fsl_elbc_write_buf(mtd, buf, mtd->writesize); + fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +static void fsl_elbc_ctrl_init(void) +{ + elbc_ctrl = kzalloc(sizeof(*elbc_ctrl), GFP_KERNEL); + if (!elbc_ctrl) + return; + + elbc_ctrl->regs = LBC_BASE_ADDR; + + /* clear event registers */ + out_be32(&elbc_ctrl->regs->ltesr, LTESR_NAND_MASK); + out_be32(&elbc_ctrl->regs->lteatr, 0); + + /* Enable interrupts for any detected events */ + out_be32(&elbc_ctrl->regs->lteir, LTESR_NAND_MASK); + + elbc_ctrl->read_bytes = 0; + elbc_ctrl->index = 0; + elbc_ctrl->addr = NULL; +} + +static int fsl_elbc_chip_init(int devnum, u8 *addr) +{ + struct mtd_info *mtd; + struct nand_chip *nand; + struct fsl_elbc_mtd *priv; + uint32_t br = 0, or = 0; + int ret; + + if (!elbc_ctrl) { + fsl_elbc_ctrl_init(); + if (!elbc_ctrl) + return -1; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->ctrl = elbc_ctrl; + priv->vbase = addr; + + /* Find which chip select it is connected to. It'd be nice + * if we could pass more than one datum to the NAND driver... + */ + for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { + phys_addr_t phys_addr = virt_to_phys(addr); + + br = in_be32(&elbc_ctrl->regs->bank[priv->bank].br); + or = in_be32(&elbc_ctrl->regs->bank[priv->bank].or); + + if ((br & BR_V) && (br & BR_MSEL) == BR_MS_FCM && + (br & or & BR_BA) == BR_PHYS_ADDR(phys_addr)) + break; + } + + if (priv->bank >= MAX_BANKS) { + printf("fsl_elbc_nand: address did not match any " + "chip selects\n"); + kfree(priv); + return -ENODEV; + } + + nand = &priv->chip; + mtd = nand_to_mtd(nand); + + elbc_ctrl->chips[priv->bank] = priv; + + /* fill in nand_chip structure */ + /* set up function call table */ + nand->read_byte = fsl_elbc_read_byte; + nand->write_buf = fsl_elbc_write_buf; + nand->read_buf = fsl_elbc_read_buf; + nand->select_chip = fsl_elbc_select_chip; + nand->cmdfunc = fsl_elbc_cmdfunc; + nand->waitfunc = fsl_elbc_wait; + + /* set up nand options */ + nand->bbt_td = &bbt_main_descr; + nand->bbt_md = &bbt_mirror_descr; + + /* set up nand options */ + nand->options = NAND_NO_SUBPAGE_WRITE; + nand->bbt_options = NAND_BBT_USE_FLASH; + + nand->controller = &elbc_ctrl->controller; + nand_set_controller_data(nand, priv); + + nand->ecc.read_page = fsl_elbc_read_page; + nand->ecc.write_page = fsl_elbc_write_page; + nand->ecc.write_subpage = fsl_elbc_write_subpage; + + priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT); + + /* If CS Base Register selects full hardware ECC then use it */ + if ((br & BR_DECC) == BR_DECC_CHK_GEN) { + nand->ecc.mode = NAND_ECC_HW; + + nand->ecc.layout = (priv->fmr & FMR_ECCM) ? + &fsl_elbc_oob_sp_eccm1 : + &fsl_elbc_oob_sp_eccm0; + + nand->ecc.size = 512; + nand->ecc.bytes = 3; + nand->ecc.steps = 1; + nand->ecc.strength = 1; + } else { + /* otherwise fall back to software ECC */ +#if defined(CONFIG_NAND_ECC_BCH) + nand->ecc.mode = NAND_ECC_SOFT_BCH; +#else + nand->ecc.mode = NAND_ECC_SOFT; +#endif + } + + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) + return ret; + + /* Large-page-specific setup */ + if (mtd->writesize == 2048) { + setbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, + OR_FCM_PGS); + in_be32(&elbc_ctrl->regs->bank[priv->bank].or); + + priv->page_size = 1; + nand->badblock_pattern = &largepage_memorybased; + + /* + * Hardware expects small page has ECCM0, large page has + * ECCM1 when booting from NAND, and we follow that even + * when not booting from NAND. + */ + priv->fmr |= FMR_ECCM; + + /* adjust ecc setup if needed */ + if ((br & BR_DECC) == BR_DECC_CHK_GEN) { + nand->ecc.steps = 4; + nand->ecc.layout = (priv->fmr & FMR_ECCM) ? + &fsl_elbc_oob_lp_eccm1 : + &fsl_elbc_oob_lp_eccm0; + } + } else if (mtd->writesize == 512) { + clrbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, + OR_FCM_PGS); + in_be32(&elbc_ctrl->regs->bank[priv->bank].or); + } else { + return -ENODEV; + } + + ret = nand_scan_tail(mtd); + if (ret) + return ret; + + ret = nand_register(devnum, mtd); + if (ret) + return ret; + + return 0; +} + +#ifndef CONFIG_SYS_NAND_BASE_LIST +#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } +#endif + +static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] = + CONFIG_SYS_NAND_BASE_LIST; + +void board_nand_init(void) +{ + int i; + + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) + fsl_elbc_chip_init(i, (u8 *)base_address[i]); +} diff --git a/drivers/mtd/nand/raw/fsl_elbc_spl.c b/drivers/mtd/nand/raw/fsl_elbc_spl.c new file mode 100644 index 0000000000..30c3308940 --- /dev/null +++ b/drivers/mtd/nand/raw/fsl_elbc_spl.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NAND boot for Freescale Enhanced Local Bus Controller, Flash Control Machine + * + * (C) Copyright 2006-2008 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * Copyright (c) 2008 Freescale Semiconductor, Inc. + * Author: Scott Wood + */ + +#include +#include +#include +#include + +#define WINDOW_SIZE 8192 + +static void nand_wait(void) +{ + fsl_lbc_t *regs = LBC_BASE_ADDR; + + for (;;) { + uint32_t status = in_be32(®s->ltesr); + + if (status == 1) + return; + + if (status & 1) { + puts("read failed (ltesr)\n"); + for (;;); + } + } +} + +#ifdef CONFIG_TPL_BUILD +int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) +#else +static int nand_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) +#endif +{ + fsl_lbc_t *regs = LBC_BASE_ADDR; + uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE; + const int large = CONFIG_SYS_NAND_OR_PRELIM & OR_FCM_PGS; + const int block_shift = large ? 17 : 14; + const int block_size = 1 << block_shift; + const int page_size = large ? 2048 : 512; + const int bad_marker = large ? page_size + 0 : page_size + 5; + int fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT) | 2; + int pos = 0; + char *dst = vdst; + + if (offs & (block_size - 1)) { + puts("bad offset\n"); + for (;;); + } + + if (large) { + fmr |= FMR_ECCM; + out_be32(®s->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | + (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); + out_be32(®s->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_CW1 << FIR_OP3_SHIFT) | + (FIR_OP_RBW << FIR_OP4_SHIFT)); + } else { + out_be32(®s->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); + out_be32(®s->fir, + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_RBW << FIR_OP3_SHIFT)); + } + + out_be32(®s->fbcr, 0); + clrsetbits_be32(®s->bank[0].br, BR_DECC, BR_DECC_CHK_GEN); + + while (pos < uboot_size) { + int i = 0; + out_be32(®s->fbar, offs >> block_shift); + + do { + int j; + unsigned int page_offs = (offs & (block_size - 1)) << 1; + + out_be32(®s->ltesr, ~0); + out_be32(®s->lteatr, 0); + out_be32(®s->fpar, page_offs); + out_be32(®s->fmr, fmr); + out_be32(®s->lsor, 0); + nand_wait(); + + page_offs %= WINDOW_SIZE; + + /* + * If either of the first two pages are marked bad, + * continue to the next block. + */ + if (i++ < 2 && buf[page_offs + bad_marker] != 0xff) { + puts("skipping\n"); + offs = (offs + block_size) & ~(block_size - 1); + pos &= ~(block_size - 1); + break; + } + + for (j = 0; j < page_size; j++) + dst[pos + j] = buf[page_offs + j]; + + pos += page_size; + offs += page_size; + } while ((offs & (block_size - 1)) && (pos < uboot_size)); + } + + return 0; +} + +/* + * Defines a static function nand_load_image() here, because non-static makes + * the code too large for certain SPLs(minimal SPL, maximum size <= 4Kbytes) + */ +#ifndef CONFIG_TPL_BUILD +#define nand_spl_load_image(offs, uboot_size, vdst) \ + nand_load_image(offs, uboot_size, vdst) +#endif + +/* + * The main entry for NAND booting. It's necessary that SDRAM is already + * configured and available since this code loads the main U-Boot image + * from NAND into SDRAM and starts it from there. + */ +void nand_boot(void) +{ + __attribute__((noreturn)) void (*uboot)(void); + /* + * Load U-Boot image from NAND into RAM + */ + nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, + CONFIG_SYS_NAND_U_BOOT_SIZE, + (void *)CONFIG_SYS_NAND_U_BOOT_DST); + +#ifdef CONFIG_NAND_ENV_DST + nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, + (void *)CONFIG_NAND_ENV_DST); + +#ifdef CONFIG_ENV_OFFSET_REDUND + nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, + (void *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); +#endif +#endif + +#ifdef CONFIG_SPL_FLUSH_IMAGE + /* + * Clean d-cache and invalidate i-cache, to + * make sure that no stale data is executed. + */ + flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); +#endif + + puts("transfering control\n"); + /* + * Jump to U-Boot image + */ + uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; + (*uboot)(); +} diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c new file mode 100644 index 0000000000..29f30d8ccc --- /dev/null +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -0,0 +1,1064 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Integrated Flash Controller NAND Machine Driver + * + * Copyright (c) 2012 Freescale Semiconductor, Inc + * + * Authors: Dipen Dudhat + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#ifndef CONFIG_SYS_FSL_IFC_BANK_COUNT +#define CONFIG_SYS_FSL_IFC_BANK_COUNT 4 +#endif + +#define MAX_BANKS CONFIG_SYS_FSL_IFC_BANK_COUNT +#define ERR_BYTE 0xFF /* Value returned for read bytes + when read failed */ + +struct fsl_ifc_ctrl; + +/* mtd information per set */ +struct fsl_ifc_mtd { + struct nand_chip chip; + struct fsl_ifc_ctrl *ctrl; + + struct device *dev; + int bank; /* Chip select bank number */ + unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */ + u8 __iomem *vbase; /* Chip select base virtual address */ +}; + +/* overview of the fsl ifc controller */ +struct fsl_ifc_ctrl { + struct nand_hw_control controller; + struct fsl_ifc_mtd *chips[MAX_BANKS]; + + /* device info */ + struct fsl_ifc regs; + void __iomem *addr; /* Address of assigned IFC buffer */ + unsigned int page; /* Last page written to / read from */ + unsigned int read_bytes; /* Number of bytes read during command */ + unsigned int column; /* Saved column from SEQIN */ + unsigned int index; /* Pointer to next byte to 'read' */ + unsigned int status; /* status read from NEESR after last op */ + unsigned int oob; /* Non zero if operating on OOB data */ + unsigned int eccread; /* Non zero for a full-page ECC read */ +}; + +static struct fsl_ifc_ctrl *ifc_ctrl; + +/* 512-byte page with 4-bit ECC, 8-bit */ +static struct nand_ecclayout oob_512_8bit_ecc4 = { + .eccbytes = 8, + .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, + .oobfree = { {0, 5}, {6, 2} }, +}; + +/* 512-byte page with 4-bit ECC, 16-bit */ +static struct nand_ecclayout oob_512_16bit_ecc4 = { + .eccbytes = 8, + .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, + .oobfree = { {2, 6}, }, +}; + +/* 2048-byte page size with 4-bit ECC */ +static struct nand_ecclayout oob_2048_ecc4 = { + .eccbytes = 32, + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + }, + .oobfree = { {2, 6}, {40, 24} }, +}; + +/* 4096-byte page size with 4-bit ECC */ +static struct nand_ecclayout oob_4096_ecc4 = { + .eccbytes = 64, + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + }, + .oobfree = { {2, 6}, {72, 56} }, +}; + +/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */ +static struct nand_ecclayout oob_4096_ecc8 = { + .eccbytes = 128, + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + }, + .oobfree = { {2, 6}, {136, 82} }, +}; + +/* 8192-byte page size with 4-bit ECC */ +static struct nand_ecclayout oob_8192_ecc4 = { + .eccbytes = 128, + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + }, + .oobfree = { {2, 6}, {136, 208} }, +}; + +/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */ +static struct nand_ecclayout oob_8192_ecc8 = { + .eccbytes = 256, + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, + }, + .oobfree = { {2, 6}, {264, 80} }, +}; + +/* + * Generic flash bbt descriptors + */ +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 2, /* 0 on 8-bit small page */ + .len = 4, + .veroffs = 6, + .maxblocks = 4, + .pattern = bbt_pattern, +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 2, /* 0 on 8-bit small page */ + .len = 4, + .veroffs = 6, + .maxblocks = 4, + .pattern = mirror_pattern, +}; + +/* + * Set up the IFC hardware block and page address fields, and the ifc nand + * structure addr field to point to the correct IFC buffer in memory + */ +static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; + int buf_num; + + ctrl->page = page_addr; + + /* Program ROW0/COL0 */ + ifc_out32(&ifc->ifc_nand.row0, page_addr); + ifc_out32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column); + + buf_num = page_addr & priv->bufnum_mask; + + ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2); + ctrl->index = column; + + /* for OOB data point to the second half of the buffer */ + if (oob) + ctrl->index += mtd->writesize; +} + +/* returns nonzero if entire page is blank */ +static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl, + u32 eccstat, unsigned int bufnum) +{ + return (eccstat >> ((3 - bufnum % 4) * 8)) & 15; +} + +/* + * execute IFC NAND command and wait for it to complete + */ +static int fsl_ifc_run_command(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; + u32 timeo = (CONFIG_SYS_HZ * 10) / 1000; + u32 time_start; + u32 eccstat; + int i; + + /* set the chip select for NAND Transaction */ + ifc_out32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT); + + /* start read/write seq */ + ifc_out32(&ifc->ifc_nand.nandseq_strt, + IFC_NAND_SEQ_STRT_FIR_STRT); + + /* wait for NAND Machine complete flag or timeout */ + time_start = get_timer(0); + + while (get_timer(time_start) < timeo) { + ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat); + + if (ctrl->status & IFC_NAND_EVTER_STAT_OPC) + break; + } + + ifc_out32(&ifc->ifc_nand.nand_evter_stat, ctrl->status); + + if (ctrl->status & IFC_NAND_EVTER_STAT_FTOER) + printf("%s: Flash Time Out Error\n", __func__); + if (ctrl->status & IFC_NAND_EVTER_STAT_WPER) + printf("%s: Write Protect Error\n", __func__); + + if (ctrl->eccread) { + int errors; + int bufnum = ctrl->page & priv->bufnum_mask; + int sector_start = bufnum * chip->ecc.steps; + int sector_end = sector_start + chip->ecc.steps - 1; + u32 *eccstat_regs; + + eccstat_regs = ifc->ifc_nand.nand_eccstat; + eccstat = ifc_in32(&eccstat_regs[sector_start / 4]); + + for (i = sector_start; i <= sector_end; i++) { + if ((i != sector_start) && !(i % 4)) + eccstat = ifc_in32(&eccstat_regs[i / 4]); + + errors = check_read_ecc(mtd, ctrl, eccstat, i); + + if (errors == 15) { + /* + * Uncorrectable error. + * We'll check for blank pages later. + * + * We disable ECCER reporting due to erratum + * IFC-A002770 -- so report it now if we + * see an uncorrectable error in ECCSTAT. + */ + ctrl->status |= IFC_NAND_EVTER_STAT_ECCER; + continue; + } + + mtd->ecc_stats.corrected += errors; + } + + ctrl->eccread = 0; + } + + /* returns 0 on success otherwise non-zero) */ + return ctrl->status == IFC_NAND_EVTER_STAT_OPC ? 0 : -EIO; +} + +static void fsl_ifc_do_read(struct nand_chip *chip, + int oob, + struct mtd_info *mtd) +{ + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; + + /* Program FIR/IFC_NAND_FCR0 for Small/Large page */ + if (mtd->writesize > 512) { + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | + (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT)); + ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0); + + ifc_out32(&ifc->ifc_nand.nand_fcr0, + (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | + (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); + } else { + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT)); + + if (oob) + ifc_out32(&ifc->ifc_nand.nand_fcr0, + NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT); + else + ifc_out32(&ifc->ifc_nand.nand_fcr0, + NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); + } +} + +/* 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); + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; + + /* clear the read buffer */ + ctrl->read_bytes = 0; + if (command != NAND_CMD_PAGEPROG) + ctrl->index = 0; + + switch (command) { + /* READ0 read the entire buffer to use hardware ECC. */ + case NAND_CMD_READ0: { + ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); + set_addr(mtd, 0, page_addr, 0); + + ctrl->read_bytes = mtd->writesize + mtd->oobsize; + ctrl->index += column; + + if (chip->ecc.mode == NAND_ECC_HW) + ctrl->eccread = 1; + + fsl_ifc_do_read(chip, 0, mtd); + fsl_ifc_run_command(mtd); + return; + } + + /* READOOB reads only the OOB because no ECC is performed. */ + case NAND_CMD_READOOB: + ifc_out32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column); + set_addr(mtd, column, page_addr, 1); + + ctrl->read_bytes = mtd->writesize + mtd->oobsize; + + fsl_ifc_do_read(chip, 1, mtd); + fsl_ifc_run_command(mtd); + + return; + + /* READID must read all possible bytes while CEB is active */ + case NAND_CMD_READID: + case NAND_CMD_PARAM: { + int timing = IFC_FIR_OP_RB; + if (command == NAND_CMD_PARAM) + timing = IFC_FIR_OP_RBCD; + + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | + (timing << IFC_NAND_FIR0_OP2_SHIFT)); + ifc_out32(&ifc->ifc_nand.nand_fcr0, + command << IFC_NAND_FCR0_CMD0_SHIFT); + ifc_out32(&ifc->ifc_nand.row3, column); + + /* + * although currently it's 8 bytes for READID, we always read + * the maximum 256 bytes(for PARAM) + */ + ifc_out32(&ifc->ifc_nand.nand_fbcr, 256); + ctrl->read_bytes = 256; + + set_addr(mtd, 0, 0, 0); + fsl_ifc_run_command(mtd); + return; + } + + /* ERASE1 stores the block and page address */ + case NAND_CMD_ERASE1: + set_addr(mtd, 0, page_addr, 0); + return; + + /* ERASE2 uses the block and page address from ERASE1 */ + case NAND_CMD_ERASE2: + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT)); + + ifc_out32(&ifc->ifc_nand.nand_fcr0, + (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) | + (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT)); + + ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); + ctrl->read_bytes = 0; + fsl_ifc_run_command(mtd); + return; + + /* SEQIN sets up the addr buffer and all registers except the length */ + case NAND_CMD_SEQIN: { + u32 nand_fcr0; + ctrl->column = column; + ctrl->oob = 0; + + if (mtd->writesize > 512) { + nand_fcr0 = + (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) | + (NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) | + (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT); + + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_WBCD << + IFC_NAND_FIR0_OP3_SHIFT) | + (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT)); + ifc_out32(&ifc->ifc_nand.nand_fir1, + (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) | + (IFC_FIR_OP_RDSTAT << + IFC_NAND_FIR1_OP6_SHIFT) | + (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT)); + } else { + nand_fcr0 = ((NAND_CMD_PAGEPROG << + IFC_NAND_FCR0_CMD1_SHIFT) | + (NAND_CMD_SEQIN << + IFC_NAND_FCR0_CMD2_SHIFT) | + (NAND_CMD_STATUS << + IFC_NAND_FCR0_CMD3_SHIFT)); + + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) | + (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT)); + ifc_out32(&ifc->ifc_nand.nand_fir1, + (IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) | + (IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) | + (IFC_FIR_OP_RDSTAT << + IFC_NAND_FIR1_OP7_SHIFT) | + (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT)); + + if (column >= mtd->writesize) + nand_fcr0 |= + NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT; + else + nand_fcr0 |= + NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT; + } + + if (column >= mtd->writesize) { + /* OOB area --> READOOB */ + column -= mtd->writesize; + ctrl->oob = 1; + } + ifc_out32(&ifc->ifc_nand.nand_fcr0, nand_fcr0); + set_addr(mtd, column, page_addr, ctrl->oob); + return; + } + + /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ + case NAND_CMD_PAGEPROG: + if (ctrl->oob) + ifc_out32(&ifc->ifc_nand.nand_fbcr, + ctrl->index - ctrl->column); + else + ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); + + fsl_ifc_run_command(mtd); + return; + + case NAND_CMD_STATUS: + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT)); + ifc_out32(&ifc->ifc_nand.nand_fcr0, + NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT); + ifc_out32(&ifc->ifc_nand.nand_fbcr, 1); + set_addr(mtd, 0, 0, 0); + ctrl->read_bytes = 1; + + fsl_ifc_run_command(mtd); + + /* + * The chip always seems to report that it is + * write-protected, even when it is not. + */ + if (chip->options & NAND_BUSWIDTH_16) + ifc_out16(ctrl->addr, + ifc_in16(ctrl->addr) | NAND_STATUS_WP); + else + out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); + return; + + case NAND_CMD_RESET: + ifc_out32(&ifc->ifc_nand.nand_fir0, + IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT); + ifc_out32(&ifc->ifc_nand.nand_fcr0, + NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT); + fsl_ifc_run_command(mtd); + return; + + default: + printf("%s: error, unsupported command 0x%x.\n", + __func__, command); + } +} + +/* + * Write buf to the IFC NAND Controller Data Buffer + */ +static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + unsigned int bufsize = mtd->writesize + mtd->oobsize; + + if (len <= 0) { + printf("%s of %d bytes", __func__, len); + ctrl->status = 0; + return; + } + + if ((unsigned int)len > bufsize - ctrl->index) { + printf("%s beyond end of buffer " + "(%d requested, %u available)\n", + __func__, len, bufsize - ctrl->index); + len = bufsize - ctrl->index; + } + + memcpy_toio(ctrl->addr + ctrl->index, buf, len); + ctrl->index += len; +} + +/* + * read a byte from either the IFC hardware buffer if it has any data left + * otherwise issue a command to read a single byte. + */ +static u8 fsl_ifc_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + unsigned int offset; + + /* + * If there are still bytes in the IFC buffer, then use the + * next byte. + */ + if (ctrl->index < ctrl->read_bytes) { + offset = ctrl->index++; + return in_8(ctrl->addr + offset); + } + + printf("%s beyond end of buffer\n", __func__); + return ERR_BYTE; +} + +/* + * 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) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + uint16_t data; + + /* + * If there are still bytes in the IFC buffer, then use the + * next byte. + */ + if (ctrl->index < ctrl->read_bytes) { + data = ifc_in16(ctrl->addr + ctrl->index); + ctrl->index += 2; + return (uint8_t)data; + } + + printf("%s beyond end of buffer\n", __func__); + return ERR_BYTE; +} + +/* + * Read from the IFC Controller Data Buffer + */ +static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + int avail; + + if (len < 0) + return; + + avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); + memcpy_fromio(buf, ctrl->addr + ctrl->index, avail); + ctrl->index += avail; + + if (len > avail) + printf("%s beyond end of buffer " + "(%d requested, %d available)\n", + __func__, len, avail); +} + +/* 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) +{ + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; + u32 nand_fsr; + int status; + + if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) + return NAND_STATUS_FAIL; + + /* Use READ_STATUS command, but wait for the device to be ready */ + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT)); + ifc_out32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS << + IFC_NAND_FCR0_CMD0_SHIFT); + ifc_out32(&ifc->ifc_nand.nand_fbcr, 1); + set_addr(mtd, 0, 0, 0); + ctrl->read_bytes = 1; + + fsl_ifc_run_command(mtd); + + if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) + return NAND_STATUS_FAIL; + + nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr); + status = nand_fsr >> 24; + + /* Chip sometimes reporting write protect even when it's not */ + return status | NAND_STATUS_WP; +} + +/* + * The controller does not check for bitflips in erased pages, + * therefore software must check instead. + */ +static int +check_erased_page(struct nand_chip *chip, u8 *buf, struct mtd_info *mtd) +{ + u8 *ecc = chip->oob_poi; + const int ecc_size = chip->ecc.bytes; + const int pkt_size = chip->ecc.size; + int i, res, bitflips; + + /* IFC starts ecc bytes at offset 8 in the spare area. */ + ecc += 8; + bitflips = 0; + for (i = 0; i < chip->ecc.steps; i++) { + res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size, + NULL, 0, chip->ecc.strength); + + if (res < 0) { + printf("fsl-ifc: NAND Flash ECC Uncorrectable Error\n"); + mtd->ecc_stats.failed++; + } else if (res > 0) { + mtd->ecc_stats.corrected += res; + } + bitflips = max(res, bitflips); + buf += pkt_size; + ecc += ecc_size; + } + + return bitflips; +} + +static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + struct fsl_ifc_mtd *priv = nand_get_controller_data(chip); + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + + fsl_ifc_read_buf(mtd, buf, mtd->writesize); + fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + + if (ctrl->status & IFC_NAND_EVTER_STAT_ECCER) + return check_erased_page(chip, buf, mtd); + + if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) + mtd->ecc_stats.failed++; + + return 0; +} + +/* 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) +{ + fsl_ifc_write_buf(mtd, buf, mtd->writesize); + fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +static void fsl_ifc_ctrl_init(void) +{ + uint32_t ver = 0; + ifc_ctrl = kzalloc(sizeof(*ifc_ctrl), GFP_KERNEL); + if (!ifc_ctrl) + return; + + ifc_ctrl->regs.gregs = IFC_FCM_BASE_ADDR; + + ver = ifc_in32(&ifc_ctrl->regs.gregs->ifc_rev); + if (ver >= FSL_IFC_V2_0_0) + ifc_ctrl->regs.rregs = + (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_64KOFFSET; + else + ifc_ctrl->regs.rregs = + (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_4KOFFSET; + + /* clear event registers */ + ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_stat, ~0U); + ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.pgrdcmpl_evt_stat, ~0U); + + /* Enable error and event for any detected errors */ + ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_en, + IFC_NAND_EVTER_EN_OPC_EN | + IFC_NAND_EVTER_EN_PGRDCMPL_EN | + IFC_NAND_EVTER_EN_FTOER_EN | + IFC_NAND_EVTER_EN_WPER_EN); + + ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.ncfgr, 0x0); +} + +static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) +{ +} + +static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv, uint32_t ver) +{ + struct fsl_ifc_runtime *ifc = ifc_ctrl->regs.rregs; + uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0; + uint32_t ncfgr = 0; + u32 timeo = (CONFIG_SYS_HZ * 10) / 1000; + u32 time_start; + + if (ver > FSL_IFC_V1_1_0) { + ncfgr = ifc_in32(&ifc->ifc_nand.ncfgr); + ifc_out32(&ifc->ifc_nand.ncfgr, ncfgr | IFC_NAND_SRAM_INIT_EN); + + /* wait for SRAM_INIT bit to be clear or timeout */ + time_start = get_timer(0); + while (get_timer(time_start) < timeo) { + ifc_ctrl->status = + ifc_in32(&ifc->ifc_nand.nand_evter_stat); + + if (!(ifc_ctrl->status & IFC_NAND_SRAM_INIT_EN)) + return 0; + } + printf("fsl-ifc: Failed to Initialise SRAM\n"); + return 1; + } + + cs = priv->bank; + + /* Save CSOR and CSOR_ext */ + csor = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor); + csor_ext = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext); + + /* chage PageSize 8K and SpareSize 1K*/ + csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000; + ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor_8k); + ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, 0x0000400); + + /* READID */ + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); + ifc_out32(&ifc->ifc_nand.nand_fcr0, + NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); + ifc_out32(&ifc->ifc_nand.row3, 0x0); + + ifc_out32(&ifc->ifc_nand.nand_fbcr, 0x0); + + /* Program ROW0/COL0 */ + ifc_out32(&ifc->ifc_nand.row0, 0x0); + ifc_out32(&ifc->ifc_nand.col0, 0x0); + + /* set the chip select for NAND Transaction */ + ifc_out32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT); + + /* start read seq */ + ifc_out32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT); + + time_start = get_timer(0); + + while (get_timer(time_start) < timeo) { + ifc_ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat); + + if (ifc_ctrl->status & IFC_NAND_EVTER_STAT_OPC) + break; + } + + if (ifc_ctrl->status != IFC_NAND_EVTER_STAT_OPC) { + printf("fsl-ifc: Failed to Initialise SRAM\n"); + return 1; + } + + ifc_out32(&ifc->ifc_nand.nand_evter_stat, ifc_ctrl->status); + + /* Restore CSOR and CSOR_ext */ + ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor); + ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, csor_ext); + + return 0; +} + +static int fsl_ifc_chip_init(int devnum, u8 *addr) +{ + struct mtd_info *mtd; + struct nand_chip *nand; + struct fsl_ifc_mtd *priv; + struct nand_ecclayout *layout; + struct fsl_ifc_fcm *gregs = NULL; + uint32_t cspr = 0, csor = 0, ver = 0; + int ret = 0; + + if (!ifc_ctrl) { + fsl_ifc_ctrl_init(); + if (!ifc_ctrl) + return -1; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->ctrl = ifc_ctrl; + priv->vbase = addr; + gregs = ifc_ctrl->regs.gregs; + + /* Find which chip select it is connected to. + */ + for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { + phys_addr_t phys_addr = virt_to_phys(addr); + + cspr = ifc_in32(&gregs->cspr_cs[priv->bank].cspr); + csor = ifc_in32(&gregs->csor_cs[priv->bank].csor); + + if ((cspr & CSPR_V) && (cspr & CSPR_MSEL) == CSPR_MSEL_NAND && + (cspr & CSPR_BA) == CSPR_PHYS_ADDR(phys_addr)) + break; + } + + if (priv->bank >= MAX_BANKS) { + printf("%s: address did not match any " + "chip selects\n", __func__); + kfree(priv); + return -ENODEV; + } + + nand = &priv->chip; + mtd = nand_to_mtd(nand); + + ifc_ctrl->chips[priv->bank] = priv; + + /* fill in nand_chip structure */ + /* set up function call table */ + + nand->write_buf = fsl_ifc_write_buf; + nand->read_buf = fsl_ifc_read_buf; + nand->select_chip = fsl_ifc_select_chip; + nand->cmdfunc = fsl_ifc_cmdfunc; + nand->waitfunc = fsl_ifc_wait; + + /* set up nand options */ + nand->bbt_td = &bbt_main_descr; + nand->bbt_md = &bbt_mirror_descr; + + /* set up nand options */ + nand->options = NAND_NO_SUBPAGE_WRITE; + nand->bbt_options = NAND_BBT_USE_FLASH; + + if (cspr & CSPR_PORT_SIZE_16) { + nand->read_byte = fsl_ifc_read_byte16; + nand->options |= NAND_BUSWIDTH_16; + } else { + nand->read_byte = fsl_ifc_read_byte; + } + + nand->controller = &ifc_ctrl->controller; + nand_set_controller_data(nand, priv); + + nand->ecc.read_page = fsl_ifc_read_page; + nand->ecc.write_page = fsl_ifc_write_page; + + /* Hardware generates ECC per 512 Bytes */ + nand->ecc.size = 512; + nand->ecc.bytes = 8; + + switch (csor & CSOR_NAND_PGS_MASK) { + case CSOR_NAND_PGS_512: + if (nand->options & NAND_BUSWIDTH_16) { + layout = &oob_512_16bit_ecc4; + } else { + layout = &oob_512_8bit_ecc4; + + /* Avoid conflict with bad block marker */ + bbt_main_descr.offs = 0; + bbt_mirror_descr.offs = 0; + } + + nand->ecc.strength = 4; + priv->bufnum_mask = 15; + break; + + case CSOR_NAND_PGS_2K: + layout = &oob_2048_ecc4; + nand->ecc.strength = 4; + priv->bufnum_mask = 3; + break; + + case CSOR_NAND_PGS_4K: + if ((csor & CSOR_NAND_ECC_MODE_MASK) == + CSOR_NAND_ECC_MODE_4) { + layout = &oob_4096_ecc4; + nand->ecc.strength = 4; + } else { + layout = &oob_4096_ecc8; + nand->ecc.strength = 8; + nand->ecc.bytes = 16; + } + + priv->bufnum_mask = 1; + break; + + case CSOR_NAND_PGS_8K: + if ((csor & CSOR_NAND_ECC_MODE_MASK) == + CSOR_NAND_ECC_MODE_4) { + layout = &oob_8192_ecc4; + nand->ecc.strength = 4; + } else { + layout = &oob_8192_ecc8; + nand->ecc.strength = 8; + nand->ecc.bytes = 16; + } + + priv->bufnum_mask = 0; + break; + + + default: + printf("ifc nand: bad csor %#x: bad page size\n", csor); + return -ENODEV; + } + + /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */ + if (csor & CSOR_NAND_ECC_DEC_EN) { + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.layout = layout; + } else { + nand->ecc.mode = NAND_ECC_SOFT; + } + + ver = ifc_in32(&gregs->ifc_rev); + if (ver >= FSL_IFC_V1_1_0) + ret = fsl_ifc_sram_init(priv, ver); + if (ret) + return ret; + + if (ver >= FSL_IFC_V2_0_0) + priv->bufnum_mask = (priv->bufnum_mask * 2) + 1; + + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) + return ret; + + ret = nand_scan_tail(mtd); + if (ret) + return ret; + + ret = nand_register(devnum, mtd); + if (ret) + return ret; + return 0; +} + +#ifndef CONFIG_SYS_NAND_BASE_LIST +#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } +#endif + +static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] = + CONFIG_SYS_NAND_BASE_LIST; + +void board_nand_init(void) +{ + int i; + + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) + fsl_ifc_chip_init(i, (u8 *)base_address[i]); +} diff --git a/drivers/mtd/nand/raw/fsl_ifc_spl.c b/drivers/mtd/nand/raw/fsl_ifc_spl.c new file mode 100644 index 0000000000..7137eb4108 --- /dev/null +++ b/drivers/mtd/nand/raw/fsl_ifc_spl.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NAND boot for Freescale Integrated Flash Controller, NAND FCM + * + * Copyright 2011 Freescale Semiconductor, Inc. + * Author: Dipen Dudhat + */ + +#include +#include +#include +#include +#ifdef CONFIG_CHAIN_OF_TRUST +#include +#endif + +static inline int is_blank(uchar *addr, int page_size) +{ + int i; + + for (i = 0; i < page_size; i++) { + if (__raw_readb(&addr[i]) != 0xff) + return 0; + } + + /* + * For the SPL, don't worry about uncorrectable errors + * where the main area is all FFs but shouldn't be. + */ + return 1; +} + +/* returns nonzero if entire page is blank */ +static inline int check_read_ecc(uchar *buf, u32 *eccstat, + unsigned int bufnum, int page_size) +{ + u32 reg = eccstat[bufnum / 4]; + int errors = (reg >> ((3 - bufnum % 4) * 8)) & 0xf; + + if (errors == 0xf) { /* uncorrectable */ + /* Blank pages fail hw ECC checks */ + if (is_blank(buf, page_size)) + return 1; + + puts("ecc error\n"); + for (;;) + ; + } + + return 0; +} + +static inline struct fsl_ifc_runtime *runtime_regs_address(void) +{ + struct fsl_ifc regs = {(void *)CONFIG_SYS_IFC_ADDR, NULL}; + int ver = 0; + + ver = ifc_in32(®s.gregs->ifc_rev); + if (ver >= FSL_IFC_V2_0_0) + regs.rregs = (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_64KOFFSET; + else + regs.rregs = (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_4KOFFSET; + + return regs.rregs; +} + +static inline void nand_wait(uchar *buf, int bufnum, int page_size) +{ + struct fsl_ifc_runtime *ifc = runtime_regs_address(); + u32 status; + u32 eccstat[8]; + int bufperpage = page_size / 512; + int bufnum_end, i; + + bufnum *= bufperpage; + bufnum_end = bufnum + bufperpage - 1; + + do { + status = ifc_in32(&ifc->ifc_nand.nand_evter_stat); + } while (!(status & IFC_NAND_EVTER_STAT_OPC)); + + if (status & IFC_NAND_EVTER_STAT_FTOER) { + puts("flash time out error\n"); + for (;;) + ; + } + + for (i = bufnum / 4; i <= bufnum_end / 4; i++) + eccstat[i] = ifc_in32(&ifc->ifc_nand.nand_eccstat[i]); + + for (i = bufnum; i <= bufnum_end; i++) { + if (check_read_ecc(buf, eccstat, i, page_size)) + break; + } + + ifc_out32(&ifc->ifc_nand.nand_evter_stat, status); +} + +static inline int bad_block(uchar *marker, int port_size) +{ + if (port_size == 8) + return __raw_readb(marker) != 0xff; + else + return __raw_readw((u16 *)marker) != 0xffff; +} + +int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) +{ + struct fsl_ifc_fcm *gregs = (void *)CONFIG_SYS_IFC_ADDR; + struct fsl_ifc_runtime *ifc = NULL; + uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE; + int page_size; + int port_size; + int pages_per_blk; + int blk_size; + int bad_marker = 0; + int bufnum_mask, bufnum, ver = 0; + + int csor, cspr; + int pos = 0; + int j = 0; + + int sram_addr; + int pg_no; + uchar *dst = vdst; + + ifc = runtime_regs_address(); + + /* Get NAND Flash configuration */ + csor = CONFIG_SYS_NAND_CSOR; + cspr = CONFIG_SYS_NAND_CSPR; + + port_size = (cspr & CSPR_PORT_SIZE_16) ? 16 : 8; + + if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_8K) { + page_size = 8192; + bufnum_mask = 0x0; + } else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_4K) { + page_size = 4096; + bufnum_mask = 0x1; + } else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_2K) { + page_size = 2048; + bufnum_mask = 0x3; + } else { + page_size = 512; + bufnum_mask = 0xf; + + if (port_size == 8) + bad_marker = 5; + } + + ver = ifc_in32(&gregs->ifc_rev); + if (ver >= FSL_IFC_V2_0_0) + bufnum_mask = (bufnum_mask * 2) + 1; + + pages_per_blk = + 32 << ((csor & CSOR_NAND_PB_MASK) >> CSOR_NAND_PB_SHIFT); + + blk_size = pages_per_blk * page_size; + + /* Open Full SRAM mapping for spare are access */ + ifc_out32(&ifc->ifc_nand.ncfgr, 0x0); + + /* Clear Boot events */ + ifc_out32(&ifc->ifc_nand.nand_evter_stat, 0xffffffff); + + /* Program FIR/FCR for Large/Small page */ + if (page_size > 512) { + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | + (IFC_FIR_OP_BTRD << IFC_NAND_FIR0_OP4_SHIFT)); + ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0); + + ifc_out32(&ifc->ifc_nand.nand_fcr0, + (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | + (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); + } else { + ifc_out32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_BTRD << IFC_NAND_FIR0_OP3_SHIFT)); + ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0); + + ifc_out32(&ifc->ifc_nand.nand_fcr0, + NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); + } + + /* Program FBCR = 0 for full page read */ + ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); + + /* Read and copy u-boot on SDRAM from NAND device, In parallel + * check for Bad block if found skip it and read continue to + * next Block + */ + while (pos < uboot_size) { + int i = 0; + do { + pg_no = offs / page_size; + bufnum = pg_no & bufnum_mask; + sram_addr = bufnum * page_size * 2; + + ifc_out32(&ifc->ifc_nand.row0, pg_no); + ifc_out32(&ifc->ifc_nand.col0, 0); + /* start read */ + ifc_out32(&ifc->ifc_nand.nandseq_strt, + IFC_NAND_SEQ_STRT_FIR_STRT); + + /* wait for read to complete */ + nand_wait(&buf[sram_addr], bufnum, page_size); + + /* + * If either of the first two pages are marked bad, + * continue to the next block. + */ + if (i++ < 2 && + bad_block(&buf[sram_addr + page_size + bad_marker], + port_size)) { + puts("skipping\n"); + offs = (offs + blk_size) & ~(blk_size - 1); + pos &= ~(blk_size - 1); + break; + } + + for (j = 0; j < page_size; j++) + dst[pos + j] = __raw_readb(&buf[sram_addr + j]); + + pos += page_size; + offs += page_size; + } while ((offs & (blk_size - 1)) && (pos < uboot_size)); + } + + return 0; +} + +/* + * Main entrypoint for NAND Boot. It's necessary that SDRAM is already + * configured and available since this code loads the main U-Boot image + * from NAND into SDRAM and starts from there. + */ +void nand_boot(void) +{ + __attribute__((noreturn)) void (*uboot)(void); + /* + * Load U-Boot image from NAND into RAM + */ + nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, + CONFIG_SYS_NAND_U_BOOT_SIZE, + (uchar *)CONFIG_SYS_NAND_U_BOOT_DST); + +#ifdef CONFIG_NAND_ENV_DST + nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, + (uchar *)CONFIG_NAND_ENV_DST); + +#ifdef CONFIG_ENV_OFFSET_REDUND + nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, + (uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); +#endif +#endif + /* + * Jump to U-Boot image + */ +#ifdef CONFIG_SPL_FLUSH_IMAGE + /* + * Clean d-cache and invalidate i-cache, to + * make sure that no stale data is executed. + */ + flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); +#endif + +#ifdef CONFIG_CHAIN_OF_TRUST + /* + * U-Boot header is appended at end of U-boot image, so + * calculate U-boot header address using U-boot header size. + */ +#define CONFIG_U_BOOT_HDR_ADDR \ + ((CONFIG_SYS_NAND_U_BOOT_START + \ + CONFIG_SYS_NAND_U_BOOT_SIZE) - \ + CONFIG_U_BOOT_HDR_SIZE) + spl_validate_uboot(CONFIG_U_BOOT_HDR_ADDR, + CONFIG_SYS_NAND_U_BOOT_START); + /* + * In case of failure in validation, spl_validate_uboot would + * not return back in case of Production environment with ITS=1. + * Thus U-Boot will not start. + * In Development environment (ITS=0 and SB_EN=1), the function + * may return back in case of non-fatal failures. + */ +#endif + + uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; + uboot(); +} + +#ifndef CONFIG_SPL_NAND_INIT +void nand_init(void) +{ +} + +void nand_deselect(void) +{ +} +#endif diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c new file mode 100644 index 0000000000..dfbdbca3ae --- /dev/null +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * FSL UPM NAND driver + * + * Copyright (C) 2007 MontaVista Software, Inc. + * Anton Vorontsov + */ + +#include +#include +#include +#include +#include +#include +#include + +static void fsl_upm_start_pattern(struct fsl_upm *upm, u32 pat_offset) +{ + clrsetbits_be32(upm->mxmr, MxMR_MAD_MSK, MxMR_OP_RUNP | pat_offset); + (void)in_be32(upm->mxmr); +} + +static void fsl_upm_end_pattern(struct fsl_upm *upm) +{ + clrbits_be32(upm->mxmr, MxMR_OP_RUNP); + + while (in_be32(upm->mxmr) & MxMR_OP_RUNP) + eieio(); +} + +static void fsl_upm_run_pattern(struct fsl_upm *upm, int width, + void __iomem *io_addr, u32 mar) +{ + out_be32(upm->mar, mar); + (void)in_be32(upm->mar); + switch (width) { + case 8: + out_8(io_addr, 0x0); + break; + case 16: + out_be16(io_addr, 0x0); + break; + case 32: + out_be32(io_addr, 0x0); + break; + } +} + +static void fun_wait(struct fsl_upm_nand *fun) +{ + if (fun->dev_ready) { + while (!fun->dev_ready(fun->chip_nr)) + debug("unexpected busy state\n"); + } else { + /* + * If the R/B pin is not connected, + * a short delay is necessary. + */ + udelay(1); + } +} + +#if CONFIG_SYS_NAND_MAX_CHIPS > 1 +static void fun_select_chip(struct mtd_info *mtd, int chip_nr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_upm_nand *fun = nand_get_controller_data(chip); + + if (chip_nr >= 0) { + fun->chip_nr = chip_nr; + chip->IO_ADDR_R = chip->IO_ADDR_W = + fun->upm.io_addr + fun->chip_offset * chip_nr; + } else if (chip_nr == -1) { + chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); + } +} +#endif + +static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_upm_nand *fun = nand_get_controller_data(chip); + void __iomem *io_addr; + u32 mar; + + if (!(ctrl & fun->last_ctrl)) { + fsl_upm_end_pattern(&fun->upm); + + if (cmd == NAND_CMD_NONE) + return; + + fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE); + } + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_ALE) + fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); + else if (ctrl & NAND_CLE) + fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); + } + + mar = cmd << (32 - fun->width); + io_addr = fun->upm.io_addr; +#if CONFIG_SYS_NAND_MAX_CHIPS > 1 + if (fun->chip_nr > 0) { + io_addr += fun->chip_offset * fun->chip_nr; + if (fun->upm_mar_chip_offset) + mar |= fun->upm_mar_chip_offset * fun->chip_nr; + } +#endif + fsl_upm_run_pattern(&fun->upm, fun->width, io_addr, mar); + + /* + * Some boards/chips needs this. At least the MPC8360E-RDK + * needs it. Probably weird chip, because I don't see any + * need for this on MPC8555E + Samsung K9F1G08U0A. Usually + * here are 0-2 unexpected busy states per block read. + */ + if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN) + fun_wait(fun); +} + +static u8 upm_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + return in_8(chip->IO_ADDR_R); +} + +static void upm_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + int i; + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_upm_nand *fun = nand_get_controller_data(chip); + + for (i = 0; i < len; i++) { + out_8(chip->IO_ADDR_W, buf[i]); + if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE) + fun_wait(fun); + } + + if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER) + fun_wait(fun); +} + +static void upm_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + int i; + struct nand_chip *chip = mtd_to_nand(mtd); + + for (i = 0; i < len; i++) + buf[i] = in_8(chip->IO_ADDR_R); +} + +static int nand_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct fsl_upm_nand *fun = nand_get_controller_data(chip); + + return fun->dev_ready(fun->chip_nr); +} + +int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun) +{ + if (fun->width != 8 && fun->width != 16 && fun->width != 32) + return -ENOSYS; + + fun->last_ctrl = NAND_CLE; + + nand_set_controller_data(chip, fun); + chip->chip_delay = fun->chip_delay; + chip->ecc.mode = NAND_ECC_SOFT; + chip->cmd_ctrl = fun_cmd_ctrl; +#if CONFIG_SYS_NAND_MAX_CHIPS > 1 + chip->select_chip = fun_select_chip; +#endif + chip->read_byte = upm_nand_read_byte; + chip->read_buf = upm_nand_read_buf; + chip->write_buf = upm_nand_write_buf; + if (fun->dev_ready) + chip->dev_ready = nand_dev_ready; + + return 0; +} diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c new file mode 100644 index 0000000000..1f4c74f0f6 --- /dev/null +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -0,0 +1,518 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2010 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com. + * + * (C) Copyright 2012 + * Amit Virdi, ST Microelectronics, amit.virdi@st.com. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static u32 fsmc_version; +static struct fsmc_regs *const fsmc_regs_p = (struct fsmc_regs *) + CONFIG_SYS_FSMC_BASE; + +/* + * ECC4 and ECC1 have 13 bytes and 3 bytes of ecc respectively for 512 bytes of + * data. ECC4 can correct up to 8 bits in 512 bytes of data while ECC1 can + * correct 1 bit in 512 bytes + */ + +static struct nand_ecclayout fsmc_ecc4_lp_layout = { + .eccbytes = 104, + .eccpos = { 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, + 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, + 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, + 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, + 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, + 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126 + }, + .oobfree = { + {.offset = 15, .length = 3}, + {.offset = 31, .length = 3}, + {.offset = 47, .length = 3}, + {.offset = 63, .length = 3}, + {.offset = 79, .length = 3}, + {.offset = 95, .length = 3}, + {.offset = 111, .length = 3}, + {.offset = 127, .length = 1} + } +}; + +/* + * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 224 bytes. 13*8 bytes + * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 118 + * bytes are free for use. + */ +static struct nand_ecclayout fsmc_ecc4_224_layout = { + .eccbytes = 104, + .eccpos = { 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, + 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, + 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, + 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, + 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, + 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, + 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, + 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126 + }, + .oobfree = { + {.offset = 15, .length = 3}, + {.offset = 31, .length = 3}, + {.offset = 47, .length = 3}, + {.offset = 63, .length = 3}, + {.offset = 79, .length = 3}, + {.offset = 95, .length = 3}, + {.offset = 111, .length = 3}, + {.offset = 127, .length = 97} + } +}; + +/* + * ECC placement definitions in oobfree type format + * There are 13 bytes of ecc for every 512 byte block and it has to be read + * consecutively and immediately after the 512 byte data block for hardware to + * generate the error bit offsets in 512 byte data + * Managing the ecc bytes in the following way makes it easier for software to + * read ecc bytes consecutive to data bytes. This way is similar to + * oobfree structure maintained already in u-boot nand driver + */ +static struct fsmc_eccplace fsmc_eccpl_lp = { + .eccplace = { + {.offset = 2, .length = 13}, + {.offset = 18, .length = 13}, + {.offset = 34, .length = 13}, + {.offset = 50, .length = 13}, + {.offset = 66, .length = 13}, + {.offset = 82, .length = 13}, + {.offset = 98, .length = 13}, + {.offset = 114, .length = 13} + } +}; + +static struct nand_ecclayout fsmc_ecc4_sp_layout = { + .eccbytes = 13, + .eccpos = { 0, 1, 2, 3, 6, 7, 8, + 9, 10, 11, 12, 13, 14 + }, + .oobfree = { + {.offset = 15, .length = 1}, + } +}; + +static struct fsmc_eccplace fsmc_eccpl_sp = { + .eccplace = { + {.offset = 0, .length = 4}, + {.offset = 6, .length = 9} + } +}; + +static struct nand_ecclayout fsmc_ecc1_layout = { + .eccbytes = 24, + .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52, + 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116}, + .oobfree = { + {.offset = 8, .length = 8}, + {.offset = 24, .length = 8}, + {.offset = 40, .length = 8}, + {.offset = 56, .length = 8}, + {.offset = 72, .length = 8}, + {.offset = 88, .length = 8}, + {.offset = 104, .length = 8}, + {.offset = 120, .length = 8} + } +}; + +/* Count the number of 0's in buff upto a max of max_bits */ +static int count_written_bits(uint8_t *buff, int size, int max_bits) +{ + int k, written_bits = 0; + + for (k = 0; k < size; k++) { + written_bits += hweight8(~buff[k]); + if (written_bits > max_bits) + break; + } + + return written_bits; +} + +static void fsmc_nand_hwcontrol(struct mtd_info *mtd, int cmd, uint ctrl) +{ + struct nand_chip *this = mtd_to_nand(mtd); + ulong IO_ADDR_W; + + if (ctrl & NAND_CTRL_CHANGE) { + IO_ADDR_W = (ulong)this->IO_ADDR_W; + + IO_ADDR_W &= ~(CONFIG_SYS_NAND_CLE | CONFIG_SYS_NAND_ALE); + if (ctrl & NAND_CLE) + IO_ADDR_W |= CONFIG_SYS_NAND_CLE; + if (ctrl & NAND_ALE) + IO_ADDR_W |= CONFIG_SYS_NAND_ALE; + + if (ctrl & NAND_NCE) { + writel(readl(&fsmc_regs_p->pc) | + FSMC_ENABLE, &fsmc_regs_p->pc); + } else { + writel(readl(&fsmc_regs_p->pc) & + ~FSMC_ENABLE, &fsmc_regs_p->pc); + } + this->IO_ADDR_W = (void *)IO_ADDR_W; + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); +} + +static int fsmc_bch8_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + /* The calculated ecc is actually the correction index in data */ + u32 err_idx[8]; + u32 num_err, i; + u32 ecc1, ecc2, ecc3, ecc4; + + num_err = (readl(&fsmc_regs_p->sts) >> 10) & 0xF; + + if (likely(num_err == 0)) + return 0; + + if (unlikely(num_err > 8)) { + /* + * This is a temporary erase check. A newly erased page read + * would result in an ecc error because the oob data is also + * erased to FF and the calculated ecc for an FF data is not + * FF..FF. + * This is a workaround to skip performing correction in case + * data is FF..FF + * + * Logic: + * For every page, each bit written as 0 is counted until these + * number of bits are greater than 8 (the maximum correction + * capability of FSMC for each 512 + 13 bytes) + */ + + int bits_ecc = count_written_bits(read_ecc, 13, 8); + int bits_data = count_written_bits(dat, 512, 8); + + if ((bits_ecc + bits_data) <= 8) { + if (bits_data) + memset(dat, 0xff, 512); + return bits_data + bits_ecc; + } + + return -EBADMSG; + } + + ecc1 = readl(&fsmc_regs_p->ecc1); + ecc2 = readl(&fsmc_regs_p->ecc2); + ecc3 = readl(&fsmc_regs_p->ecc3); + ecc4 = readl(&fsmc_regs_p->sts); + + err_idx[0] = (ecc1 >> 0) & 0x1FFF; + err_idx[1] = (ecc1 >> 13) & 0x1FFF; + err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F); + err_idx[3] = (ecc2 >> 7) & 0x1FFF; + err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF); + err_idx[5] = (ecc3 >> 1) & 0x1FFF; + err_idx[6] = (ecc3 >> 14) & 0x1FFF; + err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F); + + i = 0; + while (i < num_err) { + err_idx[i] ^= 3; + + if (err_idx[i] < 512 * 8) + __change_bit(err_idx[i], dat); + + i++; + } + + return num_err; +} + +static int fsmc_read_hwecc(struct mtd_info *mtd, + const u_char *data, u_char *ecc) +{ + u_int ecc_tmp; + int timeout = CONFIG_SYS_HZ; + ulong start; + + switch (fsmc_version) { + case FSMC_VER8: + start = get_timer(0); + while (get_timer(start) < timeout) { + /* + * Busy waiting for ecc computation + * to finish for 512 bytes + */ + if (readl(&fsmc_regs_p->sts) & FSMC_CODE_RDY) + break; + } + + ecc_tmp = readl(&fsmc_regs_p->ecc1); + ecc[0] = (u_char) (ecc_tmp >> 0); + ecc[1] = (u_char) (ecc_tmp >> 8); + ecc[2] = (u_char) (ecc_tmp >> 16); + ecc[3] = (u_char) (ecc_tmp >> 24); + + ecc_tmp = readl(&fsmc_regs_p->ecc2); + ecc[4] = (u_char) (ecc_tmp >> 0); + ecc[5] = (u_char) (ecc_tmp >> 8); + ecc[6] = (u_char) (ecc_tmp >> 16); + ecc[7] = (u_char) (ecc_tmp >> 24); + + ecc_tmp = readl(&fsmc_regs_p->ecc3); + ecc[8] = (u_char) (ecc_tmp >> 0); + ecc[9] = (u_char) (ecc_tmp >> 8); + ecc[10] = (u_char) (ecc_tmp >> 16); + ecc[11] = (u_char) (ecc_tmp >> 24); + + ecc_tmp = readl(&fsmc_regs_p->sts); + ecc[12] = (u_char) (ecc_tmp >> 16); + break; + + default: + ecc_tmp = readl(&fsmc_regs_p->ecc1); + ecc[0] = (u_char) (ecc_tmp >> 0); + ecc[1] = (u_char) (ecc_tmp >> 8); + ecc[2] = (u_char) (ecc_tmp >> 16); + break; + } + + return 0; +} + +void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) +{ + writel(readl(&fsmc_regs_p->pc) & ~FSMC_ECCPLEN_256, + &fsmc_regs_p->pc); + writel(readl(&fsmc_regs_p->pc) & ~FSMC_ECCEN, + &fsmc_regs_p->pc); + writel(readl(&fsmc_regs_p->pc) | FSMC_ECCEN, + &fsmc_regs_p->pc); +} + +/* + * 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 + * @page: page number to read + * + * This routine is needed for fsmc verison 8 as reading from NAND chip has to be + * performed in a strict sequence as follows: + * data(512 byte) -> ecc(13 byte) + * After this read, fsmc hardware generates and reports error data bits(upto 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) +{ + struct fsmc_eccplace *fsmc_eccpl; + int i, j, s, stat, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + int off, len, group = 0; + uint8_t oob[13] __attribute__ ((aligned (2))); + + /* Differentiate between small and large page ecc place definitions */ + if (mtd->writesize == 512) + fsmc_eccpl = &fsmc_eccpl_sp; + else + fsmc_eccpl = &fsmc_eccpl_lp; + + for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { + + chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, p, eccsize); + + for (j = 0; j < eccbytes;) { + off = fsmc_eccpl->eccplace[group].offset; + len = fsmc_eccpl->eccplace[group].length; + group++; + + /* + * length is intentionally kept a higher multiple of 2 + * to read at least 13 bytes even in case of 16 bit NAND + * devices + */ + if (chip->options & NAND_BUSWIDTH_16) + len = roundup(len, 2); + chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); + chip->read_buf(mtd, oob + j, len); + j += len; + } + + memcpy(&ecc_code[i], oob, 13); + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], + &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + + return 0; +} + +#ifndef CONFIG_SPL_BUILD +/* + * fsmc_nand_switch_ecc - switch the ECC operation between different engines + * + * @eccstrength - the number of bits that could be corrected + * (1 - HW, 4 - SW BCH4) + */ +int fsmc_nand_switch_ecc(uint32_t eccstrength) +{ + struct nand_chip *nand; + struct mtd_info *mtd; + int err; + + /* + * This functions is only called on SPEAr600 platforms, supporting + * 1 bit HW ECC. The BCH8 HW ECC (FSMC_VER8) from the ST-Ericsson + * Nomadik SoC is currently supporting this fsmc_nand_switch_ecc() + * function, as it doesn't need to switch to a different ECC layout. + */ + mtd = get_nand_dev_by_index(nand_curr_device); + nand = mtd_to_nand(mtd); + + /* Setup the ecc configurations again */ + if (eccstrength == 1) { + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.bytes = 3; + nand->ecc.strength = 1; + nand->ecc.layout = &fsmc_ecc1_layout; + nand->ecc.calculate = fsmc_read_hwecc; + nand->ecc.correct = nand_correct_data; + } else if (eccstrength == 4) { + /* + * .calculate .correct and .bytes will be set in + * nand_scan_tail() + */ + nand->ecc.mode = NAND_ECC_SOFT_BCH; + nand->ecc.strength = 4; + nand->ecc.layout = NULL; + } else { + printf("Error: ECC strength %d not supported!\n", eccstrength); + } + + /* Update NAND handling after ECC mode switch */ + err = nand_scan_tail(mtd); + + return err; +} +#endif /* CONFIG_SPL_BUILD */ + +int fsmc_nand_init(struct nand_chip *nand) +{ + static int chip_nr; + struct mtd_info *mtd; + u32 peripid2 = readl(&fsmc_regs_p->peripid2); + + fsmc_version = (peripid2 >> FSMC_REVISION_SHFT) & + FSMC_REVISION_MSK; + + writel(readl(&fsmc_regs_p->ctrl) | FSMC_WP, &fsmc_regs_p->ctrl); + +#if defined(CONFIG_SYS_FSMC_NAND_16BIT) + writel(FSMC_DEVWID_16 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON, + &fsmc_regs_p->pc); +#elif defined(CONFIG_SYS_FSMC_NAND_8BIT) + writel(FSMC_DEVWID_8 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON, + &fsmc_regs_p->pc); +#else +#error Please define CONFIG_SYS_FSMC_NAND_16BIT or CONFIG_SYS_FSMC_NAND_8BIT +#endif + writel(readl(&fsmc_regs_p->pc) | FSMC_TCLR_1 | FSMC_TAR_1, + &fsmc_regs_p->pc); + writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, + &fsmc_regs_p->comm); + writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, + &fsmc_regs_p->attrib); + + nand->options = 0; +#if defined(CONFIG_SYS_FSMC_NAND_16BIT) + nand->options |= NAND_BUSWIDTH_16; +#endif + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.size = 512; + nand->ecc.calculate = fsmc_read_hwecc; + nand->ecc.hwctl = fsmc_enable_hwecc; + nand->cmd_ctrl = fsmc_nand_hwcontrol; + nand->IO_ADDR_R = nand->IO_ADDR_W = + (void __iomem *)CONFIG_SYS_NAND_BASE; + nand->badblockbits = 7; + + mtd = nand_to_mtd(nand); + + switch (fsmc_version) { + case FSMC_VER8: + nand->ecc.bytes = 13; + nand->ecc.strength = 8; + nand->ecc.correct = fsmc_bch8_correct_data; + nand->ecc.read_page = fsmc_read_page_hwecc; + if (mtd->writesize == 512) + nand->ecc.layout = &fsmc_ecc4_sp_layout; + else { + if (mtd->oobsize == 224) + nand->ecc.layout = &fsmc_ecc4_224_layout; + else + nand->ecc.layout = &fsmc_ecc4_lp_layout; + } + + break; + default: + nand->ecc.bytes = 3; + nand->ecc.strength = 1; + nand->ecc.layout = &fsmc_ecc1_layout; + nand->ecc.correct = nand_correct_data; + break; + } + + /* Detect NAND chips */ + if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) + return -ENXIO; + + if (nand_scan_tail(mtd)) + return -ENXIO; + + if (nand_register(chip_nr++, mtd)) + return -ENXIO; + + return 0; +} diff --git a/drivers/mtd/nand/raw/kb9202_nand.c b/drivers/mtd/nand/raw/kb9202_nand.c new file mode 100644 index 0000000000..0f68f1cd86 --- /dev/null +++ b/drivers/mtd/nand/raw/kb9202_nand.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2006 + * KwikByte + * + * (C) Copyright 2009 + * Matthias Kaehlcke + */ + +#include +#include +#include +#include + +#include + +/* + * hardware specific access to control-lines + */ + +#define MASK_ALE (1 << 22) /* our ALE is A22 */ +#define MASK_CLE (1 << 21) /* our CLE is A21 */ + +#define KB9202_NAND_NCE (1 << 28) /* EN* on D28 */ +#define KB9202_NAND_BUSY (1 << 29) /* RB* on D29 */ + +#define KB9202_SMC2_NWS (1 << 2) +#define KB9202_SMC2_TDF (1 << 8) +#define KB9202_SMC2_RWSETUP (1 << 24) +#define KB9202_SMC2_RWHOLD (1 << 29) + +/* + * Board-specific function to access device control signals + */ +static void kb9202_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + if (ctrl & NAND_CTRL_CHANGE) { + ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; + + /* clear ALE and CLE bits */ + IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); + + if (ctrl & NAND_CLE) + IO_ADDR_W |= MASK_CLE; + + if (ctrl & NAND_ALE) + IO_ADDR_W |= MASK_ALE; + + this->IO_ADDR_W = (void *) IO_ADDR_W; + + if (ctrl & NAND_NCE) + writel(KB9202_NAND_NCE, AT91C_PIOC_CODR); + else + writel(KB9202_NAND_NCE, AT91C_PIOC_SODR); + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); +} + + +/* + * Board-specific function to access the device ready signal. + */ +static int kb9202_nand_ready(struct mtd_info *mtd) +{ + return readl(AT91C_PIOC_PDSR) & KB9202_NAND_BUSY; +} + + +/* + * Board-specific NAND init. Copied from include/linux/mtd/nand.h for reference. + * + * struct nand_chip - NAND Private Flash Chip Data + * @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 + * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines + * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing 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 + * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only + * be provided if a hardware ECC is available + * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines + * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) + * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about + * special functionality. See the defines for further explanation +*/ +/* + * This routine initializes controller and GPIOs. + */ +int board_nand_init(struct nand_chip *nand) +{ + unsigned int value; + + nand->ecc.mode = NAND_ECC_SOFT; + nand->cmd_ctrl = kb9202_nand_hwcontrol; + nand->dev_ready = kb9202_nand_ready; + + /* in case running outside of bootloader */ + writel(1 << AT91C_ID_PIOC, AT91C_PMC_PCER); + + /* setup nand flash access (allow ample margin) */ + /* 4 wait states, 1 setup, 1 hold, 1 float for 8-bit device */ + writel(AT91C_SMC2_WSEN | KB9202_SMC2_NWS | KB9202_SMC2_TDF | + AT91C_SMC2_DBW_8 | KB9202_SMC2_RWSETUP | KB9202_SMC2_RWHOLD, + AT91C_SMC_CSR3); + + /* enable internal NAND controller */ + value = readl(AT91C_EBI_CSA); + value |= AT91C_EBI_CS3A_SMC_SmartMedia; + writel(value, AT91C_EBI_CSA); + + /* enable SMOE/SMWE */ + writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_ASR); + writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_PDR); + writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_OER); + + /* set NCE to high */ + writel(KB9202_NAND_NCE, AT91C_PIOC_SODR); + + /* disable output on pin connected to the busy line of the NAND */ + writel(KB9202_NAND_BUSY, AT91C_PIOC_ODR); + + /* enable the PIO to control NCE and BUSY */ + writel(KB9202_NAND_NCE | KB9202_NAND_BUSY, AT91C_PIOC_PER); + + /* enable output for NCE */ + writel(KB9202_NAND_NCE, AT91C_PIOC_OER); + + return (0); +} diff --git a/drivers/mtd/nand/raw/kirkwood_nand.c b/drivers/mtd/nand/raw/kirkwood_nand.c new file mode 100644 index 0000000000..0757fa840b --- /dev/null +++ b/drivers/mtd/nand/raw/kirkwood_nand.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2009 + * Marvell Semiconductor + * Written-by: Prafulla Wadaskar + */ + +#include +#include +#include +#include +#include + +/* NAND Flash Soc registers */ +struct kwnandf_registers { + u32 rd_params; /* 0x10418 */ + u32 wr_param; /* 0x1041c */ + u8 pad[0x10470 - 0x1041c - 4]; + u32 ctrl; /* 0x10470 */ +}; + +static struct kwnandf_registers *nf_reg = + (struct kwnandf_registers *)KW_NANDF_BASE; + +static u32 nand_mpp_backup[9] = { 0 }; + +/* + * hardware specific access to control-lines/bits + */ +#define NAND_ACTCEBOOT_BIT 0x02 + +static void kw_nand_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *nc = mtd_to_nand(mtd); + u32 offs; + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + offs = (1 << 0); /* Commands with A[1:0] == 01 */ + else if (ctrl & NAND_ALE) + offs = (1 << 1); /* Addresses with A[1:0] == 10 */ + else + return; + + writeb(cmd, nc->IO_ADDR_W + offs); +} + +void kw_nand_select_chip(struct mtd_info *mtd, int chip) +{ + u32 data; + static const u32 nand_config[] = { + MPP0_NF_IO2, + MPP1_NF_IO3, + MPP2_NF_IO4, + MPP3_NF_IO5, + MPP4_NF_IO6, + MPP5_NF_IO7, + MPP18_NF_IO0, + MPP19_NF_IO1, + 0 + }; + + if (chip >= 0) + kirkwood_mpp_conf(nand_config, nand_mpp_backup); + else + kirkwood_mpp_conf(nand_mpp_backup, NULL); + + data = readl(&nf_reg->ctrl); + data |= NAND_ACTCEBOOT_BIT; + writel(data, &nf_reg->ctrl); +} + +int board_nand_init(struct nand_chip *nand) +{ + nand->options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING; +#if defined(CONFIG_SYS_NAND_NO_SUBPAGE_WRITE) + nand->options |= NAND_NO_SUBPAGE_WRITE; +#endif +#if defined(CONFIG_NAND_ECC_BCH) + nand->ecc.mode = NAND_ECC_SOFT_BCH; +#else + nand->ecc.mode = NAND_ECC_SOFT; +#endif + nand->cmd_ctrl = kw_nand_hwcontrol; + nand->chip_delay = 40; + nand->select_chip = kw_nand_select_chip; + return 0; +} diff --git a/drivers/mtd/nand/raw/kmeter1_nand.c b/drivers/mtd/nand/raw/kmeter1_nand.c new file mode 100644 index 0000000000..7103300060 --- /dev/null +++ b/drivers/mtd/nand/raw/kmeter1_nand.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2009 + * Heiko Schocher, DENX Software Engineering, hs@denx.de + */ + +#include +#include +#include + +#define CONFIG_NAND_MODE_REG (void *)(CONFIG_SYS_NAND_BASE + 0x20000) +#define CONFIG_NAND_DATA_REG (void *)(CONFIG_SYS_NAND_BASE + 0x30000) + +#define read_mode() in_8(CONFIG_NAND_MODE_REG) +#define write_mode(val) out_8(CONFIG_NAND_MODE_REG, val) +#define read_data() in_8(CONFIG_NAND_DATA_REG) +#define write_data(val) out_8(CONFIG_NAND_DATA_REG, val) + +#define KPN_RDY2 (1 << 7) +#define KPN_RDY1 (1 << 6) +#define KPN_WPN (1 << 4) +#define KPN_CE2N (1 << 3) +#define KPN_CE1N (1 << 2) +#define KPN_ALE (1 << 1) +#define KPN_CLE (1 << 0) + +#define KPN_DEFAULT_CHIP_DELAY 50 + +static int kpn_chip_ready(void) +{ + if (read_mode() & KPN_RDY1) + return 1; + + return 0; +} + +static void kpn_wait_rdy(void) +{ + int cnt = 1000000; + + while (--cnt && !kpn_chip_ready()) + udelay(1); + + if (!cnt) + printf ("timeout while waiting for RDY\n"); +} + +static void kpn_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + u8 reg_val = read_mode(); + + if (ctrl & NAND_CTRL_CHANGE) { + reg_val = reg_val & ~(KPN_ALE + KPN_CLE); + + if (ctrl & NAND_CLE) + reg_val = reg_val | KPN_CLE; + if (ctrl & NAND_ALE) + reg_val = reg_val | KPN_ALE; + if (ctrl & NAND_NCE) + reg_val = reg_val & ~KPN_CE1N; + else + reg_val = reg_val | KPN_CE1N; + + write_mode(reg_val); + } + if (cmd != NAND_CMD_NONE) + write_data(cmd); + + /* wait until flash is ready */ + kpn_wait_rdy(); +} + +static u_char kpn_nand_read_byte(struct mtd_info *mtd) +{ + return read_data(); +} + +static void kpn_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) { + write_data(buf[i]); + kpn_wait_rdy(); + } +} + +static void kpn_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + buf[i] = read_data(); +} + +static int kpn_nand_dev_ready(struct mtd_info *mtd) +{ + kpn_wait_rdy(); + + return 1; +} + +int board_nand_init(struct nand_chip *nand) +{ +#if defined(CONFIG_NAND_ECC_BCH) + nand->ecc.mode = NAND_ECC_SOFT_BCH; +#else + nand->ecc.mode = NAND_ECC_SOFT; +#endif + + /* Reference hardware control function */ + nand->cmd_ctrl = kpn_nand_hwcontrol; + nand->read_byte = kpn_nand_read_byte; + nand->write_buf = kpn_nand_write_buf; + nand->read_buf = kpn_nand_read_buf; + nand->dev_ready = kpn_nand_dev_ready; + nand->chip_delay = KPN_DEFAULT_CHIP_DELAY; + + /* reset mode register */ + write_mode(KPN_CE1N + KPN_CE2N + KPN_WPN); + return 0; +} diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c new file mode 100644 index 0000000000..5d4ffea608 --- /dev/null +++ b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c @@ -0,0 +1,761 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * LPC32xx MLC NAND flash controller driver + * + * (C) Copyright 2014 3ADEV + * Written by Albert ARIBAUD + * + * NOTE: + * + * The MLC NAND flash controller provides hardware Reed-Solomon ECC + * covering in- and out-of-band data together. Therefore, in- and out- + * of-band data must be written together in order to have a valid ECC. + * + * Consequently, pages with meaningful in-band data are written with + * blank (all-ones) out-of-band data and a valid ECC, and any later + * out-of-band data write will void the ECC. + * + * Therefore, code which reads such late-written out-of-band data + * should not rely on the ECC validity. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * MLC NAND controller registers. + */ +struct lpc32xx_nand_mlc_registers { + u8 buff[32768]; /* controller's serial data buffer */ + u8 data[32768]; /* NAND's raw data buffer */ + u32 cmd; + u32 addr; + u32 ecc_enc_reg; + u32 ecc_dec_reg; + u32 ecc_auto_enc_reg; + u32 ecc_auto_dec_reg; + u32 rpr; + u32 wpr; + u32 rubp; + u32 robp; + u32 sw_wp_add_low; + u32 sw_wp_add_hig; + u32 icr; + u32 time_reg; + u32 irq_mr; + u32 irq_sr; + u32 lock_pr; + u32 isr; + u32 ceh; +}; + +/* LOCK_PR register defines */ +#define LOCK_PR_UNLOCK_KEY 0x0000A25E /* Magic unlock value */ + +/* ICR defines */ +#define ICR_LARGE_BLOCKS 0x00000004 /* configure for 2KB blocks */ +#define ICR_ADDR4 0x00000002 /* configure for 4-word addrs */ + +/* CEH defines */ +#define CEH_NORMAL_CE 0x00000001 /* do not force CE ON */ + +/* ISR register defines */ +#define ISR_NAND_READY 0x00000001 +#define ISR_CONTROLLER_READY 0x00000002 +#define ISR_ECC_READY 0x00000004 +#define ISR_DECODER_ERRORS(s) ((((s) >> 4) & 3)+1) +#define ISR_DECODER_FAILURE 0x00000040 +#define ISR_DECODER_ERROR 0x00000008 + +/* time-out for NAND chip / controller loops, in us */ +#define LPC32X_NAND_TIMEOUT 5000 + +/* + * There is a single instance of the NAND MLC controller + */ + +static struct lpc32xx_nand_mlc_registers __iomem *lpc32xx_nand_mlc_registers + = (struct lpc32xx_nand_mlc_registers __iomem *)MLC_NAND_BASE; + +#define clkdiv(v, w, o) (((1+(clk/v)) & w) << o) + +/** + * OOB data in each small page are 6 'free' then 10 ECC bytes. + * To make things easier, when reading large pages, the four pages' + * 'free' OOB bytes are grouped in the first 24 bytes of the OOB buffer, + * while the the four ECC bytes are groupe in its last 40 bytes. + * + * The struct below represents how free vs ecc oob bytes are stored + * in the buffer. + * + * Note: the OOB bytes contain the bad block marker at offsets 0 and 1. + */ + +struct lpc32xx_oob { + struct { + uint8_t free_oob_bytes[6]; + } free[4]; + struct { + uint8_t ecc_oob_bytes[10]; + } ecc[4]; +}; + +/* + * Initialize the controller + */ + +static void lpc32xx_nand_init(void) +{ + unsigned int clk; + + /* Configure controller for no software write protection, x8 bus + width, large block device, and 4 address words */ + + /* unlock controller registers with magic key */ + writel(LOCK_PR_UNLOCK_KEY, + &lpc32xx_nand_mlc_registers->lock_pr); + + /* enable large blocks and large NANDs */ + writel(ICR_LARGE_BLOCKS | ICR_ADDR4, + &lpc32xx_nand_mlc_registers->icr); + + /* Make sure MLC interrupts are disabled */ + writel(0, &lpc32xx_nand_mlc_registers->irq_mr); + + /* Normal chip enable operation */ + writel(CEH_NORMAL_CE, + &lpc32xx_nand_mlc_registers->ceh); + + /* Setup NAND timing */ + clk = get_hclk_clk_rate(); + + writel( + clkdiv(CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY, 0x03, 24) | + clkdiv(CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY, 0x1F, 19) | + clkdiv(CONFIG_LPC32XX_NAND_MLC_NAND_TA, 0x07, 16) | + clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_HIGH, 0x0F, 12) | + clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_LOW, 0x0F, 8) | + clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_HIGH, 0x0F, 4) | + clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_LOW, 0x0F, 0), + &lpc32xx_nand_mlc_registers->time_reg); +} + +#if !defined(CONFIG_SPL_BUILD) + +/** + * lpc32xx_cmd_ctrl - write command to either cmd or data register + */ + +static void lpc32xx_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->cmd); + else if (ctrl & NAND_ALE) + writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->addr); +} + +/** + * lpc32xx_read_byte - read a byte from the NAND + * @mtd: MTD device structure + */ + +static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) +{ + return readb(&lpc32xx_nand_mlc_registers->data); +} + +/** + * lpc32xx_dev_ready - test if NAND device (actually controller) is ready + * @mtd: MTD device structure + * @mode: mode to set the ECC HW to. + */ + +static int lpc32xx_dev_ready(struct mtd_info *mtd) +{ + /* means *controller* ready for us */ + int status = readl(&lpc32xx_nand_mlc_registers->isr); + return status & ISR_CONTROLLER_READY; +} + +/** + * ECC layout -- this is needed whatever ECC mode we are using. + * In a 2KB (4*512B) page, R/S codes occupy 40 (4*10) bytes. + * To make U-Boot's life easier, we pack 'useable' OOB at the + * front and R/S ECC at the back. + */ + +static struct nand_ecclayout lpc32xx_largepage_ecclayout = { + .eccbytes = 40, + .eccpos = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 48, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + }, + .oobfree = { + /* bytes 0 and 1 are used for the bad block marker */ + { + .offset = 2, + .length = 22 + }, + } +}; + +/** + * lpc32xx_read_page_hwecc - read in- and out-of-band data with 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 + * @page: page number to read + * + * Use large block Auto Decode Read Mode(1) as described in User Manual + * section 8.6.2.1. + * + * The initial Read Mode and Read Start commands are sent by the caller. + * + * ECC will be false if out-of-band data has been updated since in-band + * data was initially written. + */ + +static int lpc32xx_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int oob_required, + int page) +{ + unsigned int i, status, timeout, err, max_bitflips = 0; + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; + + /* go through all four small pages */ + for (i = 0; i < 4; i++) { + /* start auto decode (reads 528 NAND bytes) */ + writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg); + /* wait for controller to return to ready state */ + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { + status = readl(&lpc32xx_nand_mlc_registers->isr); + if (status & ISR_CONTROLLER_READY) + break; + udelay(1); + } + /* if decoder failed, return failure */ + if (status & ISR_DECODER_FAILURE) + return -1; + /* keep count of maximum bitflips performed */ + if (status & ISR_DECODER_ERROR) { + err = ISR_DECODER_ERRORS(status); + if (err > max_bitflips) + max_bitflips = err; + } + /* copy first 512 bytes into buffer */ + memcpy(buf+512*i, lpc32xx_nand_mlc_registers->buff, 512); + /* copy next 6 bytes at front of OOB buffer */ + memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6); + /* copy last 10 bytes (R/S ECC) at back of OOB buffer */ + memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10); + } + return max_bitflips; +} + +/** + * lpc32xx_read_page_raw - read raw (in-band, out-of-band and ECC) data + * @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 + * + * Read NAND directly; can read pages with invalid ECC. + */ + +static int lpc32xx_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int oob_required, + int page) +{ + unsigned int i, status, timeout; + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; + + /* when we get here we've already had the Read Mode(1) */ + + /* go through all four small pages */ + for (i = 0; i < 4; i++) { + /* wait for NAND to return to ready state */ + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { + status = readl(&lpc32xx_nand_mlc_registers->isr); + if (status & ISR_NAND_READY) + break; + udelay(1); + } + /* if NAND stalled, return failure */ + if (!(status & ISR_NAND_READY)) + return -1; + /* copy first 512 bytes into buffer */ + memcpy(buf+512*i, lpc32xx_nand_mlc_registers->data, 512); + /* copy next 6 bytes at front of OOB buffer */ + memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->data, 6); + /* copy last 10 bytes (R/S ECC) at back of OOB buffer */ + memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->data, 10); + } + return 0; +} + +/** + * lpc32xx_read_oob - read out-of-band data + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * + * Read out-of-band data. User Manual section 8.6.4 suggests using Read + * Mode(3) which the controller will turn into a Read Mode(1) internally + * but nand_base.c will turn Mode(3) into Mode(0), so let's use Mode(0) + * directly. + * + * ECC covers in- and out-of-band data and was written when out-of-band + * data was blank. Therefore, if the out-of-band being read here is not + * blank, then the ECC will be false and the read will return bitflips, + * even in case of ECC failure where we will return 5 bitflips. The + * caller should be prepared to handle this. + */ + +static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + unsigned int i, status, timeout, err, max_bitflips = 0; + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; + + /* No command was sent before calling read_oob() so send one */ + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + /* go through all four small pages */ + for (i = 0; i < 4; i++) { + /* start auto decode (reads 528 NAND bytes) */ + writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg); + /* wait for controller to return to ready state */ + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { + status = readl(&lpc32xx_nand_mlc_registers->isr); + if (status & ISR_CONTROLLER_READY) + break; + udelay(1); + } + /* if decoder failure, count 'one too many' bitflips */ + if (status & ISR_DECODER_FAILURE) + max_bitflips = 5; + /* keep count of maximum bitflips performed */ + if (status & ISR_DECODER_ERROR) { + err = ISR_DECODER_ERRORS(status); + if (err > max_bitflips) + max_bitflips = err; + } + /* set read pointer to OOB area */ + writel(0, &lpc32xx_nand_mlc_registers->robp); + /* copy next 6 bytes at front of OOB buffer */ + memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6); + /* copy next 10 bytes (R/S ECC) at back of OOB buffer */ + memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10); + } + return max_bitflips; +} + +/** + * lpc32xx_write_page_hwecc - write in- and out-of-band data with ECC + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB + * + * Use large block Auto Encode as per User Manual section 8.6.4. + * + * The initial Write Serial Input and final Auto Program commands are + * sent by the caller. + */ + +static int lpc32xx_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required, + int page) +{ + unsigned int i, status, timeout; + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; + + /* when we get here we've already had the SEQIN */ + for (i = 0; i < 4; i++) { + /* start encode (expects 518 writes to buff) */ + writel(0, &lpc32xx_nand_mlc_registers->ecc_enc_reg); + /* copy first 512 bytes from buffer */ + memcpy(&lpc32xx_nand_mlc_registers->buff, buf+512*i, 512); + /* copy next 6 bytes from OOB buffer -- excluding ECC */ + memcpy(&lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6); + /* wait for ECC to return to ready state */ + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { + status = readl(&lpc32xx_nand_mlc_registers->isr); + if (status & ISR_ECC_READY) + break; + udelay(1); + } + /* if ECC stalled, return failure */ + if (!(status & ISR_ECC_READY)) + return -1; + /* Trigger auto encode (writes 528 bytes to NAND) */ + writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_enc_reg); + /* wait for controller to return to ready state */ + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { + status = readl(&lpc32xx_nand_mlc_registers->isr); + if (status & ISR_CONTROLLER_READY) + break; + udelay(1); + } + /* if controller stalled, return error */ + if (!(status & ISR_CONTROLLER_READY)) + return -1; + } + return 0; +} + +/** + * lpc32xx_write_page_raw - write raw (in-band, out-of-band and ECC) data + * @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 + * + * Use large block write but without encode. + * + * The initial Write Serial Input and final Auto Program commands are + * sent by the caller. + * + * This function will write the full out-of-band data, including the + * ECC area. Therefore, it can write pages with valid *or* invalid ECC. + */ + +static int lpc32xx_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required, + int page) +{ + unsigned int i; + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; + + /* when we get here we've already had the Read Mode(1) */ + for (i = 0; i < 4; i++) { + /* copy first 512 bytes from buffer */ + memcpy(lpc32xx_nand_mlc_registers->buff, buf+512*i, 512); + /* copy next 6 bytes into OOB buffer -- excluding ECC */ + memcpy(lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6); + /* copy next 10 bytes into OOB buffer -- that is 'ECC' */ + memcpy(lpc32xx_nand_mlc_registers->buff, &oob->ecc[i], 10); + } + return 0; +} + +/** + * lpc32xx_write_oob - write out-of-band data + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * + * Since ECC covers in- and out-of-band data, writing out-of-band data + * with ECC will render the page ECC wrong -- or, if the page was blank, + * then it will produce a good ECC but a later in-band data write will + * render it wrong. + * + * Therefore, do not compute or write any ECC, and always return success. + * + * This implies that we do four writes, since non-ECC out-of-band data + * are not contiguous in a large page. + */ + +static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + /* update oob on all 4 subpages in sequence */ + unsigned int i, status, timeout; + struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi; + + for (i = 0; i < 4; i++) { + /* start data input */ + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x200+0x210*i, page); + /* copy 6 non-ECC out-of-band bytes directly into NAND */ + memcpy(lpc32xx_nand_mlc_registers->data, &oob->free[i], 6); + /* program page */ + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + /* wait for NAND to return to ready state */ + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { + status = readl(&lpc32xx_nand_mlc_registers->isr); + if (status & ISR_NAND_READY) + break; + udelay(1); + } + /* if NAND stalled, return error */ + if (!(status & ISR_NAND_READY)) + return -1; + } + return 0; +} + +/** + * lpc32xx_waitfunc - wait until a command is done + * @mtd: MTD device structure + * @chip: NAND chip structure + * + * Wait for controller and FLASH to both be ready. + */ + +static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) +{ + int status; + unsigned int timeout; + /* wait until both controller and NAND are ready */ + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { + status = readl(&lpc32xx_nand_mlc_registers->isr); + if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY)) + == (ISR_CONTROLLER_READY || ISR_NAND_READY)) + break; + udelay(1); + } + /* if controller or NAND stalled, return error */ + if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY)) + != (ISR_CONTROLLER_READY || ISR_NAND_READY)) + return -1; + /* write NAND status command */ + writel(NAND_CMD_STATUS, &lpc32xx_nand_mlc_registers->cmd); + /* read back status and return it */ + return readb(&lpc32xx_nand_mlc_registers->data); +} + +/* + * We are self-initializing, so we need our own chip struct + */ + +static struct nand_chip lpc32xx_chip; + +/* + * Initialize the controller + */ + +void board_nand_init(void) +{ + struct mtd_info *mtd = nand_to_mtd(&lpc32xx_chip); + int ret; + + /* Set all BOARDSPECIFIC (actually core-specific) fields */ + + lpc32xx_chip.IO_ADDR_R = &lpc32xx_nand_mlc_registers->buff; + lpc32xx_chip.IO_ADDR_W = &lpc32xx_nand_mlc_registers->buff; + lpc32xx_chip.cmd_ctrl = lpc32xx_cmd_ctrl; + /* do not set init_size: nand_base.c will read sizes from chip */ + lpc32xx_chip.dev_ready = lpc32xx_dev_ready; + /* do not set setup_read_retry: this is NAND-chip-specific */ + /* do not set chip_delay: we have dev_ready defined. */ + lpc32xx_chip.options |= NAND_NO_SUBPAGE_WRITE; + + /* Set needed ECC fields */ + + lpc32xx_chip.ecc.mode = NAND_ECC_HW; + lpc32xx_chip.ecc.layout = &lpc32xx_largepage_ecclayout; + lpc32xx_chip.ecc.size = 512; + lpc32xx_chip.ecc.bytes = 10; + lpc32xx_chip.ecc.strength = 4; + lpc32xx_chip.ecc.read_page = lpc32xx_read_page_hwecc; + lpc32xx_chip.ecc.read_page_raw = lpc32xx_read_page_raw; + lpc32xx_chip.ecc.write_page = lpc32xx_write_page_hwecc; + lpc32xx_chip.ecc.write_page_raw = lpc32xx_write_page_raw; + lpc32xx_chip.ecc.read_oob = lpc32xx_read_oob; + lpc32xx_chip.ecc.write_oob = lpc32xx_write_oob; + lpc32xx_chip.waitfunc = lpc32xx_waitfunc; + + lpc32xx_chip.read_byte = lpc32xx_read_byte; /* FIXME: NEEDED? */ + + /* BBT options: read from last two pages */ + lpc32xx_chip.bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_LASTBLOCK + | NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE + | NAND_BBT_WRITE; + + /* Initialize NAND interface */ + lpc32xx_nand_init(); + + /* identify chip */ + ret = nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL); + if (ret) { + pr_err("nand_scan_ident returned %i", ret); + return; + } + + /* finish scanning the chip */ + ret = nand_scan_tail(mtd); + if (ret) { + pr_err("nand_scan_tail returned %i", ret); + return; + } + + /* chip is good, register it */ + ret = nand_register(0, mtd); + if (ret) + pr_err("nand_register returned %i", ret); +} + +#else /* defined(CONFIG_SPL_BUILD) */ + +void nand_init(void) +{ + /* enable NAND controller */ + lpc32xx_mlc_nand_init(); + /* initialize NAND controller */ + lpc32xx_nand_init(); +} + +void nand_deselect(void) +{ + /* nothing to do, but SPL requires this function */ +} + +static int read_single_page(uint8_t *dest, int page, + struct lpc32xx_oob *oob) +{ + int status, i, timeout, err, max_bitflips = 0; + + /* enter read mode */ + writel(NAND_CMD_READ0, &lpc32xx_nand_mlc_registers->cmd); + /* send column (lsb then MSB) and page (lsb to MSB) */ + writel(0, &lpc32xx_nand_mlc_registers->addr); + writel(0, &lpc32xx_nand_mlc_registers->addr); + writel(page & 0xff, &lpc32xx_nand_mlc_registers->addr); + writel((page>>8) & 0xff, &lpc32xx_nand_mlc_registers->addr); + writel((page>>16) & 0xff, &lpc32xx_nand_mlc_registers->addr); + /* start reading */ + writel(NAND_CMD_READSTART, &lpc32xx_nand_mlc_registers->cmd); + + /* large page auto decode read */ + for (i = 0; i < 4; i++) { + /* start auto decode (reads 528 NAND bytes) */ + writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg); + /* wait for controller to return to ready state */ + for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) { + status = readl(&lpc32xx_nand_mlc_registers->isr); + if (status & ISR_CONTROLLER_READY) + break; + udelay(1); + } + /* if controller stalled, return error */ + if (!(status & ISR_CONTROLLER_READY)) + return -1; + /* if decoder failure, return error */ + if (status & ISR_DECODER_FAILURE) + return -1; + /* keep count of maximum bitflips performed */ + if (status & ISR_DECODER_ERROR) { + err = ISR_DECODER_ERRORS(status); + if (err > max_bitflips) + max_bitflips = err; + } + /* copy first 512 bytes into buffer */ + memcpy(dest+i*512, lpc32xx_nand_mlc_registers->buff, 512); + /* copy next 6 bytes bytes into OOB buffer */ + memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6); + } + return max_bitflips; +} + +/* + * Load U-Boot signed image. + * This loads an image from NAND, skipping bad blocks. + * A block is declared bad if at least one of its readable pages has + * a bad block marker in its OOB at position 0. + * If all pages ion a block are unreadable, the block is considered + * bad (i.e., assumed not to be part of the image) and skipped. + * + * IMPORTANT NOTE: + * + * If the first block of the image is fully unreadable, it will be + * ignored and skipped as if it had been marked bad. If it was not + * actually marked bad at the time of writing the image, the resulting + * image loaded will lack a header and magic number. It could thus be + * considered as a raw, headerless, image and SPL might erroneously + * jump into it. + * + * In order to avoid this risk, LPC32XX-based boards which use this + * driver MUST define CONFIG_SPL_PANIC_ON_RAW_IMAGE. + */ + +#define BYTES_PER_PAGE 2048 +#define PAGES_PER_BLOCK 64 +#define BYTES_PER_BLOCK (BYTES_PER_PAGE * PAGES_PER_BLOCK) +#define PAGES_PER_CHIP_MAX 524288 + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) +{ + int bytes_left = size; + int pages_left = DIV_ROUND_UP(size, BYTES_PER_PAGE); + int blocks_left = DIV_ROUND_UP(size, BYTES_PER_BLOCK); + int block = 0; + int page = offs / BYTES_PER_PAGE; + /* perform reads block by block */ + while (blocks_left) { + /* compute first page number to read */ + void *block_page_dst = dst; + /* read at most one block, possibly less */ + int block_bytes_left = bytes_left; + if (block_bytes_left > BYTES_PER_BLOCK) + block_bytes_left = BYTES_PER_BLOCK; + /* keep track of good, failed, and "bad" pages */ + int block_pages_good = 0; + int block_pages_bad = 0; + int block_pages_err = 0; + /* we shall read a full block of pages, maybe less */ + int block_pages_left = pages_left; + if (block_pages_left > PAGES_PER_BLOCK) + block_pages_left = PAGES_PER_BLOCK; + int block_pages = block_pages_left; + int block_page = page; + /* while pages are left and the block is not known as bad */ + while ((block_pages > 0) && (block_pages_bad == 0)) { + /* we will read OOB, too, for bad block markers */ + struct lpc32xx_oob oob; + /* read page */ + int res = read_single_page(block_page_dst, block_page, + &oob); + /* count readable pages */ + if (res >= 0) { + /* this page is good */ + block_pages_good++; + /* this page is bad */ + if ((oob.free[0].free_oob_bytes[0] != 0xff) + | (oob.free[0].free_oob_bytes[1] != 0xff)) + block_pages_bad++; + } else + /* count errors */ + block_pages_err++; + /* we're done with this page */ + block_page++; + block_page_dst += BYTES_PER_PAGE; + if (block_pages) + block_pages--; + } + /* a fully unreadable block is considered bad */ + if (block_pages_good == 0) + block_pages_bad = block_pages_err; + /* errors are fatal only in good blocks */ + if ((block_pages_err > 0) && (block_pages_bad == 0)) + return -1; + /* we keep reads only of good blocks */ + if (block_pages_bad == 0) { + dst += block_bytes_left; + bytes_left -= block_bytes_left; + pages_left -= block_pages_left; + blocks_left--; + } + /* good or bad, we're done with this block */ + block++; + page += PAGES_PER_BLOCK; + } + + /* report success */ + return 0; +} + +#endif /* CONFIG_SPL_BUILD */ diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_slc.c b/drivers/mtd/nand/raw/lpc32xx_nand_slc.c new file mode 100644 index 0000000000..99f6e15f4e --- /dev/null +++ b/drivers/mtd/nand/raw/lpc32xx_nand_slc.c @@ -0,0 +1,597 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * LPC32xx SLC NAND flash controller driver + * + * (C) Copyright 2015 Vladimir Zapolskiy + * + * Hardware ECC support original source code + * Copyright (C) 2008 by NXP Semiconductors + * Author: Kevin Wells + * + * Copyright (c) 2015 Tyco Fire Protection Products. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_DMA_LPC32XX) && defined(CONFIG_SPL_BUILD) +#warning "DMA support in SPL image is not tested" +#endif + +struct lpc32xx_nand_slc_regs { + u32 data; + u32 addr; + u32 cmd; + u32 stop; + u32 ctrl; + u32 cfg; + u32 stat; + u32 int_stat; + u32 ien; + u32 isr; + u32 icr; + u32 tac; + u32 tc; + u32 ecc; + u32 dma_data; +}; + +/* CFG register */ +#define CFG_CE_LOW (1 << 5) +#define CFG_DMA_ECC (1 << 4) /* Enable DMA ECC bit */ +#define CFG_ECC_EN (1 << 3) /* ECC enable bit */ +#define CFG_DMA_BURST (1 << 2) /* DMA burst bit */ +#define CFG_DMA_DIR (1 << 1) /* DMA write(0)/read(1) bit */ + +/* CTRL register */ +#define CTRL_SW_RESET (1 << 2) +#define CTRL_ECC_CLEAR (1 << 1) /* Reset ECC bit */ +#define CTRL_DMA_START (1 << 0) /* Start DMA channel bit */ + +/* STAT register */ +#define STAT_DMA_FIFO (1 << 2) /* DMA FIFO has data bit */ +#define STAT_NAND_READY (1 << 0) + +/* INT_STAT register */ +#define INT_STAT_TC (1 << 1) +#define INT_STAT_RDY (1 << 0) + +/* TAC register bits, be aware of overflows */ +#define TAC_W_RDY(n) (max_t(uint32_t, (n), 0xF) << 28) +#define TAC_W_WIDTH(n) (max_t(uint32_t, (n), 0xF) << 24) +#define TAC_W_HOLD(n) (max_t(uint32_t, (n), 0xF) << 20) +#define TAC_W_SETUP(n) (max_t(uint32_t, (n), 0xF) << 16) +#define TAC_R_RDY(n) (max_t(uint32_t, (n), 0xF) << 12) +#define TAC_R_WIDTH(n) (max_t(uint32_t, (n), 0xF) << 8) +#define TAC_R_HOLD(n) (max_t(uint32_t, (n), 0xF) << 4) +#define TAC_R_SETUP(n) (max_t(uint32_t, (n), 0xF) << 0) + +/* NAND ECC Layout for small page NAND devices + * Note: For large page devices, the default layouts are used. */ +static struct nand_ecclayout lpc32xx_nand_oob_16 = { + .eccbytes = 6, + .eccpos = {10, 11, 12, 13, 14, 15}, + .oobfree = { + {.offset = 0, + . length = 4}, + {.offset = 6, + . length = 4} + } +}; + +#if defined(CONFIG_DMA_LPC32XX) +#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE) + +/* + * DMA Descriptors + * For Large Block: 17 descriptors = ((16 Data and ECC Read) + 1 Spare Area) + * For Small Block: 5 descriptors = ((4 Data and ECC Read) + 1 Spare Area) + */ +static struct lpc32xx_dmac_ll dmalist[ECCSTEPS * 2 + 1]; +static u32 ecc_buffer[8]; /* MAX ECC size */ +static unsigned int dmachan = (unsigned int)-1; /* Invalid channel */ + +/* + * Helper macro for the DMA client (i.e. NAND SLC): + * - to write the next DMA linked list item address + * (see arch/include/asm/arch-lpc32xx/dma.h). + * - to assign the DMA data register to DMA source or destination address. + * - to assign the ECC register to DMA source or destination address. + */ +#define lpc32xx_dmac_next_lli(x) ((u32)x) +#define lpc32xx_dmac_set_dma_data() ((u32)&lpc32xx_nand_slc_regs->dma_data) +#define lpc32xx_dmac_set_ecc() ((u32)&lpc32xx_nand_slc_regs->ecc) +#endif + +static struct lpc32xx_nand_slc_regs __iomem *lpc32xx_nand_slc_regs + = (struct lpc32xx_nand_slc_regs __iomem *)SLC_NAND_BASE; + +static void lpc32xx_nand_init(void) +{ + uint32_t hclk = get_hclk_clk_rate(); + + /* Reset SLC NAND controller */ + writel(CTRL_SW_RESET, &lpc32xx_nand_slc_regs->ctrl); + + /* 8-bit bus, no DMA, no ECC, ordinary CE signal */ + writel(0, &lpc32xx_nand_slc_regs->cfg); + + /* Interrupts disabled and cleared */ + writel(0, &lpc32xx_nand_slc_regs->ien); + writel(INT_STAT_TC | INT_STAT_RDY, + &lpc32xx_nand_slc_regs->icr); + + /* Configure NAND flash timings */ + writel(TAC_W_RDY(CONFIG_LPC32XX_NAND_SLC_WDR_CLKS) | + TAC_W_WIDTH(hclk / CONFIG_LPC32XX_NAND_SLC_WWIDTH) | + TAC_W_HOLD(hclk / CONFIG_LPC32XX_NAND_SLC_WHOLD) | + TAC_W_SETUP(hclk / CONFIG_LPC32XX_NAND_SLC_WSETUP) | + TAC_R_RDY(CONFIG_LPC32XX_NAND_SLC_RDR_CLKS) | + TAC_R_WIDTH(hclk / CONFIG_LPC32XX_NAND_SLC_RWIDTH) | + TAC_R_HOLD(hclk / CONFIG_LPC32XX_NAND_SLC_RHOLD) | + TAC_R_SETUP(hclk / CONFIG_LPC32XX_NAND_SLC_RSETUP), + &lpc32xx_nand_slc_regs->tac); +} + +static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, + int cmd, unsigned int ctrl) +{ + debug("ctrl: 0x%08x, cmd: 0x%08x\n", ctrl, cmd); + + if (ctrl & NAND_NCE) + setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_CE_LOW); + else + clrbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_CE_LOW); + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + writel(cmd & 0xFF, &lpc32xx_nand_slc_regs->cmd); + else if (ctrl & NAND_ALE) + writel(cmd & 0xFF, &lpc32xx_nand_slc_regs->addr); +} + +static int lpc32xx_nand_dev_ready(struct mtd_info *mtd) +{ + return readl(&lpc32xx_nand_slc_regs->stat) & STAT_NAND_READY; +} + +#if defined(CONFIG_DMA_LPC32XX) +/* + * Prepares DMA descriptors for NAND RD/WR operations + * If the size is < 256 Bytes then it is assumed to be + * an OOB transfer + */ +static void lpc32xx_nand_dma_configure(struct nand_chip *chip, + const u8 *buffer, int size, + int read) +{ + u32 i, dmasrc, ctrl, ecc_ctrl, oob_ctrl, dmadst; + struct lpc32xx_dmac_ll *dmalist_cur; + struct lpc32xx_dmac_ll *dmalist_cur_ecc; + + /* + * CTRL descriptor entry for reading ECC + * Copy Multiple times to sync DMA with Flash Controller + */ + ecc_ctrl = 0x5 | + DMAC_CHAN_SRC_BURST_1 | + DMAC_CHAN_DEST_BURST_1 | + DMAC_CHAN_SRC_WIDTH_32 | + DMAC_CHAN_DEST_WIDTH_32 | + DMAC_CHAN_DEST_AHB1; + + /* CTRL descriptor entry for reading/writing Data */ + ctrl = (CONFIG_SYS_NAND_ECCSIZE / 4) | + DMAC_CHAN_SRC_BURST_4 | + DMAC_CHAN_DEST_BURST_4 | + DMAC_CHAN_SRC_WIDTH_32 | + DMAC_CHAN_DEST_WIDTH_32 | + DMAC_CHAN_DEST_AHB1; + + /* CTRL descriptor entry for reading/writing Spare Area */ + oob_ctrl = (CONFIG_SYS_NAND_OOBSIZE / 4) | + DMAC_CHAN_SRC_BURST_4 | + DMAC_CHAN_DEST_BURST_4 | + DMAC_CHAN_SRC_WIDTH_32 | + DMAC_CHAN_DEST_WIDTH_32 | + DMAC_CHAN_DEST_AHB1; + + if (read) { + dmasrc = lpc32xx_dmac_set_dma_data(); + dmadst = (u32)buffer; + ctrl |= DMAC_CHAN_DEST_AUTOINC; + } else { + dmadst = lpc32xx_dmac_set_dma_data(); + dmasrc = (u32)buffer; + ctrl |= DMAC_CHAN_SRC_AUTOINC; + } + + /* + * Write Operation Sequence for Small Block NAND + * ---------------------------------------------------------- + * 1. X'fer 256 bytes of data from Memory to Flash. + * 2. Copy generated ECC data from Register to Spare Area + * 3. X'fer next 256 bytes of data from Memory to Flash. + * 4. Copy generated ECC data from Register to Spare Area. + * 5. X'fer 16 byets of Spare area from Memory to Flash. + * Read Operation Sequence for Small Block NAND + * ---------------------------------------------------------- + * 1. X'fer 256 bytes of data from Flash to Memory. + * 2. Copy generated ECC data from Register to ECC calc Buffer. + * 3. X'fer next 256 bytes of data from Flash to Memory. + * 4. Copy generated ECC data from Register to ECC calc Buffer. + * 5. X'fer 16 bytes of Spare area from Flash to Memory. + * Write Operation Sequence for Large Block NAND + * ---------------------------------------------------------- + * 1. Steps(1-4) of Write Operations repeate for four times + * which generates 16 DMA descriptors to X'fer 2048 bytes of + * data & 32 bytes of ECC data. + * 2. X'fer 64 bytes of Spare area from Memory to Flash. + * Read Operation Sequence for Large Block NAND + * ---------------------------------------------------------- + * 1. Steps(1-4) of Read Operations repeate for four times + * which generates 16 DMA descriptors to X'fer 2048 bytes of + * data & 32 bytes of ECC data. + * 2. X'fer 64 bytes of Spare area from Flash to Memory. + */ + + for (i = 0; i < size/CONFIG_SYS_NAND_ECCSIZE; i++) { + dmalist_cur = &dmalist[i * 2]; + dmalist_cur_ecc = &dmalist[(i * 2) + 1]; + + dmalist_cur->dma_src = (read ? (dmasrc) : (dmasrc + (i*256))); + dmalist_cur->dma_dest = (read ? (dmadst + (i*256)) : dmadst); + dmalist_cur->next_lli = lpc32xx_dmac_next_lli(dmalist_cur_ecc); + dmalist_cur->next_ctrl = ctrl; + + dmalist_cur_ecc->dma_src = lpc32xx_dmac_set_ecc(); + dmalist_cur_ecc->dma_dest = (u32)&ecc_buffer[i]; + dmalist_cur_ecc->next_lli = + lpc32xx_dmac_next_lli(&dmalist[(i * 2) + 2]); + dmalist_cur_ecc->next_ctrl = ecc_ctrl; + } + + if (i) { /* Data only transfer */ + dmalist_cur_ecc = &dmalist[(i * 2) - 1]; + dmalist_cur_ecc->next_lli = 0; + dmalist_cur_ecc->next_ctrl |= DMAC_CHAN_INT_TC_EN; + return; + } + + /* OOB only transfer */ + if (read) { + dmasrc = lpc32xx_dmac_set_dma_data(); + dmadst = (u32)buffer; + oob_ctrl |= DMAC_CHAN_DEST_AUTOINC; + } else { + dmadst = lpc32xx_dmac_set_dma_data(); + dmasrc = (u32)buffer; + oob_ctrl |= DMAC_CHAN_SRC_AUTOINC; + } + + /* Read/ Write Spare Area Data To/From Flash */ + dmalist_cur = &dmalist[i * 2]; + dmalist_cur->dma_src = dmasrc; + dmalist_cur->dma_dest = dmadst; + dmalist_cur->next_lli = 0; + dmalist_cur->next_ctrl = (oob_ctrl | DMAC_CHAN_INT_TC_EN); +} + +static void lpc32xx_nand_xfer(struct mtd_info *mtd, const u8 *buf, + int len, int read) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + u32 config; + int ret; + + /* DMA Channel Configuration */ + config = (read ? DMAC_CHAN_FLOW_D_P2M : DMAC_CHAN_FLOW_D_M2P) | + (read ? DMAC_DEST_PERIP(0) : DMAC_DEST_PERIP(DMA_PERID_NAND1)) | + (read ? DMAC_SRC_PERIP(DMA_PERID_NAND1) : DMAC_SRC_PERIP(0)) | + DMAC_CHAN_ENABLE; + + /* Prepare DMA descriptors */ + lpc32xx_nand_dma_configure(chip, buf, len, read); + + /* Setup SLC controller and start transfer */ + if (read) + setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_DMA_DIR); + else /* NAND_ECC_WRITE */ + clrbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_DMA_DIR); + setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_DMA_BURST); + + /* Write length for new transfers */ + if (!((readl(&lpc32xx_nand_slc_regs->stat) & STAT_DMA_FIFO) | + readl(&lpc32xx_nand_slc_regs->tc))) { + int tmp = (len != mtd->oobsize) ? mtd->oobsize : 0; + writel(len + tmp, &lpc32xx_nand_slc_regs->tc); + } + + setbits_le32(&lpc32xx_nand_slc_regs->ctrl, CTRL_DMA_START); + + /* Start DMA transfers */ + ret = lpc32xx_dma_start_xfer(dmachan, dmalist, config); + if (unlikely(ret < 0)) + BUG(); + + + /* Wait for NAND to be ready */ + while (!lpc32xx_nand_dev_ready(mtd)) + ; + + /* Wait till DMA transfer is DONE */ + if (lpc32xx_dma_wait_status(dmachan)) + pr_err("NAND DMA transfer error!\r\n"); + + /* Stop DMA & HW ECC */ + clrbits_le32(&lpc32xx_nand_slc_regs->ctrl, CTRL_DMA_START); + clrbits_le32(&lpc32xx_nand_slc_regs->cfg, + CFG_DMA_DIR | CFG_DMA_BURST | CFG_ECC_EN | CFG_DMA_ECC); +} + +static u32 slc_ecc_copy_to_buffer(u8 *spare, const u32 *ecc, int count) +{ + int i; + for (i = 0; i < (count * CONFIG_SYS_NAND_ECCBYTES); + i += CONFIG_SYS_NAND_ECCBYTES) { + u32 ce = ecc[i / CONFIG_SYS_NAND_ECCBYTES]; + ce = ~(ce << 2) & 0xFFFFFF; + spare[i+2] = (u8)(ce & 0xFF); ce >>= 8; + spare[i+1] = (u8)(ce & 0xFF); ce >>= 8; + spare[i] = (u8)(ce & 0xFF); + } + return 0; +} + +static int lpc32xx_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, + uint8_t *ecc_code) +{ + return slc_ecc_copy_to_buffer(ecc_code, ecc_buffer, ECCSTEPS); +} + +/* + * Enables and prepares SLC NAND controller + * for doing data transfers with H/W ECC enabled. + */ +static void lpc32xx_hwecc_enable(struct mtd_info *mtd, int mode) +{ + /* Clear ECC */ + writel(CTRL_ECC_CLEAR, &lpc32xx_nand_slc_regs->ctrl); + + /* Setup SLC controller for H/W ECC operations */ + setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_ECC_EN | CFG_DMA_ECC); +} + +/* + * lpc32xx_correct_data - [NAND Interface] Detect and correct bit error(s) + * mtd: MTD block structure + * dat: 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 byte block + */ +int lpc32xx_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + unsigned int i; + int ret1, ret2 = 0; + u_char *r = read_ecc; + u_char *c = calc_ecc; + u16 data_offset = 0; + + for (i = 0 ; i < ECCSTEPS ; i++) { + r += CONFIG_SYS_NAND_ECCBYTES; + c += CONFIG_SYS_NAND_ECCBYTES; + data_offset += CONFIG_SYS_NAND_ECCSIZE; + + ret1 = nand_correct_data(mtd, dat + data_offset, r, c); + if (ret1 < 0) + return -EBADMSG; + else + ret2 += ret1; + } + + return ret2; +} +#endif + +#if defined(CONFIG_DMA_LPC32XX) +static void lpc32xx_dma_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + lpc32xx_nand_xfer(mtd, buf, len, 1); +} +#else +static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + while (len-- > 0) + *buf++ = readl(&lpc32xx_nand_slc_regs->data); +} +#endif + +static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) +{ + return readl(&lpc32xx_nand_slc_regs->data); +} + +#if defined(CONFIG_DMA_LPC32XX) +static void lpc32xx_dma_write_buf(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + lpc32xx_nand_xfer(mtd, buf, len, 0); +} +#else +static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + while (len-- > 0) + writel(*buf++, &lpc32xx_nand_slc_regs->data); +} +#endif + +static void lpc32xx_write_byte(struct mtd_info *mtd, uint8_t byte) +{ + writel(byte, &lpc32xx_nand_slc_regs->data); +} + +#if defined(CONFIG_DMA_LPC32XX) +/* Reuse the logic from "nand_read_page_hwecc()" */ +static int lpc32xx_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int i; + int stat; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + unsigned int max_bitflips = 0; + + /* + * As per the "LPC32x0 and LPC32x0/01 User manual" table 173 notes + * and section 9.7, the NAND SLC & DMA allowed single DMA transaction + * of a page size using DMA controller scatter/gather mode through + * linked list; the ECC read is done without any software intervention. + */ + + lpc32xx_hwecc_enable(mtd, NAND_ECC_READ); + lpc32xx_dma_read_buf(mtd, p, chip->ecc.size * chip->ecc.steps); + lpc32xx_ecc_calculate(mtd, p, &ecc_calc[0]); + lpc32xx_dma_read_buf(mtd, chip->oob_poi, mtd->oobsize); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + stat = chip->ecc.correct(mtd, p, &ecc_code[0], &ecc_calc[0]); + if (stat < 0) + mtd->ecc_stats.failed++; + else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } + + return max_bitflips; +} + +/* Reuse the logic from "nand_write_page_hwecc()" */ +static int lpc32xx_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required, + int page) +{ + int i; + uint8_t *ecc_calc = chip->buffers->ecccalc; + const uint8_t *p = buf; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + /* + * As per the "LPC32x0 and LPC32x0/01 User manual" table 173 notes + * and section 9.7, the NAND SLC & DMA allowed single DMA transaction + * of a page size using DMA controller scatter/gather mode through + * linked list; the ECC read is done without any software intervention. + */ + + lpc32xx_hwecc_enable(mtd, NAND_ECC_WRITE); + lpc32xx_dma_write_buf(mtd, p, chip->ecc.size * chip->ecc.steps); + lpc32xx_ecc_calculate(mtd, p, &ecc_calc[0]); + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ecc_calc[i]; + + lpc32xx_dma_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} +#endif + +/* + * LPC32xx has only one SLC NAND controller, don't utilize + * CONFIG_SYS_NAND_SELF_INIT to be able to reuse this function + * both in SPL NAND and U-Boot images. + */ +int board_nand_init(struct nand_chip *lpc32xx_chip) +{ +#if defined(CONFIG_DMA_LPC32XX) + int ret; + + /* Acquire a channel for our use */ + ret = lpc32xx_dma_get_channel(); + if (unlikely(ret < 0)) { + pr_info("Unable to get free DMA channel for NAND transfers\n"); + return -1; + } + dmachan = (unsigned int)ret; +#endif + + lpc32xx_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; + lpc32xx_chip->dev_ready = lpc32xx_nand_dev_ready; + + /* + * The implementation of these functions is quite common, but + * they MUST be defined, because access to data register + * is strictly 32-bit aligned. + */ + lpc32xx_chip->read_byte = lpc32xx_read_byte; + lpc32xx_chip->write_byte = lpc32xx_write_byte; + +#if defined(CONFIG_DMA_LPC32XX) + /* Hardware ECC calculation is supported when DMA driver is selected */ + lpc32xx_chip->ecc.mode = NAND_ECC_HW; + + lpc32xx_chip->read_buf = lpc32xx_dma_read_buf; + lpc32xx_chip->write_buf = lpc32xx_dma_write_buf; + + lpc32xx_chip->ecc.calculate = lpc32xx_ecc_calculate; + lpc32xx_chip->ecc.correct = lpc32xx_correct_data; + lpc32xx_chip->ecc.hwctl = lpc32xx_hwecc_enable; + lpc32xx_chip->chip_delay = 2000; + + lpc32xx_chip->ecc.read_page = lpc32xx_read_page_hwecc; + lpc32xx_chip->ecc.write_page = lpc32xx_write_page_hwecc; + lpc32xx_chip->options |= NAND_NO_SUBPAGE_WRITE; +#else + /* + * Hardware ECC calculation is not supported by the driver, + * because it requires DMA support, see LPC32x0 User Manual, + * note after SLC_ECC register description (UM10326, p.198) + */ + lpc32xx_chip->ecc.mode = NAND_ECC_SOFT; + + /* + * The implementation of these functions is quite common, but + * they MUST be defined, because access to data register + * is strictly 32-bit aligned. + */ + lpc32xx_chip->read_buf = lpc32xx_read_buf; + lpc32xx_chip->write_buf = lpc32xx_write_buf; +#endif + + /* + * These values are predefined + * for both small and large page NAND flash devices. + */ + lpc32xx_chip->ecc.size = CONFIG_SYS_NAND_ECCSIZE; + lpc32xx_chip->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; + lpc32xx_chip->ecc.strength = 1; + + if (CONFIG_SYS_NAND_PAGE_SIZE != NAND_LARGE_BLOCK_PAGE_SIZE) + lpc32xx_chip->ecc.layout = &lpc32xx_nand_oob_16; + +#if defined(CONFIG_SYS_NAND_USE_FLASH_BBT) + lpc32xx_chip->bbt_options |= NAND_BBT_USE_FLASH; +#endif + + /* Initialize NAND interface */ + lpc32xx_nand_init(); + + return 0; +} diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c new file mode 100644 index 0000000000..cf97e0f74f --- /dev/null +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -0,0 +1,1307 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. + * Copyright 2008 Sascha Hauer, kernel@pengutronix.de + * Copyright 2009 Ilya Yanok, + */ + +#include +#include +#include +#include +#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) || \ + defined(CONFIG_MX51) || defined(CONFIG_MX53) +#include +#endif +#include "mxc_nand.h" + +#define DRIVER_NAME "mxc_nand" + +struct mxc_nand_host { + struct nand_chip *nand; + + struct mxc_nand_regs __iomem *regs; +#ifdef MXC_NFC_V3_2 + struct mxc_nand_ip_regs __iomem *ip_regs; +#endif + int spare_only; + int status_request; + int pagesize_2k; + int clk_act; + uint16_t col_addr; + unsigned int page_addr; +}; + +static struct mxc_nand_host mxc_host; +static struct mxc_nand_host *host = &mxc_host; + +/* Define delays in microsec for NAND device operations */ +#define TROP_US_DELAY 2000 +/* Macros to get byte and bit positions of ECC */ +#define COLPOS(x) ((x) >> 3) +#define BITPOS(x) ((x) & 0xf) + +/* Define single bit Error positions in Main & Spare area */ +#define MAIN_SINGLEBIT_ERROR 0x4 +#define SPARE_SINGLEBIT_ERROR 0x1 + +/* OOB placement block for use with hardware ecc generation */ +#if defined(MXC_NFC_V1) +#ifndef CONFIG_SYS_NAND_LARGEPAGE +static struct nand_ecclayout nand_hw_eccoob = { + .eccbytes = 5, + .eccpos = {6, 7, 8, 9, 10}, + .oobfree = { {0, 5}, {11, 5}, } +}; +#else +static struct nand_ecclayout nand_hw_eccoob2k = { + .eccbytes = 20, + .eccpos = { + 6, 7, 8, 9, 10, + 22, 23, 24, 25, 26, + 38, 39, 40, 41, 42, + 54, 55, 56, 57, 58, + }, + .oobfree = { {2, 4}, {11, 11}, {27, 11}, {43, 11}, {59, 5} }, +}; +#endif +#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) +#ifndef CONFIG_SYS_NAND_LARGEPAGE +static struct nand_ecclayout nand_hw_eccoob = { + .eccbytes = 9, + .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15}, + .oobfree = { {2, 5} } +}; +#else +static struct nand_ecclayout nand_hw_eccoob2k = { + .eccbytes = 36, + .eccpos = { + 7, 8, 9, 10, 11, 12, 13, 14, 15, + 23, 24, 25, 26, 27, 28, 29, 30, 31, + 39, 40, 41, 42, 43, 44, 45, 46, 47, + 55, 56, 57, 58, 59, 60, 61, 62, 63, + }, + .oobfree = { {2, 5}, {16, 7}, {32, 7}, {48, 7} }, +}; +#endif +#endif + +static int is_16bit_nand(void) +{ +#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT) + return 1; +#else + return 0; +#endif +} + +static uint32_t *mxc_nand_memcpy32(uint32_t *dest, uint32_t *source, size_t size) +{ + uint32_t *d = dest; + + size >>= 2; + while (size--) + __raw_writel(__raw_readl(source++), d++); + return dest; +} + +/* + * This function polls the NANDFC to wait for the basic operation to + * complete by checking the INT bit. + */ +static void wait_op_done(struct mxc_nand_host *host, int max_retries, + uint16_t param) +{ + uint32_t tmp; + + while (max_retries-- > 0) { +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + tmp = readnfc(&host->regs->config2); + if (tmp & NFC_V1_V2_CONFIG2_INT) { + tmp &= ~NFC_V1_V2_CONFIG2_INT; + writenfc(tmp, &host->regs->config2); +#elif defined(MXC_NFC_V3_2) + tmp = readnfc(&host->ip_regs->ipc); + if (tmp & NFC_V3_IPC_INT) { + tmp &= ~NFC_V3_IPC_INT; + writenfc(tmp, &host->ip_regs->ipc); +#endif + break; + } + udelay(1); + } + if (max_retries < 0) { + pr_debug("%s(%d): INT not set\n", + __func__, param); + } +} + +/* + * This function issues the specified command to the NAND device and + * waits for completion. + */ +static void send_cmd(struct mxc_nand_host *host, uint16_t cmd) +{ + pr_debug("send_cmd(host, 0x%x)\n", cmd); + + writenfc(cmd, &host->regs->flash_cmd); + writenfc(NFC_CMD, &host->regs->operation); + + /* Wait for operation to complete */ + wait_op_done(host, TROP_US_DELAY, cmd); +} + +/* + * This function sends an address (or partial address) to the + * NAND device. The address is used to select the source/destination for + * a NAND command. + */ +static void send_addr(struct mxc_nand_host *host, uint16_t addr) +{ + pr_debug("send_addr(host, 0x%x)\n", addr); + + writenfc(addr, &host->regs->flash_addr); + writenfc(NFC_ADDR, &host->regs->operation); + + /* Wait for operation to complete */ + wait_op_done(host, TROP_US_DELAY, addr); +} + +/* + * This function requests the NANDFC to initiate the transfer + * of data currently in the NANDFC RAM buffer to the NAND device. + */ +static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, + int spare_only) +{ + if (spare_only) + pr_debug("send_prog_page (%d)\n", spare_only); + + if (is_mxc_nfc_21() || is_mxc_nfc_32()) { + int i; + /* + * The controller copies the 64 bytes of spare data from + * the first 16 bytes of each of the 4 64 byte spare buffers. + * Copy the contiguous data starting in spare_area[0] to + * the four spare area buffers. + */ + for (i = 1; i < 4; i++) { + void __iomem *src = &host->regs->spare_area[0][i * 16]; + void __iomem *dst = &host->regs->spare_area[i][0]; + + mxc_nand_memcpy32(dst, src, 16); + } + } + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + writenfc(buf_id, &host->regs->buf_addr); +#elif defined(MXC_NFC_V3_2) + uint32_t tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_V3_CONFIG1_RBA_MASK; + tmp |= NFC_V3_CONFIG1_RBA(buf_id); + writenfc(tmp, &host->regs->config1); +#endif + + /* Configure spare or page+spare access */ + if (!host->pagesize_2k) { + uint32_t config1 = readnfc(&host->regs->config1); + if (spare_only) + config1 |= NFC_CONFIG1_SP_EN; + else + config1 &= ~NFC_CONFIG1_SP_EN; + writenfc(config1, &host->regs->config1); + } + + writenfc(NFC_INPUT, &host->regs->operation); + + /* Wait for operation to complete */ + wait_op_done(host, TROP_US_DELAY, spare_only); +} + +/* + * Requests NANDFC to initiate the transfer of data from the + * NAND device into in the NANDFC ram buffer. + */ +static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, + int spare_only) +{ + pr_debug("send_read_page (%d)\n", spare_only); + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + writenfc(buf_id, &host->regs->buf_addr); +#elif defined(MXC_NFC_V3_2) + uint32_t tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_V3_CONFIG1_RBA_MASK; + tmp |= NFC_V3_CONFIG1_RBA(buf_id); + writenfc(tmp, &host->regs->config1); +#endif + + /* Configure spare or page+spare access */ + if (!host->pagesize_2k) { + uint32_t config1 = readnfc(&host->regs->config1); + if (spare_only) + config1 |= NFC_CONFIG1_SP_EN; + else + config1 &= ~NFC_CONFIG1_SP_EN; + writenfc(config1, &host->regs->config1); + } + + writenfc(NFC_OUTPUT, &host->regs->operation); + + /* Wait for operation to complete */ + wait_op_done(host, TROP_US_DELAY, spare_only); + + if (is_mxc_nfc_21() || is_mxc_nfc_32()) { + int i; + + /* + * The controller copies the 64 bytes of spare data to + * the first 16 bytes of each of the 4 spare buffers. + * Make the data contiguous starting in spare_area[0]. + */ + for (i = 1; i < 4; i++) { + void __iomem *src = &host->regs->spare_area[i][0]; + void __iomem *dst = &host->regs->spare_area[0][i * 16]; + + mxc_nand_memcpy32(dst, src, 16); + } + } +} + +/* Request the NANDFC to perform a read of the NAND device ID. */ +static void send_read_id(struct mxc_nand_host *host) +{ + uint32_t tmp; + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + /* NANDFC buffer 0 is used for device ID output */ + writenfc(0x0, &host->regs->buf_addr); +#elif defined(MXC_NFC_V3_2) + tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_V3_CONFIG1_RBA_MASK; + writenfc(tmp, &host->regs->config1); +#endif + + /* Read ID into main buffer */ + tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_CONFIG1_SP_EN; + writenfc(tmp, &host->regs->config1); + + writenfc(NFC_ID, &host->regs->operation); + + /* Wait for operation to complete */ + wait_op_done(host, TROP_US_DELAY, 0); +} + +/* + * This function requests the NANDFC to perform a read of the + * NAND device status and returns the current status. + */ +static uint16_t get_dev_status(struct mxc_nand_host *host) +{ +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + void __iomem *main_buf = host->regs->main_area[1]; + uint32_t store; +#endif + uint32_t ret, tmp; + /* Issue status request to NAND device */ + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + /* store the main area1 first word, later do recovery */ + store = readl(main_buf); + /* NANDFC buffer 1 is used for device status */ + writenfc(1, &host->regs->buf_addr); +#endif + + /* Read status into main buffer */ + tmp = readnfc(&host->regs->config1); + tmp &= ~NFC_CONFIG1_SP_EN; + writenfc(tmp, &host->regs->config1); + + writenfc(NFC_STATUS, &host->regs->operation); + + /* Wait for operation to complete */ + wait_op_done(host, TROP_US_DELAY, 0); + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + /* + * Status is placed in first word of main buffer + * get status, then recovery area 1 data + */ + ret = readw(main_buf); + writel(store, main_buf); +#elif defined(MXC_NFC_V3_2) + ret = readnfc(&host->regs->config1) >> 16; +#endif + + return ret; +} + +/* This function is used by upper layer to checks if device is ready */ +static int mxc_nand_dev_ready(struct mtd_info *mtd) +{ + /* + * NFC handles R/B internally. Therefore, this function + * always returns status as ready. + */ + return 1; +} + +static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + uint16_t tmp = readnfc(&host->regs->config1); + + if (on) + tmp |= NFC_V1_V2_CONFIG1_ECC_EN; + else + tmp &= ~NFC_V1_V2_CONFIG1_ECC_EN; + writenfc(tmp, &host->regs->config1); +#elif defined(MXC_NFC_V3_2) + uint32_t tmp = readnfc(&host->ip_regs->config2); + + if (on) + tmp |= NFC_V3_CONFIG2_ECC_EN; + else + tmp &= ~NFC_V3_CONFIG2_ECC_EN; + writenfc(tmp, &host->ip_regs->config2); +#endif +} + +#ifdef CONFIG_MXC_NAND_HWECC +static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + /* + * If HW ECC is enabled, we turn it on during init. There is + * no need to enable again here. + */ +} + +#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) +static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + uint8_t *buf = chip->oob_poi; + int length = mtd->oobsize; + int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; + uint8_t *bufpoi = buf; + int i, toread; + + pr_debug("%s: Reading OOB area of page %u to oob %p\n", + __func__, page, buf); + + chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); + for (i = 0; i < chip->ecc.steps; i++) { + toread = min_t(int, length, chip->ecc.prepad); + if (toread) { + chip->read_buf(mtd, bufpoi, toread); + bufpoi += toread; + length -= toread; + } + bufpoi += chip->ecc.bytes; + host->col_addr += chip->ecc.bytes; + length -= chip->ecc.bytes; + + toread = min_t(int, length, chip->ecc.postpad); + if (toread) { + chip->read_buf(mtd, bufpoi, toread); + bufpoi += toread; + length -= toread; + } + } + if (length > 0) + chip->read_buf(mtd, bufpoi, length); + + _mxc_nand_enable_hwecc(mtd, 0); + chip->cmdfunc(mtd, NAND_CMD_READOOB, + mtd->writesize + chip->ecc.prepad, page); + bufpoi = buf + chip->ecc.prepad; + length = mtd->oobsize - chip->ecc.prepad; + for (i = 0; i < chip->ecc.steps; i++) { + toread = min_t(int, length, chip->ecc.bytes); + chip->read_buf(mtd, bufpoi, toread); + bufpoi += eccpitch; + length -= eccpitch; + host->col_addr += chip->ecc.postpad + chip->ecc.prepad; + } + _mxc_nand_enable_hwecc(mtd, 1); + return 1; +} + +static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, + int oob_required, + int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; + uint8_t *oob = chip->oob_poi; + int steps, size; + int n; + + _mxc_nand_enable_hwecc(mtd, 0); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + + for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { + host->col_addr = n * eccsize; + chip->read_buf(mtd, buf, eccsize); + buf += eccsize; + + host->col_addr = mtd->writesize + n * eccpitch; + if (chip->ecc.prepad) { + chip->read_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->read_buf(mtd, oob, eccbytes); + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->read_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + size = mtd->oobsize - (oob - chip->oob_poi); + if (size) + chip->read_buf(mtd, oob, size); + _mxc_nand_enable_hwecc(mtd, 1); + + return 0; +} + +static int mxc_nand_read_page_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, + int oob_required, + int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + int n, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + + pr_debug("Reading page %u to buf %p oob %p\n", + page, buf, oob); + + /* first read the data area and the available portion of OOB */ + for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { + int stat; + + host->col_addr = n * eccsize; + + chip->read_buf(mtd, p, eccsize); + + host->col_addr = mtd->writesize + n * eccpitch; + + if (chip->ecc.prepad) { + chip->read_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + stat = chip->ecc.correct(mtd, p, oob, NULL); + + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->read_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + /* Calculate remaining oob bytes */ + n = mtd->oobsize - (oob - chip->oob_poi); + if (n) + chip->read_buf(mtd, oob, n); + + /* Then switch ECC off and read the OOB area to get the ECC code */ + _mxc_nand_enable_hwecc(mtd, 0); + chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); + eccsteps = chip->ecc.steps; + oob = chip->oob_poi + chip->ecc.prepad; + for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { + host->col_addr = mtd->writesize + + n * eccpitch + + chip->ecc.prepad; + chip->read_buf(mtd, oob, eccbytes); + oob += eccbytes + chip->ecc.postpad; + } + _mxc_nand_enable_hwecc(mtd, 1); + return 0; +} + +static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; + int length = mtd->oobsize; + int i, len, status, steps = chip->ecc.steps; + const uint8_t *bufpoi = chip->oob_poi; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + for (i = 0; i < steps; i++) { + len = min_t(int, length, eccpitch); + + chip->write_buf(mtd, bufpoi, len); + bufpoi += len; + length -= len; + host->col_addr += chip->ecc.prepad + chip->ecc.postpad; + } + if (length > 0) + chip->write_buf(mtd, bufpoi, length); + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, + int oob_required, int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; + uint8_t *oob = chip->oob_poi; + int steps, size; + int n; + + for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { + host->col_addr = n * eccsize; + chip->write_buf(mtd, buf, eccsize); + buf += eccsize; + + host->col_addr = mtd->writesize + n * eccpitch; + + if (chip->ecc.prepad) { + chip->write_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + host->col_addr += eccbytes; + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->write_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + size = mtd->oobsize - (oob - chip->oob_poi); + if (size) + chip->write_buf(mtd, oob, size); + return 0; +} + +static int mxc_nand_write_page_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, + int oob_required, int page) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + int i, n, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; + int eccsteps = chip->ecc.steps; + const uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + + chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + + for (i = n = 0; + eccsteps; + n++, eccsteps--, i += eccbytes, p += eccsize) { + host->col_addr = n * eccsize; + + chip->write_buf(mtd, p, eccsize); + + host->col_addr = mtd->writesize + n * eccpitch; + + if (chip->ecc.prepad) { + chip->write_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->write_buf(mtd, oob, eccbytes); + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->write_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + /* Calculate remaining oob bytes */ + i = mtd->oobsize - (oob - chip->oob_poi); + if (i) + chip->write_buf(mtd, oob, i); + return 0; +} + +static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + uint32_t ecc_status = readl(&host->regs->ecc_status_result); + int subpages = mtd->writesize / nand_chip->subpagesize; + int pg2blk_shift = nand_chip->phys_erase_shift - + nand_chip->page_shift; + + do { + if ((ecc_status & 0xf) > 4) { + static int last_bad = -1; + + if (last_bad != host->page_addr >> pg2blk_shift) { + last_bad = host->page_addr >> pg2blk_shift; + printk(KERN_DEBUG + "MXC_NAND: HWECC uncorrectable ECC error" + " in block %u page %u subpage %d\n", + last_bad, host->page_addr, + mtd->writesize / nand_chip->subpagesize + - subpages); + } + return -EBADMSG; + } + ecc_status >>= 4; + subpages--; + } while (subpages > 0); + + return 0; +} +#else +#define mxc_nand_read_page_syndrome NULL +#define mxc_nand_read_page_raw_syndrome NULL +#define mxc_nand_read_oob_syndrome NULL +#define mxc_nand_write_page_syndrome NULL +#define mxc_nand_write_page_raw_syndrome NULL +#define mxc_nand_write_oob_syndrome NULL + +static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + + /* + * 1-Bit errors are automatically corrected in HW. No need for + * additional correction. 2-Bit errors cannot be corrected by + * HW ECC, so we need to return failure + */ + uint16_t ecc_status = readnfc(&host->regs->ecc_status_result); + + if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { + pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); + return -EBADMSG; + } + + return 0; +} +#endif + +static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + return 0; +} +#endif + +static u_char mxc_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + uint8_t ret = 0; + uint16_t col; + uint16_t __iomem *main_buf = + (uint16_t __iomem *)host->regs->main_area[0]; + uint16_t __iomem *spare_buf = + (uint16_t __iomem *)host->regs->spare_area[0]; + union { + uint16_t word; + uint8_t bytes[2]; + } nfc_word; + + /* Check for status request */ + if (host->status_request) + return get_dev_status(host) & 0xFF; + + /* Get column for 16-bit access */ + col = host->col_addr >> 1; + + /* If we are accessing the spare region */ + if (host->spare_only) + nfc_word.word = readw(&spare_buf[col]); + else + nfc_word.word = readw(&main_buf[col]); + + /* Pick upper/lower byte of word from RAM buffer */ + ret = nfc_word.bytes[host->col_addr & 0x1]; + + /* Update saved column address */ + if (nand_chip->options & NAND_BUSWIDTH_16) + host->col_addr += 2; + else + host->col_addr++; + + 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 col, ret; + uint16_t __iomem *p; + + pr_debug("mxc_nand_read_word(col = %d)\n", host->col_addr); + + col = host->col_addr; + /* Adjust saved column address */ + if (col < mtd->writesize && host->spare_only) + col += mtd->writesize; + + if (col < mtd->writesize) { + p = (uint16_t __iomem *)(host->regs->main_area[0] + + (col >> 1)); + } else { + p = (uint16_t __iomem *)(host->regs->spare_area[0] + + ((col - mtd->writesize) >> 1)); + } + + if (col & 1) { + union { + uint16_t word; + uint8_t bytes[2]; + } nfc_word[3]; + + nfc_word[0].word = readw(p); + nfc_word[1].word = readw(p + 1); + + nfc_word[2].bytes[0] = nfc_word[0].bytes[1]; + nfc_word[2].bytes[1] = nfc_word[1].bytes[0]; + + ret = nfc_word[2].word; + } else { + ret = readw(p); + } + + /* Update saved column address */ + host->col_addr = col + 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) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + int n, col, i = 0; + + pr_debug("mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr, + len); + + col = host->col_addr; + + /* Adjust saved column address */ + if (col < mtd->writesize && host->spare_only) + col += mtd->writesize; + + n = mtd->writesize + mtd->oobsize - col; + n = min(len, n); + + pr_debug("%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n); + + while (n > 0) { + void __iomem *p; + + if (col < mtd->writesize) { + p = host->regs->main_area[0] + (col & ~3); + } else { + p = host->regs->spare_area[0] - + mtd->writesize + (col & ~3); + } + + pr_debug("%s:%d: p = %p\n", __func__, + __LINE__, p); + + if (((col | (unsigned long)&buf[i]) & 3) || n < 4) { + union { + uint32_t word; + uint8_t bytes[4]; + } nfc_word; + + nfc_word.word = readl(p); + nfc_word.bytes[col & 3] = buf[i++]; + n--; + col++; + + writel(nfc_word.word, p); + } else { + int m = mtd->writesize - col; + + if (col >= mtd->writesize) + m += mtd->oobsize; + + m = min(n, m) & ~3; + + pr_debug("%s:%d: n = %d, m = %d, i = %d, col = %d\n", + __func__, __LINE__, n, m, i, col); + + mxc_nand_memcpy32(p, (uint32_t *)&buf[i], m); + col += m; + i += m; + n -= m; + } + } + /* Update saved column address */ + host->col_addr = col; +} + +/* + * Read the data buffer from the NAND Flash. To read the data from NAND + * 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) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + int n, col, i = 0; + + pr_debug("mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, + len); + + col = host->col_addr; + + /* Adjust saved column address */ + if (col < mtd->writesize && host->spare_only) + col += mtd->writesize; + + n = mtd->writesize + mtd->oobsize - col; + n = min(len, n); + + while (n > 0) { + void __iomem *p; + + if (col < mtd->writesize) { + p = host->regs->main_area[0] + (col & ~3); + } else { + p = host->regs->spare_area[0] - + mtd->writesize + (col & ~3); + } + + if (((col | (int)&buf[i]) & 3) || n < 4) { + union { + uint32_t word; + uint8_t bytes[4]; + } nfc_word; + + nfc_word.word = readl(p); + buf[i++] = nfc_word.bytes[col & 3]; + n--; + col++; + } else { + int m = mtd->writesize - col; + + if (col >= mtd->writesize) + m += mtd->oobsize; + + m = min(n, m) & ~3; + mxc_nand_memcpy32((uint32_t *)&buf[i], p, m); + + col += m; + i += m; + n -= m; + } + } + /* Update saved column address */ + host->col_addr = col; +} + +/* + * This function is used by upper layer for select and + * deselect of the NAND chip + */ +static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + + switch (chip) { + case -1: + /* TODO: Disable the NFC clock */ + if (host->clk_act) + host->clk_act = 0; + break; + case 0: + /* TODO: Enable the NFC clock */ + if (!host->clk_act) + host->clk_act = 1; + break; + + default: + break; + } +} + +/* + * Used by the upper layer to write command to NAND Flash for + * different operations to be carried out on NAND Flash + */ +void mxc_nand_command(struct mtd_info *mtd, unsigned command, + int column, int page_addr) +{ + struct nand_chip *nand_chip = mtd_to_nand(mtd); + struct mxc_nand_host *host = nand_get_controller_data(nand_chip); + + pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", + command, column, page_addr); + + /* Reset command state information */ + host->status_request = false; + + /* Command pre-processing step */ + switch (command) { + + case NAND_CMD_STATUS: + host->col_addr = 0; + host->status_request = true; + break; + + case NAND_CMD_READ0: + host->page_addr = page_addr; + host->col_addr = column; + host->spare_only = false; + break; + + case NAND_CMD_READOOB: + host->col_addr = column; + host->spare_only = true; + if (host->pagesize_2k) + command = NAND_CMD_READ0; /* only READ0 is valid */ + break; + + case NAND_CMD_SEQIN: + if (column >= mtd->writesize) { + /* + * before sending SEQIN command for partial write, + * we need read one page out. FSL NFC does not support + * partial write. It always sends out 512+ecc+512+ecc + * for large page nand flash. But for small page nand + * flash, it does support SPARE ONLY operation. + */ + if (host->pagesize_2k) { + /* call ourself to read a page */ + mxc_nand_command(mtd, NAND_CMD_READ0, 0, + page_addr); + } + + host->col_addr = column - mtd->writesize; + host->spare_only = true; + + /* Set program pointer to spare region */ + if (!host->pagesize_2k) + send_cmd(host, NAND_CMD_READOOB); + } else { + host->spare_only = false; + host->col_addr = column; + + /* Set program pointer to page start */ + if (!host->pagesize_2k) + send_cmd(host, NAND_CMD_READ0); + } + break; + + case NAND_CMD_PAGEPROG: + send_prog_page(host, 0, host->spare_only); + + if (host->pagesize_2k && is_mxc_nfc_1()) { + /* data in 4 areas */ + send_prog_page(host, 1, host->spare_only); + send_prog_page(host, 2, host->spare_only); + send_prog_page(host, 3, host->spare_only); + } + + break; + } + + /* Write out the command to the device. */ + send_cmd(host, command); + + /* Write out column address, if necessary */ + if (column != -1) { + /* + * MXC NANDFC can only perform full page+spare or + * spare-only read/write. When the upper layers perform + * a read/write buffer operation, we will use the saved + * column address to index into the full page. + */ + send_addr(host, 0); + if (host->pagesize_2k) + /* another col addr cycle for 2k page */ + send_addr(host, 0); + } + + /* Write out page address, if necessary */ + if (page_addr != -1) { + u32 page_mask = nand_chip->pagemask; + do { + send_addr(host, page_addr & 0xFF); + page_addr >>= 8; + page_mask >>= 8; + } while (page_mask); + } + + /* Command post-processing step */ + switch (command) { + + case NAND_CMD_RESET: + break; + + case NAND_CMD_READOOB: + case NAND_CMD_READ0: + if (host->pagesize_2k) { + /* send read confirm command */ + send_cmd(host, NAND_CMD_READSTART); + /* read for each AREA */ + send_read_page(host, 0, host->spare_only); + if (is_mxc_nfc_1()) { + send_read_page(host, 1, host->spare_only); + send_read_page(host, 2, host->spare_only); + send_read_page(host, 3, host->spare_only); + } + } else { + send_read_page(host, 0, host->spare_only); + } + break; + + case NAND_CMD_READID: + host->col_addr = 0; + send_read_id(host); + break; + + case NAND_CMD_PAGEPROG: + break; + + case NAND_CMD_STATUS: + break; + + case NAND_CMD_ERASE2: + break; + } +} + +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = bbt_pattern, +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = mirror_pattern, +}; + +#endif + +int board_nand_init(struct nand_chip *this) +{ + struct mtd_info *mtd; +#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) + uint32_t tmp; +#endif + +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + this->bbt_options |= NAND_BBT_USE_FLASH; + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; +#endif + + /* structures must be linked */ + mtd = &this->mtd; + host->nand = this; + + /* 5 us command delay time */ + this->chip_delay = 5; + + nand_set_controller_data(this, host); + this->dev_ready = mxc_nand_dev_ready; + this->cmdfunc = mxc_nand_command; + this->select_chip = mxc_nand_select_chip; + 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; + + host->regs = (struct mxc_nand_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE; +#ifdef MXC_NFC_V3_2 + host->ip_regs = + (struct mxc_nand_ip_regs __iomem *)CONFIG_MXC_NAND_IP_REGS_BASE; +#endif + host->clk_act = 1; + +#ifdef CONFIG_MXC_NAND_HWECC + this->ecc.calculate = mxc_nand_calculate_ecc; + this->ecc.hwctl = mxc_nand_enable_hwecc; + this->ecc.correct = mxc_nand_correct_data; + if (is_mxc_nfc_21() || is_mxc_nfc_32()) { + this->ecc.mode = NAND_ECC_HW_SYNDROME; + this->ecc.read_page = mxc_nand_read_page_syndrome; + this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome; + this->ecc.read_oob = mxc_nand_read_oob_syndrome; + this->ecc.write_page = mxc_nand_write_page_syndrome; + this->ecc.write_page_raw = mxc_nand_write_page_raw_syndrome; + this->ecc.write_oob = mxc_nand_write_oob_syndrome; + this->ecc.bytes = 9; + this->ecc.prepad = 7; + } else { + this->ecc.mode = NAND_ECC_HW; + } + + if (is_mxc_nfc_1()) + this->ecc.strength = 1; + else + this->ecc.strength = 4; + + host->pagesize_2k = 0; + + this->ecc.size = 512; + _mxc_nand_enable_hwecc(mtd, 1); +#else + this->ecc.layout = &nand_soft_eccoob; + this->ecc.mode = NAND_ECC_SOFT; + _mxc_nand_enable_hwecc(mtd, 0); +#endif + /* Reset NAND */ + this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + + /* NAND bus width determines access functions used by upper layer */ + if (is_16bit_nand()) + this->options |= NAND_BUSWIDTH_16; + +#ifdef CONFIG_SYS_NAND_LARGEPAGE + host->pagesize_2k = 1; + this->ecc.layout = &nand_hw_eccoob2k; +#else + host->pagesize_2k = 0; + this->ecc.layout = &nand_hw_eccoob; +#endif + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) +#ifdef MXC_NFC_V2_1 + tmp = readnfc(&host->regs->config1); + tmp |= NFC_V2_CONFIG1_ONE_CYCLE; + tmp |= NFC_V2_CONFIG1_ECC_MODE_4; + writenfc(tmp, &host->regs->config1); + if (host->pagesize_2k) + writenfc(64/2, &host->regs->spare_area_size); + else + writenfc(16/2, &host->regs->spare_area_size); +#endif + + /* + * preset operation + * Unlock the internal RAM Buffer + */ + writenfc(0x2, &host->regs->config); + + /* Blocks to be unlocked */ + writenfc(0x0, &host->regs->unlockstart_blkaddr); + /* Originally (Freescale LTIB 2.6.21) 0x4000 was written to the + * unlockend_blkaddr, but the magic 0x4000 does not always work + * when writing more than some 32 megabytes (on 2k page nands) + * However 0xFFFF doesn't seem to have this kind + * of limitation (tried it back and forth several times). + * The linux kernel driver sets this to 0xFFFF for the v2 controller + * only, but probably this was not tested there for v1. + * The very same limitation seems to apply to this kernel driver. + * This might be NAND chip specific and the i.MX31 datasheet is + * extremely vague about the semantics of this register. + */ + writenfc(0xFFFF, &host->regs->unlockend_blkaddr); + + /* Unlock Block Command for given address range */ + writenfc(0x4, &host->regs->wrprot); +#elif defined(MXC_NFC_V3_2) + writenfc(NFC_V3_CONFIG1_RBA(0), &host->regs->config1); + writenfc(NFC_V3_IPC_CREQ, &host->ip_regs->ipc); + + /* Unlock the internal RAM Buffer */ + writenfc(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK, + &host->ip_regs->wrprot); + + /* Blocks to be unlocked */ + for (tmp = 0; tmp < CONFIG_SYS_NAND_MAX_CHIPS; tmp++) + writenfc(0x0 | 0xFFFF << 16, + &host->ip_regs->wrprot_unlock_blkaddr[tmp]); + + writenfc(0, &host->ip_regs->ipc); + + tmp = readnfc(&host->ip_regs->config2); + tmp &= ~(NFC_V3_CONFIG2_SPAS_MASK | NFC_V3_CONFIG2_EDC_MASK | + NFC_V3_CONFIG2_ECC_MODE_8 | NFC_V3_CONFIG2_PS_MASK); + tmp |= NFC_V3_CONFIG2_ONE_CYCLE; + + if (host->pagesize_2k) { + tmp |= NFC_V3_CONFIG2_SPAS(64/2); + tmp |= NFC_V3_CONFIG2_PS_2048; + } else { + tmp |= NFC_V3_CONFIG2_SPAS(16/2); + tmp |= NFC_V3_CONFIG2_PS_512; + } + + writenfc(tmp, &host->ip_regs->config2); + + tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) | + NFC_V3_CONFIG3_NO_SDMA | + NFC_V3_CONFIG3_RBB_MODE | + NFC_V3_CONFIG3_SBB(6) | /* Reset default */ + NFC_V3_CONFIG3_ADD_OP(0); + + if (!(this->options & NAND_BUSWIDTH_16)) + tmp |= NFC_V3_CONFIG3_FW8; + + writenfc(tmp, &host->ip_regs->config3); + + writenfc(0, &host->ip_regs->delay_line); +#endif + + return 0; +} diff --git a/drivers/mtd/nand/raw/mxc_nand.h b/drivers/mtd/nand/raw/mxc_nand.h new file mode 100644 index 0000000000..1c7f3a2e22 --- /dev/null +++ b/drivers/mtd/nand/raw/mxc_nand.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (c) 2009 Magnus Lilja + */ + +#ifndef __MXC_NAND_H +#define __MXC_NAND_H + +/* + * Register map and bit definitions for the Freescale NAND Flash Controller + * present in various i.MX devices. + * + * MX31 and MX27 have version 1, which has: + * 4 512-byte main buffers and + * 4 16-byte spare buffers + * to support up to 2K byte pagesize nand. + * Reading or writing a 2K page requires 4 FDI/FDO cycles. + * + * MX25 and MX35 have version 2.1, and MX51 and MX53 have version 3.2, which + * have: + * 8 512-byte main buffers and + * 8 64-byte spare buffers + * to support up to 4K byte pagesize nand. + * Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle. + * Also some of registers are moved and/or changed meaning as seen below. + */ +#if defined(CONFIG_MX27) || defined(CONFIG_MX31) +#define MXC_NFC_V1 +#define is_mxc_nfc_1() 1 +#define is_mxc_nfc_21() 0 +#define is_mxc_nfc_32() 0 +#elif defined(CONFIG_MX25) || defined(CONFIG_MX35) +#define MXC_NFC_V2_1 +#define is_mxc_nfc_1() 0 +#define is_mxc_nfc_21() 1 +#define is_mxc_nfc_32() 0 +#elif defined(CONFIG_MX51) || defined(CONFIG_MX53) +#define MXC_NFC_V3 +#define MXC_NFC_V3_2 +#define is_mxc_nfc_1() 0 +#define is_mxc_nfc_21() 0 +#define is_mxc_nfc_32() 1 +#else +#error "MXC NFC implementation not supported" +#endif +#define is_mxc_nfc_3() is_mxc_nfc_32() + +#if defined(MXC_NFC_V1) +#define NAND_MXC_NR_BUFS 4 +#define NAND_MXC_SPARE_BUF_SIZE 16 +#define NAND_MXC_REG_OFFSET 0xe00 +#define NAND_MXC_2K_MULTI_CYCLE +#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) +#define NAND_MXC_NR_BUFS 8 +#define NAND_MXC_SPARE_BUF_SIZE 64 +#define NAND_MXC_REG_OFFSET 0x1e00 +#endif + +struct mxc_nand_regs { + u8 main_area[NAND_MXC_NR_BUFS][0x200]; + u8 spare_area[NAND_MXC_NR_BUFS][NAND_MXC_SPARE_BUF_SIZE]; + /* + * reserved size is offset of nfc registers + * minus total main and spare sizes + */ + u8 reserved1[NAND_MXC_REG_OFFSET + - NAND_MXC_NR_BUFS * (512 + NAND_MXC_SPARE_BUF_SIZE)]; +#if defined(MXC_NFC_V1) + u16 buf_size; + u16 reserved2; + u16 buf_addr; + u16 flash_addr; + u16 flash_cmd; + u16 config; + u16 ecc_status_result; + u16 rsltmain_area; + u16 rsltspare_area; + u16 wrprot; + u16 unlockstart_blkaddr; + u16 unlockend_blkaddr; + u16 nf_wrprst; + u16 config1; + u16 config2; +#elif defined(MXC_NFC_V2_1) + u16 reserved2[2]; + u16 buf_addr; + u16 flash_addr; + u16 flash_cmd; + u16 config; + u32 ecc_status_result; + u16 spare_area_size; + u16 wrprot; + u16 reserved3[2]; + u16 nf_wrprst; + u16 config1; + u16 config2; + u16 reserved4; + u16 unlockstart_blkaddr; + u16 unlockend_blkaddr; + u16 unlockstart_blkaddr1; + u16 unlockend_blkaddr1; + u16 unlockstart_blkaddr2; + u16 unlockend_blkaddr2; + u16 unlockstart_blkaddr3; + u16 unlockend_blkaddr3; +#elif defined(MXC_NFC_V3_2) + u32 flash_cmd; + u32 flash_addr[12]; + u32 config1; + u32 ecc_status_result; + u32 status_sum; + u32 launch; +#endif +}; + +#ifdef MXC_NFC_V3_2 +struct mxc_nand_ip_regs { + u32 wrprot; + u32 wrprot_unlock_blkaddr[8]; + u32 config2; + u32 config3; + u32 ipc; + u32 err_addr; + u32 delay_line; +}; +#endif + +/* Set FCMD to 1, rest to 0 for Command operation */ +#define NFC_CMD 0x1 + +/* Set FADD to 1, rest to 0 for Address operation */ +#define NFC_ADDR 0x2 + +/* Set FDI to 1, rest to 0 for Input operation */ +#define NFC_INPUT 0x4 + +/* Set FDO to 001, rest to 0 for Data Output operation */ +#define NFC_OUTPUT 0x8 + +/* Set FDO to 010, rest to 0 for Read ID operation */ +#define NFC_ID 0x10 + +/* Set FDO to 100, rest to 0 for Read Status operation */ +#define NFC_STATUS 0x20 + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) +#define NFC_CONFIG1_SP_EN (1 << 2) +#define NFC_CONFIG1_RST (1 << 6) +#define NFC_CONFIG1_CE (1 << 7) +#elif defined(MXC_NFC_V3_2) +#define NFC_CONFIG1_SP_EN (1 << 0) +#define NFC_CONFIG1_CE (1 << 1) +#define NFC_CONFIG1_RST (1 << 2) +#endif +#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3) +#define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4) +#define NFC_V1_V2_CONFIG1_BIG (1 << 5) +#define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0) +#define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8) +#define NFC_V2_CONFIG1_FP_INT (1 << 11) +#define NFC_V3_CONFIG1_RBA_MASK (0x7 << 4) +#define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7) << 4) + +#define NFC_V1_V2_CONFIG2_INT (1 << 15) +#define NFC_V3_CONFIG2_PS_MASK (0x3 << 0) +#define NFC_V3_CONFIG2_PS_512 (0 << 0) +#define NFC_V3_CONFIG2_PS_2048 (1 << 0) +#define NFC_V3_CONFIG2_PS_4096 (2 << 0) +#define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2) +#define NFC_V3_CONFIG2_ECC_EN (1 << 3) +#define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4) +#define NFC_V3_CONFIG2_NUM_ADDR_PH0 (1 << 5) +#define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6) +#define NFC_V3_CONFIG2_PPB_MASK (0x3 << 7) +#define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7) +#define NFC_V3_CONFIG2_EDC_MASK (0x7 << 9) +#define NFC_V3_CONFIG2_EDC(x) (((x) & 0x7) << 9) +#define NFC_V3_CONFIG2_NUM_ADDR_PH1(x) (((x) & 0x3) << 12) +#define NFC_V3_CONFIG2_INT_MSK (1 << 15) +#define NFC_V3_CONFIG2_SPAS_MASK (0xff << 16) +#define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16) +#define NFC_V3_CONFIG2_ST_CMD_MASK (0xff << 24) +#define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24) + +#define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0) +#define NFC_V3_CONFIG3_FW8 (1 << 3) +#define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8) +#define NFC_V3_CONFIG3_NUM_OF_DEVS(x) (((x) & 0x7) << 12) +#define NFC_V3_CONFIG3_RBB_MODE (1 << 15) +#define NFC_V3_CONFIG3_NO_SDMA (1 << 20) + +#define NFC_V3_WRPROT_UNLOCK (1 << 2) +#define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6) + +#define NFC_V3_IPC_CREQ (1 << 0) +#define NFC_V3_IPC_INT (1 << 31) + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) +#define operation config2 +#define readnfc readw +#define writenfc writew +#elif defined(MXC_NFC_V3_2) +#define operation launch +#define readnfc readl +#define writenfc writel +#endif + +#endif /* __MXC_NAND_H */ diff --git a/drivers/mtd/nand/raw/mxc_nand_spl.c b/drivers/mtd/nand/raw/mxc_nand_spl.c new file mode 100644 index 0000000000..6c03db8428 --- /dev/null +++ b/drivers/mtd/nand/raw/mxc_nand_spl.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2009 + * Magnus Lilja + * + * (C) Copyright 2008 + * Maxim Artamonov, + * + * (C) Copyright 2006-2008 + * Stefan Roese, DENX Software Engineering, sr at denx.de. + */ + +#include +#include +#include +#include +#include "mxc_nand.h" + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) +static struct mxc_nand_regs *const nfc = (void *)NFC_BASE_ADDR; +#elif defined(MXC_NFC_V3_2) +static struct mxc_nand_regs *const nfc = (void *)NFC_BASE_ADDR_AXI; +static struct mxc_nand_ip_regs *const nfc_ip = (void *)NFC_BASE_ADDR; +#endif + +static void nfc_wait_ready(void) +{ + uint32_t tmp; + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + while (!(readnfc(&nfc->config2) & NFC_V1_V2_CONFIG2_INT)) + ; + + /* Reset interrupt flag */ + tmp = readnfc(&nfc->config2); + tmp &= ~NFC_V1_V2_CONFIG2_INT; + writenfc(tmp, &nfc->config2); +#elif defined(MXC_NFC_V3_2) + while (!(readnfc(&nfc_ip->ipc) & NFC_V3_IPC_INT)) + ; + + /* Reset interrupt flag */ + tmp = readnfc(&nfc_ip->ipc); + tmp &= ~NFC_V3_IPC_INT; + writenfc(tmp, &nfc_ip->ipc); +#endif +} + +static void nfc_nand_init(void) +{ +#if defined(MXC_NFC_V3_2) + int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; + int tmp; + + tmp = (readnfc(&nfc_ip->config2) & ~(NFC_V3_CONFIG2_SPAS_MASK | + NFC_V3_CONFIG2_EDC_MASK | NFC_V3_CONFIG2_PS_MASK)) | + NFC_V3_CONFIG2_SPAS(CONFIG_SYS_NAND_OOBSIZE / 2) | + NFC_V3_CONFIG2_INT_MSK | NFC_V3_CONFIG2_ECC_EN | + NFC_V3_CONFIG2_ONE_CYCLE; + if (CONFIG_SYS_NAND_PAGE_SIZE == 4096) + tmp |= NFC_V3_CONFIG2_PS_4096; + else if (CONFIG_SYS_NAND_PAGE_SIZE == 2048) + tmp |= NFC_V3_CONFIG2_PS_2048; + else if (CONFIG_SYS_NAND_PAGE_SIZE == 512) + tmp |= NFC_V3_CONFIG2_PS_512; + /* + * if spare size is larger that 16 bytes per 512 byte hunk + * then use 8 symbol correction instead of 4 + */ + if (CONFIG_SYS_NAND_OOBSIZE / ecc_per_page > 16) + tmp |= NFC_V3_CONFIG2_ECC_MODE_8; + else + tmp &= ~NFC_V3_CONFIG2_ECC_MODE_8; + writenfc(tmp, &nfc_ip->config2); + + tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) | + NFC_V3_CONFIG3_NO_SDMA | + NFC_V3_CONFIG3_RBB_MODE | + NFC_V3_CONFIG3_SBB(6) | /* Reset default */ + NFC_V3_CONFIG3_ADD_OP(0); +#ifndef CONFIG_SYS_NAND_BUSWIDTH_16 + tmp |= NFC_V3_CONFIG3_FW8; +#endif + writenfc(tmp, &nfc_ip->config3); + + writenfc(0, &nfc_ip->delay_line); +#elif defined(MXC_NFC_V2_1) + int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; + int config1; + + writenfc(CONFIG_SYS_NAND_OOBSIZE / 2, &nfc->spare_area_size); + + /* unlocking RAM Buff */ + writenfc(0x2, &nfc->config); + + /* hardware ECC checking and correct */ + config1 = readnfc(&nfc->config1) | NFC_V1_V2_CONFIG1_ECC_EN | + NFC_V1_V2_CONFIG1_INT_MSK | NFC_V2_CONFIG1_ONE_CYCLE | + NFC_V2_CONFIG1_FP_INT; + /* + * if spare size is larger that 16 bytes per 512 byte hunk + * then use 8 symbol correction instead of 4 + */ + if (CONFIG_SYS_NAND_OOBSIZE / ecc_per_page > 16) + config1 &= ~NFC_V2_CONFIG1_ECC_MODE_4; + else + config1 |= NFC_V2_CONFIG1_ECC_MODE_4; + writenfc(config1, &nfc->config1); +#elif defined(MXC_NFC_V1) + /* unlocking RAM Buff */ + writenfc(0x2, &nfc->config); + + /* hardware ECC checking and correct */ + writenfc(NFC_V1_V2_CONFIG1_ECC_EN | NFC_V1_V2_CONFIG1_INT_MSK, + &nfc->config1); +#endif +} + +static void nfc_nand_command(unsigned short command) +{ + writenfc(command, &nfc->flash_cmd); + writenfc(NFC_CMD, &nfc->operation); + nfc_wait_ready(); +} + +static void nfc_nand_address(unsigned short address) +{ + writenfc(address, &nfc->flash_addr); + writenfc(NFC_ADDR, &nfc->operation); + nfc_wait_ready(); +} + +static void nfc_nand_page_address(unsigned int page_address) +{ + unsigned int page_count; + + nfc_nand_address(0x00); + + /* code only for large page flash */ + if (CONFIG_SYS_NAND_PAGE_SIZE > 512) + nfc_nand_address(0x00); + + page_count = CONFIG_SYS_NAND_SIZE / CONFIG_SYS_NAND_PAGE_SIZE; + + if (page_address <= page_count) { + page_count--; /* transform 0x01000000 to 0x00ffffff */ + do { + nfc_nand_address(page_address & 0xff); + page_address = page_address >> 8; + page_count = page_count >> 8; + } while (page_count); + } + + nfc_nand_address(0x00); +} + +static void nfc_nand_data_output(void) +{ +#ifdef NAND_MXC_2K_MULTI_CYCLE + int i; +#endif + +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + writenfc(0, &nfc->buf_addr); +#elif defined(MXC_NFC_V3_2) + int config1 = readnfc(&nfc->config1); + config1 &= ~NFC_V3_CONFIG1_RBA_MASK; + writenfc(config1, &nfc->config1); +#endif + writenfc(NFC_OUTPUT, &nfc->operation); + nfc_wait_ready(); +#ifdef NAND_MXC_2K_MULTI_CYCLE + /* + * This NAND controller requires multiple input commands + * for pages larger than 512 bytes. + */ + for (i = 1; i < CONFIG_SYS_NAND_PAGE_SIZE / 512; i++) { + writenfc(i, &nfc->buf_addr); + writenfc(NFC_OUTPUT, &nfc->operation); + nfc_wait_ready(); + } +#endif +} + +static int nfc_nand_check_ecc(void) +{ +#if defined(MXC_NFC_V1) + u16 ecc_status = readw(&nfc->ecc_status_result); + return (ecc_status & 0x3) == 2 || (ecc_status >> 2) == 2; +#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) + u32 ecc_status = readl(&nfc->ecc_status_result); + int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; + int err_limit = CONFIG_SYS_NAND_OOBSIZE / ecc_per_page > 16 ? 8 : 4; + int subpages = CONFIG_SYS_NAND_PAGE_SIZE / 512; + + do { + if ((ecc_status & 0xf) > err_limit) + return 1; + ecc_status >>= 4; + } while (--subpages); + + return 0; +#endif +} + +static void nfc_nand_read_page(unsigned int page_address) +{ + /* read in first 0 buffer */ +#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) + writenfc(0, &nfc->buf_addr); +#elif defined(MXC_NFC_V3_2) + int config1 = readnfc(&nfc->config1); + config1 &= ~NFC_V3_CONFIG1_RBA_MASK; + writenfc(config1, &nfc->config1); +#endif + nfc_nand_command(NAND_CMD_READ0); + nfc_nand_page_address(page_address); + + if (CONFIG_SYS_NAND_PAGE_SIZE > 512) + nfc_nand_command(NAND_CMD_READSTART); + + nfc_nand_data_output(); /* fill the main buffer 0 */ +} + +static int nfc_read_page(unsigned int page_address, unsigned char *buf) +{ + int i; + u32 *src; + u32 *dst; + + nfc_nand_read_page(page_address); + + if (nfc_nand_check_ecc()) + return -EBADMSG; + + src = (u32 *)&nfc->main_area[0][0]; + dst = (u32 *)buf; + + /* main copy loop from NAND-buffer to SDRAM memory */ + for (i = 0; i < CONFIG_SYS_NAND_PAGE_SIZE / 4; i++) { + writel(readl(src), dst); + src++; + dst++; + } + + return 0; +} + +static int is_badblock(int pagenumber) +{ + int page = pagenumber; + u32 badblock; + u32 *src; + + /* Check the first two pages for bad block markers */ + for (page = pagenumber; page < pagenumber + 2; page++) { + nfc_nand_read_page(page); + + src = (u32 *)&nfc->spare_area[0][0]; + + /* + * IMPORTANT NOTE: The nand flash controller uses a non- + * standard layout for large page devices. This can + * affect the position of the bad block marker. + */ + /* Get the bad block marker */ + badblock = readl(&src[CONFIG_SYS_NAND_BAD_BLOCK_POS / 4]); + badblock >>= 8 * (CONFIG_SYS_NAND_BAD_BLOCK_POS % 4); + badblock &= 0xff; + + /* bad block marker verify */ + if (badblock != 0xff) + return 1; /* potential bad block */ + } + + return 0; +} + +int nand_spl_load_image(uint32_t from, unsigned int size, void *buf) +{ + int i; + unsigned int page; + unsigned int maxpages = CONFIG_SYS_NAND_SIZE / + CONFIG_SYS_NAND_PAGE_SIZE; + + nfc_nand_init(); + + /* Convert to page number */ + page = from / CONFIG_SYS_NAND_PAGE_SIZE; + i = 0; + + size = roundup(size, CONFIG_SYS_NAND_PAGE_SIZE); + while (i < size / CONFIG_SYS_NAND_PAGE_SIZE) { + if (nfc_read_page(page, buf) < 0) + return -1; + + page++; + i++; + buf = buf + CONFIG_SYS_NAND_PAGE_SIZE; + + /* + * Check if we have crossed a block boundary, and if so + * check for bad block. + */ + if (!(page % CONFIG_SYS_NAND_PAGE_COUNT)) { + /* + * Yes, new block. See if this block is good. If not, + * loop until we find a good block. + */ + while (is_badblock(page)) { + page = page + CONFIG_SYS_NAND_PAGE_COUNT; + /* Check i we've reached the end of flash. */ + if (page >= maxpages) + return -1; + } + } + } + + return 0; +} + +#ifndef CONFIG_SPL_FRAMEWORK +/* + * The main entry for NAND booting. It's necessary that SDRAM is already + * configured and available since this code loads the main U-Boot image + * from NAND into SDRAM and starts it from there. + */ +void nand_boot(void) +{ + __attribute__((noreturn)) void (*uboot)(void); + + /* + * CONFIG_SYS_NAND_U_BOOT_OFFS and CONFIG_SYS_NAND_U_BOOT_SIZE must + * be aligned to full pages + */ + if (!nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, + CONFIG_SYS_NAND_U_BOOT_SIZE, + (uchar *)CONFIG_SYS_NAND_U_BOOT_DST)) { + /* Copy from NAND successful, start U-Boot */ + uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; + uboot(); + } else { + /* Unrecoverable error when copying from NAND */ + hang(); + } +} +#endif + +void nand_init(void) {} +void nand_deselect(void) {} diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c new file mode 100644 index 0000000000..e3341812a2 --- /dev/null +++ b/drivers/mtd/nand/raw/mxs_nand.c @@ -0,0 +1,1302 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Freescale i.MX28 NAND flash driver + * + * Copyright (C) 2011 Marek Vasut + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * Freescale GPMI NFC NAND Flash Driver + * + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mxs_nand.h" + +#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4 + +#if (defined(CONFIG_MX6) || defined(CONFIG_MX7)) +#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 2 +#else +#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 0 +#endif +#define MXS_NAND_METADATA_SIZE 10 +#define MXS_NAND_BITS_PER_ECC_LEVEL 13 + +#if !defined(CONFIG_SYS_CACHELINE_SIZE) || CONFIG_SYS_CACHELINE_SIZE < 32 +#define MXS_NAND_COMMAND_BUFFER_SIZE 32 +#else +#define MXS_NAND_COMMAND_BUFFER_SIZE CONFIG_SYS_CACHELINE_SIZE +#endif + +#define MXS_NAND_BCH_TIMEOUT 10000 + +struct nand_ecclayout fake_ecc_layout; + +/* + * Cache management functions + */ +#ifndef CONFIG_SYS_DCACHE_OFF +static void mxs_nand_flush_data_buf(struct mxs_nand_info *info) +{ + uint32_t addr = (uint32_t)info->data_buf; + + flush_dcache_range(addr, addr + info->data_buf_size); +} + +static void mxs_nand_inval_data_buf(struct mxs_nand_info *info) +{ + uint32_t addr = (uint32_t)info->data_buf; + + invalidate_dcache_range(addr, addr + info->data_buf_size); +} + +static void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info) +{ + uint32_t addr = (uint32_t)info->cmd_buf; + + flush_dcache_range(addr, addr + MXS_NAND_COMMAND_BUFFER_SIZE); +} +#else +static inline void mxs_nand_flush_data_buf(struct mxs_nand_info *info) {} +static inline void mxs_nand_inval_data_buf(struct mxs_nand_info *info) {} +static inline void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info) {} +#endif + +static struct mxs_dma_desc *mxs_nand_get_dma_desc(struct mxs_nand_info *info) +{ + struct mxs_dma_desc *desc; + + if (info->desc_index >= MXS_NAND_DMA_DESCRIPTOR_COUNT) { + printf("MXS NAND: Too many DMA descriptors requested\n"); + return NULL; + } + + desc = info->desc[info->desc_index]; + info->desc_index++; + + return desc; +} + +static void mxs_nand_return_dma_descs(struct mxs_nand_info *info) +{ + int i; + struct mxs_dma_desc *desc; + + for (i = 0; i < info->desc_index; i++) { + desc = info->desc[i]; + memset(desc, 0, sizeof(struct mxs_dma_desc)); + desc->address = (dma_addr_t)desc; + } + + info->desc_index = 0; +} + +static uint32_t mxs_nand_aux_status_offset(void) +{ + return (MXS_NAND_METADATA_SIZE + 0x3) & ~0x3; +} + +static inline int mxs_nand_calc_mark_offset(struct bch_geometry *geo, + uint32_t page_data_size) +{ + uint32_t chunk_data_size_in_bits = geo->ecc_chunk_size * 8; + uint32_t chunk_ecc_size_in_bits = geo->ecc_strength * geo->gf_len; + uint32_t chunk_total_size_in_bits; + uint32_t block_mark_chunk_number; + uint32_t block_mark_chunk_bit_offset; + uint32_t block_mark_bit_offset; + + chunk_total_size_in_bits = + chunk_data_size_in_bits + chunk_ecc_size_in_bits; + + /* Compute the bit offset of the block mark within the physical page. */ + block_mark_bit_offset = page_data_size * 8; + + /* Subtract the metadata bits. */ + block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8; + + /* + * Compute the chunk number (starting at zero) in which the block mark + * appears. + */ + block_mark_chunk_number = + block_mark_bit_offset / chunk_total_size_in_bits; + + /* + * Compute the bit offset of the block mark within its chunk, and + * validate it. + */ + block_mark_chunk_bit_offset = block_mark_bit_offset - + (block_mark_chunk_number * chunk_total_size_in_bits); + + if (block_mark_chunk_bit_offset > chunk_data_size_in_bits) + return -EINVAL; + + /* + * Now that we know the chunk number in which the block mark appears, + * we can subtract all the ECC bits that appear before it. + */ + block_mark_bit_offset -= + block_mark_chunk_number * chunk_ecc_size_in_bits; + + geo->block_mark_byte_offset = block_mark_bit_offset >> 3; + geo->block_mark_bit_offset = block_mark_bit_offset & 0x7; + + return 0; +} + +static inline int mxs_nand_calc_ecc_layout_by_info(struct bch_geometry *geo, + struct mtd_info *mtd, + unsigned int ecc_strength, + unsigned int ecc_step) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(chip); + + switch (ecc_step) { + case SZ_512: + geo->gf_len = 13; + break; + case SZ_1K: + geo->gf_len = 14; + break; + default: + return -EINVAL; + } + + geo->ecc_chunk_size = ecc_step; + geo->ecc_strength = round_up(ecc_strength, 2); + + /* Keep the C >= O */ + if (geo->ecc_chunk_size < mtd->oobsize) + return -EINVAL; + + if (geo->ecc_strength > nand_info->max_ecc_strength_supported) + return -EINVAL; + + geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size; + + return 0; +} + +static inline int mxs_nand_calc_ecc_layout(struct bch_geometry *geo, + struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(chip); + + /* The default for the length of Galois Field. */ + geo->gf_len = 13; + + /* The default for chunk size. */ + geo->ecc_chunk_size = 512; + + if (geo->ecc_chunk_size < mtd->oobsize) { + geo->gf_len = 14; + geo->ecc_chunk_size *= 2; + } + + if (mtd->oobsize > geo->ecc_chunk_size) { + printf("Not support the NAND chips whose oob size is larger then %d bytes!\n", + geo->ecc_chunk_size); + return -EINVAL; + } + + geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size; + + /* + * Determine the ECC layout with the formula: + * ECC bits per chunk = (total page spare data bits) / + * (bits per ECC level) / (chunks per page) + * where: + * total page spare data bits = + * (page oob size - meta data size) * (bits per byte) + */ + geo->ecc_strength = ((mtd->oobsize - MXS_NAND_METADATA_SIZE) * 8) + / (geo->gf_len * geo->ecc_chunk_count); + + geo->ecc_strength = min(round_down(geo->ecc_strength, 2), + nand_info->max_ecc_strength_supported); + + return 0; +} + +/* + * Wait for BCH complete IRQ and clear the IRQ + */ +static int mxs_nand_wait_for_bch_complete(struct mxs_nand_info *nand_info) +{ + int timeout = MXS_NAND_BCH_TIMEOUT; + int ret; + + ret = mxs_wait_mask_set(&nand_info->bch_regs->hw_bch_ctrl_reg, + BCH_CTRL_COMPLETE_IRQ, timeout); + + writel(BCH_CTRL_COMPLETE_IRQ, &nand_info->bch_regs->hw_bch_ctrl_clr); + + return ret; +} + +/* + * This is the function that we install in the cmd_ctrl function pointer of the + * owning struct nand_chip. The only functions in the reference implementation + * that use these functions pointers are cmdfunc and select_chip. + * + * In this driver, we implement our own select_chip, so this function will only + * be called by the reference implementation's cmdfunc. For this reason, we can + * ignore the chip enable bit and concentrate only on sending bytes to the NAND + * Flash. + */ +static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + struct mxs_dma_desc *d; + uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; + int ret; + + /* + * If this condition is true, something is _VERY_ wrong in MTD + * subsystem! + */ + if (nand_info->cmd_queue_len == MXS_NAND_COMMAND_BUFFER_SIZE) { + printf("MXS NAND: Command queue too long\n"); + return; + } + + /* + * Every operation begins with a command byte and a series of zero or + * more address bytes. These are distinguished by either the Address + * Latch Enable (ALE) or Command Latch Enable (CLE) signals being + * asserted. When MTD is ready to execute the command, it will + * deasert both latch enables. + * + * Rather than run a separate DMA operation for every single byte, we + * queue them up and run a single DMA operation for the entire series + * of command and data bytes. + */ + if (ctrl & (NAND_ALE | NAND_CLE)) { + if (data != NAND_CMD_NONE) + nand_info->cmd_buf[nand_info->cmd_queue_len++] = data; + return; + } + + /* + * If control arrives here, MTD has deasserted both the ALE and CLE, + * which means it's ready to run an operation. Check if we have any + * bytes to send. + */ + if (nand_info->cmd_queue_len == 0) + return; + + /* Compile the DMA descriptor -- a descriptor that sends command. */ + d = mxs_nand_get_dma_desc(nand_info); + d->cmd.data = + MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ | + MXS_DMA_DESC_CHAIN | MXS_DMA_DESC_DEC_SEM | + MXS_DMA_DESC_WAIT4END | (3 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | + (nand_info->cmd_queue_len << MXS_DMA_DESC_BYTES_OFFSET); + + d->cmd.address = (dma_addr_t)nand_info->cmd_buf; + + d->cmd.pio_words[0] = + GPMI_CTRL0_COMMAND_MODE_WRITE | + GPMI_CTRL0_WORD_LENGTH | + (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | + GPMI_CTRL0_ADDRESS_NAND_CLE | + GPMI_CTRL0_ADDRESS_INCREMENT | + nand_info->cmd_queue_len; + + mxs_dma_desc_append(channel, d); + + /* Flush caches */ + mxs_nand_flush_cmd_buf(nand_info); + + /* Execute the DMA chain. */ + ret = mxs_dma_go(channel); + if (ret) + printf("MXS NAND: Error sending command\n"); + + mxs_nand_return_dma_descs(nand_info); + + /* Reset the command queue. */ + nand_info->cmd_queue_len = 0; +} + +/* + * Test if the NAND flash is ready. + */ +static int mxs_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(chip); + uint32_t tmp; + + tmp = readl(&nand_info->gpmi_regs->hw_gpmi_stat); + tmp >>= (GPMI_STAT_READY_BUSY_OFFSET + nand_info->cur_chip); + + return tmp & 1; +} + +/* + * Select the NAND chip. + */ +static void mxs_nand_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + + nand_info->cur_chip = chip; +} + +/* + * Handle block mark swapping. + * + * Note that, when this function is called, it doesn't know whether it's + * swapping the block mark, or swapping it *back* -- but it doesn't matter + * because the the operation is the same. + */ +static void mxs_nand_swap_block_mark(struct bch_geometry *geo, + uint8_t *data_buf, uint8_t *oob_buf) +{ + uint32_t bit_offset = geo->block_mark_bit_offset; + uint32_t buf_offset = geo->block_mark_byte_offset; + + uint32_t src; + uint32_t dst; + + /* + * Get the byte from the data area that overlays the block mark. Since + * the ECC engine applies its own view to the bits in the page, the + * physical block mark won't (in general) appear on a byte boundary in + * the data. + */ + src = data_buf[buf_offset] >> bit_offset; + src |= data_buf[buf_offset + 1] << (8 - bit_offset); + + dst = oob_buf[0]; + + oob_buf[0] = src; + + data_buf[buf_offset] &= ~(0xff << bit_offset); + data_buf[buf_offset + 1] &= 0xff << bit_offset; + + data_buf[buf_offset] |= dst << bit_offset; + data_buf[buf_offset + 1] |= dst >> (8 - bit_offset); +} + +/* + * Read data from NAND. + */ +static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + struct mxs_dma_desc *d; + uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; + int ret; + + if (length > NAND_MAX_PAGESIZE) { + printf("MXS NAND: DMA buffer too big\n"); + return; + } + + if (!buf) { + printf("MXS NAND: DMA buffer is NULL\n"); + return; + } + + /* Compile the DMA descriptor - a descriptor that reads data. */ + d = mxs_nand_get_dma_desc(nand_info); + d->cmd.data = + MXS_DMA_DESC_COMMAND_DMA_WRITE | MXS_DMA_DESC_IRQ | + MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | + (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | + (length << MXS_DMA_DESC_BYTES_OFFSET); + + d->cmd.address = (dma_addr_t)nand_info->data_buf; + + d->cmd.pio_words[0] = + GPMI_CTRL0_COMMAND_MODE_READ | + GPMI_CTRL0_WORD_LENGTH | + (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | + GPMI_CTRL0_ADDRESS_NAND_DATA | + length; + + mxs_dma_desc_append(channel, d); + + /* + * A DMA descriptor that waits for the command to end and the chip to + * become ready. + * + * I think we actually should *not* be waiting for the chip to become + * ready because, after all, we don't care. I think the original code + * did that and no one has re-thought it yet. + */ + d = mxs_nand_get_dma_desc(nand_info); + d->cmd.data = + MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | + MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_DEC_SEM | + MXS_DMA_DESC_WAIT4END | (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET); + + d->cmd.address = 0; + + d->cmd.pio_words[0] = + GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | + GPMI_CTRL0_WORD_LENGTH | + (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | + GPMI_CTRL0_ADDRESS_NAND_DATA; + + mxs_dma_desc_append(channel, d); + + /* Invalidate caches */ + mxs_nand_inval_data_buf(nand_info); + + /* Execute the DMA chain. */ + ret = mxs_dma_go(channel); + if (ret) { + printf("MXS NAND: DMA read error\n"); + goto rtn; + } + + /* Invalidate caches */ + mxs_nand_inval_data_buf(nand_info); + + memcpy(buf, nand_info->data_buf, length); + +rtn: + mxs_nand_return_dma_descs(nand_info); +} + +/* + * Write data to NAND. + */ +static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, + int length) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + struct mxs_dma_desc *d; + uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; + int ret; + + if (length > NAND_MAX_PAGESIZE) { + printf("MXS NAND: DMA buffer too big\n"); + return; + } + + if (!buf) { + printf("MXS NAND: DMA buffer is NULL\n"); + return; + } + + memcpy(nand_info->data_buf, buf, length); + + /* Compile the DMA descriptor - a descriptor that writes data. */ + d = mxs_nand_get_dma_desc(nand_info); + d->cmd.data = + MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ | + MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | + (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | + (length << MXS_DMA_DESC_BYTES_OFFSET); + + d->cmd.address = (dma_addr_t)nand_info->data_buf; + + d->cmd.pio_words[0] = + GPMI_CTRL0_COMMAND_MODE_WRITE | + GPMI_CTRL0_WORD_LENGTH | + (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | + GPMI_CTRL0_ADDRESS_NAND_DATA | + length; + + mxs_dma_desc_append(channel, d); + + /* Flush caches */ + mxs_nand_flush_data_buf(nand_info); + + /* Execute the DMA chain. */ + ret = mxs_dma_go(channel); + if (ret) + printf("MXS NAND: DMA write error\n"); + + mxs_nand_return_dma_descs(nand_info); +} + +/* + * Read a single byte from NAND. + */ +static uint8_t mxs_nand_read_byte(struct mtd_info *mtd) +{ + uint8_t buf; + mxs_nand_read_buf(mtd, &buf, 1); + return buf; +} + +/* + * Read a page from NAND. + */ +static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand, + uint8_t *buf, int oob_required, + int page) +{ + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + struct bch_geometry *geo = &nand_info->bch_geometry; + struct mxs_dma_desc *d; + uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; + uint32_t corrected = 0, failed = 0; + uint8_t *status; + int i, ret; + + /* Compile the DMA descriptor - wait for ready. */ + d = mxs_nand_get_dma_desc(nand_info); + d->cmd.data = + MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | + MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_WAIT4END | + (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET); + + d->cmd.address = 0; + + d->cmd.pio_words[0] = + GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | + GPMI_CTRL0_WORD_LENGTH | + (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | + GPMI_CTRL0_ADDRESS_NAND_DATA; + + mxs_dma_desc_append(channel, d); + + /* Compile the DMA descriptor - enable the BCH block and read. */ + d = mxs_nand_get_dma_desc(nand_info); + d->cmd.data = + MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | + MXS_DMA_DESC_WAIT4END | (6 << MXS_DMA_DESC_PIO_WORDS_OFFSET); + + d->cmd.address = 0; + + d->cmd.pio_words[0] = + GPMI_CTRL0_COMMAND_MODE_READ | + GPMI_CTRL0_WORD_LENGTH | + (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | + GPMI_CTRL0_ADDRESS_NAND_DATA | + (mtd->writesize + mtd->oobsize); + d->cmd.pio_words[1] = 0; + d->cmd.pio_words[2] = + GPMI_ECCCTRL_ENABLE_ECC | + GPMI_ECCCTRL_ECC_CMD_DECODE | + GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE; + d->cmd.pio_words[3] = mtd->writesize + mtd->oobsize; + d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf; + d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf; + + mxs_dma_desc_append(channel, d); + + /* Compile the DMA descriptor - disable the BCH block. */ + d = mxs_nand_get_dma_desc(nand_info); + d->cmd.data = + MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | + MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_WAIT4END | + (3 << MXS_DMA_DESC_PIO_WORDS_OFFSET); + + d->cmd.address = 0; + + d->cmd.pio_words[0] = + GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | + GPMI_CTRL0_WORD_LENGTH | + (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | + GPMI_CTRL0_ADDRESS_NAND_DATA | + (mtd->writesize + mtd->oobsize); + d->cmd.pio_words[1] = 0; + d->cmd.pio_words[2] = 0; + + mxs_dma_desc_append(channel, d); + + /* Compile the DMA descriptor - deassert the NAND lock and interrupt. */ + d = mxs_nand_get_dma_desc(nand_info); + d->cmd.data = + MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | + MXS_DMA_DESC_DEC_SEM; + + d->cmd.address = 0; + + mxs_dma_desc_append(channel, d); + + /* Invalidate caches */ + mxs_nand_inval_data_buf(nand_info); + + /* Execute the DMA chain. */ + ret = mxs_dma_go(channel); + if (ret) { + printf("MXS NAND: DMA read error\n"); + goto rtn; + } + + ret = mxs_nand_wait_for_bch_complete(nand_info); + if (ret) { + printf("MXS NAND: BCH read timeout\n"); + goto rtn; + } + + /* Invalidate caches */ + mxs_nand_inval_data_buf(nand_info); + + /* Read DMA completed, now do the mark swapping. */ + mxs_nand_swap_block_mark(geo, nand_info->data_buf, nand_info->oob_buf); + + /* Loop over status bytes, accumulating ECC status. */ + status = nand_info->oob_buf + mxs_nand_aux_status_offset(); + for (i = 0; i < geo->ecc_chunk_count; i++) { + if (status[i] == 0x00) + continue; + + if (status[i] == 0xff) + continue; + + if (status[i] == 0xfe) { + failed++; + continue; + } + + corrected += status[i]; + } + + /* Propagate ECC status to the owning MTD. */ + mtd->ecc_stats.failed += failed; + mtd->ecc_stats.corrected += corrected; + + /* + * It's time to deliver the OOB bytes. See mxs_nand_ecc_read_oob() for + * details about our policy for delivering the OOB. + * + * We fill the caller's buffer with set bits, and then copy the block + * mark to the caller's buffer. Note that, if block mark swapping was + * necessary, it has already been done, so we can rely on the first + * byte of the auxiliary buffer to contain the block mark. + */ + memset(nand->oob_poi, 0xff, mtd->oobsize); + + nand->oob_poi[0] = nand_info->oob_buf[0]; + + memcpy(buf, nand_info->data_buf, mtd->writesize); + +rtn: + mxs_nand_return_dma_descs(nand_info); + + return ret; +} + +/* + * Write a page to NAND. + */ +static int mxs_nand_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *nand, const uint8_t *buf, + int oob_required, int page) +{ + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + struct bch_geometry *geo = &nand_info->bch_geometry; + struct mxs_dma_desc *d; + uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; + int ret; + + memcpy(nand_info->data_buf, buf, mtd->writesize); + memcpy(nand_info->oob_buf, nand->oob_poi, mtd->oobsize); + + /* Handle block mark swapping. */ + mxs_nand_swap_block_mark(geo, nand_info->data_buf, nand_info->oob_buf); + + /* Compile the DMA descriptor - write data. */ + d = mxs_nand_get_dma_desc(nand_info); + d->cmd.data = + MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | + MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | + (6 << MXS_DMA_DESC_PIO_WORDS_OFFSET); + + d->cmd.address = 0; + + d->cmd.pio_words[0] = + GPMI_CTRL0_COMMAND_MODE_WRITE | + GPMI_CTRL0_WORD_LENGTH | + (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | + GPMI_CTRL0_ADDRESS_NAND_DATA; + d->cmd.pio_words[1] = 0; + d->cmd.pio_words[2] = + GPMI_ECCCTRL_ENABLE_ECC | + GPMI_ECCCTRL_ECC_CMD_ENCODE | + GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE; + d->cmd.pio_words[3] = (mtd->writesize + mtd->oobsize); + d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf; + d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf; + + mxs_dma_desc_append(channel, d); + + /* Flush caches */ + mxs_nand_flush_data_buf(nand_info); + + /* Execute the DMA chain. */ + ret = mxs_dma_go(channel); + if (ret) { + printf("MXS NAND: DMA write error\n"); + goto rtn; + } + + ret = mxs_nand_wait_for_bch_complete(nand_info); + if (ret) { + printf("MXS NAND: BCH write timeout\n"); + goto rtn; + } + +rtn: + mxs_nand_return_dma_descs(nand_info); + return 0; +} + +/* + * Read OOB from NAND. + * + * This function is a veneer that replaces the function originally installed by + * the NAND Flash MTD code. + */ +static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(chip); + int ret; + + if (ops->mode == MTD_OPS_RAW) + nand_info->raw_oob_mode = 1; + else + nand_info->raw_oob_mode = 0; + + ret = nand_info->hooked_read_oob(mtd, from, ops); + + nand_info->raw_oob_mode = 0; + + return ret; +} + +/* + * Write OOB to NAND. + * + * This function is a veneer that replaces the function originally installed by + * the NAND Flash MTD code. + */ +static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(chip); + int ret; + + if (ops->mode == MTD_OPS_RAW) + nand_info->raw_oob_mode = 1; + else + nand_info->raw_oob_mode = 0; + + ret = nand_info->hooked_write_oob(mtd, to, ops); + + nand_info->raw_oob_mode = 0; + + return ret; +} + +/* + * Mark a block bad in NAND. + * + * This function is a veneer that replaces the function originally installed by + * the NAND Flash MTD code. + */ +static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(chip); + int ret; + + nand_info->marking_block_bad = 1; + + ret = nand_info->hooked_block_markbad(mtd, ofs); + + nand_info->marking_block_bad = 0; + + return ret; +} + +/* + * There are several places in this driver where we have to handle the OOB and + * block marks. This is the function where things are the most complicated, so + * this is where we try to explain it all. All the other places refer back to + * here. + * + * These are the rules, in order of decreasing importance: + * + * 1) Nothing the caller does can be allowed to imperil the block mark, so all + * write operations take measures to protect it. + * + * 2) In read operations, the first byte of the OOB we return must reflect the + * true state of the block mark, no matter where that block mark appears in + * the physical page. + * + * 3) ECC-based read operations return an OOB full of set bits (since we never + * allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads + * return). + * + * 4) "Raw" read operations return a direct view of the physical bytes in the + * page, using the conventional definition of which bytes are data and which + * are OOB. This gives the caller a way to see the actual, physical bytes + * in the page, without the distortions applied by our ECC engine. + * + * What we do for this specific read operation depends on whether we're doing + * "raw" read, or an ECC-based read. + * + * It turns out that knowing whether we want an "ECC-based" or "raw" read is not + * easy. When reading a page, for example, the NAND Flash MTD code calls our + * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an + * 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). + * + * Since MTD assumes the OOB is not covered by ECC, there is no pair of + * ECC-based/raw functions for reading or or writing the OOB. The fact that the + * caller wants an ECC-based or raw view of the page is not propagated down to + * this driver. + * + * Since our OOB *is* covered by ECC, we need this information. So, we hook the + * ecc.read_oob and ecc.write_oob function pointers in the owning + * struct mtd_info with our own functions. These hook functions set the + * raw_oob_mode field so that, when control finally arrives here, we'll know + * what to do. + */ +static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand, + int page) +{ + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + + /* + * First, fill in the OOB buffer. If we're doing a raw read, we need to + * get the bytes from the physical page. If we're not doing a raw read, + * we need to fill the buffer with set bits. + */ + if (nand_info->raw_oob_mode) { + /* + * If control arrives here, we're doing a "raw" read. Send the + * command to read the conventional OOB and read it. + */ + nand->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + nand->read_buf(mtd, nand->oob_poi, mtd->oobsize); + } else { + /* + * If control arrives here, we're not doing a "raw" read. Fill + * the OOB buffer with set bits and correct the block mark. + */ + memset(nand->oob_poi, 0xff, mtd->oobsize); + + nand->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + mxs_nand_read_buf(mtd, nand->oob_poi, 1); + } + + return 0; + +} + +/* + * Write OOB data to NAND. + */ +static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *nand, + int page) +{ + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + uint8_t block_mark = 0; + + /* + * There are fundamental incompatibilities between the i.MX GPMI NFC and + * the NAND Flash MTD model that make it essentially impossible to write + * the out-of-band bytes. + * + * We permit *ONE* exception. If the *intent* of writing the OOB is to + * mark a block bad, we can do that. + */ + + if (!nand_info->marking_block_bad) { + printf("NXS NAND: Writing OOB isn't supported\n"); + return -EIO; + } + + /* Write the block mark. */ + nand->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + nand->write_buf(mtd, &block_mark, 1); + nand->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + /* Check if it worked. */ + if (nand->waitfunc(mtd, nand) & NAND_STATUS_FAIL) + return -EIO; + + return 0; +} + +/* + * Claims all blocks are good. + * + * In principle, this function is *only* called when the NAND Flash MTD system + * isn't allowed to keep an in-memory bad block table, so it is forced to ask + * the driver for bad block information. + * + * In fact, we permit the NAND Flash MTD system to have an in-memory BBT, so + * this function is *only* called when we take it away. + * + * Thus, this function is only called when we want *all* blocks to look good, + * so it *always* return success. + */ +static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs) +{ + return 0; +} + +static int mxs_nand_set_geometry(struct mtd_info *mtd, struct bch_geometry *geo) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_chip *nand = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + + if (chip->ecc.strength > 0 && chip->ecc.size > 0) + return mxs_nand_calc_ecc_layout_by_info(geo, mtd, + chip->ecc.strength, chip->ecc.size); + + if (nand_info->use_minimum_ecc || + mxs_nand_calc_ecc_layout(geo, mtd)) { + if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0)) + return -EINVAL; + + return mxs_nand_calc_ecc_layout_by_info(geo, mtd, + chip->ecc_strength_ds, chip->ecc_step_ds); + } + + return 0; +} + +/* + * At this point, the physical NAND Flash chips have been identified and + * counted, so we know the physical geometry. This enables us to make some + * important configuration decisions. + * + * The return value of this function propagates directly back to this driver's + * board_nand_init(). Anything other than zero will cause this driver to + * tear everything down and declare failure. + */ +int mxs_nand_setup_ecc(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + struct bch_geometry *geo = &nand_info->bch_geometry; + struct mxs_bch_regs *bch_regs = nand_info->bch_regs; + uint32_t tmp; + int ret; + + ret = mxs_nand_set_geometry(mtd, geo); + if (ret) + return ret; + + mxs_nand_calc_mark_offset(geo, mtd->writesize); + + /* Configure BCH and set NFC geometry */ + mxs_reset_block(&bch_regs->hw_bch_ctrl_reg); + + /* Configure layout 0 */ + tmp = (geo->ecc_chunk_count - 1) << BCH_FLASHLAYOUT0_NBLOCKS_OFFSET; + tmp |= MXS_NAND_METADATA_SIZE << BCH_FLASHLAYOUT0_META_SIZE_OFFSET; + tmp |= (geo->ecc_strength >> 1) << BCH_FLASHLAYOUT0_ECC0_OFFSET; + tmp |= geo->ecc_chunk_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT; + tmp |= (geo->gf_len == 14 ? 1 : 0) << + BCH_FLASHLAYOUT0_GF13_0_GF14_1_OFFSET; + writel(tmp, &bch_regs->hw_bch_flash0layout0); + + tmp = (mtd->writesize + mtd->oobsize) + << BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET; + tmp |= (geo->ecc_strength >> 1) << BCH_FLASHLAYOUT1_ECCN_OFFSET; + tmp |= geo->ecc_chunk_size >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT; + tmp |= (geo->gf_len == 14 ? 1 : 0) << + BCH_FLASHLAYOUT1_GF13_0_GF14_1_OFFSET; + writel(tmp, &bch_regs->hw_bch_flash0layout1); + + /* Set *all* chip selects to use layout 0 */ + writel(0, &bch_regs->hw_bch_layoutselect); + + /* Enable BCH complete interrupt */ + writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set); + + /* Hook some operations at the MTD level. */ + if (mtd->_read_oob != mxs_nand_hook_read_oob) { + nand_info->hooked_read_oob = mtd->_read_oob; + mtd->_read_oob = mxs_nand_hook_read_oob; + } + + if (mtd->_write_oob != mxs_nand_hook_write_oob) { + nand_info->hooked_write_oob = mtd->_write_oob; + mtd->_write_oob = mxs_nand_hook_write_oob; + } + + if (mtd->_block_markbad != mxs_nand_hook_block_markbad) { + nand_info->hooked_block_markbad = mtd->_block_markbad; + mtd->_block_markbad = mxs_nand_hook_block_markbad; + } + + return 0; +} + +/* + * Allocate DMA buffers + */ +int mxs_nand_alloc_buffers(struct mxs_nand_info *nand_info) +{ + uint8_t *buf; + const int size = NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE; + + nand_info->data_buf_size = roundup(size, MXS_DMA_ALIGNMENT); + + /* DMA buffers */ + buf = memalign(MXS_DMA_ALIGNMENT, nand_info->data_buf_size); + if (!buf) { + printf("MXS NAND: Error allocating DMA buffers\n"); + return -ENOMEM; + } + + memset(buf, 0, nand_info->data_buf_size); + + nand_info->data_buf = buf; + nand_info->oob_buf = buf + NAND_MAX_PAGESIZE; + /* Command buffers */ + nand_info->cmd_buf = memalign(MXS_DMA_ALIGNMENT, + MXS_NAND_COMMAND_BUFFER_SIZE); + if (!nand_info->cmd_buf) { + free(buf); + printf("MXS NAND: Error allocating command buffers\n"); + return -ENOMEM; + } + memset(nand_info->cmd_buf, 0, MXS_NAND_COMMAND_BUFFER_SIZE); + nand_info->cmd_queue_len = 0; + + return 0; +} + +/* + * Initializes the NFC hardware. + */ +int mxs_nand_init_dma(struct mxs_nand_info *info) +{ + int i = 0, j, ret = 0; + + info->desc = malloc(sizeof(struct mxs_dma_desc *) * + MXS_NAND_DMA_DESCRIPTOR_COUNT); + if (!info->desc) { + ret = -ENOMEM; + goto err1; + } + + /* Allocate the DMA descriptors. */ + for (i = 0; i < MXS_NAND_DMA_DESCRIPTOR_COUNT; i++) { + info->desc[i] = mxs_dma_desc_alloc(); + if (!info->desc[i]) { + ret = -ENOMEM; + goto err2; + } + } + + /* Init the DMA controller. */ + mxs_dma_init(); + for (j = MXS_DMA_CHANNEL_AHB_APBH_GPMI0; + j <= MXS_DMA_CHANNEL_AHB_APBH_GPMI7; j++) { + ret = mxs_dma_init_channel(j); + if (ret) + goto err3; + } + + /* Reset the GPMI block. */ + mxs_reset_block(&info->gpmi_regs->hw_gpmi_ctrl0_reg); + mxs_reset_block(&info->bch_regs->hw_bch_ctrl_reg); + + /* + * Choose NAND mode, set IRQ polarity, disable write protection and + * select BCH ECC. + */ + clrsetbits_le32(&info->gpmi_regs->hw_gpmi_ctrl1, + GPMI_CTRL1_GPMI_MODE, + GPMI_CTRL1_ATA_IRQRDY_POLARITY | GPMI_CTRL1_DEV_RESET | + GPMI_CTRL1_BCH_MODE); + + return 0; + +err3: + for (--j; j >= MXS_DMA_CHANNEL_AHB_APBH_GPMI0; j--) + mxs_dma_release(j); +err2: + for (--i; i >= 0; i--) + mxs_dma_desc_free(info->desc[i]); + free(info->desc); +err1: + if (ret == -ENOMEM) + printf("MXS NAND: Unable to allocate DMA descriptors\n"); + return ret; +} + +int mxs_nand_init_spl(struct nand_chip *nand) +{ + struct mxs_nand_info *nand_info; + int err; + + nand_info = malloc(sizeof(struct mxs_nand_info)); + if (!nand_info) { + printf("MXS NAND: Failed to allocate private data\n"); + return -ENOMEM; + } + memset(nand_info, 0, sizeof(struct mxs_nand_info)); + + nand_info->gpmi_regs = (struct mxs_gpmi_regs *)MXS_GPMI_BASE; + nand_info->bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE; + err = mxs_nand_alloc_buffers(nand_info); + if (err) + return err; + + err = mxs_nand_init_dma(nand_info); + if (err) + return err; + + nand_set_controller_data(nand, nand_info); + + nand->options |= NAND_NO_SUBPAGE_WRITE; + + nand->cmd_ctrl = mxs_nand_cmd_ctrl; + nand->dev_ready = mxs_nand_device_ready; + nand->select_chip = mxs_nand_select_chip; + + nand->read_byte = mxs_nand_read_byte; + nand->read_buf = mxs_nand_read_buf; + + nand->ecc.read_page = mxs_nand_ecc_read_page; + + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.bytes = 9; + nand->ecc.size = 512; + nand->ecc.strength = 8; + + return 0; +} + +int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info) +{ + struct mtd_info *mtd; + struct nand_chip *nand; + int err; + + nand = &nand_info->chip; + mtd = nand_to_mtd(nand); + err = mxs_nand_alloc_buffers(nand_info); + if (err) + return err; + + err = mxs_nand_init_dma(nand_info); + if (err) + goto err_free_buffers; + + memset(&fake_ecc_layout, 0, sizeof(fake_ecc_layout)); + +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; +#endif + + nand_set_controller_data(nand, nand_info); + nand->options |= NAND_NO_SUBPAGE_WRITE; + + if (nand_info->dev) + nand->flash_node = dev_of_offset(nand_info->dev); + + nand->cmd_ctrl = mxs_nand_cmd_ctrl; + + nand->dev_ready = mxs_nand_device_ready; + nand->select_chip = mxs_nand_select_chip; + nand->block_bad = mxs_nand_block_bad; + + nand->read_byte = mxs_nand_read_byte; + + nand->read_buf = mxs_nand_read_buf; + nand->write_buf = mxs_nand_write_buf; + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) + goto err_free_buffers; + + if (mxs_nand_setup_ecc(mtd)) + goto err_free_buffers; + + nand->ecc.read_page = mxs_nand_ecc_read_page; + nand->ecc.write_page = mxs_nand_ecc_write_page; + nand->ecc.read_oob = mxs_nand_ecc_read_oob; + nand->ecc.write_oob = mxs_nand_ecc_write_oob; + + nand->ecc.layout = &fake_ecc_layout; + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.size = nand_info->bch_geometry.ecc_chunk_size; + nand->ecc.strength = nand_info->bch_geometry.ecc_strength; + + /* second phase scan */ + err = nand_scan_tail(mtd); + if (err) + goto err_free_buffers; + + err = nand_register(0, mtd); + if (err) + goto err_free_buffers; + + return 0; + +err_free_buffers: + free(nand_info->data_buf); + free(nand_info->cmd_buf); + + return err; +} + +#ifndef CONFIG_NAND_MXS_DT +void board_nand_init(void) +{ + struct mxs_nand_info *nand_info; + + nand_info = malloc(sizeof(struct mxs_nand_info)); + if (!nand_info) { + printf("MXS NAND: Failed to allocate private data\n"); + return; + } + memset(nand_info, 0, sizeof(struct mxs_nand_info)); + + nand_info->gpmi_regs = (struct mxs_gpmi_regs *)MXS_GPMI_BASE; + nand_info->bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE; + + /* Refer to Chapter 17 for i.MX6DQ, Chapter 18 for i.MX6SX */ + if (is_mx6sx() || is_mx7()) + nand_info->max_ecc_strength_supported = 62; + else + nand_info->max_ecc_strength_supported = 40; + +#ifdef CONFIG_NAND_MXS_USE_MINIMUM_ECC + nand_info->use_minimum_ecc = true; +#endif + + if (mxs_nand_init_ctrl(nand_info) < 0) + goto err; + + return; + +err: + free(nand_info); +} +#endif diff --git a/drivers/mtd/nand/raw/mxs_nand.h b/drivers/mtd/nand/raw/mxs_nand.h new file mode 100644 index 0000000000..4bd65cded9 --- /dev/null +++ b/drivers/mtd/nand/raw/mxs_nand.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * NXP GPMI NAND flash driver + * + * Copyright (C) 2018 Toradex + * Authors: + * Stefan Agner + */ + +#include +#include +#include +#include + +/** + * @gf_len: The length of Galois Field. (e.g., 13 or 14) + * @ecc_strength: A number that describes the strength of the ECC + * algorithm. + * @ecc_chunk_size: The size, in bytes, of a single ECC chunk. Note + * the first chunk in the page includes both data and + * metadata, so it's a bit larger than this value. + * @ecc_chunk_count: The number of ECC chunks in the page, + * @block_mark_byte_offset: The byte offset in the ECC-based page view at + * which the underlying physical block mark appears. + * @block_mark_bit_offset: The bit offset into the ECC-based page view at + * which the underlying physical block mark appears. + */ +struct bch_geometry { + unsigned int gf_len; + unsigned int ecc_strength; + unsigned int ecc_chunk_size; + unsigned int ecc_chunk_count; + unsigned int block_mark_byte_offset; + unsigned int block_mark_bit_offset; +}; + +struct mxs_nand_info { + struct nand_chip chip; + struct udevice *dev; + unsigned int max_ecc_strength_supported; + bool use_minimum_ecc; + int cur_chip; + + uint32_t cmd_queue_len; + uint32_t data_buf_size; + struct bch_geometry bch_geometry; + + uint8_t *cmd_buf; + uint8_t *data_buf; + uint8_t *oob_buf; + + uint8_t marking_block_bad; + uint8_t raw_oob_mode; + + struct mxs_gpmi_regs *gpmi_regs; + struct mxs_bch_regs *bch_regs; + + /* Functions with altered behaviour */ + int (*hooked_read_oob)(struct mtd_info *mtd, + loff_t from, struct mtd_oob_ops *ops); + int (*hooked_write_oob)(struct mtd_info *mtd, + loff_t to, struct mtd_oob_ops *ops); + int (*hooked_block_markbad)(struct mtd_info *mtd, + loff_t ofs); + + /* DMA descriptors */ + struct mxs_dma_desc **desc; + uint32_t desc_index; +}; + +int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info); +int mxs_nand_init_spl(struct nand_chip *nand); +int mxs_nand_setup_ecc(struct mtd_info *mtd); diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c new file mode 100644 index 0000000000..44dec5dedf --- /dev/null +++ b/drivers/mtd/nand/raw/mxs_nand_dt.c @@ -0,0 +1,94 @@ +/* + * NXP GPMI NAND flash driver (DT initialization) + * + * Copyright (C) 2018 Toradex + * Authors: + * Stefan Agner + * + * Based on denali_dt.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include "mxs_nand.h" + +struct mxs_nand_dt_data { + unsigned int max_ecc_strength_supported; +}; + +static const struct mxs_nand_dt_data mxs_nand_imx6q_data = { + .max_ecc_strength_supported = 40, +}; + +static const struct mxs_nand_dt_data mxs_nand_imx7d_data = { + .max_ecc_strength_supported = 62, +}; + +static const struct udevice_id mxs_nand_dt_ids[] = { + { + .compatible = "fsl,imx6q-gpmi-nand", + .data = (unsigned long)&mxs_nand_imx6q_data, + }, + { + .compatible = "fsl,imx7d-gpmi-nand", + .data = (unsigned long)&mxs_nand_imx7d_data, + }, + { /* sentinel */ } +}; + +static int mxs_nand_dt_probe(struct udevice *dev) +{ + struct mxs_nand_info *info = dev_get_priv(dev); + const struct mxs_nand_dt_data *data; + struct resource res; + int ret; + + data = (void *)dev_get_driver_data(dev); + if (data) + info->max_ecc_strength_supported = data->max_ecc_strength_supported; + + info->dev = dev; + + ret = dev_read_resource_byname(dev, "gpmi-nand", &res); + if (ret) + return ret; + + info->gpmi_regs = devm_ioremap(dev, res.start, resource_size(&res)); + + + ret = dev_read_resource_byname(dev, "bch", &res); + if (ret) + return ret; + + info->bch_regs = devm_ioremap(dev, res.start, resource_size(&res)); + + info->use_minimum_ecc = dev_read_bool(dev, "fsl,use-minimum-ecc"); + + return mxs_nand_init_ctrl(info); +} + +U_BOOT_DRIVER(mxs_nand_dt) = { + .name = "mxs-nand-dt", + .id = UCLASS_MTD, + .of_match = mxs_nand_dt_ids, + .probe = mxs_nand_dt_probe, + .priv_auto_alloc_size = sizeof(struct mxs_nand_info), +}; + +void board_nand_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MTD, + DM_GET_DRIVER(mxs_nand_dt), + &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize MXS NAND controller. (error %d)\n", + ret); +} diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c new file mode 100644 index 0000000000..2d7bbe83cc --- /dev/null +++ b/drivers/mtd/nand/raw/mxs_nand_spl.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Gateworks Corporation + * Author: Tim Harvey + */ +#include +#include +#include +#include "mxs_nand.h" + +static struct mtd_info *mtd; +static struct nand_chip nand_chip; + +static void mxs_nand_command(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + register struct nand_chip *chip = mtd_to_nand(mtd); + u32 timeo, time_start; + + /* write out the command to the device */ + chip->cmd_ctrl(mtd, command, NAND_CLE); + + /* Serially input address */ + if (column != -1) { + chip->cmd_ctrl(mtd, column, NAND_ALE); + chip->cmd_ctrl(mtd, column >> 8, NAND_ALE); + } + if (page_addr != -1) { + chip->cmd_ctrl(mtd, page_addr, NAND_ALE); + chip->cmd_ctrl(mtd, page_addr >> 8, NAND_ALE); + /* One more address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) + chip->cmd_ctrl(mtd, page_addr >> 16, NAND_ALE); + } + chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); + + if (command == NAND_CMD_READ0) { + chip->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_CLE); + chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); + } + + /* wait for nand ready */ + ndelay(100); + timeo = (CONFIG_SYS_HZ * 20) / 1000; + time_start = get_timer(0); + while (get_timer(time_start) < timeo) { + if (chip->dev_ready(mtd)) + break; + } +} + +#if defined (CONFIG_SPL_NAND_IDENT) + +/* Trying to detect the NAND flash using ONFi, JEDEC, and (extended) IDs */ +static int mxs_flash_full_ident(struct mtd_info *mtd) +{ + int nand_maf_id, nand_dev_id; + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_flash_dev *type; + + type = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, NULL); + + if (IS_ERR(type)) { + chip->select_chip(mtd, -1); + return PTR_ERR(type); + } + + return 0; +} + +#else + +/* Trying to detect the NAND flash using ONFi only */ +static int mxs_flash_onfi_ident(struct mtd_info *mtd) +{ + register struct nand_chip *chip = mtd_to_nand(mtd); + int i; + u8 mfg_id, dev_id; + u8 id_data[8]; + struct nand_onfi_params *p = &chip->onfi_params; + + /* Reset the chip */ + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + + /* Send the command for reading device ID */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + mfg_id = chip->read_byte(mtd); + dev_id = chip->read_byte(mtd); + + /* Try again to make sure */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + for (i = 0; i < 8; i++) + id_data[i] = chip->read_byte(mtd); + if (id_data[0] != mfg_id || id_data[1] != dev_id) { + printf("second ID read did not match"); + return -1; + } + debug("0x%02x:0x%02x ", mfg_id, dev_id); + + /* read ONFI */ + chip->onfi_version = 0; + chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); + if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || + chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') { + return -2; + } + + /* we have ONFI, probe it */ + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); + chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); + mtd->name = p->model; + mtd->writesize = le32_to_cpu(p->byte_per_page); + mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; + mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); + chip->chipsize = le32_to_cpu(p->blocks_per_lun); + chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; + /* Calculate the address shift from the page size */ + chip->page_shift = ffs(mtd->writesize) - 1; + chip->phys_erase_shift = ffs(mtd->erasesize) - 1; + /* Convert chipsize to number of pages per chip -1 */ + chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + chip->badblockbits = 8; + + debug("erasesize=%d (>>%d)\n", mtd->erasesize, chip->phys_erase_shift); + debug("writesize=%d (>>%d)\n", mtd->writesize, chip->page_shift); + debug("oobsize=%d\n", mtd->oobsize); + debug("chipsize=%lld\n", chip->chipsize); + + return 0; +} + +#endif /* CONFIG_SPL_NAND_IDENT */ + +static int mxs_flash_ident(struct mtd_info *mtd) +{ + int ret; +#if defined (CONFIG_SPL_NAND_IDENT) + ret = mxs_flash_full_ident(mtd); +#else + ret = mxs_flash_onfi_ident(mtd); +#endif + return ret; +} + +static int mxs_read_page_ecc(struct mtd_info *mtd, void *buf, unsigned int page) +{ + register struct nand_chip *chip = mtd_to_nand(mtd); + int ret; + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); + ret = nand_chip.ecc.read_page(mtd, chip, buf, 1, page); + if (ret < 0) { + printf("read_page failed %d\n", ret); + return -1; + } + return 0; +} + +static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt) +{ + register struct nand_chip *chip = mtd_to_nand(mtd); + unsigned int block = offs >> chip->phys_erase_shift; + unsigned int page = offs >> chip->page_shift; + + debug("%s offs=0x%08x block:%d page:%d\n", __func__, (int)offs, block, + page); + chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + memset(chip->oob_poi, 0, mtd->oobsize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + return chip->oob_poi[0] != 0xff; +} + +/* setup mtd and nand structs and init mxs_nand driver */ +static int mxs_nand_init(void) +{ + /* return if already initalized */ + if (nand_chip.numchips) + return 0; + + /* init mxs nand driver */ + mxs_nand_init_spl(&nand_chip); + mtd = nand_to_mtd(&nand_chip); + /* set mtd functions */ + nand_chip.cmdfunc = mxs_nand_command; + nand_chip.numchips = 1; + + /* identify flash device */ + if (mxs_flash_ident(mtd)) { + printf("Failed to identify\n"); + return -1; + } + + /* allocate and initialize buffers */ + nand_chip.buffers = memalign(ARCH_DMA_MINALIGN, + sizeof(*nand_chip.buffers)); + nand_chip.oob_poi = nand_chip.buffers->databuf + mtd->writesize; + /* setup flash layout (does not scan as we override that) */ + mtd->size = nand_chip.chipsize; + nand_chip.scan_bbt(mtd); + + return 0; +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) +{ + struct nand_chip *chip; + unsigned int page; + unsigned int nand_page_per_block; + unsigned int sz = 0; + + if (mxs_nand_init()) + return -ENODEV; + chip = mtd_to_nand(mtd); + page = offs >> chip->page_shift; + nand_page_per_block = mtd->erasesize / mtd->writesize; + + debug("%s offset:0x%08x len:%d page:%d\n", __func__, offs, size, page); + + size = roundup(size, mtd->writesize); + while (sz < size) { + if (mxs_read_page_ecc(mtd, buf, page) < 0) + return -1; + sz += mtd->writesize; + offs += mtd->writesize; + page++; + buf += mtd->writesize; + + /* + * Check if we have crossed a block boundary, and if so + * check for bad block. + */ + if (!(page % nand_page_per_block)) { + /* + * Yes, new block. See if this block is good. If not, + * loop until we find a good block. + */ + while (is_badblock(mtd, offs, 1)) { + page = page + nand_page_per_block; + /* Check i we've reached the end of flash. */ + if (page >= mtd->size >> chip->page_shift) + return -ENOMEM; + } + } + } + + return 0; +} + +int nand_default_bbt(struct mtd_info *mtd) +{ + return 0; +} + +void nand_init(void) +{ +} + +void nand_deselect(void) +{ +} + diff --git a/drivers/mtd/nand/raw/nand.c b/drivers/mtd/nand/raw/nand.c new file mode 100644 index 0000000000..bca51ffbf2 --- /dev/null +++ b/drivers/mtd/nand/raw/nand.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2005 + * 2N Telekomunikace, a.s. + * Ladislav Michl + */ + +#include +#include +#include +#include + +#ifndef CONFIG_SYS_NAND_BASE_LIST +#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } +#endif + +int nand_curr_device = -1; + +static struct mtd_info *nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; + +#ifndef CONFIG_SYS_NAND_SELF_INIT +static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; +static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST; +#endif + +static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; + +static unsigned long total_nand_size; /* in kiB */ + +struct mtd_info *get_nand_dev_by_index(int dev) +{ + if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev] || + !nand_info[dev]->name) + return NULL; + + return nand_info[dev]; +} + +int nand_mtd_to_devnum(struct mtd_info *mtd) +{ + int i; + + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { + if (mtd && get_nand_dev_by_index(i) == mtd) + return i; + } + + return -ENODEV; +} + +/* Register an initialized NAND mtd device with the U-Boot NAND command. */ +int nand_register(int devnum, struct mtd_info *mtd) +{ + if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE) + return -EINVAL; + + nand_info[devnum] = mtd; + + sprintf(dev_name[devnum], "nand%d", devnum); + mtd->name = dev_name[devnum]; + +#ifdef CONFIG_MTD_DEVICE + /* + * Add MTD device so that we can reference it later + * via the mtdcore infrastructure (e.g. ubi). + */ + add_mtd_device(mtd); +#endif + + total_nand_size += mtd->size / 1024; + + if (nand_curr_device == -1) + nand_curr_device = devnum; + + return 0; +} + +#ifndef CONFIG_SYS_NAND_SELF_INIT +static void nand_init_chip(int i) +{ + struct nand_chip *nand = &nand_chip[i]; + struct mtd_info *mtd = nand_to_mtd(nand); + ulong base_addr = base_address[i]; + int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; + + if (maxchips < 1) + maxchips = 1; + + nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; + + if (board_nand_init(nand)) + return; + + if (nand_scan(mtd, maxchips)) + return; + + nand_register(i, mtd); +} +#endif + +#ifdef CONFIG_MTD_CONCAT +static void create_mtd_concat(void) +{ + struct mtd_info *nand_info_list[CONFIG_SYS_MAX_NAND_DEVICE]; + int nand_devices_found = 0; + int i; + + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { + struct mtd_info *mtd = get_nand_dev_by_index(i); + if (mtd != NULL) { + nand_info_list[nand_devices_found] = mtd; + nand_devices_found++; + } + } + if (nand_devices_found > 1) { + struct mtd_info *mtd; + char c_mtd_name[16]; + + /* + * We detected multiple devices. Concatenate them together. + */ + sprintf(c_mtd_name, "nand%d", nand_devices_found); + mtd = mtd_concat_create(nand_info_list, nand_devices_found, + c_mtd_name); + + if (mtd == NULL) + return; + + nand_register(nand_devices_found, mtd); + } + + return; +} +#else +static void create_mtd_concat(void) +{ +} +#endif + +unsigned long nand_size(void) +{ + return total_nand_size; +} + +void nand_init(void) +{ + static int initialized; + + /* + * Avoid initializing NAND Flash multiple times, + * otherwise it will calculate a wrong total size. + */ + if (initialized) + return; + initialized = 1; + +#ifdef CONFIG_SYS_NAND_SELF_INIT + board_nand_init(); +#else + int i; + + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) + nand_init_chip(i); +#endif + +#ifdef CONFIG_SYS_NAND_SELECT_DEVICE + /* + * Select the chip in the board/cpu specific driver + */ + board_nand_select_device(mtd_to_nand(get_nand_dev_by_index(nand_curr_device)), + nand_curr_device); +#endif + + create_mtd_concat(); +} diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c new file mode 100644 index 0000000000..92daebe120 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_base.c @@ -0,0 +1,4619 @@ +/* + * Overview: + * This is the generic MTD driver for NAND flash devices. It should be + * capable of working with almost all NAND chips currently available. + * + * Additional technical information is available on + * http://www.linux-mtd.infradead.org/doc/nand.html + * + * 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 + * + * TODO: + * Enable cached programming for 2k page size chips + * Check, if mtd->ecctype should be set to MTD_ECC_HW + * if we have HW ECC support. + * BBT table is not serialized, has to be fixed + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#if CONFIG_IS_ENABLED(OF_CONTROL) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MTD_PARTITIONS +#include +#endif +#include +#include + +/* Define default oob placement schemes for large and small page devices */ +static struct nand_ecclayout nand_oob_8 = { + .eccbytes = 3, + .eccpos = {0, 1, 2}, + .oobfree = { + {.offset = 3, + .length = 2}, + {.offset = 6, + .length = 2} } +}; + +static struct nand_ecclayout nand_oob_16 = { + .eccbytes = 6, + .eccpos = {0, 1, 2, 3, 6, 7}, + .oobfree = { + {.offset = 8, + . length = 8} } +}; + +static struct nand_ecclayout nand_oob_64 = { + .eccbytes = 24, + .eccpos = { + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { + {.offset = 2, + .length = 38} } +}; + +static struct nand_ecclayout nand_oob_128 = { + .eccbytes = 48, + .eccpos = { + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}, + .oobfree = { + {.offset = 2, + .length = 78} } +}; + +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, + struct mtd_oob_ops *ops); + +/* + * For devices which display every fart in the system on a separate LED. Is + * compiled away when LED support is disabled. + */ +DEFINE_LED_TRIGGER(nand_led_trigger); + +static int check_offs_len(struct mtd_info *mtd, + loff_t ofs, uint64_t len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int ret = 0; + + /* Start address must align on block boundary */ + if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) { + pr_debug("%s: unaligned address\n", __func__); + ret = -EINVAL; + } + + /* Length must align on block boundary */ + if (len & ((1ULL << chip->phys_erase_shift) - 1)) { + pr_debug("%s: length not block aligned\n", __func__); + ret = -EINVAL; + } + + return ret; +} + +/** + * nand_release_device - [GENERIC] release chip + * @mtd: MTD device structure + * + * Release chip lock and wake up anyone waiting on the device. + */ +static void nand_release_device(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + /* De-select the NAND device */ + chip->select_chip(mtd, -1); +} + +/** + * nand_read_byte - [DEFAULT] read one byte from the chip + * @mtd: MTD device structure + * + * Default read function for 8bit buswidth + */ +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_onfi_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); +} + +static void iowrite8_rep(void *addr, const uint8_t *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + writeb(buf[i], addr); +} +static void ioread8_rep(void *addr, uint8_t *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + buf[i] = readb(addr); +} + +static void ioread16_rep(void *addr, void *buf, int len) +{ + int i; + u16 *p = (u16 *) buf; + + for (i = 0; i < len; i++) + p[i] = readw(addr); +} + +static void iowrite16_rep(void *addr, void *buf, int len) +{ + int i; + u16 *p = (u16 *) buf; + + for (i = 0; i < len; i++) + writew(p[i], addr); +} + +/** + * 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. + */ +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. + */ +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. + */ +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. + */ +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 + * @ofs: offset from device start + * + * Check, if the block is bad. + */ +static int nand_block_bad(struct mtd_info *mtd, loff_t ofs) +{ + int page, res = 0, i = 0; + struct nand_chip *chip = mtd_to_nand(mtd); + u16 bad; + + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) + ofs += mtd->erasesize - mtd->writesize; + + page = (int)(ofs >> chip->page_shift) & chip->pagemask; + + do { + if (chip->options & NAND_BUSWIDTH_16) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, + chip->badblockpos & 0xFE, page); + bad = cpu_to_le16(chip->read_word(mtd)); + if (chip->badblockpos & 0x1) + bad >>= 8; + else + bad &= 0xFF; + } else { + chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, + page); + bad = chip->read_byte(mtd); + } + + if (likely(chip->badblockbits == 8)) + res = bad != 0xFF; + else + res = hweight8(bad) < chip->badblockbits; + ofs += mtd->writesize; + page = (int)(ofs >> chip->page_shift) & chip->pagemask; + i++; + } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); + + return res; +} + +/** + * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker + * @mtd: MTD device structure + * @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) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_oob_ops ops; + uint8_t buf[2] = { 0, 0 }; + int ret = 0, res, i = 0; + + memset(&ops, 0, sizeof(ops)); + ops.oobbuf = buf; + ops.ooboffs = chip->badblockpos; + if (chip->options & NAND_BUSWIDTH_16) { + ops.ooboffs &= ~0x01; + ops.len = ops.ooblen = 2; + } else { + ops.len = ops.ooblen = 1; + } + ops.mode = MTD_OPS_PLACE_OOB; + + /* Write to first/last page(s) if necessary */ + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) + ofs += mtd->erasesize - mtd->writesize; + do { + res = nand_do_write_oob(mtd, ofs, &ops); + if (!ret) + ret = res; + + i++; + ofs += mtd->writesize; + } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); + + return ret; +} + +/** + * nand_block_markbad_lowlevel - mark a block bad + * @mtd: MTD device structure + * @ofs: offset from device start + * + * This function performs the generic NAND bad block marking steps (i.e., bad + * block table(s) and/or marker(s)). We only allow the hardware driver to + * specify how to write bad block markers to OOB (chip->block_markbad). + * + * We try operations in the following order: + * (1) erase the affected block, to allow OOB marker to be written cleanly + * (2) write bad block marker to OOB area of affected block (unless flag + * NAND_BBT_NO_OOB_BBM is present) + * (3) update the BBT + * Note that we retain the first error encountered in (2) or (3), finish the + * procedures, and dump the error in the end. +*/ +static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int res, ret = 0; + + if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) { + struct erase_info einfo; + + /* Attempt erase before marking OOB */ + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = ofs; + einfo.len = 1ULL << chip->phys_erase_shift; + nand_erase_nand(mtd, &einfo, 0); + + /* Write bad block marker to OOB */ + nand_get_device(mtd, FL_WRITING); + ret = chip->block_markbad(mtd, ofs); + nand_release_device(mtd); + } + + /* Mark block bad in BBT */ + if (chip->bbt) { + res = nand_markbad_bbt(mtd, ofs); + if (!ret) + ret = res; + } + + if (!ret) + mtd->ecc_stats.badblocks++; + + return ret; +} + +/** + * nand_check_wp - [GENERIC] check if the chip is write protected + * @mtd: MTD device structure + * + * Check, if the device is write protected. The function expects, that the + * device is already selected. + */ +static int nand_check_wp(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + /* Broken xD cards report WP despite being writable */ + if (chip->options & NAND_BROKEN_XD) + return 0; + + /* Check the WP bit */ + chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; +} + +/** + * nand_block_isreserved - [GENERIC] Check if a block is marked reserved. + * @mtd: MTD device structure + * @ofs: offset from device start + * + * Check if the block is marked as reserved. + */ +static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + if (!chip->bbt) + return 0; + /* Return info from the table */ + return nand_isreserved_bbt(mtd, ofs); +} + +/** + * nand_block_checkbad - [GENERIC] Check if a block is marked bad + * @mtd: MTD device structure + * @ofs: offset from device start + * @allowbbt: 1, if its allowed to access the bbt area + * + * Check, if the block is bad. Either by reading the bad block table or + * calling of the scan function. + */ +static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + if (!(chip->options & NAND_SKIP_BBTSCAN) && + !(chip->options & NAND_BBT_SCANNED)) { + chip->options |= NAND_BBT_SCANNED; + chip->scan_bbt(mtd); + } + + if (!chip->bbt) + return chip->block_bad(mtd, ofs); + + /* Return info from the table */ + return nand_isbad_bbt(mtd, ofs, allowbbt); +} + +/** + * 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); + u32 timeo = (CONFIG_SYS_HZ * 400) / 1000; + u32 time_start; + + time_start = get_timer(0); + /* Wait until command is processed or timeout occurs */ + while (get_timer(time_start) < timeo) { + if (chip->dev_ready) + if (chip->dev_ready(mtd)) + break; + } + + if (!chip->dev_ready(mtd)) + pr_warn("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); + u32 time_start; + + timeo = (CONFIG_SYS_HZ * timeo) / 1000; + time_start = get_timer(0); + while (get_timer(time_start) < timeo) { + if ((chip->read_byte(mtd) & NAND_STATUS_READY)) + break; + WATCHDOG_RESET(); + } +}; + +/** + * 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; + } + 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_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 */ + 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); +} + +/** + * 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 */ + 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; + 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_CACHEDPROG: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_RNDIN: + 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_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); + return; + + case NAND_CMD_READ0: + 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 + * @mtd: MTD device structure + * @new_state: the state which is requested + * + * Used when in panic, no locks are taken. + */ +static void panic_nand_get_device(struct nand_chip *chip, + struct mtd_info *mtd, int new_state) +{ + /* Hardware controller shared among independent devices */ + chip->controller->active = chip; + chip->state = new_state; +} + +/** + * nand_get_device - [GENERIC] Get chip for selected access + * @mtd: MTD device structure + * @new_state: the state which is requested + * + * Get the device and lock it for exclusive access + */ +static int +nand_get_device(struct mtd_info *mtd, int new_state) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + chip->state = new_state; + return 0; +} + +/** + * panic_nand_wait - [GENERIC] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure + * @timeo: timeout + * + * Wait for command done. This is a helper function for nand_wait used when + * 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) +{ + int i; + for (i = 0; i < timeo; i++) { + if (chip->dev_ready) { + if (chip->dev_ready(mtd)) + break; + } else { + if (chip->read_byte(mtd) & NAND_STATUS_READY) + break; + } + mdelay(1); + } +} + +/** + * 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) +{ + int status; + unsigned long timeo = 400; + + led_trigger_event(nand_led_trigger, LED_FULL); + + /* + * Apply this short delay always to ensure that we do wait tWB in any + * case on any machine. + */ + ndelay(100); + + chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + + u32 timer = (CONFIG_SYS_HZ * timeo) / 1000; + u32 time_start; + + time_start = get_timer(0); + while (get_timer(time_start) < timer) { + if (chip->dev_ready) { + if (chip->dev_ready(mtd)) + break; + } else { + if (chip->read_byte(mtd) & NAND_STATUS_READY) + break; + } + } + led_trigger_event(nand_led_trigger, LED_OFF); + + status = (int)chip->read_byte(mtd); + /* This can happen if in case of timeout or buggy dev_ready */ + WARN_ON(!(status & NAND_STATUS_READY)); + return status; +} + +/** + * nand_reset_data_interface - Reset data interface and timings + * @chip: The NAND chip + * @chipnr: Internal die id + * + * Reset the Data interface and timings to ONFI mode 0. + * + * Returns 0 for success or negative error code otherwise. + */ +static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_data_interface *conf; + int ret; + + if (!chip->setup_data_interface) + return 0; + + /* + * The ONFI specification says: + * " + * To transition from NV-DDR or NV-DDR2 to the SDR data + * interface, the host shall use the Reset (FFh) command + * using SDR timing mode 0. A device in any timing mode is + * required to recognize Reset (FFh) command issued in SDR + * timing mode 0. + * " + * + * Configure the data interface in SDR mode and set the + * timings to timing mode 0. + */ + + conf = nand_get_default_data_interface(); + ret = chip->setup_data_interface(mtd, chipnr, conf); + if (ret) + pr_err("Failed to configure data interface to SDR timing mode 0\n"); + + return ret; +} + +/** + * nand_setup_data_interface - Setup the best data interface and timings + * @chip: The NAND chip + * @chipnr: Internal die id + * + * Find and configure the best data interface and NAND timings supported by + * the chip and the driver. + * First tries to retrieve supported timing modes from ONFI information, + * and if the NAND chip does not support ONFI, relies on the + * ->onfi_timing_mode_default specified in the nand_ids table. + * + * Returns 0 for success or negative error code otherwise. + */ +static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + if (!chip->setup_data_interface || !chip->data_interface) + return 0; + + /* + * Ensure the timing mode has been changed on the chip side + * before changing timings on the controller side. + */ + if (chip->onfi_version) { + u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { + chip->onfi_timing_mode_default, + }; + + ret = chip->onfi_set_features(mtd, chip, + ONFI_FEATURE_ADDR_TIMING_MODE, + tmode_param); + if (ret) + goto err; + } + + ret = chip->setup_data_interface(mtd, chipnr, chip->data_interface); +err: + return ret; +} + +/** + * nand_init_data_interface - find the best data interface and timings + * @chip: The NAND chip + * + * Find the best data interface and NAND timings supported by the chip + * and the driver. + * First tries to retrieve supported timing modes from ONFI information, + * and if the NAND chip does not support ONFI, relies on the + * ->onfi_timing_mode_default specified in the nand_ids table. After this + * function nand_chip->data_interface is initialized with the best timing mode + * available. + * + * Returns 0 for success or negative error code otherwise. + */ +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) + return 0; + + /* + * First try to identify the best timings from ONFI parameters and + * 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->onfi_timing_mode_default) + return 0; + + modes = GENMASK(chip->onfi_timing_mode_default, 0); + } + + chip->data_interface = kzalloc(sizeof(*chip->data_interface), + GFP_KERNEL); + if (!chip->data_interface) + return -ENOMEM; + + for (mode = fls(modes) - 1; mode >= 0; mode--) { + ret = onfi_init_data_interface(chip, chip->data_interface, + NAND_SDR_IFACE, mode); + if (ret) + continue; + + /* Pass -1 to only */ + ret = chip->setup_data_interface(mtd, + NAND_DATA_IFACE_CHECK_ONLY, + chip->data_interface); + if (!ret) { + chip->onfi_timing_mode_default = mode; + break; + } + } + + return 0; +} + +static void __maybe_unused nand_release_data_interface(struct nand_chip *chip) +{ + kfree(chip->data_interface); +} + +/** + * nand_reset - Reset and initialize a NAND device + * @chip: The NAND chip + * @chipnr: Internal die id + * + * Returns 0 for success or negative error code otherwise + */ +int nand_reset(struct nand_chip *chip, int chipnr) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + ret = nand_reset_data_interface(chip, chipnr); + if (ret) + return ret; + + /* + * 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->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + chip->select_chip(mtd, -1); + + chip->select_chip(mtd, chipnr); + ret = nand_setup_data_interface(chip, chipnr); + chip->select_chip(mtd, -1); + if (ret) + return ret; + + return 0; +} + +/** + * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data + * @buf: buffer to test + * @len: buffer length + * @bitflips_threshold: maximum number of bitflips + * + * Check if a buffer contains only 0xff, which means the underlying region + * has been erased and is ready to be programmed. + * The bitflips_threshold specify the maximum number of bitflips before + * considering the region is not erased. + * Note: The logic of this function has been extracted from the memweight + * implementation, except that nand_check_erased_buf function exit before + * testing the whole buffer if the number of bitflips exceed the + * bitflips_threshold value. + * + * Returns a positive number of bitflips less than or equal to + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the + * threshold. + */ +static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) +{ + const unsigned char *bitmap = buf; + int bitflips = 0; + int weight; + + for (; len && ((uintptr_t)bitmap) % sizeof(long); + len--, bitmap++) { + weight = hweight8(*bitmap); + bitflips += BITS_PER_BYTE - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + for (; len >= 4; len -= 4, bitmap += 4) { + weight = hweight32(*((u32 *)bitmap)); + bitflips += 32 - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + for (; len > 0; len--, bitmap++) { + weight = hweight8(*bitmap); + bitflips += BITS_PER_BYTE - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + return bitflips; +} + +/** + * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only + * 0xff data + * @data: data buffer to test + * @datalen: data length + * @ecc: ECC buffer + * @ecclen: ECC length + * @extraoob: extra OOB buffer + * @extraooblen: extra OOB length + * @bitflips_threshold: maximum number of bitflips + * + * Check if a data buffer and its associated ECC and OOB data contains only + * 0xff pattern, which means the underlying region has been erased and is + * ready to be programmed. + * The bitflips_threshold specify the maximum number of bitflips before + * considering the region as not erased. + * + * Note: + * 1/ ECC algorithms are working on pre-defined block sizes which are usually + * different from the NAND page size. When fixing bitflips, ECC engines will + * report the number of errors per chunk, and the NAND core infrastructure + * expect you to return the maximum number of bitflips for the whole page. + * This is why you should always use this function on a single chunk and + * not on the whole page. After checking each chunk you should update your + * max_bitflips value accordingly. + * 2/ When checking for bitflips in erased pages you should not only check + * the payload data but also their associated ECC data, because a user might + * have programmed almost all bits to 1 but a few. In this case, we + * shouldn't consider the chunk as erased, and checking ECC bytes prevent + * this case. + * 3/ The extraoob argument is optional, and should be used if some of your OOB + * data are protected by the ECC engine. + * It could also be used if you support subpages and want to attach some + * extra OOB data to an ECC chunk. + * + * Returns a positive number of bitflips less than or equal to + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the + * threshold. In case of success, the passed buffers are filled with 0xff. + */ +int nand_check_erased_ecc_chunk(void *data, int datalen, + void *ecc, int ecclen, + void *extraoob, int extraooblen, + int bitflips_threshold) +{ + int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0; + + data_bitflips = nand_check_erased_buf(data, datalen, + bitflips_threshold); + if (data_bitflips < 0) + return data_bitflips; + + bitflips_threshold -= data_bitflips; + + ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold); + if (ecc_bitflips < 0) + return ecc_bitflips; + + bitflips_threshold -= ecc_bitflips; + + extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen, + bitflips_threshold); + if (extraoob_bitflips < 0) + return extraoob_bitflips; + + if (data_bitflips) + memset(data, 0xff, datalen); + + if (ecc_bitflips) + memset(ecc, 0xff, ecclen); + + if (extraoob_bitflips) + memset(extraoob, 0xff, extraooblen); + + return data_bitflips + ecc_bitflips + extraoob_bitflips; +} +EXPORT_SYMBOL(nand_check_erased_ecc_chunk); + +/** + * 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 + * @page: page number to read + * + * Not for syndrome calculating ECC controllers, which use a special oob layout. + */ +static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + chip->read_buf(mtd, buf, mtd->writesize); + if (oob_required) + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return 0; +} + +/** + * 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 + * @page: page number to read + * + * 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, + int oob_required, int page) +{ + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + uint8_t *oob = chip->oob_poi; + int steps, size; + + for (steps = chip->ecc.steps; steps > 0; steps--) { + chip->read_buf(mtd, buf, eccsize); + buf += eccsize; + + if (chip->ecc.prepad) { + chip->read_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->read_buf(mtd, oob, eccbytes); + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->read_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + size = mtd->oobsize - (oob - chip->oob_poi); + if (size) + chip->read_buf(mtd, oob, size); + + return 0; +} + +/** + * 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) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + unsigned int max_bitflips = 0; + + chip->ecc.read_page_raw(mtd, chip, buf, 1, page); + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + eccsteps = chip->ecc.steps; + p = buf; + + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } + } + return max_bitflips; +} + +/** + * 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) +{ + int start_step, end_step, num_steps; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *p; + int data_col_addr, i, gaps = 0; + int datafrag_len, eccfrag_len, aligned_len, aligned_pos; + int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; + int index; + unsigned int max_bitflips = 0; + + /* Column address within the page aligned to ECC size (256bytes) */ + start_step = data_offs / chip->ecc.size; + end_step = (data_offs + readlen - 1) / chip->ecc.size; + num_steps = end_step - start_step + 1; + index = start_step * chip->ecc.bytes; + + /* Data size aligned to ECC ecc.size */ + datafrag_len = num_steps * chip->ecc.size; + eccfrag_len = num_steps * chip->ecc.bytes; + + data_col_addr = start_step * chip->ecc.size; + /* If we read not a page aligned data */ + if (data_col_addr != 0) + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); + + p = bufpoi + data_col_addr; + chip->read_buf(mtd, p, datafrag_len); + + /* Calculate ECC */ + for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) + chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); + + /* + * The performance is faster if we position offsets according to + * ecc.pos. Let's make sure that there are no gaps in ECC positions. + */ + for (i = 0; i < eccfrag_len - 1; i++) { + if (eccpos[i + index] + 1 != eccpos[i + index + 1]) { + gaps = 1; + break; + } + } + if (gaps) { + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + } else { + /* + * Send the command to read the particular ECC bytes take care + * about buswidth alignment in read_buf. + */ + aligned_pos = eccpos[index] & ~(busw - 1); + aligned_len = eccfrag_len; + if (eccpos[index] & (busw - 1)) + aligned_len++; + if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1)) + aligned_len++; + + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, + mtd->writesize + aligned_pos, -1); + chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); + } + + for (i = 0; i < eccfrag_len; i++) + chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]]; + + p = bufpoi + data_col_addr; + for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { + int stat; + + stat = chip->ecc.correct(mtd, p, + &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, chip->ecc.size, + &chip->buffers->ecccode[i], + chip->ecc.bytes, + NULL, 0, + chip->ecc.strength); + } + + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } + } + return max_bitflips; +} + +/** + * 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 + * @page: page number to read + * + * 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) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + unsigned int max_bitflips = 0; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, p, eccsize); + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + } + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + eccsteps = chip->ecc.steps; + p = buf; + + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, eccsize, + &ecc_code[i], eccbytes, + NULL, 0, + chip->ecc.strength); + } + + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } + } + return max_bitflips; +} + +/** + * 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 + * @page: page number to read + * + * Hardware ECC for large page chips, require OOB to be read first. For this + * ECC mode, the write_page method is re-used from ECC_HW. These methods + * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with + * 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) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *ecc_calc = chip->buffers->ecccalc; + unsigned int max_bitflips = 0; + + /* Read the OOB area first */ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, p, eccsize); + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, eccsize, + &ecc_code[i], eccbytes, + NULL, 0, + chip->ecc.strength); + } + + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } + } + return max_bitflips; +} + +/** + * 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 + * @page: page number to read + * + * 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) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad; + uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + unsigned int max_bitflips = 0; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, p, eccsize); + + if (chip->ecc.prepad) { + chip->read_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->ecc.hwctl(mtd, NAND_ECC_READSYN); + chip->read_buf(mtd, oob, eccbytes); + stat = chip->ecc.correct(mtd, p, oob, NULL); + + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->read_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, chip->ecc.size, + oob - eccpadbytes, + eccpadbytes, + NULL, 0, + chip->ecc.strength); + } + + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } + } + + /* Calculate remaining oob bytes */ + i = mtd->oobsize - (oob - chip->oob_poi); + if (i) + chip->read_buf(mtd, oob, i); + + return max_bitflips; +} + +/** + * nand_transfer_oob - [INTERN] Transfer oob to client buffer + * @chip: nand chip structure + * @oob: oob destination address + * @ops: oob ops structure + * @len: size of oob to transfer + */ +static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, + struct mtd_oob_ops *ops, size_t len) +{ + switch (ops->mode) { + + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: + memcpy(oob, chip->oob_poi + ops->ooboffs, len); + return oob + len; + + case MTD_OPS_AUTO_OOB: { + struct nand_oobfree *free = chip->ecc.layout->oobfree; + uint32_t boffs = 0, roffs = ops->ooboffs; + size_t bytes = 0; + + for (; free->length && len; free++, len -= bytes) { + /* Read request not from offset 0? */ + if (unlikely(roffs)) { + if (roffs >= free->length) { + roffs -= free->length; + continue; + } + boffs = free->offset + roffs; + bytes = min_t(size_t, len, + (free->length - roffs)); + roffs = 0; + } else { + bytes = min_t(size_t, len, free->length); + boffs = free->offset; + } + memcpy(oob, chip->oob_poi + boffs, bytes); + oob += bytes; + } + return oob; + } + default: + BUG(); + } + return NULL; +} + +/** + * nand_setup_read_retry - [INTERN] Set the READ RETRY mode + * @mtd: MTD device structure + * @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) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + pr_debug("setting READ RETRY mode %d\n", retry_mode); + + if (retry_mode >= chip->read_retries) + return -EINVAL; + + if (!chip->setup_read_retry) + return -EOPNOTSUPP; + + return chip->setup_read_retry(mtd, retry_mode); +} + +/** + * nand_do_read_ops - [INTERN] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob ops structure + * + * Internal function. Called with chip held. + */ +static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + int chipnr, page, realpage, col, bytes, aligned, oob_required; + struct nand_chip *chip = mtd_to_nand(mtd); + int ret = 0; + uint32_t readlen = ops->len; + uint32_t oobreadlen = ops->ooblen; + uint32_t max_oobsize = mtd_oobavail(mtd, ops); + + uint8_t *bufpoi, *oob, *buf; + int use_bufpoi; + unsigned int max_bitflips = 0; + int retry_mode = 0; + bool ecc_fail = false; + + chipnr = (int)(from >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + realpage = (int)(from >> chip->page_shift); + page = realpage & chip->pagemask; + + col = (int)(from & (mtd->writesize - 1)); + + buf = ops->datbuf; + oob = ops->oobbuf; + oob_required = oob ? 1 : 0; + + while (1) { + unsigned int ecc_failures = mtd->ecc_stats.failed; + + WATCHDOG_RESET(); + bytes = min(mtd->writesize - col, readlen); + aligned = (bytes == mtd->writesize); + + if (!aligned) + use_bufpoi = 1; + else if (chip->options & NAND_USE_BOUNCE_BUFFER) + use_bufpoi = !IS_ALIGNED((unsigned long)buf, + chip->buf_align); + else + use_bufpoi = 0; + + /* Is the current page in the buffer? */ + if (realpage != chip->pagebuf || oob) { + bufpoi = use_bufpoi ? chip->buffers->databuf : buf; + + if (use_bufpoi && aligned) + pr_debug("%s: using read bounce buffer for buf@%p\n", + __func__, buf); + +read_retry: + if (nand_standard_page_accessors(&chip->ecc)) + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + + /* + * Now read the page into the buffer. Absent an error, + * 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, + oob_required, + page); + else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && + !oob) + ret = chip->ecc.read_subpage(mtd, chip, + col, bytes, bufpoi, + page); + else + ret = chip->ecc.read_page(mtd, chip, bufpoi, + oob_required, page); + if (ret < 0) { + if (use_bufpoi) + /* Invalidate page cache */ + chip->pagebuf = -1; + break; + } + + max_bitflips = max_t(unsigned int, max_bitflips, ret); + + /* Transfer not aligned data */ + if (use_bufpoi) { + if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && + !(mtd->ecc_stats.failed - ecc_failures) && + (ops->mode != MTD_OPS_RAW)) { + chip->pagebuf = realpage; + chip->pagebuf_bitflips = ret; + } else { + /* Invalidate page cache */ + chip->pagebuf = -1; + } + memcpy(buf, chip->buffers->databuf + col, bytes); + } + + if (unlikely(oob)) { + int toread = min(oobreadlen, max_oobsize); + + if (toread) { + oob = nand_transfer_oob(chip, + oob, ops, toread); + oobreadlen -= toread; + } + } + + 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); + } + + if (mtd->ecc_stats.failed - ecc_failures) { + if (retry_mode + 1 < chip->read_retries) { + retry_mode++; + ret = nand_setup_read_retry(mtd, + retry_mode); + if (ret < 0) + break; + + /* Reset failures; retry */ + mtd->ecc_stats.failed = ecc_failures; + goto read_retry; + } else { + /* No more retry modes; real failure */ + ecc_fail = true; + } + } + + buf += bytes; + } else { + memcpy(buf, chip->buffers->databuf + col, bytes); + buf += bytes; + max_bitflips = max_t(unsigned int, max_bitflips, + chip->pagebuf_bitflips); + } + + readlen -= bytes; + + /* Reset to retry mode 0 */ + if (retry_mode) { + ret = nand_setup_read_retry(mtd, 0); + if (ret < 0) + break; + retry_mode = 0; + } + + if (!readlen) + break; + + /* For subsequent reads align to page boundary */ + col = 0; + /* Increment page address */ + realpage++; + + page = realpage & chip->pagemask; + /* Check, if we cross a chip boundary */ + if (!page) { + chipnr++; + chip->select_chip(mtd, -1); + chip->select_chip(mtd, chipnr); + } + } + chip->select_chip(mtd, -1); + + ops->retlen = ops->len - (size_t) readlen; + if (oob) + ops->oobretlen = ops->ooblen - oobreadlen; + + if (ret < 0) + return ret; + + if (ecc_fail) + return -EBADMSG; + + return max_bitflips; +} + +/** + * 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 + */ +static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return 0; +} + +/** + * 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 + */ +static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + int length = mtd->oobsize; + int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; + int eccsize = chip->ecc.size; + uint8_t *bufpoi = chip->oob_poi; + int i, toread, sndrnd = 0, pos; + + chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page); + for (i = 0; i < chip->ecc.steps; i++) { + if (sndrnd) { + pos = eccsize + i * (eccsize + chunk); + if (mtd->writesize > 512) + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1); + else + chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page); + } else + sndrnd = 1; + toread = min_t(int, length, chunk); + chip->read_buf(mtd, bufpoi, toread); + bufpoi += toread; + length -= toread; + } + if (length > 0) + chip->read_buf(mtd, bufpoi, length); + + return 0; +} + +/** + * 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 + */ +static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + int status = 0; + const uint8_t *buf = chip->oob_poi; + int length = mtd->oobsize; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + chip->write_buf(mtd, buf, length); + /* Send command to program the OOB data */ + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +/** + * 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 + */ +static int nand_write_oob_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; + int eccsize = chip->ecc.size, length = mtd->oobsize; + int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps; + const uint8_t *bufpoi = chip->oob_poi; + + /* + * data-ecc-data-ecc ... ecc-oob + * or + * data-pad-ecc-pad-data-pad .... ecc-pad-oob + */ + if (!chip->ecc.prepad && !chip->ecc.postpad) { + pos = steps * (eccsize + chunk); + steps = 0; + } else + pos = eccsize; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); + for (i = 0; i < steps; i++) { + if (sndcmd) { + if (mtd->writesize <= 512) { + uint32_t fill = 0xFFFFFFFF; + + len = eccsize; + while (len > 0) { + int num = min_t(int, len, 4); + chip->write_buf(mtd, (uint8_t *)&fill, + num); + len -= num; + } + } else { + pos = eccsize + i * (eccsize + chunk); + chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1); + } + } else + sndcmd = 1; + len = min_t(int, length, chunk); + chip->write_buf(mtd, bufpoi, len); + bufpoi += len; + length -= len; + } + if (length > 0) + chip->write_buf(mtd, bufpoi, length); + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +/** + * nand_do_read_oob - [INTERN] NAND read out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operations description structure + * + * NAND read out-of-band data from the spare area. + */ +static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + int page, realpage, chipnr; + struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_ecc_stats stats; + int readlen = ops->ooblen; + int len; + uint8_t *buf = ops->oobbuf; + int ret = 0; + + pr_debug("%s: from = 0x%08Lx, len = %i\n", + __func__, (unsigned long long)from, readlen); + + stats = mtd->ecc_stats; + + len = mtd_oobavail(mtd, ops); + + if (unlikely(ops->ooboffs >= len)) { + pr_debug("%s: attempt to start read outside oob\n", + __func__); + return -EINVAL; + } + + /* Do not allow reads past end of device */ + if (unlikely(from >= mtd->size || + ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - + (from >> chip->page_shift)) * len)) { + pr_debug("%s: attempt to read beyond end of device\n", + __func__); + return -EINVAL; + } + + chipnr = (int)(from >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + /* Shift to get page */ + realpage = (int)(from >> chip->page_shift); + page = realpage & chip->pagemask; + + while (1) { + WATCHDOG_RESET(); + + if (ops->mode == MTD_OPS_RAW) + ret = chip->ecc.read_oob_raw(mtd, chip, page); + else + ret = chip->ecc.read_oob(mtd, chip, page); + + if (ret < 0) + break; + + len = min(len, readlen); + buf = nand_transfer_oob(chip, 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); + } + + readlen -= len; + if (!readlen) + break; + + /* Increment page address */ + realpage++; + + page = realpage & chip->pagemask; + /* Check, if we cross a chip boundary */ + if (!page) { + chipnr++; + chip->select_chip(mtd, -1); + chip->select_chip(mtd, chipnr); + } + } + chip->select_chip(mtd, -1); + + ops->oobretlen = ops->ooblen - readlen; + + if (ret < 0) + return ret; + + if (mtd->ecc_stats.failed - stats.failed) + return -EBADMSG; + + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +} + +/** + * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure + * + * NAND read data and/or out-of-band data. + */ +static int nand_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + int ret = -ENOTSUPP; + + ops->retlen = 0; + + /* Do not allow reads past end of device */ + if (ops->datbuf && (from + ops->len) > mtd->size) { + pr_debug("%s: attempt to read beyond end of device\n", + __func__); + return -EINVAL; + } + + nand_get_device(mtd, FL_READING); + + switch (ops->mode) { + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: + break; + + default: + goto out; + } + + if (!ops->datbuf) + ret = nand_do_read_oob(mtd, from, ops); + else + ret = nand_do_read_ops(mtd, from, ops); + +out: + nand_release_device(mtd); + return ret; +} + + +/** + * 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 + * @page: page number to write + * + * Not for syndrome calculating ECC controllers, which use a special oob layout. + */ +static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page) +{ + chip->write_buf(mtd, buf, mtd->writesize); + if (oob_required) + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +/** + * 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 + * @page: page number to write + * + * 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, + const uint8_t *buf, int oob_required, + int page) +{ + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + uint8_t *oob = chip->oob_poi; + int steps, size; + + for (steps = chip->ecc.steps; steps > 0; steps--) { + chip->write_buf(mtd, buf, eccsize); + buf += eccsize; + + if (chip->ecc.prepad) { + chip->write_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->write_buf(mtd, oob, eccbytes); + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->write_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + size = mtd->oobsize - (oob - chip->oob_poi); + if (size) + chip->write_buf(mtd, oob, size); + + return 0; +} +/** + * 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) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *ecc_calc = chip->buffers->ecccalc; + const uint8_t *p = buf; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + /* Software ECC calculation */ + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ecc_calc[i]; + + return chip->ecc.write_page_raw(mtd, 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) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *ecc_calc = chip->buffers->ecccalc; + const uint8_t *p = buf; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->write_buf(mtd, p, eccsize); + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + } + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ecc_calc[i]; + + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + + +/** + * 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 + * @buf: data buffer + * @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) +{ + uint8_t *oob_buf = chip->oob_poi; + uint8_t *ecc_calc = chip->buffers->ecccalc; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + int ecc_steps = chip->ecc.steps; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint32_t start_step = offset / ecc_size; + uint32_t end_step = (offset + data_len - 1) / ecc_size; + int oob_bytes = mtd->oobsize / ecc_steps; + int step, i; + + for (step = 0; step < ecc_steps; step++) { + /* configure controller for WRITE access */ + chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + + /* write data (untouched subpages already masked by 0xFF) */ + chip->write_buf(mtd, buf, ecc_size); + + /* mask ECC of un-touched subpages by padding 0xFF */ + if ((step < start_step) || (step > end_step)) + memset(ecc_calc, 0xff, ecc_bytes); + else + chip->ecc.calculate(mtd, buf, ecc_calc); + + /* mask OOB of un-touched subpages by padding 0xFF */ + /* if oob_required, preserve OOB metadata of written subpage */ + if (!oob_required || (step < start_step) || (step > end_step)) + memset(oob_buf, 0xff, oob_bytes); + + buf += ecc_size; + ecc_calc += ecc_bytes; + oob_buf += oob_bytes; + } + + /* copy calculated ECC for whole page to chip->buffer->oob */ + /* this include masked-value(0xFF) for unwritten subpages */ + ecc_calc = chip->buffers->ecccalc; + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ecc_calc[i]; + + /* write OOB buffer to NAND device */ + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + + +/** + * 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 + * @page: page number to write + * + * 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) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + const uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + + chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->write_buf(mtd, p, eccsize); + + if (chip->ecc.prepad) { + chip->write_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->ecc.calculate(mtd, p, oob); + chip->write_buf(mtd, oob, eccbytes); + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->write_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + /* Calculate remaining oob bytes */ + i = mtd->oobsize - (oob - chip->oob_poi); + if (i) + chip->write_buf(mtd, oob, i); + + return 0; +} + +/** + * nand_write_page - [REPLACEABLE] write one page + * @mtd: MTD device structure + * @chip: NAND chip descriptor + * @offset: address offset within the page + * @data_len: length of actual data to be written + * @buf: the data to write + * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write + * @raw: use _raw version of write_page + */ +static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, + uint32_t offset, int data_len, const uint8_t *buf, + int oob_required, int page, int raw) +{ + int status, subpage; + + if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && + chip->ecc.write_subpage) + subpage = offset || (data_len < mtd->writesize); + else + subpage = 0; + + if (nand_standard_page_accessors(&chip->ecc)) + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + + if (unlikely(raw)) + status = chip->ecc.write_page_raw(mtd, chip, buf, + oob_required, page); + else if (subpage) + status = chip->ecc.write_subpage(mtd, chip, offset, data_len, + buf, oob_required, page); + else + status = chip->ecc.write_page(mtd, chip, buf, oob_required, + page); + + if (status < 0) + return status; + + if (nand_standard_page_accessors(&chip->ecc)) { + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + return -EIO; + } + + return 0; +} + +/** + * nand_fill_oob - [INTERN] Transfer client buffer to oob + * @mtd: MTD device structure + * @oob: oob data buffer + * @len: oob data write length + * @ops: oob ops structure + */ +static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, + struct mtd_oob_ops *ops) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + /* + * Initialise to all 0xFF, to avoid the possibility of left over OOB + * data from a previous OOB read. + */ + memset(chip->oob_poi, 0xff, mtd->oobsize); + + switch (ops->mode) { + + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: + memcpy(chip->oob_poi + ops->ooboffs, oob, len); + return oob + len; + + case MTD_OPS_AUTO_OOB: { + struct nand_oobfree *free = chip->ecc.layout->oobfree; + uint32_t boffs = 0, woffs = ops->ooboffs; + size_t bytes = 0; + + for (; free->length && len; free++, len -= bytes) { + /* Write request not from offset 0? */ + if (unlikely(woffs)) { + if (woffs >= free->length) { + woffs -= free->length; + continue; + } + boffs = free->offset + woffs; + bytes = min_t(size_t, len, + (free->length - woffs)); + woffs = 0; + } else { + bytes = min_t(size_t, len, free->length); + boffs = free->offset; + } + memcpy(chip->oob_poi + boffs, oob, bytes); + oob += bytes; + } + return oob; + } + default: + BUG(); + } + return NULL; +} + +#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) + +/** + * nand_do_write_ops - [INTERN] NAND write with ECC + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operations description structure + * + * NAND write with ECC. + */ +static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + int chipnr, realpage, page, column; + struct nand_chip *chip = mtd_to_nand(mtd); + uint32_t writelen = ops->len; + + uint32_t oobwritelen = ops->ooblen; + uint32_t oobmaxlen = mtd_oobavail(mtd, ops); + + uint8_t *oob = ops->oobbuf; + uint8_t *buf = ops->datbuf; + int ret; + int oob_required = oob ? 1 : 0; + + ops->retlen = 0; + if (!writelen) + return 0; + + /* Reject writes, which are not page aligned */ + if (NOTALIGNED(to)) { + pr_notice("%s: attempt to write non page aligned data\n", + __func__); + return -EINVAL; + } + + column = to & (mtd->writesize - 1); + + chipnr = (int)(to >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + /* Check, if it is write protected */ + if (nand_check_wp(mtd)) { + ret = -EIO; + goto err_out; + } + + realpage = (int)(to >> chip->page_shift); + page = realpage & chip->pagemask; + + /* Invalidate the page cache, when we write to the cached page */ + if (to <= ((loff_t)chip->pagebuf << chip->page_shift) && + ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len)) + chip->pagebuf = -1; + + /* Don't allow multipage oob writes with offset */ + if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) { + ret = -EINVAL; + goto err_out; + } + + while (1) { + int bytes = mtd->writesize; + uint8_t *wbuf = buf; + int use_bufpoi; + int part_pagewr = (column || writelen < mtd->writesize); + + if (part_pagewr) + use_bufpoi = 1; + else if (chip->options & NAND_USE_BOUNCE_BUFFER) + use_bufpoi = !IS_ALIGNED((unsigned long)buf, + chip->buf_align); + else + use_bufpoi = 0; + + WATCHDOG_RESET(); + /* Partial page write?, or need to use bounce buffer */ + if (use_bufpoi) { + pr_debug("%s: using write bounce buffer for buf@%p\n", + __func__, buf); + if (part_pagewr) + bytes = min_t(int, bytes - column, writelen); + chip->pagebuf = -1; + memset(chip->buffers->databuf, 0xff, mtd->writesize); + memcpy(&chip->buffers->databuf[column], buf, bytes); + wbuf = chip->buffers->databuf; + } + + if (unlikely(oob)) { + size_t len = min(oobwritelen, oobmaxlen); + oob = nand_fill_oob(mtd, oob, len, ops); + oobwritelen -= len; + } else { + /* We still need to erase leftover OOB data */ + memset(chip->oob_poi, 0xff, mtd->oobsize); + } + ret = chip->write_page(mtd, chip, column, bytes, wbuf, + oob_required, page, + (ops->mode == MTD_OPS_RAW)); + if (ret) + break; + + writelen -= bytes; + if (!writelen) + break; + + column = 0; + buf += bytes; + realpage++; + + page = realpage & chip->pagemask; + /* Check, if we cross a chip boundary */ + if (!page) { + chipnr++; + chip->select_chip(mtd, -1); + chip->select_chip(mtd, chipnr); + } + } + + ops->retlen = ops->len - writelen; + if (unlikely(oob)) + ops->oobretlen = ops->ooblen; + +err_out: + chip->select_chip(mtd, -1); + return ret; +} + +/** + * panic_nand_write - [MTD Interface] NAND write with ECC + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write + * + * NAND write with ECC. Used when performing writes in interrupt context, this + * may for example be called by mtdoops when writing an oops while in panic. + */ +static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const uint8_t *buf) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_oob_ops ops; + int ret; + + /* Wait for the device to get ready */ + panic_nand_wait(mtd, chip, 400); + + /* Grab the device */ + panic_nand_get_device(chip, mtd, FL_WRITING); + + memset(&ops, 0, sizeof(ops)); + ops.len = len; + ops.datbuf = (uint8_t *)buf; + ops.mode = MTD_OPS_PLACE_OOB; + + ret = nand_do_write_ops(mtd, to, &ops); + + *retlen = ops.retlen; + return ret; +} + +/** + * nand_do_write_oob - [MTD Interface] NAND write out-of-band + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure + * + * NAND write out-of-band. + */ +static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + int chipnr, page, status, len; + struct nand_chip *chip = mtd_to_nand(mtd); + + pr_debug("%s: to = 0x%08x, len = %i\n", + __func__, (unsigned int)to, (int)ops->ooblen); + + len = mtd_oobavail(mtd, ops); + + /* Do not allow write past end of page */ + if ((ops->ooboffs + ops->ooblen) > len) { + pr_debug("%s: attempt to write past end of page\n", + __func__); + return -EINVAL; + } + + if (unlikely(ops->ooboffs >= len)) { + pr_debug("%s: attempt to start write outside oob\n", + __func__); + return -EINVAL; + } + + /* Do not allow write past end of device */ + if (unlikely(to >= mtd->size || + ops->ooboffs + ops->ooblen > + ((mtd->size >> chip->page_shift) - + (to >> chip->page_shift)) * len)) { + pr_debug("%s: attempt to write beyond end of device\n", + __func__); + return -EINVAL; + } + + chipnr = (int)(to >> chip->chip_shift); + + /* + * Reset the chip. Some chips (like the Toshiba TC5832DC found in one + * of my DiskOnChip 2000 test units) will clear the whole data page too + * if we don't do this. I have no clue why, but I seem to have 'fixed' + * it in the doc2000 driver in August 1999. dwmw2. + */ + nand_reset(chip, chipnr); + + chip->select_chip(mtd, 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); + return -EROFS; + } + + /* Invalidate the page cache, if we write to the cached page */ + if (page == chip->pagebuf) + chip->pagebuf = -1; + + 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); + else + status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); + + chip->select_chip(mtd, -1); + + if (status) + return status; + + ops->oobretlen = ops->ooblen; + + return 0; +} + +/** + * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure + */ +static int nand_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + int ret = -ENOTSUPP; + + ops->retlen = 0; + + /* Do not allow writes past end of device */ + if (ops->datbuf && (to + ops->len) > mtd->size) { + pr_debug("%s: attempt to write beyond end of device\n", + __func__); + return -EINVAL; + } + + nand_get_device(mtd, FL_WRITING); + + switch (ops->mode) { + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: + break; + + default: + goto out; + } + + if (!ops->datbuf) + ret = nand_do_write_oob(mtd, to, ops); + else + ret = nand_do_write_ops(mtd, to, ops); + +out: + nand_release_device(mtd); + return ret; +} + +/** + * single_erase - [GENERIC] NAND standard block erase command function + * @mtd: MTD device structure + * @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) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + /* Send commands to erase a block */ + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); + + return chip->waitfunc(mtd, chip); +} + +/** + * nand_erase - [MTD Interface] erase block(s) + * @mtd: MTD device structure + * @instr: erase instruction + * + * Erase one ore more blocks. + */ +static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + return nand_erase_nand(mtd, instr, 0); +} + +/** + * nand_erase_nand - [INTERN] erase block(s) + * @mtd: MTD device structure + * @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 allowbbt) +{ + 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", + __func__, (unsigned long long)instr->addr, + (unsigned long long)instr->len); + + if (check_offs_len(mtd, instr->addr, instr->len)) + return -EINVAL; + + /* Grab the lock and see if the device is available */ + nand_get_device(mtd, FL_ERASING); + + /* Shift to get first page */ + page = (int)(instr->addr >> chip->page_shift); + chipnr = (int)(instr->addr >> chip->chip_shift); + + /* Calculate pages in each block */ + pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); + + /* Select the NAND device */ + chip->select_chip(mtd, chipnr); + + /* Check, if it is write protected */ + if (nand_check_wp(mtd)) { + pr_debug("%s: device is write protected!\n", + __func__); + instr->state = MTD_ERASE_FAILED; + goto erase_exit; + } + + /* Loop through the pages */ + len = instr->len; + + instr->state = MTD_ERASING; + + while (len) { + WATCHDOG_RESET(); + + /* Check if we have a bad block, we do not erase bad blocks! */ + if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) << + chip->page_shift, allowbbt)) { + pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", + __func__, page); + instr->state = MTD_ERASE_FAILED; + goto erase_exit; + } + + /* + * Invalidate the page cache, if we erase the block which + * contains the current cached page. + */ + if (page <= chip->pagebuf && chip->pagebuf < + (page + pages_per_block)) + chip->pagebuf = -1; + + status = chip->erase(mtd, page & chip->pagemask); + + /* See if block erase succeeded */ + if (status & NAND_STATUS_FAIL) { + pr_debug("%s: failed erase, page 0x%08x\n", + __func__, page); + instr->state = MTD_ERASE_FAILED; + instr->fail_addr = + ((loff_t)page << chip->page_shift); + goto erase_exit; + } + + /* Increment page address and decrement length */ + len -= (1ULL << chip->phys_erase_shift); + page += pages_per_block; + + /* Check, if we cross a chip boundary */ + if (len && !(page & chip->pagemask)) { + chipnr++; + chip->select_chip(mtd, -1); + chip->select_chip(mtd, chipnr); + } + } + instr->state = MTD_ERASE_DONE; + +erase_exit: + + ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; + + /* Deselect and wake up anyone waiting on the device */ + chip->select_chip(mtd, -1); + nand_release_device(mtd); + + /* Do call back function */ + if (!ret) + mtd_erase_callback(instr); + + /* Return more or less happy */ + return ret; +} + +/** + * nand_sync - [MTD Interface] sync + * @mtd: MTD device structure + * + * Sync is actually a wait for chip ready function. + */ +static void nand_sync(struct mtd_info *mtd) +{ + pr_debug("%s: called\n", __func__); + + /* Grab the lock and see if the device is available */ + nand_get_device(mtd, FL_SYNCING); + /* Release it and go back */ + nand_release_device(mtd); +} + +/** + * nand_block_isbad - [MTD Interface] Check if block at offset is bad + * @mtd: MTD device structure + * @offs: offset relative to mtd start + */ +static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int chipnr = (int)(offs >> chip->chip_shift); + int ret; + + /* Select the NAND device */ + nand_get_device(mtd, FL_READING); + chip->select_chip(mtd, chipnr); + + ret = nand_block_checkbad(mtd, offs, 0); + + chip->select_chip(mtd, -1); + nand_release_device(mtd); + + return ret; +} + +/** + * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad + * @mtd: MTD device structure + * @ofs: offset relative to mtd start + */ +static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + int ret; + + ret = nand_block_isbad(mtd, ofs); + if (ret) { + /* If it was bad already, return success and do nothing */ + if (ret > 0) + return 0; + return ret; + } + + return nand_block_markbad_lowlevel(mtd, ofs); +} + +/** + * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand + * @mtd: MTD device structure + * @chip: nand chip info structure + * @addr: feature address. + * @subfeature_param: the subfeature parameters, a four bytes array. + */ +static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, + int addr, uint8_t *subfeature_param) +{ + int status; + int i; + +#ifdef CONFIG_SYS_NAND_ONFI_DETECTION + if (!chip->onfi_version || + !(le16_to_cpu(chip->onfi_params.opt_cmd) + & ONFI_OPT_CMD_SET_GET_FEATURES)) + return -ENOTSUPP; +#endif + + chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + chip->write_byte(mtd, subfeature_param[i]); + + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + return -EIO; + return 0; +} + +/** + * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand + * @mtd: MTD device structure + * @chip: nand chip info structure + * @addr: feature address. + * @subfeature_param: the subfeature parameters, a four bytes array. + */ +static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, + int addr, uint8_t *subfeature_param) +{ + int i; + +#ifdef CONFIG_SYS_NAND_ONFI_DETECTION + if (!chip->onfi_version || + !(le16_to_cpu(chip->onfi_params.opt_cmd) + & ONFI_OPT_CMD_SET_GET_FEATURES)) + return -ENOTSUPP; +#endif + + chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + *subfeature_param++ = chip->read_byte(mtd); + return 0; +} + +/* Set default functions */ +static void nand_set_defaults(struct nand_chip *chip, int busw) +{ + /* 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 == NULL) + 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->onfi_set_features) + chip->onfi_set_features = nand_onfi_set_features; + if (!chip->onfi_get_features) + chip->onfi_get_features = nand_onfi_get_features; + + /* If called twice, pointers that depend on busw may need to be reset */ + if (!chip->read_byte || chip->read_byte == nand_read_byte) + chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; + 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; + if (!chip->scan_bbt) + chip->scan_bbt = nand_default_bbt; + + if (!chip->controller) { + chip->controller = &chip->hwcontrol; + spin_lock_init(&chip->controller->lock); + init_waitqueue_head(&chip->controller->wq); + } + + if (!chip->buf_align) + chip->buf_align = 1; +} + +/* Sanitize ONFI strings so we can safely print them */ +static void sanitize_string(char *s, size_t len) +{ + ssize_t i; + + /* Null terminate */ + s[len - 1] = 0; + + /* Remove non printable chars */ + for (i = 0; i < len - 1; i++) { + if (s[i] < ' ' || s[i] > 127) + s[i] = '?'; + } + + /* Remove trailing spaces */ + 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; +} + +#ifdef CONFIG_SYS_NAND_ONFI_DETECTION +/* Parse the Extended Parameter Page. */ +static int nand_flash_detect_ext_param_page(struct mtd_info *mtd, + struct nand_chip *chip, struct nand_onfi_params *p) +{ + struct onfi_ext_param_page *ep; + struct onfi_ext_section *s; + struct onfi_ext_ecc_info *ecc; + uint8_t *cursor; + int ret = -EINVAL; + int len; + int i; + + len = le16_to_cpu(p->ext_param_page_length) * 16; + ep = kmalloc(len, GFP_KERNEL); + if (!ep) + return -ENOMEM; + + /* Send our own NAND_CMD_PARAM. */ + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); + + /* Use the Change Read Column command to skip the ONFI param pages. */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, + sizeof(*p) * p->num_of_param_pages , -1); + + /* Read out the Extended Parameter Page. */ + chip->read_buf(mtd, (uint8_t *)ep, len); + if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2) + != le16_to_cpu(ep->crc))) { + pr_debug("fail in the CRC.\n"); + goto ext_out; + } + + /* + * Check the signature. + * Do not strictly follow the ONFI spec, maybe changed in future. + */ + if (strncmp((char *)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; +} + +static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; + + return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, + feature); +} + +/* + * Configure chip properties from Micron vendor-specific ONFI table + */ +static void nand_onfi_detect_micron(struct nand_chip *chip, + struct nand_onfi_params *p) +{ + struct nand_onfi_vendor_micron *micron = (void *)p->vendor; + + if (le16_to_cpu(p->vendor_revision) < 1) + return; + + chip->read_retries = micron->read_retry_options; + chip->setup_read_retry = nand_setup_read_retry_micron; +} + +/* + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. + */ +static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, + int *busw) +{ + struct nand_onfi_params *p = &chip->onfi_params; + int i, j; + int val; + + /* Try ONFI for unknown chip or LP */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); + if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || + chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') + return 0; + + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); + for (i = 0; i < 3; i++) { + for (j = 0; j < sizeof(*p); j++) + ((uint8_t *)p)[j] = chip->read_byte(mtd); + if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == + le16_to_cpu(p->crc)) { + break; + } + } + + if (i == 3) { + pr_err("Could not find valid ONFI parameter page; aborting\n"); + return 0; + } + + /* Check version */ + val = le16_to_cpu(p->revision); + if (val & (1 << 5)) + chip->onfi_version = 23; + else if (val & (1 << 4)) + chip->onfi_version = 22; + else if (val & (1 << 3)) + chip->onfi_version = 21; + else if (val & (1 << 2)) + chip->onfi_version = 20; + else if (val & (1 << 1)) + chip->onfi_version = 10; + + if (!chip->onfi_version) { + pr_info("unsupported ONFI version: %d\n", val); + return 0; + } + + sanitize_string(p->manufacturer, sizeof(p->manufacturer)); + sanitize_string(p->model, sizeof(p->model)); + if (!mtd->name) + mtd->name = p->model; + + 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; + + if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS) + *busw = NAND_BUSWIDTH_16; + else + *busw = 0; + + if (p->ecc_bits != 0xff) { + chip->ecc_strength_ds = p->ecc_bits; + chip->ecc_step_ds = 512; + } else if (chip->onfi_version >= 21 && + (onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) { + + /* + * The nand_flash_detect_ext_param_page() uses the + * Change Read Column command which maybe not supported + * by the chip->cmdfunc. So try to update the chip->cmdfunc + * now. We do not replace user supplied command function. + */ + if (mtd->writesize > 512 && chip->cmdfunc == nand_command) + chip->cmdfunc = nand_command_lp; + + /* The Extended Parameter Page is supported since ONFI 2.1. */ + if (nand_flash_detect_ext_param_page(mtd, chip, p)) + pr_warn("Failed to detect ONFI extended param page\n"); + } else { + pr_warn("Could not retrieve ONFI ECC requirements\n"); + } + + if (p->jedec_id == NAND_MFR_MICRON) + nand_onfi_detect_micron(chip, p); + + return 1; +} +#else +static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, + int *busw) +{ + return 0; +} +#endif + +/* + * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise. + */ +static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip, + int *busw) +{ + struct nand_jedec_params *p = &chip->jedec_params; + struct jedec_ecc_info *ecc; + int val; + int i, j; + + /* Try JEDEC for unknown chip or LP */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1); + if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' || + chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' || + chip->read_byte(mtd) != 'C') + return 0; + + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1); + for (i = 0; i < 3; i++) { + for (j = 0; j < sizeof(*p); j++) + ((uint8_t *)p)[j] = chip->read_byte(mtd); + + 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"); + return 0; + } + + /* Check version */ + val = le16_to_cpu(p->revision); + if (val & (1 << 2)) + chip->jedec_version = 10; + else if (val & (1 << 1)) + chip->jedec_version = 1; /* vendor specific version */ + + if (!chip->jedec_version) { + pr_info("unsupported JEDEC version: %d\n", val); + return 0; + } + + sanitize_string(p->manufacturer, sizeof(p->manufacturer)); + sanitize_string(p->model, sizeof(p->model)); + if (!mtd->name) + mtd->name = p->model; + + 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 (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS) + *busw = NAND_BUSWIDTH_16; + else + *busw = 0; + + /* 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"); + } + + return 1; +} + +/* + * nand_id_has_period - Check if an ID string has a given wraparound period + * @id_data: the ID string + * @arrlen: the length of the @id_data array + * @period: the period of repitition + * + * Check if an ID string is repeated within a given sequence of bytes at + * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a + * period of 3). This is a helper function for nand_id_len(). Returns non-zero + * if the repetition has a period of @period; otherwise, returns zero. + */ +static int nand_id_has_period(u8 *id_data, int arrlen, int period) +{ + int i, j; + for (i = 0; i < period; i++) + for (j = i + period; j < arrlen; j += period) + if (id_data[i] != id_data[j]) + return 0; + return 1; +} + +/* + * nand_id_len - Get the length of an ID string returned by CMD_READID + * @id_data: the ID string + * @arrlen: the length of the @id_data array + + * Returns the length of the ID string, according to known wraparound/trailing + * zero patterns. If no pattern exists, returns the length of the array. + */ +static int nand_id_len(u8 *id_data, int arrlen) +{ + int last_nonzero, period; + + /* Find last non-zero byte */ + for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--) + if (id_data[last_nonzero]) + break; + + /* All zeros */ + if (last_nonzero < 0) + return 0; + + /* Calculate wraparound period */ + for (period = 1; period < arrlen; period++) + if (nand_id_has_period(id_data, arrlen, period)) + break; + + /* There's a repeated pattern */ + if (period < arrlen) + return period; + + /* There are trailing zeros */ + if (last_nonzero < arrlen - 1) + return last_nonzero + 1; + + /* No pattern detected */ + return arrlen; +} + +/* Extract the bits of per cell from the 3rd byte of the extended ID */ +static int nand_get_bits_per_cell(u8 cellinfo) +{ + int bits; + + bits = cellinfo & NAND_CI_CELLTYPE_MSK; + bits >>= NAND_CI_CELLTYPE_SHIFT; + return bits + 1; +} + +/* + * Many new NAND share similar device ID codes, which represent the size of the + * chip. The rest of the parameters must be decoded according to generic or + * manufacturer-specific "extended ID" decoding patterns. + */ +static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, + u8 id_data[8], int *busw) +{ + int extid, id_len; + /* The 3rd id byte holds MLC / multichip data */ + chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); + /* The 4th id byte is the important one */ + extid = id_data[3]; + + id_len = nand_id_len(id_data, 8); + + /* + * Field definitions are in the following datasheets: + * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) + * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) + * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22) + * + * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung + * ID to decide what to do. + */ + if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG && + !nand_is_slc(chip) && id_data[5] != 0x00) { + /* Calc pagesize */ + mtd->writesize = 2048 << (extid & 0x03); + extid >>= 2; + /* Calc oobsize */ + switch (((extid >> 2) & 0x04) | (extid & 0x03)) { + case 1: + mtd->oobsize = 128; + break; + case 2: + mtd->oobsize = 218; + break; + case 3: + mtd->oobsize = 400; + break; + case 4: + mtd->oobsize = 436; + break; + case 5: + mtd->oobsize = 512; + break; + case 6: + mtd->oobsize = 640; + break; + case 7: + default: /* Other cases are "reserved" (unknown) */ + mtd->oobsize = 1024; + break; + } + extid >>= 2; + /* Calc blocksize */ + mtd->erasesize = (128 * 1024) << + (((extid >> 1) & 0x04) | (extid & 0x03)); + *busw = 0; + } else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX && + !nand_is_slc(chip)) { + unsigned int tmp; + + /* Calc pagesize */ + mtd->writesize = 2048 << (extid & 0x03); + extid >>= 2; + /* Calc oobsize */ + switch (((extid >> 2) & 0x04) | (extid & 0x03)) { + case 0: + mtd->oobsize = 128; + break; + case 1: + mtd->oobsize = 224; + break; + case 2: + mtd->oobsize = 448; + break; + case 3: + mtd->oobsize = 64; + break; + case 4: + mtd->oobsize = 32; + break; + case 5: + mtd->oobsize = 16; + break; + default: + mtd->oobsize = 640; + break; + } + extid >>= 2; + /* Calc blocksize */ + tmp = ((extid >> 1) & 0x04) | (extid & 0x03); + if (tmp < 0x03) + mtd->erasesize = (128 * 1024) << tmp; + else if (tmp == 0x03) + mtd->erasesize = 768 * 1024; + else + mtd->erasesize = (64 * 1024) << tmp; + *busw = 0; + } else { + /* Calc pagesize */ + mtd->writesize = 1024 << (extid & 0x03); + extid >>= 2; + /* Calc oobsize */ + mtd->oobsize = (8 << (extid & 0x01)) * + (mtd->writesize >> 9); + extid >>= 2; + /* Calc blocksize. Blocksize is multiples of 64KiB */ + mtd->erasesize = (64 * 1024) << (extid & 0x03); + extid >>= 2; + /* Get buswidth information */ + *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; + + /* + * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per + * 512B page. For Toshiba SLC, we decode the 5th/6th byte as + * follows: + * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm, + * 110b -> 24nm + * - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC + */ + if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA && + nand_is_slc(chip) && + (id_data[5] & 0x7) == 0x6 /* 24nm */ && + !(id_data[4] & 0x80) /* !BENAND */) { + mtd->oobsize = 32 * mtd->writesize >> 9; + } + + } +} + +/* + * Old devices have chip data hardcoded in the device ID table. nand_decode_id + * decodes a matching ID table entry and assigns the MTD size parameters for + * the chip. + */ +static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip, + struct nand_flash_dev *type, u8 id_data[8], + int *busw) +{ + int maf_id = id_data[0]; + + mtd->erasesize = type->erasesize; + mtd->writesize = type->pagesize; + mtd->oobsize = mtd->writesize / 32; + *busw = type->options & NAND_BUSWIDTH_16; + + /* All legacy ID NAND are small-page, SLC */ + chip->bits_per_cell = 1; + + /* + * Check for Spansion/AMD ID + repeating 5th, 6th byte since + * some Spansion chips have erasesize that conflicts with size + * listed in nand_ids table. + * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) + */ + if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00 + && id_data[6] == 0x00 && id_data[7] == 0x00 + && mtd->writesize == 512) { + mtd->erasesize = 128 * 1024; + mtd->erasesize <<= ((id_data[3] & 0x03) << 1); + } +} + +/* + * Set the bad block marker/indicator (BBM/BBI) patterns according to some + * heuristic patterns using various detected parameters (e.g., manufacturer, + * page size, cell-type information). + */ +static void nand_decode_bbm_options(struct mtd_info *mtd, + struct nand_chip *chip, u8 id_data[8]) +{ + int maf_id = id_data[0]; + + /* Set the bad block position */ + if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) + chip->badblockpos = NAND_LARGE_BADBLOCK_POS; + else + chip->badblockpos = NAND_SMALL_BADBLOCK_POS; + + /* + * Bad block marker is stored in the last page of each block on Samsung + * and Hynix MLC devices; stored in first two pages of each block on + * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba, + * AMD/Spansion, and Macronix. All others scan only the first page. + */ + if (!nand_is_slc(chip) && + (maf_id == NAND_MFR_SAMSUNG || + maf_id == NAND_MFR_HYNIX)) + chip->bbt_options |= NAND_BBT_SCANLASTPAGE; + else if ((nand_is_slc(chip) && + (maf_id == NAND_MFR_SAMSUNG || + maf_id == NAND_MFR_HYNIX || + maf_id == NAND_MFR_TOSHIBA || + maf_id == NAND_MFR_AMD || + maf_id == NAND_MFR_MACRONIX)) || + (mtd->writesize == 2048 && + maf_id == NAND_MFR_MICRON)) + chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; +} + +static inline bool is_full_id_nand(struct nand_flash_dev *type) +{ + return type->id_len; +} + +static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, + struct nand_flash_dev *type, u8 *id_data, int *busw) +{ + if (!strncmp((char *)type->id, (char *)id_data, type->id_len)) { + mtd->writesize = type->pagesize; + mtd->erasesize = type->erasesize; + mtd->oobsize = type->oobsize; + + chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); + chip->chipsize = (uint64_t)type->chipsize << 20; + chip->options |= type->options; + chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); + chip->ecc_step_ds = NAND_ECC_STEP(type); + chip->onfi_timing_mode_default = + type->onfi_timing_mode_default; + + *busw = type->options & NAND_BUSWIDTH_16; + + if (!mtd->name) + mtd->name = type->name; + + return true; + } + return false; +} + +/* + * Get the flash and manufacturer id and lookup if the type is supported. + */ +struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, + struct nand_chip *chip, + int *maf_id, int *dev_id, + struct nand_flash_dev *type) +{ + int busw; + int i, maf_idx; + u8 id_data[8]; + + /* + * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) + * after power-up. + */ + nand_reset(chip, 0); + + /* Select the device */ + chip->select_chip(mtd, 0); + + /* Send the command for reading device ID */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + *maf_id = chip->read_byte(mtd); + *dev_id = chip->read_byte(mtd); + + /* + * Try again to make sure, as some systems the bus-hold or other + * interface concerns can cause random data which looks like a + * possibly credible NAND flash to appear. If the two results do + * not match, ignore the device completely. + */ + + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read entire ID string */ + for (i = 0; i < 8; i++) + id_data[i] = chip->read_byte(mtd); + + if (id_data[0] != *maf_id || id_data[1] != *dev_id) { + pr_info("second ID read did not match %02x,%02x against %02x,%02x\n", + *maf_id, *dev_id, id_data[0], id_data[1]); + return ERR_PTR(-ENODEV); + } + + if (!type) + type = nand_flash_ids; + + for (; type->name != NULL; type++) { + if (is_full_id_nand(type)) { + if (find_full_id_nand(mtd, chip, type, id_data, &busw)) + goto ident_done; + } else if (*dev_id == type->dev_id) { + break; + } + } + + chip->onfi_version = 0; + if (!type->name || !type->pagesize) { + /* Check if the chip is ONFI compliant */ + if (nand_flash_detect_onfi(mtd, chip, &busw)) + goto ident_done; + + /* Check if the chip is JEDEC compliant */ + if (nand_flash_detect_jedec(mtd, chip, &busw)) + goto ident_done; + } + + if (!type->name) + return ERR_PTR(-ENODEV); + + if (!mtd->name) + mtd->name = type->name; + + chip->chipsize = (uint64_t)type->chipsize << 20; + + if (!type->pagesize) { + /* Decode parameters from extended ID */ + nand_decode_ext_id(mtd, chip, id_data, &busw); + } else { + nand_decode_id(mtd, chip, type, id_data, &busw); + } + /* Get chip options */ + chip->options |= type->options; + + /* + * Check if chip is not a Samsung device. Do not clear the + * options for chips which do not have an extended id. + */ + if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) + chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; +ident_done: + + /* Try to identify manufacturer */ + for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { + if (nand_manuf_ids[maf_idx].id == *maf_id) + break; + } + + if (chip->options & NAND_BUSWIDTH_AUTO) { + WARN_ON(chip->options & NAND_BUSWIDTH_16); + chip->options |= busw; + nand_set_defaults(chip, busw); + } else if (busw != (chip->options & NAND_BUSWIDTH_16)) { + /* + * Check, if buswidth is correct. Hardware drivers should set + * chip correct! + */ + pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", + *maf_id, *dev_id); + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name); + pr_warn("bus width %d instead %d bit\n", + (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, + busw ? 16 : 8); + return ERR_PTR(-EINVAL); + } + + nand_decode_bbm_options(mtd, chip, id_data); + + /* Calculate the address shift from the page size */ + chip->page_shift = ffs(mtd->writesize) - 1; + /* Convert chipsize to number of pages per chip -1 */ + chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + + chip->bbt_erase_shift = chip->phys_erase_shift = + ffs(mtd->erasesize) - 1; + if (chip->chipsize & 0xffffffff) + chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; + else { + chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); + chip->chip_shift += 32 - 1; + } + + if (chip->chip_shift - chip->page_shift > 16) + 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; + + pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", + *maf_id, *dev_id); + +#ifdef CONFIG_SYS_NAND_ONFI_DETECTION + if (chip->onfi_version) + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, + chip->onfi_params.model); + else if (chip->jedec_version) + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, + chip->jedec_params.model); + else + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, + type->name); +#else + if (chip->jedec_version) + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, + chip->jedec_params.model); + else + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, + type->name); + + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, + type->name); +#endif + + pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n", + (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", + mtd->erasesize >> 10, mtd->writesize, mtd->oobsize); + return type; +} +EXPORT_SYMBOL(nand_get_flash_type); + +#if CONFIG_IS_ENABLED(OF_CONTROL) +DECLARE_GLOBAL_DATA_PTR; + +static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, int node) +{ + int ret, ecc_mode = -1, ecc_strength, ecc_step; + const void *blob = gd->fdt_blob; + const char *str; + + ret = fdtdec_get_int(blob, node, "nand-bus-width", -1); + if (ret == 16) + chip->options |= NAND_BUSWIDTH_16; + + if (fdtdec_get_bool(blob, node, "nand-on-flash-bbt")) + chip->bbt_options |= NAND_BBT_USE_FLASH; + + str = fdt_getprop(blob, node, "nand-ecc-mode", NULL); + if (str) { + if (!strcmp(str, "none")) + ecc_mode = NAND_ECC_NONE; + else if (!strcmp(str, "soft")) + ecc_mode = NAND_ECC_SOFT; + else if (!strcmp(str, "hw")) + ecc_mode = NAND_ECC_HW; + else if (!strcmp(str, "hw_syndrome")) + ecc_mode = NAND_ECC_HW_SYNDROME; + else if (!strcmp(str, "hw_oob_first")) + ecc_mode = NAND_ECC_HW_OOB_FIRST; + else if (!strcmp(str, "soft_bch")) + ecc_mode = NAND_ECC_SOFT_BCH; + } + + + ecc_strength = fdtdec_get_int(blob, node, "nand-ecc-strength", -1); + ecc_step = fdtdec_get_int(blob, node, "nand-ecc-step-size", -1); + + if ((ecc_step >= 0 && !(ecc_strength >= 0)) || + (!(ecc_step >= 0) && ecc_strength >= 0)) { + pr_err("must set both strength and step size in DT\n"); + return -EINVAL; + } + + if (ecc_mode >= 0) + chip->ecc.mode = ecc_mode; + + if (ecc_strength >= 0) + chip->ecc.strength = ecc_strength; + + if (ecc_step > 0) + chip->ecc.size = ecc_step; + + if (fdt_getprop(blob, node, "nand-ecc-maximize", NULL)) + chip->ecc.options |= NAND_ECC_MAXIMIZE; + + return 0; +} +#else +static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, int node) +{ + return 0; +} +#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ + +/** + * nand_scan_ident - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: number of chips to scan for + * @table: alternative NAND ID table + * + * This is the first phase of the normal nand_scan() function. It reads the + * flash ID and sets up MTD fields accordingly. + * + */ +int nand_scan_ident(struct mtd_info *mtd, int maxchips, + struct nand_flash_dev *table) +{ + int i, nand_maf_id, nand_dev_id; + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_flash_dev *type; + int ret; + + if (chip->flash_node) { + ret = nand_dt_init(mtd, chip, chip->flash_node); + if (ret) + return ret; + } + + /* Set the default functions */ + nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16); + + /* Read the flash type */ + type = nand_get_flash_type(mtd, chip, &nand_maf_id, + &nand_dev_id, table); + + if (IS_ERR(type)) { + if (!(chip->options & NAND_SCAN_SILENT_NODEV)) + pr_warn("No NAND device found\n"); + chip->select_chip(mtd, -1); + return PTR_ERR(type); + } + + /* Initialize the ->data_interface field. */ + ret = nand_init_data_interface(chip); + if (ret) + return ret; + + /* + * Setup the data interface correctly on the chip and controller side. + * This explicit call to nand_setup_data_interface() is only required + * for the first die, because nand_reset() has been called before + * ->data_interface and ->default_onfi_timing_mode were set. + * For the other dies, nand_reset() will automatically switch to the + * best mode for us. + */ + ret = nand_setup_data_interface(chip, 0); + if (ret) + return ret; + + chip->select_chip(mtd, -1); + + /* Check for a chip array */ + for (i = 1; i < maxchips; i++) { + /* See comment in nand_get_flash_type for reset */ + nand_reset(chip, i); + + chip->select_chip(mtd, i); + /* Send the command for reading device ID */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + /* Read manufacturer and device IDs */ + if (nand_maf_id != chip->read_byte(mtd) || + nand_dev_id != chip->read_byte(mtd)) { + chip->select_chip(mtd, -1); + break; + } + chip->select_chip(mtd, -1); + } + +#ifdef DEBUG + if (i > 1) + pr_info("%d chips detected\n", i); +#endif + + /* Store the number of chips and calc total size for mtd */ + chip->numchips = i; + mtd->size = i * chip->chipsize; + + return 0; +} +EXPORT_SYMBOL(nand_scan_ident); + +/** + * nand_check_ecc_caps - check the sanity of preset ECC settings + * @chip: nand chip info structure + * @caps: ECC caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * When ECC step size and strength are already set, check if they are supported + * by the controller and the calculated ECC bytes fit within the chip's OOB. + * On success, the calculated ECC bytes is set. + */ +int nand_check_ecc_caps(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int preset_step = chip->ecc.size; + int preset_strength = chip->ecc.strength; + int nsteps, ecc_bytes; + int i, j; + + if (WARN_ON(oobavail < 0)) + return -EINVAL; + + if (!preset_step || !preset_strength) + return -ENODATA; + + nsteps = mtd->writesize / preset_step; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + + if (stepinfo->stepsize != preset_step) + continue; + + for (j = 0; j < stepinfo->nstrengths; j++) { + if (stepinfo->strengths[j] != preset_strength) + continue; + + ecc_bytes = caps->calc_ecc_bytes(preset_step, + preset_strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + return ecc_bytes; + + if (ecc_bytes * nsteps > oobavail) { + pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB", + preset_step, preset_strength); + return -ENOSPC; + } + + chip->ecc.bytes = ecc_bytes; + + return 0; + } + } + + pr_err("ECC (step, strength) = (%d, %d) not supported on this controller", + preset_step, preset_strength); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(nand_check_ecc_caps); + +/** + * nand_match_ecc_req - meet the chip's requirement with least ECC bytes + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * If a chip's ECC requirement is provided, try to meet it with the least + * number of ECC bytes (i.e. with the largest number of OOB-free bytes). + * On success, the chosen ECC settings are set. + */ +int nand_match_ecc_req(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int req_step = chip->ecc_step_ds; + int req_strength = chip->ecc_strength_ds; + int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total; + int best_step, best_strength, best_ecc_bytes; + int best_ecc_bytes_total = INT_MAX; + int i, j; + + if (WARN_ON(oobavail < 0)) + return -EINVAL; + + /* No information provided by the NAND chip */ + if (!req_step || !req_strength) + return -ENOTSUPP; + + /* number of correctable bits the chip requires in a page */ + req_corr = mtd->writesize / req_step * req_strength; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + step_size = stepinfo->stepsize; + + for (j = 0; j < stepinfo->nstrengths; j++) { + strength = stepinfo->strengths[j]; + + /* + * If both step size and strength are smaller than the + * chip's requirement, it is not easy to compare the + * resulted reliability. + */ + if (step_size < req_step && strength < req_strength) + continue; + + if (mtd->writesize % step_size) + continue; + + nsteps = mtd->writesize / step_size; + + ecc_bytes = caps->calc_ecc_bytes(step_size, strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + continue; + ecc_bytes_total = ecc_bytes * nsteps; + + if (ecc_bytes_total > oobavail || + strength * nsteps < req_corr) + continue; + + /* + * We assume the best is to meet the chip's requrement + * with the least number of ECC bytes. + */ + if (ecc_bytes_total < best_ecc_bytes_total) { + best_ecc_bytes_total = ecc_bytes_total; + best_step = step_size; + best_strength = strength; + best_ecc_bytes = ecc_bytes; + } + } + } + + if (best_ecc_bytes_total == INT_MAX) + return -ENOTSUPP; + + chip->ecc.size = best_step; + chip->ecc.strength = best_strength; + chip->ecc.bytes = best_ecc_bytes; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_match_ecc_req); + +/** + * nand_maximize_ecc - choose the max ECC strength available + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * Choose the max ECC strength that is supported on the controller, and can fit + * within the chip's OOB. On success, the chosen ECC settings are set. + */ +int nand_maximize_ecc(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int step_size, strength, nsteps, ecc_bytes, corr; + int best_corr = 0; + int best_step = 0; + int best_strength, best_ecc_bytes; + int i, j; + + if (WARN_ON(oobavail < 0)) + return -EINVAL; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + step_size = stepinfo->stepsize; + + /* If chip->ecc.size is already set, respect it */ + if (chip->ecc.size && step_size != chip->ecc.size) + continue; + + for (j = 0; j < stepinfo->nstrengths; j++) { + strength = stepinfo->strengths[j]; + + if (mtd->writesize % step_size) + continue; + + nsteps = mtd->writesize / step_size; + + ecc_bytes = caps->calc_ecc_bytes(step_size, strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + continue; + + if (ecc_bytes * nsteps > oobavail) + continue; + + corr = strength * nsteps; + + /* + * If the number of correctable bits is the same, + * bigger step_size has more reliability. + */ + if (corr > best_corr || + (corr == best_corr && step_size > best_step)) { + best_corr = corr; + best_step = step_size; + best_strength = strength; + best_ecc_bytes = ecc_bytes; + } + } + } + + if (!best_corr) + return -ENOTSUPP; + + chip->ecc.size = best_step; + chip->ecc.strength = best_strength; + chip->ecc.bytes = best_ecc_bytes; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_maximize_ecc); + +/* + * Check if the chip configuration meet the datasheet requirements. + + * If our configuration corrects A bits per B bytes and the minimum + * required correction level is X bits per Y bytes, then we must ensure + * both of the following are true: + * + * (1) A / B >= X / Y + * (2) A >= X + * + * Requirement (1) ensures we can correct for the required bitflip density. + * Requirement (2) ensures we can correct even when all bitflips are clumped + * in the same sector. + */ +static bool nand_ecc_strength_good(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int corr, ds_corr; + + if (ecc->size == 0 || chip->ecc_step_ds == 0) + /* Not enough information */ + return true; + + /* + * We get the number of corrected bits per page to compare + * the correction density. + */ + corr = (mtd->writesize * ecc->strength) / ecc->size; + ds_corr = (mtd->writesize * chip->ecc_strength_ds) / chip->ecc_step_ds; + + return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds; +} + +static bool invalid_ecc_page_accessors(struct nand_chip *chip) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (nand_standard_page_accessors(ecc)) + return false; + + /* + * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND + * controller driver implements all the page accessors because + * default helpers are not suitable when the core does not + * send the READ0/PAGEPROG commands. + */ + return (!ecc->read_page || !ecc->write_page || + !ecc->read_page_raw || !ecc->write_page_raw || + (NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) || + (NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage && + ecc->hwctl && ecc->calculate)); +} + +/** + * nand_scan_tail - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * + * This is the second phase of the normal nand_scan() function. It fills out + * all the uninitialized function pointers with the defaults and scans for a + * bad block table if appropriate. + */ +int nand_scan_tail(struct mtd_info *mtd) +{ + int i; + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + struct nand_buffers *nbuf; + + /* New bad blocks should be marked in OOB, flash-based BBT, or both */ + BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && + !(chip->bbt_options & NAND_BBT_USE_FLASH)); + + if (invalid_ecc_page_accessors(chip)) { + pr_err("Invalid ECC page accessors setup\n"); + return -EINVAL; + } + + if (!(chip->options & NAND_OWN_BUFFERS)) { + nbuf = kzalloc(sizeof(struct nand_buffers), GFP_KERNEL); + chip->buffers = nbuf; + } else { + if (!chip->buffers) + return -ENOMEM; + } + + /* Set the internal oob buffer location, just after the page data */ + chip->oob_poi = chip->buffers->databuf + mtd->writesize; + + /* + * If no default placement scheme is given, select an appropriate one. + */ + if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) { + switch (mtd->oobsize) { + case 8: + ecc->layout = &nand_oob_8; + break; + case 16: + ecc->layout = &nand_oob_16; + break; + case 64: + ecc->layout = &nand_oob_64; + break; + case 128: + ecc->layout = &nand_oob_128; + break; + default: + pr_warn("No oob scheme defined for oobsize %d\n", + mtd->oobsize); + BUG(); + } + } + + if (!chip->write_page) + chip->write_page = nand_write_page; + + /* + * Check ECC mode, default to software if 3byte/512byte hardware ECC is + * selected and we have 256 byte pagesize fallback to software ECC + */ + + switch (ecc->mode) { + case NAND_ECC_HW_OOB_FIRST: + /* Similar to NAND_ECC_HW, but a separate read_page handle */ + if (!ecc->calculate || !ecc->correct || !ecc->hwctl) { + pr_warn("No ECC functions supplied; hardware ECC not possible\n"); + BUG(); + } + if (!ecc->read_page) + ecc->read_page = nand_read_page_hwecc_oob_first; + + case NAND_ECC_HW: + /* Use standard hwecc read page function? */ + if (!ecc->read_page) + ecc->read_page = nand_read_page_hwecc; + if (!ecc->write_page) + ecc->write_page = nand_write_page_hwecc; + if (!ecc->read_page_raw) + ecc->read_page_raw = nand_read_page_raw; + if (!ecc->write_page_raw) + ecc->write_page_raw = nand_write_page_raw; + if (!ecc->read_oob) + ecc->read_oob = nand_read_oob_std; + if (!ecc->write_oob) + ecc->write_oob = nand_write_oob_std; + if (!ecc->read_subpage) + ecc->read_subpage = nand_read_subpage; + if (!ecc->write_subpage && ecc->hwctl && ecc->calculate) + ecc->write_subpage = nand_write_subpage_hwecc; + + case NAND_ECC_HW_SYNDROME: + if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) && + (!ecc->read_page || + ecc->read_page == nand_read_page_hwecc || + !ecc->write_page || + ecc->write_page == nand_write_page_hwecc)) { + pr_warn("No ECC functions supplied; hardware ECC not possible\n"); + BUG(); + } + /* Use standard syndrome read/write page function? */ + if (!ecc->read_page) + ecc->read_page = nand_read_page_syndrome; + if (!ecc->write_page) + ecc->write_page = nand_write_page_syndrome; + if (!ecc->read_page_raw) + ecc->read_page_raw = nand_read_page_raw_syndrome; + if (!ecc->write_page_raw) + ecc->write_page_raw = nand_write_page_raw_syndrome; + if (!ecc->read_oob) + ecc->read_oob = nand_read_oob_syndrome; + if (!ecc->write_oob) + ecc->write_oob = nand_write_oob_syndrome; + + if (mtd->writesize >= ecc->size) { + if (!ecc->strength) { + pr_warn("Driver must set ecc.strength when using hardware ECC\n"); + BUG(); + } + break; + } + pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n", + ecc->size, mtd->writesize); + ecc->mode = NAND_ECC_SOFT; + + case NAND_ECC_SOFT: + ecc->calculate = nand_calculate_ecc; + ecc->correct = nand_correct_data; + ecc->read_page = nand_read_page_swecc; + ecc->read_subpage = nand_read_subpage; + ecc->write_page = nand_write_page_swecc; + ecc->read_page_raw = nand_read_page_raw; + ecc->write_page_raw = nand_write_page_raw; + ecc->read_oob = nand_read_oob_std; + ecc->write_oob = nand_write_oob_std; + if (!ecc->size) + ecc->size = 256; + ecc->bytes = 3; + ecc->strength = 1; + break; + + case NAND_ECC_SOFT_BCH: + if (!mtd_nand_has_bch()) { + pr_warn("CONFIG_MTD_NAND_ECC_BCH not enabled\n"); + BUG(); + } + ecc->calculate = nand_bch_calculate_ecc; + ecc->correct = nand_bch_correct_data; + ecc->read_page = nand_read_page_swecc; + ecc->read_subpage = nand_read_subpage; + ecc->write_page = nand_write_page_swecc; + ecc->read_page_raw = nand_read_page_raw; + ecc->write_page_raw = nand_write_page_raw; + ecc->read_oob = nand_read_oob_std; + ecc->write_oob = nand_write_oob_std; + /* + * Board driver should supply ecc.size and ecc.strength values + * to select how many bits are correctable. Otherwise, default + * to 4 bits for large page devices. + */ + if (!ecc->size && (mtd->oobsize >= 64)) { + ecc->size = 512; + ecc->strength = 4; + } + + /* See nand_bch_init() for details. */ + ecc->bytes = 0; + ecc->priv = nand_bch_init(mtd); + if (!ecc->priv) { + pr_warn("BCH ECC initialization failed!\n"); + BUG(); + } + break; + + case NAND_ECC_NONE: + pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n"); + ecc->read_page = nand_read_page_raw; + ecc->write_page = nand_write_page_raw; + ecc->read_oob = nand_read_oob_std; + ecc->read_page_raw = nand_read_page_raw; + ecc->write_page_raw = nand_write_page_raw; + ecc->write_oob = nand_write_oob_std; + ecc->size = mtd->writesize; + ecc->bytes = 0; + ecc->strength = 0; + break; + + default: + pr_warn("Invalid NAND_ECC_MODE %d\n", ecc->mode); + BUG(); + } + + /* For many systems, the standard OOB write also works for raw */ + if (!ecc->read_oob_raw) + ecc->read_oob_raw = ecc->read_oob; + if (!ecc->write_oob_raw) + ecc->write_oob_raw = ecc->write_oob; + + /* + * The number of bytes available for a client to place data into + * the out of band area. + */ + mtd->oobavail = 0; + if (ecc->layout) { + for (i = 0; ecc->layout->oobfree[i].length; i++) + mtd->oobavail += ecc->layout->oobfree[i].length; + } + + /* ECC sanity check: warn if it's too weak */ + if (!nand_ecc_strength_good(mtd)) + pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n", + mtd->name); + + /* + * Set the number of read / write steps for one page depending on ECC + * mode. + */ + ecc->steps = mtd->writesize / ecc->size; + if (ecc->steps * ecc->size != mtd->writesize) { + pr_warn("Invalid ECC parameters\n"); + BUG(); + } + ecc->total = ecc->steps * ecc->bytes; + + /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */ + if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) { + switch (ecc->steps) { + case 2: + mtd->subpage_sft = 1; + break; + case 4: + case 8: + case 16: + mtd->subpage_sft = 2; + break; + } + } + chip->subpagesize = mtd->writesize >> mtd->subpage_sft; + + /* Initialize state */ + chip->state = FL_READY; + + /* Invalidate the pagebuffer reference */ + chip->pagebuf = -1; + + /* Large page NAND with SOFT_ECC should support subpage reads */ + switch (ecc->mode) { + case NAND_ECC_SOFT: + case NAND_ECC_SOFT_BCH: + if (chip->page_shift > 9) + chip->options |= NAND_SUBPAGE_READ; + break; + + default: + break; + } + + /* Fill in remaining MTD driver data */ + mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH; + mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : + MTD_CAP_NANDFLASH; + mtd->_erase = nand_erase; + mtd->_panic_write = panic_nand_write; + mtd->_read_oob = nand_read_oob; + mtd->_write_oob = nand_write_oob; + mtd->_sync = nand_sync; + mtd->_lock = NULL; + mtd->_unlock = NULL; + mtd->_block_isreserved = nand_block_isreserved; + mtd->_block_isbad = nand_block_isbad; + mtd->_block_markbad = nand_block_markbad; + mtd->writebufsize = mtd->writesize; + + /* propagate ecc info to mtd_info */ + mtd->ecclayout = ecc->layout; + mtd->ecc_strength = ecc->strength; + mtd->ecc_step_size = ecc->size; + /* + * Initialize bitflip_threshold to its default prior scan_bbt() call. + * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be + * properly set. + */ + if (!mtd->bitflip_threshold) + mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4); + + return 0; +} +EXPORT_SYMBOL(nand_scan_tail); + +/** + * nand_scan - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: number of chips to scan for + * + * 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(struct mtd_info *mtd, int maxchips) +{ + int ret; + + ret = nand_scan_ident(mtd, maxchips, NULL); + if (!ret) + ret = nand_scan_tail(mtd); + return ret; +} +EXPORT_SYMBOL(nand_scan); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Steven J. Hill "); +MODULE_AUTHOR("Thomas Gleixner "); +MODULE_DESCRIPTION("Generic NAND flash driver code"); diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c new file mode 100644 index 0000000000..ba785c5d53 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -0,0 +1,1373 @@ +/* + * Overview: + * Bad block table support for the NAND driver + * + * Copyright © 2004 Thomas Gleixner (tglx@linutronix.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Description: + * + * When nand_scan_bbt is called, then it tries to find the bad block table + * depending on the options in the BBT descriptor(s). If no flash based BBT + * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory + * marked good / bad blocks. This information is used to create a memory BBT. + * Once a new bad block is discovered then the "factory" information is updated + * on the device. + * If a flash based BBT is specified then the function first tries to find the + * BBT on flash. If a BBT is found then the contents are read and the memory + * based BBT is created. If a mirrored BBT is selected then the mirror is + * searched too and the versions are compared. If the mirror has a greater + * version number, then the mirror BBT is used to build the memory based BBT. + * If the tables are not versioned, then we "or" the bad block information. + * If one of the BBTs is out of date or does not exist it is (re)created. + * If no BBT exists at all then the device is scanned for factory marked + * good / bad blocks and the bad block tables are created. + * + * For manufacturer created BBTs like the one found on M-SYS DOC devices + * the BBT is searched and read but never created + * + * The auto generated bad block table is located in the last good blocks + * of the device. The table is mirrored, so it can be updated eventually. + * The table is marked in the OOB area with an ident pattern and a version + * number which indicates which of both tables is more up to date. If the NAND + * controller needs the complete OOB area for the ECC information then the + * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of + * course): it moves the ident pattern and the version byte into the data area + * and the OOB area will remain untouched. + * + * The table uses 2 bits per block + * 11b: block is good + * 00b: block is factory marked bad + * 01b, 10b: block is marked bad due to wear + * + * The memory bad block table uses the following scheme: + * 00b: block is good + * 01b: block is marked bad due to wear + * 10b: block is reserved (to protect the bbt area) + * 11b: block is factory marked bad + * + * Multichip devices like DOC store the bad block info per floor. + * + * Following assumptions are made: + * - bbts start at a page boundary, if autolocated on a block boundary + * - the space necessary for a bbt in FLASH does not exceed a block boundary + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BBT_BLOCK_GOOD 0x00 +#define BBT_BLOCK_WORN 0x01 +#define BBT_BLOCK_RESERVED 0x02 +#define BBT_BLOCK_FACTORY_BAD 0x03 + +#define BBT_ENTRY_MASK 0x03 +#define BBT_ENTRY_SHIFT 2 + +static int nand_update_bbt(struct mtd_info *mtd, loff_t offs); + +static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block) +{ + uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT]; + entry >>= (block & BBT_ENTRY_MASK) * 2; + return entry & BBT_ENTRY_MASK; +} + +static inline void bbt_mark_entry(struct nand_chip *chip, int block, + uint8_t mark) +{ + uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2); + chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk; +} + +static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) +{ + if (memcmp(buf, td->pattern, td->len)) + return -1; + return 0; +} + +/** + * check_pattern - [GENERIC] check if a pattern is in the buffer + * @buf: the buffer to search + * @len: the length of buffer to search + * @paglen: the pagelength + * @td: search pattern descriptor + * + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. + */ +static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) +{ + if (td->options & NAND_BBT_NO_OOB) + return check_pattern_no_oob(buf, td); + + /* Compare the pattern */ + if (memcmp(buf + paglen + td->offs, td->pattern, td->len)) + return -1; + + return 0; +} + +/** + * check_short_pattern - [GENERIC] check if a pattern is in the buffer + * @buf: the buffer to search + * @td: search pattern descriptor + * + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. Same as check_pattern, but no optional empty + * check. + */ +static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) +{ + /* Compare the pattern */ + if (memcmp(buf + td->offs, td->pattern, td->len)) + return -1; + return 0; +} + +/** + * add_marker_len - compute the length of the marker in data area + * @td: BBT descriptor used for computation + * + * The length will be 0 if the marker is located in OOB area. + */ +static u32 add_marker_len(struct nand_bbt_descr *td) +{ + u32 len; + + if (!(td->options & NAND_BBT_NO_OOB)) + return 0; + + len = td->len; + if (td->options & NAND_BBT_VERSION) + len++; + return len; +} + +/** + * read_bbt - [GENERIC] Read the bad block table starting from page + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @td: the bbt describtion table + * @offs: block number offset in the table + * + * Read the bad block table starting from page. + */ +static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, + struct nand_bbt_descr *td, int offs) +{ + int res, ret = 0, i, j, act = 0; + struct nand_chip *this = mtd_to_nand(mtd); + size_t retlen, len, totlen; + loff_t from; + int bits = td->options & NAND_BBT_NRBITS_MSK; + uint8_t msk = (uint8_t)((1 << bits) - 1); + u32 marker_len; + int reserved_block_code = td->reserved_block_code; + + totlen = (num * bits) >> 3; + marker_len = add_marker_len(td); + from = ((loff_t)page) << this->page_shift; + + while (totlen) { + len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); + if (marker_len) { + /* + * In case the BBT marker is not in the OOB area it + * will be just in the first page. + */ + len -= marker_len; + from += marker_len; + marker_len = 0; + } + res = mtd_read(mtd, from, len, &retlen, buf); + if (res < 0) { + if (mtd_is_eccerr(res)) { + pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n", + from & ~mtd->writesize); + return res; + } else if (mtd_is_bitflip(res)) { + pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n", + from & ~mtd->writesize); + ret = res; + } else { + pr_info("nand_bbt: error reading BBT\n"); + return res; + } + } + + /* Analyse data */ + for (i = 0; i < len; i++) { + uint8_t dat = buf[i]; + for (j = 0; j < 8; j += bits, act++) { + uint8_t tmp = (dat >> j) & msk; + if (tmp == msk) + continue; + if (reserved_block_code && (tmp == reserved_block_code)) { + pr_info("nand_read_bbt: reserved block at 0x%012llx\n", + (loff_t)(offs + act) << + this->bbt_erase_shift); + bbt_mark_entry(this, offs + act, + BBT_BLOCK_RESERVED); + mtd->ecc_stats.bbtblocks++; + continue; + } + /* + * Leave it for now, if it's matured we can + * move this message to pr_debug. + */ + pr_info("nand_read_bbt: bad block at 0x%012llx\n", + (loff_t)(offs + act) << + this->bbt_erase_shift); + /* Factory marked bad or worn out? */ + if (tmp == 0) + bbt_mark_entry(this, offs + act, + BBT_BLOCK_FACTORY_BAD); + else + bbt_mark_entry(this, offs + act, + BBT_BLOCK_WORN); + mtd->ecc_stats.badblocks++; + } + } + totlen -= len; + from += len; + } + return ret; +} + +/** + * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @chip: read the table for a specific chip, -1 read all chips; applies only if + * NAND_BBT_PERCHIP option is set + * + * Read the bad block table for all chips starting at a given page. We assume + * that the bbt bits are in consecutive order. + */ +static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int res = 0, i; + + if (td->options & NAND_BBT_PERCHIP) { + int offs = 0; + for (i = 0; i < this->numchips; i++) { + if (chip == -1 || chip == i) + res = read_bbt(mtd, buf, td->pages[i], + this->chipsize >> this->bbt_erase_shift, + td, offs); + if (res) + return res; + offs += this->chipsize >> this->bbt_erase_shift; + } + } else { + res = read_bbt(mtd, buf, td->pages[0], + mtd->size >> this->bbt_erase_shift, td, 0); + if (res) + return res; + } + return 0; +} + +/* BBT marker is in the first page, no OOB */ +static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, + struct nand_bbt_descr *td) +{ + size_t retlen; + size_t len; + + len = td->len; + if (td->options & NAND_BBT_VERSION) + len++; + + return mtd_read(mtd, offs, len, &retlen, buf); +} + +/** + * scan_read_oob - [GENERIC] Scan data+OOB region to buffer + * @mtd: MTD device structure + * @buf: temporary buffer + * @offs: offset at which to scan + * @len: length of data region to read + * + * Scan read data from data+OOB. May traverse multiple pages, interleaving + * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest" + * ECC condition (error or bitflip). May quit on the first (non-ECC) error. + */ +static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, + size_t len) +{ + struct mtd_oob_ops ops; + int res, ret = 0; + + ops.mode = MTD_OPS_PLACE_OOB; + ops.ooboffs = 0; + ops.ooblen = mtd->oobsize; + + while (len > 0) { + ops.datbuf = buf; + ops.len = min(len, (size_t)mtd->writesize); + ops.oobbuf = buf + ops.len; + + res = mtd_read_oob(mtd, offs, &ops); + if (res) { + if (!mtd_is_bitflip_or_eccerr(res)) + return res; + else if (mtd_is_eccerr(res) || !ret) + ret = res; + } + + buf += mtd->oobsize + mtd->writesize; + len -= mtd->writesize; + offs += mtd->writesize; + } + return ret; +} + +static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs, + size_t len, struct nand_bbt_descr *td) +{ + if (td->options & NAND_BBT_NO_OOB) + return scan_read_data(mtd, buf, offs, td); + else + return scan_read_oob(mtd, buf, offs, len); +} + +/* Scan write data with oob to flash */ +static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, + uint8_t *buf, uint8_t *oob) +{ + struct mtd_oob_ops ops; + + ops.mode = MTD_OPS_PLACE_OOB; + ops.ooboffs = 0; + ops.ooblen = mtd->oobsize; + ops.datbuf = buf; + ops.oobbuf = oob; + ops.len = len; + + return mtd_write_oob(mtd, offs, &ops); +} + +static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) +{ + u32 ver_offs = td->veroffs; + + if (!(td->options & NAND_BBT_NO_OOB)) + ver_offs += mtd->writesize; + return ver_offs; +} + +/** + * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * + * Read the bad block table(s) for all chips starting at a given page. We + * assume that the bbt bits are in consecutive order. + */ +static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, struct nand_bbt_descr *md) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + /* Read the primary version, if available */ + if (td->options & NAND_BBT_VERSION) { + scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift, + mtd->writesize, td); + td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; + pr_info("Bad block table at page %d, version 0x%02X\n", + td->pages[0], td->version[0]); + } + + /* Read the mirror version, if available */ + if (md && (md->options & NAND_BBT_VERSION)) { + scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift, + mtd->writesize, md); + md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; + pr_info("Bad block table at page %d, version 0x%02X\n", + md->pages[0], md->version[0]); + } +} + +/* Scan a given block partially */ +static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, + loff_t offs, uint8_t *buf, int numpages) +{ + struct mtd_oob_ops ops; + int j, ret; + + ops.ooblen = mtd->oobsize; + ops.oobbuf = buf; + ops.ooboffs = 0; + ops.datbuf = NULL; + ops.mode = MTD_OPS_PLACE_OOB; + + for (j = 0; j < numpages; j++) { + /* + * Read the full oob until read_oob is fixed to handle single + * byte reads for 16 bit buswidth. + */ + ret = mtd_read_oob(mtd, offs, &ops); + /* Ignore ECC errors when checking for BBM */ + if (ret && !mtd_is_bitflip_or_eccerr(ret)) + return ret; + + if (check_short_pattern(buf, bd)) + return 1; + + offs += mtd->writesize; + } + return 0; +} + +/** + * create_bbt - [GENERIC] Create a bad block table by scanning the device + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * @chip: create the table for a specific chip, -1 read all chips; applies only + * if NAND_BBT_PERCHIP option is set + * + * Create a bad block table by scanning the device for the given good/bad block + * identify pattern. + */ +static int create_bbt(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *bd, int chip) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int i, numblocks, numpages; + int startblock; + loff_t from; + + pr_info("Scanning device for bad blocks\n"); + + if (bd->options & NAND_BBT_SCAN2NDPAGE) + numpages = 2; + else + numpages = 1; + + if (chip == -1) { + numblocks = mtd->size >> this->bbt_erase_shift; + startblock = 0; + from = 0; + } else { + if (chip >= this->numchips) { + pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", + chip + 1, this->numchips); + return -EINVAL; + } + numblocks = this->chipsize >> this->bbt_erase_shift; + startblock = chip * numblocks; + numblocks += startblock; + from = (loff_t)startblock << this->bbt_erase_shift; + } + + if (this->bbt_options & NAND_BBT_SCANLASTPAGE) + from += mtd->erasesize - (mtd->writesize * numpages); + + for (i = startblock; i < numblocks; i++) { + int ret; + + BUG_ON(bd->options & NAND_BBT_NO_OOB); + + ret = scan_block_fast(mtd, bd, from, buf, numpages); + if (ret < 0) + return ret; + + if (ret) { + bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD); + pr_warn("Bad eraseblock %d at 0x%012llx\n", + i, (unsigned long long)from); + mtd->ecc_stats.badblocks++; + } + + from += (1 << this->bbt_erase_shift); + } + return 0; +} + +/** + * search_bbt - [GENERIC] scan the device for a specific bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * + * Read the bad block table by searching for a given ident pattern. Search is + * preformed either from the beginning up or from the end of the device + * downwards. The search starts always at the start of a block. If the option + * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains + * the bad block information of this chip. This is necessary to provide support + * for certain DOC devices. + * + * The bbt ident pattern resides in the oob area of the first page in a block. + */ +static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int i, chips; + int startblock, block, dir; + int scanlen = mtd->writesize + mtd->oobsize; + int bbtblocks; + int blocktopage = this->bbt_erase_shift - this->page_shift; + + /* Search direction top -> down? */ + if (td->options & NAND_BBT_LASTBLOCK) { + startblock = (mtd->size >> this->bbt_erase_shift) - 1; + dir = -1; + } else { + startblock = 0; + dir = 1; + } + + /* Do we have a bbt per chip? */ + if (td->options & NAND_BBT_PERCHIP) { + chips = this->numchips; + bbtblocks = this->chipsize >> this->bbt_erase_shift; + startblock &= bbtblocks - 1; + } else { + chips = 1; + bbtblocks = mtd->size >> this->bbt_erase_shift; + } + + for (i = 0; i < chips; i++) { + /* Reset version information */ + td->version[i] = 0; + td->pages[i] = -1; + /* Scan the maximum number of blocks */ + for (block = 0; block < td->maxblocks; block++) { + + int actblock = startblock + dir * block; + loff_t offs = (loff_t)actblock << this->bbt_erase_shift; + + /* Read first page */ + scan_read(mtd, buf, offs, mtd->writesize, td); + if (!check_pattern(buf, scanlen, mtd->writesize, td)) { + td->pages[i] = actblock << blocktopage; + if (td->options & NAND_BBT_VERSION) { + offs = bbt_get_ver_offs(mtd, td); + td->version[i] = buf[offs]; + } + break; + } + } + startblock += this->chipsize >> this->bbt_erase_shift; + } + /* Check, if we found a bbt for each requested chip */ + for (i = 0; i < chips; i++) { + if (td->pages[i] == -1) + pr_warn("Bad block table not found for chip %d\n", i); + else + pr_info("Bad block table found at page %d, version 0x%02X\n", + td->pages[i], td->version[i]); + } + return 0; +} + +/** + * search_read_bbts - [GENERIC] scan the device for bad block table(s) + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * + * Search and read the bad block table(s). + */ +static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, + struct nand_bbt_descr *md) +{ + /* Search the primary table */ + search_bbt(mtd, buf, td); + + /* Search the mirror table */ + if (md) + search_bbt(mtd, buf, md); +} + +/** + * write_bbt - [GENERIC] (Re)write the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all + * + * (Re)write the bad block table. + */ +static int write_bbt(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, struct nand_bbt_descr *md, + int chipsel) +{ + struct nand_chip *this = mtd_to_nand(mtd); + struct erase_info einfo; + int i, res, chip = 0; + int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; + int nrchips, pageoffs, ooboffs; + uint8_t msk[4]; + uint8_t rcode = td->reserved_block_code; + size_t retlen, len = 0; + loff_t to; + struct mtd_oob_ops ops; + + ops.ooblen = mtd->oobsize; + ops.ooboffs = 0; + ops.datbuf = NULL; + ops.mode = MTD_OPS_PLACE_OOB; + + if (!rcode) + rcode = 0xff; + /* Write bad block table per chip rather than per device? */ + if (td->options & NAND_BBT_PERCHIP) { + numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + /* Full device write or specific chip? */ + if (chipsel == -1) { + nrchips = this->numchips; + } else { + nrchips = chipsel + 1; + chip = chipsel; + } + } else { + numblocks = (int)(mtd->size >> this->bbt_erase_shift); + nrchips = 1; + } + + /* Loop through the chips */ + for (; chip < nrchips; chip++) { + /* + * There was already a version of the table, reuse the page + * This applies for absolute placement too, as we have the + * page nr. in td->pages. + */ + if (td->pages[chip] != -1) { + page = td->pages[chip]; + goto write; + } + + /* + * Automatic placement of the bad block table. Search direction + * top -> down? + */ + if (td->options & NAND_BBT_LASTBLOCK) { + startblock = numblocks * (chip + 1) - 1; + dir = -1; + } else { + startblock = chip * numblocks; + dir = 1; + } + + for (i = 0; i < td->maxblocks; i++) { + int block = startblock + dir * i; + /* Check, if the block is bad */ + switch (bbt_get_entry(this, block)) { + case BBT_BLOCK_WORN: + case BBT_BLOCK_FACTORY_BAD: + continue; + } + page = block << + (this->bbt_erase_shift - this->page_shift); + /* Check, if the block is used by the mirror table */ + if (!md || md->pages[chip] != page) + goto write; + } + pr_err("No space left to write bad block table\n"); + return -ENOSPC; + write: + + /* Set up shift count and masks for the flash table */ + bits = td->options & NAND_BBT_NRBITS_MSK; + msk[2] = ~rcode; + switch (bits) { + case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; + msk[3] = 0x01; + break; + case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; + msk[3] = 0x03; + break; + case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; + msk[3] = 0x0f; + break; + case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; + msk[3] = 0xff; + break; + default: return -EINVAL; + } + + to = ((loff_t)page) << this->page_shift; + + /* Must we save the block contents? */ + if (td->options & NAND_BBT_SAVECONTENT) { + /* Make it block aligned */ + to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1); + len = 1 << this->bbt_erase_shift; + res = mtd_read(mtd, to, len, &retlen, buf); + if (res < 0) { + if (retlen != len) { + pr_info("nand_bbt: error reading block for writing the bad block table\n"); + return res; + } + pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n"); + } + /* Read oob data */ + ops.ooblen = (len >> this->page_shift) * mtd->oobsize; + ops.oobbuf = &buf[len]; + res = mtd_read_oob(mtd, to + mtd->writesize, &ops); + if (res < 0 || ops.oobretlen != ops.ooblen) + goto outerr; + + /* Calc the byte offset in the buffer */ + pageoffs = page - (int)(to >> this->page_shift); + offs = pageoffs << this->page_shift; + /* Preset the bbt area with 0xff */ + memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); + ooboffs = len + (pageoffs * mtd->oobsize); + + } else if (td->options & NAND_BBT_NO_OOB) { + ooboffs = 0; + offs = td->len; + /* The version byte */ + if (td->options & NAND_BBT_VERSION) + offs++; + /* Calc length */ + len = (size_t)(numblocks >> sft); + len += offs; + /* Make it page aligned! */ + len = ALIGN(len, mtd->writesize); + /* Preset the buffer with 0xff */ + memset(buf, 0xff, len); + /* Pattern is located at the begin of first page */ + memcpy(buf, td->pattern, td->len); + } else { + /* Calc length */ + len = (size_t)(numblocks >> sft); + /* Make it page aligned! */ + len = ALIGN(len, mtd->writesize); + /* Preset the buffer with 0xff */ + memset(buf, 0xff, len + + (len >> this->page_shift)* mtd->oobsize); + offs = 0; + ooboffs = len; + /* Pattern is located in oob area of first page */ + memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); + } + + if (td->options & NAND_BBT_VERSION) + buf[ooboffs + td->veroffs] = td->version[chip]; + + /* Walk through the memory table */ + for (i = 0; i < numblocks; i++) { + uint8_t dat; + int sftcnt = (i << (3 - sft)) & sftmsk; + dat = bbt_get_entry(this, chip * numblocks + i); + /* Do not store the reserved bbt blocks! */ + buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt); + } + + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = to; + einfo.len = 1 << this->bbt_erase_shift; + res = nand_erase_nand(mtd, &einfo, 1); + if (res < 0) + goto outerr; + + res = scan_write_bbt(mtd, to, len, buf, + td->options & NAND_BBT_NO_OOB ? NULL : + &buf[len]); + if (res < 0) + goto outerr; + + pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", + (unsigned long long)to, td->version[chip]); + + /* Mark it as used */ + td->pages[chip] = page; + } + return 0; + + outerr: + pr_warn("nand_bbt: error while writing bad block table %d\n", res); + return res; +} + +/** + * nand_memory_bbt - [GENERIC] create a memory based bad block table + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern + * + * The function creates a memory based bbt by scanning the device for + * manufacturer / software marked good / bad blocks. + */ +static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + return create_bbt(mtd, this->buffers->databuf, bd, -1); +} + +/** + * check_create - [GENERIC] create and write bbt(s) if necessary + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * + * The function checks the results of the previous call to read_bbt and creates + * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found + * for the chip/device. Update is necessary if one of the tables is missing or + * the version nr. of one table is less than the other. + */ +static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) +{ + int i, chips, writeops, create, chipsel, res, res2; + struct nand_chip *this = mtd_to_nand(mtd); + struct nand_bbt_descr *td = this->bbt_td; + struct nand_bbt_descr *md = this->bbt_md; + struct nand_bbt_descr *rd, *rd2; + + /* Do we have a bbt per chip? */ + if (td->options & NAND_BBT_PERCHIP) + chips = this->numchips; + else + chips = 1; + + for (i = 0; i < chips; i++) { + writeops = 0; + create = 0; + rd = NULL; + rd2 = NULL; + res = res2 = 0; + /* Per chip or per device? */ + chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; + /* Mirrored table available? */ + if (md) { + if (td->pages[i] == -1 && md->pages[i] == -1) { + create = 1; + writeops = 0x03; + } else if (td->pages[i] == -1) { + rd = md; + writeops = 0x01; + } else if (md->pages[i] == -1) { + rd = td; + writeops = 0x02; + } else if (td->version[i] == md->version[i]) { + rd = td; + if (!(td->options & NAND_BBT_VERSION)) + rd2 = md; + } else if (((int8_t)(td->version[i] - md->version[i])) > 0) { + rd = td; + writeops = 0x02; + } else { + rd = md; + writeops = 0x01; + } + } else { + if (td->pages[i] == -1) { + create = 1; + writeops = 0x01; + } else { + rd = td; + } + } + + if (create) { + /* Create the bad block table by scanning the device? */ + if (!(td->options & NAND_BBT_CREATE)) + continue; + + /* Create the table in memory by scanning the chip(s) */ + if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) + create_bbt(mtd, buf, bd, chipsel); + + td->version[i] = 1; + if (md) + md->version[i] = 1; + } + + /* Read back first? */ + if (rd) { + res = read_abs_bbt(mtd, buf, rd, chipsel); + if (mtd_is_eccerr(res)) { + /* Mark table as invalid */ + rd->pages[i] = -1; + rd->version[i] = 0; + i--; + continue; + } + } + /* If they weren't versioned, read both */ + if (rd2) { + res2 = read_abs_bbt(mtd, buf, rd2, chipsel); + if (mtd_is_eccerr(res2)) { + /* Mark table as invalid */ + rd2->pages[i] = -1; + rd2->version[i] = 0; + i--; + continue; + } + } + + /* Scrub the flash table(s)? */ + if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) + writeops = 0x03; + + /* Update version numbers before writing */ + if (md) { + td->version[i] = max(td->version[i], md->version[i]); + md->version[i] = td->version[i]; + } + + /* Write the bad block table to the device? */ + if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { + res = write_bbt(mtd, buf, td, md, chipsel); + if (res < 0) + return res; + } + + /* Write the mirror bad block table to the device? */ + if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { + res = write_bbt(mtd, buf, md, td, chipsel); + if (res < 0) + return res; + } + } + return 0; +} + +/** + * mark_bbt_regions - [GENERIC] mark the bad block table regions + * @mtd: MTD device structure + * @td: bad block table descriptor + * + * The bad block table regions are marked as "bad" to prevent accidental + * erasures / writes. The regions are identified by the mark 0x02. + */ +static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int i, j, chips, block, nrblocks, update; + uint8_t oldval; + + /* Do we have a bbt per chip? */ + if (td->options & NAND_BBT_PERCHIP) { + chips = this->numchips; + nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); + } else { + chips = 1; + nrblocks = (int)(mtd->size >> this->bbt_erase_shift); + } + + for (i = 0; i < chips; i++) { + if ((td->options & NAND_BBT_ABSPAGE) || + !(td->options & NAND_BBT_WRITE)) { + if (td->pages[i] == -1) + continue; + block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); + oldval = bbt_get_entry(this, block); + bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); + if ((oldval != BBT_BLOCK_RESERVED) && + td->reserved_block_code) + nand_update_bbt(mtd, (loff_t)block << + this->bbt_erase_shift); + continue; + } + update = 0; + if (td->options & NAND_BBT_LASTBLOCK) + block = ((i + 1) * nrblocks) - td->maxblocks; + else + block = i * nrblocks; + for (j = 0; j < td->maxblocks; j++) { + oldval = bbt_get_entry(this, block); + bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); + if (oldval != BBT_BLOCK_RESERVED) + update = 1; + block++; + } + /* + * If we want reserved blocks to be recorded to flash, and some + * new ones have been marked, then we need to update the stored + * bbts. This should only happen once. + */ + if (update && td->reserved_block_code) + nand_update_bbt(mtd, (loff_t)(block - 1) << + this->bbt_erase_shift); + } +} + +/** + * verify_bbt_descr - verify the bad block description + * @mtd: MTD device structure + * @bd: the table to verify + * + * This functions performs a few sanity checks on the bad block description + * table. + */ +static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + u32 pattern_len; + u32 bits; + u32 table_size; + + if (!bd) + return; + + pattern_len = bd->len; + bits = bd->options & NAND_BBT_NRBITS_MSK; + + BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && + !(this->bbt_options & NAND_BBT_USE_FLASH)); + BUG_ON(!bits); + + if (bd->options & NAND_BBT_VERSION) + pattern_len++; + + if (bd->options & NAND_BBT_NO_OOB) { + BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); + BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); + BUG_ON(bd->offs); + if (bd->options & NAND_BBT_VERSION) + BUG_ON(bd->veroffs != bd->len); + BUG_ON(bd->options & NAND_BBT_SAVECONTENT); + } + + if (bd->options & NAND_BBT_PERCHIP) + table_size = this->chipsize >> this->bbt_erase_shift; + else + table_size = mtd->size >> this->bbt_erase_shift; + table_size >>= 3; + table_size *= bits; + if (bd->options & NAND_BBT_NO_OOB) + table_size += pattern_len; + BUG_ON(table_size > (1 << this->bbt_erase_shift)); +} + +/** + * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern + * + * The function checks, if a bad block table(s) is/are already available. If + * not it scans the device for manufacturer marked good / bad blocks and writes + * the bad block table(s) to the selected place. + * + * The bad block table memory is allocated here. It must be freed by calling + * the nand_free_bbt function. + */ +static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int len, res; + uint8_t *buf; + struct nand_bbt_descr *td = this->bbt_td; + struct nand_bbt_descr *md = this->bbt_md; + + len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1; + /* + * Allocate memory (2bit per block) and clear the memory bad block + * table. + */ + this->bbt = kzalloc(len, GFP_KERNEL); + if (!this->bbt) + return -ENOMEM; + + /* + * If no primary table decriptor is given, scan the device to build a + * memory based bad block table. + */ + if (!td) { + if ((res = nand_memory_bbt(mtd, bd))) { + pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); + goto err; + } + return 0; + } + verify_bbt_descr(mtd, td); + verify_bbt_descr(mtd, md); + + /* Allocate a temporary buffer for one eraseblock incl. oob */ + len = (1 << this->bbt_erase_shift); + len += (len >> this->page_shift) * mtd->oobsize; + buf = vmalloc(len); + if (!buf) { + res = -ENOMEM; + goto err; + } + + /* Is the bbt at a given page? */ + if (td->options & NAND_BBT_ABSPAGE) { + read_abs_bbts(mtd, buf, td, md); + } else { + /* Search the bad block table using a pattern in oob */ + search_read_bbts(mtd, buf, td, md); + } + + res = check_create(mtd, buf, bd); + if (res) + goto err; + + /* Prevent the bbt regions from erasing / writing */ + mark_bbt_region(mtd, td); + if (md) + mark_bbt_region(mtd, md); + + vfree(buf); + return 0; + +err: + kfree(this->bbt); + this->bbt = NULL; + return res; +} + +/** + * nand_update_bbt - update bad block table(s) + * @mtd: MTD device structure + * @offs: the offset of the newly marked block + * + * The function updates the bad block table(s). + */ +static int nand_update_bbt(struct mtd_info *mtd, loff_t offs) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int len, res = 0; + int chip, chipsel; + uint8_t *buf; + struct nand_bbt_descr *td = this->bbt_td; + struct nand_bbt_descr *md = this->bbt_md; + + if (!this->bbt || !td) + return -EINVAL; + + /* Allocate a temporary buffer for one eraseblock incl. oob */ + len = (1 << this->bbt_erase_shift); + len += (len >> this->page_shift) * mtd->oobsize; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* Do we have a bbt per chip? */ + if (td->options & NAND_BBT_PERCHIP) { + chip = (int)(offs >> this->chip_shift); + chipsel = chip; + } else { + chip = 0; + chipsel = -1; + } + + td->version[chip]++; + if (md) + md->version[chip]++; + + /* Write the bad block table to the device? */ + if (td->options & NAND_BBT_WRITE) { + res = write_bbt(mtd, buf, td, md, chipsel); + if (res < 0) + goto out; + } + /* Write the mirror bad block table to the device? */ + if (md && (md->options & NAND_BBT_WRITE)) { + res = write_bbt(mtd, buf, md, td, chipsel); + } + + out: + kfree(buf); + return res; +} + +/* + * Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. + */ +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +/* Generic flash bbt descriptors */ +static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 8, + .len = 4, + .veroffs = 12, + .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 8, + .len = 4, + .veroffs = 12, + .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, + .pattern = mirror_pattern +}; + +static struct nand_bbt_descr bbt_main_no_oob_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP + | NAND_BBT_NO_OOB, + .len = 4, + .veroffs = 4, + .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_no_oob_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP + | NAND_BBT_NO_OOB, + .len = 4, + .veroffs = 4, + .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, + .pattern = mirror_pattern +}; + +#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB) +/** + * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure + * @this: NAND chip to create descriptor for + * + * This function allocates and initializes a nand_bbt_descr for BBM detection + * based on the properties of @this. The new descriptor is stored in + * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when + * passed to this function. + */ +static int nand_create_badblock_pattern(struct nand_chip *this) +{ + struct nand_bbt_descr *bd; + if (this->badblock_pattern) { + pr_warn("Bad block pattern already allocated; not replacing\n"); + return -EINVAL; + } + bd = kzalloc(sizeof(*bd), GFP_KERNEL); + if (!bd) + return -ENOMEM; + bd->options = this->bbt_options & BADBLOCK_SCAN_MASK; + bd->offs = this->badblockpos; + bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; + bd->pattern = scan_ff_pattern; + bd->options |= NAND_BBT_DYNAMICSTRUCT; + this->badblock_pattern = bd; + return 0; +} + +/** + * nand_default_bbt - [NAND Interface] Select a default bad block table for the device + * @mtd: MTD device structure + * + * This function selects the default bad block table support for the device and + * calls the nand_scan_bbt function. + */ +int nand_default_bbt(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int ret; + + /* Is a flash based bad block table requested? */ + if (this->bbt_options & NAND_BBT_USE_FLASH) { + /* Use the default pattern descriptors */ + if (!this->bbt_td) { + if (this->bbt_options & NAND_BBT_NO_OOB) { + this->bbt_td = &bbt_main_no_oob_descr; + this->bbt_md = &bbt_mirror_no_oob_descr; + } else { + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + } + } + } else { + this->bbt_td = NULL; + this->bbt_md = NULL; + } + + if (!this->badblock_pattern) { + ret = nand_create_badblock_pattern(this); + if (ret) + return ret; + } + + return nand_scan_bbt(mtd, this->badblock_pattern); +} + +/** + * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved + * @mtd: MTD device structure + * @offs: offset in the device + */ +int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int block; + + block = (int)(offs >> this->bbt_erase_shift); + return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED; +} + +/** + * nand_isbad_bbt - [NAND Interface] Check if a block is bad + * @mtd: MTD device structure + * @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) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int block, res; + + block = (int)(offs >> this->bbt_erase_shift); + res = bbt_get_entry(this, block); + + pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", + (unsigned int)offs, block, res); + + switch (res) { + case BBT_BLOCK_GOOD: + return 0; + case BBT_BLOCK_WORN: + return 1; + case BBT_BLOCK_RESERVED: + return allowbbt ? 0 : 1; + } + return 1; +} + +/** + * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT + * @mtd: MTD device structure + * @offs: offset of the bad block + */ +int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int block, ret = 0; + + block = (int)(offs >> this->bbt_erase_shift); + + /* Mark bad block in memory */ + bbt_mark_entry(this, block, BBT_BLOCK_WORN); + + /* Update flash-based bad block table */ + if (this->bbt_options & NAND_BBT_USE_FLASH) + ret = nand_update_bbt(mtd, offs); + + return ret; +} diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c new file mode 100644 index 0000000000..afa0418168 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_bch.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This file provides ECC correction for more than 1 bit per block of data, + * using binary BCH codes. It relies on the generic BCH library lib/bch.c. + * + * Copyright © 2011 Ivan Djelic + * + */ + +#include +/*#include */ +#include + +#include +#include +#include +#include +#include +#include + +/** + * struct nand_bch_control - private NAND BCH control structure + * @bch: BCH control structure + * @ecclayout: private ecc layout for this BCH configuration + * @errloc: error location array + * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid + */ +struct nand_bch_control { + struct bch_control *bch; + struct nand_ecclayout ecclayout; + unsigned int *errloc; + unsigned char *eccmask; +}; + +/** + * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block + * @mtd: MTD block structure + * @buf: input buffer with raw data + * @code: output buffer with ECC + */ +int nand_bch_calculate_ecc(struct mtd_info *mtd, 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; + + memset(code, 0, chip->ecc.bytes); + encode_bch(nbc->bch, buf, chip->ecc.size, code); + + /* apply mask so that an erased page is a valid codeword */ + for (i = 0; i < chip->ecc.bytes; i++) + code[i] ^= nbc->eccmask[i]; + + return 0; +} + +/** + * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) + * @mtd: MTD block structure + * @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, + 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; + + count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc, + NULL, errloc); + if (count > 0) { + for (i = 0; i < count; i++) { + if (errloc[i] < (chip->ecc.size*8)) + /* error is located in data, correct it */ + buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); + /* else error in ecc, no action needed */ + + pr_debug("%s: corrected bitflip %u\n", + __func__, errloc[i]); + } + } else if (count < 0) { + printk(KERN_ERR "ecc unrecoverable error\n"); + count = -EBADMSG; + } + return count; +} + +/** + * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction + * @mtd: MTD block structure + * + * Returns: + * a pointer to a new NAND BCH control structure, or NULL upon failure + * + * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes + * are used to compute BCH parameters m (Galois field order) and t (error + * correction capability). @eccbytes should be equal to the number of bytes + * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8. + * + * Example: to configure 4 bit correction per 512 bytes, you should pass + * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8) + * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits) + */ +struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + unsigned int m, t, eccsteps, i; + struct nand_ecclayout *layout = nand->ecc.layout; + struct nand_bch_control *nbc = NULL; + unsigned char *erased_page; + unsigned int eccsize = nand->ecc.size; + unsigned int eccbytes = nand->ecc.bytes; + unsigned int eccstrength = nand->ecc.strength; + + if (!eccbytes && eccstrength) { + eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8); + nand->ecc.bytes = eccbytes; + } + + if (!eccsize || !eccbytes) { + printk(KERN_WARNING "ecc parameters not supplied\n"); + goto fail; + } + + m = fls(1+8*eccsize); + t = (eccbytes*8)/m; + + nbc = kzalloc(sizeof(*nbc), GFP_KERNEL); + if (!nbc) + goto fail; + + nbc->bch = init_bch(m, t, 0); + if (!nbc->bch) + goto fail; + + /* verify that eccbytes has the expected value */ + if (nbc->bch->ecc_bytes != eccbytes) { + printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", + eccbytes, nbc->bch->ecc_bytes); + goto fail; + } + + eccsteps = mtd->writesize/eccsize; + + /* if no ecc placement scheme was provided, build one */ + if (!layout) { + + /* handle large page devices only */ + if (mtd->oobsize < 64) { + printk(KERN_WARNING "must provide an oob scheme for " + "oobsize %d\n", mtd->oobsize); + goto fail; + } + + layout = &nbc->ecclayout; + layout->eccbytes = eccsteps*eccbytes; + + /* reserve 2 bytes for bad block marker */ + if (layout->eccbytes+2 > mtd->oobsize) { + printk(KERN_WARNING "no suitable oob scheme available " + "for oobsize %d eccbytes %u\n", mtd->oobsize, + eccbytes); + goto fail; + } + /* put ecc bytes at oob tail */ + for (i = 0; i < layout->eccbytes; i++) + layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; + + layout->oobfree[0].offset = 2; + layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; + + nand->ecc.layout = layout; + } + + /* sanity checks */ + if (8*(eccsize+eccbytes) >= (1 << m)) { + printk(KERN_WARNING "eccsize %u is too large\n", eccsize); + goto fail; + } + if (layout->eccbytes != (eccsteps*eccbytes)) { + printk(KERN_WARNING "invalid ecc layout\n"); + goto fail; + } + + nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); + nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); + if (!nbc->eccmask || !nbc->errloc) + goto fail; + /* + * compute and store the inverted ecc of an erased ecc block + */ + erased_page = kmalloc(eccsize, GFP_KERNEL); + if (!erased_page) + goto fail; + + memset(erased_page, 0xff, eccsize); + memset(nbc->eccmask, 0, eccbytes); + encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); + kfree(erased_page); + + for (i = 0; i < eccbytes; i++) + nbc->eccmask[i] ^= 0xff; + + if (!eccstrength) + nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize); + + return nbc; +fail: + nand_bch_free(nbc); + return NULL; +} + +/** + * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources + * @nbc: NAND BCH control structure + */ +void nand_bch_free(struct nand_bch_control *nbc) +{ + if (nbc) { + free_bch(nbc->bch); + kfree(nbc->errloc); + kfree(nbc->eccmask); + kfree(nbc); + } +} diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c new file mode 100644 index 0000000000..2bc329be1a --- /dev/null +++ b/drivers/mtd/nand/raw/nand_ecc.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This file contains an ECC algorithm from Toshiba that detects and + * corrects 1 bit errors in a 256 byte block of data. + * + * drivers/mtd/nand/raw/nand_ecc.c + * + * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) + * Toshiba America Electronics Components, Inc. + * + * Copyright (C) 2006 Thomas Gleixner + * + * As a special exception, if other files instantiate templates or use + * macros or inline functions from these files, or you compile these + * files and link them with other works to produce a work based on these + * files, these files do not by themselves cause the resulting work to be + * covered by the GNU General Public License. However the source code for + * these files must still be made available in accordance with section (3) + * of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + */ + +#include + +#include +#include +#include + +/* + * NAND-SPL has no sofware ECC for now, so don't include nand_calculate_ecc(), + * only nand_correct_data() is needed + */ + +#if !defined(CONFIG_NAND_SPL) || defined(CONFIG_SPL_NAND_SOFTECC) +/* + * Pre-calculated 256-way 1 byte column parity + */ +static const u_char nand_ecc_precalc_table[] = { + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 +}; + +/** + * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block + * @mtd: MTD block structure + * @dat: raw data + * @ecc_code: buffer for ECC + */ +int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; + int i; + + /* Initialize variables */ + reg1 = reg2 = reg3 = 0; + + /* Build up column parity */ + for(i = 0; i < 256; i++) { + /* Get CP0 - CP5 from table */ + idx = nand_ecc_precalc_table[*dat++]; + reg1 ^= (idx & 0x3f); + + /* All bit XOR = 1 ? */ + if (idx & 0x40) { + reg3 ^= (uint8_t) i; + reg2 ^= ~((uint8_t) i); + } + } + + /* Create non-inverted ECC code from line parity */ + tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ + tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ + tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ + tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ + tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ + tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ + tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ + tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ + + tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ + tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ + tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ + tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ + tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ + tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ + tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ + tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ + + /* Calculate final ECC code */ + ecc_code[0] = ~tmp1; + ecc_code[1] = ~tmp2; + ecc_code[2] = ((~reg1) << 2) | 0x03; + + return 0; +} +#endif /* CONFIG_NAND_SPL */ + +static inline int countbits(uint32_t byte) +{ + int res = 0; + + for (;byte; byte >>= 1) + res += byte & 0x01; + return res; +} + +/** + * nand_correct_data - [NAND Interface] Detect and correct bit error(s) + * @mtd: MTD block structure + * @dat: 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 byte block + */ +int nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + uint8_t s0, s1, s2; + + s1 = calc_ecc[0] ^ read_ecc[0]; + s0 = calc_ecc[1] ^ read_ecc[1]; + s2 = calc_ecc[2] ^ read_ecc[2]; + if ((s0 | s1 | s2) == 0) + return 0; + + /* Check for a single bit error */ + if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && + ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && + ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { + + uint32_t byteoffs, bitnum; + + byteoffs = (s1 << 0) & 0x80; + byteoffs |= (s1 << 1) & 0x40; + byteoffs |= (s1 << 2) & 0x20; + byteoffs |= (s1 << 3) & 0x10; + + byteoffs |= (s0 >> 4) & 0x08; + byteoffs |= (s0 >> 3) & 0x04; + byteoffs |= (s0 >> 2) & 0x02; + byteoffs |= (s0 >> 1) & 0x01; + + bitnum = (s2 >> 5) & 0x04; + bitnum |= (s2 >> 4) & 0x02; + bitnum |= (s2 >> 3) & 0x01; + + dat[byteoffs] ^= (1 << bitnum); + + return 1; + } + + if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) + return 1; + + return -EBADMSG; +} diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c new file mode 100644 index 0000000000..4009d64123 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_ids.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include + +#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS +#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) + +#define SP_OPTIONS NAND_NEED_READRDY +#define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16) + +/* + * The chip ID list: + * name, device ID, page size, chip size in MiB, eraseblock size, options + * + * If page size and eraseblock size are 0, the sizes are taken from the + * extended chip ID. + */ +struct nand_flash_dev nand_flash_ids[] = { +#ifdef CONFIG_MTD_NAND_MUSEUM_IDS + LEGACY_ID_NAND("NAND 1MiB 5V 8-bit", 0x6e, 1, SZ_4K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 2MiB 5V 8-bit", 0x64, 2, SZ_4K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 1MiB 3,3V 8-bit", 0xe8, 1, SZ_4K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 1MiB 3,3V 8-bit", 0xec, 1, SZ_4K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 2MiB 3,3V 8-bit", 0xea, 2, SZ_4K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xd5, 4, SZ_8K, SP_OPTIONS), + + LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xe6, 8, SZ_8K, SP_OPTIONS), +#endif + /* + * Some incompatible NAND chips share device ID's and so must be + * listed by full ID. We list them first so that we can easily identify + * the most specific match. + */ + {"TC58NVG0S3E 1G 3.3V 8-bit", + { .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} }, + SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), + 2 }, + {"TC58NVG2S0F 4G 3.3V 8-bit", + { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, + SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, + {"TC58NVG2S0H 4G 3.3V 8-bit", + { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} }, + SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) }, + {"TC58NVG3S0F 8G 3.3V 8-bit", + { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} }, + SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) }, + {"TC58NVG5D2 32G 3.3V 8-bit", + { .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} }, + SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) }, + {"TC58NVG6D2 64G 3.3V 8-bit", + { .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} }, + SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) }, + {"SDTNRGAMA 64G 3.3V 8-bit", + { .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} }, + SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) }, + {"H27UCG8T2ATR-BC 64G 3.3V 8-bit", + { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, + SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640, + NAND_ECC_INFO(40, SZ_1K), 4 }, + {"H27QCG8T2E5R‐BCF 64G 3.3V 8-bit", + { .id = {0xad, 0xde, 0x14, 0xa7, 0x42, 0x4a} }, + SZ_16K, SZ_8K, SZ_4M, NAND_NEED_SCRAMBLING, 6, 1664, + NAND_ECC_INFO(56, SZ_1K), 1 }, + + LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE5, 4, SZ_8K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xD6, 8, SZ_8K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xE6, 8, SZ_8K, SP_OPTIONS), + + LEGACY_ID_NAND("NAND 16MiB 1,8V 8-bit", 0x33, 16, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 16MiB 3,3V 8-bit", 0x73, 16, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 16MiB 1,8V 16-bit", 0x43, 16, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 16MiB 3,3V 16-bit", 0x53, 16, SZ_16K, SP_OPTIONS16), + + LEGACY_ID_NAND("NAND 32MiB 1,8V 8-bit", 0x35, 32, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 32MiB 3,3V 8-bit", 0x75, 32, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 32MiB 1,8V 16-bit", 0x45, 32, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 32MiB 3,3V 16-bit", 0x55, 32, SZ_16K, SP_OPTIONS16), + + LEGACY_ID_NAND("NAND 64MiB 1,8V 8-bit", 0x36, 64, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 64MiB 3,3V 8-bit", 0x76, 64, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 64MiB 1,8V 16-bit", 0x46, 64, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 64MiB 3,3V 16-bit", 0x56, 64, SZ_16K, SP_OPTIONS16), + + LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x78, 128, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 128MiB 1,8V 8-bit", 0x39, 128, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 128MiB 3,3V 8-bit", 0x79, 128, SZ_16K, SP_OPTIONS), + LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x72, 128, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 128MiB 1,8V 16-bit", 0x49, 128, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x74, 128, SZ_16K, SP_OPTIONS16), + LEGACY_ID_NAND("NAND 128MiB 3,3V 16-bit", 0x59, 128, SZ_16K, SP_OPTIONS16), + + LEGACY_ID_NAND("NAND 256MiB 3,3V 8-bit", 0x71, 256, SZ_16K, SP_OPTIONS), + + /* + * These are the new chips with large page size. Their page size and + * eraseblock size are determined from the extended ID bytes. + */ + + /* 512 Megabit */ + EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA2, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 1,8V 8-bit", 0xA0, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF2, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xD0, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 8-bit", 0xF0, 64, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB2, 64, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64MiB 1,8V 16-bit", 0xB0, 64, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC2, 64, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64MiB 3,3V 16-bit", 0xC0, 64, LP_OPTIONS16), + + /* 1 Gigabit */ + EXTENDED_ID_NAND("NAND 128MiB 1,8V 8-bit", 0xA1, 128, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xF1, 128, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 128MiB 3,3V 8-bit", 0xD1, 128, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xB1, 128, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 128MiB 3,3V 16-bit", 0xC1, 128, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 128MiB 1,8V 16-bit", 0xAD, 128, LP_OPTIONS16), + + /* 2 Gigabit */ + EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit", 0xAA, 256, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit", 0xDA, 256, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16), + + /* 4 Gigabit */ + EXTENDED_ID_NAND("NAND 512MiB 1,8V 8-bit", 0xAC, 512, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 512MiB 3,3V 8-bit", 0xDC, 512, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 512MiB 1,8V 16-bit", 0xBC, 512, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 512MiB 3,3V 16-bit", 0xCC, 512, LP_OPTIONS16), + + /* 8 Gigabit */ + EXTENDED_ID_NAND("NAND 1GiB 1,8V 8-bit", 0xA3, 1024, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 1GiB 3,3V 8-bit", 0xD3, 1024, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 1GiB 1,8V 16-bit", 0xB3, 1024, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 1GiB 3,3V 16-bit", 0xC3, 1024, LP_OPTIONS16), + + /* 16 Gigabit */ + EXTENDED_ID_NAND("NAND 2GiB 1,8V 8-bit", 0xA5, 2048, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 2GiB 3,3V 8-bit", 0xD5, 2048, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 2GiB 1,8V 16-bit", 0xB5, 2048, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 2GiB 3,3V 16-bit", 0xC5, 2048, LP_OPTIONS16), + + /* 32 Gigabit */ + EXTENDED_ID_NAND("NAND 4GiB 1,8V 8-bit", 0xA7, 4096, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 4GiB 3,3V 8-bit", 0xD7, 4096, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 4GiB 1,8V 16-bit", 0xB7, 4096, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 4GiB 3,3V 16-bit", 0xC7, 4096, LP_OPTIONS16), + + /* 64 Gigabit */ + EXTENDED_ID_NAND("NAND 8GiB 1,8V 8-bit", 0xAE, 8192, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 8GiB 3,3V 8-bit", 0xDE, 8192, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 8GiB 1,8V 16-bit", 0xBE, 8192, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 8GiB 3,3V 16-bit", 0xCE, 8192, LP_OPTIONS16), + + /* 128 Gigabit */ + EXTENDED_ID_NAND("NAND 16GiB 1,8V 8-bit", 0x1A, 16384, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 16GiB 3,3V 8-bit", 0x3A, 16384, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 16GiB 1,8V 16-bit", 0x2A, 16384, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 16GiB 3,3V 16-bit", 0x4A, 16384, LP_OPTIONS16), + + /* 256 Gigabit */ + EXTENDED_ID_NAND("NAND 32GiB 1,8V 8-bit", 0x1C, 32768, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 32GiB 3,3V 8-bit", 0x3C, 32768, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 32GiB 1,8V 16-bit", 0x2C, 32768, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 32GiB 3,3V 16-bit", 0x4C, 32768, LP_OPTIONS16), + + /* 512 Gigabit */ + EXTENDED_ID_NAND("NAND 64GiB 1,8V 8-bit", 0x1E, 65536, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64GiB 3,3V 8-bit", 0x3E, 65536, LP_OPTIONS), + EXTENDED_ID_NAND("NAND 64GiB 1,8V 16-bit", 0x2E, 65536, LP_OPTIONS16), + EXTENDED_ID_NAND("NAND 64GiB 3,3V 16-bit", 0x4E, 65536, LP_OPTIONS16), + + {NULL} +}; + +/* Manufacturer IDs */ +struct nand_manufacturers nand_manuf_ids[] = { + {NAND_MFR_TOSHIBA, "Toshiba"}, + {NAND_MFR_SAMSUNG, "Samsung"}, + {NAND_MFR_FUJITSU, "Fujitsu"}, + {NAND_MFR_NATIONAL, "National"}, + {NAND_MFR_RENESAS, "Renesas"}, + {NAND_MFR_STMICRO, "ST Micro"}, + {NAND_MFR_HYNIX, "Hynix"}, + {NAND_MFR_MICRON, "Micron"}, + {NAND_MFR_AMD, "AMD/Spansion"}, + {NAND_MFR_MACRONIX, "Macronix"}, + {NAND_MFR_EON, "Eon"}, + {NAND_MFR_SANDISK, "SanDisk"}, + {NAND_MFR_INTEL, "Intel"}, + {NAND_MFR_ATO, "ATO"}, + {0x0, "Unknown"} +}; + +EXPORT_SYMBOL(nand_manuf_ids); +EXPORT_SYMBOL(nand_flash_ids); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Gleixner "); +MODULE_DESCRIPTION("Nand device & manufacturer IDs"); diff --git a/drivers/mtd/nand/raw/nand_plat.c b/drivers/mtd/nand/raw/nand_plat.c new file mode 100644 index 0000000000..335c3e3471 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_plat.c @@ -0,0 +1,64 @@ +/* + * Genericish driver for memory mapped NAND devices + * + * Copyright (c) 2006-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +/* Your board must implement the following macros: + * NAND_PLAT_WRITE_CMD(chip, cmd) + * NAND_PLAT_WRITE_ADR(chip, cmd) + * NAND_PLAT_INIT() + * + * It may also implement the following: + * NAND_PLAT_DEV_READY(chip) + */ + +#include +#include +#ifdef NAND_PLAT_GPIO_DEV_READY +# include +# define NAND_PLAT_DEV_READY(chip) gpio_get_value(NAND_PLAT_GPIO_DEV_READY) +#endif + +#include + +static void plat_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *this = mtd_to_nand(mtd); + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + NAND_PLAT_WRITE_CMD(this, cmd); + else + NAND_PLAT_WRITE_ADR(this, cmd); +} + +#ifdef NAND_PLAT_DEV_READY +static int plat_dev_ready(struct mtd_info *mtd) +{ + return NAND_PLAT_DEV_READY((struct nand_chip *)mtd_to_nand(mtd)); +} +#else +# define plat_dev_ready NULL +#endif + +int board_nand_init(struct nand_chip *nand) +{ +#ifdef NAND_PLAT_GPIO_DEV_READY + gpio_request(NAND_PLAT_GPIO_DEV_READY, "nand-plat"); + gpio_direction_input(NAND_PLAT_GPIO_DEV_READY); +#endif + +#ifdef NAND_PLAT_INIT + NAND_PLAT_INIT(); +#endif + + nand->cmd_ctrl = plat_cmd_ctrl; + nand->dev_ready = plat_dev_ready; + nand->ecc.mode = NAND_ECC_SOFT; + + return 0; +} diff --git a/drivers/mtd/nand/raw/nand_spl_load.c b/drivers/mtd/nand/raw/nand_spl_load.c new file mode 100644 index 0000000000..ecd373e054 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_spl_load.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + */ + +#include +#include + +/* + * The main entry for NAND booting. It's necessary that SDRAM is already + * configured and available since this code loads the main U-Boot image + * from NAND into SDRAM and starts it from there. + */ +void nand_boot(void) +{ + __attribute__((noreturn)) void (*uboot)(void); + + /* + * Load U-Boot image from NAND into RAM + */ + nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, + CONFIG_SYS_NAND_U_BOOT_SIZE, + (void *)CONFIG_SYS_NAND_U_BOOT_DST); + +#ifdef CONFIG_NAND_ENV_DST + nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, + (void *)CONFIG_NAND_ENV_DST); + +#ifdef CONFIG_ENV_OFFSET_REDUND + nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, + (void *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); +#endif +#endif + + /* + * Jump to U-Boot image + */ + uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; + (*uboot)(); +} diff --git a/drivers/mtd/nand/raw/nand_spl_loaders.c b/drivers/mtd/nand/raw/nand_spl_loaders.c new file mode 100644 index 0000000000..177c12b581 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_spl_loaders.c @@ -0,0 +1,104 @@ +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) +{ + unsigned int block, lastblock; + unsigned int page, page_offset; + + /* offs has to be aligned to a page address! */ + block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; + lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; + page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; + page_offset = offs % CONFIG_SYS_NAND_PAGE_SIZE; + + while (block <= lastblock) { + if (!nand_is_bad_block(block)) { + /* Skip bad blocks */ + while (page < CONFIG_SYS_NAND_PAGE_COUNT) { + nand_read_page(block, page, dst); + /* + * When offs is not aligned to page address the + * extra offset is copied to dst as well. Copy + * the image such that its first byte will be + * at the dst. + */ + if (unlikely(page_offset)) { + memmove(dst, dst + page_offset, + CONFIG_SYS_NAND_PAGE_SIZE); + dst = (void *)((int)dst - page_offset); + page_offset = 0; + } + dst += CONFIG_SYS_NAND_PAGE_SIZE; + page++; + } + + page = 0; + } else { + lastblock++; + } + + block++; + } + + return 0; +} + +#ifdef CONFIG_SPL_UBI +/* + * Temporary storage for non NAND page aligned and non NAND page sized + * reads. Note: This does not support runtime detected FLASH yet, but + * that should be reasonably easy to fix by making the buffer large + * enough :) + */ +static u8 scratch_buf[CONFIG_SYS_NAND_PAGE_SIZE]; + +/** + * nand_spl_read_block - Read data from physical eraseblock into a buffer + * @block: Number of the physical eraseblock + * @offset: Data offset from the start of @peb + * @len: Data size to read + * @dst: Address of the destination buffer + * + * This could be further optimized if we'd have a subpage read + * function in the simple code. On NAND which allows subpage reads + * this would spare quite some time to readout e.g. the VID header of + * UBI. + * + * Notes: + * @offset + @len are not allowed to be larger than a physical + * erase block. No sanity check done for simplicity reasons. + * + * To support runtime detected flash this needs to be extended by + * information about the actual flash geometry, but thats beyond the + * scope of this effort and for most applications where fast boot is + * required it is not an issue anyway. + */ +int nand_spl_read_block(int block, int offset, int len, void *dst) +{ + int page, read; + + /* Calculate the page number */ + page = offset / CONFIG_SYS_NAND_PAGE_SIZE; + + /* Offset to the start of a flash page */ + offset = offset % CONFIG_SYS_NAND_PAGE_SIZE; + + while (len) { + /* + * Non page aligned reads go to the scratch buffer. + * Page aligned reads go directly to the destination. + */ + if (offset || len < CONFIG_SYS_NAND_PAGE_SIZE) { + nand_read_page(block, page, scratch_buf); + read = min(len, CONFIG_SYS_NAND_PAGE_SIZE - offset); + memcpy(dst, scratch_buf + offset, read); + offset = 0; + } else { + nand_read_page(block, page, dst); + read = CONFIG_SYS_NAND_PAGE_SIZE; + } + page++; + len -= read; + dst += read; + } + return 0; +} +#endif diff --git a/drivers/mtd/nand/raw/nand_spl_simple.c b/drivers/mtd/nand/raw/nand_spl_simple.c new file mode 100644 index 0000000000..09e053541a --- /dev/null +++ b/drivers/mtd/nand/raw/nand_spl_simple.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2006-2008 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + */ + +#include +#include +#include +#include + +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; +static struct mtd_info *mtd; +static struct nand_chip nand_chip; + +#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ + CONFIG_SYS_NAND_ECCSIZE) +#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) + + +#if (CONFIG_SYS_NAND_PAGE_SIZE <= 512) +/* + * NAND command for small page NAND devices (512) + */ +static int nand_command(int block, int page, uint32_t offs, + u8 cmd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; + + while (!this->dev_ready(mtd)) + ; + + /* Begin command latch cycle */ + this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + /* Set ALE and clear CLE to start address cycle */ + /* Column address */ + this->cmd_ctrl(mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE); + this->cmd_ctrl(mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */ + this->cmd_ctrl(mtd, (page_addr >> 8) & 0xff, + NAND_CTRL_ALE); /* A[24:17] */ +#ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE + /* One more address cycle for devices > 32MiB */ + this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f, + NAND_CTRL_ALE); /* A[28:25] */ +#endif + /* Latch in address */ + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Wait a while for the data to be ready + */ + while (!this->dev_ready(mtd)) + ; + + return 0; +} +#else +/* + * NAND command for large page NAND devices (2k) + */ +static int nand_command(int block, int page, uint32_t offs, + u8 cmd) +{ + struct nand_chip *this = mtd_to_nand(mtd); + int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; + void (*hwctrl)(struct mtd_info *mtd, int cmd, + unsigned int ctrl) = this->cmd_ctrl; + + while (!this->dev_ready(mtd)) + ; + + /* Emulate NAND_CMD_READOOB */ + if (cmd == NAND_CMD_READOOB) { + offs += CONFIG_SYS_NAND_PAGE_SIZE; + cmd = NAND_CMD_READ0; + } + + /* Shift the offset from byte addressing to word addressing. */ + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) + offs >>= 1; + + /* Begin command latch cycle */ + hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + /* Set ALE and clear CLE to start address cycle */ + /* Column address */ + hwctrl(mtd, offs & 0xff, + NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ + hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */ + /* Row address */ + hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */ + hwctrl(mtd, ((page_addr >> 8) & 0xff), + NAND_CTRL_ALE); /* A[27:20] */ +#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE + /* One more address cycle for devices > 128MiB */ + hwctrl(mtd, (page_addr >> 16) & 0x0f, + NAND_CTRL_ALE); /* A[31:28] */ +#endif + /* Latch in address */ + hwctrl(mtd, NAND_CMD_READSTART, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Wait a while for the data to be ready + */ + while (!this->dev_ready(mtd)) + ; + + return 0; +} +#endif + +static int nand_is_bad_block(int block) +{ + struct nand_chip *this = mtd_to_nand(mtd); + u_char bb_data[2]; + + nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, + NAND_CMD_READOOB); + + /* + * Read one byte (or two if it's a 16 bit chip). + */ + if (this->options & NAND_BUSWIDTH_16) { + this->read_buf(mtd, bb_data, 2); + if (bb_data[0] != 0xff || bb_data[1] != 0xff) + return 1; + } else { + this->read_buf(mtd, bb_data, 1); + if (bb_data[0] != 0xff) + return 1; + } + + return 0; +} + +#if defined(CONFIG_SYS_NAND_HW_ECC_OOBFIRST) +static int nand_read_page(int block, int page, uchar *dst) +{ + struct nand_chip *this = mtd_to_nand(mtd); + u_char ecc_calc[ECCTOTAL]; + u_char ecc_code[ECCTOTAL]; + u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; + int i; + int eccsize = CONFIG_SYS_NAND_ECCSIZE; + int eccbytes = CONFIG_SYS_NAND_ECCBYTES; + int eccsteps = ECCSTEPS; + uint8_t *p = dst; + + nand_command(block, page, 0, NAND_CMD_READOOB); + this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); + nand_command(block, page, 0, NAND_CMD_READ0); + + /* Pick the ECC bytes out of the oob data */ + for (i = 0; i < ECCTOTAL; i++) + ecc_code[i] = oob_data[nand_ecc_pos[i]]; + + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + this->ecc.hwctl(mtd, NAND_ECC_READ); + this->read_buf(mtd, p, eccsize); + this->ecc.calculate(mtd, p, &ecc_calc[i]); + this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + } + + return 0; +} +#else +static int nand_read_page(int block, int page, void *dst) +{ + struct nand_chip *this = mtd_to_nand(mtd); + u_char ecc_calc[ECCTOTAL]; + u_char ecc_code[ECCTOTAL]; + u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; + int i; + int eccsize = CONFIG_SYS_NAND_ECCSIZE; + int eccbytes = CONFIG_SYS_NAND_ECCBYTES; + int eccsteps = ECCSTEPS; + uint8_t *p = dst; + + nand_command(block, page, 0, NAND_CMD_READ0); + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + if (this->ecc.mode != NAND_ECC_SOFT) + this->ecc.hwctl(mtd, NAND_ECC_READ); + this->read_buf(mtd, p, eccsize); + this->ecc.calculate(mtd, p, &ecc_calc[i]); + } + this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); + + /* Pick the ECC bytes out of the oob data */ + for (i = 0; i < ECCTOTAL; i++) + ecc_code[i] = oob_data[nand_ecc_pos[i]]; + + eccsteps = ECCSTEPS; + p = dst; + + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + /* No chance to do something with the possible error message + * from correct_data(). We just hope that all possible errors + * are corrected by this routine. + */ + this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + } + + return 0; +} +#endif + +/* nand_init() - initialize data to make nand usable by SPL */ +void nand_init(void) +{ + /* + * Init board specific nand support + */ + mtd = nand_to_mtd(&nand_chip); + nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = + (void __iomem *)CONFIG_SYS_NAND_BASE; + board_nand_init(&nand_chip); + +#ifdef CONFIG_SPL_NAND_SOFTECC + if (nand_chip.ecc.mode == NAND_ECC_SOFT) { + nand_chip.ecc.calculate = nand_calculate_ecc; + nand_chip.ecc.correct = nand_correct_data; + } +#endif + + if (nand_chip.select_chip) + nand_chip.select_chip(mtd, 0); +} + +/* Unselect after operation */ +void nand_deselect(void) +{ + if (nand_chip.select_chip) + nand_chip.select_chip(mtd, -1); +} + +#include "nand_spl_loaders.c" diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c new file mode 100644 index 0000000000..c0545a4fb1 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_timings.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2014 Free Electrons + * + * Author: Boris BREZILLON + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include + +static const struct nand_data_interface onfi_sdr_timings[] = { + /* Mode 0 */ + { + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tADL_min = 400000, + .tALH_min = 20000, + .tALS_min = 50000, + .tAR_min = 25000, + .tCEA_max = 100000, + .tCEH_min = 20000, + .tCH_min = 20000, + .tCHZ_max = 100000, + .tCLH_min = 20000, + .tCLR_min = 20000, + .tCLS_min = 50000, + .tCOH_min = 0, + .tCS_min = 70000, + .tDH_min = 20000, + .tDS_min = 40000, + .tFEAT_max = 1000000, + .tIR_min = 10000, + .tITC_max = 1000000, + .tRC_min = 100000, + .tREA_max = 40000, + .tREH_min = 30000, + .tRHOH_min = 0, + .tRHW_min = 200000, + .tRHZ_max = 200000, + .tRLOH_min = 0, + .tRP_min = 50000, + .tRR_min = 40000, + .tRST_max = 250000000000ULL, + .tWB_max = 200000, + .tWC_min = 100000, + .tWH_min = 30000, + .tWHR_min = 120000, + .tWP_min = 50000, + .tWW_min = 100000, + }, + }, + /* Mode 1 */ + { + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tADL_min = 400000, + .tALH_min = 10000, + .tALS_min = 25000, + .tAR_min = 10000, + .tCEA_max = 45000, + .tCEH_min = 20000, + .tCH_min = 10000, + .tCHZ_max = 50000, + .tCLH_min = 10000, + .tCLR_min = 10000, + .tCLS_min = 25000, + .tCOH_min = 15000, + .tCS_min = 35000, + .tDH_min = 10000, + .tDS_min = 20000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 50000, + .tREA_max = 30000, + .tREH_min = 15000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 0, + .tRP_min = 25000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 45000, + .tWH_min = 15000, + .tWHR_min = 80000, + .tWP_min = 25000, + .tWW_min = 100000, + }, + }, + /* Mode 2 */ + { + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tADL_min = 400000, + .tALH_min = 10000, + .tALS_min = 15000, + .tAR_min = 10000, + .tCEA_max = 30000, + .tCEH_min = 20000, + .tCH_min = 10000, + .tCHZ_max = 50000, + .tCLH_min = 10000, + .tCLR_min = 10000, + .tCLS_min = 15000, + .tCOH_min = 15000, + .tCS_min = 25000, + .tDH_min = 5000, + .tDS_min = 15000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 35000, + .tREA_max = 25000, + .tREH_min = 15000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 0, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tRP_min = 17000, + .tWC_min = 35000, + .tWH_min = 15000, + .tWHR_min = 80000, + .tWP_min = 17000, + .tWW_min = 100000, + }, + }, + /* Mode 3 */ + { + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tADL_min = 400000, + .tALH_min = 5000, + .tALS_min = 10000, + .tAR_min = 10000, + .tCEA_max = 25000, + .tCEH_min = 20000, + .tCH_min = 5000, + .tCHZ_max = 50000, + .tCLH_min = 5000, + .tCLR_min = 10000, + .tCLS_min = 10000, + .tCOH_min = 15000, + .tCS_min = 25000, + .tDH_min = 5000, + .tDS_min = 10000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 30000, + .tREA_max = 20000, + .tREH_min = 10000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 0, + .tRP_min = 15000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 30000, + .tWH_min = 10000, + .tWHR_min = 80000, + .tWP_min = 15000, + .tWW_min = 100000, + }, + }, + /* Mode 4 */ + { + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tADL_min = 400000, + .tALH_min = 5000, + .tALS_min = 10000, + .tAR_min = 10000, + .tCEA_max = 25000, + .tCEH_min = 20000, + .tCH_min = 5000, + .tCHZ_max = 30000, + .tCLH_min = 5000, + .tCLR_min = 10000, + .tCLS_min = 10000, + .tCOH_min = 15000, + .tCS_min = 20000, + .tDH_min = 5000, + .tDS_min = 10000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 25000, + .tREA_max = 20000, + .tREH_min = 10000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 5000, + .tRP_min = 12000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 25000, + .tWH_min = 10000, + .tWHR_min = 80000, + .tWP_min = 12000, + .tWW_min = 100000, + }, + }, + /* Mode 5 */ + { + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, + .tADL_min = 400000, + .tALH_min = 5000, + .tALS_min = 10000, + .tAR_min = 10000, + .tCEA_max = 25000, + .tCEH_min = 20000, + .tCH_min = 5000, + .tCHZ_max = 30000, + .tCLH_min = 5000, + .tCLR_min = 10000, + .tCLS_min = 10000, + .tCOH_min = 15000, + .tCS_min = 15000, + .tDH_min = 5000, + .tDS_min = 7000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 20000, + .tREA_max = 16000, + .tREH_min = 7000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 5000, + .tRP_min = 10000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 20000, + .tWH_min = 7000, + .tWHR_min = 80000, + .tWP_min = 10000, + .tWW_min = 100000, + }, + }, +}; + +/** + * 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_init_data_interface - [NAND Interface] Initialize a data interface from + * given ONFI mode + * @iface: The data interface to be initialized + * @mode: The ONFI timing mode + */ +int onfi_init_data_interface(struct nand_chip *chip, + struct nand_data_interface *iface, + enum nand_data_interface_type type, + int timing_mode) +{ + if (type != NAND_SDR_IFACE) + return -EINVAL; + + if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings)) + return -EINVAL; + + *iface = onfi_sdr_timings[timing_mode]; + + /* + * Initialize timings that cannot be deduced from timing mode: + * tR, tPROG, tCCS, ... + * These information are part of the ONFI parameter page. + */ + if (chip->onfi_version) { + struct nand_onfi_params *params = &chip->onfi_params; + struct nand_sdr_timings *timings = &iface->timings.sdr; + + /* microseconds -> picoseconds */ + timings->tPROG_max = 1000000ULL * le16_to_cpu(params->t_prog); + timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers); + timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r); + + /* nanoseconds -> picoseconds */ + timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs); + } + + return 0; +} +EXPORT_SYMBOL(onfi_init_data_interface); + +/** + * nand_get_default_data_interface - [NAND Interface] Retrieve NAND + * data interface for mode 0. This is used as default timing after + * reset. + */ +const struct nand_data_interface *nand_get_default_data_interface(void) +{ + return &onfi_sdr_timings[0]; +} +EXPORT_SYMBOL(nand_get_default_data_interface); diff --git a/drivers/mtd/nand/raw/nand_util.c b/drivers/mtd/nand/raw/nand_util.c new file mode 100644 index 0000000000..fc2235c1a0 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_util.c @@ -0,0 +1,904 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * drivers/mtd/nand/raw/nand_util.c + * + * Copyright (C) 2006 by Weiss-Electronic GmbH. + * All rights reserved. + * + * @author: Guido Classen + * @descr: NAND Flash support + * @references: borrowed heavily from Linux mtd-utils code: + * flash_eraseall.c by Arcom Control System Ltd + * nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com) + * and Thomas Gleixner (tglx@linutronix.de) + * + * Copyright (C) 2008 Nokia Corporation: drop_ffs() function by + * Artem Bityutskiy from mtd-utils + * + * Copyright 2010 Freescale Semiconductor + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +typedef struct erase_info erase_info_t; +typedef struct mtd_info mtd_info_t; + +/* support only for native endian JFFS2 */ +#define cpu_to_je16(x) (x) +#define cpu_to_je32(x) (x) + +/** + * nand_erase_opts: - erase NAND flash with support for various options + * (jffs2 formatting) + * + * @param mtd nand mtd instance to erase + * @param opts options, @see struct nand_erase_options + * @return 0 in case of success + * + * This code is ported from flash_eraseall.c from Linux mtd utils by + * Arcom Control System Ltd. + */ +int nand_erase_opts(struct mtd_info *mtd, + const nand_erase_options_t *opts) +{ + struct jffs2_unknown_node cleanmarker; + erase_info_t erase; + unsigned long erase_length, erased_length; /* in blocks */ + int result; + int percent_complete = -1; + const char *mtd_device = mtd->name; + struct mtd_oob_ops oob_opts; + struct nand_chip *chip = mtd_to_nand(mtd); + + if ((opts->offset & (mtd->erasesize - 1)) != 0) { + printf("Attempt to erase non block-aligned data\n"); + return -1; + } + + memset(&erase, 0, sizeof(erase)); + memset(&oob_opts, 0, sizeof(oob_opts)); + + erase.mtd = mtd; + erase.len = mtd->erasesize; + erase.addr = opts->offset; + erase_length = lldiv(opts->length + mtd->erasesize - 1, + mtd->erasesize); + + cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); + cleanmarker.totlen = cpu_to_je32(8); + + /* scrub option allows to erase badblock. To prevent internal + * check from erase() method, set block check method to dummy + * and disable bad block table while erasing. + */ + if (opts->scrub) { + erase.scrub = opts->scrub; + /* + * We don't need the bad block table anymore... + * after scrub, there are no bad blocks left! + */ + if (chip->bbt) { + kfree(chip->bbt); + } + chip->bbt = NULL; + chip->options &= ~NAND_BBT_SCANNED; + } + + for (erased_length = 0; + erased_length < erase_length; + erase.addr += mtd->erasesize) { + + WATCHDOG_RESET(); + + if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) { + puts("Size of erase exceeds limit\n"); + return -EFBIG; + } + if (!opts->scrub) { + int ret = mtd_block_isbad(mtd, erase.addr); + if (ret > 0) { + if (!opts->quiet) + printf("\rSkipping bad block at " + "0x%08llx " + " \n", + erase.addr); + + if (!opts->spread) + erased_length++; + + continue; + + } else if (ret < 0) { + printf("\n%s: MTD get bad block failed: %d\n", + mtd_device, + ret); + return -1; + } + } + + erased_length++; + + result = mtd_erase(mtd, &erase); + if (result != 0) { + printf("\n%s: MTD Erase failure: %d\n", + mtd_device, result); + continue; + } + + /* format for JFFS2 ? */ + if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) { + struct mtd_oob_ops ops; + ops.ooblen = 8; + ops.datbuf = NULL; + ops.oobbuf = (uint8_t *)&cleanmarker; + ops.ooboffs = 0; + ops.mode = MTD_OPS_AUTO_OOB; + + result = mtd_write_oob(mtd, erase.addr, &ops); + if (result != 0) { + printf("\n%s: MTD writeoob failure: %d\n", + mtd_device, result); + continue; + } + } + + if (!opts->quiet) { + unsigned long long n = erased_length * 100ULL; + int percent; + + do_div(n, erase_length); + percent = (int)n; + + /* output progress message only at whole percent + * steps to reduce the number of messages printed + * on (slow) serial consoles + */ + if (percent != percent_complete) { + percent_complete = percent; + + printf("\rErasing at 0x%llx -- %3d%% complete.", + erase.addr, percent); + + if (opts->jffs2 && result == 0) + printf(" Cleanmarker written at 0x%llx.", + erase.addr); + } + } + } + if (!opts->quiet) + printf("\n"); + + return 0; +} + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + +#define NAND_CMD_LOCK_TIGHT 0x2c +#define NAND_CMD_LOCK_STATUS 0x7a + +/****************************************************************************** + * Support for locking / unlocking operations of some NAND devices + *****************************************************************************/ + +/** + * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT + * state + * + * @param mtd nand mtd instance + * @param tight bring device in lock tight mode + * + * @return 0 on success, -1 in case of error + * + * The lock / lock-tight command only applies to the whole chip. To get some + * parts of the chip lock and others unlocked use the following sequence: + * + * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin) + * - Call nand_unlock() once for each consecutive area to be unlocked + * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1) + * + * If the device is in lock-tight state software can't change the + * current active lock/unlock state of all pages. nand_lock() / nand_unlock() + * calls will fail. It is only posible to leave lock-tight state by + * an hardware signal (low pulse on _WP pin) or by power down. + */ +int nand_lock(struct mtd_info *mtd, int tight) +{ + int ret = 0; + int status; + struct nand_chip *chip = mtd_to_nand(mtd); + + /* select the NAND device */ + chip->select_chip(mtd, 0); + + /* check the Lock Tight Status */ + chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, 0); + if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { + printf("nand_lock: Device is locked tight!\n"); + ret = -1; + goto out; + } + + chip->cmdfunc(mtd, + (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK), + -1, -1); + + /* call wait ready function */ + status = chip->waitfunc(mtd, chip); + + /* see if device thinks it succeeded */ + if (status & 0x01) { + ret = -1; + } + + out: + /* de-select the NAND device */ + chip->select_chip(mtd, -1); + return ret; +} + +/** + * nand_get_lock_status: - query current lock state from one page of NAND + * flash + * + * @param mtd nand mtd instance + * @param offset page address to query (must be page-aligned!) + * + * @return -1 in case of error + * >0 lock status: + * bitfield with the following combinations: + * NAND_LOCK_STATUS_TIGHT: page in tight state + * NAND_LOCK_STATUS_UNLOCK: page unlocked + * + */ +int nand_get_lock_status(struct mtd_info *mtd, loff_t offset) +{ + int ret = 0; + int chipnr; + int page; + struct nand_chip *chip = mtd_to_nand(mtd); + + /* select the NAND device */ + chipnr = (int)(offset >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + + if ((offset & (mtd->writesize - 1)) != 0) { + printf("nand_get_lock_status: " + "Start address must be beginning of " + "nand page!\n"); + ret = -1; + goto out; + } + + /* check the Lock Status */ + page = (int)(offset >> chip->page_shift); + chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); + + ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT + | NAND_LOCK_STATUS_UNLOCK); + + out: + /* de-select the NAND device */ + chip->select_chip(mtd, -1); + return ret; +} + +/** + * nand_unlock: - Unlock area of NAND pages + * only one consecutive area can be unlocked at one time! + * + * @param mtd nand mtd instance + * @param start start byte address + * @param length number of bytes to unlock (must be a multiple of + * page size mtd->writesize) + * @param allexcept if set, unlock everything not selected + * + * @return 0 on success, -1 in case of error + */ +int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, + int allexcept) +{ + int ret = 0; + int chipnr; + int status; + int page; + struct nand_chip *chip = mtd_to_nand(mtd); + + debug("nand_unlock%s: start: %08llx, length: %zd!\n", + allexcept ? " (allexcept)" : "", start, length); + + /* select the NAND device */ + chipnr = (int)(start >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + /* check the WP bit */ + chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) { + printf("nand_unlock: Device is write protected!\n"); + ret = -1; + goto out; + } + + /* check the Lock Tight Status */ + page = (int)(start >> chip->page_shift); + chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); + if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { + printf("nand_unlock: Device is locked tight!\n"); + ret = -1; + goto out; + } + + if ((start & (mtd->erasesize - 1)) != 0) { + printf("nand_unlock: Start address must be beginning of " + "nand block!\n"); + ret = -1; + goto out; + } + + if (length == 0 || (length & (mtd->erasesize - 1)) != 0) { + printf("nand_unlock: Length must be a multiple of nand block " + "size %08x!\n", mtd->erasesize); + ret = -1; + goto out; + } + + /* + * Set length so that the last address is set to the + * starting address of the last block + */ + length -= mtd->erasesize; + + /* submit address of first page to unlock */ + chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); + + /* submit ADDRESS of LAST page to unlock */ + page += (int)(length >> chip->page_shift); + + /* + * Page addresses for unlocking are supposed to be block-aligned. + * At least some NAND chips use the low bit to indicate that the + * page range should be inverted. + */ + if (allexcept) + page |= 1; + + chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask); + + /* call wait ready function */ + status = chip->waitfunc(mtd, chip); + /* see if device thinks it succeeded */ + if (status & 0x01) { + /* there was an error */ + ret = -1; + goto out; + } + + out: + /* de-select the NAND device */ + chip->select_chip(mtd, -1); + return ret; +} +#endif + +/** + * check_skip_len + * + * Check if there are any bad blocks, and whether length including bad + * blocks fits into device + * + * @param mtd nand mtd instance + * @param offset offset in flash + * @param length image length + * @param used length of flash needed for the requested length + * @return 0 if the image fits and there are no bad blocks + * 1 if the image fits, but there are bad blocks + * -1 if the image does not fit + */ +static int check_skip_len(struct mtd_info *mtd, loff_t offset, size_t length, + size_t *used) +{ + size_t len_excl_bad = 0; + int ret = 0; + + while (len_excl_bad < length) { + size_t block_len, block_off; + loff_t block_start; + + if (offset >= mtd->size) + return -1; + + block_start = offset & ~(loff_t)(mtd->erasesize - 1); + block_off = offset & (mtd->erasesize - 1); + block_len = mtd->erasesize - block_off; + + if (!nand_block_isbad(mtd, block_start)) + len_excl_bad += block_len; + else + ret = 1; + + offset += block_len; + *used += block_len; + } + + /* If the length is not a multiple of block_len, adjust. */ + if (len_excl_bad > length) + *used -= (len_excl_bad - length); + + return ret; +} + +#ifdef CONFIG_CMD_NAND_TRIMFFS +static size_t drop_ffs(const struct mtd_info *mtd, const u_char *buf, + const size_t *len) +{ + size_t l = *len; + ssize_t i; + + for (i = l - 1; i >= 0; i--) + if (buf[i] != 0xFF) + break; + + /* The resulting length must be aligned to the minimum flash I/O size */ + l = i + 1; + l = (l + mtd->writesize - 1) / mtd->writesize; + l *= mtd->writesize; + + /* + * since the input length may be unaligned, prevent access past the end + * of the buffer + */ + return min(l, *len); +} +#endif + +/** + * nand_verify_page_oob: + * + * Verify a page of NAND flash, including the OOB. + * Reads page of NAND and verifies the contents and OOB against the + * values in ops. + * + * @param mtd nand mtd instance + * @param ops MTD operations, including data to verify + * @param ofs offset in flash + * @return 0 in case of success + */ +int nand_verify_page_oob(struct mtd_info *mtd, struct mtd_oob_ops *ops, + loff_t ofs) +{ + int rval; + struct mtd_oob_ops vops; + size_t verlen = mtd->writesize + mtd->oobsize; + + memcpy(&vops, ops, sizeof(vops)); + + vops.datbuf = memalign(ARCH_DMA_MINALIGN, verlen); + + if (!vops.datbuf) + return -ENOMEM; + + vops.oobbuf = vops.datbuf + mtd->writesize; + + rval = mtd_read_oob(mtd, ofs, &vops); + if (!rval) + rval = memcmp(ops->datbuf, vops.datbuf, vops.len); + if (!rval) + rval = memcmp(ops->oobbuf, vops.oobbuf, vops.ooblen); + + free(vops.datbuf); + + return rval ? -EIO : 0; +} + +/** + * nand_verify: + * + * Verify a region of NAND flash. + * Reads NAND in page-sized chunks and verifies the contents against + * the contents of a buffer. The offset into the NAND must be + * page-aligned, and the function doesn't handle skipping bad blocks. + * + * @param mtd nand mtd instance + * @param ofs offset in flash + * @param len buffer length + * @param buf buffer to read from + * @return 0 in case of success + */ +int nand_verify(struct mtd_info *mtd, loff_t ofs, size_t len, u_char *buf) +{ + int rval = 0; + size_t verofs; + size_t verlen = mtd->writesize; + uint8_t *verbuf = memalign(ARCH_DMA_MINALIGN, verlen); + + if (!verbuf) + return -ENOMEM; + + /* Read the NAND back in page-size groups to limit malloc size */ + for (verofs = ofs; verofs < ofs + len; + verofs += verlen, buf += verlen) { + verlen = min(mtd->writesize, (uint32_t)(ofs + len - verofs)); + rval = nand_read(mtd, verofs, &verlen, verbuf); + if (!rval || (rval == -EUCLEAN)) + rval = memcmp(buf, verbuf, verlen); + + if (rval) + break; + } + + free(verbuf); + + return rval ? -EIO : 0; +} + + + +/** + * nand_write_skip_bad: + * + * Write image to NAND flash. + * Blocks that are marked bad are skipped and the is written to the next + * block instead as long as the image is short enough to fit even after + * skipping the bad blocks. Due to bad blocks we may not be able to + * perform the requested write. In the case where the write would + * extend beyond the end of the NAND device, both length and actual (if + * not NULL) are set to 0. In the case where the write would extend + * beyond the limit we are passed, length is set to 0 and actual is set + * to the required length. + * + * @param mtd nand mtd instance + * @param offset offset in flash + * @param length buffer length + * @param actual set to size required to write length worth of + * buffer or 0 on error, if not NULL + * @param lim maximum size that actual may be in order to not + * exceed the buffer + * @param buffer buffer to read from + * @param flags flags modifying the behaviour of the write to NAND + * @return 0 in case of success + */ +int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, + size_t *actual, loff_t lim, u_char *buffer, int flags) +{ + int rval = 0, blocksize; + size_t left_to_write = *length; + size_t used_for_write = 0; + u_char *p_buffer = buffer; + int need_skip; + + if (actual) + *actual = 0; + + blocksize = mtd->erasesize; + + /* + * nand_write() handles unaligned, partial page writes. + * + * We allow length to be unaligned, for convenience in + * using the $filesize variable. + * + * However, starting at an unaligned offset makes the + * semantics of bad block skipping ambiguous (really, + * you should only start a block skipping access at a + * partition boundary). So don't try to handle that. + */ + if ((offset & (mtd->writesize - 1)) != 0) { + printf("Attempt to write non page-aligned data\n"); + *length = 0; + return -EINVAL; + } + + need_skip = check_skip_len(mtd, offset, *length, &used_for_write); + + if (actual) + *actual = used_for_write; + + if (need_skip < 0) { + printf("Attempt to write outside the flash area\n"); + *length = 0; + return -EINVAL; + } + + if (used_for_write > lim) { + puts("Size of write exceeds partition or device limit\n"); + *length = 0; + return -EFBIG; + } + + if (!need_skip && !(flags & WITH_DROP_FFS)) { + rval = nand_write(mtd, offset, length, buffer); + + if ((flags & WITH_WR_VERIFY) && !rval) + rval = nand_verify(mtd, offset, *length, buffer); + + if (rval == 0) + return 0; + + *length = 0; + printf("NAND write to offset %llx failed %d\n", + offset, rval); + return rval; + } + + while (left_to_write > 0) { + size_t block_offset = offset & (mtd->erasesize - 1); + size_t write_size, truncated_write_size; + + WATCHDOG_RESET(); + + if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) { + printf("Skip bad block 0x%08llx\n", + offset & ~(mtd->erasesize - 1)); + offset += mtd->erasesize - block_offset; + continue; + } + + if (left_to_write < (blocksize - block_offset)) + write_size = left_to_write; + else + write_size = blocksize - block_offset; + + truncated_write_size = write_size; +#ifdef CONFIG_CMD_NAND_TRIMFFS + if (flags & WITH_DROP_FFS) + truncated_write_size = drop_ffs(mtd, p_buffer, + &write_size); +#endif + + rval = nand_write(mtd, offset, &truncated_write_size, + p_buffer); + + if ((flags & WITH_WR_VERIFY) && !rval) + rval = nand_verify(mtd, offset, + truncated_write_size, p_buffer); + + offset += write_size; + p_buffer += write_size; + + if (rval != 0) { + printf("NAND write to offset %llx failed %d\n", + offset, rval); + *length -= left_to_write; + return rval; + } + + left_to_write -= write_size; + } + + return 0; +} + +/** + * nand_read_skip_bad: + * + * Read image from NAND flash. + * Blocks that are marked bad are skipped and the next block is read + * instead as long as the image is short enough to fit even after + * skipping the bad blocks. Due to bad blocks we may not be able to + * perform the requested read. In the case where the read would extend + * beyond the end of the NAND device, both length and actual (if not + * NULL) are set to 0. In the case where the read would extend beyond + * the limit we are passed, length is set to 0 and actual is set to the + * required length. + * + * @param mtd nand mtd instance + * @param offset offset in flash + * @param length buffer length, on return holds number of read bytes + * @param actual set to size required to read length worth of buffer or 0 + * on error, if not NULL + * @param lim maximum size that actual may be in order to not exceed the + * buffer + * @param buffer buffer to write to + * @return 0 in case of success + */ +int nand_read_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, + size_t *actual, loff_t lim, u_char *buffer) +{ + int rval; + size_t left_to_read = *length; + size_t used_for_read = 0; + u_char *p_buffer = buffer; + int need_skip; + + if ((offset & (mtd->writesize - 1)) != 0) { + printf("Attempt to read non page-aligned data\n"); + *length = 0; + if (actual) + *actual = 0; + return -EINVAL; + } + + need_skip = check_skip_len(mtd, offset, *length, &used_for_read); + + if (actual) + *actual = used_for_read; + + if (need_skip < 0) { + printf("Attempt to read outside the flash area\n"); + *length = 0; + return -EINVAL; + } + + if (used_for_read > lim) { + puts("Size of read exceeds partition or device limit\n"); + *length = 0; + return -EFBIG; + } + + if (!need_skip) { + rval = nand_read(mtd, offset, length, buffer); + if (!rval || rval == -EUCLEAN) + return 0; + + *length = 0; + printf("NAND read from offset %llx failed %d\n", + offset, rval); + return rval; + } + + while (left_to_read > 0) { + size_t block_offset = offset & (mtd->erasesize - 1); + size_t read_length; + + WATCHDOG_RESET(); + + if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) { + printf("Skipping bad block 0x%08llx\n", + offset & ~(mtd->erasesize - 1)); + offset += mtd->erasesize - block_offset; + continue; + } + + if (left_to_read < (mtd->erasesize - block_offset)) + read_length = left_to_read; + else + read_length = mtd->erasesize - block_offset; + + rval = nand_read(mtd, offset, &read_length, p_buffer); + if (rval && rval != -EUCLEAN) { + printf("NAND read from offset %llx failed %d\n", + offset, rval); + *length -= left_to_read; + return rval; + } + + left_to_read -= read_length; + offset += read_length; + p_buffer += read_length; + } + + return 0; +} + +#ifdef CONFIG_CMD_NAND_TORTURE + +/** + * check_pattern: + * + * Check if buffer contains only a certain byte pattern. + * + * @param buf buffer to check + * @param patt the pattern to check + * @param size buffer size in bytes + * @return 1 if there are only patt bytes in buf + * 0 if something else was found + */ +static int check_pattern(const u_char *buf, u_char patt, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (buf[i] != patt) + return 0; + return 1; +} + +/** + * nand_torture: + * + * Torture a block of NAND flash. + * This is useful to determine if a block that caused a write error is still + * good or should be marked as bad. + * + * @param mtd nand mtd instance + * @param offset offset in flash + * @return 0 if the block is still good + */ +int nand_torture(struct mtd_info *mtd, loff_t offset) +{ + u_char patterns[] = {0xa5, 0x5a, 0x00}; + struct erase_info instr = { + .mtd = mtd, + .addr = offset, + .len = mtd->erasesize, + }; + size_t retlen; + int err, ret = -1, i, patt_count; + u_char *buf; + + if ((offset & (mtd->erasesize - 1)) != 0) { + puts("Attempt to torture a block at a non block-aligned offset\n"); + return -EINVAL; + } + + if (offset + mtd->erasesize > mtd->size) { + puts("Attempt to torture a block outside the flash area\n"); + return -EINVAL; + } + + patt_count = ARRAY_SIZE(patterns); + + buf = malloc_cache_aligned(mtd->erasesize); + if (buf == NULL) { + puts("Out of memory for erase block buffer\n"); + return -ENOMEM; + } + + for (i = 0; i < patt_count; i++) { + err = mtd_erase(mtd, &instr); + if (err) { + printf("%s: erase() failed for block at 0x%llx: %d\n", + mtd->name, instr.addr, err); + goto out; + } + + /* Make sure the block contains only 0xff bytes */ + err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); + if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { + printf("%s: read() failed for block at 0x%llx: %d\n", + mtd->name, instr.addr, err); + goto out; + } + + err = check_pattern(buf, 0xff, mtd->erasesize); + if (!err) { + printf("Erased block at 0x%llx, but a non-0xff byte was found\n", + offset); + ret = -EIO; + goto out; + } + + /* Write a pattern and check it */ + memset(buf, patterns[i], mtd->erasesize); + err = mtd_write(mtd, offset, mtd->erasesize, &retlen, buf); + if (err || retlen != mtd->erasesize) { + printf("%s: write() failed for block at 0x%llx: %d\n", + mtd->name, instr.addr, err); + goto out; + } + + err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); + if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { + printf("%s: read() failed for block at 0x%llx: %d\n", + mtd->name, instr.addr, err); + goto out; + } + + err = check_pattern(buf, patterns[i], mtd->erasesize); + if (!err) { + printf("Pattern 0x%.2x checking failed for block at " + "0x%llx\n", patterns[i], offset); + ret = -EIO; + goto out; + } + } + + ret = 0; + +out: + free(buf); + return ret; +} + +#endif diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c new file mode 100644 index 0000000000..35c6dd1f1b --- /dev/null +++ b/drivers/mtd/nand/raw/omap_elm.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2010-2011 Texas Instruments, + * Mansoor Ahamed + * + * BCH Error Location Module (ELM) support. + * + * NOTE: + * 1. Supports only continuous mode. Dont see need for page mode in uboot + * 2. Supports only syndrome polynomial 0. i.e. poly local variable is + * always set to ELM_DEFAULT_POLY. Dont see need for other polynomial + * sets in uboot + */ + +#include +#include +#include +#include +#include + +#define DRIVER_NAME "omap-elm" +#define ELM_DEFAULT_POLY (0) + +struct elm *elm_cfg; + +/** + * elm_load_syndromes - Load BCH syndromes based on bch_type selection + * @syndrome: BCH syndrome + * @bch_type: BCH4/BCH8/BCH16 + * @poly: Syndrome Polynomial set to use + */ +static void elm_load_syndromes(u8 *syndrome, enum bch_level bch_type, u8 poly) +{ + u32 *ptr; + u32 val; + + /* reg 0 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0]; + val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) | + (syndrome[3] << 24); + writel(val, ptr); + /* reg 1 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1]; + val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) | + (syndrome[7] << 24); + writel(val, ptr); + + if (bch_type == BCH_8_BIT || bch_type == BCH_16_BIT) { + /* reg 2 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2]; + val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) | + (syndrome[11] << 24); + writel(val, ptr); + /* reg 3 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[3]; + val = syndrome[12] | (syndrome[13] << 8) | + (syndrome[14] << 16) | (syndrome[15] << 24); + writel(val, ptr); + } + + if (bch_type == BCH_16_BIT) { + /* reg 4 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4]; + val = syndrome[16] | (syndrome[17] << 8) | + (syndrome[18] << 16) | (syndrome[19] << 24); + writel(val, ptr); + + /* reg 5 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[5]; + val = syndrome[20] | (syndrome[21] << 8) | + (syndrome[22] << 16) | (syndrome[23] << 24); + writel(val, ptr); + + /* reg 6 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]; + val = syndrome[24] | (syndrome[25] << 8) | + (syndrome[26] << 16) | (syndrome[27] << 24); + writel(val, ptr); + } +} + +/** + * elm_check_errors - Check for BCH errors and return error locations + * @syndrome: BCH syndrome + * @bch_type: BCH4/BCH8/BCH16 + * @error_count: Returns number of errrors in the syndrome + * @error_locations: Returns error locations (in decimal) in this array + * + * Check the provided syndrome for BCH errors and return error count + * and locations in the array passed. Returns -1 if error is not correctable, + * else returns 0 + */ +int elm_check_error(u8 *syndrome, enum bch_level bch_type, u32 *error_count, + u32 *error_locations) +{ + u8 poly = ELM_DEFAULT_POLY; + s8 i; + u32 location_status; + + elm_load_syndromes(syndrome, bch_type, poly); + + /* start processing */ + writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]) + | ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID), + &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]); + + /* wait for processing to complete */ + while ((readl(&elm_cfg->irqstatus) & (0x1 << poly)) != 0x1) + ; + /* clear status */ + writel((readl(&elm_cfg->irqstatus) | (0x1 << poly)), + &elm_cfg->irqstatus); + + /* check if correctable */ + location_status = readl(&elm_cfg->error_location[poly].location_status); + if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) { + printf("%s: uncorrectable ECC errors\n", DRIVER_NAME); + return -EBADMSG; + } + + /* get error count */ + *error_count = readl(&elm_cfg->error_location[poly].location_status) & + ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK; + + for (i = 0; i < *error_count; i++) { + error_locations[i] = + readl(&elm_cfg->error_location[poly].error_location_x[i]); + } + + return 0; +} + + +/** + * elm_config - Configure ELM module + * @level: 4 / 8 / 16 bit BCH + * + * Configure ELM module based on BCH level. + * Set mode as continuous mode. + * Currently we are using only syndrome 0 and syndromes 1 to 6 are not used. + * Also, the mode is set only for syndrome 0 + */ +int elm_config(enum bch_level level) +{ + u32 val; + u8 poly = ELM_DEFAULT_POLY; + u32 buffer_size = 0x7FF; + + /* config size and level */ + val = (u32)(level) & ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK; + val |= ((buffer_size << ELM_LOCATION_CONFIG_ECC_SIZE_POS) & + ELM_LOCATION_CONFIG_ECC_SIZE_MASK); + writel(val, &elm_cfg->location_config); + + /* config continous mode */ + /* enable interrupt generation for syndrome polynomial set */ + writel((readl(&elm_cfg->irqenable) | (0x1 << poly)), + &elm_cfg->irqenable); + /* set continuous mode for the syndrome polynomial set */ + writel((readl(&elm_cfg->page_ctrl) & ~(0x1 << poly)), + &elm_cfg->page_ctrl); + + return 0; +} + +/** + * elm_reset - Do a soft reset of ELM + * + * Perform a soft reset of ELM and return after reset is done. + */ +void elm_reset(void) +{ + /* initiate reset */ + writel((readl(&elm_cfg->sysconfig) | ELM_SYSCONFIG_SOFTRESET), + &elm_cfg->sysconfig); + + /* wait for reset complete and normal operation */ + while ((readl(&elm_cfg->sysstatus) & ELM_SYSSTATUS_RESETDONE) != + ELM_SYSSTATUS_RESETDONE) + ; +} + +/** + * elm_init - Initialize ELM module + * + * Initialize ELM support. Currently it does only base address init + * and ELM reset. + */ +void elm_init(void) +{ + elm_cfg = (struct elm *)ELM_BASE; + elm_reset(); +} diff --git a/drivers/mtd/nand/raw/omap_gpmc.c b/drivers/mtd/nand/raw/omap_gpmc.c new file mode 100644 index 0000000000..6a050501b0 --- /dev/null +++ b/drivers/mtd/nand/raw/omap_gpmc.c @@ -0,0 +1,1037 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2004-2008 Texas Instruments, + * Rohit Choraria + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BADBLOCK_MARKER_LENGTH 2 +#define SECTOR_BYTES 512 +#define ECCCLEAR (0x1 << 8) +#define ECCRESULTREG1 (0x1 << 0) +/* 4 bit padding to make byte aligned, 56 = 52 + 4 */ +#define BCH4_BIT_PAD 4 + +#ifdef CONFIG_BCH +static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2, + 0x97, 0x79, 0xe5, 0x24, 0xb5}; +#endif +static uint8_t cs_next; +static __maybe_unused struct nand_ecclayout omap_ecclayout; + +#if defined(CONFIG_NAND_OMAP_GPMC_WSCFG) +static const int8_t wscfg[CONFIG_SYS_MAX_NAND_DEVICE] = + { CONFIG_NAND_OMAP_GPMC_WSCFG }; +#else +/* wscfg is preset to zero since its a static variable */ +static const int8_t wscfg[CONFIG_SYS_MAX_NAND_DEVICE]; +#endif + +/* + * Driver configurations + */ +struct omap_nand_info { + struct bch_control *control; + enum omap_ecc ecc_scheme; + uint8_t cs; + uint8_t ws; /* wait status pin (0,1) */ +}; + +/* We are wasting a bit of memory but al least we are safe */ +static struct omap_nand_info omap_nand_info[GPMC_MAX_CS]; + +/* + * omap_nand_hwcontrol - Set the address pointers corretly for the + * following address/data/command operation + */ +static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd, + uint32_t ctrl) +{ + register struct nand_chip *this = mtd_to_nand(mtd); + struct omap_nand_info *info = nand_get_controller_data(this); + int cs = info->cs; + + /* + * Point the IO_ADDR to DATA and ADDRESS registers instead + * of chip address + */ + switch (ctrl) { + case NAND_CTRL_CHANGE | NAND_CTRL_CLE: + this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; + break; + case NAND_CTRL_CHANGE | NAND_CTRL_ALE: + this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr; + break; + case NAND_CTRL_CHANGE | NAND_NCE: + this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; + break; + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); +} + +/* Check wait pin as dev ready indicator */ +static int omap_dev_ready(struct mtd_info *mtd) +{ + register struct nand_chip *this = mtd_to_nand(mtd); + struct omap_nand_info *info = nand_get_controller_data(this); + return gpmc_cfg->status & (1 << (8 + info->ws)); +} + +/* + * gen_true_ecc - This function will generate true ECC value, which + * can be used when correcting data read from NAND flash memory core + * + * @ecc_buf: buffer to store ecc code + * + * @return: re-formatted ECC value + */ +static uint32_t gen_true_ecc(uint8_t *ecc_buf) +{ + return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) | + ((ecc_buf[2] & 0x0F) << 8); +} + +/* + * omap_correct_data - Compares the ecc read from nand spare area with ECC + * registers values and corrects one bit error if it has occurred + * Further details can be had from OMAP TRM and the following selected links: + * http://en.wikipedia.org/wiki/Hamming_code + * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf + * + * @mtd: MTD device structure + * @dat: page data + * @read_ecc: ecc read from nand flash + * @calc_ecc: ecc read from ECC registers + * + * @return 0 if data is OK or corrected, else returns -1 + */ +static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + uint32_t orig_ecc, new_ecc, res, hm; + uint16_t parity_bits, byte; + uint8_t bit; + + /* Regenerate the orginal ECC */ + orig_ecc = gen_true_ecc(read_ecc); + new_ecc = gen_true_ecc(calc_ecc); + /* Get the XOR of real ecc */ + res = orig_ecc ^ new_ecc; + if (res) { + /* Get the hamming width */ + hm = hweight32(res); + /* Single bit errors can be corrected! */ + if (hm == 12) { + /* Correctable data! */ + parity_bits = res >> 16; + bit = (parity_bits & 0x7); + byte = (parity_bits >> 3) & 0x1FF; + /* Flip the bit to correct */ + dat[byte] ^= (0x1 << bit); + } else if (hm == 1) { + printf("Error: Ecc is wrong\n"); + /* ECC itself is corrupted */ + return 2; + } else { + /* + * hm distance != parity pairs OR one, could mean 2 bit + * error OR potentially be on a blank page.. + * orig_ecc: contains spare area data from nand flash. + * new_ecc: generated ecc while reading data area. + * Note: if the ecc = 0, all data bits from which it was + * generated are 0xFF. + * The 3 byte(24 bits) ecc is generated per 512byte + * chunk of a page. If orig_ecc(from spare area) + * is 0xFF && new_ecc(computed now from data area)=0x0, + * this means that data area is 0xFF and spare area is + * 0xFF. A sure sign of a erased page! + */ + if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000)) + return 0; + printf("Error: Bad compare! failed\n"); + /* detected 2 bit error */ + return -EBADMSG; + } + } + return 0; +} + +/* + * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write + * @mtd: MTD device structure + * @mode: Read/Write mode + */ +__maybe_unused +static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct omap_nand_info *info = nand_get_controller_data(nand); + unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0; + unsigned int ecc_algo = 0; + unsigned int bch_type = 0; + unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00; + u32 ecc_size_config_val = 0; + u32 ecc_config_val = 0; + int cs = info->cs; + + /* configure GPMC for specific ecc-scheme */ + switch (info->ecc_scheme) { + case OMAP_ECC_HAM1_CODE_SW: + return; + case OMAP_ECC_HAM1_CODE_HW: + ecc_algo = 0x0; + bch_type = 0x0; + bch_wrapmode = 0x00; + eccsize0 = 0xFF; + eccsize1 = 0xFF; + break; + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH8_CODE_HW: + ecc_algo = 0x1; + bch_type = 0x1; + if (mode == NAND_ECC_WRITE) { + bch_wrapmode = 0x01; + eccsize0 = 0; /* extra bits in nibbles per sector */ + eccsize1 = 28; /* OOB bits in nibbles per sector */ + } else { + bch_wrapmode = 0x01; + eccsize0 = 26; /* ECC bits in nibbles per sector */ + eccsize1 = 2; /* non-ECC bits in nibbles per sector */ + } + break; + case OMAP_ECC_BCH16_CODE_HW: + ecc_algo = 0x1; + bch_type = 0x2; + if (mode == NAND_ECC_WRITE) { + bch_wrapmode = 0x01; + eccsize0 = 0; /* extra bits in nibbles per sector */ + eccsize1 = 52; /* OOB bits in nibbles per sector */ + } else { + bch_wrapmode = 0x01; + eccsize0 = 52; /* ECC bits in nibbles per sector */ + eccsize1 = 0; /* non-ECC bits in nibbles per sector */ + } + break; + default: + return; + } + /* Clear ecc and enable bits */ + writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control); + /* Configure ecc size for BCH */ + ecc_size_config_val = (eccsize1 << 22) | (eccsize0 << 12); + writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config); + + /* Configure device details for BCH engine */ + ecc_config_val = ((ecc_algo << 16) | /* HAM1 | BCHx */ + (bch_type << 12) | /* BCH4/BCH8/BCH16 */ + (bch_wrapmode << 8) | /* wrap mode */ + (dev_width << 7) | /* bus width */ + (0x0 << 4) | /* number of sectors */ + (cs << 1) | /* ECC CS */ + (0x1)); /* enable ECC */ + writel(ecc_config_val, &gpmc_cfg->ecc_config); +} + +/* + * omap_calculate_ecc - Read ECC result + * @mtd: MTD structure + * @dat: unused + * @ecc_code: ecc_code buffer + * Using noninverted ECC can be considered ugly since writing a blank + * page ie. padding will clear the ECC bytes. This is no problem as + * long nobody is trying to write data on the seemingly unused page. + * Reading an erased page will produce an ECC mismatch between + * generated and read ECC bytes that has to be dealt with separately. + * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC + * is used, the result of read will be 0x0 while the ECC offsets of the + * spare area will be 0xFF which will result in an ECC mismatch. + */ +static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, + uint8_t *ecc_code) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct omap_nand_info *info = nand_get_controller_data(chip); + const uint32_t *ptr; + uint32_t val = 0; + int8_t i = 0, j; + + switch (info->ecc_scheme) { + case OMAP_ECC_HAM1_CODE_HW: + val = readl(&gpmc_cfg->ecc1_result); + ecc_code[0] = val & 0xFF; + ecc_code[1] = (val >> 16) & 0xFF; + ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0); + break; +#ifdef CONFIG_BCH + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: +#endif + case OMAP_ECC_BCH8_CODE_HW: + ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3]; + val = readl(ptr); + ecc_code[i++] = (val >> 0) & 0xFF; + ptr--; + for (j = 0; j < 3; j++) { + val = readl(ptr); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + ptr--; + } + break; + case OMAP_ECC_BCH16_CODE_HW: + val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]); + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + for (j = 3; j >= 0; j--) { + val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j] + ); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + } + break; + default: + return -EINVAL; + } + /* ECC scheme specific syndrome customizations */ + switch (info->ecc_scheme) { + case OMAP_ECC_HAM1_CODE_HW: + break; +#ifdef CONFIG_BCH + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + + for (i = 0; i < chip->ecc.bytes; i++) + *(ecc_code + i) = *(ecc_code + i) ^ + bch8_polynomial[i]; + break; +#endif + case OMAP_ECC_BCH8_CODE_HW: + ecc_code[chip->ecc.bytes - 1] = 0x00; + break; + case OMAP_ECC_BCH16_CODE_HW: + break; + default: + return -EINVAL; + } + return 0; +} + +#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH + +#define PREFETCH_CONFIG1_CS_SHIFT 24 +#define PREFETCH_FIFOTHRESHOLD_MAX 0x40 +#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8) +#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff) +#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F) +#define ENABLE_PREFETCH (1 << 7) + +/** + * omap_prefetch_enable - configures and starts prefetch transfer + * @fifo_th: fifo threshold to be used for read/ write + * @count: number of bytes to be transferred + * @is_write: prefetch read(0) or write post(1) mode + * @cs: chip select to use + */ +static int omap_prefetch_enable(int fifo_th, unsigned int count, int is_write, int cs) +{ + uint32_t val; + + if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) + return -EINVAL; + + if (readl(&gpmc_cfg->prefetch_control)) + return -EBUSY; + + /* Set the amount of bytes to be prefetched */ + writel(count, &gpmc_cfg->prefetch_config2); + + val = (cs << PREFETCH_CONFIG1_CS_SHIFT) | (is_write & 1) | + PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH; + writel(val, &gpmc_cfg->prefetch_config1); + + /* Start the prefetch engine */ + writel(1, &gpmc_cfg->prefetch_control); + + return 0; +} + +/** + * omap_prefetch_reset - disables and stops the prefetch engine + */ +static void omap_prefetch_reset(void) +{ + writel(0, &gpmc_cfg->prefetch_control); + writel(0, &gpmc_cfg->prefetch_config1); +} + +static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int len) +{ + int ret; + uint32_t cnt; + struct omap_nand_info *info = nand_get_controller_data(chip); + + ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0, info->cs); + if (ret < 0) + return ret; + + do { + int i; + + cnt = readl(&gpmc_cfg->prefetch_status); + cnt = PREFETCH_STATUS_FIFO_CNT(cnt); + + for (i = 0; i < cnt / 4; i++) { + *buf++ = readl(CONFIG_SYS_NAND_BASE); + len -= 4; + } + } while (len); + + omap_prefetch_reset(); + + return 0; +} + +static inline void omap_nand_read(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + if (chip->options & NAND_BUSWIDTH_16) + nand_read_buf16(mtd, buf, len); + else + nand_read_buf(mtd, buf, len); +} + +static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int ret; + uint32_t head, tail; + struct nand_chip *chip = mtd_to_nand(mtd); + + /* + * If the destination buffer is unaligned, start with reading + * the overlap byte-wise. + */ + head = ((uint32_t) buf) % 4; + if (head) { + omap_nand_read(mtd, buf, head); + buf += head; + len -= head; + } + + /* + * Only transfer multiples of 4 bytes in a pre-fetched fashion. + * If there's a residue, care for it byte-wise afterwards. + */ + tail = len % 4; + + ret = __read_prefetch_aligned(chip, (uint32_t *)buf, len - tail); + if (ret < 0) { + /* fallback in case the prefetch engine is busy */ + omap_nand_read(mtd, buf, len); + } else if (tail) { + buf += len - tail; + omap_nand_read(mtd, buf, tail); + } +} +#endif /* CONFIG_NAND_OMAP_GPMC_PREFETCH */ + +#ifdef CONFIG_NAND_OMAP_ELM +/* + * omap_reverse_list - re-orders list elements in reverse order [internal] + * @list: pointer to start of list + * @length: length of list +*/ +static void omap_reverse_list(u8 *list, unsigned int length) +{ + unsigned int i, j; + unsigned int half_length = length / 2; + u8 tmp; + for (i = 0, j = length - 1; i < half_length; i++, j--) { + tmp = list[i]; + list[i] = list[j]; + list[j] = tmp; + } +} + +/* + * omap_correct_data_bch - Compares the ecc read from nand spare area + * with ECC registers values and corrects one bit error if it has occurred + * + * @mtd: MTD device structure + * @dat: page data + * @read_ecc: ecc read from nand flash (ignored) + * @calc_ecc: ecc read from ECC registers + * + * @return 0 if data is OK or corrected, else returns -1 + */ +static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct omap_nand_info *info = nand_get_controller_data(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + uint32_t error_count = 0, error_max; + uint32_t error_loc[ELM_MAX_ERROR_COUNT]; + enum bch_level bch_type; + uint32_t i, ecc_flag = 0; + uint8_t count; + uint32_t byte_pos, bit_pos; + int err = 0; + + /* check calculated ecc */ + for (i = 0; i < ecc->bytes && !ecc_flag; i++) { + if (calc_ecc[i] != 0x00) + ecc_flag = 1; + } + if (!ecc_flag) + return 0; + + /* check for whether its a erased-page */ + ecc_flag = 0; + for (i = 0; i < ecc->bytes && !ecc_flag; i++) { + if (read_ecc[i] != 0xff) + ecc_flag = 1; + } + if (!ecc_flag) + return 0; + + /* + * while reading ECC result we read it in big endian. + * Hence while loading to ELM we have rotate to get the right endian. + */ + switch (info->ecc_scheme) { + case OMAP_ECC_BCH8_CODE_HW: + bch_type = BCH_8_BIT; + omap_reverse_list(calc_ecc, ecc->bytes - 1); + break; + case OMAP_ECC_BCH16_CODE_HW: + bch_type = BCH_16_BIT; + omap_reverse_list(calc_ecc, ecc->bytes); + break; + default: + return -EINVAL; + } + /* use elm module to check for errors */ + elm_config(bch_type); + err = elm_check_error(calc_ecc, bch_type, &error_count, error_loc); + if (err) + return err; + + /* correct bch error */ + for (count = 0; count < error_count; count++) { + switch (info->ecc_scheme) { + case OMAP_ECC_BCH8_CODE_HW: + /* 14th byte in ECC is reserved to match ROM layout */ + error_max = SECTOR_BYTES + (ecc->bytes - 1); + break; + case OMAP_ECC_BCH16_CODE_HW: + error_max = SECTOR_BYTES + ecc->bytes; + break; + default: + return -EINVAL; + } + byte_pos = error_max - (error_loc[count] / 8) - 1; + bit_pos = error_loc[count] % 8; + if (byte_pos < SECTOR_BYTES) { + dat[byte_pos] ^= 1 << bit_pos; + debug("nand: bit-flip corrected @data=%d\n", byte_pos); + } else if (byte_pos < error_max) { + read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos; + debug("nand: bit-flip corrected @oob=%d\n", byte_pos - + SECTOR_BYTES); + } else { + err = -EBADMSG; + printf("nand: error: invalid bit-flip location\n"); + } + } + return (err) ? err : error_count; +} + +/** + * omap_read_page_bch - hardware ecc based page read function + * @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 + * @page: page number to read + * + */ +static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *oob = chip->oob_poi; + uint32_t data_pos; + uint32_t oob_pos; + + data_pos = 0; + /* oob area start */ + oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0]; + oob += chip->ecc.layout->eccpos[0]; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize, + oob += eccbytes) { + chip->ecc.hwctl(mtd, NAND_ECC_READ); + /* read data */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1); + chip->read_buf(mtd, p, eccsize); + + /* read respective ecc from oob area */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1); + chip->read_buf(mtd, oob, eccbytes); + /* read syndrome */ + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + data_pos += eccsize; + oob_pos += eccbytes; + } + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + eccsteps = chip->ecc.steps; + p = buf; + + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} +#endif /* CONFIG_NAND_OMAP_ELM */ + +/* + * OMAP3 BCH8 support (with BCH library) + */ +#ifdef CONFIG_BCH +/** + * omap_correct_data_bch_sw - Decode received data and correct errors + * @mtd: MTD device structure + * @data: page data + * @read_ecc: ecc read from nand flash + * @calc_ecc: ecc read from HW ECC registers + */ +static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data, + u_char *read_ecc, u_char *calc_ecc) +{ + int i, count; + /* cannot correct more than 8 errors */ + unsigned int errloc[8]; + struct nand_chip *chip = mtd_to_nand(mtd); + struct omap_nand_info *info = nand_get_controller_data(chip); + + count = decode_bch(info->control, NULL, SECTOR_BYTES, + read_ecc, calc_ecc, NULL, errloc); + if (count > 0) { + /* correct errors */ + for (i = 0; i < count; i++) { + /* correct data only, not ecc bytes */ + if (errloc[i] < SECTOR_BYTES << 3) + data[errloc[i] >> 3] ^= 1 << (errloc[i] & 7); + debug("corrected bitflip %u\n", errloc[i]); +#ifdef DEBUG + puts("read_ecc: "); + /* + * BCH8 have 13 bytes of ECC; BCH4 needs adoption + * here! + */ + for (i = 0; i < 13; i++) + printf("%02x ", read_ecc[i]); + puts("\n"); + puts("calc_ecc: "); + for (i = 0; i < 13; i++) + printf("%02x ", calc_ecc[i]); + puts("\n"); +#endif + } + } else if (count < 0) { + puts("ecc unrecoverable error\n"); + } + return count; +} + +/** + * omap_free_bch - Release BCH ecc resources + * @mtd: MTD device structure + */ +static void __maybe_unused omap_free_bch(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct omap_nand_info *info = nand_get_controller_data(chip); + + if (info->control) { + free_bch(info->control); + info->control = NULL; + } +} +#endif /* CONFIG_BCH */ + +/** + * omap_select_ecc_scheme - configures driver for particular ecc-scheme + * @nand: NAND chip device structure + * @ecc_scheme: ecc scheme to configure + * @pagesize: number of main-area bytes per page of NAND device + * @oobsize: number of OOB/spare bytes per page of NAND device + */ +static int omap_select_ecc_scheme(struct nand_chip *nand, + enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) { + struct omap_nand_info *info = nand_get_controller_data(nand); + struct nand_ecclayout *ecclayout = &omap_ecclayout; + int eccsteps = pagesize / SECTOR_BYTES; + int i; + + switch (ecc_scheme) { + case OMAP_ECC_HAM1_CODE_SW: + debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n"); + /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are + * initialized in nand_scan_tail(), so just set ecc.mode */ + info->control = NULL; + nand->ecc.mode = NAND_ECC_SOFT; + nand->ecc.layout = NULL; + nand->ecc.size = 0; + break; + + case OMAP_ECC_HAM1_CODE_HW: + debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n"); + /* check ecc-scheme requirements before updating ecc info */ + if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { + printf("nand: error: insufficient OOB: require=%d\n", ( + (3 * eccsteps) + BADBLOCK_MARKER_LENGTH)); + return -EINVAL; + } + info->control = NULL; + /* populate ecc specific fields */ + memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.strength = 1; + nand->ecc.size = SECTOR_BYTES; + nand->ecc.bytes = 3; + nand->ecc.hwctl = omap_enable_hwecc; + nand->ecc.correct = omap_correct_data; + nand->ecc.calculate = omap_calculate_ecc; + /* define ecc-layout */ + ecclayout->eccbytes = nand->ecc.bytes * eccsteps; + for (i = 0; i < ecclayout->eccbytes; i++) { + if (nand->options & NAND_BUSWIDTH_16) + ecclayout->eccpos[i] = i + 2; + else + ecclayout->eccpos[i] = i + 1; + } + ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - + BADBLOCK_MARKER_LENGTH; + break; + + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: +#ifdef CONFIG_BCH + debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); + /* check ecc-scheme requirements before updating ecc info */ + if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { + printf("nand: error: insufficient OOB: require=%d\n", ( + (13 * eccsteps) + BADBLOCK_MARKER_LENGTH)); + return -EINVAL; + } + /* check if BCH S/W library can be used for error detection */ + info->control = init_bch(13, 8, 0x201b); + if (!info->control) { + printf("nand: error: could not init_bch()\n"); + return -ENODEV; + } + /* populate ecc specific fields */ + memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.strength = 8; + nand->ecc.size = SECTOR_BYTES; + nand->ecc.bytes = 13; + nand->ecc.hwctl = omap_enable_hwecc; + nand->ecc.correct = omap_correct_data_bch_sw; + nand->ecc.calculate = omap_calculate_ecc; + /* define ecc-layout */ + ecclayout->eccbytes = nand->ecc.bytes * eccsteps; + ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; + for (i = 1; i < ecclayout->eccbytes; i++) { + if (i % nand->ecc.bytes) + ecclayout->eccpos[i] = + ecclayout->eccpos[i - 1] + 1; + else + ecclayout->eccpos[i] = + ecclayout->eccpos[i - 1] + 2; + } + ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - + BADBLOCK_MARKER_LENGTH; + break; +#else + printf("nand: error: CONFIG_BCH required for ECC\n"); + return -EINVAL; +#endif + + case OMAP_ECC_BCH8_CODE_HW: +#ifdef CONFIG_NAND_OMAP_ELM + debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n"); + /* check ecc-scheme requirements before updating ecc info */ + if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { + printf("nand: error: insufficient OOB: require=%d\n", ( + (14 * eccsteps) + BADBLOCK_MARKER_LENGTH)); + return -EINVAL; + } + /* intialize ELM for ECC error detection */ + elm_init(); + info->control = NULL; + /* populate ecc specific fields */ + memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.strength = 8; + nand->ecc.size = SECTOR_BYTES; + nand->ecc.bytes = 14; + nand->ecc.hwctl = omap_enable_hwecc; + nand->ecc.correct = omap_correct_data_bch; + nand->ecc.calculate = omap_calculate_ecc; + nand->ecc.read_page = omap_read_page_bch; + /* define ecc-layout */ + ecclayout->eccbytes = nand->ecc.bytes * eccsteps; + for (i = 0; i < ecclayout->eccbytes; i++) + ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - + BADBLOCK_MARKER_LENGTH; + break; +#else + printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); + return -EINVAL; +#endif + + case OMAP_ECC_BCH16_CODE_HW: +#ifdef CONFIG_NAND_OMAP_ELM + debug("nand: using OMAP_ECC_BCH16_CODE_HW\n"); + /* check ecc-scheme requirements before updating ecc info */ + if ((26 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { + printf("nand: error: insufficient OOB: require=%d\n", ( + (26 * eccsteps) + BADBLOCK_MARKER_LENGTH)); + return -EINVAL; + } + /* intialize ELM for ECC error detection */ + elm_init(); + /* populate ecc specific fields */ + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.size = SECTOR_BYTES; + nand->ecc.bytes = 26; + nand->ecc.strength = 16; + nand->ecc.hwctl = omap_enable_hwecc; + nand->ecc.correct = omap_correct_data_bch; + nand->ecc.calculate = omap_calculate_ecc; + nand->ecc.read_page = omap_read_page_bch; + /* define ecc-layout */ + ecclayout->eccbytes = nand->ecc.bytes * eccsteps; + for (i = 0; i < ecclayout->eccbytes; i++) + ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes - + BADBLOCK_MARKER_LENGTH; + break; +#else + printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); + return -EINVAL; +#endif + default: + debug("nand: error: ecc scheme not enabled or supported\n"); + return -EINVAL; + } + + /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */ + if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW) + nand->ecc.layout = ecclayout; + + info->ecc_scheme = ecc_scheme; + return 0; +} + +#ifndef CONFIG_SPL_BUILD +/* + * omap_nand_switch_ecc - switch the ECC operation between different engines + * (h/w and s/w) and different algorithms (hamming and BCHx) + * + * @hardware - true if one of the HW engines should be used + * @eccstrength - the number of bits that could be corrected + * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16) + */ +int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength) +{ + struct nand_chip *nand; + struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device); + int err = 0; + + if (!mtd) { + printf("nand: error: no NAND devices found\n"); + return -ENODEV; + } + + nand = mtd_to_nand(mtd); + nand->options |= NAND_OWN_BUFFERS; + nand->options &= ~NAND_SUBPAGE_READ; + /* Setup the ecc configurations again */ + if (hardware) { + if (eccstrength == 1) { + err = omap_select_ecc_scheme(nand, + OMAP_ECC_HAM1_CODE_HW, + mtd->writesize, mtd->oobsize); + } else if (eccstrength == 8) { + err = omap_select_ecc_scheme(nand, + OMAP_ECC_BCH8_CODE_HW, + mtd->writesize, mtd->oobsize); + } else if (eccstrength == 16) { + err = omap_select_ecc_scheme(nand, + OMAP_ECC_BCH16_CODE_HW, + mtd->writesize, mtd->oobsize); + } else { + printf("nand: error: unsupported ECC scheme\n"); + return -EINVAL; + } + } else { + if (eccstrength == 1) { + err = omap_select_ecc_scheme(nand, + OMAP_ECC_HAM1_CODE_SW, + mtd->writesize, mtd->oobsize); + } else if (eccstrength == 8) { + err = omap_select_ecc_scheme(nand, + OMAP_ECC_BCH8_CODE_HW_DETECTION_SW, + mtd->writesize, mtd->oobsize); + } else { + printf("nand: error: unsupported ECC scheme\n"); + return -EINVAL; + } + } + + /* Update NAND handling after ECC mode switch */ + if (!err) + err = nand_scan_tail(mtd); + return err; +} +#endif /* CONFIG_SPL_BUILD */ + +/* + * Board-specific NAND initialization. The following members of the + * argument are board-specific: + * - 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 + * - cmd_ctrl: hardwarespecific function for accesing control-lines + * - waitfunc: hardwarespecific function for accesing device ready/busy line + * - ecc.hwctl: function to enable (reset) hardware ecc generator + * - ecc.mode: mode of ecc, see defines + * - chip_delay: chip dependent delay for transfering data from array to + * read regs (tR) + * - options: various chip options. They can partly be set to inform + * nand_scan about special functionality. See the defines for further + * explanation + */ +int board_nand_init(struct nand_chip *nand) +{ + int32_t gpmc_config = 0; + int cs = cs_next++; + int err = 0; + /* + * xloader/Uboot's gpmc configuration would have configured GPMC for + * nand type of memory. The following logic scans and latches on to the + * first CS with NAND type memory. + * TBD: need to make this logic generic to handle multiple CS NAND + * devices. + */ + while (cs < GPMC_MAX_CS) { + /* Check if NAND type is set */ + if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) { + /* Found it!! */ + break; + } + cs++; + } + if (cs >= GPMC_MAX_CS) { + printf("nand: error: Unable to find NAND settings in " + "GPMC Configuration - quitting\n"); + return -ENODEV; + } + + gpmc_config = readl(&gpmc_cfg->config); + /* Disable Write protect */ + gpmc_config |= 0x10; + writel(gpmc_config, &gpmc_cfg->config); + + nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; + nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; + omap_nand_info[cs].control = NULL; + omap_nand_info[cs].cs = cs; + omap_nand_info[cs].ws = wscfg[cs]; + nand_set_controller_data(nand, &omap_nand_info[cs]); + nand->cmd_ctrl = omap_nand_hwcontrol; + nand->options |= NAND_NO_PADDING | NAND_CACHEPRG; + nand->chip_delay = 100; + nand->ecc.layout = &omap_ecclayout; + + /* configure driver and controller based on NAND device bus-width */ + gpmc_config = readl(&gpmc_cfg->cs[cs].config1); +#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT) + nand->options |= NAND_BUSWIDTH_16; + writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1); +#else + nand->options &= ~NAND_BUSWIDTH_16; + writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1); +#endif + /* select ECC scheme */ +#if defined(CONFIG_NAND_OMAP_ECCSCHEME) + err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME, + CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); +#else + /* pagesize and oobsize are not required to configure sw ecc-scheme */ + err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW, + 0, 0); +#endif + if (err) + return err; + +#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH + nand->read_buf = omap_nand_read_prefetch; +#else + if (nand->options & NAND_BUSWIDTH_16) + nand->read_buf = nand_read_buf16; + else + nand->read_buf = nand_read_buf; +#endif + + nand->dev_ready = omap_dev_ready; + + return 0; +} diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c new file mode 100644 index 0000000000..4c783f1e1e --- /dev/null +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -0,0 +1,1828 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * drivers/mtd/nand/raw/pxa3xx_nand.c + * + * Copyright © 2005 Intel Corporation + * Copyright © 2006 Marvell International Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pxa3xx_nand.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define TIMEOUT_DRAIN_FIFO 5 /* in ms */ +#define CHIP_DELAY_TIMEOUT 200 +#define NAND_STOP_DELAY 40 + +/* + * Define a buffer size for the initial command that detects the flash device: + * STATUS, READID and PARAM. + * ONFI param page is 256 bytes, and there are three redundant copies + * to be read. JEDEC param page is 512 bytes, and there are also three + * redundant copies to be read. + * Hence this buffer should be at least 512 x 3. Let's pick 2048. + */ +#define INIT_BUFFER_SIZE 2048 + +/* registers and bit definitions */ +#define NDCR (0x00) /* Control register */ +#define NDTR0CS0 (0x04) /* Timing Parameter 0 for CS0 */ +#define NDTR1CS0 (0x0C) /* Timing Parameter 1 for CS0 */ +#define NDSR (0x14) /* Status Register */ +#define NDPCR (0x18) /* Page Count Register */ +#define NDBDR0 (0x1C) /* Bad Block Register 0 */ +#define NDBDR1 (0x20) /* Bad Block Register 1 */ +#define NDECCCTRL (0x28) /* ECC control */ +#define NDDB (0x40) /* Data Buffer */ +#define NDCB0 (0x48) /* Command Buffer0 */ +#define NDCB1 (0x4C) /* Command Buffer1 */ +#define NDCB2 (0x50) /* Command Buffer2 */ + +#define NDCR_SPARE_EN (0x1 << 31) +#define NDCR_ECC_EN (0x1 << 30) +#define NDCR_DMA_EN (0x1 << 29) +#define NDCR_ND_RUN (0x1 << 28) +#define NDCR_DWIDTH_C (0x1 << 27) +#define NDCR_DWIDTH_M (0x1 << 26) +#define NDCR_PAGE_SZ (0x1 << 24) +#define NDCR_NCSX (0x1 << 23) +#define NDCR_ND_MODE (0x3 << 21) +#define NDCR_NAND_MODE (0x0) +#define NDCR_CLR_PG_CNT (0x1 << 20) +#define NFCV1_NDCR_ARB_CNTL (0x1 << 19) +#define NDCR_RD_ID_CNT_MASK (0x7 << 16) +#define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK) + +#define NDCR_RA_START (0x1 << 15) +#define NDCR_PG_PER_BLK (0x1 << 14) +#define NDCR_ND_ARB_EN (0x1 << 12) +#define NDCR_INT_MASK (0xFFF) + +#define NDSR_MASK (0xfff) +#define NDSR_ERR_CNT_OFF (16) +#define NDSR_ERR_CNT_MASK (0x1f) +#define NDSR_ERR_CNT(sr) ((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK) +#define NDSR_RDY (0x1 << 12) +#define NDSR_FLASH_RDY (0x1 << 11) +#define NDSR_CS0_PAGED (0x1 << 10) +#define NDSR_CS1_PAGED (0x1 << 9) +#define NDSR_CS0_CMDD (0x1 << 8) +#define NDSR_CS1_CMDD (0x1 << 7) +#define NDSR_CS0_BBD (0x1 << 6) +#define NDSR_CS1_BBD (0x1 << 5) +#define NDSR_UNCORERR (0x1 << 4) +#define NDSR_CORERR (0x1 << 3) +#define NDSR_WRDREQ (0x1 << 2) +#define NDSR_RDDREQ (0x1 << 1) +#define NDSR_WRCMDREQ (0x1) + +#define NDCB0_LEN_OVRD (0x1 << 28) +#define NDCB0_ST_ROW_EN (0x1 << 26) +#define NDCB0_AUTO_RS (0x1 << 25) +#define NDCB0_CSEL (0x1 << 24) +#define NDCB0_EXT_CMD_TYPE_MASK (0x7 << 29) +#define NDCB0_EXT_CMD_TYPE(x) (((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK) +#define NDCB0_CMD_TYPE_MASK (0x7 << 21) +#define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK) +#define NDCB0_NC (0x1 << 20) +#define NDCB0_DBC (0x1 << 19) +#define NDCB0_ADDR_CYC_MASK (0x7 << 16) +#define NDCB0_ADDR_CYC(x) (((x) << 16) & NDCB0_ADDR_CYC_MASK) +#define NDCB0_CMD2_MASK (0xff << 8) +#define NDCB0_CMD1_MASK (0xff) +#define NDCB0_ADDR_CYC_SHIFT (16) + +#define EXT_CMD_TYPE_DISPATCH 6 /* Command dispatch */ +#define EXT_CMD_TYPE_NAKED_RW 5 /* Naked read or Naked write */ +#define EXT_CMD_TYPE_READ 4 /* Read */ +#define EXT_CMD_TYPE_DISP_WR 4 /* Command dispatch with write */ +#define EXT_CMD_TYPE_FINAL 3 /* Final command */ +#define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ +#define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */ + +/* + * This should be large enough to read 'ONFI' and 'JEDEC'. + * Let's use 7 bytes, which is the maximum ID count supported + * by the controller (see NDCR_RD_ID_CNT_MASK). + */ +#define READ_ID_BYTES 7 + +/* macros for registers read/write */ +#define nand_writel(info, off, val) \ + writel((val), (info)->mmio_base + (off)) + +#define nand_readl(info, off) \ + readl((info)->mmio_base + (off)) + +/* error code and state */ +enum { + ERR_NONE = 0, + ERR_DMABUSERR = -1, + ERR_SENDCMD = -2, + ERR_UNCORERR = -3, + ERR_BBERR = -4, + ERR_CORERR = -5, +}; + +enum { + STATE_IDLE = 0, + STATE_PREPARED, + STATE_CMD_HANDLE, + STATE_DMA_READING, + STATE_DMA_WRITING, + STATE_DMA_DONE, + STATE_PIO_READING, + STATE_PIO_WRITING, + STATE_CMD_DONE, + STATE_READY, +}; + +enum pxa3xx_nand_variant { + PXA3XX_NAND_VARIANT_PXA, + PXA3XX_NAND_VARIANT_ARMADA370, +}; + +struct pxa3xx_nand_host { + struct nand_chip chip; + void *info_data; + + /* page size of attached chip */ + int use_ecc; + int cs; + + /* calculated from pxa3xx_nand_flash data */ + unsigned int col_addr_cycles; + unsigned int row_addr_cycles; +}; + +struct pxa3xx_nand_info { + struct nand_hw_control controller; + struct pxa3xx_nand_platform_data *pdata; + + struct clk *clk; + void __iomem *mmio_base; + unsigned long mmio_phys; + int cmd_complete, dev_ready; + + unsigned int buf_start; + unsigned int buf_count; + unsigned int buf_size; + unsigned int data_buff_pos; + unsigned int oob_buff_pos; + + unsigned char *data_buff; + unsigned char *oob_buff; + + struct pxa3xx_nand_host *host[NUM_CHIP_SELECT]; + unsigned int state; + + /* + * This driver supports NFCv1 (as found in PXA SoC) + * and NFCv2 (as found in Armada 370/XP SoC). + */ + enum pxa3xx_nand_variant variant; + + int cs; + int use_ecc; /* use HW ECC ? */ + int ecc_bch; /* using BCH ECC? */ + int use_spare; /* use spare ? */ + int need_wait; + + /* Amount of real data per full chunk */ + unsigned int chunk_size; + + /* Amount of spare data per full chunk */ + unsigned int spare_size; + + /* Number of full chunks (i.e chunk_size + spare_size) */ + unsigned int nfullchunks; + + /* + * Total number of chunks. If equal to nfullchunks, then there + * are only full chunks. Otherwise, there is one last chunk of + * size (last_chunk_size + last_spare_size) + */ + unsigned int ntotalchunks; + + /* Amount of real data in the last chunk */ + unsigned int last_chunk_size; + + /* Amount of spare data in the last chunk */ + unsigned int last_spare_size; + + unsigned int ecc_size; + unsigned int ecc_err_cnt; + unsigned int max_bitflips; + int retcode; + + /* + * Variables only valid during command + * execution. step_chunk_size and step_spare_size is the + * amount of real data and spare data in the current + * chunk. cur_chunk is the current chunk being + * read/programmed. + */ + unsigned int step_chunk_size; + unsigned int step_spare_size; + unsigned int cur_chunk; + + /* cached register value */ + uint32_t reg_ndcr; + uint32_t ndtr0cs0; + uint32_t ndtr1cs0; + + /* generated NDCBx register values */ + uint32_t ndcb0; + uint32_t ndcb1; + uint32_t ndcb2; + uint32_t ndcb3; +}; + +static struct pxa3xx_nand_timing timing[] = { + /* + * tCH Enable signal hold time + * tCS Enable signal setup time + * tWH ND_nWE high duration + * tWP ND_nWE pulse time + * tRH ND_nRE high duration + * tRP ND_nRE pulse width + * tR ND_nWE high to ND_nRE low for read + * tWHR ND_nWE high to ND_nRE low for status read + * tAR ND_ALE low to ND_nRE low delay + */ + /*ch cs wh wp rh rp r whr ar */ + { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, + { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, + { 10, 25, 15, 25, 15, 30, 25000, 60, 10, }, + { 10, 35, 15, 25, 15, 25, 25000, 60, 10, }, + { 5, 20, 10, 12, 10, 12, 25000, 60, 10, }, +}; + +static struct pxa3xx_nand_flash builtin_flash_types[] = { + /* + * chip_id + * flash_width Width of Flash memory (DWIDTH_M) + * dfc_width Width of flash controller(DWIDTH_C) + * *timing + * http://www.linux-mtd.infradead.org/nand-data/nanddata.html + */ + { 0x46ec, 16, 16, &timing[1] }, + { 0xdaec, 8, 8, &timing[1] }, + { 0xd7ec, 8, 8, &timing[1] }, + { 0xa12c, 8, 8, &timing[2] }, + { 0xb12c, 16, 16, &timing[2] }, + { 0xdc2c, 8, 8, &timing[2] }, + { 0xcc2c, 16, 16, &timing[2] }, + { 0xba20, 16, 16, &timing[3] }, + { 0xda98, 8, 8, &timing[4] }, +}; + +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT +static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' }; +static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 8, + .len = 6, + .veroffs = 14, + .maxblocks = 8, /* Last 8 blocks in each chip */ + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 8, + .len = 6, + .veroffs = 14, + .maxblocks = 8, /* Last 8 blocks in each chip */ + .pattern = bbt_mirror_pattern +}; +#endif + +static struct nand_ecclayout ecc_layout_2KB_bch4bit = { + .eccbytes = 32, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { {2, 30} } +}; + +static struct nand_ecclayout ecc_layout_2KB_bch8bit = { + .eccbytes = 64, + .eccpos = { + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}, + .oobfree = { {1, 4}, {6, 26} } +}; + +static struct nand_ecclayout ecc_layout_4KB_bch4bit = { + .eccbytes = 64, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}, + /* Bootrom looks in bytes 0 & 5 for bad blocks */ + .oobfree = { {6, 26}, { 64, 32} } +}; + +static struct nand_ecclayout ecc_layout_8KB_bch4bit = { + .eccbytes = 128, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + + 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255}, + + /* Bootrom looks in bytes 0 & 5 for bad blocks */ + .oobfree = { {1, 4}, {6, 26}, { 64, 32}, {128, 32}, {192, 32} } +}; + +static struct nand_ecclayout ecc_layout_4KB_bch8bit = { + .eccbytes = 128, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { } +}; + +static struct nand_ecclayout ecc_layout_8KB_bch8bit = { + .eccbytes = 256, + .eccpos = {}, + /* HW ECC handles all ECC data and all spare area is free for OOB */ + .oobfree = {{0, 160} } +}; + +#define NDTR0_tCH(c) (min((c), 7) << 19) +#define NDTR0_tCS(c) (min((c), 7) << 16) +#define NDTR0_tWH(c) (min((c), 7) << 11) +#define NDTR0_tWP(c) (min((c), 7) << 8) +#define NDTR0_tRH(c) (min((c), 7) << 3) +#define NDTR0_tRP(c) (min((c), 7) << 0) + +#define NDTR1_tR(c) (min((c), 65535) << 16) +#define NDTR1_tWHR(c) (min((c), 15) << 4) +#define NDTR1_tAR(c) (min((c), 15) << 0) + +/* convert nano-seconds to nand flash controller clock cycles */ +#define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) + +static enum pxa3xx_nand_variant pxa3xx_nand_get_variant(void) +{ + /* We only support the Armada 370/XP/38x for now */ + return PXA3XX_NAND_VARIANT_ARMADA370; +} + +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, + const struct pxa3xx_nand_timing *t) +{ + struct pxa3xx_nand_info *info = host->info_data; + unsigned long nand_clk = mvebu_get_nand_clock(); + uint32_t ndtr0, ndtr1; + + ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) | + NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) | + NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) | + NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) | + NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) | + NDTR0_tRP(ns2cycle(t->tRP, nand_clk)); + + ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) | + NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | + NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); + + info->ndtr0cs0 = ndtr0; + info->ndtr1cs0 = ndtr1; + nand_writel(info, NDTR0CS0, ndtr0); + nand_writel(info, NDTR1CS0, ndtr1); +} + +static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, + const struct nand_sdr_timings *t) +{ + struct pxa3xx_nand_info *info = host->info_data; + struct nand_chip *chip = &host->chip; + unsigned long nand_clk = mvebu_get_nand_clock(); + uint32_t ndtr0, ndtr1; + + u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000); + u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000); + u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000); + u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000); + u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000); + u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000); + u32 tR = chip->chip_delay * 1000; + u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000); + u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000); + + /* fallback to a default value if tR = 0 */ + if (!tR) + tR = 20000; + + ndtr0 = NDTR0_tCH(ns2cycle(tCH_min, nand_clk)) | + NDTR0_tCS(ns2cycle(tCS_min, nand_clk)) | + NDTR0_tWH(ns2cycle(tWH_min, nand_clk)) | + NDTR0_tWP(ns2cycle(tWP_min, nand_clk)) | + NDTR0_tRH(ns2cycle(tREH_min, nand_clk)) | + NDTR0_tRP(ns2cycle(tRP_min, nand_clk)); + + ndtr1 = NDTR1_tR(ns2cycle(tR, nand_clk)) | + NDTR1_tWHR(ns2cycle(tWHR_min, nand_clk)) | + NDTR1_tAR(ns2cycle(tAR_min, nand_clk)); + + info->ndtr0cs0 = ndtr0; + info->ndtr1cs0 = ndtr1; + nand_writel(info, NDTR0CS0, ndtr0); + nand_writel(info, NDTR1CS0, ndtr1); +} + +static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host) +{ + const struct nand_sdr_timings *timings; + struct nand_chip *chip = &host->chip; + struct pxa3xx_nand_info *info = host->info_data; + const struct pxa3xx_nand_flash *f = NULL; + struct mtd_info *mtd = nand_to_mtd(&host->chip); + int mode, id, ntypes, i; + + mode = onfi_get_async_timing_mode(chip); + if (mode == ONFI_TIMING_MODE_UNKNOWN) { + ntypes = ARRAY_SIZE(builtin_flash_types); + + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + id = chip->read_byte(mtd); + id |= chip->read_byte(mtd) << 0x8; + + for (i = 0; i < ntypes; i++) { + f = &builtin_flash_types[i]; + + if (f->chip_id == id) + break; + } + + if (i == ntypes) { + dev_err(&info->pdev->dev, "Error: timings not found\n"); + return -EINVAL; + } + + pxa3xx_nand_set_timing(host, f->timing); + + if (f->flash_width == 16) { + info->reg_ndcr |= NDCR_DWIDTH_M; + chip->options |= NAND_BUSWIDTH_16; + } + + info->reg_ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; + } else { + mode = fls(mode) - 1; + if (mode < 0) + mode = 0; + + timings = onfi_async_timing_mode_to_sdr_timings(mode); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + pxa3xx_nand_set_sdr_timing(host, timings); + } + + return 0; +} + +/** + * NOTE: it is a must to set ND_RUN first, then write + * command buffer, otherwise, it does not work. + * We enable all the interrupt at the same time, and + * let pxa3xx_nand_irq to handle all logic. + */ +static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) +{ + uint32_t ndcr; + + ndcr = info->reg_ndcr; + + if (info->use_ecc) { + ndcr |= NDCR_ECC_EN; + if (info->ecc_bch) + nand_writel(info, NDECCCTRL, 0x1); + } else { + ndcr &= ~NDCR_ECC_EN; + if (info->ecc_bch) + nand_writel(info, NDECCCTRL, 0x0); + } + + ndcr &= ~NDCR_DMA_EN; + + if (info->use_spare) + ndcr |= NDCR_SPARE_EN; + else + ndcr &= ~NDCR_SPARE_EN; + + ndcr |= NDCR_ND_RUN; + + /* clear status bits and run */ + nand_writel(info, NDSR, NDSR_MASK); + nand_writel(info, NDCR, 0); + nand_writel(info, NDCR, ndcr); +} + +static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) +{ + uint32_t ndcr; + + ndcr = nand_readl(info, NDCR); + nand_writel(info, NDCR, ndcr | int_mask); +} + +static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) +{ + if (info->ecc_bch) { + u32 ts; + + /* + * According to the datasheet, when reading from NDDB + * with BCH enabled, after each 32 bytes reads, we + * have to make sure that the NDSR.RDDREQ bit is set. + * + * Drain the FIFO 8 32 bits reads at a time, and skip + * the polling on the last read. + */ + while (len > 8) { + readsl(info->mmio_base + NDDB, data, 8); + + ts = get_timer(0); + while (!(nand_readl(info, NDSR) & NDSR_RDDREQ)) { + if (get_timer(ts) > TIMEOUT_DRAIN_FIFO) { + dev_err(&info->pdev->dev, + "Timeout on RDDREQ while draining the FIFO\n"); + return; + } + } + + data += 32; + len -= 8; + } + } + + readsl(info->mmio_base + NDDB, data, len); +} + +static void handle_data_pio(struct pxa3xx_nand_info *info) +{ + switch (info->state) { + case STATE_PIO_WRITING: + if (info->step_chunk_size) + writesl(info->mmio_base + NDDB, + info->data_buff + info->data_buff_pos, + DIV_ROUND_UP(info->step_chunk_size, 4)); + + if (info->step_spare_size) + writesl(info->mmio_base + NDDB, + info->oob_buff + info->oob_buff_pos, + DIV_ROUND_UP(info->step_spare_size, 4)); + break; + case STATE_PIO_READING: + if (info->step_chunk_size) + drain_fifo(info, + info->data_buff + info->data_buff_pos, + DIV_ROUND_UP(info->step_chunk_size, 4)); + + if (info->step_spare_size) + drain_fifo(info, + info->oob_buff + info->oob_buff_pos, + DIV_ROUND_UP(info->step_spare_size, 4)); + break; + default: + dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, + info->state); + BUG(); + } + + /* Update buffer pointers for multi-page read/write */ + info->data_buff_pos += info->step_chunk_size; + info->oob_buff_pos += info->step_spare_size; +} + +static void pxa3xx_nand_irq_thread(struct pxa3xx_nand_info *info) +{ + handle_data_pio(info); + + info->state = STATE_CMD_DONE; + nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); +} + +static irqreturn_t pxa3xx_nand_irq(struct pxa3xx_nand_info *info) +{ + unsigned int status, is_completed = 0, is_ready = 0; + unsigned int ready, cmd_done; + irqreturn_t ret = IRQ_HANDLED; + + if (info->cs == 0) { + ready = NDSR_FLASH_RDY; + cmd_done = NDSR_CS0_CMDD; + } else { + ready = NDSR_RDY; + cmd_done = NDSR_CS1_CMDD; + } + + /* TODO - find out why we need the delay during write operation. */ + ndelay(1); + + status = nand_readl(info, NDSR); + + if (status & NDSR_UNCORERR) + info->retcode = ERR_UNCORERR; + if (status & NDSR_CORERR) { + info->retcode = ERR_CORERR; + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 && + info->ecc_bch) + info->ecc_err_cnt = NDSR_ERR_CNT(status); + else + info->ecc_err_cnt = 1; + + /* + * Each chunk composing a page is corrected independently, + * and we need to store maximum number of corrected bitflips + * to return it to the MTD layer in ecc.read_page(). + */ + info->max_bitflips = max_t(unsigned int, + info->max_bitflips, + info->ecc_err_cnt); + } + if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) { + info->state = (status & NDSR_RDDREQ) ? + STATE_PIO_READING : STATE_PIO_WRITING; + /* Call the IRQ thread in U-Boot directly */ + pxa3xx_nand_irq_thread(info); + return 0; + } + if (status & cmd_done) { + info->state = STATE_CMD_DONE; + is_completed = 1; + } + if (status & ready) { + info->state = STATE_READY; + is_ready = 1; + } + + /* + * Clear all status bit before issuing the next command, which + * can and will alter the status bits and will deserve a new + * interrupt on its own. This lets the controller exit the IRQ + */ + nand_writel(info, NDSR, status); + + if (status & NDSR_WRCMDREQ) { + status &= ~NDSR_WRCMDREQ; + info->state = STATE_CMD_HANDLE; + + /* + * Command buffer registers NDCB{0-2} (and optionally NDCB3) + * must be loaded by writing directly either 12 or 16 + * bytes directly to NDCB0, four bytes at a time. + * + * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored + * but each NDCBx register can be read. + */ + nand_writel(info, NDCB0, info->ndcb0); + nand_writel(info, NDCB0, info->ndcb1); + nand_writel(info, NDCB0, info->ndcb2); + + /* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */ + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) + nand_writel(info, NDCB0, info->ndcb3); + } + + if (is_completed) + info->cmd_complete = 1; + if (is_ready) + info->dev_ready = 1; + + return ret; +} + +static inline int is_buf_blank(uint8_t *buf, size_t len) +{ + for (; len > 0; len--) + if (*buf++ != 0xff) + return 0; + return 1; +} + +static void set_command_address(struct pxa3xx_nand_info *info, + unsigned int page_size, uint16_t column, int page_addr) +{ + /* small page addr setting */ + if (page_size < info->chunk_size) { + info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) + | (column & 0xFF); + + info->ndcb2 = 0; + } else { + info->ndcb1 = ((page_addr & 0xFFFF) << 16) + | (column & 0xFFFF); + + if (page_addr & 0xFF0000) + info->ndcb2 = (page_addr & 0xFF0000) >> 16; + else + info->ndcb2 = 0; + } +} + +static void prepare_start_command(struct pxa3xx_nand_info *info, int command) +{ + struct pxa3xx_nand_host *host = info->host[info->cs]; + struct mtd_info *mtd = nand_to_mtd(&host->chip); + + /* reset data and oob column point to handle data */ + info->buf_start = 0; + info->buf_count = 0; + info->data_buff_pos = 0; + info->oob_buff_pos = 0; + info->step_chunk_size = 0; + info->step_spare_size = 0; + info->cur_chunk = 0; + info->use_ecc = 0; + info->use_spare = 1; + info->retcode = ERR_NONE; + info->ecc_err_cnt = 0; + info->ndcb3 = 0; + info->need_wait = 0; + + switch (command) { + case NAND_CMD_READ0: + case NAND_CMD_READOOB: + case NAND_CMD_PAGEPROG: + info->use_ecc = 1; + break; + case NAND_CMD_PARAM: + info->use_spare = 0; + break; + default: + info->ndcb1 = 0; + info->ndcb2 = 0; + break; + } + + /* + * If we are about to issue a read command, or about to set + * the write address, then clean the data buffer. + */ + if (command == NAND_CMD_READ0 || + command == NAND_CMD_READOOB || + command == NAND_CMD_SEQIN) { + info->buf_count = mtd->writesize + mtd->oobsize; + memset(info->data_buff, 0xFF, info->buf_count); + } +} + +static int prepare_set_command(struct pxa3xx_nand_info *info, int command, + int ext_cmd_type, uint16_t column, int page_addr) +{ + int addr_cycle, exec_cmd; + struct pxa3xx_nand_host *host; + struct mtd_info *mtd; + + host = info->host[info->cs]; + mtd = nand_to_mtd(&host->chip); + addr_cycle = 0; + exec_cmd = 1; + + if (info->cs != 0) + info->ndcb0 = NDCB0_CSEL; + else + info->ndcb0 = 0; + + if (command == NAND_CMD_SEQIN) + exec_cmd = 0; + + addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles + + host->col_addr_cycles); + + switch (command) { + case NAND_CMD_READOOB: + case NAND_CMD_READ0: + info->buf_start = column; + info->ndcb0 |= NDCB0_CMD_TYPE(0) + | addr_cycle + | NAND_CMD_READ0; + + if (command == NAND_CMD_READOOB) + info->buf_start += mtd->writesize; + + if (info->cur_chunk < info->nfullchunks) { + info->step_chunk_size = info->chunk_size; + info->step_spare_size = info->spare_size; + } else { + info->step_chunk_size = info->last_chunk_size; + info->step_spare_size = info->last_spare_size; + } + + /* + * Multiple page read needs an 'extended command type' field, + * which is either naked-read or last-read according to the + * state. + */ + if (mtd->writesize == info->chunk_size) { + info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); + } else if (mtd->writesize > info->chunk_size) { + info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) + | NDCB0_LEN_OVRD + | NDCB0_EXT_CMD_TYPE(ext_cmd_type); + info->ndcb3 = info->step_chunk_size + + info->step_spare_size; + } + + set_command_address(info, mtd->writesize, column, page_addr); + break; + + case NAND_CMD_SEQIN: + + info->buf_start = column; + set_command_address(info, mtd->writesize, 0, page_addr); + + /* + * Multiple page programming needs to execute the initial + * SEQIN command that sets the page address. + */ + if (mtd->writesize > info->chunk_size) { + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_EXT_CMD_TYPE(ext_cmd_type) + | addr_cycle + | command; + exec_cmd = 1; + } + break; + + case NAND_CMD_PAGEPROG: + if (is_buf_blank(info->data_buff, + (mtd->writesize + mtd->oobsize))) { + exec_cmd = 0; + break; + } + + if (info->cur_chunk < info->nfullchunks) { + info->step_chunk_size = info->chunk_size; + info->step_spare_size = info->spare_size; + } else { + info->step_chunk_size = info->last_chunk_size; + info->step_spare_size = info->last_spare_size; + } + + /* Second command setting for large pages */ + if (mtd->writesize > info->chunk_size) { + /* + * Multiple page write uses the 'extended command' + * field. This can be used to issue a command dispatch + * or a naked-write depending on the current stage. + */ + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_LEN_OVRD + | NDCB0_EXT_CMD_TYPE(ext_cmd_type); + info->ndcb3 = info->step_chunk_size + + info->step_spare_size; + + /* + * This is the command dispatch that completes a chunked + * page program operation. + */ + if (info->cur_chunk == info->ntotalchunks) { + info->ndcb0 = NDCB0_CMD_TYPE(0x1) + | NDCB0_EXT_CMD_TYPE(ext_cmd_type) + | command; + info->ndcb1 = 0; + info->ndcb2 = 0; + info->ndcb3 = 0; + } + } else { + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_AUTO_RS + | NDCB0_ST_ROW_EN + | NDCB0_DBC + | (NAND_CMD_PAGEPROG << 8) + | NAND_CMD_SEQIN + | addr_cycle; + } + break; + + case NAND_CMD_PARAM: + info->buf_count = INIT_BUFFER_SIZE; + info->ndcb0 |= NDCB0_CMD_TYPE(0) + | NDCB0_ADDR_CYC(1) + | NDCB0_LEN_OVRD + | command; + info->ndcb1 = (column & 0xFF); + info->ndcb3 = INIT_BUFFER_SIZE; + info->step_chunk_size = INIT_BUFFER_SIZE; + break; + + case NAND_CMD_READID: + info->buf_count = READ_ID_BYTES; + info->ndcb0 |= NDCB0_CMD_TYPE(3) + | NDCB0_ADDR_CYC(1) + | command; + info->ndcb1 = (column & 0xFF); + + info->step_chunk_size = 8; + break; + case NAND_CMD_STATUS: + info->buf_count = 1; + info->ndcb0 |= NDCB0_CMD_TYPE(4) + | NDCB0_ADDR_CYC(1) + | command; + + info->step_chunk_size = 8; + break; + + case NAND_CMD_ERASE1: + info->ndcb0 |= NDCB0_CMD_TYPE(2) + | NDCB0_AUTO_RS + | NDCB0_ADDR_CYC(3) + | NDCB0_DBC + | (NAND_CMD_ERASE2 << 8) + | NAND_CMD_ERASE1; + info->ndcb1 = page_addr; + info->ndcb2 = 0; + + break; + case NAND_CMD_RESET: + info->ndcb0 |= NDCB0_CMD_TYPE(5) + | command; + + break; + + case NAND_CMD_ERASE2: + exec_cmd = 0; + break; + + default: + exec_cmd = 0; + dev_err(&info->pdev->dev, "non-supported command %x\n", + command); + break; + } + + return exec_cmd; +} + +static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct pxa3xx_nand_host *host = nand_get_controller_data(chip); + struct pxa3xx_nand_info *info = host->info_data; + int exec_cmd; + + /* + * if this is a x16 device ,then convert the input + * "byte" address into a "word" address appropriate + * for indexing a word-oriented device + */ + if (info->reg_ndcr & NDCR_DWIDTH_M) + column /= 2; + + /* + * There may be different NAND chip hooked to + * different chip select, so check whether + * chip select has been changed, if yes, reset the timing + */ + if (info->cs != host->cs) { + info->cs = host->cs; + nand_writel(info, NDTR0CS0, info->ndtr0cs0); + nand_writel(info, NDTR1CS0, info->ndtr1cs0); + } + + prepare_start_command(info, command); + + info->state = STATE_PREPARED; + exec_cmd = prepare_set_command(info, command, 0, column, page_addr); + + if (exec_cmd) { + u32 ts; + + info->cmd_complete = 0; + info->dev_ready = 0; + info->need_wait = 1; + pxa3xx_nand_start(info); + + ts = get_timer(0); + while (1) { + u32 status; + + status = nand_readl(info, NDSR); + if (status) + pxa3xx_nand_irq(info); + + if (info->cmd_complete) + break; + + if (get_timer(ts) > CHIP_DELAY_TIMEOUT) { + dev_err(&info->pdev->dev, "Wait timeout!!!\n"); + return; + } + } + } + info->state = STATE_IDLE; +} + +static void nand_cmdfunc_extended(struct mtd_info *mtd, + const unsigned command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct pxa3xx_nand_host *host = nand_get_controller_data(chip); + struct pxa3xx_nand_info *info = host->info_data; + int exec_cmd, ext_cmd_type; + + /* + * if this is a x16 device then convert the input + * "byte" address into a "word" address appropriate + * for indexing a word-oriented device + */ + if (info->reg_ndcr & NDCR_DWIDTH_M) + column /= 2; + + /* + * There may be different NAND chip hooked to + * different chip select, so check whether + * chip select has been changed, if yes, reset the timing + */ + if (info->cs != host->cs) { + info->cs = host->cs; + nand_writel(info, NDTR0CS0, info->ndtr0cs0); + nand_writel(info, NDTR1CS0, info->ndtr1cs0); + } + + /* Select the extended command for the first command */ + switch (command) { + case NAND_CMD_READ0: + case NAND_CMD_READOOB: + ext_cmd_type = EXT_CMD_TYPE_MONO; + break; + case NAND_CMD_SEQIN: + ext_cmd_type = EXT_CMD_TYPE_DISPATCH; + break; + case NAND_CMD_PAGEPROG: + ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; + break; + default: + ext_cmd_type = 0; + break; + } + + prepare_start_command(info, command); + + /* + * Prepare the "is ready" completion before starting a command + * transaction sequence. If the command is not executed the + * completion will be completed, see below. + * + * We can do that inside the loop because the command variable + * is invariant and thus so is the exec_cmd. + */ + info->need_wait = 1; + info->dev_ready = 0; + + do { + u32 ts; + + info->state = STATE_PREPARED; + exec_cmd = prepare_set_command(info, command, ext_cmd_type, + column, page_addr); + if (!exec_cmd) { + info->need_wait = 0; + info->dev_ready = 1; + break; + } + + info->cmd_complete = 0; + pxa3xx_nand_start(info); + + ts = get_timer(0); + while (1) { + u32 status; + + status = nand_readl(info, NDSR); + if (status) + pxa3xx_nand_irq(info); + + if (info->cmd_complete) + break; + + if (get_timer(ts) > CHIP_DELAY_TIMEOUT) { + dev_err(&info->pdev->dev, "Wait timeout!!!\n"); + return; + } + } + + /* Only a few commands need several steps */ + if (command != NAND_CMD_PAGEPROG && + command != NAND_CMD_READ0 && + command != NAND_CMD_READOOB) + break; + + info->cur_chunk++; + + /* Check if the sequence is complete */ + if (info->cur_chunk == info->ntotalchunks && + command != NAND_CMD_PAGEPROG) + break; + + /* + * After a splitted program command sequence has issued + * the command dispatch, the command sequence is complete. + */ + if (info->cur_chunk == (info->ntotalchunks + 1) && + command == NAND_CMD_PAGEPROG && + ext_cmd_type == EXT_CMD_TYPE_DISPATCH) + break; + + if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) { + /* Last read: issue a 'last naked read' */ + if (info->cur_chunk == info->ntotalchunks - 1) + ext_cmd_type = EXT_CMD_TYPE_LAST_RW; + else + ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; + + /* + * If a splitted program command has no more data to transfer, + * the command dispatch must be issued to complete. + */ + } else if (command == NAND_CMD_PAGEPROG && + info->cur_chunk == info->ntotalchunks) { + ext_cmd_type = EXT_CMD_TYPE_DISPATCH; + } + } while (1); + + info->state = STATE_IDLE; +} + +static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required, + int page) +{ + chip->write_buf(mtd, buf, mtd->writesize); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int oob_required, + int page) +{ + struct pxa3xx_nand_host *host = nand_get_controller_data(chip); + struct pxa3xx_nand_info *info = host->info_data; + + chip->read_buf(mtd, buf, mtd->writesize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + if (info->retcode == ERR_CORERR && info->use_ecc) { + mtd->ecc_stats.corrected += info->ecc_err_cnt; + + } else if (info->retcode == ERR_UNCORERR) { + /* + * for blank page (all 0xff), HW will calculate its ECC as + * 0, which is different from the ECC information within + * OOB, ignore such uncorrectable errors + */ + if (is_buf_blank(buf, mtd->writesize)) + info->retcode = ERR_NONE; + else + mtd->ecc_stats.failed++; + } + + return info->max_bitflips; +} + +static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct pxa3xx_nand_host *host = nand_get_controller_data(chip); + struct pxa3xx_nand_info *info = host->info_data; + char retval = 0xFF; + + if (info->buf_start < info->buf_count) + /* Has just send a new command? */ + retval = info->data_buff[info->buf_start++]; + + return retval; +} + +static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct pxa3xx_nand_host *host = nand_get_controller_data(chip); + struct pxa3xx_nand_info *info = host->info_data; + u16 retval = 0xFFFF; + + if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { + retval = *((u16 *)(info->data_buff+info->buf_start)); + info->buf_start += 2; + } + return retval; +} + +static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct pxa3xx_nand_host *host = nand_get_controller_data(chip); + struct pxa3xx_nand_info *info = host->info_data; + int real_len = min_t(size_t, len, info->buf_count - info->buf_start); + + memcpy(buf, info->data_buff + info->buf_start, real_len); + info->buf_start += real_len; +} + +static void pxa3xx_nand_write_buf(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct pxa3xx_nand_host *host = nand_get_controller_data(chip); + struct pxa3xx_nand_info *info = host->info_data; + int real_len = min_t(size_t, len, info->buf_count - info->buf_start); + + memcpy(info->data_buff + info->buf_start, buf, real_len); + info->buf_start += real_len; +} + +static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip) +{ + return; +} + +static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct pxa3xx_nand_host *host = nand_get_controller_data(chip); + struct pxa3xx_nand_info *info = host->info_data; + + if (info->need_wait) { + u32 ts; + + info->need_wait = 0; + + ts = get_timer(0); + while (1) { + u32 status; + + status = nand_readl(info, NDSR); + if (status) + pxa3xx_nand_irq(info); + + if (info->dev_ready) + break; + + if (get_timer(ts) > CHIP_DELAY_TIMEOUT) { + dev_err(&info->pdev->dev, "Ready timeout!!!\n"); + return NAND_STATUS_FAIL; + } + } + } + + /* pxa3xx_nand_send_command has waited for command complete */ + if (this->state == FL_WRITING || this->state == FL_ERASING) { + if (info->retcode == ERR_NONE) + return 0; + else + return NAND_STATUS_FAIL; + } + + return NAND_STATUS_READY; +} + +static int pxa3xx_nand_config_ident(struct pxa3xx_nand_info *info) +{ + struct pxa3xx_nand_platform_data *pdata = info->pdata; + + /* Configure default flash values */ + info->reg_ndcr = 0x0; /* enable all interrupts */ + info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; + info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); + info->reg_ndcr |= NDCR_SPARE_EN; + + return 0; +} + +static void pxa3xx_nand_config_tail(struct pxa3xx_nand_info *info) +{ + struct pxa3xx_nand_host *host = info->host[info->cs]; + struct mtd_info *mtd = nand_to_mtd(&info->host[info->cs]->chip); + struct nand_chip *chip = mtd_to_nand(mtd); + + info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; + info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0; + info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0; +} + +static void pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) +{ + struct pxa3xx_nand_platform_data *pdata = info->pdata; + uint32_t ndcr = nand_readl(info, NDCR); + + /* Set an initial chunk size */ + info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; + info->reg_ndcr = ndcr & + ~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL); + info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; + info->ndtr0cs0 = nand_readl(info, NDTR0CS0); + info->ndtr1cs0 = nand_readl(info, NDTR1CS0); +} + +static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) +{ + info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); + if (info->data_buff == NULL) + return -ENOMEM; + return 0; +} + +static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host) +{ + struct pxa3xx_nand_info *info = host->info_data; + struct pxa3xx_nand_platform_data *pdata = info->pdata; + struct mtd_info *mtd; + struct nand_chip *chip; + const struct nand_sdr_timings *timings; + int ret; + + mtd = nand_to_mtd(&info->host[info->cs]->chip); + chip = mtd_to_nand(mtd); + + /* configure default flash values */ + info->reg_ndcr = 0x0; /* enable all interrupts */ + info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; + info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); + info->reg_ndcr |= NDCR_SPARE_EN; /* enable spare by default */ + + /* use the common timing to make a try */ + timings = onfi_async_timing_mode_to_sdr_timings(0); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + pxa3xx_nand_set_sdr_timing(host, timings); + + chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); + ret = chip->waitfunc(mtd, chip); + if (ret & NAND_STATUS_FAIL) + return -ENODEV; + + return 0; +} + +static int pxa_ecc_init(struct pxa3xx_nand_info *info, + struct nand_ecc_ctrl *ecc, + int strength, int ecc_stepsize, int page_size) +{ + if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) { + info->nfullchunks = 1; + info->ntotalchunks = 1; + info->chunk_size = 2048; + info->spare_size = 40; + info->ecc_size = 24; + ecc->mode = NAND_ECC_HW; + ecc->size = 512; + ecc->strength = 1; + + } else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) { + info->nfullchunks = 1; + info->ntotalchunks = 1; + info->chunk_size = 512; + info->spare_size = 8; + info->ecc_size = 8; + ecc->mode = NAND_ECC_HW; + ecc->size = 512; + ecc->strength = 1; + + /* + * Required ECC: 4-bit correction per 512 bytes + * Select: 16-bit correction per 2048 bytes + */ + } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) { + info->ecc_bch = 1; + info->nfullchunks = 1; + info->ntotalchunks = 1; + info->chunk_size = 2048; + info->spare_size = 32; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_2KB_bch4bit; + ecc->strength = 16; + + } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) { + info->ecc_bch = 1; + info->nfullchunks = 2; + info->ntotalchunks = 2; + info->chunk_size = 2048; + info->spare_size = 32; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_4KB_bch4bit; + ecc->strength = 16; + + } else if (strength == 4 && ecc_stepsize == 512 && page_size == 8192) { + info->ecc_bch = 1; + info->nfullchunks = 4; + info->ntotalchunks = 4; + info->chunk_size = 2048; + info->spare_size = 32; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_8KB_bch4bit; + ecc->strength = 16; + + /* + * Required ECC: 8-bit correction per 512 bytes + * Select: 16-bit correction per 1024 bytes + */ + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) { + info->ecc_bch = 1; + info->nfullchunks = 1; + info->ntotalchunks = 2; + info->chunk_size = 1024; + info->spare_size = 0; + info->last_chunk_size = 1024; + info->last_spare_size = 64; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_2KB_bch8bit; + ecc->strength = 16; + + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) { + info->ecc_bch = 1; + info->nfullchunks = 4; + info->ntotalchunks = 5; + info->chunk_size = 1024; + info->spare_size = 0; + info->last_chunk_size = 0; + info->last_spare_size = 64; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_4KB_bch8bit; + ecc->strength = 16; + + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 8192) { + info->ecc_bch = 1; + info->nfullchunks = 8; + info->ntotalchunks = 9; + info->chunk_size = 1024; + info->spare_size = 0; + info->last_chunk_size = 0; + info->last_spare_size = 160; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_8KB_bch8bit; + ecc->strength = 16; + + } else { + dev_err(&info->pdev->dev, + "ECC strength %d at page size %d is not supported\n", + strength, page_size); + return -ENODEV; + } + + return 0; +} + +static int pxa3xx_nand_scan(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct pxa3xx_nand_host *host = nand_get_controller_data(chip); + struct pxa3xx_nand_info *info = host->info_data; + struct pxa3xx_nand_platform_data *pdata = info->pdata; + int ret; + uint16_t ecc_strength, ecc_step; + + if (pdata->keep_config) { + pxa3xx_nand_detect_config(info); + } else { + ret = pxa3xx_nand_config_ident(info); + if (ret) + return ret; + ret = pxa3xx_nand_sensing(host); + if (ret) { + dev_info(&info->pdev->dev, + "There is no chip on cs %d!\n", + info->cs); + return ret; + } + } + + /* Device detection must be done with ECC disabled */ + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) + nand_writel(info, NDECCCTRL, 0x0); + + if (nand_scan_ident(mtd, 1, NULL)) + return -ENODEV; + + if (!pdata->keep_config) { + ret = pxa3xx_nand_init_timings(host); + if (ret) { + dev_err(&info->pdev->dev, + "Failed to set timings: %d\n", ret); + return ret; + } + } + +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + /* + * We'll use a bad block table stored in-flash and don't + * allow writing the bad block marker to the flash. + */ + chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB_BBM; + chip->bbt_td = &bbt_main_descr; + chip->bbt_md = &bbt_mirror_descr; +#endif + + if (pdata->ecc_strength && pdata->ecc_step_size) { + ecc_strength = pdata->ecc_strength; + ecc_step = pdata->ecc_step_size; + } else { + ecc_strength = chip->ecc_strength_ds; + ecc_step = chip->ecc_step_ds; + } + + /* Set default ECC strength requirements on non-ONFI devices */ + if (ecc_strength < 1 && ecc_step < 1) { + ecc_strength = 1; + ecc_step = 512; + } + + ret = pxa_ecc_init(info, &chip->ecc, ecc_strength, + ecc_step, mtd->writesize); + if (ret) + return ret; + + /* + * If the page size is bigger than the FIFO size, let's check + * we are given the right variant and then switch to the extended + * (aka split) command handling, + */ + if (mtd->writesize > info->chunk_size) { + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) { + chip->cmdfunc = nand_cmdfunc_extended; + } else { + dev_err(&info->pdev->dev, + "unsupported page size on this variant\n"); + return -ENODEV; + } + } + + /* calculate addressing information */ + if (mtd->writesize >= 2048) + host->col_addr_cycles = 2; + else + host->col_addr_cycles = 1; + + /* release the initial buffer */ + kfree(info->data_buff); + + /* allocate the real data + oob buffer */ + info->buf_size = mtd->writesize + mtd->oobsize; + ret = pxa3xx_nand_init_buff(info); + if (ret) + return ret; + info->oob_buff = info->data_buff + mtd->writesize; + + if ((mtd->size >> chip->page_shift) > 65536) + host->row_addr_cycles = 3; + else + host->row_addr_cycles = 2; + + if (!pdata->keep_config) + pxa3xx_nand_config_tail(info); + + return nand_scan_tail(mtd); +} + +static int alloc_nand_resource(struct pxa3xx_nand_info *info) +{ + struct pxa3xx_nand_platform_data *pdata; + struct pxa3xx_nand_host *host; + struct nand_chip *chip = NULL; + struct mtd_info *mtd; + int ret, cs; + + pdata = info->pdata; + if (pdata->num_cs <= 0) + return -ENODEV; + + info->variant = pxa3xx_nand_get_variant(); + for (cs = 0; cs < pdata->num_cs; cs++) { + chip = (struct nand_chip *) + ((u8 *)&info[1] + sizeof(*host) * cs); + mtd = nand_to_mtd(chip); + host = (struct pxa3xx_nand_host *)chip; + info->host[cs] = host; + host->cs = cs; + host->info_data = info; + mtd->owner = THIS_MODULE; + + nand_set_controller_data(chip, host); + chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; + chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; + chip->controller = &info->controller; + chip->waitfunc = pxa3xx_nand_waitfunc; + chip->select_chip = pxa3xx_nand_select_chip; + chip->read_word = pxa3xx_nand_read_word; + chip->read_byte = pxa3xx_nand_read_byte; + chip->read_buf = pxa3xx_nand_read_buf; + chip->write_buf = pxa3xx_nand_write_buf; + chip->options |= NAND_NO_SUBPAGE_WRITE; + chip->cmdfunc = nand_cmdfunc; + } + + /* Allocate a buffer to allow flash detection */ + info->buf_size = INIT_BUFFER_SIZE; + info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); + if (info->data_buff == NULL) { + ret = -ENOMEM; + goto fail_disable_clk; + } + + /* initialize all interrupts to be disabled */ + disable_int(info, NDSR_MASK); + + return 0; + + kfree(info->data_buff); +fail_disable_clk: + return ret; +} + +static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) +{ + struct pxa3xx_nand_platform_data *pdata; + const void *blob = gd->fdt_blob; + int node = -1; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + /* Get address decoding nodes from the FDT blob */ + do { + node = fdt_node_offset_by_compatible(blob, node, + "marvell,mvebu-pxa3xx-nand"); + if (node < 0) + break; + + /* Bypass disabeld nodes */ + if (!fdtdec_get_is_enabled(blob, node)) + continue; + + /* Get the first enabled NAND controler base address */ + info->mmio_base = + (void __iomem *)fdtdec_get_addr_size_auto_noparent( + blob, node, "reg", 0, NULL, true); + + pdata->num_cs = fdtdec_get_int(blob, node, "num-cs", 1); + if (pdata->num_cs != 1) { + pr_err("pxa3xx driver supports single CS only\n"); + break; + } + + if (fdtdec_get_bool(blob, node, "nand-enable-arbiter")) + pdata->enable_arbiter = 1; + + if (fdtdec_get_bool(blob, node, "nand-keep-config")) + pdata->keep_config = 1; + + /* + * ECC parameters. + * If these are not set, they will be selected according + * to the detected flash type. + */ + /* ECC strength */ + pdata->ecc_strength = fdtdec_get_int(blob, node, + "nand-ecc-strength", 0); + + /* ECC step size */ + pdata->ecc_step_size = fdtdec_get_int(blob, node, + "nand-ecc-step-size", 0); + + info->pdata = pdata; + + /* Currently support only a single NAND controller */ + return 0; + + } while (node >= 0); + + return -EINVAL; +} + +static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info) +{ + struct pxa3xx_nand_platform_data *pdata; + int ret, cs, probe_success; + + ret = pxa3xx_nand_probe_dt(info); + if (ret) + return ret; + + pdata = info->pdata; + + ret = alloc_nand_resource(info); + if (ret) { + dev_err(&pdev->dev, "alloc nand resource failed\n"); + return ret; + } + + probe_success = 0; + for (cs = 0; cs < pdata->num_cs; cs++) { + struct mtd_info *mtd = nand_to_mtd(&info->host[cs]->chip); + + /* + * The mtd name matches the one used in 'mtdparts' kernel + * parameter. This name cannot be changed or otherwise + * user's mtd partitions configuration would get broken. + */ + mtd->name = "pxa3xx_nand-0"; + info->cs = cs; + ret = pxa3xx_nand_scan(mtd); + if (ret) { + dev_info(&pdev->dev, "failed to scan nand at cs %d\n", + cs); + continue; + } + + if (nand_register(cs, mtd)) + continue; + + probe_success = 1; + } + + if (!probe_success) + return -ENODEV; + + return 0; +} + +/* + * Main initialization routine + */ +void board_nand_init(void) +{ + struct pxa3xx_nand_info *info; + struct pxa3xx_nand_host *host; + int ret; + + info = kzalloc(sizeof(*info) + + sizeof(*host) * CONFIG_SYS_MAX_NAND_DEVICE, + GFP_KERNEL); + if (!info) + return; + + ret = pxa3xx_nand_probe(info); + if (ret) + return; +} diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.h b/drivers/mtd/nand/raw/pxa3xx_nand.h new file mode 100644 index 0000000000..8f24ae6d18 --- /dev/null +++ b/drivers/mtd/nand/raw/pxa3xx_nand.h @@ -0,0 +1,64 @@ +#ifndef __ASM_ARCH_PXA3XX_NAND_H +#define __ASM_ARCH_PXA3XX_NAND_H + +#include +#include + +struct pxa3xx_nand_timing { + unsigned int tCH; /* Enable signal hold time */ + unsigned int tCS; /* Enable signal setup time */ + unsigned int tWH; /* ND_nWE high duration */ + unsigned int tWP; /* ND_nWE pulse time */ + unsigned int tRH; /* ND_nRE high duration */ + unsigned int tRP; /* ND_nRE pulse width */ + unsigned int tR; /* ND_nWE high to ND_nRE low for read */ + unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */ + unsigned int tAR; /* ND_ALE low to ND_nRE low delay */ +}; + +struct pxa3xx_nand_flash { + uint32_t chip_id; + unsigned int flash_width; /* Width of Flash memory (DWIDTH_M) */ + unsigned int dfc_width; /* Width of flash controller(DWIDTH_C) */ + struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ +}; + +/* + * Current pxa3xx_nand controller has two chip select which + * both be workable. + * + * Notice should be taken that: + * When you want to use this feature, you should not enable the + * keep configuration feature, for two chip select could be + * attached with different nand chip. The different page size + * and timing requirement make the keep configuration impossible. + */ + +/* The max num of chip select current support */ +#define NUM_CHIP_SELECT (2) +struct pxa3xx_nand_platform_data { + /* the data flash bus is shared between the Static Memory + * Controller and the Data Flash Controller, the arbiter + * controls the ownership of the bus + */ + int enable_arbiter; + + /* allow platform code to keep OBM/bootloader defined NFC config */ + int keep_config; + + /* indicate how many chip selects will be used */ + int num_cs; + + /* use an flash-based bad block table */ + bool flash_bbt; + + /* requested ECC strength and ECC step size */ + int ecc_strength, ecc_step_size; + + const struct mtd_partition *parts[NUM_CHIP_SELECT]; + unsigned int nr_parts[NUM_CHIP_SELECT]; + + const struct pxa3xx_nand_flash *flash; + size_t num_flash; +}; +#endif /* __ASM_ARCH_PXA3XX_NAND_H */ diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c new file mode 100644 index 0000000000..3ccb168d13 --- /dev/null +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -0,0 +1,1850 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Boris BREZILLON + * Copyright (C) 2015 Roy Spliet + * + * Derived from: + * https://github.com/yuq/sunxi-nfc-mtd + * Copyright (C) 2013 Qiang Yu + * + * https://github.com/hno/Allwinner-Info + * Copyright (C) 2013 Henrik Nordström + * + * Copyright (C) 2013 Dmitriy B. + * Copyright (C) 2013 Sergey Lapin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define NFC_REG_CTL 0x0000 +#define NFC_REG_ST 0x0004 +#define NFC_REG_INT 0x0008 +#define NFC_REG_TIMING_CTL 0x000C +#define NFC_REG_TIMING_CFG 0x0010 +#define NFC_REG_ADDR_LOW 0x0014 +#define NFC_REG_ADDR_HIGH 0x0018 +#define NFC_REG_SECTOR_NUM 0x001C +#define NFC_REG_CNT 0x0020 +#define NFC_REG_CMD 0x0024 +#define NFC_REG_RCMD_SET 0x0028 +#define NFC_REG_WCMD_SET 0x002C +#define NFC_REG_IO_DATA 0x0030 +#define NFC_REG_ECC_CTL 0x0034 +#define NFC_REG_ECC_ST 0x0038 +#define NFC_REG_DEBUG 0x003C +#define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3) +#define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4)) +#define NFC_REG_SPARE_AREA 0x00A0 +#define NFC_REG_PAT_ID 0x00A4 +#define NFC_RAM0_BASE 0x0400 +#define NFC_RAM1_BASE 0x0800 + +/* define bit use in NFC_CTL */ +#define NFC_EN BIT(0) +#define NFC_RESET BIT(1) +#define NFC_BUS_WIDTH_MSK BIT(2) +#define NFC_BUS_WIDTH_8 (0 << 2) +#define NFC_BUS_WIDTH_16 (1 << 2) +#define NFC_RB_SEL_MSK BIT(3) +#define NFC_RB_SEL(x) ((x) << 3) +#define NFC_CE_SEL_MSK (0x7 << 24) +#define NFC_CE_SEL(x) ((x) << 24) +#define NFC_CE_CTL BIT(6) +#define NFC_PAGE_SHIFT_MSK (0xf << 8) +#define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8) +#define NFC_SAM BIT(12) +#define NFC_RAM_METHOD BIT(14) +#define NFC_DEBUG_CTL BIT(31) + +/* define bit use in NFC_ST */ +#define NFC_RB_B2R BIT(0) +#define NFC_CMD_INT_FLAG BIT(1) +#define NFC_DMA_INT_FLAG BIT(2) +#define NFC_CMD_FIFO_STATUS BIT(3) +#define NFC_STA BIT(4) +#define NFC_NATCH_INT_FLAG BIT(5) +#define NFC_RB_STATE(x) BIT(x + 8) + +/* define bit use in NFC_INT */ +#define NFC_B2R_INT_ENABLE BIT(0) +#define NFC_CMD_INT_ENABLE BIT(1) +#define NFC_DMA_INT_ENABLE BIT(2) +#define NFC_INT_MASK (NFC_B2R_INT_ENABLE | \ + NFC_CMD_INT_ENABLE | \ + NFC_DMA_INT_ENABLE) + +/* define bit use in NFC_TIMING_CTL */ +#define NFC_TIMING_CTL_EDO BIT(8) + +/* define NFC_TIMING_CFG register layout */ +#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \ + (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \ + (((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) | \ + (((tCAD) & 0x7) << 8)) + +/* define bit use in NFC_CMD */ +#define NFC_CMD_LOW_BYTE_MSK 0xff +#define NFC_CMD_HIGH_BYTE_MSK (0xff << 8) +#define NFC_CMD(x) (x) +#define NFC_ADR_NUM_MSK (0x7 << 16) +#define NFC_ADR_NUM(x) (((x) - 1) << 16) +#define NFC_SEND_ADR BIT(19) +#define NFC_ACCESS_DIR BIT(20) +#define NFC_DATA_TRANS BIT(21) +#define NFC_SEND_CMD1 BIT(22) +#define NFC_WAIT_FLAG BIT(23) +#define NFC_SEND_CMD2 BIT(24) +#define NFC_SEQ BIT(25) +#define NFC_DATA_SWAP_METHOD BIT(26) +#define NFC_ROW_AUTO_INC BIT(27) +#define NFC_SEND_CMD3 BIT(28) +#define NFC_SEND_CMD4 BIT(29) +#define NFC_CMD_TYPE_MSK (0x3 << 30) +#define NFC_NORMAL_OP (0 << 30) +#define NFC_ECC_OP (1 << 30) +#define NFC_PAGE_OP (2 << 30) + +/* define bit use in NFC_RCMD_SET */ +#define NFC_READ_CMD_MSK 0xff +#define NFC_RND_READ_CMD0_MSK (0xff << 8) +#define NFC_RND_READ_CMD1_MSK (0xff << 16) + +/* define bit use in NFC_WCMD_SET */ +#define NFC_PROGRAM_CMD_MSK 0xff +#define NFC_RND_WRITE_CMD_MSK (0xff << 8) +#define NFC_READ_CMD0_MSK (0xff << 16) +#define NFC_READ_CMD1_MSK (0xff << 24) + +/* define bit use in NFC_ECC_CTL */ +#define NFC_ECC_EN BIT(0) +#define NFC_ECC_PIPELINE BIT(3) +#define NFC_ECC_EXCEPTION BIT(4) +#define NFC_ECC_BLOCK_SIZE_MSK BIT(5) +#define NFC_ECC_BLOCK_512 (1 << 5) +#define NFC_RANDOM_EN BIT(9) +#define NFC_RANDOM_DIRECTION BIT(10) +#define NFC_ECC_MODE_MSK (0xf << 12) +#define NFC_ECC_MODE(x) ((x) << 12) +#define NFC_RANDOM_SEED_MSK (0x7fff << 16) +#define NFC_RANDOM_SEED(x) ((x) << 16) + +/* define bit use in NFC_ECC_ST */ +#define NFC_ECC_ERR(x) BIT(x) +#define NFC_ECC_PAT_FOUND(x) BIT(x + 16) +#define NFC_ECC_ERR_CNT(b, x) (((x) >> ((b) * 8)) & 0xff) + +#define NFC_DEFAULT_TIMEOUT_MS 1000 + +#define NFC_SRAM_SIZE 1024 + +#define NFC_MAX_CS 7 + +/* + * Ready/Busy detection type: describes the Ready/Busy detection modes + * + * @RB_NONE: no external detection available, rely on STATUS command + * and software timeouts + * @RB_NATIVE: use sunxi NAND controller Ready/Busy support. The Ready/Busy + * pin of the NAND flash chip must be connected to one of the + * native NAND R/B pins (those which can be muxed to the NAND + * Controller) + * @RB_GPIO: use a simple GPIO to handle Ready/Busy status. The Ready/Busy + * pin of the NAND flash chip must be connected to a GPIO capable + * pin. + */ +enum sunxi_nand_rb_type { + RB_NONE, + RB_NATIVE, + RB_GPIO, +}; + +/* + * Ready/Busy structure: stores information related to Ready/Busy detection + * + * @type: the Ready/Busy detection mode + * @info: information related to the R/B detection mode. Either a gpio + * id or a native R/B id (those supported by the NAND controller). + */ +struct sunxi_nand_rb { + enum sunxi_nand_rb_type type; + union { + struct gpio_desc gpio; + int nativeid; + } info; +}; + +/* + * Chip Select structure: stores information related to NAND Chip Select + * + * @cs: the NAND CS id used to communicate with a NAND Chip + * @rb: the Ready/Busy description + */ +struct sunxi_nand_chip_sel { + u8 cs; + struct sunxi_nand_rb rb; +}; + +/* + * sunxi HW ECC infos: stores information related to HW ECC support + * + * @mode: the sunxi ECC mode field deduced from ECC requirements + * @layout: the OOB layout depending on the ECC requirements and the + * selected ECC mode + */ +struct sunxi_nand_hw_ecc { + int mode; + struct nand_ecclayout layout; +}; + +/* + * NAND chip structure: stores NAND chip device related information + * + * @node: used to store NAND chips into a list + * @nand: base NAND chip structure + * @mtd: base MTD structure + * @clk_rate: clk_rate required for this NAND chip + * @timing_cfg TIMING_CFG register value for this NAND chip + * @selected: current active CS + * @nsels: number of CS lines required by the NAND chip + * @sels: array of CS lines descriptions + */ +struct sunxi_nand_chip { + struct list_head node; + struct nand_chip nand; + unsigned long clk_rate; + u32 timing_cfg; + u32 timing_ctl; + int selected; + int addr_cycles; + u32 addr[2]; + int cmd_cycles; + u8 cmd[2]; + int nsels; + struct sunxi_nand_chip_sel sels[0]; +}; + +static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) +{ + return container_of(nand, struct sunxi_nand_chip, nand); +} + +/* + * NAND Controller structure: stores sunxi NAND controller information + * + * @controller: base controller structure + * @dev: parent device (used to print error messages) + * @regs: NAND controller registers + * @ahb_clk: NAND Controller AHB clock + * @mod_clk: NAND Controller mod clock + * @assigned_cs: bitmask describing already assigned CS lines + * @clk_rate: NAND controller current clock rate + * @chips: a list containing all the NAND chips attached to + * this NAND controller + * @complete: a completion object used to wait for NAND + * controller events + */ +struct sunxi_nfc { + struct nand_hw_control controller; + struct device *dev; + void __iomem *regs; + struct clk *ahb_clk; + struct clk *mod_clk; + unsigned long assigned_cs; + unsigned long clk_rate; + struct list_head chips; +}; + +static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl) +{ + return container_of(ctrl, struct sunxi_nfc, controller); +} + +static void sunxi_nfc_set_clk_rate(unsigned long hz) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + int div_m, div_n; + + div_m = (clock_get_pll6() + hz - 1) / hz; + for (div_n = 0; div_n < 3 && div_m > 16; div_n++) { + if (div_m % 2) + div_m++; + div_m >>= 1; + } + if (div_m > 16) + div_m = 16; + + /* config mod clock */ + writel(CCM_NAND_CTRL_ENABLE | CCM_NAND_CTRL_PLL6 | + CCM_NAND_CTRL_N(div_n) | CCM_NAND_CTRL_M(div_m), + &ccm->nand0_clk_cfg); + + /* gate on nand clock */ + setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_NAND0)); +#ifdef CONFIG_MACH_SUN9I + setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); +#else + setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); +#endif +} + +static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags, + unsigned int timeout_ms) +{ + unsigned int timeout_ticks; + u32 time_start, status; + int ret = -ETIMEDOUT; + + if (!timeout_ms) + timeout_ms = NFC_DEFAULT_TIMEOUT_MS; + + timeout_ticks = (timeout_ms * CONFIG_SYS_HZ) / 1000; + + time_start = get_timer(0); + + do { + status = readl(nfc->regs + NFC_REG_ST); + if ((status & flags) == flags) { + ret = 0; + break; + } + + udelay(1); + } while (get_timer(time_start) < timeout_ticks); + + writel(status & flags, nfc->regs + NFC_REG_ST); + + return ret; +} + +static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc) +{ + unsigned long timeout = (CONFIG_SYS_HZ * + NFC_DEFAULT_TIMEOUT_MS) / 1000; + u32 time_start; + + time_start = get_timer(0); + do { + if (!(readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS)) + return 0; + } while (get_timer(time_start) < timeout); + + dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n"); + return -ETIMEDOUT; +} + +static int sunxi_nfc_rst(struct sunxi_nfc *nfc) +{ + unsigned long timeout = (CONFIG_SYS_HZ * + NFC_DEFAULT_TIMEOUT_MS) / 1000; + u32 time_start; + + writel(0, nfc->regs + NFC_REG_ECC_CTL); + writel(NFC_RESET, nfc->regs + NFC_REG_CTL); + + time_start = get_timer(0); + do { + if (!(readl(nfc->regs + NFC_REG_CTL) & NFC_RESET)) + return 0; + } while (get_timer(time_start) < timeout); + + dev_err(nfc->dev, "wait for NAND controller reset timedout\n"); + return -ETIMEDOUT; +} + +static int sunxi_nfc_dev_ready(struct mtd_info *mtd) +{ + 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); + struct sunxi_nand_rb *rb; + unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20); + int ret; + + if (sunxi_nand->selected < 0) + return 0; + + rb = &sunxi_nand->sels[sunxi_nand->selected].rb; + + switch (rb->type) { + case RB_NATIVE: + ret = !!(readl(nfc->regs + NFC_REG_ST) & + NFC_RB_STATE(rb->info.nativeid)); + if (ret) + break; + + sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo); + ret = !!(readl(nfc->regs + NFC_REG_ST) & + NFC_RB_STATE(rb->info.nativeid)); + break; + case RB_GPIO: + ret = dm_gpio_get_value(&rb->info.gpio); + break; + case RB_NONE: + default: + ret = 0; + dev_err(nfc->dev, "cannot check R/B NAND status!\n"); + break; + } + + return ret; +} + +static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) +{ + 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); + struct sunxi_nand_chip_sel *sel; + u32 ctl; + + if (chip > 0 && chip >= sunxi_nand->nsels) + return; + + if (chip == sunxi_nand->selected) + return; + + ctl = readl(nfc->regs + NFC_REG_CTL) & + ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN); + + if (chip >= 0) { + sel = &sunxi_nand->sels[chip]; + + ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | + NFC_PAGE_SHIFT(nand->page_shift - 10); + if (sel->rb.type == RB_NONE) { + nand->dev_ready = NULL; + } else { + nand->dev_ready = sunxi_nfc_dev_ready; + if (sel->rb.type == RB_NATIVE) + ctl |= NFC_RB_SEL(sel->rb.info.nativeid); + } + + writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); + + if (nfc->clk_rate != sunxi_nand->clk_rate) { + sunxi_nfc_set_clk_rate(sunxi_nand->clk_rate); + nfc->clk_rate = sunxi_nand->clk_rate; + } + } + + writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL); + writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); + writel(ctl, nfc->regs + NFC_REG_CTL); + + sunxi_nand->selected = chip; +} + +static void sunxi_nfc_read_buf(struct mtd_info *mtd, 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; + int cnt; + int offs = 0; + u32 tmp; + + while (len > offs) { + cnt = min(len - offs, NFC_SRAM_SIZE); + + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); + if (ret) + break; + + writel(cnt, nfc->regs + NFC_REG_CNT); + tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD; + writel(tmp, nfc->regs + NFC_REG_CMD); + + ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + if (ret) + break; + + if (buf) + memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE, + cnt); + offs += cnt; + } +} + +static void sunxi_nfc_write_buf(struct mtd_info *mtd, 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; + int cnt; + int offs = 0; + u32 tmp; + + while (len > offs) { + cnt = min(len - offs, NFC_SRAM_SIZE); + + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); + if (ret) + break; + + writel(cnt, nfc->regs + NFC_REG_CNT); + memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt); + tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | + NFC_ACCESS_DIR; + writel(tmp, nfc->regs + NFC_REG_CMD); + + ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + if (ret) + break; + + offs += cnt; + } +} + +static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd) +{ + uint8_t ret; + + sunxi_nfc_read_buf(mtd, &ret, 1); + + return ret; +} + +static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, 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; + u32 tmp; + + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); + if (ret) + return; + + if (ctrl & NAND_CTRL_CHANGE) { + tmp = readl(nfc->regs + NFC_REG_CTL); + if (ctrl & NAND_NCE) + tmp |= NFC_CE_CTL; + else + tmp &= ~NFC_CE_CTL; + writel(tmp, nfc->regs + NFC_REG_CTL); + } + + if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) && + !(ctrl & (NAND_CLE | NAND_ALE))) { + u32 cmd = 0; + + if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles) + return; + + if (sunxi_nand->cmd_cycles--) + cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0]; + + if (sunxi_nand->cmd_cycles--) { + cmd |= NFC_SEND_CMD2; + writel(sunxi_nand->cmd[1], + nfc->regs + NFC_REG_RCMD_SET); + } + + sunxi_nand->cmd_cycles = 0; + + if (sunxi_nand->addr_cycles) { + cmd |= NFC_SEND_ADR | + NFC_ADR_NUM(sunxi_nand->addr_cycles); + writel(sunxi_nand->addr[0], + nfc->regs + NFC_REG_ADDR_LOW); + } + + if (sunxi_nand->addr_cycles > 4) + writel(sunxi_nand->addr[1], + nfc->regs + NFC_REG_ADDR_HIGH); + + writel(cmd, nfc->regs + NFC_REG_CMD); + sunxi_nand->addr[0] = 0; + sunxi_nand->addr[1] = 0; + sunxi_nand->addr_cycles = 0; + sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + } + + if (ctrl & NAND_CLE) { + sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat; + } else if (ctrl & NAND_ALE) { + sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |= + dat << ((sunxi_nand->addr_cycles % 4) * 8); + sunxi_nand->addr_cycles++; + } +} + +/* These seed values have been extracted from Allwinner's BSP */ +static const u16 sunxi_nfc_randomizer_page_seeds[] = { + 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72, + 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436, + 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d, + 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130, + 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56, + 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55, + 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb, + 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17, + 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62, + 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064, + 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126, + 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e, + 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3, + 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b, + 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d, + 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db, +}; + +/* + * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds + * have been generated using + * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what + * the randomizer engine does internally before de/scrambling OOB data. + * + * Those tables are statically defined to avoid calculating randomizer state + * at runtime. + */ +static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = { + 0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64, + 0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409, + 0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617, + 0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d, + 0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91, + 0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d, + 0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab, + 0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8, + 0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8, + 0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b, + 0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5, + 0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a, + 0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891, + 0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36, + 0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd, + 0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0, +}; + +static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = { + 0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6, + 0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982, + 0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9, + 0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07, + 0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e, + 0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2, + 0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c, + 0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f, + 0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc, + 0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e, + 0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8, + 0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68, + 0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d, + 0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179, + 0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601, + 0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd, +}; + +static u16 sunxi_nfc_randomizer_step(u16 state, int count) +{ + state &= 0x7fff; + + /* + * This loop is just a simple implementation of a Fibonacci LFSR using + * the x16 + x15 + 1 polynomial. + */ + while (count--) + state = ((state >> 1) | + (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff; + + return state; +} + +static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc) +{ + const u16 *seeds = sunxi_nfc_randomizer_page_seeds; + int mod = mtd->erasesize / mtd->writesize; + + if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds)) + mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds); + + if (ecc) { + if (mtd->ecc_step_size == 512) + seeds = sunxi_nfc_randomizer_ecc512_seeds; + else + seeds = sunxi_nfc_randomizer_ecc1024_seeds; + } + + return seeds[page % mod]; +} + +static void sunxi_nfc_randomizer_config(struct mtd_info *mtd, + int page, bool ecc) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); + u16 state; + + if (!(nand->options & NAND_NEED_SCRAMBLING)) + return; + + ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); + state = sunxi_nfc_randomizer_state(mtd, page, ecc); + ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK; + writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL); +} + +static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + + if (!(nand->options & NAND_NEED_SCRAMBLING)) + return; + + writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN, + nfc->regs + NFC_REG_ECC_CTL); +} + +static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + + if (!(nand->options & NAND_NEED_SCRAMBLING)) + return; + + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN, + nfc->regs + NFC_REG_ECC_CTL); +} + +static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm) +{ + u16 state = sunxi_nfc_randomizer_state(mtd, page, true); + + bbm[0] ^= state; + bbm[1] ^= sunxi_nfc_randomizer_step(state, 8); +} + +static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd, + const uint8_t *buf, int len, + bool ecc, int page) +{ + sunxi_nfc_randomizer_config(mtd, page, ecc); + sunxi_nfc_randomizer_enable(mtd); + sunxi_nfc_write_buf(mtd, buf, len); + sunxi_nfc_randomizer_disable(mtd); +} + +static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf, + int len, bool ecc, int page) +{ + sunxi_nfc_randomizer_config(mtd, page, ecc); + sunxi_nfc_randomizer_enable(mtd); + sunxi_nfc_read_buf(mtd, buf, len); + sunxi_nfc_randomizer_disable(mtd); +} + +static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + struct sunxi_nand_hw_ecc *data = nand->ecc.priv; + u32 ecc_ctl; + + ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); + ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE | + NFC_ECC_BLOCK_SIZE_MSK); + ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION; + + if (nand->ecc.size == 512) + ecc_ctl |= NFC_ECC_BLOCK_512; + + writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL); +} + +static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, + nfc->regs + NFC_REG_ECC_CTL); +} + +static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf) +{ + buf[0] = user_data; + buf[1] = user_data >> 8; + buf[2] = user_data >> 16; + buf[3] = user_data >> 24; +} + +static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, + u8 *data, int data_off, + u8 *oob, int oob_off, + int *cur_off, + unsigned int *max_bitflips, + bool bbm, int page) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + struct nand_ecc_ctrl *ecc = &nand->ecc; + int raw_mode = 0; + u32 status; + int ret; + + if (*cur_off != data_off) + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); + + sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page); + + if (data_off + ecc->size != oob_off) + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); + + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); + if (ret) + return ret; + + sunxi_nfc_randomizer_enable(mtd); + writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, + nfc->regs + NFC_REG_CMD); + + ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + sunxi_nfc_randomizer_disable(mtd); + if (ret) + return ret; + + *cur_off = oob_off + ecc->bytes + 4; + + status = readl(nfc->regs + NFC_REG_ECC_ST); + if (status & NFC_ECC_PAT_FOUND(0)) { + u8 pattern = 0xff; + + if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) + pattern = 0x0; + + memset(data, pattern, ecc->size); + memset(oob, pattern, ecc->bytes + 4); + + return 1; + } + + ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0))); + + memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); + + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); + sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page); + + if (status & NFC_ECC_ERR(0)) { + /* + * Re-read the data with the randomizer disabled to identify + * bitflips in erased pages. + */ + if (nand->options & NAND_NEED_SCRAMBLING) { + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); + nand->read_buf(mtd, data, ecc->size); + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); + nand->read_buf(mtd, oob, ecc->bytes + 4); + } + + ret = nand_check_erased_ecc_chunk(data, ecc->size, + oob, ecc->bytes + 4, + NULL, 0, ecc->strength); + if (ret >= 0) + raw_mode = 1; + } else { + /* + * The engine protects 4 bytes of OOB data per chunk. + * Retrieve the corrected OOB bytes. + */ + sunxi_nfc_user_data_to_buf(readl(nfc->regs + + NFC_REG_USER_DATA(0)), + oob); + + /* De-randomize the Bad Block Marker. */ + if (bbm && nand->options & NAND_NEED_SCRAMBLING) + sunxi_nfc_randomize_bbm(mtd, page, oob); + } + + if (ret < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += ret; + *max_bitflips = max_t(unsigned int, *max_bitflips, ret); + } + + return raw_mode; +} + +static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd, + u8 *oob, int *cur_off, + bool randomize, int page) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &nand->ecc; + int offset = ((ecc->bytes + 4) * ecc->steps); + int len = mtd->oobsize - offset; + + if (len <= 0) + return; + + if (*cur_off != offset) + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, + offset + mtd->writesize, -1); + + if (!randomize) + sunxi_nfc_read_buf(mtd, oob + offset, len); + else + sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len, + false, page); + + *cur_off = mtd->oobsize + mtd->writesize; +} + +static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf) +{ + return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); +} + +static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, + const u8 *data, int data_off, + const u8 *oob, int oob_off, + int *cur_off, bool bbm, + int page) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + struct nand_ecc_ctrl *ecc = &nand->ecc; + int ret; + + if (data_off != *cur_off) + nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1); + + sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page); + + /* Fill OOB data in */ + if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) { + u8 user_data[4]; + + memcpy(user_data, oob, 4); + sunxi_nfc_randomize_bbm(mtd, page, user_data); + writel(sunxi_nfc_buf_to_user_data(user_data), + nfc->regs + NFC_REG_USER_DATA(0)); + } else { + writel(sunxi_nfc_buf_to_user_data(oob), + nfc->regs + NFC_REG_USER_DATA(0)); + } + + if (data_off + ecc->size != oob_off) + nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1); + + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); + if (ret) + return ret; + + sunxi_nfc_randomizer_enable(mtd); + writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | + NFC_ACCESS_DIR | NFC_ECC_OP, + nfc->regs + NFC_REG_CMD); + + ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + sunxi_nfc_randomizer_disable(mtd); + if (ret) + return ret; + + *cur_off = oob_off + ecc->bytes + 4; + + return 0; +} + +static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd, + u8 *oob, int *cur_off, + int page) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &nand->ecc; + int offset = ((ecc->bytes + 4) * ecc->steps); + int len = mtd->oobsize - offset; + + if (len <= 0) + return; + + if (*cur_off != offset) + nand->cmdfunc(mtd, NAND_CMD_RNDIN, + offset + mtd->writesize, -1); + + sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page); + + *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, + int oob_required, int page) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + unsigned int max_bitflips = 0; + int ret, i, cur_off = 0; + bool raw_mode = false; + + sunxi_nfc_hw_ecc_enable(mtd); + + for (i = 0; i < ecc->steps; i++) { + int data_off = i * ecc->size; + int oob_off = i * (ecc->bytes + 4); + u8 *data = buf + data_off; + u8 *oob = chip->oob_poi + oob_off; + + ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, + oob_off + mtd->writesize, + &cur_off, &max_bitflips, + !i, page); + if (ret < 0) + return ret; + else if (ret) + raw_mode = true; + } + + if (oob_required) + sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, + !raw_mode, page); + + sunxi_nfc_hw_ecc_disable(mtd); + + return max_bitflips; +} + +static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, + struct nand_chip *chip, + uint32_t data_offs, uint32_t readlen, + uint8_t *bufpoi, int page) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + int ret, i, cur_off = 0; + unsigned int max_bitflips = 0; + + sunxi_nfc_hw_ecc_enable(mtd); + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + for (i = data_offs / ecc->size; + i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) { + int data_off = i * ecc->size; + int oob_off = i * (ecc->bytes + 4); + u8 *data = bufpoi + data_off; + u8 *oob = chip->oob_poi + oob_off; + + ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, + oob, oob_off + mtd->writesize, + &cur_off, &max_bitflips, !i, page); + if (ret < 0) + return ret; + } + + sunxi_nfc_hw_ecc_disable(mtd); + + return max_bitflips; +} + +static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required, + int page) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + int ret, i, cur_off = 0; + + sunxi_nfc_hw_ecc_enable(mtd); + + for (i = 0; i < ecc->steps; i++) { + int data_off = i * ecc->size; + int oob_off = i * (ecc->bytes + 4); + const u8 *data = buf + data_off; + const u8 *oob = chip->oob_poi + oob_off; + + ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, + oob_off + mtd->writesize, + &cur_off, !i, page); + if (ret) + return ret; + } + + if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) + sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, + &cur_off, page); + + sunxi_nfc_hw_ecc_disable(mtd); + + return 0; +} + +static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, + struct nand_chip *chip, + u32 data_offs, u32 data_len, + const u8 *buf, int oob_required, + int page) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + int ret, i, cur_off = 0; + + sunxi_nfc_hw_ecc_enable(mtd); + + for (i = data_offs / ecc->size; + i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) { + int data_off = i * ecc->size; + int oob_off = i * (ecc->bytes + 4); + const u8 *data = buf + data_off; + const u8 *oob = chip->oob_poi + oob_off; + + ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, + oob_off + mtd->writesize, + &cur_off, !i, page); + if (ret) + return ret; + } + + sunxi_nfc_hw_ecc_disable(mtd); + + return 0; +} + +static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int oob_required, + int page) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + unsigned int max_bitflips = 0; + int ret, i, cur_off = 0; + bool raw_mode = false; + + sunxi_nfc_hw_ecc_enable(mtd); + + for (i = 0; i < ecc->steps; i++) { + int data_off = i * (ecc->size + ecc->bytes + 4); + int oob_off = data_off + ecc->size; + u8 *data = buf + (i * ecc->size); + u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); + + ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, + oob_off, &cur_off, + &max_bitflips, !i, page); + if (ret < 0) + return ret; + else if (ret) + raw_mode = true; + } + + if (oob_required) + sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, + !raw_mode, page); + + sunxi_nfc_hw_ecc_disable(mtd); + + return max_bitflips; +} + +static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, + int oob_required, int page) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + int ret, i, cur_off = 0; + + sunxi_nfc_hw_ecc_enable(mtd); + + for (i = 0; i < ecc->steps; i++) { + int data_off = i * (ecc->size + ecc->bytes + 4); + int oob_off = data_off + ecc->size; + const u8 *data = buf + (i * ecc->size); + const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); + + ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, + oob, oob_off, &cur_off, + false, page); + if (ret) + return ret; + } + + if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) + sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, + &cur_off, page); + + sunxi_nfc_hw_ecc_disable(mtd); + + return 0; +} + +static const s32 tWB_lut[] = {6, 12, 16, 20}; +static const s32 tRHW_lut[] = {4, 8, 12, 20}; + +static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, + u32 clk_period) +{ + u32 clk_cycles = DIV_ROUND_UP(duration, clk_period); + int i; + + for (i = 0; i < lut_size; i++) { + if (clk_cycles <= lut[i]) + return i; + } + + /* Doesn't fit */ + return -EINVAL; +} + +#define sunxi_nand_lookup_timing(l, p, c) \ + _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) + +static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, + const struct nand_sdr_timings *timings) +{ + u32 min_clk_period = 0; + s32 tWB, tADL, tWHR, tRHW, tCAD; + + /* T1 <=> tCLS */ + if (timings->tCLS_min > min_clk_period) + min_clk_period = timings->tCLS_min; + + /* T2 <=> tCLH */ + if (timings->tCLH_min > min_clk_period) + min_clk_period = timings->tCLH_min; + + /* T3 <=> tCS */ + if (timings->tCS_min > min_clk_period) + min_clk_period = timings->tCS_min; + + /* T4 <=> tCH */ + if (timings->tCH_min > min_clk_period) + min_clk_period = timings->tCH_min; + + /* T5 <=> tWP */ + if (timings->tWP_min > min_clk_period) + min_clk_period = timings->tWP_min; + + /* T6 <=> tWH */ + if (timings->tWH_min > min_clk_period) + min_clk_period = timings->tWH_min; + + /* T7 <=> tALS */ + if (timings->tALS_min > min_clk_period) + min_clk_period = timings->tALS_min; + + /* T8 <=> tDS */ + if (timings->tDS_min > min_clk_period) + min_clk_period = timings->tDS_min; + + /* T9 <=> tDH */ + if (timings->tDH_min > min_clk_period) + min_clk_period = timings->tDH_min; + + /* T10 <=> tRR */ + if (timings->tRR_min > (min_clk_period * 3)) + min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3); + + /* T11 <=> tALH */ + if (timings->tALH_min > min_clk_period) + min_clk_period = timings->tALH_min; + + /* T12 <=> tRP */ + if (timings->tRP_min > min_clk_period) + min_clk_period = timings->tRP_min; + + /* T13 <=> tREH */ + if (timings->tREH_min > min_clk_period) + min_clk_period = timings->tREH_min; + + /* T14 <=> tRC */ + if (timings->tRC_min > (min_clk_period * 2)) + min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2); + + /* T15 <=> tWC */ + if (timings->tWC_min > (min_clk_period * 2)) + min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); + + /* T16 - T19 + tCAD */ + tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max, + min_clk_period); + if (tWB < 0) { + dev_err(nfc->dev, "unsupported tWB\n"); + return tWB; + } + + tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3; + if (tADL > 3) { + dev_err(nfc->dev, "unsupported tADL\n"); + return -EINVAL; + } + + tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3; + if (tWHR > 3) { + dev_err(nfc->dev, "unsupported tWHR\n"); + return -EINVAL; + } + + tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min, + min_clk_period); + if (tRHW < 0) { + dev_err(nfc->dev, "unsupported tRHW\n"); + return tRHW; + } + + /* + * TODO: according to ONFI specs this value only applies for DDR NAND, + * but Allwinner seems to set this to 0x7. Mimic them for now. + */ + tCAD = 0x7; + + /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */ + chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); + + /* + * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data + * output cycle timings shall be used if the host drives tRC less than + * 30 ns. + */ + chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0; + + /* Convert min_clk_period from picoseconds to nanoseconds */ + min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); + + /* + * Convert min_clk_period into a clk frequency, then get the + * appropriate rate for the NAND controller IP given this formula + * (specified in the datasheet): + * nand clk_rate = min_clk_rate + */ + chip->clk_rate = 1000000000L / min_clk_period; + + return 0; +} + +static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(&chip->nand); + const struct nand_sdr_timings *timings; + int ret; + int mode; + + mode = onfi_get_async_timing_mode(&chip->nand); + if (mode == ONFI_TIMING_MODE_UNKNOWN) { + mode = chip->nand.onfi_timing_mode_default; + } else { + uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; + int i; + + mode = fls(mode) - 1; + if (mode < 0) + mode = 0; + + feature[0] = mode; + for (i = 0; i < chip->nsels; i++) { + chip->nand.select_chip(mtd, i); + ret = chip->nand.onfi_set_features(mtd, + &chip->nand, + ONFI_FEATURE_ADDR_TIMING_MODE, + feature); + chip->nand.select_chip(mtd, -1); + if (ret && ret != -ENOTSUPP) + return ret; + } + } + + timings = onfi_async_timing_mode_to_sdr_timings(mode); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + return sunxi_nand_chip_set_timings(chip, timings); +} + +static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, + struct nand_ecc_ctrl *ecc) +{ + static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; + struct sunxi_nand_hw_ecc *data; + struct nand_ecclayout *layout; + int nsectors; + int ret; + int i; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (ecc->size != 512 && ecc->size != 1024) + return -EINVAL; + + /* Prefer 1k ECC chunk over 512 ones */ + if (ecc->size == 512 && mtd->writesize > 512) { + ecc->size = 1024; + ecc->strength *= 2; + } + + /* Add ECC info retrieval from DT */ + for (i = 0; i < ARRAY_SIZE(strengths); i++) { + if (ecc->strength <= strengths[i]) { + /* + * Update ecc->strength value with the actual strength + * that will be used by the ECC engine. + */ + ecc->strength = strengths[i]; + break; + } + } + + if (i >= ARRAY_SIZE(strengths)) { + dev_err(nfc->dev, "unsupported strength\n"); + ret = -ENOTSUPP; + goto err; + } + + data->mode = i; + + /* HW ECC always request ECC bytes for 1024 bytes blocks */ + ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8); + + /* HW ECC always work with even numbers of ECC bytes */ + ecc->bytes = ALIGN(ecc->bytes, 2); + + layout = &data->layout; + nsectors = mtd->writesize / ecc->size; + + if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) { + ret = -EINVAL; + goto err; + } + + layout->eccbytes = (ecc->bytes * nsectors); + + ecc->layout = layout; + ecc->priv = data; + + return 0; + +err: + kfree(data); + + return ret; +} + +#ifndef __UBOOT__ +static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc) +{ + kfree(ecc->priv); +} +#endif /* __UBOOT__ */ + +static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, + struct nand_ecc_ctrl *ecc) +{ + struct nand_ecclayout *layout; + int nsectors; + int i, j; + int ret; + + ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc); + if (ret) + return ret; + + ecc->read_page = sunxi_nfc_hw_ecc_read_page; + ecc->write_page = sunxi_nfc_hw_ecc_write_page; + ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage; + ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage; + layout = ecc->layout; + nsectors = mtd->writesize / ecc->size; + + for (i = 0; i < nsectors; i++) { + if (i) { + layout->oobfree[i].offset = + layout->oobfree[i - 1].offset + + layout->oobfree[i - 1].length + + ecc->bytes; + layout->oobfree[i].length = 4; + } else { + /* + * The first 2 bytes are used for BB markers, hence we + * only have 2 bytes available in the first user data + * section. + */ + layout->oobfree[i].length = 2; + layout->oobfree[i].offset = 2; + } + + for (j = 0; j < ecc->bytes; j++) + layout->eccpos[(ecc->bytes * i) + j] = + layout->oobfree[i].offset + + layout->oobfree[i].length + j; + } + + if (mtd->oobsize > (ecc->bytes + 4) * nsectors) { + layout->oobfree[nsectors].offset = + layout->oobfree[nsectors - 1].offset + + layout->oobfree[nsectors - 1].length + + ecc->bytes; + layout->oobfree[nsectors].length = mtd->oobsize - + ((ecc->bytes + 4) * nsectors); + } + + return 0; +} + +static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd, + struct nand_ecc_ctrl *ecc) +{ + struct nand_ecclayout *layout; + int nsectors; + int i; + int ret; + + ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc); + if (ret) + return ret; + + ecc->prepad = 4; + ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page; + ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page; + + layout = ecc->layout; + nsectors = mtd->writesize / ecc->size; + + for (i = 0; i < (ecc->bytes * nsectors); i++) + layout->eccpos[i] = i; + + layout->oobfree[0].length = mtd->oobsize - i; + layout->oobfree[0].offset = i; + + return 0; +} + +#ifndef __UBOOT__ +static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc) +{ + switch (ecc->mode) { + case NAND_ECC_HW: + case NAND_ECC_HW_SYNDROME: + sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc); + break; + case NAND_ECC_NONE: + kfree(ecc->layout); + default: + break; + } +} +#endif /* __UBOOT__ */ + +static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + int ret; + + if (!ecc->size) { + ecc->size = nand->ecc_step_ds; + ecc->strength = nand->ecc_strength_ds; + } + + if (!ecc->size || !ecc->strength) + return -EINVAL; + + switch (ecc->mode) { + case NAND_ECC_SOFT_BCH: + break; + case NAND_ECC_HW: + ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc); + if (ret) + return ret; + break; + case NAND_ECC_HW_SYNDROME: + ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc); + if (ret) + return ret; + break; + case NAND_ECC_NONE: + ecc->layout = kzalloc(sizeof(*ecc->layout), GFP_KERNEL); + if (!ecc->layout) + return -ENOMEM; + ecc->layout->oobfree[0].length = mtd->oobsize; + case NAND_ECC_SOFT: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum) +{ + const struct nand_sdr_timings *timings; + const void *blob = gd->fdt_blob; + struct sunxi_nand_chip *chip; + struct mtd_info *mtd; + struct nand_chip *nand; + int nsels; + int ret; + int i; + u32 cs[8], rb[8]; + + if (!fdt_getprop(blob, node, "reg", &nsels)) + return -EINVAL; + + nsels /= sizeof(u32); + if (!nsels || nsels > 8) { + dev_err(dev, "invalid reg property size\n"); + return -EINVAL; + } + + chip = kzalloc(sizeof(*chip) + + (nsels * sizeof(struct sunxi_nand_chip_sel)), + GFP_KERNEL); + if (!chip) { + dev_err(dev, "could not allocate chip\n"); + return -ENOMEM; + } + + chip->nsels = nsels; + chip->selected = -1; + + for (i = 0; i < nsels; i++) { + cs[i] = -1; + rb[i] = -1; + } + + ret = fdtdec_get_int_array(gd->fdt_blob, node, "reg", cs, nsels); + if (ret) { + dev_err(dev, "could not retrieve reg property: %d\n", ret); + return ret; + } + + ret = fdtdec_get_int_array(gd->fdt_blob, node, "allwinner,rb", rb, + nsels); + if (ret) { + dev_err(dev, "could not retrieve reg property: %d\n", ret); + return ret; + } + + for (i = 0; i < nsels; i++) { + int tmp = cs[i]; + + if (tmp > NFC_MAX_CS) { + dev_err(dev, + "invalid reg value: %u (max CS = 7)\n", + tmp); + return -EINVAL; + } + + if (test_and_set_bit(tmp, &nfc->assigned_cs)) { + dev_err(dev, "CS %d already assigned\n", tmp); + return -EINVAL; + } + + chip->sels[i].cs = tmp; + + tmp = rb[i]; + if (tmp >= 0 && tmp < 2) { + chip->sels[i].rb.type = RB_NATIVE; + chip->sels[i].rb.info.nativeid = tmp; + } else { + ret = gpio_request_by_name_nodev(offset_to_ofnode(node), + "rb-gpios", i, + &chip->sels[i].rb.info.gpio, + GPIOD_IS_IN); + if (ret) + chip->sels[i].rb.type = RB_GPIO; + else + chip->sels[i].rb.type = RB_NONE; + } + } + + timings = onfi_async_timing_mode_to_sdr_timings(0); + if (IS_ERR(timings)) { + ret = PTR_ERR(timings); + dev_err(dev, + "could not retrieve timings for ONFI mode 0: %d\n", + ret); + return ret; + } + + ret = sunxi_nand_chip_set_timings(chip, timings); + if (ret) { + dev_err(dev, "could not configure chip timings: %d\n", ret); + return ret; + } + + nand = &chip->nand; + /* Default tR value specified in the ONFI spec (chapter 4.15.1) */ + nand->chip_delay = 200; + nand->controller = &nfc->controller; + /* + * Set the ECC mode to the default value in case nothing is specified + * in the DT. + */ + nand->ecc.mode = NAND_ECC_HW; + nand->flash_node = node; + 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; + + mtd = nand_to_mtd(nand); + ret = nand_scan_ident(mtd, nsels, NULL); + if (ret) + return ret; + + if (nand->bbt_options & NAND_BBT_USE_FLASH) + nand->bbt_options |= NAND_BBT_NO_OOB; + + if (nand->options & NAND_NEED_SCRAMBLING) + nand->options |= NAND_NO_SUBPAGE_WRITE; + + nand->options |= NAND_SUBPAGE_READ; + + ret = sunxi_nand_chip_init_timings(chip); + if (ret) { + dev_err(dev, "could not configure chip timings: %d\n", ret); + return ret; + } + + ret = sunxi_nand_ecc_init(mtd, &nand->ecc); + if (ret) { + dev_err(dev, "ECC init failed: %d\n", ret); + return ret; + } + + ret = nand_scan_tail(mtd); + if (ret) { + dev_err(dev, "nand_scan_tail failed: %d\n", ret); + return ret; + } + + ret = nand_register(devnum, mtd); + if (ret) { + dev_err(dev, "failed to register mtd device: %d\n", ret); + return ret; + } + + list_add_tail(&chip->node, &nfc->chips); + + return 0; +} + +static int sunxi_nand_chips_init(int node, struct sunxi_nfc *nfc) +{ + const void *blob = gd->fdt_blob; + int nand_node; + int ret, i = 0; + + for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0; + nand_node = fdt_next_subnode(blob, nand_node)) + i++; + + if (i > 8) { + dev_err(dev, "too many NAND chips: %d (max = 8)\n", i); + return -EINVAL; + } + + i = 0; + for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0; + nand_node = fdt_next_subnode(blob, nand_node)) { + ret = sunxi_nand_chip_init(nand_node, nfc, i++); + if (ret) + return ret; + } + + return 0; +} + +#ifndef __UBOOT__ +static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc) +{ + struct sunxi_nand_chip *chip; + + while (!list_empty(&nfc->chips)) { + chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip, + node); + nand_release(&chip->mtd); + sunxi_nand_ecc_cleanup(&chip->nand.ecc); + list_del(&chip->node); + kfree(chip); + } +} +#endif /* __UBOOT__ */ + +void sunxi_nand_init(void) +{ + const void *blob = gd->fdt_blob; + struct sunxi_nfc *nfc; + fdt_addr_t regs; + int node; + int ret; + + nfc = kzalloc(sizeof(*nfc), GFP_KERNEL); + if (!nfc) + return; + + spin_lock_init(&nfc->controller.lock); + init_waitqueue_head(&nfc->controller.wq); + INIT_LIST_HEAD(&nfc->chips); + + node = fdtdec_next_compatible(blob, 0, COMPAT_SUNXI_NAND); + if (node < 0) { + pr_err("unable to find nfc node in device tree\n"); + goto err; + } + + if (!fdtdec_get_is_enabled(blob, node)) { + pr_err("nfc disabled in device tree\n"); + goto err; + } + + regs = fdtdec_get_addr(blob, node, "reg"); + if (regs == FDT_ADDR_T_NONE) { + pr_err("unable to find nfc address in device tree\n"); + goto err; + } + + nfc->regs = (void *)regs; + + ret = sunxi_nfc_rst(nfc); + if (ret) + goto err; + + ret = sunxi_nand_chips_init(node, nfc); + if (ret) { + dev_err(dev, "failed to init nand chips\n"); + goto err; + } + + return; + +err: + kfree(nfc); +} + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Boris BREZILLON"); +MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver"); diff --git a/drivers/mtd/nand/raw/sunxi_nand_spl.c b/drivers/mtd/nand/raw/sunxi_nand_spl.c new file mode 100644 index 0000000000..6cde9814c4 --- /dev/null +++ b/drivers/mtd/nand/raw/sunxi_nand_spl.c @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2014-2015, Antmicro Ltd + * Copyright (c) 2015, AW-SOM Technologies + */ + +#include +#include +#include +#include +#include +#include + +/* registers */ +#define NFC_CTL 0x00000000 +#define NFC_ST 0x00000004 +#define NFC_INT 0x00000008 +#define NFC_TIMING_CTL 0x0000000C +#define NFC_TIMING_CFG 0x00000010 +#define NFC_ADDR_LOW 0x00000014 +#define NFC_ADDR_HIGH 0x00000018 +#define NFC_SECTOR_NUM 0x0000001C +#define NFC_CNT 0x00000020 +#define NFC_CMD 0x00000024 +#define NFC_RCMD_SET 0x00000028 +#define NFC_WCMD_SET 0x0000002C +#define NFC_IO_DATA 0x00000030 +#define NFC_ECC_CTL 0x00000034 +#define NFC_ECC_ST 0x00000038 +#define NFC_DEBUG 0x0000003C +#define NFC_ECC_CNT0 0x00000040 +#define NFC_ECC_CNT1 0x00000044 +#define NFC_ECC_CNT2 0x00000048 +#define NFC_ECC_CNT3 0x0000004C +#define NFC_USER_DATA_BASE 0x00000050 +#define NFC_EFNAND_STATUS 0x00000090 +#define NFC_SPARE_AREA 0x000000A0 +#define NFC_PATTERN_ID 0x000000A4 +#define NFC_RAM0_BASE 0x00000400 +#define NFC_RAM1_BASE 0x00000800 + +#define NFC_CTL_EN (1 << 0) +#define NFC_CTL_RESET (1 << 1) +#define NFC_CTL_RAM_METHOD (1 << 14) +#define NFC_CTL_PAGE_SIZE_MASK (0xf << 8) +#define NFC_CTL_PAGE_SIZE(a) ((fls(a) - 11) << 8) + + +#define NFC_ECC_EN (1 << 0) +#define NFC_ECC_PIPELINE (1 << 3) +#define NFC_ECC_EXCEPTION (1 << 4) +#define NFC_ECC_BLOCK_SIZE (1 << 5) +#define NFC_ECC_RANDOM_EN (1 << 9) +#define NFC_ECC_RANDOM_DIRECTION (1 << 10) + + +#define NFC_ADDR_NUM_OFFSET 16 +#define NFC_SEND_ADDR (1 << 19) +#define NFC_ACCESS_DIR (1 << 20) +#define NFC_DATA_TRANS (1 << 21) +#define NFC_SEND_CMD1 (1 << 22) +#define NFC_WAIT_FLAG (1 << 23) +#define NFC_SEND_CMD2 (1 << 24) +#define NFC_SEQ (1 << 25) +#define NFC_DATA_SWAP_METHOD (1 << 26) +#define NFC_ROW_AUTO_INC (1 << 27) +#define NFC_SEND_CMD3 (1 << 28) +#define NFC_SEND_CMD4 (1 << 29) +#define NFC_RAW_CMD (0 << 30) +#define NFC_ECC_CMD (1 << 30) +#define NFC_PAGE_CMD (2 << 30) + +#define NFC_ST_CMD_INT_FLAG (1 << 1) +#define NFC_ST_DMA_INT_FLAG (1 << 2) +#define NFC_ST_CMD_FIFO_STAT (1 << 3) + +#define NFC_READ_CMD_OFFSET 0 +#define NFC_RANDOM_READ_CMD0_OFFSET 8 +#define NFC_RANDOM_READ_CMD1_OFFSET 16 + +#define NFC_CMD_RNDOUTSTART 0xE0 +#define NFC_CMD_RNDOUT 0x05 +#define NFC_CMD_READSTART 0x30 + +struct nfc_config { + int page_size; + int ecc_strength; + int ecc_size; + int addr_cycles; + int nseeds; + bool randomize; + bool valid; +}; + +/* minimal "boot0" style NAND support for Allwinner A20 */ + +/* random seed used by linux */ +const uint16_t random_seed[128] = { + 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72, + 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436, + 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d, + 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130, + 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56, + 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55, + 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb, + 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17, + 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62, + 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064, + 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126, + 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e, + 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3, + 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b, + 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d, + 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db, +}; + +#define DEFAULT_TIMEOUT_US 100000 + +static int check_value_inner(int offset, int expected_bits, + int timeout_us, int negation) +{ + do { + int val = readl(offset) & expected_bits; + if (negation ? !val : val) + return 1; + udelay(1); + } while (--timeout_us); + + return 0; +} + +static inline int check_value(int offset, int expected_bits, + int timeout_us) +{ + return check_value_inner(offset, expected_bits, timeout_us, 0); +} + +static inline int check_value_negated(int offset, int unexpected_bits, + int timeout_us) +{ + return check_value_inner(offset, unexpected_bits, timeout_us, 1); +} + +static int nand_wait_cmd_fifo_empty(void) +{ + if (!check_value_negated(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_FIFO_STAT, + DEFAULT_TIMEOUT_US)) { + printf("nand: timeout waiting for empty cmd FIFO\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int nand_wait_int(void) +{ + if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, + DEFAULT_TIMEOUT_US)) { + printf("nand: timeout waiting for interruption\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int nand_exec_cmd(u32 cmd) +{ + int ret; + + ret = nand_wait_cmd_fifo_empty(); + if (ret) + return ret; + + writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); + writel(cmd, SUNXI_NFC_BASE + NFC_CMD); + + return nand_wait_int(); +} + +void nand_init(void) +{ + uint32_t val; + + board_nand_init(); + + val = readl(SUNXI_NFC_BASE + NFC_CTL); + /* enable and reset CTL */ + writel(val | NFC_CTL_EN | NFC_CTL_RESET, + SUNXI_NFC_BASE + NFC_CTL); + + if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL, + NFC_CTL_RESET, DEFAULT_TIMEOUT_US)) { + printf("Couldn't initialize nand\n"); + } + + /* reset NAND */ + nand_exec_cmd(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET); +} + +static void nand_apply_config(const struct nfc_config *conf) +{ + u32 val; + + nand_wait_cmd_fifo_empty(); + + val = readl(SUNXI_NFC_BASE + NFC_CTL); + val &= ~NFC_CTL_PAGE_SIZE_MASK; + writel(val | NFC_CTL_RAM_METHOD | NFC_CTL_PAGE_SIZE(conf->page_size), + SUNXI_NFC_BASE + NFC_CTL); + writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT); + writel(conf->page_size, SUNXI_NFC_BASE + NFC_SPARE_AREA); +} + +static int nand_load_page(const struct nfc_config *conf, u32 offs) +{ + int page = offs / conf->page_size; + + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | + (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | + (NFC_CMD_READSTART << NFC_READ_CMD_OFFSET), + SUNXI_NFC_BASE + NFC_RCMD_SET); + writel(((page & 0xFFFF) << 16), SUNXI_NFC_BASE + NFC_ADDR_LOW); + writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH); + + return nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | + NFC_SEND_ADDR | NFC_WAIT_FLAG | + ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET)); +} + +static int nand_change_column(u16 column) +{ + int ret; + + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | + (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | + (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET), + SUNXI_NFC_BASE + NFC_RCMD_SET); + writel(column, SUNXI_NFC_BASE + NFC_ADDR_LOW); + + ret = nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | + (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | + NFC_CMD_RNDOUT); + if (ret) + return ret; + + /* Ensure tCCS has passed before reading data */ + udelay(1); + + return 0; +} + +static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116}; + +static int nand_read_page(const struct nfc_config *conf, u32 offs, + void *dest, int len) +{ + int nsectors = len / conf->ecc_size; + u16 rand_seed = 0; + int oob_chunk_sz = ecc_bytes[conf->ecc_strength]; + int page = offs / conf->page_size; + u32 ecc_st; + int i; + + if (offs % conf->page_size || len % conf->ecc_size || + len > conf->page_size || len < 0) + return -EINVAL; + + /* Choose correct seed if randomized */ + if (conf->randomize) + rand_seed = random_seed[page % conf->nseeds]; + + /* Retrieve data from SRAM (PIO) */ + for (i = 0; i < nsectors; i++) { + int data_off = i * conf->ecc_size; + int oob_off = conf->page_size + (i * oob_chunk_sz); + u8 *data = dest + data_off; + + /* Clear ECC status and restart ECC engine */ + writel(0, SUNXI_NFC_BASE + NFC_ECC_ST); + writel((rand_seed << 16) | (conf->ecc_strength << 12) | + (conf->randomize ? NFC_ECC_RANDOM_EN : 0) | + (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) | + NFC_ECC_EN | NFC_ECC_EXCEPTION, + SUNXI_NFC_BASE + NFC_ECC_CTL); + + /* Move the data in SRAM */ + nand_change_column(data_off); + writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT); + nand_exec_cmd(NFC_DATA_TRANS); + + /* + * Let the ECC engine consume the ECC bytes and possibly correct + * the data. + */ + nand_change_column(oob_off); + nand_exec_cmd(NFC_DATA_TRANS | NFC_ECC_CMD); + + /* Get the ECC status */ + ecc_st = readl(SUNXI_NFC_BASE + NFC_ECC_ST); + + /* ECC error detected. */ + if (ecc_st & 0xffff) + return -EIO; + + /* + * Return 1 if the first chunk is empty (needed for + * configuration detection). + */ + if (!i && (ecc_st & 0x10000)) + return 1; + + /* Retrieve the data from SRAM */ + memcpy_fromio(data, SUNXI_NFC_BASE + NFC_RAM0_BASE, + conf->ecc_size); + + /* Stop the ECC engine */ + writel(readl(SUNXI_NFC_BASE + NFC_ECC_CTL) & ~NFC_ECC_EN, + SUNXI_NFC_BASE + NFC_ECC_CTL); + + if (data_off + conf->ecc_size >= len) + break; + } + + return 0; +} + +static int nand_max_ecc_strength(struct nfc_config *conf) +{ + int max_oobsize, max_ecc_bytes; + int nsectors = conf->page_size / conf->ecc_size; + int i; + + /* + * ECC strength is limited by the size of the OOB area which is + * correlated with the page size. + */ + switch (conf->page_size) { + case 2048: + max_oobsize = 64; + break; + case 4096: + max_oobsize = 256; + break; + case 8192: + max_oobsize = 640; + break; + case 16384: + max_oobsize = 1664; + break; + default: + return -EINVAL; + } + + max_ecc_bytes = max_oobsize / nsectors; + + for (i = 0; i < ARRAY_SIZE(ecc_bytes); i++) { + if (ecc_bytes[i] > max_ecc_bytes) + break; + } + + if (!i) + return -EINVAL; + + return i - 1; +} + +static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs, + void *dest) +{ + /* NAND with pages > 4k will likely require 1k sector size. */ + int min_ecc_size = conf->page_size > 4096 ? 1024 : 512; + int page = offs / conf->page_size; + int ret; + + /* + * In most cases, 1k sectors are preferred over 512b ones, start + * testing this config first. + */ + for (conf->ecc_size = 1024; conf->ecc_size >= min_ecc_size; + conf->ecc_size >>= 1) { + int max_ecc_strength = nand_max_ecc_strength(conf); + + nand_apply_config(conf); + + /* + * We are starting from the maximum ECC strength because + * most of the time NAND vendors provide an OOB area that + * barely meets the ECC requirements. + */ + for (conf->ecc_strength = max_ecc_strength; + conf->ecc_strength >= 0; + conf->ecc_strength--) { + conf->randomize = false; + if (nand_change_column(0)) + return -EIO; + + /* + * Only read the first sector to speedup detection. + */ + ret = nand_read_page(conf, offs, dest, conf->ecc_size); + if (!ret) { + return 0; + } else if (ret > 0) { + /* + * If page is empty we can't deduce anything + * about the ECC config => stop the detection. + */ + return -EINVAL; + } + + conf->randomize = true; + conf->nseeds = ARRAY_SIZE(random_seed); + do { + if (nand_change_column(0)) + return -EIO; + + if (!nand_read_page(conf, offs, dest, + conf->ecc_size)) + return 0; + + /* + * Find the next ->nseeds value that would + * change the randomizer seed for the page + * we're trying to read. + */ + while (conf->nseeds >= 16) { + int seed = page % conf->nseeds; + + conf->nseeds >>= 1; + if (seed != page % conf->nseeds) + break; + } + } while (conf->nseeds >= 16); + } + } + + return -EINVAL; +} + +static int nand_detect_config(struct nfc_config *conf, u32 offs, void *dest) +{ + if (conf->valid) + return 0; + + /* + * Modern NANDs are more likely than legacy ones, so we start testing + * with 5 address cycles. + */ + for (conf->addr_cycles = 5; + conf->addr_cycles >= 4; + conf->addr_cycles--) { + int max_page_size = conf->addr_cycles == 4 ? 2048 : 16384; + + /* + * Ignoring 1k pages cause I'm not even sure this case exist + * in the real world. + */ + for (conf->page_size = 2048; conf->page_size <= max_page_size; + conf->page_size <<= 1) { + if (nand_load_page(conf, offs)) + return -1; + + if (!nand_detect_ecc_config(conf, offs, dest)) { + conf->valid = true; + return 0; + } + } + } + + return -EINVAL; +} + +static int nand_read_buffer(struct nfc_config *conf, uint32_t offs, + unsigned int size, void *dest) +{ + int first_seed = 0, page, ret; + + size = ALIGN(size, conf->page_size); + page = offs / conf->page_size; + if (conf->randomize) + first_seed = page % conf->nseeds; + + for (; size; size -= conf->page_size) { + if (nand_load_page(conf, offs)) + return -1; + + ret = nand_read_page(conf, offs, dest, conf->page_size); + /* + * The ->nseeds value should be equal to the number of pages + * in an eraseblock. Since we don't know this information in + * advance we might have picked a wrong value. + */ + if (ret < 0 && conf->randomize) { + int cur_seed = page % conf->nseeds; + + /* + * We already tried all the seed values => we are + * facing a real corruption. + */ + if (cur_seed < first_seed) + return -EIO; + + /* Try to adjust ->nseeds and read the page again... */ + conf->nseeds = cur_seed; + + if (nand_change_column(0)) + return -EIO; + + /* ... it still fails => it's a real corruption. */ + if (nand_read_page(conf, offs, dest, conf->page_size)) + return -EIO; + } else if (ret && conf->randomize) { + memset(dest, 0xff, conf->page_size); + } + + page++; + offs += conf->page_size; + dest += conf->page_size; + } + + return 0; +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{ + static struct nfc_config conf = { }; + int ret; + + ret = nand_detect_config(&conf, offs, dest); + if (ret) + return ret; + + return nand_read_buffer(&conf, offs, size, dest); +} + +void nand_deselect(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + + clrbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0)); +#ifdef CONFIG_MACH_SUN9I + clrbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); +#else + clrbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); +#endif + clrbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1); +} diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c new file mode 100644 index 0000000000..74acdfb308 --- /dev/null +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -0,0 +1,1002 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2011 NVIDIA Corporation + * (C) Copyright 2006 Detlev Zundel, dzu@denx.de + * (C) Copyright 2006 DENX Software Engineering + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tegra_nand.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define NAND_CMD_TIMEOUT_MS 10 + +#define SKIPPED_SPARE_BYTES 4 + +/* ECC bytes to be generated for tag data */ +#define TAG_ECC_BYTES 4 + +static const struct udevice_id tegra_nand_dt_ids[] = { + { + .compatible = "nvidia,tegra20-nand", + }, + { /* sentinel */ } +}; + +/* 64 byte oob block info for large page (== 2KB) device + * + * OOB flash layout for Tegra with Reed-Solomon 4 symbol correct ECC: + * Skipped bytes(4) + * Main area Ecc(36) + * Tag data(20) + * Tag data Ecc(4) + * + * Yaffs2 will use 16 tag bytes. + */ +static struct nand_ecclayout eccoob = { + .eccbytes = 36, + .eccpos = { + 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, + }, + .oobavail = 20, + .oobfree = { + { + .offset = 40, + .length = 20, + }, + } +}; + +enum { + ECC_OK, + ECC_TAG_ERROR = 1 << 0, + ECC_DATA_ERROR = 1 << 1 +}; + +/* Timing parameters */ +enum { + FDT_NAND_MAX_TRP_TREA, + FDT_NAND_TWB, + FDT_NAND_MAX_TCR_TAR_TRR, + FDT_NAND_TWHR, + FDT_NAND_MAX_TCS_TCH_TALS_TALH, + FDT_NAND_TWH, + FDT_NAND_TWP, + FDT_NAND_TRH, + FDT_NAND_TADL, + + FDT_NAND_TIMING_COUNT +}; + +/* Information about an attached NAND chip */ +struct fdt_nand { + struct nand_ctlr *reg; + int enabled; /* 1 to enable, 0 to disable */ + struct gpio_desc wp_gpio; /* write-protect GPIO */ + s32 width; /* bit width, normally 8 */ + u32 timing[FDT_NAND_TIMING_COUNT]; +}; + +struct nand_drv { + struct nand_ctlr *reg; + struct fdt_nand config; +}; + +struct tegra_nand_info { + struct udevice *dev; + struct nand_drv nand_ctrl; + struct nand_chip nand_chip; +}; + +/** + * Wait for command completion + * + * @param reg nand_ctlr structure + * @return + * 1 - Command completed + * 0 - Timeout + */ +static int nand_waitfor_cmd_completion(struct nand_ctlr *reg) +{ + u32 reg_val; + int running; + int i; + + for (i = 0; i < NAND_CMD_TIMEOUT_MS * 1000; i++) { + if ((readl(®->command) & CMD_GO) || + !(readl(®->status) & STATUS_RBSY0) || + !(readl(®->isr) & ISR_IS_CMD_DONE)) { + udelay(1); + continue; + } + reg_val = readl(®->dma_mst_ctrl); + /* + * If DMA_MST_CTRL_EN_A_ENABLE or DMA_MST_CTRL_EN_B_ENABLE + * is set, that means DMA engine is running. + * + * Then we have to wait until DMA_MST_CTRL_IS_DMA_DONE + * is cleared, indicating DMA transfer completion. + */ + running = reg_val & (DMA_MST_CTRL_EN_A_ENABLE | + DMA_MST_CTRL_EN_B_ENABLE); + if (!running || (reg_val & DMA_MST_CTRL_IS_DMA_DONE)) + return 1; + udelay(1); + } + return 0; +} + +/** + * Read one byte from the chip + * + * @param mtd MTD device structure + * @return data byte + * + * Read function for 8bit bus-width + */ +static uint8_t read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_drv *info; + + info = (struct nand_drv *)nand_get_controller_data(chip); + + writel(CMD_GO | CMD_PIO | CMD_RX | CMD_CE0 | CMD_A_VALID, + &info->reg->command); + if (!nand_waitfor_cmd_completion(info->reg)) + printf("Command timeout\n"); + + return (uint8_t)readl(&info->reg->resp); +} + +/** + * Read len bytes from the chip into a buffer + * + * @param mtd MTD device structure + * @param buf buffer to store data to + * @param len number of bytes to read + * + * Read function for 8bit bus-width + */ +static void read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i, s; + unsigned int reg; + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_drv *info = (struct nand_drv *)nand_get_controller_data(chip); + + for (i = 0; i < len; i += 4) { + s = (len - i) > 4 ? 4 : len - i; + writel(CMD_PIO | CMD_RX | CMD_A_VALID | CMD_CE0 | + ((s - 1) << CMD_TRANS_SIZE_SHIFT) | CMD_GO, + &info->reg->command); + if (!nand_waitfor_cmd_completion(info->reg)) + puts("Command timeout during read_buf\n"); + reg = readl(&info->reg->resp); + memcpy(buf + i, ®, s); + } +} + +/** + * Check NAND status to see if it is ready or not + * + * @param mtd MTD device structure + * @return + * 1 - ready + * 0 - not ready + */ +static int nand_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int reg_val; + struct nand_drv *info; + + info = (struct nand_drv *)nand_get_controller_data(chip); + + reg_val = readl(&info->reg->status); + if (reg_val & STATUS_RBSY0) + return 1; + else + return 0; +} + +/* Dummy implementation: we don't support multiple chips */ +static void nand_select_chip(struct mtd_info *mtd, int chipnr) +{ + switch (chipnr) { + case -1: + case 0: + break; + + default: + BUG(); + } +} + +/** + * Clear all interrupt status bits + * + * @param reg nand_ctlr structure + */ +static void nand_clear_interrupt_status(struct nand_ctlr *reg) +{ + u32 reg_val; + + /* Clear interrupt status */ + reg_val = readl(®->isr); + writel(reg_val, ®->isr); +} + +/** + * Send command to NAND device + * + * @param mtd MTD device structure + * @param command the command to be sent + * @param column the column address for this command, -1 if none + * @param page_addr the page address for this command, -1 if none + */ +static void nand_command(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_drv *info; + + info = (struct nand_drv *)nand_get_controller_data(chip); + + /* + * Write out the command to the device. + * + * Only command NAND_CMD_RESET or NAND_CMD_READID will come + * here before mtd->writesize is initialized. + */ + + /* Emulate NAND_CMD_READOOB */ + if (command == NAND_CMD_READOOB) { + assert(mtd->writesize != 0); + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Adjust columns for 16 bit bus-width */ + if (column != -1 && (chip->options & NAND_BUSWIDTH_16)) + column >>= 1; + + nand_clear_interrupt_status(info->reg); + + /* Stop DMA engine, clear DMA completion status */ + writel(DMA_MST_CTRL_EN_A_DISABLE + | DMA_MST_CTRL_EN_B_DISABLE + | DMA_MST_CTRL_IS_DMA_DONE, + &info->reg->dma_mst_ctrl); + + /* + * Program and erase have their own busy handlers + * status and sequential in needs no delay + */ + switch (command) { + case NAND_CMD_READID: + writel(NAND_CMD_READID, &info->reg->cmd_reg1); + writel(column & 0xFF, &info->reg->addr_reg1); + writel(CMD_GO | CMD_CLE | CMD_ALE | CMD_CE0, + &info->reg->command); + break; + case NAND_CMD_PARAM: + writel(NAND_CMD_PARAM, &info->reg->cmd_reg1); + writel(column & 0xFF, &info->reg->addr_reg1); + writel(CMD_GO | CMD_CLE | CMD_ALE | CMD_CE0, + &info->reg->command); + break; + case NAND_CMD_READ0: + writel(NAND_CMD_READ0, &info->reg->cmd_reg1); + writel(NAND_CMD_READSTART, &info->reg->cmd_reg2); + writel((page_addr << 16) | (column & 0xFFFF), + &info->reg->addr_reg1); + writel(page_addr >> 16, &info->reg->addr_reg2); + return; + case NAND_CMD_SEQIN: + writel(NAND_CMD_SEQIN, &info->reg->cmd_reg1); + writel(NAND_CMD_PAGEPROG, &info->reg->cmd_reg2); + writel((page_addr << 16) | (column & 0xFFFF), + &info->reg->addr_reg1); + writel(page_addr >> 16, + &info->reg->addr_reg2); + return; + case NAND_CMD_PAGEPROG: + return; + case NAND_CMD_ERASE1: + writel(NAND_CMD_ERASE1, &info->reg->cmd_reg1); + writel(NAND_CMD_ERASE2, &info->reg->cmd_reg2); + writel(page_addr, &info->reg->addr_reg1); + writel(CMD_GO | CMD_CLE | CMD_ALE | + CMD_SEC_CMD | CMD_CE0 | CMD_ALE_BYTES3, + &info->reg->command); + break; + case NAND_CMD_ERASE2: + return; + case NAND_CMD_STATUS: + writel(NAND_CMD_STATUS, &info->reg->cmd_reg1); + writel(CMD_GO | CMD_CLE | CMD_PIO | CMD_RX + | ((1 - 0) << CMD_TRANS_SIZE_SHIFT) + | CMD_CE0, + &info->reg->command); + break; + case NAND_CMD_RESET: + writel(NAND_CMD_RESET, &info->reg->cmd_reg1); + writel(CMD_GO | CMD_CLE | CMD_CE0, + &info->reg->command); + break; + case NAND_CMD_RNDOUT: + default: + printf("%s: Unsupported command %d\n", __func__, command); + return; + } + if (!nand_waitfor_cmd_completion(info->reg)) + printf("Command 0x%02X timeout\n", command); +} + +/** + * Check whether the pointed buffer are all 0xff (blank). + * + * @param buf data buffer for blank check + * @param len length of the buffer in byte + * @return + * 1 - blank + * 0 - non-blank + */ +static int blank_check(u8 *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (buf[i] != 0xFF) + return 0; + return 1; +} + +/** + * After a DMA transfer for read, we call this function to see whether there + * is any uncorrectable error on the pointed data buffer or oob buffer. + * + * @param reg nand_ctlr structure + * @param databuf data buffer + * @param a_len data buffer length + * @param oobbuf oob buffer + * @param b_len oob buffer length + * @return + * ECC_OK - no ECC error or correctable ECC error + * ECC_TAG_ERROR - uncorrectable tag ECC error + * ECC_DATA_ERROR - uncorrectable data ECC error + * ECC_DATA_ERROR + ECC_TAG_ERROR - uncorrectable data+tag ECC error + */ +static int check_ecc_error(struct nand_ctlr *reg, u8 *databuf, + int a_len, u8 *oobbuf, int b_len) +{ + int return_val = ECC_OK; + u32 reg_val; + + if (!(readl(®->isr) & ISR_IS_ECC_ERR)) + return ECC_OK; + + /* + * Area A is used for the data block (databuf). Area B is used for + * the spare block (oobbuf) + */ + reg_val = readl(®->dec_status); + if ((reg_val & DEC_STATUS_A_ECC_FAIL) && databuf) { + reg_val = readl(®->bch_dec_status_buf); + /* + * If uncorrectable error occurs on data area, then see whether + * they are all FF. If all are FF, it's a blank page. + * Not error. + */ + if ((reg_val & BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK) && + !blank_check(databuf, a_len)) + return_val |= ECC_DATA_ERROR; + } + + if ((reg_val & DEC_STATUS_B_ECC_FAIL) && oobbuf) { + reg_val = readl(®->bch_dec_status_buf); + /* + * If uncorrectable error occurs on tag area, then see whether + * they are all FF. If all are FF, it's a blank page. + * Not error. + */ + if ((reg_val & BCH_DEC_STATUS_FAIL_TAG_MASK) && + !blank_check(oobbuf, b_len)) + return_val |= ECC_TAG_ERROR; + } + + return return_val; +} + +/** + * Set GO bit to send command to device + * + * @param reg nand_ctlr structure + */ +static void start_command(struct nand_ctlr *reg) +{ + u32 reg_val; + + reg_val = readl(®->command); + reg_val |= CMD_GO; + writel(reg_val, ®->command); +} + +/** + * Clear command GO bit, DMA GO bit, and DMA completion status + * + * @param reg nand_ctlr structure + */ +static void stop_command(struct nand_ctlr *reg) +{ + /* Stop command */ + writel(0, ®->command); + + /* Stop DMA engine and clear DMA completion status */ + writel(DMA_MST_CTRL_GO_DISABLE + | DMA_MST_CTRL_IS_DMA_DONE, + ®->dma_mst_ctrl); +} + +/** + * Set up NAND bus width and page size + * + * @param info nand_info structure + * @param *reg_val address of reg_val + * @return 0 if ok, -1 on error + */ +static int set_bus_width_page_size(struct mtd_info *our_mtd, + struct fdt_nand *config, u32 *reg_val) +{ + if (config->width == 8) + *reg_val = CFG_BUS_WIDTH_8BIT; + else if (config->width == 16) + *reg_val = CFG_BUS_WIDTH_16BIT; + else { + debug("%s: Unsupported bus width %d\n", __func__, + config->width); + return -1; + } + + if (our_mtd->writesize == 512) + *reg_val |= CFG_PAGE_SIZE_512; + else if (our_mtd->writesize == 2048) + *reg_val |= CFG_PAGE_SIZE_2048; + else if (our_mtd->writesize == 4096) + *reg_val |= CFG_PAGE_SIZE_4096; + else { + debug("%s: Unsupported page size %d\n", __func__, + our_mtd->writesize); + return -1; + } + + return 0; +} + +/** + * Page read/write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf data buffer + * @param page page number + * @param with_ecc 1 to enable ECC, 0 to disable ECC + * @param is_writing 0 for read, 1 for write + * @return 0 when successfully completed + * -EIO when command timeout + */ +static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page, int with_ecc, int is_writing) +{ + u32 reg_val; + int tag_size; + struct nand_oobfree *free = chip->ecc.layout->oobfree; + /* 4*128=512 (byte) is the value that our HW can support. */ + ALLOC_CACHE_ALIGN_BUFFER(u32, tag_buf, 128); + char *tag_ptr; + struct nand_drv *info; + struct fdt_nand *config; + unsigned int bbflags; + struct bounce_buffer bbstate, bbstate_oob; + + if ((uintptr_t)buf & 0x03) { + printf("buf %p has to be 4-byte aligned\n", buf); + return -EINVAL; + } + + info = (struct nand_drv *)nand_get_controller_data(chip); + config = &info->config; + if (set_bus_width_page_size(mtd, config, ®_val)) + return -EINVAL; + + /* Need to be 4-byte aligned */ + tag_ptr = (char *)tag_buf; + + stop_command(info->reg); + + if (is_writing) + bbflags = GEN_BB_READ; + else + bbflags = GEN_BB_WRITE; + + bounce_buffer_start(&bbstate, (void *)buf, 1 << chip->page_shift, + bbflags); + writel((1 << chip->page_shift) - 1, &info->reg->dma_cfg_a); + writel(virt_to_phys(bbstate.bounce_buffer), &info->reg->data_block_ptr); + + /* Set ECC selection, configure ECC settings */ + if (with_ecc) { + if (is_writing) + memcpy(tag_ptr, chip->oob_poi + free->offset, + chip->ecc.layout->oobavail + TAG_ECC_BYTES); + tag_size = chip->ecc.layout->oobavail + TAG_ECC_BYTES; + reg_val |= (CFG_SKIP_SPARE_SEL_4 + | CFG_SKIP_SPARE_ENABLE + | CFG_HW_ECC_CORRECTION_ENABLE + | CFG_ECC_EN_TAG_DISABLE + | CFG_HW_ECC_SEL_RS + | CFG_HW_ECC_ENABLE + | CFG_TVAL4 + | (tag_size - 1)); + + if (!is_writing) + tag_size += SKIPPED_SPARE_BYTES; + bounce_buffer_start(&bbstate_oob, (void *)tag_ptr, tag_size, + bbflags); + } else { + tag_size = mtd->oobsize; + reg_val |= (CFG_SKIP_SPARE_DISABLE + | CFG_HW_ECC_CORRECTION_DISABLE + | CFG_ECC_EN_TAG_DISABLE + | CFG_HW_ECC_DISABLE + | (tag_size - 1)); + bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi, + tag_size, bbflags); + } + writel(reg_val, &info->reg->config); + writel(virt_to_phys(bbstate_oob.bounce_buffer), &info->reg->tag_ptr); + writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); + writel(tag_size - 1, &info->reg->dma_cfg_b); + + nand_clear_interrupt_status(info->reg); + + reg_val = CMD_CLE | CMD_ALE + | CMD_SEC_CMD + | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT) + | CMD_A_VALID + | CMD_B_VALID + | (CMD_TRANS_SIZE_PAGE << CMD_TRANS_SIZE_SHIFT) + | CMD_CE0; + if (!is_writing) + reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX); + else + reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX); + writel(reg_val, &info->reg->command); + + /* Setup DMA engine */ + reg_val = DMA_MST_CTRL_GO_ENABLE + | DMA_MST_CTRL_BURST_8WORDS + | DMA_MST_CTRL_EN_A_ENABLE + | DMA_MST_CTRL_EN_B_ENABLE; + + if (!is_writing) + reg_val |= DMA_MST_CTRL_DIR_READ; + else + reg_val |= DMA_MST_CTRL_DIR_WRITE; + + writel(reg_val, &info->reg->dma_mst_ctrl); + + start_command(info->reg); + + if (!nand_waitfor_cmd_completion(info->reg)) { + if (!is_writing) + printf("Read Page 0x%X timeout ", page); + else + printf("Write Page 0x%X timeout ", page); + if (with_ecc) + printf("with ECC"); + else + printf("without ECC"); + printf("\n"); + return -EIO; + } + + bounce_buffer_stop(&bbstate_oob); + bounce_buffer_stop(&bbstate); + + if (with_ecc && !is_writing) { + memcpy(chip->oob_poi, tag_ptr, + SKIPPED_SPARE_BYTES); + memcpy(chip->oob_poi + free->offset, + tag_ptr + SKIPPED_SPARE_BYTES, + chip->ecc.layout->oobavail); + reg_val = (u32)check_ecc_error(info->reg, (u8 *)buf, + 1 << chip->page_shift, + (u8 *)(tag_ptr + SKIPPED_SPARE_BYTES), + chip->ecc.layout->oobavail); + if (reg_val & ECC_TAG_ERROR) + printf("Read Page 0x%X tag ECC error\n", page); + if (reg_val & ECC_DATA_ERROR) + printf("Read Page 0x%X data ECC error\n", + page); + if (reg_val & (ECC_DATA_ERROR | ECC_TAG_ERROR)) + return -EIO; + } + return 0; +} + +/** + * Hardware ecc based page read function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf buffer to store read data + * @param page page number to read + * @return 0 when successfully completed + * -EIO when command timeout + */ +static int nand_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +{ + return nand_rw_page(mtd, chip, buf, page, 1, 0); +} + +/** + * Hardware ecc based page write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf data buffer + */ +static int nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required, + int page) +{ + nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1); + return 0; +} + + +/** + * Read raw page data without ecc + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf buffer to store read data + * @param page page number to read + * @return 0 when successfully completed + * -EINVAL when chip->oob_poi is not double-word aligned + * -EIO when command timeout + */ +static int nand_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +{ + return nand_rw_page(mtd, chip, buf, page, 0, 0); +} + +/** + * Raw page write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf data buffer + */ +static int nand_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, + int oob_required, int page) +{ + nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1); + return 0; +} + +/** + * OOB data read/write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param page page number to read + * @param with_ecc 1 to enable ECC, 0 to disable ECC + * @param is_writing 0 for read, 1 for write + * @return 0 when successfully completed + * -EINVAL when chip->oob_poi is not double-word aligned + * -EIO when command timeout + */ +static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int with_ecc, int is_writing) +{ + u32 reg_val; + int tag_size; + struct nand_oobfree *free = chip->ecc.layout->oobfree; + struct nand_drv *info; + unsigned int bbflags; + struct bounce_buffer bbstate_oob; + + if (((int)chip->oob_poi) & 0x03) + return -EINVAL; + info = (struct nand_drv *)nand_get_controller_data(chip); + if (set_bus_width_page_size(mtd, &info->config, ®_val)) + return -EINVAL; + + stop_command(info->reg); + + /* Set ECC selection */ + tag_size = mtd->oobsize; + if (with_ecc) + reg_val |= CFG_ECC_EN_TAG_ENABLE; + else + reg_val |= (CFG_ECC_EN_TAG_DISABLE); + + reg_val |= ((tag_size - 1) | + CFG_SKIP_SPARE_DISABLE | + CFG_HW_ECC_CORRECTION_DISABLE | + CFG_HW_ECC_DISABLE); + writel(reg_val, &info->reg->config); + + if (is_writing && with_ecc) + tag_size -= TAG_ECC_BYTES; + + if (is_writing) + bbflags = GEN_BB_READ; + else + bbflags = GEN_BB_WRITE; + + bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi, tag_size, + bbflags); + writel(virt_to_phys(bbstate_oob.bounce_buffer), &info->reg->tag_ptr); + + writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); + + writel(tag_size - 1, &info->reg->dma_cfg_b); + + nand_clear_interrupt_status(info->reg); + + reg_val = CMD_CLE | CMD_ALE + | CMD_SEC_CMD + | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT) + | CMD_B_VALID + | CMD_CE0; + if (!is_writing) + reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX); + else + reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX); + writel(reg_val, &info->reg->command); + + /* Setup DMA engine */ + reg_val = DMA_MST_CTRL_GO_ENABLE + | DMA_MST_CTRL_BURST_8WORDS + | DMA_MST_CTRL_EN_B_ENABLE; + if (!is_writing) + reg_val |= DMA_MST_CTRL_DIR_READ; + else + reg_val |= DMA_MST_CTRL_DIR_WRITE; + + writel(reg_val, &info->reg->dma_mst_ctrl); + + start_command(info->reg); + + if (!nand_waitfor_cmd_completion(info->reg)) { + if (!is_writing) + printf("Read OOB of Page 0x%X timeout\n", page); + else + printf("Write OOB of Page 0x%X timeout\n", page); + return -EIO; + } + + bounce_buffer_stop(&bbstate_oob); + + if (with_ecc && !is_writing) { + reg_val = (u32)check_ecc_error(info->reg, 0, 0, + (u8 *)(chip->oob_poi + free->offset), + chip->ecc.layout->oobavail); + if (reg_val & ECC_TAG_ERROR) + printf("Read OOB of Page 0x%X tag ECC error\n", page); + } + return 0; +} + +/** + * OOB data read function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param page page number to read + */ +static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + nand_rw_oob(mtd, chip, page, 0, 0); + return 0; +} + +/** + * OOB data write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param page page number to write + * @return 0 when successfully completed + * -EINVAL when chip->oob_poi is not double-word aligned + * -EIO when command timeout + */ +static int nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + + return nand_rw_oob(mtd, chip, page, 0, 1); +} + +/** + * Set up NAND memory timings according to the provided parameters + * + * @param timing Timing parameters + * @param reg NAND controller register address + */ +static void setup_timing(unsigned timing[FDT_NAND_TIMING_COUNT], + struct nand_ctlr *reg) +{ + u32 reg_val, clk_rate, clk_period, time_val; + + clk_rate = (u32)clock_get_periph_rate(PERIPH_ID_NDFLASH, + CLOCK_ID_PERIPH) / 1000000; + clk_period = 1000 / clk_rate; + reg_val = ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) << + TIMING_TRP_RESP_CNT_SHIFT) & TIMING_TRP_RESP_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TWB] / clk_period) << + TIMING_TWB_CNT_SHIFT) & TIMING_TWB_CNT_MASK; + time_val = timing[FDT_NAND_MAX_TCR_TAR_TRR] / clk_period; + if (time_val > 2) + reg_val |= ((time_val - 2) << TIMING_TCR_TAR_TRR_CNT_SHIFT) & + TIMING_TCR_TAR_TRR_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TWHR] / clk_period) << + TIMING_TWHR_CNT_SHIFT) & TIMING_TWHR_CNT_MASK; + time_val = timing[FDT_NAND_MAX_TCS_TCH_TALS_TALH] / clk_period; + if (time_val > 1) + reg_val |= ((time_val - 1) << TIMING_TCS_CNT_SHIFT) & + TIMING_TCS_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TWH] / clk_period) << + TIMING_TWH_CNT_SHIFT) & TIMING_TWH_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TWP] / clk_period) << + TIMING_TWP_CNT_SHIFT) & TIMING_TWP_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TRH] / clk_period) << + TIMING_TRH_CNT_SHIFT) & TIMING_TRH_CNT_MASK; + reg_val |= ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) << + TIMING_TRP_CNT_SHIFT) & TIMING_TRP_CNT_MASK; + writel(reg_val, ®->timing); + + reg_val = 0; + time_val = timing[FDT_NAND_TADL] / clk_period; + if (time_val > 2) + reg_val = (time_val - 2) & TIMING2_TADL_CNT_MASK; + writel(reg_val, ®->timing2); +} + +/** + * Decode NAND parameters from the device tree + * + * @param dev Driver model device + * @param config Device tree NAND configuration + * @return 0 if ok, -ve on error (FDT_ERR_...) + */ +static int fdt_decode_nand(struct udevice *dev, struct fdt_nand *config) +{ + int err; + + config->reg = (struct nand_ctlr *)dev_read_addr(dev); + config->enabled = dev_read_enabled(dev); + config->width = dev_read_u32_default(dev, "nvidia,nand-width", 8); + err = gpio_request_by_name(dev, "nvidia,wp-gpios", 0, &config->wp_gpio, + GPIOD_IS_OUT); + if (err) + return err; + err = dev_read_u32_array(dev, "nvidia,timing", config->timing, + FDT_NAND_TIMING_COUNT); + if (err < 0) + return err; + + return 0; +} + +static int tegra_probe(struct udevice *dev) +{ + struct tegra_nand_info *tegra = dev_get_priv(dev); + struct nand_chip *nand = &tegra->nand_chip; + struct nand_drv *info = &tegra->nand_ctrl; + struct fdt_nand *config = &info->config; + struct mtd_info *our_mtd; + int ret; + + if (fdt_decode_nand(dev, config)) { + printf("Could not decode nand-flash in device tree\n"); + return -1; + } + if (!config->enabled) + return -1; + info->reg = config->reg; + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.layout = &eccoob; + + nand->options = LP_OPTIONS; + nand->cmdfunc = nand_command; + nand->read_byte = read_byte; + nand->read_buf = read_buf; + nand->ecc.read_page = nand_read_page_hwecc; + nand->ecc.write_page = nand_write_page_hwecc; + nand->ecc.read_page_raw = nand_read_page_raw; + nand->ecc.write_page_raw = nand_write_page_raw; + nand->ecc.read_oob = nand_read_oob; + nand->ecc.write_oob = nand_write_oob; + nand->ecc.strength = 1; + nand->select_chip = nand_select_chip; + nand->dev_ready = nand_dev_ready; + nand_set_controller_data(nand, &tegra->nand_ctrl); + + /* Disable subpage writes as we do not provide ecc->hwctl */ + nand->options |= NAND_NO_SUBPAGE_WRITE; + + /* Adjust controller clock rate */ + clock_start_periph_pll(PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH, 52000000); + + /* Adjust timing for NAND device */ + setup_timing(config->timing, info->reg); + + dm_gpio_set_value(&config->wp_gpio, 1); + + our_mtd = nand_to_mtd(nand); + ret = nand_scan_ident(our_mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL); + if (ret) + return ret; + + nand->ecc.size = our_mtd->writesize; + nand->ecc.bytes = our_mtd->oobsize; + + ret = nand_scan_tail(our_mtd); + if (ret) + return ret; + + ret = nand_register(0, our_mtd); + if (ret) { + dev_err(dev, "Failed to register MTD: %d\n", ret); + return ret; + } + + return 0; +} + +U_BOOT_DRIVER(tegra_nand) = { + .name = "tegra-nand", + .id = UCLASS_MTD, + .of_match = tegra_nand_dt_ids, + .probe = tegra_probe, + .priv_auto_alloc_size = sizeof(struct tegra_nand_info), +}; + +void board_nand_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MTD, + DM_GET_DRIVER(tegra_nand), &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize %s. (error %d)\n", dev->name, + ret); +} diff --git a/drivers/mtd/nand/raw/tegra_nand.h b/drivers/mtd/nand/raw/tegra_nand.h new file mode 100644 index 0000000000..7740160661 --- /dev/null +++ b/drivers/mtd/nand/raw/tegra_nand.h @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2011 NVIDIA Corporation + */ + +/* register offset */ +#define COMMAND_0 0x00 +#define CMD_GO (1 << 31) +#define CMD_CLE (1 << 30) +#define CMD_ALE (1 << 29) +#define CMD_PIO (1 << 28) +#define CMD_TX (1 << 27) +#define CMD_RX (1 << 26) +#define CMD_SEC_CMD (1 << 25) +#define CMD_AFT_DAT_MASK (1 << 24) +#define CMD_AFT_DAT_DISABLE 0 +#define CMD_AFT_DAT_ENABLE (1 << 24) +#define CMD_TRANS_SIZE_SHIFT 20 +#define CMD_TRANS_SIZE_PAGE 8 +#define CMD_A_VALID (1 << 19) +#define CMD_B_VALID (1 << 18) +#define CMD_RD_STATUS_CHK (1 << 17) +#define CMD_R_BSY_CHK (1 << 16) +#define CMD_CE7 (1 << 15) +#define CMD_CE6 (1 << 14) +#define CMD_CE5 (1 << 13) +#define CMD_CE4 (1 << 12) +#define CMD_CE3 (1 << 11) +#define CMD_CE2 (1 << 10) +#define CMD_CE1 (1 << 9) +#define CMD_CE0 (1 << 8) +#define CMD_CLE_BYTE_SIZE_SHIFT 4 +enum { + CMD_CLE_BYTES1 = 0, + CMD_CLE_BYTES2, + CMD_CLE_BYTES3, + CMD_CLE_BYTES4, +}; +#define CMD_ALE_BYTE_SIZE_SHIFT 0 +enum { + CMD_ALE_BYTES1 = 0, + CMD_ALE_BYTES2, + CMD_ALE_BYTES3, + CMD_ALE_BYTES4, + CMD_ALE_BYTES5, + CMD_ALE_BYTES6, + CMD_ALE_BYTES7, + CMD_ALE_BYTES8 +}; + +#define STATUS_0 0x04 +#define STATUS_RBSY0 (1 << 8) + +#define ISR_0 0x08 +#define ISR_IS_CMD_DONE (1 << 5) +#define ISR_IS_ECC_ERR (1 << 4) + +#define IER_0 0x0C + +#define CFG_0 0x10 +#define CFG_HW_ECC_MASK (1 << 31) +#define CFG_HW_ECC_DISABLE 0 +#define CFG_HW_ECC_ENABLE (1 << 31) +#define CFG_HW_ECC_SEL_MASK (1 << 30) +#define CFG_HW_ECC_SEL_HAMMING 0 +#define CFG_HW_ECC_SEL_RS (1 << 30) +#define CFG_HW_ECC_CORRECTION_MASK (1 << 29) +#define CFG_HW_ECC_CORRECTION_DISABLE 0 +#define CFG_HW_ECC_CORRECTION_ENABLE (1 << 29) +#define CFG_PIPELINE_EN_MASK (1 << 28) +#define CFG_PIPELINE_EN_DISABLE 0 +#define CFG_PIPELINE_EN_ENABLE (1 << 28) +#define CFG_ECC_EN_TAG_MASK (1 << 27) +#define CFG_ECC_EN_TAG_DISABLE 0 +#define CFG_ECC_EN_TAG_ENABLE (1 << 27) +#define CFG_TVALUE_MASK (3 << 24) +enum { + CFG_TVAL4 = 0 << 24, + CFG_TVAL6 = 1 << 24, + CFG_TVAL8 = 2 << 24 +}; +#define CFG_SKIP_SPARE_MASK (1 << 23) +#define CFG_SKIP_SPARE_DISABLE 0 +#define CFG_SKIP_SPARE_ENABLE (1 << 23) +#define CFG_COM_BSY_MASK (1 << 22) +#define CFG_COM_BSY_DISABLE 0 +#define CFG_COM_BSY_ENABLE (1 << 22) +#define CFG_BUS_WIDTH_MASK (1 << 21) +#define CFG_BUS_WIDTH_8BIT 0 +#define CFG_BUS_WIDTH_16BIT (1 << 21) +#define CFG_LPDDR1_MODE_MASK (1 << 20) +#define CFG_LPDDR1_MODE_DISABLE 0 +#define CFG_LPDDR1_MODE_ENABLE (1 << 20) +#define CFG_EDO_MODE_MASK (1 << 19) +#define CFG_EDO_MODE_DISABLE 0 +#define CFG_EDO_MODE_ENABLE (1 << 19) +#define CFG_PAGE_SIZE_SEL_MASK (7 << 16) +enum { + CFG_PAGE_SIZE_256 = 0 << 16, + CFG_PAGE_SIZE_512 = 1 << 16, + CFG_PAGE_SIZE_1024 = 2 << 16, + CFG_PAGE_SIZE_2048 = 3 << 16, + CFG_PAGE_SIZE_4096 = 4 << 16 +}; +#define CFG_SKIP_SPARE_SEL_MASK (3 << 14) +enum { + CFG_SKIP_SPARE_SEL_4 = 0 << 14, + CFG_SKIP_SPARE_SEL_8 = 1 << 14, + CFG_SKIP_SPARE_SEL_12 = 2 << 14, + CFG_SKIP_SPARE_SEL_16 = 3 << 14 +}; +#define CFG_TAG_BYTE_SIZE_MASK 0x1FF + +#define TIMING_0 0x14 +#define TIMING_TRP_RESP_CNT_SHIFT 28 +#define TIMING_TRP_RESP_CNT_MASK (0xf << TIMING_TRP_RESP_CNT_SHIFT) +#define TIMING_TWB_CNT_SHIFT 24 +#define TIMING_TWB_CNT_MASK (0xf << TIMING_TWB_CNT_SHIFT) +#define TIMING_TCR_TAR_TRR_CNT_SHIFT 20 +#define TIMING_TCR_TAR_TRR_CNT_MASK (0xf << TIMING_TCR_TAR_TRR_CNT_SHIFT) +#define TIMING_TWHR_CNT_SHIFT 16 +#define TIMING_TWHR_CNT_MASK (0xf << TIMING_TWHR_CNT_SHIFT) +#define TIMING_TCS_CNT_SHIFT 14 +#define TIMING_TCS_CNT_MASK (3 << TIMING_TCS_CNT_SHIFT) +#define TIMING_TWH_CNT_SHIFT 12 +#define TIMING_TWH_CNT_MASK (3 << TIMING_TWH_CNT_SHIFT) +#define TIMING_TWP_CNT_SHIFT 8 +#define TIMING_TWP_CNT_MASK (0xf << TIMING_TWP_CNT_SHIFT) +#define TIMING_TRH_CNT_SHIFT 4 +#define TIMING_TRH_CNT_MASK (3 << TIMING_TRH_CNT_SHIFT) +#define TIMING_TRP_CNT_SHIFT 0 +#define TIMING_TRP_CNT_MASK (0xf << TIMING_TRP_CNT_SHIFT) + +#define RESP_0 0x18 + +#define TIMING2_0 0x1C +#define TIMING2_TADL_CNT_SHIFT 0 +#define TIMING2_TADL_CNT_MASK (0xf << TIMING2_TADL_CNT_SHIFT) + +#define CMD_REG1_0 0x20 +#define CMD_REG2_0 0x24 +#define ADDR_REG1_0 0x28 +#define ADDR_REG2_0 0x2C + +#define DMA_MST_CTRL_0 0x30 +#define DMA_MST_CTRL_GO_MASK (1 << 31) +#define DMA_MST_CTRL_GO_DISABLE 0 +#define DMA_MST_CTRL_GO_ENABLE (1 << 31) +#define DMA_MST_CTRL_DIR_MASK (1 << 30) +#define DMA_MST_CTRL_DIR_READ 0 +#define DMA_MST_CTRL_DIR_WRITE (1 << 30) +#define DMA_MST_CTRL_PERF_EN_MASK (1 << 29) +#define DMA_MST_CTRL_PERF_EN_DISABLE 0 +#define DMA_MST_CTRL_PERF_EN_ENABLE (1 << 29) +#define DMA_MST_CTRL_REUSE_BUFFER_MASK (1 << 27) +#define DMA_MST_CTRL_REUSE_BUFFER_DISABLE 0 +#define DMA_MST_CTRL_REUSE_BUFFER_ENABLE (1 << 27) +#define DMA_MST_CTRL_BURST_SIZE_SHIFT 24 +#define DMA_MST_CTRL_BURST_SIZE_MASK (7 << DMA_MST_CTRL_BURST_SIZE_SHIFT) +enum { + DMA_MST_CTRL_BURST_1WORDS = 2 << DMA_MST_CTRL_BURST_SIZE_SHIFT, + DMA_MST_CTRL_BURST_4WORDS = 3 << DMA_MST_CTRL_BURST_SIZE_SHIFT, + DMA_MST_CTRL_BURST_8WORDS = 4 << DMA_MST_CTRL_BURST_SIZE_SHIFT, + DMA_MST_CTRL_BURST_16WORDS = 5 << DMA_MST_CTRL_BURST_SIZE_SHIFT +}; +#define DMA_MST_CTRL_IS_DMA_DONE (1 << 20) +#define DMA_MST_CTRL_EN_A_MASK (1 << 2) +#define DMA_MST_CTRL_EN_A_DISABLE 0 +#define DMA_MST_CTRL_EN_A_ENABLE (1 << 2) +#define DMA_MST_CTRL_EN_B_MASK (1 << 1) +#define DMA_MST_CTRL_EN_B_DISABLE 0 +#define DMA_MST_CTRL_EN_B_ENABLE (1 << 1) + +#define DMA_CFG_A_0 0x34 +#define DMA_CFG_B_0 0x38 +#define FIFO_CTRL_0 0x3C +#define DATA_BLOCK_PTR_0 0x40 +#define TAG_PTR_0 0x44 +#define ECC_PTR_0 0x48 + +#define DEC_STATUS_0 0x4C +#define DEC_STATUS_A_ECC_FAIL (1 << 1) +#define DEC_STATUS_B_ECC_FAIL (1 << 0) + +#define BCH_CONFIG_0 0xCC +#define BCH_CONFIG_BCH_TVALUE_SHIFT 4 +#define BCH_CONFIG_BCH_TVALUE_MASK (3 << BCH_CONFIG_BCH_TVALUE_SHIFT) +enum { + BCH_CONFIG_BCH_TVAL4 = 0 << BCH_CONFIG_BCH_TVALUE_SHIFT, + BCH_CONFIG_BCH_TVAL8 = 1 << BCH_CONFIG_BCH_TVALUE_SHIFT, + BCH_CONFIG_BCH_TVAL14 = 2 << BCH_CONFIG_BCH_TVALUE_SHIFT, + BCH_CONFIG_BCH_TVAL16 = 3 << BCH_CONFIG_BCH_TVALUE_SHIFT +}; +#define BCH_CONFIG_BCH_ECC_MASK (1 << 0) +#define BCH_CONFIG_BCH_ECC_DISABLE 0 +#define BCH_CONFIG_BCH_ECC_ENABLE (1 << 0) + +#define BCH_DEC_RESULT_0 0xD0 +#define BCH_DEC_RESULT_CORRFAIL_ERR_MASK (1 << 8) +#define BCH_DEC_RESULT_PAGE_COUNT_MASK 0xFF + +#define BCH_DEC_STATUS_BUF_0 0xD4 +#define BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK 0xFF000000 +#define BCH_DEC_STATUS_CORR_SEC_FLAG_MASK 0x00FF0000 +#define BCH_DEC_STATUS_FAIL_TAG_MASK (1 << 14) +#define BCH_DEC_STATUS_CORR_TAG_MASK (1 << 13) +#define BCH_DEC_STATUS_MAX_CORR_CNT_MASK (0x1f << 8) +#define BCH_DEC_STATUS_PAGE_NUMBER_MASK 0xFF + +#define LP_OPTIONS 0 + +struct nand_ctlr { + u32 command; /* offset 00h */ + u32 status; /* offset 04h */ + u32 isr; /* offset 08h */ + u32 ier; /* offset 0Ch */ + u32 config; /* offset 10h */ + u32 timing; /* offset 14h */ + u32 resp; /* offset 18h */ + u32 timing2; /* offset 1Ch */ + u32 cmd_reg1; /* offset 20h */ + u32 cmd_reg2; /* offset 24h */ + u32 addr_reg1; /* offset 28h */ + u32 addr_reg2; /* offset 2Ch */ + u32 dma_mst_ctrl; /* offset 30h */ + u32 dma_cfg_a; /* offset 34h */ + u32 dma_cfg_b; /* offset 38h */ + u32 fifo_ctrl; /* offset 3Ch */ + u32 data_block_ptr; /* offset 40h */ + u32 tag_ptr; /* offset 44h */ + u32 resv1; /* offset 48h */ + u32 dec_status; /* offset 4Ch */ + u32 hwstatus_cmd; /* offset 50h */ + u32 hwstatus_mask; /* offset 54h */ + u32 resv2[29]; + u32 bch_config; /* offset CCh */ + u32 bch_dec_result; /* offset D0h */ + u32 bch_dec_status_buf; + /* offset D4h */ +}; diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c new file mode 100644 index 0000000000..619d0403e9 --- /dev/null +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -0,0 +1,768 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2009-2015 Freescale Semiconductor, Inc. and others + * + * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver. + * Ported to U-Boot by Stefan Agner + * Based on RFC driver posted on Kernel Mailing list by Bill Pringlemeir + * Jason ported to M54418TWR and MVFA5. + * Authors: Stefan Agner + * Bill Pringlemeir + * Shaohui Xie + * Jason Jin + * + * Based on original driver mpc5121_nfc.c. + * + * 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 +#include + +#include +#include +#include + +#include +#include +#include + +/* 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] values. See section: + * - 31.4.7 Flash Command Code Description, Vybrid manual + * - 23.8.6 Flash Command Sequencer, MPC5125 manual + * + * Briefly these are bitmasks of controller cycles. + */ +#define READ_PAGE_CMD_CODE 0x7EE0 +#define READ_ONFI_PARAM_CMD_CODE 0x4860 +#define PROGRAM_PAGE_CMD_CODE 0x7FC0 +#define ERASE_CMD_CODE 0x4EC0 +#define READ_ID_CMD_CODE 0x4804 +#define RESET_CMD_CODE 0x4040 +#define STATUS_READ_CMD_CODE 0x4068 + +/* 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 (1<<0) + +/* NFC_COL_ADDR Field */ +#define COL_ADDR_MASK 0x0000FFFF +#define COL_ADDR_SHIFT 0 + +/* NFC_ROW_ADDR Field */ +#define ROW_ADDR_MASK 0x00FFFFFF +#define ROW_ADDR_SHIFT 0 +#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 (1<<21) +#define CONFIG_DMA_REQ_BIT (1<<20) +#define CONFIG_ECC_MODE_MASK 0x000E0000 +#define CONFIG_ECC_MODE_SHIFT 17 +#define CONFIG_FAST_FLASH_BIT (1<<16) +#define CONFIG_16BIT (1<<7) +#define CONFIG_BOOT_MODE_BIT (1<<6) +#define CONFIG_ADDR_AUTO_INCR_BIT (1<<5) +#define CONFIG_BUFNO_AUTO_INCR_BIT (1<<4) +#define CONFIG_PAGE_CNT_MASK 0xF +#define CONFIG_PAGE_CNT_SHIFT 0 + +/* NFC_IRQ_STATUS Field */ +#define IDLE_IRQ_BIT (1<<29) +#define IDLE_EN_BIT (1<<20) +#define CMD_DONE_CLEAR_BIT (1<<18) +#define IDLE_CLEAR_BIT (1<<17) + +#define NFC_TIMEOUT (1000) + +/* + * 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_alt_buf { + ALT_BUF_DATA = 0, + ALT_BUF_ID = 1, + ALT_BUF_STAT = 2, + ALT_BUF_ONFI = 3, +}; + +struct vf610_nfc { + struct nand_chip chip; + void __iomem *regs; + uint buf_offset; + int write_sz; + /* Status and ID are in alternate locations. */ + enum vf610_nfc_alt_buf alt_buf; +}; + +#define mtd_to_nfc(_mtd) nand_get_controller_data(mtd_to_nand(_mtd)) + +#if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES) +#define ECC_HW_MODE ECC_45_BYTE + +static struct nand_ecclayout vf610_nfc_ecc = { + .eccbytes = 45, + .eccpos = {19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { + {.offset = 2, + .length = 17} } +}; +#elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES) +#define ECC_HW_MODE ECC_60_BYTE + +static struct nand_ecclayout vf610_nfc_ecc = { + .eccbytes = 60, + .eccpos = { 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63 }, + .oobfree = { + {.offset = 2, + .length = 2} } +}; +#endif + +static inline u32 vf610_nfc_read(struct mtd_info *mtd, uint reg) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + return readl(nfc->regs + reg); +} + +static inline void vf610_nfc_write(struct mtd_info *mtd, uint reg, u32 val) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + writel(val, nfc->regs + reg); +} + +static inline void vf610_nfc_set(struct mtd_info *mtd, uint reg, u32 bits) +{ + vf610_nfc_write(mtd, reg, vf610_nfc_read(mtd, reg) | bits); +} + +static inline void vf610_nfc_clear(struct mtd_info *mtd, uint reg, u32 bits) +{ + vf610_nfc_write(mtd, reg, vf610_nfc_read(mtd, reg) & ~bits); +} + +static inline void vf610_nfc_set_field(struct mtd_info *mtd, u32 reg, + u32 mask, u32 shift, u32 val) +{ + vf610_nfc_write(mtd, reg, + (vf610_nfc_read(mtd, reg) & (~mask)) | val << shift); +} + +static inline void vf610_nfc_memcpy(void *dst, const void *src, size_t n) +{ + /* + * 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. + * + * For the time being, use memcpy + */ + memcpy(dst, src, n); +} + +/* Clear flags for upcoming command */ +static inline void vf610_nfc_clear_status(void __iomem *regbase) +{ + void __iomem *reg = regbase + NFC_IRQ_STATUS; + u32 tmp = __raw_readl(reg); + tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT; + __raw_writel(tmp, reg); +} + +/* Wait for complete operation */ +static void vf610_nfc_done(struct mtd_info *mtd) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + uint start; + + /* + * 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(mtd, NFC_FLASH_CMD2, START_BIT); + + start = get_timer(0); + + while (!(vf610_nfc_read(mtd, NFC_IRQ_STATUS) & IDLE_IRQ_BIT)) { + if (get_timer(start) > NFC_TIMEOUT) { + printf("Timeout while waiting for IDLE.\n"); + return; + } + } + vf610_nfc_clear_status(nfc->regs); +} + +static u8 vf610_nfc_get_id(struct mtd_info *mtd, int col) +{ + u32 flash_id; + + if (col < 4) { + flash_id = vf610_nfc_read(mtd, NFC_FLASH_STATUS1); + flash_id >>= (3 - col) * 8; + } else { + flash_id = vf610_nfc_read(mtd, NFC_FLASH_STATUS2); + flash_id >>= 24; + } + + return flash_id & 0xff; +} + +static u8 vf610_nfc_get_status(struct mtd_info *mtd) +{ + return vf610_nfc_read(mtd, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK; +} + +/* Single command */ +static void vf610_nfc_send_command(void __iomem *regbase, u32 cmd_byte1, + u32 cmd_code) +{ + void __iomem *reg = regbase + NFC_FLASH_CMD2; + u32 tmp; + vf610_nfc_clear_status(regbase); + + tmp = __raw_readl(reg); + tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK); + tmp |= cmd_byte1 << CMD_BYTE1_SHIFT; + tmp |= cmd_code << CMD_CODE_SHIFT; + __raw_writel(tmp, reg); +} + +/* Two commands */ +static void vf610_nfc_send_commands(void __iomem *regbase, u32 cmd_byte1, + u32 cmd_byte2, u32 cmd_code) +{ + void __iomem *reg = regbase + NFC_FLASH_CMD1; + u32 tmp; + vf610_nfc_send_command(regbase, cmd_byte1, cmd_code); + + tmp = __raw_readl(reg); + tmp &= ~CMD_BYTE2_MASK; + tmp |= cmd_byte2 << CMD_BYTE2_SHIFT; + __raw_writel(tmp, reg); +} + +static void vf610_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) +{ + if (column != -1) { + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + if (nfc->chip.options & NAND_BUSWIDTH_16) + column = column / 2; + vf610_nfc_set_field(mtd, NFC_COL_ADDR, COL_ADDR_MASK, + COL_ADDR_SHIFT, column); + } + if (page != -1) + vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK, + ROW_ADDR_SHIFT, page); +} + +static inline void vf610_nfc_ecc_mode(struct mtd_info *mtd, int ecc_mode) +{ + vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG, + CONFIG_ECC_MODE_MASK, + CONFIG_ECC_MODE_SHIFT, ecc_mode); +} + +static inline void vf610_nfc_transfer_size(void __iomem *regbase, int size) +{ + __raw_writel(size, regbase + NFC_SECTOR_SIZE); +} + +/* Send command to NAND chip */ +static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, + int column, int page) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0; + + nfc->buf_offset = max(column, 0); + nfc->alt_buf = ALT_BUF_DATA; + + switch (command) { + case NAND_CMD_SEQIN: + /* Use valid column/page from preread... */ + vf610_nfc_addr_cycle(mtd, column, page); + nfc->buf_offset = 0; + + /* + * SEQIN => data => PAGEPROG sequence is done by the controller + * hence we do not need to issue the command here... + */ + return; + case NAND_CMD_PAGEPROG: + trfr_sz += nfc->write_sz; + vf610_nfc_ecc_mode(mtd, ECC_HW_MODE); + vf610_nfc_transfer_size(nfc->regs, trfr_sz); + vf610_nfc_send_commands(nfc->regs, NAND_CMD_SEQIN, + command, PROGRAM_PAGE_CMD_CODE); + break; + + case NAND_CMD_RESET: + vf610_nfc_transfer_size(nfc->regs, 0); + vf610_nfc_send_command(nfc->regs, command, RESET_CMD_CODE); + break; + + case NAND_CMD_READOOB: + trfr_sz += mtd->oobsize; + column = mtd->writesize; + vf610_nfc_transfer_size(nfc->regs, trfr_sz); + vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0, + NAND_CMD_READSTART, READ_PAGE_CMD_CODE); + vf610_nfc_addr_cycle(mtd, column, page); + vf610_nfc_ecc_mode(mtd, ECC_BYPASS); + break; + + case NAND_CMD_READ0: + trfr_sz += mtd->writesize + mtd->oobsize; + vf610_nfc_transfer_size(nfc->regs, trfr_sz); + vf610_nfc_ecc_mode(mtd, ECC_HW_MODE); + vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0, + NAND_CMD_READSTART, READ_PAGE_CMD_CODE); + vf610_nfc_addr_cycle(mtd, column, page); + break; + + case NAND_CMD_PARAM: + nfc->alt_buf = ALT_BUF_ONFI; + trfr_sz = 3 * sizeof(struct nand_onfi_params); + vf610_nfc_transfer_size(nfc->regs, trfr_sz); + vf610_nfc_send_command(nfc->regs, NAND_CMD_PARAM, + READ_ONFI_PARAM_CMD_CODE); + vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK, + ROW_ADDR_SHIFT, column); + vf610_nfc_ecc_mode(mtd, ECC_BYPASS); + break; + + case NAND_CMD_ERASE1: + vf610_nfc_transfer_size(nfc->regs, 0); + vf610_nfc_send_commands(nfc->regs, command, + NAND_CMD_ERASE2, ERASE_CMD_CODE); + vf610_nfc_addr_cycle(mtd, column, page); + break; + + case NAND_CMD_READID: + nfc->alt_buf = ALT_BUF_ID; + nfc->buf_offset = 0; + vf610_nfc_transfer_size(nfc->regs, 0); + vf610_nfc_send_command(nfc->regs, command, READ_ID_CMD_CODE); + vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK, + ROW_ADDR_SHIFT, column); + break; + + case NAND_CMD_STATUS: + nfc->alt_buf = ALT_BUF_STAT; + vf610_nfc_transfer_size(nfc->regs, 0); + vf610_nfc_send_command(nfc->regs, command, STATUS_READ_CMD_CODE); + break; + default: + return; + } + + vf610_nfc_done(mtd); + + nfc->write_sz = 0; +} + +/* Read data from NFC buffers */ +static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + uint c = nfc->buf_offset; + + /* Alternate buffers are only supported through read_byte */ + if (nfc->alt_buf) + return; + + vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len); + + nfc->buf_offset += len; +} + +/* Write data to NFC buffers */ +static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + uint c = nfc->buf_offset; + uint l; + + l = min_t(uint, len, mtd->writesize + mtd->oobsize - c); + vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l); + + nfc->write_sz += l; + nfc->buf_offset += l; +} + +/* Read byte from NFC buffers */ +static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + u8 tmp; + uint c = nfc->buf_offset; + + switch (nfc->alt_buf) { + case ALT_BUF_ID: + tmp = vf610_nfc_get_id(mtd, c); + break; + case ALT_BUF_STAT: + tmp = vf610_nfc_get_status(mtd); + break; +#ifdef __LITTLE_ENDIAN + case ALT_BUF_ONFI: + /* Reverse byte since the controller uses big endianness */ + c = nfc->buf_offset ^ 0x3; + /* fall-through */ +#endif + default: + tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c)); + break; + } + nfc->buf_offset++; + return tmp; +} + +/* Read word from NFC buffers */ +static u16 vf610_nfc_read_word(struct mtd_info *mtd) +{ + u16 tmp; + + vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp)); + return tmp; +} + +/* If not provided, upper layers apply a fixed delay. */ +static int vf610_nfc_dev_ready(struct mtd_info *mtd) +{ + /* NFC handles R/B internally; always ready. */ + return 1; +} + +/* + * 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) +{ +#ifdef CONFIG_VF610 + u32 tmp = vf610_nfc_read(mtd, NFC_ROW_ADDR); + tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK); + + if (chip >= 0) { + tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT; + tmp |= (1 << chip) << ROW_ADDR_CHIP_SEL_SHIFT; + } + + vf610_nfc_write(mtd, NFC_ROW_ADDR, tmp); +#endif +} + +/* Count the number of 0's in buff upto max_bits */ +static inline int count_written_bits(uint8_t *buff, int size, int max_bits) +{ + uint32_t *buff32 = (uint32_t *)buff; + int k, written_bits = 0; + + for (k = 0; k < (size / 4); k++) { + written_bits += hweight32(~buff32[k]); + if (written_bits > max_bits) + break; + } + + return written_bits; +} + +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; + int flips_threshold = nfc->chip.ecc.strength / 2; + + ecc_status = vf610_nfc_read(mtd, ecc_status_off) & 0xff; + ecc_count = ecc_status & ECC_STATUS_ERR_COUNT; + + if (!(ecc_status & ECC_STATUS_MASK)) + return ecc_count; + + /* Read OOB without ECC unit enabled */ + vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page); + vf610_nfc_read_buf(mtd, oob, mtd->oobsize); + + /* + * On an erased page, bit count (including OOB) should be zero or + * at least less then half of the ECC strength. + */ + flips = count_written_bits(dat, nfc->chip.ecc.size, flips_threshold); + flips += count_written_bits(oob, mtd->oobsize, flips_threshold); + + if (unlikely(flips > flips_threshold)) + return -EINVAL; + + /* Erased page. */ + memset(dat, 0xff, nfc->chip.ecc.size); + memset(oob, 0xff, mtd->oobsize); + return flips; +} + +static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int eccsize = chip->ecc.size; + int stat; + + vf610_nfc_read_buf(mtd, buf, eccsize); + if (oob_required) + vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + + 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; + } +} + +/* + * ECC will be calculated automatically + */ +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); + + vf610_nfc_write_buf(mtd, buf, mtd->writesize); + if (oob_required) + vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* Always write whole page including OOB due to HW ECC */ + nfc->write_sz = mtd->writesize + mtd->oobsize; + + return 0; +} + +struct vf610_nfc_config { + int hardware_ecc; + int width; + int flash_bbt; +}; + +static int vf610_nfc_nand_init(int devnum, void __iomem *addr) +{ + struct mtd_info *mtd; + struct nand_chip *chip; + struct vf610_nfc *nfc; + int err = 0; + struct vf610_nfc_config cfg = { + .hardware_ecc = 1, +#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT + .width = 16, +#else + .width = 8, +#endif + .flash_bbt = 1, + }; + + nfc = malloc(sizeof(*nfc)); + if (!nfc) { + printf(KERN_ERR "%s: Memory exhausted!\n", __func__); + return -ENOMEM; + } + + chip = &nfc->chip; + nfc->regs = addr; + + mtd = nand_to_mtd(chip); + nand_set_controller_data(chip, nfc); + + if (cfg.width == 16) + chip->options |= NAND_BUSWIDTH_16; + + chip->dev_ready = vf610_nfc_dev_ready; + chip->cmdfunc = vf610_nfc_command; + chip->read_byte = vf610_nfc_read_byte; + chip->read_word = vf610_nfc_read_word; + chip->read_buf = vf610_nfc_read_buf; + chip->write_buf = vf610_nfc_write_buf; + chip->select_chip = vf610_nfc_select_chip; + + chip->options |= NAND_NO_SUBPAGE_WRITE; + + chip->ecc.size = PAGE_2K; + + /* Set configuration register. */ + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT); + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT); + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT); + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT); + vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT); + + /* Disable virtual pages, only one elementary transfer unit */ + vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK, + CONFIG_PAGE_CNT_SHIFT, 1); + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) { + err = -ENXIO; + goto error; + } + + if (cfg.width == 16) + vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); + + /* Bad block options. */ + if (cfg.flash_bbt) + chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB | + NAND_BBT_CREATE; + + /* 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 error; + } + + if (cfg.hardware_ecc) { + if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) { + dev_err(nfc->dev, "Unsupported flash with hwecc\n"); + err = -ENXIO; + goto error; + } + + if (chip->ecc.size != mtd->writesize) { + dev_err(nfc->dev, "ecc size: %d\n", chip->ecc.size); + dev_err(nfc->dev, "Step size needs to be page size\n"); + err = -ENXIO; + goto error; + } + + /* Current HW ECC layouts only use 64 bytes of OOB */ + if (mtd->oobsize > 64) + mtd->oobsize = 64; + + /* propagate ecc.layout to mtd_info */ + mtd->ecclayout = chip->ecc.layout; + chip->ecc.read_page = vf610_nfc_read_page; + chip->ecc.write_page = vf610_nfc_write_page; + chip->ecc.mode = NAND_ECC_HW; + + chip->ecc.size = PAGE_2K; + chip->ecc.layout = &vf610_nfc_ecc; +#if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES) + chip->ecc.strength = 24; + chip->ecc.bytes = 45; +#elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES) + chip->ecc.strength = 32; + chip->ecc.bytes = 60; +#endif + + /* Set ECC_STATUS offset */ + vf610_nfc_set_field(mtd, 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(mtd, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT); + } + + /* second phase scan */ + err = nand_scan_tail(mtd); + if (err) + return err; + + err = nand_register(devnum, mtd); + if (err) + return err; + + return 0; + +error: + return err; +} + +void board_nand_init(void) +{ + int err = vf610_nfc_nand_init(0, (void __iomem *)CONFIG_SYS_NAND_BASE); + if (err) + printf("VF610 NAND init failed (err %d)\n", err); +} diff --git a/drivers/mtd/nand/raw/zynq_nand.c b/drivers/mtd/nand/raw/zynq_nand.c new file mode 100644 index 0000000000..e932a58bf6 --- /dev/null +++ b/drivers/mtd/nand/raw/zynq_nand.c @@ -0,0 +1,1254 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Xilinx, Inc. + * + * Xilinx Zynq NAND Flash Controller Driver + * This driver is based on plat_nand.c and mxc_nand.c drivers + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The NAND flash driver defines */ +#define ZYNQ_NAND_CMD_PHASE 1 +#define ZYNQ_NAND_DATA_PHASE 2 +#define ZYNQ_NAND_ECC_SIZE 512 +#define ZYNQ_NAND_SET_OPMODE_8BIT (0 << 0) +#define ZYNQ_NAND_SET_OPMODE_16BIT (1 << 0) +#define ZYNQ_NAND_ECC_STATUS (1 << 6) +#define ZYNQ_MEMC_CLRCR_INT_CLR1 (1 << 4) +#define ZYNQ_MEMC_SR_RAW_INT_ST1 (1 << 6) +#define ZYNQ_MEMC_SR_INT_ST1 (1 << 4) +#define ZYNQ_MEMC_NAND_ECC_MODE_MASK 0xC + +/* Flash memory controller operating parameters */ +#define ZYNQ_NAND_CLR_CONFIG ((0x1 << 1) | /* Disable interrupt */ \ + (0x1 << 4) | /* Clear interrupt */ \ + (0x1 << 6)) /* Disable ECC interrupt */ + +#ifndef CONFIG_NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS + +/* Assuming 50MHz clock (20ns cycle time) and 3V operation */ +#define ZYNQ_NAND_SET_CYCLES ((0x2 << 20) | /* t_rr from nand_cycles */ \ + (0x2 << 17) | /* t_ar from nand_cycles */ \ + (0x1 << 14) | /* t_clr from nand_cycles */ \ + (0x3 << 11) | /* t_wp from nand_cycles */ \ + (0x2 << 8) | /* t_rea from nand_cycles */ \ + (0x5 << 4) | /* t_wc from nand_cycles */ \ + (0x5 << 0)) /* t_rc from nand_cycles */ +#endif + + +#define ZYNQ_NAND_DIRECT_CMD ((0x4 << 23) | /* Chip 0 from interface 1 */ \ + (0x2 << 21)) /* UpdateRegs operation */ + +#define ZYNQ_NAND_ECC_CONFIG ((0x1 << 2) | /* ECC available on APB */ \ + (0x1 << 4) | /* ECC read at end of page */ \ + (0x0 << 5)) /* No Jumping */ + +#define ZYNQ_NAND_ECC_CMD1 ((0x80) | /* Write command */ \ + (0x00 << 8) | /* Read command */ \ + (0x30 << 16) | /* Read End command */ \ + (0x1 << 24)) /* Read End command calid */ + +#define ZYNQ_NAND_ECC_CMD2 ((0x85) | /* Write col change cmd */ \ + (0x05 << 8) | /* Read col change cmd */ \ + (0xE0 << 16) | /* Read col change end cmd */ \ + (0x1 << 24)) /* Read col change + end cmd valid */ +/* AXI Address definitions */ +#define START_CMD_SHIFT 3 +#define END_CMD_SHIFT 11 +#define END_CMD_VALID_SHIFT 20 +#define ADDR_CYCLES_SHIFT 21 +#define CLEAR_CS_SHIFT 21 +#define ECC_LAST_SHIFT 10 +#define COMMAND_PHASE (0 << 19) +#define DATA_PHASE (1 << 19) +#define ONDIE_ECC_FEATURE_ADDR 0x90 +#define ONDIE_ECC_FEATURE_ENABLE 0x08 + +#define ZYNQ_NAND_ECC_LAST (1 << ECC_LAST_SHIFT) /* Set ECC_Last */ +#define ZYNQ_NAND_CLEAR_CS (1 << CLEAR_CS_SHIFT) /* Clear chip select */ + +/* ECC block registers bit position and bit mask */ +#define ZYNQ_NAND_ECC_BUSY (1 << 6) /* ECC block is busy */ +#define ZYNQ_NAND_ECC_MASK 0x00FFFFFF /* ECC value mask */ + +#define ZYNQ_NAND_ROW_ADDR_CYCL_MASK 0x0F +#define ZYNQ_NAND_COL_ADDR_CYCL_MASK 0xF0 + +#define ZYNQ_NAND_MIO_NUM_NAND_8BIT 13 +#define ZYNQ_NAND_MIO_NUM_NAND_16BIT 8 + +enum zynq_nand_bus_width { + NAND_BW_UNKNOWN = -1, + NAND_BW_8BIT, + NAND_BW_16BIT, +}; + +#ifndef NAND_CMD_LOCK_TIGHT +#define NAND_CMD_LOCK_TIGHT 0x2c +#endif + +#ifndef NAND_CMD_LOCK_STATUS +#define NAND_CMD_LOCK_STATUS 0x7a +#endif + +/* SMC register set */ +struct zynq_nand_smc_regs { + u32 csr; /* 0x00 */ + u32 reserved0[2]; + u32 cfr; /* 0x0C */ + u32 dcr; /* 0x10 */ + u32 scr; /* 0x14 */ + u32 sor; /* 0x18 */ + u32 reserved1[249]; + u32 esr; /* 0x400 */ + u32 emcr; /* 0x404 */ + u32 emcmd1r; /* 0x408 */ + u32 emcmd2r; /* 0x40C */ + u32 reserved2[2]; + u32 eval0r; /* 0x418 */ +}; +#define zynq_nand_smc_base ((struct zynq_nand_smc_regs __iomem *)\ + ZYNQ_SMC_BASEADDR) + +/* + * struct zynq_nand_info - Defines the NAND flash driver instance + * @parts: Pointer to the mtd_partition structure + * @nand_base: Virtual address of the NAND flash device + * @end_cmd_pending: End command is pending + * @end_cmd: End command + */ +struct zynq_nand_info { + void __iomem *nand_base; + u8 end_cmd_pending; + u8 end_cmd; +}; + +/* + * struct zynq_nand_command_format - Defines NAND flash command format + * @start_cmd: First cycle command (Start command) + * @end_cmd: Second cycle command (Last command) + * @addr_cycles: Number of address cycles required to send the address + * @end_cmd_valid: The second cycle command is valid for cmd or data phase + */ +struct zynq_nand_command_format { + u8 start_cmd; + u8 end_cmd; + u8 addr_cycles; + u8 end_cmd_valid; +}; + +/* The NAND flash operations command format */ +static const struct zynq_nand_command_format zynq_nand_commands[] = { + {NAND_CMD_READ0, NAND_CMD_READSTART, 5, ZYNQ_NAND_CMD_PHASE}, + {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, ZYNQ_NAND_CMD_PHASE}, + {NAND_CMD_READID, NAND_CMD_NONE, 1, 0}, + {NAND_CMD_STATUS, NAND_CMD_NONE, 0, 0}, + {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5, ZYNQ_NAND_DATA_PHASE}, + {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, 0}, + {NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3, ZYNQ_NAND_CMD_PHASE}, + {NAND_CMD_RESET, NAND_CMD_NONE, 0, 0}, + {NAND_CMD_PARAM, NAND_CMD_NONE, 1, 0}, + {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, 0}, + {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, 0}, + {NAND_CMD_LOCK, NAND_CMD_NONE, 0, 0}, + {NAND_CMD_LOCK_TIGHT, NAND_CMD_NONE, 0, 0}, + {NAND_CMD_UNLOCK1, NAND_CMD_NONE, 3, 0}, + {NAND_CMD_UNLOCK2, NAND_CMD_NONE, 3, 0}, + {NAND_CMD_LOCK_STATUS, NAND_CMD_NONE, 3, 0}, + {NAND_CMD_NONE, NAND_CMD_NONE, 0, 0}, + /* Add all the flash commands supported by the flash device */ +}; + +/* Define default oob placement schemes for large and small page devices */ +static struct nand_ecclayout nand_oob_16 = { + .eccbytes = 3, + .eccpos = {0, 1, 2}, + .oobfree = { + { .offset = 8, .length = 8 } + } +}; + +static struct nand_ecclayout nand_oob_64 = { + .eccbytes = 12, + .eccpos = { + 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63}, + .oobfree = { + { .offset = 2, .length = 50 } + } +}; + +static struct nand_ecclayout ondie_nand_oob_64 = { + .eccbytes = 32, + + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 24, 25, 26, 27, 28, 29, 30, 31, + 40, 41, 42, 43, 44, 45, 46, 47, + 56, 57, 58, 59, 60, 61, 62, 63 + }, + + .oobfree = { + { .offset = 4, .length = 4 }, + { .offset = 20, .length = 4 }, + { .offset = 36, .length = 4 }, + { .offset = 52, .length = 4 } + } +}; + +/* bbt decriptors for chips with on-die ECC and + chips with 64-byte OOB */ +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = mirror_pattern +}; + +/* + * zynq_nand_waitfor_ecc_completion - Wait for ECC completion + * + * returns: status for command completion, -1 for Timeout + */ +static int zynq_nand_waitfor_ecc_completion(void) +{ + unsigned long timeout; + u32 status; + + /* Wait max 10us */ + timeout = 10; + status = readl(&zynq_nand_smc_base->esr); + while (status & ZYNQ_NAND_ECC_BUSY) { + status = readl(&zynq_nand_smc_base->esr); + if (timeout == 0) + return -1; + timeout--; + udelay(1); + } + + return status; +} + +/* + * zynq_nand_init_nand_flash - Initialize NAND controller + * @option: Device property flags + * + * This function initializes the NAND flash interface on the NAND controller. + * + * returns: 0 on success or error value on failure + */ +static int zynq_nand_init_nand_flash(int option) +{ + u32 status; + + /* disable interrupts */ + writel(ZYNQ_NAND_CLR_CONFIG, &zynq_nand_smc_base->cfr); +#ifndef CONFIG_NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS + /* Initialize the NAND interface by setting cycles and operation mode */ + writel(ZYNQ_NAND_SET_CYCLES, &zynq_nand_smc_base->scr); +#endif + if (option & NAND_BUSWIDTH_16) + writel(ZYNQ_NAND_SET_OPMODE_16BIT, &zynq_nand_smc_base->sor); + else + writel(ZYNQ_NAND_SET_OPMODE_8BIT, &zynq_nand_smc_base->sor); + + writel(ZYNQ_NAND_DIRECT_CMD, &zynq_nand_smc_base->dcr); + + /* Wait till the ECC operation is complete */ + status = zynq_nand_waitfor_ecc_completion(); + if (status < 0) { + printf("%s: Timeout\n", __func__); + return status; + } + + /* Set the command1 and command2 register */ + writel(ZYNQ_NAND_ECC_CMD1, &zynq_nand_smc_base->emcmd1r); + writel(ZYNQ_NAND_ECC_CMD2, &zynq_nand_smc_base->emcmd2r); + + return 0; +} + +/* + * zynq_nand_calculate_hwecc - Calculate Hardware ECC + * @mtd: Pointer to the mtd_info structure + * @data: Pointer to the page data + * @ecc_code: Pointer to the ECC buffer where ECC data needs to be stored + * + * This function retrieves the Hardware ECC data from the controller and returns + * ECC data back to the MTD subsystem. + * + * returns: 0 on success or error value on failure + */ +static int zynq_nand_calculate_hwecc(struct mtd_info *mtd, const u8 *data, + u8 *ecc_code) +{ + u32 ecc_value = 0; + u8 ecc_reg, ecc_byte; + u32 ecc_status; + + /* Wait till the ECC operation is complete */ + ecc_status = zynq_nand_waitfor_ecc_completion(); + if (ecc_status < 0) { + printf("%s: Timeout\n", __func__); + return ecc_status; + } + + for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) { + /* Read ECC value for each block */ + ecc_value = readl(&zynq_nand_smc_base->eval0r + ecc_reg); + + /* Get the ecc status from ecc read value */ + ecc_status = (ecc_value >> 24) & 0xFF; + + /* ECC value valid */ + if (ecc_status & ZYNQ_NAND_ECC_STATUS) { + for (ecc_byte = 0; ecc_byte < 3; ecc_byte++) { + /* Copy ECC bytes to MTD buffer */ + *ecc_code = ecc_value & 0xFF; + ecc_value = ecc_value >> 8; + ecc_code++; + } + } else { + debug("%s: ecc status failed\n", __func__); + } + } + + return 0; +} + +/* + * onehot - onehot function + * @value: value to check for onehot + * + * This function checks whether a value is onehot or not. + * onehot is if and only if one bit is set. + * + * FIXME: Try to move this in common.h + */ +static bool onehot(unsigned short value) +{ + bool onehot; + + onehot = value && !(value & (value - 1)); + return onehot; +} + +/* + * zynq_nand_correct_data - ECC correction function + * @mtd: Pointer to the mtd_info structure + * @buf: Pointer to the page data + * @read_ecc: Pointer to the ECC value read from spare data area + * @calc_ecc: Pointer to the calculated ECC value + * + * This function corrects the ECC single bit errors & detects 2-bit errors. + * + * returns: 0 if no ECC errors found + * 1 if single bit error found and corrected. + * -1 if multiple ECC errors found. + */ +static int zynq_nand_correct_data(struct mtd_info *mtd, unsigned char *buf, + unsigned char *read_ecc, unsigned char *calc_ecc) +{ + unsigned char bit_addr; + unsigned int byte_addr; + unsigned short ecc_odd, ecc_even; + unsigned short read_ecc_lower, read_ecc_upper; + unsigned short calc_ecc_lower, calc_ecc_upper; + + read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) & 0xfff; + read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) & 0xfff; + + calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) & 0xfff; + calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) & 0xfff; + + ecc_odd = read_ecc_lower ^ calc_ecc_lower; + ecc_even = read_ecc_upper ^ calc_ecc_upper; + + if ((ecc_odd == 0) && (ecc_even == 0)) + return 0; /* no error */ + + if (ecc_odd == (~ecc_even & 0xfff)) { + /* bits [11:3] of error code is byte offset */ + byte_addr = (ecc_odd >> 3) & 0x1ff; + /* bits [2:0] of error code is bit offset */ + bit_addr = ecc_odd & 0x7; + /* Toggling error bit */ + buf[byte_addr] ^= (1 << bit_addr); + return 1; + } + + if (onehot(ecc_odd | ecc_even)) + return 1; /* one error in parity */ + + return -1; /* Uncorrectable error */ +} + +/* + * zynq_nand_read_oob - [REPLACABLE] the most common OOB data read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not + */ +static int zynq_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + unsigned long data_phase_addr = 0; + int data_width = 4; + u8 *p; + + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + + p = chip->oob_poi; + chip->read_buf(mtd, p, (mtd->oobsize - data_width)); + p += mtd->oobsize - data_width; + + data_phase_addr = (unsigned long)chip->IO_ADDR_R; + data_phase_addr |= ZYNQ_NAND_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem *)data_phase_addr; + chip->read_buf(mtd, p, data_width); + + return 0; +} + +/* + * zynq_nand_write_oob - [REPLACABLE] the most common OOB data write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write + */ +static int zynq_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + int status = 0, data_width = 4; + const u8 *buf = chip->oob_poi; + unsigned long data_phase_addr = 0; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + + chip->write_buf(mtd, buf, (mtd->oobsize - data_width)); + buf += mtd->oobsize - data_width; + + data_phase_addr = (unsigned long)chip->IO_ADDR_W; + data_phase_addr |= ZYNQ_NAND_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem *)data_phase_addr; + chip->write_buf(mtd, buf, data_width); + + /* Send command to program the OOB data */ + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +/* + * zynq_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: must write chip->oob_poi to OOB + * @page: page number to read + */ +static int zynq_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + u8 *buf, int oob_required, int page) +{ + unsigned long data_width = 4; + unsigned long data_phase_addr = 0; + u8 *p; + + chip->read_buf(mtd, buf, mtd->writesize); + + p = chip->oob_poi; + chip->read_buf(mtd, p, (mtd->oobsize - data_width)); + p += (mtd->oobsize - data_width); + + data_phase_addr = (unsigned long)chip->IO_ADDR_R; + data_phase_addr |= ZYNQ_NAND_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem *)data_phase_addr; + + chip->read_buf(mtd, p, data_width); + return 0; +} + +static int zynq_nand_read_page_raw_nooob(struct mtd_info *mtd, + struct nand_chip *chip, u8 *buf, int oob_required, int page) +{ + chip->read_buf(mtd, buf, mtd->writesize); + return 0; +} + +static int zynq_nand_read_subpage_raw(struct mtd_info *mtd, + struct nand_chip *chip, u32 data_offs, + u32 readlen, u8 *buf, int page) +{ + if (data_offs != 0) { + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_offs, -1); + buf += data_offs; + } + chip->read_buf(mtd, buf, readlen); + + return 0; +} + +/* + * zynq_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 + */ +static int zynq_nand_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, const u8 *buf, int oob_required, int page) +{ + unsigned long data_width = 4; + unsigned long data_phase_addr = 0; + u8 *p; + + chip->write_buf(mtd, buf, mtd->writesize); + + p = chip->oob_poi; + chip->write_buf(mtd, p, (mtd->oobsize - data_width)); + p += (mtd->oobsize - data_width); + + data_phase_addr = (unsigned long)chip->IO_ADDR_W; + data_phase_addr |= ZYNQ_NAND_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem *)data_phase_addr; + + chip->write_buf(mtd, p, data_width); + + return 0; +} + +/* + * nand_write_page_hwecc - Hardware ECC based page write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: must write chip->oob_poi to OOB + * + * This functions writes data and hardware generated ECC values in to the page. + */ +static int zynq_nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const u8 *buf, int oob_required, int page) +{ + int i, eccsteps, eccsize = chip->ecc.size; + u8 *ecc_calc = chip->buffers->ecccalc; + const u8 *p = buf; + u32 *eccpos = chip->ecc.layout->eccpos; + unsigned long data_phase_addr = 0; + unsigned long data_width = 4; + u8 *oob_ptr; + + for (eccsteps = chip->ecc.steps; (eccsteps - 1); eccsteps--) { + chip->write_buf(mtd, p, eccsize); + p += eccsize; + } + chip->write_buf(mtd, p, (eccsize - data_width)); + p += eccsize - data_width; + + /* Set ECC Last bit to 1 */ + data_phase_addr = (unsigned long) chip->IO_ADDR_W; + data_phase_addr |= ZYNQ_NAND_ECC_LAST; + chip->IO_ADDR_W = (void __iomem *)data_phase_addr; + chip->write_buf(mtd, p, data_width); + + /* Wait for ECC to be calculated and read the error values */ + p = buf; + chip->ecc.calculate(mtd, p, &ecc_calc[0]); + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]); + + /* Clear ECC last bit */ + data_phase_addr = (unsigned long)chip->IO_ADDR_W; + data_phase_addr &= ~ZYNQ_NAND_ECC_LAST; + chip->IO_ADDR_W = (void __iomem *)data_phase_addr; + + /* Write the spare area with ECC bytes */ + oob_ptr = chip->oob_poi; + chip->write_buf(mtd, oob_ptr, (mtd->oobsize - data_width)); + + data_phase_addr = (unsigned long)chip->IO_ADDR_W; + data_phase_addr |= ZYNQ_NAND_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem *)data_phase_addr; + oob_ptr += (mtd->oobsize - data_width); + chip->write_buf(mtd, oob_ptr, data_width); + + return 0; +} + +/* + * zynq_nand_write_page_swecc - [REPLACABLE] 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 + */ +static int zynq_nand_write_page_swecc(struct mtd_info *mtd, + struct nand_chip *chip, const u8 *buf, int oob_required, int page) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + u8 *ecc_calc = chip->buffers->ecccalc; + const u8 *p = buf; + u32 *eccpos = chip->ecc.layout->eccpos; + + /* Software ecc calculation */ + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ecc_calc[i]; + + return chip->ecc.write_page_raw(mtd, chip, buf, 1, page); +} + +/* + * nand_read_page_hwecc - Hardware ECC based page read function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the buffer to store read data + * @oob_required: must write chip->oob_poi to OOB + * @page: page number to read + * + * This functions reads data and checks the data integrity by comparing hardware + * generated ECC values and read ECC values from spare area. + * + * returns: 0 always and updates ECC operation status in to MTD structure + */ +static int zynq_nand_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, u8 *buf, int oob_required, int page) +{ + int i, stat, eccsteps, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + u8 *p = buf; + u8 *ecc_calc = chip->buffers->ecccalc; + u8 *ecc_code = chip->buffers->ecccode; + u32 *eccpos = chip->ecc.layout->eccpos; + unsigned long data_phase_addr = 0; + unsigned long data_width = 4; + u8 *oob_ptr; + + for (eccsteps = chip->ecc.steps; (eccsteps - 1); eccsteps--) { + chip->read_buf(mtd, p, eccsize); + p += eccsize; + } + chip->read_buf(mtd, p, (eccsize - data_width)); + p += eccsize - data_width; + + /* Set ECC Last bit to 1 */ + data_phase_addr = (unsigned long)chip->IO_ADDR_R; + data_phase_addr |= ZYNQ_NAND_ECC_LAST; + chip->IO_ADDR_R = (void __iomem *)data_phase_addr; + chip->read_buf(mtd, p, data_width); + + /* Read the calculated ECC value */ + p = buf; + chip->ecc.calculate(mtd, p, &ecc_calc[0]); + + /* Clear ECC last bit */ + data_phase_addr = (unsigned long)chip->IO_ADDR_R; + data_phase_addr &= ~ZYNQ_NAND_ECC_LAST; + chip->IO_ADDR_R = (void __iomem *)data_phase_addr; + + /* Read the stored ECC value */ + oob_ptr = chip->oob_poi; + chip->read_buf(mtd, oob_ptr, (mtd->oobsize - data_width)); + + /* de-assert chip select */ + data_phase_addr = (unsigned long)chip->IO_ADDR_R; + data_phase_addr |= ZYNQ_NAND_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem *)data_phase_addr; + + oob_ptr += (mtd->oobsize - data_width); + chip->read_buf(mtd, oob_ptr, data_width); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = ~(chip->oob_poi[eccpos[i]]); + + eccsteps = chip->ecc.steps; + p = buf; + + /* Check ECC error for all blocks and correct if it is correctable */ + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/* + * zynq_nand_read_page_swecc - [REPLACABLE] software ecc based page + * read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read + */ +static int zynq_nand_read_page_swecc(struct mtd_info *mtd, + struct nand_chip *chip, u8 *buf, int oob_required, int page) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + u8 *p = buf; + u8 *ecc_calc = chip->buffers->ecccalc; + u8 *ecc_code = chip->buffers->ecccode; + u32 *eccpos = chip->ecc.layout->eccpos; + + chip->ecc.read_page_raw(mtd, chip, buf, 1, page); + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + eccsteps = chip->ecc.steps; + p = buf; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/* + * zynq_nand_select_chip - Select the flash device + * @mtd: Pointer to the mtd_info structure + * @chip: Chip number to be selected + * + * This function is empty as the NAND controller handles chip select line + * internally based on the chip address passed in command and data phase. + */ +static void zynq_nand_select_chip(struct mtd_info *mtd, int chip) +{ + /* Not support multiple chips yet */ +} + +/* + * zynq_nand_cmd_function - Send command to NAND device + * @mtd: Pointer to the mtd_info structure + * @command: The command to be sent to the flash device + * @column: The column address for this command, -1 if none + * @page_addr: The page address for this command, -1 if none + */ +static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd->priv; + const struct zynq_nand_command_format *curr_cmd = NULL; + u8 addr_cycles = 0; + struct zynq_nand_info *xnand = (struct zynq_nand_info *)chip->priv; + void *cmd_addr; + unsigned long cmd_data = 0; + unsigned long cmd_phase_addr = 0; + unsigned long data_phase_addr = 0; + u8 end_cmd = 0; + u8 end_cmd_valid = 0; + u32 index; + + if (xnand->end_cmd_pending) { + /* Check for end command if this command request is same as the + * pending command then return + */ + if (xnand->end_cmd == command) { + xnand->end_cmd = 0; + xnand->end_cmd_pending = 0; + return; + } + } + + /* Emulate NAND_CMD_READOOB for large page device */ + if ((mtd->writesize > ZYNQ_NAND_ECC_SIZE) && + (command == NAND_CMD_READOOB)) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Get the command format */ + for (index = 0; index < ARRAY_SIZE(zynq_nand_commands); index++) + if (command == zynq_nand_commands[index].start_cmd) + break; + + if (index == ARRAY_SIZE(zynq_nand_commands)) { + printf("%s: Unsupported start cmd %02x\n", __func__, command); + return; + } + curr_cmd = &zynq_nand_commands[index]; + + /* Clear interrupt */ + writel(ZYNQ_MEMC_CLRCR_INT_CLR1, &zynq_nand_smc_base->cfr); + + /* Get the command phase address */ + if (curr_cmd->end_cmd_valid == ZYNQ_NAND_CMD_PHASE) + end_cmd_valid = 1; + + if (curr_cmd->end_cmd == NAND_CMD_NONE) + end_cmd = 0x0; + else + end_cmd = curr_cmd->end_cmd; + + if (command == NAND_CMD_READ0 || + command == NAND_CMD_SEQIN) { + addr_cycles = chip->onfi_params.addr_cycles & + ZYNQ_NAND_ROW_ADDR_CYCL_MASK; + addr_cycles += ((chip->onfi_params.addr_cycles & + ZYNQ_NAND_COL_ADDR_CYCL_MASK) >> 4); + } else { + addr_cycles = curr_cmd->addr_cycles; + } + + cmd_phase_addr = (unsigned long)xnand->nand_base | + (addr_cycles << ADDR_CYCLES_SHIFT) | + (end_cmd_valid << END_CMD_VALID_SHIFT) | + (COMMAND_PHASE) | + (end_cmd << END_CMD_SHIFT) | + (curr_cmd->start_cmd << START_CMD_SHIFT); + + cmd_addr = (void __iomem *)cmd_phase_addr; + + /* Get the data phase address */ + end_cmd_valid = 0; + + data_phase_addr = (unsigned long)xnand->nand_base | + (0x0 << CLEAR_CS_SHIFT) | + (end_cmd_valid << END_CMD_VALID_SHIFT) | + (DATA_PHASE) | + (end_cmd << END_CMD_SHIFT) | + (0x0 << ECC_LAST_SHIFT); + + chip->IO_ADDR_R = (void __iomem *)data_phase_addr; + chip->IO_ADDR_W = chip->IO_ADDR_R; + + /* Command phase AXI Read & Write */ + if (column != -1 && page_addr != -1) { + /* Adjust columns for 16 bit bus width */ + if (chip->options & NAND_BUSWIDTH_16) + column >>= 1; + cmd_data = column; + if (mtd->writesize > ZYNQ_NAND_ECC_SIZE) { + cmd_data |= page_addr << 16; + /* Another address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) { + writel(cmd_data, cmd_addr); + cmd_data = (page_addr >> 16); + } + } else { + cmd_data |= page_addr << 8; + } + } else if (page_addr != -1) { /* Erase */ + cmd_data = page_addr; + } else if (column != -1) { /* Change read/write column, read id etc */ + /* Adjust columns for 16 bit bus width */ + if ((chip->options & NAND_BUSWIDTH_16) && + ((command == NAND_CMD_READ0) || + (command == NAND_CMD_SEQIN) || + (command == NAND_CMD_RNDOUT) || + (command == NAND_CMD_RNDIN))) + column >>= 1; + cmd_data = column; + } + + writel(cmd_data, cmd_addr); + + if (curr_cmd->end_cmd_valid) { + xnand->end_cmd = curr_cmd->end_cmd; + xnand->end_cmd_pending = 1; + } + + ndelay(100); + + if ((command == NAND_CMD_READ0) || + (command == NAND_CMD_RESET) || + (command == NAND_CMD_PARAM) || + (command == NAND_CMD_GET_FEATURES)) + /* wait until command is processed */ + nand_wait_ready(mtd); +} + +/* + * zynq_nand_read_buf - read chip data into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + */ +static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + + /* Make sure that buf is 32 bit aligned */ + if (((unsigned long)buf & 0x3) != 0) { + if (((unsigned long)buf & 0x1) != 0) { + if (len) { + *buf = readb(chip->IO_ADDR_R); + buf += 1; + len--; + } + } + + if (((unsigned long)buf & 0x3) != 0) { + if (len >= 2) { + *(u16 *)buf = readw(chip->IO_ADDR_R); + buf += 2; + len -= 2; + } + } + } + + /* copy aligned data */ + while (len >= 4) { + *(u32 *)buf = readl(chip->IO_ADDR_R); + buf += 4; + len -= 4; + } + + /* mop up any remaining bytes */ + if (len) { + if (len >= 2) { + *(u16 *)buf = readw(chip->IO_ADDR_R); + buf += 2; + len -= 2; + } + if (len) + *buf = readb(chip->IO_ADDR_R); + } +} + +/* + * zynq_nand_write_buf - write buffer to chip + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + */ +static void zynq_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + const u32 *nand = chip->IO_ADDR_W; + + /* Make sure that buf is 32 bit aligned */ + if (((unsigned long)buf & 0x3) != 0) { + if (((unsigned long)buf & 0x1) != 0) { + if (len) { + writeb(*buf, nand); + buf += 1; + len--; + } + } + + if (((unsigned long)buf & 0x3) != 0) { + if (len >= 2) { + writew(*(u16 *)buf, nand); + buf += 2; + len -= 2; + } + } + } + + /* copy aligned data */ + while (len >= 4) { + writel(*(u32 *)buf, nand); + buf += 4; + len -= 4; + } + + /* mop up any remaining bytes */ + if (len) { + if (len >= 2) { + writew(*(u16 *)buf, nand); + buf += 2; + len -= 2; + } + + if (len) + writeb(*buf, nand); + } +} + +/* + * zynq_nand_device_ready - Check device ready/busy line + * @mtd: Pointer to the mtd_info structure + * + * returns: 0 on busy or 1 on ready state + */ +static int zynq_nand_device_ready(struct mtd_info *mtd) +{ + u32 csr_val; + + csr_val = readl(&zynq_nand_smc_base->csr); + /* Check the raw_int_status1 bit */ + if (csr_val & ZYNQ_MEMC_SR_RAW_INT_ST1) { + /* Clear the interrupt condition */ + writel(ZYNQ_MEMC_SR_INT_ST1, &zynq_nand_smc_base->cfr); + return 1; + } + + return 0; +} + +static int zynq_nand_check_is_16bit_bw_flash(void) +{ + int is_16bit_bw = NAND_BW_UNKNOWN; + int mio_num_8bit = 0, mio_num_16bit = 0; + + mio_num_8bit = zynq_slcr_get_mio_pin_status("nand8"); + if (mio_num_8bit == ZYNQ_NAND_MIO_NUM_NAND_8BIT) + is_16bit_bw = NAND_BW_8BIT; + + mio_num_16bit = zynq_slcr_get_mio_pin_status("nand16"); + if (mio_num_8bit == ZYNQ_NAND_MIO_NUM_NAND_8BIT && + mio_num_16bit == ZYNQ_NAND_MIO_NUM_NAND_16BIT) + is_16bit_bw = NAND_BW_16BIT; + + return is_16bit_bw; +} + +static int zynq_nand_init(struct nand_chip *nand_chip, int devnum) +{ + struct zynq_nand_info *xnand; + struct mtd_info *mtd; + unsigned long ecc_page_size; + u8 maf_id, dev_id, i; + u8 get_feature[4]; + u8 set_feature[4] = {ONDIE_ECC_FEATURE_ENABLE, 0x00, 0x00, 0x00}; + unsigned long ecc_cfg; + int ondie_ecc_enabled = 0; + int err = -1; + int is_16bit_bw; + + xnand = calloc(1, sizeof(struct zynq_nand_info)); + if (!xnand) { + printf("%s: failed to allocate\n", __func__); + goto fail; + } + + xnand->nand_base = (void __iomem *)ZYNQ_NAND_BASEADDR; + mtd = nand_to_mtd(nand_chip); + + nand_chip->priv = xnand; + mtd->priv = nand_chip; + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = xnand->nand_base; + nand_chip->IO_ADDR_W = xnand->nand_base; + + /* Set the driver entry points for MTD */ + nand_chip->cmdfunc = zynq_nand_cmd_function; + nand_chip->dev_ready = zynq_nand_device_ready; + nand_chip->select_chip = zynq_nand_select_chip; + + /* If we don't set this delay driver sets 20us by default */ + nand_chip->chip_delay = 30; + + /* Buffer read/write routines */ + nand_chip->read_buf = zynq_nand_read_buf; + nand_chip->write_buf = zynq_nand_write_buf; + + is_16bit_bw = zynq_nand_check_is_16bit_bw_flash(); + if (is_16bit_bw == NAND_BW_UNKNOWN) { + printf("%s: Unable detect NAND based on MIO settings\n", + __func__); + goto fail; + } + + if (is_16bit_bw == NAND_BW_16BIT) + nand_chip->options = NAND_BUSWIDTH_16; + + nand_chip->bbt_options = NAND_BBT_USE_FLASH; + + /* Initialize the NAND flash interface on NAND controller */ + if (zynq_nand_init_nand_flash(nand_chip->options) < 0) { + printf("%s: nand flash init failed\n", __func__); + goto fail; + } + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1, NULL)) { + printf("%s: nand_scan_ident failed\n", __func__); + goto fail; + } + /* Send the command for reading device ID */ + nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + maf_id = nand_chip->read_byte(mtd); + dev_id = nand_chip->read_byte(mtd); + + if ((maf_id == 0x2c) && ((dev_id == 0xf1) || + (dev_id == 0xa1) || (dev_id == 0xb1) || + (dev_id == 0xaa) || (dev_id == 0xba) || + (dev_id == 0xda) || (dev_id == 0xca) || + (dev_id == 0xac) || (dev_id == 0xbc) || + (dev_id == 0xdc) || (dev_id == 0xcc) || + (dev_id == 0xa3) || (dev_id == 0xb3) || + (dev_id == 0xd3) || (dev_id == 0xc3))) { + nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + for (i = 0; i < 4; i++) + writeb(set_feature[i], nand_chip->IO_ADDR_W); + + /* Wait for 1us after writing data with SET_FEATURES command */ + ndelay(1000); + + nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + nand_chip->read_buf(mtd, get_feature, 4); + + if (get_feature[0] & ONDIE_ECC_FEATURE_ENABLE) { + debug("%s: OnDie ECC flash\n", __func__); + ondie_ecc_enabled = 1; + } else { + printf("%s: Unable to detect OnDie ECC\n", __func__); + } + } + + if (ondie_ecc_enabled) { + /* Bypass the controller ECC block */ + ecc_cfg = readl(&zynq_nand_smc_base->emcr); + ecc_cfg &= ~ZYNQ_MEMC_NAND_ECC_MODE_MASK; + writel(ecc_cfg, &zynq_nand_smc_base->emcr); + + /* The software ECC routines won't work + * with the SMC controller + */ + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.strength = 1; + nand_chip->ecc.read_page = zynq_nand_read_page_raw_nooob; + nand_chip->ecc.read_subpage = zynq_nand_read_subpage_raw; + nand_chip->ecc.write_page = zynq_nand_write_page_raw; + nand_chip->ecc.read_page_raw = zynq_nand_read_page_raw; + nand_chip->ecc.write_page_raw = zynq_nand_write_page_raw; + nand_chip->ecc.read_oob = zynq_nand_read_oob; + nand_chip->ecc.write_oob = zynq_nand_write_oob; + nand_chip->ecc.size = mtd->writesize; + nand_chip->ecc.bytes = 0; + + /* NAND with on-die ECC supports subpage reads */ + nand_chip->options |= NAND_SUBPAGE_READ; + + /* On-Die ECC spare bytes offset 8 is used for ECC codes */ + if (ondie_ecc_enabled) { + nand_chip->ecc.layout = &ondie_nand_oob_64; + /* Use the BBT pattern descriptors */ + nand_chip->bbt_td = &bbt_main_descr; + nand_chip->bbt_md = &bbt_mirror_descr; + } + } else { + /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.strength = 1; + nand_chip->ecc.size = ZYNQ_NAND_ECC_SIZE; + nand_chip->ecc.bytes = 3; + nand_chip->ecc.calculate = zynq_nand_calculate_hwecc; + nand_chip->ecc.correct = zynq_nand_correct_data; + nand_chip->ecc.hwctl = NULL; + nand_chip->ecc.read_page = zynq_nand_read_page_hwecc; + nand_chip->ecc.write_page = zynq_nand_write_page_hwecc; + nand_chip->ecc.read_page_raw = zynq_nand_read_page_raw; + nand_chip->ecc.write_page_raw = zynq_nand_write_page_raw; + nand_chip->ecc.read_oob = zynq_nand_read_oob; + nand_chip->ecc.write_oob = zynq_nand_write_oob; + + switch (mtd->writesize) { + case 512: + ecc_page_size = 0x1; + /* Set the ECC memory config register */ + writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size), + &zynq_nand_smc_base->emcr); + break; + case 1024: + ecc_page_size = 0x2; + /* Set the ECC memory config register */ + writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size), + &zynq_nand_smc_base->emcr); + break; + case 2048: + ecc_page_size = 0x3; + /* Set the ECC memory config register */ + writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size), + &zynq_nand_smc_base->emcr); + break; + default: + nand_chip->ecc.mode = NAND_ECC_SOFT; + nand_chip->ecc.calculate = nand_calculate_ecc; + nand_chip->ecc.correct = nand_correct_data; + nand_chip->ecc.read_page = zynq_nand_read_page_swecc; + nand_chip->ecc.write_page = zynq_nand_write_page_swecc; + nand_chip->ecc.size = 256; + break; + } + + if (mtd->oobsize == 16) + nand_chip->ecc.layout = &nand_oob_16; + else if (mtd->oobsize == 64) + nand_chip->ecc.layout = &nand_oob_64; + else + printf("%s: No oob layout found\n", __func__); + } + + /* Second phase scan */ + if (nand_scan_tail(mtd)) { + printf("%s: nand_scan_tail failed\n", __func__); + goto fail; + } + if (nand_register(devnum, mtd)) + goto fail; + return 0; +fail: + free(xnand); + return err; +} + +static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; + +void board_nand_init(void) +{ + struct nand_chip *nand = &nand_chip[0]; + + if (zynq_nand_init(nand, 0)) + puts("ZYNQ NAND init failed\n"); +} diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c deleted file mode 100644 index 3ccb168d13..0000000000 --- a/drivers/mtd/nand/sunxi_nand.c +++ /dev/null @@ -1,1850 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2013 Boris BREZILLON - * Copyright (C) 2015 Roy Spliet - * - * Derived from: - * https://github.com/yuq/sunxi-nfc-mtd - * Copyright (C) 2013 Qiang Yu - * - * https://github.com/hno/Allwinner-Info - * Copyright (C) 2013 Henrik Nordström - * - * Copyright (C) 2013 Dmitriy B. - * Copyright (C) 2013 Sergey Lapin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -#define NFC_REG_CTL 0x0000 -#define NFC_REG_ST 0x0004 -#define NFC_REG_INT 0x0008 -#define NFC_REG_TIMING_CTL 0x000C -#define NFC_REG_TIMING_CFG 0x0010 -#define NFC_REG_ADDR_LOW 0x0014 -#define NFC_REG_ADDR_HIGH 0x0018 -#define NFC_REG_SECTOR_NUM 0x001C -#define NFC_REG_CNT 0x0020 -#define NFC_REG_CMD 0x0024 -#define NFC_REG_RCMD_SET 0x0028 -#define NFC_REG_WCMD_SET 0x002C -#define NFC_REG_IO_DATA 0x0030 -#define NFC_REG_ECC_CTL 0x0034 -#define NFC_REG_ECC_ST 0x0038 -#define NFC_REG_DEBUG 0x003C -#define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3) -#define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4)) -#define NFC_REG_SPARE_AREA 0x00A0 -#define NFC_REG_PAT_ID 0x00A4 -#define NFC_RAM0_BASE 0x0400 -#define NFC_RAM1_BASE 0x0800 - -/* define bit use in NFC_CTL */ -#define NFC_EN BIT(0) -#define NFC_RESET BIT(1) -#define NFC_BUS_WIDTH_MSK BIT(2) -#define NFC_BUS_WIDTH_8 (0 << 2) -#define NFC_BUS_WIDTH_16 (1 << 2) -#define NFC_RB_SEL_MSK BIT(3) -#define NFC_RB_SEL(x) ((x) << 3) -#define NFC_CE_SEL_MSK (0x7 << 24) -#define NFC_CE_SEL(x) ((x) << 24) -#define NFC_CE_CTL BIT(6) -#define NFC_PAGE_SHIFT_MSK (0xf << 8) -#define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8) -#define NFC_SAM BIT(12) -#define NFC_RAM_METHOD BIT(14) -#define NFC_DEBUG_CTL BIT(31) - -/* define bit use in NFC_ST */ -#define NFC_RB_B2R BIT(0) -#define NFC_CMD_INT_FLAG BIT(1) -#define NFC_DMA_INT_FLAG BIT(2) -#define NFC_CMD_FIFO_STATUS BIT(3) -#define NFC_STA BIT(4) -#define NFC_NATCH_INT_FLAG BIT(5) -#define NFC_RB_STATE(x) BIT(x + 8) - -/* define bit use in NFC_INT */ -#define NFC_B2R_INT_ENABLE BIT(0) -#define NFC_CMD_INT_ENABLE BIT(1) -#define NFC_DMA_INT_ENABLE BIT(2) -#define NFC_INT_MASK (NFC_B2R_INT_ENABLE | \ - NFC_CMD_INT_ENABLE | \ - NFC_DMA_INT_ENABLE) - -/* define bit use in NFC_TIMING_CTL */ -#define NFC_TIMING_CTL_EDO BIT(8) - -/* define NFC_TIMING_CFG register layout */ -#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \ - (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \ - (((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) | \ - (((tCAD) & 0x7) << 8)) - -/* define bit use in NFC_CMD */ -#define NFC_CMD_LOW_BYTE_MSK 0xff -#define NFC_CMD_HIGH_BYTE_MSK (0xff << 8) -#define NFC_CMD(x) (x) -#define NFC_ADR_NUM_MSK (0x7 << 16) -#define NFC_ADR_NUM(x) (((x) - 1) << 16) -#define NFC_SEND_ADR BIT(19) -#define NFC_ACCESS_DIR BIT(20) -#define NFC_DATA_TRANS BIT(21) -#define NFC_SEND_CMD1 BIT(22) -#define NFC_WAIT_FLAG BIT(23) -#define NFC_SEND_CMD2 BIT(24) -#define NFC_SEQ BIT(25) -#define NFC_DATA_SWAP_METHOD BIT(26) -#define NFC_ROW_AUTO_INC BIT(27) -#define NFC_SEND_CMD3 BIT(28) -#define NFC_SEND_CMD4 BIT(29) -#define NFC_CMD_TYPE_MSK (0x3 << 30) -#define NFC_NORMAL_OP (0 << 30) -#define NFC_ECC_OP (1 << 30) -#define NFC_PAGE_OP (2 << 30) - -/* define bit use in NFC_RCMD_SET */ -#define NFC_READ_CMD_MSK 0xff -#define NFC_RND_READ_CMD0_MSK (0xff << 8) -#define NFC_RND_READ_CMD1_MSK (0xff << 16) - -/* define bit use in NFC_WCMD_SET */ -#define NFC_PROGRAM_CMD_MSK 0xff -#define NFC_RND_WRITE_CMD_MSK (0xff << 8) -#define NFC_READ_CMD0_MSK (0xff << 16) -#define NFC_READ_CMD1_MSK (0xff << 24) - -/* define bit use in NFC_ECC_CTL */ -#define NFC_ECC_EN BIT(0) -#define NFC_ECC_PIPELINE BIT(3) -#define NFC_ECC_EXCEPTION BIT(4) -#define NFC_ECC_BLOCK_SIZE_MSK BIT(5) -#define NFC_ECC_BLOCK_512 (1 << 5) -#define NFC_RANDOM_EN BIT(9) -#define NFC_RANDOM_DIRECTION BIT(10) -#define NFC_ECC_MODE_MSK (0xf << 12) -#define NFC_ECC_MODE(x) ((x) << 12) -#define NFC_RANDOM_SEED_MSK (0x7fff << 16) -#define NFC_RANDOM_SEED(x) ((x) << 16) - -/* define bit use in NFC_ECC_ST */ -#define NFC_ECC_ERR(x) BIT(x) -#define NFC_ECC_PAT_FOUND(x) BIT(x + 16) -#define NFC_ECC_ERR_CNT(b, x) (((x) >> ((b) * 8)) & 0xff) - -#define NFC_DEFAULT_TIMEOUT_MS 1000 - -#define NFC_SRAM_SIZE 1024 - -#define NFC_MAX_CS 7 - -/* - * Ready/Busy detection type: describes the Ready/Busy detection modes - * - * @RB_NONE: no external detection available, rely on STATUS command - * and software timeouts - * @RB_NATIVE: use sunxi NAND controller Ready/Busy support. The Ready/Busy - * pin of the NAND flash chip must be connected to one of the - * native NAND R/B pins (those which can be muxed to the NAND - * Controller) - * @RB_GPIO: use a simple GPIO to handle Ready/Busy status. The Ready/Busy - * pin of the NAND flash chip must be connected to a GPIO capable - * pin. - */ -enum sunxi_nand_rb_type { - RB_NONE, - RB_NATIVE, - RB_GPIO, -}; - -/* - * Ready/Busy structure: stores information related to Ready/Busy detection - * - * @type: the Ready/Busy detection mode - * @info: information related to the R/B detection mode. Either a gpio - * id or a native R/B id (those supported by the NAND controller). - */ -struct sunxi_nand_rb { - enum sunxi_nand_rb_type type; - union { - struct gpio_desc gpio; - int nativeid; - } info; -}; - -/* - * Chip Select structure: stores information related to NAND Chip Select - * - * @cs: the NAND CS id used to communicate with a NAND Chip - * @rb: the Ready/Busy description - */ -struct sunxi_nand_chip_sel { - u8 cs; - struct sunxi_nand_rb rb; -}; - -/* - * sunxi HW ECC infos: stores information related to HW ECC support - * - * @mode: the sunxi ECC mode field deduced from ECC requirements - * @layout: the OOB layout depending on the ECC requirements and the - * selected ECC mode - */ -struct sunxi_nand_hw_ecc { - int mode; - struct nand_ecclayout layout; -}; - -/* - * NAND chip structure: stores NAND chip device related information - * - * @node: used to store NAND chips into a list - * @nand: base NAND chip structure - * @mtd: base MTD structure - * @clk_rate: clk_rate required for this NAND chip - * @timing_cfg TIMING_CFG register value for this NAND chip - * @selected: current active CS - * @nsels: number of CS lines required by the NAND chip - * @sels: array of CS lines descriptions - */ -struct sunxi_nand_chip { - struct list_head node; - struct nand_chip nand; - unsigned long clk_rate; - u32 timing_cfg; - u32 timing_ctl; - int selected; - int addr_cycles; - u32 addr[2]; - int cmd_cycles; - u8 cmd[2]; - int nsels; - struct sunxi_nand_chip_sel sels[0]; -}; - -static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) -{ - return container_of(nand, struct sunxi_nand_chip, nand); -} - -/* - * NAND Controller structure: stores sunxi NAND controller information - * - * @controller: base controller structure - * @dev: parent device (used to print error messages) - * @regs: NAND controller registers - * @ahb_clk: NAND Controller AHB clock - * @mod_clk: NAND Controller mod clock - * @assigned_cs: bitmask describing already assigned CS lines - * @clk_rate: NAND controller current clock rate - * @chips: a list containing all the NAND chips attached to - * this NAND controller - * @complete: a completion object used to wait for NAND - * controller events - */ -struct sunxi_nfc { - struct nand_hw_control controller; - struct device *dev; - void __iomem *regs; - struct clk *ahb_clk; - struct clk *mod_clk; - unsigned long assigned_cs; - unsigned long clk_rate; - struct list_head chips; -}; - -static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl) -{ - return container_of(ctrl, struct sunxi_nfc, controller); -} - -static void sunxi_nfc_set_clk_rate(unsigned long hz) -{ - struct sunxi_ccm_reg *const ccm = - (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - int div_m, div_n; - - div_m = (clock_get_pll6() + hz - 1) / hz; - for (div_n = 0; div_n < 3 && div_m > 16; div_n++) { - if (div_m % 2) - div_m++; - div_m >>= 1; - } - if (div_m > 16) - div_m = 16; - - /* config mod clock */ - writel(CCM_NAND_CTRL_ENABLE | CCM_NAND_CTRL_PLL6 | - CCM_NAND_CTRL_N(div_n) | CCM_NAND_CTRL_M(div_m), - &ccm->nand0_clk_cfg); - - /* gate on nand clock */ - setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_NAND0)); -#ifdef CONFIG_MACH_SUN9I - setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); -#else - setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); -#endif -} - -static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags, - unsigned int timeout_ms) -{ - unsigned int timeout_ticks; - u32 time_start, status; - int ret = -ETIMEDOUT; - - if (!timeout_ms) - timeout_ms = NFC_DEFAULT_TIMEOUT_MS; - - timeout_ticks = (timeout_ms * CONFIG_SYS_HZ) / 1000; - - time_start = get_timer(0); - - do { - status = readl(nfc->regs + NFC_REG_ST); - if ((status & flags) == flags) { - ret = 0; - break; - } - - udelay(1); - } while (get_timer(time_start) < timeout_ticks); - - writel(status & flags, nfc->regs + NFC_REG_ST); - - return ret; -} - -static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc) -{ - unsigned long timeout = (CONFIG_SYS_HZ * - NFC_DEFAULT_TIMEOUT_MS) / 1000; - u32 time_start; - - time_start = get_timer(0); - do { - if (!(readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS)) - return 0; - } while (get_timer(time_start) < timeout); - - dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n"); - return -ETIMEDOUT; -} - -static int sunxi_nfc_rst(struct sunxi_nfc *nfc) -{ - unsigned long timeout = (CONFIG_SYS_HZ * - NFC_DEFAULT_TIMEOUT_MS) / 1000; - u32 time_start; - - writel(0, nfc->regs + NFC_REG_ECC_CTL); - writel(NFC_RESET, nfc->regs + NFC_REG_CTL); - - time_start = get_timer(0); - do { - if (!(readl(nfc->regs + NFC_REG_CTL) & NFC_RESET)) - return 0; - } while (get_timer(time_start) < timeout); - - dev_err(nfc->dev, "wait for NAND controller reset timedout\n"); - return -ETIMEDOUT; -} - -static int sunxi_nfc_dev_ready(struct mtd_info *mtd) -{ - 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); - struct sunxi_nand_rb *rb; - unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20); - int ret; - - if (sunxi_nand->selected < 0) - return 0; - - rb = &sunxi_nand->sels[sunxi_nand->selected].rb; - - switch (rb->type) { - case RB_NATIVE: - ret = !!(readl(nfc->regs + NFC_REG_ST) & - NFC_RB_STATE(rb->info.nativeid)); - if (ret) - break; - - sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo); - ret = !!(readl(nfc->regs + NFC_REG_ST) & - NFC_RB_STATE(rb->info.nativeid)); - break; - case RB_GPIO: - ret = dm_gpio_get_value(&rb->info.gpio); - break; - case RB_NONE: - default: - ret = 0; - dev_err(nfc->dev, "cannot check R/B NAND status!\n"); - break; - } - - return ret; -} - -static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) -{ - 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); - struct sunxi_nand_chip_sel *sel; - u32 ctl; - - if (chip > 0 && chip >= sunxi_nand->nsels) - return; - - if (chip == sunxi_nand->selected) - return; - - ctl = readl(nfc->regs + NFC_REG_CTL) & - ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN); - - if (chip >= 0) { - sel = &sunxi_nand->sels[chip]; - - ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | - NFC_PAGE_SHIFT(nand->page_shift - 10); - if (sel->rb.type == RB_NONE) { - nand->dev_ready = NULL; - } else { - nand->dev_ready = sunxi_nfc_dev_ready; - if (sel->rb.type == RB_NATIVE) - ctl |= NFC_RB_SEL(sel->rb.info.nativeid); - } - - writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); - - if (nfc->clk_rate != sunxi_nand->clk_rate) { - sunxi_nfc_set_clk_rate(sunxi_nand->clk_rate); - nfc->clk_rate = sunxi_nand->clk_rate; - } - } - - writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL); - writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); - writel(ctl, nfc->regs + NFC_REG_CTL); - - sunxi_nand->selected = chip; -} - -static void sunxi_nfc_read_buf(struct mtd_info *mtd, 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; - int cnt; - int offs = 0; - u32 tmp; - - while (len > offs) { - cnt = min(len - offs, NFC_SRAM_SIZE); - - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - break; - - writel(cnt, nfc->regs + NFC_REG_CNT); - tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD; - writel(tmp, nfc->regs + NFC_REG_CMD); - - ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); - if (ret) - break; - - if (buf) - memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE, - cnt); - offs += cnt; - } -} - -static void sunxi_nfc_write_buf(struct mtd_info *mtd, 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; - int cnt; - int offs = 0; - u32 tmp; - - while (len > offs) { - cnt = min(len - offs, NFC_SRAM_SIZE); - - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - break; - - writel(cnt, nfc->regs + NFC_REG_CNT); - memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt); - tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | - NFC_ACCESS_DIR; - writel(tmp, nfc->regs + NFC_REG_CMD); - - ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); - if (ret) - break; - - offs += cnt; - } -} - -static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd) -{ - uint8_t ret; - - sunxi_nfc_read_buf(mtd, &ret, 1); - - return ret; -} - -static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, 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; - u32 tmp; - - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - return; - - if (ctrl & NAND_CTRL_CHANGE) { - tmp = readl(nfc->regs + NFC_REG_CTL); - if (ctrl & NAND_NCE) - tmp |= NFC_CE_CTL; - else - tmp &= ~NFC_CE_CTL; - writel(tmp, nfc->regs + NFC_REG_CTL); - } - - if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) && - !(ctrl & (NAND_CLE | NAND_ALE))) { - u32 cmd = 0; - - if (!sunxi_nand->addr_cycles && !sunxi_nand->cmd_cycles) - return; - - if (sunxi_nand->cmd_cycles--) - cmd |= NFC_SEND_CMD1 | sunxi_nand->cmd[0]; - - if (sunxi_nand->cmd_cycles--) { - cmd |= NFC_SEND_CMD2; - writel(sunxi_nand->cmd[1], - nfc->regs + NFC_REG_RCMD_SET); - } - - sunxi_nand->cmd_cycles = 0; - - if (sunxi_nand->addr_cycles) { - cmd |= NFC_SEND_ADR | - NFC_ADR_NUM(sunxi_nand->addr_cycles); - writel(sunxi_nand->addr[0], - nfc->regs + NFC_REG_ADDR_LOW); - } - - if (sunxi_nand->addr_cycles > 4) - writel(sunxi_nand->addr[1], - nfc->regs + NFC_REG_ADDR_HIGH); - - writel(cmd, nfc->regs + NFC_REG_CMD); - sunxi_nand->addr[0] = 0; - sunxi_nand->addr[1] = 0; - sunxi_nand->addr_cycles = 0; - sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); - } - - if (ctrl & NAND_CLE) { - sunxi_nand->cmd[sunxi_nand->cmd_cycles++] = dat; - } else if (ctrl & NAND_ALE) { - sunxi_nand->addr[sunxi_nand->addr_cycles / 4] |= - dat << ((sunxi_nand->addr_cycles % 4) * 8); - sunxi_nand->addr_cycles++; - } -} - -/* These seed values have been extracted from Allwinner's BSP */ -static const u16 sunxi_nfc_randomizer_page_seeds[] = { - 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72, - 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436, - 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d, - 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130, - 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56, - 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55, - 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb, - 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17, - 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62, - 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064, - 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126, - 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e, - 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3, - 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b, - 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d, - 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db, -}; - -/* - * sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds - * have been generated using - * sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what - * the randomizer engine does internally before de/scrambling OOB data. - * - * Those tables are statically defined to avoid calculating randomizer state - * at runtime. - */ -static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = { - 0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64, - 0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409, - 0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617, - 0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d, - 0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91, - 0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d, - 0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab, - 0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8, - 0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8, - 0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b, - 0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5, - 0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a, - 0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891, - 0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36, - 0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd, - 0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0, -}; - -static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = { - 0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6, - 0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982, - 0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9, - 0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07, - 0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e, - 0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2, - 0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c, - 0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f, - 0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc, - 0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e, - 0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8, - 0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68, - 0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d, - 0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179, - 0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601, - 0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd, -}; - -static u16 sunxi_nfc_randomizer_step(u16 state, int count) -{ - state &= 0x7fff; - - /* - * This loop is just a simple implementation of a Fibonacci LFSR using - * the x16 + x15 + 1 polynomial. - */ - while (count--) - state = ((state >> 1) | - (((state ^ (state >> 1)) & 1) << 14)) & 0x7fff; - - return state; -} - -static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc) -{ - const u16 *seeds = sunxi_nfc_randomizer_page_seeds; - int mod = mtd->erasesize / mtd->writesize; - - if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds)) - mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds); - - if (ecc) { - if (mtd->ecc_step_size == 512) - seeds = sunxi_nfc_randomizer_ecc512_seeds; - else - seeds = sunxi_nfc_randomizer_ecc1024_seeds; - } - - return seeds[page % mod]; -} - -static void sunxi_nfc_randomizer_config(struct mtd_info *mtd, - int page, bool ecc) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); - u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); - u16 state; - - if (!(nand->options & NAND_NEED_SCRAMBLING)) - return; - - ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); - state = sunxi_nfc_randomizer_state(mtd, page, ecc); - ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK; - writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL); -} - -static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); - - if (!(nand->options & NAND_NEED_SCRAMBLING)) - return; - - writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN, - nfc->regs + NFC_REG_ECC_CTL); -} - -static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); - - if (!(nand->options & NAND_NEED_SCRAMBLING)) - return; - - writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN, - nfc->regs + NFC_REG_ECC_CTL); -} - -static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm) -{ - u16 state = sunxi_nfc_randomizer_state(mtd, page, true); - - bbm[0] ^= state; - bbm[1] ^= sunxi_nfc_randomizer_step(state, 8); -} - -static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd, - const uint8_t *buf, int len, - bool ecc, int page) -{ - sunxi_nfc_randomizer_config(mtd, page, ecc); - sunxi_nfc_randomizer_enable(mtd); - sunxi_nfc_write_buf(mtd, buf, len); - sunxi_nfc_randomizer_disable(mtd); -} - -static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf, - int len, bool ecc, int page) -{ - sunxi_nfc_randomizer_config(mtd, page, ecc); - sunxi_nfc_randomizer_enable(mtd); - sunxi_nfc_read_buf(mtd, buf, len); - sunxi_nfc_randomizer_disable(mtd); -} - -static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); - struct sunxi_nand_hw_ecc *data = nand->ecc.priv; - u32 ecc_ctl; - - ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); - ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE | - NFC_ECC_BLOCK_SIZE_MSK); - ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION; - - if (nand->ecc.size == 512) - ecc_ctl |= NFC_ECC_BLOCK_512; - - writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL); -} - -static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); - - writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, - nfc->regs + NFC_REG_ECC_CTL); -} - -static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf) -{ - buf[0] = user_data; - buf[1] = user_data >> 8; - buf[2] = user_data >> 16; - buf[3] = user_data >> 24; -} - -static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, - u8 *data, int data_off, - u8 *oob, int oob_off, - int *cur_off, - unsigned int *max_bitflips, - bool bbm, int page) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); - struct nand_ecc_ctrl *ecc = &nand->ecc; - int raw_mode = 0; - u32 status; - int ret; - - if (*cur_off != data_off) - nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); - - sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page); - - if (data_off + ecc->size != oob_off) - nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); - - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - return ret; - - sunxi_nfc_randomizer_enable(mtd); - writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, - nfc->regs + NFC_REG_CMD); - - ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); - sunxi_nfc_randomizer_disable(mtd); - if (ret) - return ret; - - *cur_off = oob_off + ecc->bytes + 4; - - status = readl(nfc->regs + NFC_REG_ECC_ST); - if (status & NFC_ECC_PAT_FOUND(0)) { - u8 pattern = 0xff; - - if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) - pattern = 0x0; - - memset(data, pattern, ecc->size); - memset(oob, pattern, ecc->bytes + 4); - - return 1; - } - - ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0))); - - memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); - - nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); - sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page); - - if (status & NFC_ECC_ERR(0)) { - /* - * Re-read the data with the randomizer disabled to identify - * bitflips in erased pages. - */ - if (nand->options & NAND_NEED_SCRAMBLING) { - nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); - nand->read_buf(mtd, data, ecc->size); - nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); - nand->read_buf(mtd, oob, ecc->bytes + 4); - } - - ret = nand_check_erased_ecc_chunk(data, ecc->size, - oob, ecc->bytes + 4, - NULL, 0, ecc->strength); - if (ret >= 0) - raw_mode = 1; - } else { - /* - * The engine protects 4 bytes of OOB data per chunk. - * Retrieve the corrected OOB bytes. - */ - sunxi_nfc_user_data_to_buf(readl(nfc->regs + - NFC_REG_USER_DATA(0)), - oob); - - /* De-randomize the Bad Block Marker. */ - if (bbm && nand->options & NAND_NEED_SCRAMBLING) - sunxi_nfc_randomize_bbm(mtd, page, oob); - } - - if (ret < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += ret; - *max_bitflips = max_t(unsigned int, *max_bitflips, ret); - } - - return raw_mode; -} - -static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd, - u8 *oob, int *cur_off, - bool randomize, int page) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct nand_ecc_ctrl *ecc = &nand->ecc; - int offset = ((ecc->bytes + 4) * ecc->steps); - int len = mtd->oobsize - offset; - - if (len <= 0) - return; - - if (*cur_off != offset) - nand->cmdfunc(mtd, NAND_CMD_RNDOUT, - offset + mtd->writesize, -1); - - if (!randomize) - sunxi_nfc_read_buf(mtd, oob + offset, len); - else - sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len, - false, page); - - *cur_off = mtd->oobsize + mtd->writesize; -} - -static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf) -{ - return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); -} - -static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, - const u8 *data, int data_off, - const u8 *oob, int oob_off, - int *cur_off, bool bbm, - int page) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); - struct nand_ecc_ctrl *ecc = &nand->ecc; - int ret; - - if (data_off != *cur_off) - nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1); - - sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page); - - /* Fill OOB data in */ - if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) { - u8 user_data[4]; - - memcpy(user_data, oob, 4); - sunxi_nfc_randomize_bbm(mtd, page, user_data); - writel(sunxi_nfc_buf_to_user_data(user_data), - nfc->regs + NFC_REG_USER_DATA(0)); - } else { - writel(sunxi_nfc_buf_to_user_data(oob), - nfc->regs + NFC_REG_USER_DATA(0)); - } - - if (data_off + ecc->size != oob_off) - nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1); - - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - return ret; - - sunxi_nfc_randomizer_enable(mtd); - writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | - NFC_ACCESS_DIR | NFC_ECC_OP, - nfc->regs + NFC_REG_CMD); - - ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); - sunxi_nfc_randomizer_disable(mtd); - if (ret) - return ret; - - *cur_off = oob_off + ecc->bytes + 4; - - return 0; -} - -static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd, - u8 *oob, int *cur_off, - int page) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - struct nand_ecc_ctrl *ecc = &nand->ecc; - int offset = ((ecc->bytes + 4) * ecc->steps); - int len = mtd->oobsize - offset; - - if (len <= 0) - return; - - if (*cur_off != offset) - nand->cmdfunc(mtd, NAND_CMD_RNDIN, - offset + mtd->writesize, -1); - - sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page); - - *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, - int oob_required, int page) -{ - struct nand_ecc_ctrl *ecc = &chip->ecc; - unsigned int max_bitflips = 0; - int ret, i, cur_off = 0; - bool raw_mode = false; - - sunxi_nfc_hw_ecc_enable(mtd); - - for (i = 0; i < ecc->steps; i++) { - int data_off = i * ecc->size; - int oob_off = i * (ecc->bytes + 4); - u8 *data = buf + data_off; - u8 *oob = chip->oob_poi + oob_off; - - ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, - oob_off + mtd->writesize, - &cur_off, &max_bitflips, - !i, page); - if (ret < 0) - return ret; - else if (ret) - raw_mode = true; - } - - if (oob_required) - sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, - !raw_mode, page); - - sunxi_nfc_hw_ecc_disable(mtd); - - return max_bitflips; -} - -static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, - struct nand_chip *chip, - uint32_t data_offs, uint32_t readlen, - uint8_t *bufpoi, int page) -{ - struct nand_ecc_ctrl *ecc = &chip->ecc; - int ret, i, cur_off = 0; - unsigned int max_bitflips = 0; - - sunxi_nfc_hw_ecc_enable(mtd); - - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - for (i = data_offs / ecc->size; - i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) { - int data_off = i * ecc->size; - int oob_off = i * (ecc->bytes + 4); - u8 *data = bufpoi + data_off; - u8 *oob = chip->oob_poi + oob_off; - - ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, - oob, oob_off + mtd->writesize, - &cur_off, &max_bitflips, !i, page); - if (ret < 0) - return ret; - } - - sunxi_nfc_hw_ecc_disable(mtd); - - return max_bitflips; -} - -static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) -{ - struct nand_ecc_ctrl *ecc = &chip->ecc; - int ret, i, cur_off = 0; - - sunxi_nfc_hw_ecc_enable(mtd); - - for (i = 0; i < ecc->steps; i++) { - int data_off = i * ecc->size; - int oob_off = i * (ecc->bytes + 4); - const u8 *data = buf + data_off; - const u8 *oob = chip->oob_poi + oob_off; - - ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, - oob_off + mtd->writesize, - &cur_off, !i, page); - if (ret) - return ret; - } - - if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) - sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, - &cur_off, page); - - sunxi_nfc_hw_ecc_disable(mtd); - - return 0; -} - -static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, - struct nand_chip *chip, - u32 data_offs, u32 data_len, - const u8 *buf, int oob_required, - int page) -{ - struct nand_ecc_ctrl *ecc = &chip->ecc; - int ret, i, cur_off = 0; - - sunxi_nfc_hw_ecc_enable(mtd); - - for (i = data_offs / ecc->size; - i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) { - int data_off = i * ecc->size; - int oob_off = i * (ecc->bytes + 4); - const u8 *data = buf + data_off; - const u8 *oob = chip->oob_poi + oob_off; - - ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, - oob_off + mtd->writesize, - &cur_off, !i, page); - if (ret) - return ret; - } - - sunxi_nfc_hw_ecc_disable(mtd); - - return 0; -} - -static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, int oob_required, - int page) -{ - struct nand_ecc_ctrl *ecc = &chip->ecc; - unsigned int max_bitflips = 0; - int ret, i, cur_off = 0; - bool raw_mode = false; - - sunxi_nfc_hw_ecc_enable(mtd); - - for (i = 0; i < ecc->steps; i++) { - int data_off = i * (ecc->size + ecc->bytes + 4); - int oob_off = data_off + ecc->size; - u8 *data = buf + (i * ecc->size); - u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); - - ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, - oob_off, &cur_off, - &max_bitflips, !i, page); - if (ret < 0) - return ret; - else if (ret) - raw_mode = true; - } - - if (oob_required) - sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off, - !raw_mode, page); - - sunxi_nfc_hw_ecc_disable(mtd); - - return max_bitflips; -} - -static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, - int oob_required, int page) -{ - struct nand_ecc_ctrl *ecc = &chip->ecc; - int ret, i, cur_off = 0; - - sunxi_nfc_hw_ecc_enable(mtd); - - for (i = 0; i < ecc->steps; i++) { - int data_off = i * (ecc->size + ecc->bytes + 4); - int oob_off = data_off + ecc->size; - const u8 *data = buf + (i * ecc->size); - const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); - - ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, - oob, oob_off, &cur_off, - false, page); - if (ret) - return ret; - } - - if (oob_required || (chip->options & NAND_NEED_SCRAMBLING)) - sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, - &cur_off, page); - - sunxi_nfc_hw_ecc_disable(mtd); - - return 0; -} - -static const s32 tWB_lut[] = {6, 12, 16, 20}; -static const s32 tRHW_lut[] = {4, 8, 12, 20}; - -static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, - u32 clk_period) -{ - u32 clk_cycles = DIV_ROUND_UP(duration, clk_period); - int i; - - for (i = 0; i < lut_size; i++) { - if (clk_cycles <= lut[i]) - return i; - } - - /* Doesn't fit */ - return -EINVAL; -} - -#define sunxi_nand_lookup_timing(l, p, c) \ - _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) - -static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, - const struct nand_sdr_timings *timings) -{ - u32 min_clk_period = 0; - s32 tWB, tADL, tWHR, tRHW, tCAD; - - /* T1 <=> tCLS */ - if (timings->tCLS_min > min_clk_period) - min_clk_period = timings->tCLS_min; - - /* T2 <=> tCLH */ - if (timings->tCLH_min > min_clk_period) - min_clk_period = timings->tCLH_min; - - /* T3 <=> tCS */ - if (timings->tCS_min > min_clk_period) - min_clk_period = timings->tCS_min; - - /* T4 <=> tCH */ - if (timings->tCH_min > min_clk_period) - min_clk_period = timings->tCH_min; - - /* T5 <=> tWP */ - if (timings->tWP_min > min_clk_period) - min_clk_period = timings->tWP_min; - - /* T6 <=> tWH */ - if (timings->tWH_min > min_clk_period) - min_clk_period = timings->tWH_min; - - /* T7 <=> tALS */ - if (timings->tALS_min > min_clk_period) - min_clk_period = timings->tALS_min; - - /* T8 <=> tDS */ - if (timings->tDS_min > min_clk_period) - min_clk_period = timings->tDS_min; - - /* T9 <=> tDH */ - if (timings->tDH_min > min_clk_period) - min_clk_period = timings->tDH_min; - - /* T10 <=> tRR */ - if (timings->tRR_min > (min_clk_period * 3)) - min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3); - - /* T11 <=> tALH */ - if (timings->tALH_min > min_clk_period) - min_clk_period = timings->tALH_min; - - /* T12 <=> tRP */ - if (timings->tRP_min > min_clk_period) - min_clk_period = timings->tRP_min; - - /* T13 <=> tREH */ - if (timings->tREH_min > min_clk_period) - min_clk_period = timings->tREH_min; - - /* T14 <=> tRC */ - if (timings->tRC_min > (min_clk_period * 2)) - min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2); - - /* T15 <=> tWC */ - if (timings->tWC_min > (min_clk_period * 2)) - min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); - - /* T16 - T19 + tCAD */ - tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max, - min_clk_period); - if (tWB < 0) { - dev_err(nfc->dev, "unsupported tWB\n"); - return tWB; - } - - tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3; - if (tADL > 3) { - dev_err(nfc->dev, "unsupported tADL\n"); - return -EINVAL; - } - - tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3; - if (tWHR > 3) { - dev_err(nfc->dev, "unsupported tWHR\n"); - return -EINVAL; - } - - tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min, - min_clk_period); - if (tRHW < 0) { - dev_err(nfc->dev, "unsupported tRHW\n"); - return tRHW; - } - - /* - * TODO: according to ONFI specs this value only applies for DDR NAND, - * but Allwinner seems to set this to 0x7. Mimic them for now. - */ - tCAD = 0x7; - - /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */ - chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); - - /* - * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data - * output cycle timings shall be used if the host drives tRC less than - * 30 ns. - */ - chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0; - - /* Convert min_clk_period from picoseconds to nanoseconds */ - min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); - - /* - * Convert min_clk_period into a clk frequency, then get the - * appropriate rate for the NAND controller IP given this formula - * (specified in the datasheet): - * nand clk_rate = min_clk_rate - */ - chip->clk_rate = 1000000000L / min_clk_period; - - return 0; -} - -static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(&chip->nand); - const struct nand_sdr_timings *timings; - int ret; - int mode; - - mode = onfi_get_async_timing_mode(&chip->nand); - if (mode == ONFI_TIMING_MODE_UNKNOWN) { - mode = chip->nand.onfi_timing_mode_default; - } else { - uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; - int i; - - mode = fls(mode) - 1; - if (mode < 0) - mode = 0; - - feature[0] = mode; - for (i = 0; i < chip->nsels; i++) { - chip->nand.select_chip(mtd, i); - ret = chip->nand.onfi_set_features(mtd, - &chip->nand, - ONFI_FEATURE_ADDR_TIMING_MODE, - feature); - chip->nand.select_chip(mtd, -1); - if (ret && ret != -ENOTSUPP) - return ret; - } - } - - timings = onfi_async_timing_mode_to_sdr_timings(mode); - if (IS_ERR(timings)) - return PTR_ERR(timings); - - return sunxi_nand_chip_set_timings(chip, timings); -} - -static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, - struct nand_ecc_ctrl *ecc) -{ - static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; - struct sunxi_nand_hw_ecc *data; - struct nand_ecclayout *layout; - int nsectors; - int ret; - int i; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - if (ecc->size != 512 && ecc->size != 1024) - return -EINVAL; - - /* Prefer 1k ECC chunk over 512 ones */ - if (ecc->size == 512 && mtd->writesize > 512) { - ecc->size = 1024; - ecc->strength *= 2; - } - - /* Add ECC info retrieval from DT */ - for (i = 0; i < ARRAY_SIZE(strengths); i++) { - if (ecc->strength <= strengths[i]) { - /* - * Update ecc->strength value with the actual strength - * that will be used by the ECC engine. - */ - ecc->strength = strengths[i]; - break; - } - } - - if (i >= ARRAY_SIZE(strengths)) { - dev_err(nfc->dev, "unsupported strength\n"); - ret = -ENOTSUPP; - goto err; - } - - data->mode = i; - - /* HW ECC always request ECC bytes for 1024 bytes blocks */ - ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8); - - /* HW ECC always work with even numbers of ECC bytes */ - ecc->bytes = ALIGN(ecc->bytes, 2); - - layout = &data->layout; - nsectors = mtd->writesize / ecc->size; - - if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) { - ret = -EINVAL; - goto err; - } - - layout->eccbytes = (ecc->bytes * nsectors); - - ecc->layout = layout; - ecc->priv = data; - - return 0; - -err: - kfree(data); - - return ret; -} - -#ifndef __UBOOT__ -static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc) -{ - kfree(ecc->priv); -} -#endif /* __UBOOT__ */ - -static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, - struct nand_ecc_ctrl *ecc) -{ - struct nand_ecclayout *layout; - int nsectors; - int i, j; - int ret; - - ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc); - if (ret) - return ret; - - ecc->read_page = sunxi_nfc_hw_ecc_read_page; - ecc->write_page = sunxi_nfc_hw_ecc_write_page; - ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage; - ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage; - layout = ecc->layout; - nsectors = mtd->writesize / ecc->size; - - for (i = 0; i < nsectors; i++) { - if (i) { - layout->oobfree[i].offset = - layout->oobfree[i - 1].offset + - layout->oobfree[i - 1].length + - ecc->bytes; - layout->oobfree[i].length = 4; - } else { - /* - * The first 2 bytes are used for BB markers, hence we - * only have 2 bytes available in the first user data - * section. - */ - layout->oobfree[i].length = 2; - layout->oobfree[i].offset = 2; - } - - for (j = 0; j < ecc->bytes; j++) - layout->eccpos[(ecc->bytes * i) + j] = - layout->oobfree[i].offset + - layout->oobfree[i].length + j; - } - - if (mtd->oobsize > (ecc->bytes + 4) * nsectors) { - layout->oobfree[nsectors].offset = - layout->oobfree[nsectors - 1].offset + - layout->oobfree[nsectors - 1].length + - ecc->bytes; - layout->oobfree[nsectors].length = mtd->oobsize - - ((ecc->bytes + 4) * nsectors); - } - - return 0; -} - -static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd, - struct nand_ecc_ctrl *ecc) -{ - struct nand_ecclayout *layout; - int nsectors; - int i; - int ret; - - ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc); - if (ret) - return ret; - - ecc->prepad = 4; - ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page; - ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page; - - layout = ecc->layout; - nsectors = mtd->writesize / ecc->size; - - for (i = 0; i < (ecc->bytes * nsectors); i++) - layout->eccpos[i] = i; - - layout->oobfree[0].length = mtd->oobsize - i; - layout->oobfree[0].offset = i; - - return 0; -} - -#ifndef __UBOOT__ -static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc) -{ - switch (ecc->mode) { - case NAND_ECC_HW: - case NAND_ECC_HW_SYNDROME: - sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc); - break; - case NAND_ECC_NONE: - kfree(ecc->layout); - default: - break; - } -} -#endif /* __UBOOT__ */ - -static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc) -{ - struct nand_chip *nand = mtd_to_nand(mtd); - int ret; - - if (!ecc->size) { - ecc->size = nand->ecc_step_ds; - ecc->strength = nand->ecc_strength_ds; - } - - if (!ecc->size || !ecc->strength) - return -EINVAL; - - switch (ecc->mode) { - case NAND_ECC_SOFT_BCH: - break; - case NAND_ECC_HW: - ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc); - if (ret) - return ret; - break; - case NAND_ECC_HW_SYNDROME: - ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc); - if (ret) - return ret; - break; - case NAND_ECC_NONE: - ecc->layout = kzalloc(sizeof(*ecc->layout), GFP_KERNEL); - if (!ecc->layout) - return -ENOMEM; - ecc->layout->oobfree[0].length = mtd->oobsize; - case NAND_ECC_SOFT: - break; - default: - return -EINVAL; - } - - return 0; -} - -static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum) -{ - const struct nand_sdr_timings *timings; - const void *blob = gd->fdt_blob; - struct sunxi_nand_chip *chip; - struct mtd_info *mtd; - struct nand_chip *nand; - int nsels; - int ret; - int i; - u32 cs[8], rb[8]; - - if (!fdt_getprop(blob, node, "reg", &nsels)) - return -EINVAL; - - nsels /= sizeof(u32); - if (!nsels || nsels > 8) { - dev_err(dev, "invalid reg property size\n"); - return -EINVAL; - } - - chip = kzalloc(sizeof(*chip) + - (nsels * sizeof(struct sunxi_nand_chip_sel)), - GFP_KERNEL); - if (!chip) { - dev_err(dev, "could not allocate chip\n"); - return -ENOMEM; - } - - chip->nsels = nsels; - chip->selected = -1; - - for (i = 0; i < nsels; i++) { - cs[i] = -1; - rb[i] = -1; - } - - ret = fdtdec_get_int_array(gd->fdt_blob, node, "reg", cs, nsels); - if (ret) { - dev_err(dev, "could not retrieve reg property: %d\n", ret); - return ret; - } - - ret = fdtdec_get_int_array(gd->fdt_blob, node, "allwinner,rb", rb, - nsels); - if (ret) { - dev_err(dev, "could not retrieve reg property: %d\n", ret); - return ret; - } - - for (i = 0; i < nsels; i++) { - int tmp = cs[i]; - - if (tmp > NFC_MAX_CS) { - dev_err(dev, - "invalid reg value: %u (max CS = 7)\n", - tmp); - return -EINVAL; - } - - if (test_and_set_bit(tmp, &nfc->assigned_cs)) { - dev_err(dev, "CS %d already assigned\n", tmp); - return -EINVAL; - } - - chip->sels[i].cs = tmp; - - tmp = rb[i]; - if (tmp >= 0 && tmp < 2) { - chip->sels[i].rb.type = RB_NATIVE; - chip->sels[i].rb.info.nativeid = tmp; - } else { - ret = gpio_request_by_name_nodev(offset_to_ofnode(node), - "rb-gpios", i, - &chip->sels[i].rb.info.gpio, - GPIOD_IS_IN); - if (ret) - chip->sels[i].rb.type = RB_GPIO; - else - chip->sels[i].rb.type = RB_NONE; - } - } - - timings = onfi_async_timing_mode_to_sdr_timings(0); - if (IS_ERR(timings)) { - ret = PTR_ERR(timings); - dev_err(dev, - "could not retrieve timings for ONFI mode 0: %d\n", - ret); - return ret; - } - - ret = sunxi_nand_chip_set_timings(chip, timings); - if (ret) { - dev_err(dev, "could not configure chip timings: %d\n", ret); - return ret; - } - - nand = &chip->nand; - /* Default tR value specified in the ONFI spec (chapter 4.15.1) */ - nand->chip_delay = 200; - nand->controller = &nfc->controller; - /* - * Set the ECC mode to the default value in case nothing is specified - * in the DT. - */ - nand->ecc.mode = NAND_ECC_HW; - nand->flash_node = node; - 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; - - mtd = nand_to_mtd(nand); - ret = nand_scan_ident(mtd, nsels, NULL); - if (ret) - return ret; - - if (nand->bbt_options & NAND_BBT_USE_FLASH) - nand->bbt_options |= NAND_BBT_NO_OOB; - - if (nand->options & NAND_NEED_SCRAMBLING) - nand->options |= NAND_NO_SUBPAGE_WRITE; - - nand->options |= NAND_SUBPAGE_READ; - - ret = sunxi_nand_chip_init_timings(chip); - if (ret) { - dev_err(dev, "could not configure chip timings: %d\n", ret); - return ret; - } - - ret = sunxi_nand_ecc_init(mtd, &nand->ecc); - if (ret) { - dev_err(dev, "ECC init failed: %d\n", ret); - return ret; - } - - ret = nand_scan_tail(mtd); - if (ret) { - dev_err(dev, "nand_scan_tail failed: %d\n", ret); - return ret; - } - - ret = nand_register(devnum, mtd); - if (ret) { - dev_err(dev, "failed to register mtd device: %d\n", ret); - return ret; - } - - list_add_tail(&chip->node, &nfc->chips); - - return 0; -} - -static int sunxi_nand_chips_init(int node, struct sunxi_nfc *nfc) -{ - const void *blob = gd->fdt_blob; - int nand_node; - int ret, i = 0; - - for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0; - nand_node = fdt_next_subnode(blob, nand_node)) - i++; - - if (i > 8) { - dev_err(dev, "too many NAND chips: %d (max = 8)\n", i); - return -EINVAL; - } - - i = 0; - for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0; - nand_node = fdt_next_subnode(blob, nand_node)) { - ret = sunxi_nand_chip_init(nand_node, nfc, i++); - if (ret) - return ret; - } - - return 0; -} - -#ifndef __UBOOT__ -static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc) -{ - struct sunxi_nand_chip *chip; - - while (!list_empty(&nfc->chips)) { - chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip, - node); - nand_release(&chip->mtd); - sunxi_nand_ecc_cleanup(&chip->nand.ecc); - list_del(&chip->node); - kfree(chip); - } -} -#endif /* __UBOOT__ */ - -void sunxi_nand_init(void) -{ - const void *blob = gd->fdt_blob; - struct sunxi_nfc *nfc; - fdt_addr_t regs; - int node; - int ret; - - nfc = kzalloc(sizeof(*nfc), GFP_KERNEL); - if (!nfc) - return; - - spin_lock_init(&nfc->controller.lock); - init_waitqueue_head(&nfc->controller.wq); - INIT_LIST_HEAD(&nfc->chips); - - node = fdtdec_next_compatible(blob, 0, COMPAT_SUNXI_NAND); - if (node < 0) { - pr_err("unable to find nfc node in device tree\n"); - goto err; - } - - if (!fdtdec_get_is_enabled(blob, node)) { - pr_err("nfc disabled in device tree\n"); - goto err; - } - - regs = fdtdec_get_addr(blob, node, "reg"); - if (regs == FDT_ADDR_T_NONE) { - pr_err("unable to find nfc address in device tree\n"); - goto err; - } - - nfc->regs = (void *)regs; - - ret = sunxi_nfc_rst(nfc); - if (ret) - goto err; - - ret = sunxi_nand_chips_init(node, nfc); - if (ret) { - dev_err(dev, "failed to init nand chips\n"); - goto err; - } - - return; - -err: - kfree(nfc); -} - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Boris BREZILLON"); -MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver"); diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c deleted file mode 100644 index 6cde9814c4..0000000000 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ /dev/null @@ -1,548 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2014-2015, Antmicro Ltd - * Copyright (c) 2015, AW-SOM Technologies - */ - -#include -#include -#include -#include -#include -#include - -/* registers */ -#define NFC_CTL 0x00000000 -#define NFC_ST 0x00000004 -#define NFC_INT 0x00000008 -#define NFC_TIMING_CTL 0x0000000C -#define NFC_TIMING_CFG 0x00000010 -#define NFC_ADDR_LOW 0x00000014 -#define NFC_ADDR_HIGH 0x00000018 -#define NFC_SECTOR_NUM 0x0000001C -#define NFC_CNT 0x00000020 -#define NFC_CMD 0x00000024 -#define NFC_RCMD_SET 0x00000028 -#define NFC_WCMD_SET 0x0000002C -#define NFC_IO_DATA 0x00000030 -#define NFC_ECC_CTL 0x00000034 -#define NFC_ECC_ST 0x00000038 -#define NFC_DEBUG 0x0000003C -#define NFC_ECC_CNT0 0x00000040 -#define NFC_ECC_CNT1 0x00000044 -#define NFC_ECC_CNT2 0x00000048 -#define NFC_ECC_CNT3 0x0000004C -#define NFC_USER_DATA_BASE 0x00000050 -#define NFC_EFNAND_STATUS 0x00000090 -#define NFC_SPARE_AREA 0x000000A0 -#define NFC_PATTERN_ID 0x000000A4 -#define NFC_RAM0_BASE 0x00000400 -#define NFC_RAM1_BASE 0x00000800 - -#define NFC_CTL_EN (1 << 0) -#define NFC_CTL_RESET (1 << 1) -#define NFC_CTL_RAM_METHOD (1 << 14) -#define NFC_CTL_PAGE_SIZE_MASK (0xf << 8) -#define NFC_CTL_PAGE_SIZE(a) ((fls(a) - 11) << 8) - - -#define NFC_ECC_EN (1 << 0) -#define NFC_ECC_PIPELINE (1 << 3) -#define NFC_ECC_EXCEPTION (1 << 4) -#define NFC_ECC_BLOCK_SIZE (1 << 5) -#define NFC_ECC_RANDOM_EN (1 << 9) -#define NFC_ECC_RANDOM_DIRECTION (1 << 10) - - -#define NFC_ADDR_NUM_OFFSET 16 -#define NFC_SEND_ADDR (1 << 19) -#define NFC_ACCESS_DIR (1 << 20) -#define NFC_DATA_TRANS (1 << 21) -#define NFC_SEND_CMD1 (1 << 22) -#define NFC_WAIT_FLAG (1 << 23) -#define NFC_SEND_CMD2 (1 << 24) -#define NFC_SEQ (1 << 25) -#define NFC_DATA_SWAP_METHOD (1 << 26) -#define NFC_ROW_AUTO_INC (1 << 27) -#define NFC_SEND_CMD3 (1 << 28) -#define NFC_SEND_CMD4 (1 << 29) -#define NFC_RAW_CMD (0 << 30) -#define NFC_ECC_CMD (1 << 30) -#define NFC_PAGE_CMD (2 << 30) - -#define NFC_ST_CMD_INT_FLAG (1 << 1) -#define NFC_ST_DMA_INT_FLAG (1 << 2) -#define NFC_ST_CMD_FIFO_STAT (1 << 3) - -#define NFC_READ_CMD_OFFSET 0 -#define NFC_RANDOM_READ_CMD0_OFFSET 8 -#define NFC_RANDOM_READ_CMD1_OFFSET 16 - -#define NFC_CMD_RNDOUTSTART 0xE0 -#define NFC_CMD_RNDOUT 0x05 -#define NFC_CMD_READSTART 0x30 - -struct nfc_config { - int page_size; - int ecc_strength; - int ecc_size; - int addr_cycles; - int nseeds; - bool randomize; - bool valid; -}; - -/* minimal "boot0" style NAND support for Allwinner A20 */ - -/* random seed used by linux */ -const uint16_t random_seed[128] = { - 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72, - 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436, - 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d, - 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130, - 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56, - 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55, - 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb, - 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17, - 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62, - 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064, - 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126, - 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e, - 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3, - 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b, - 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d, - 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db, -}; - -#define DEFAULT_TIMEOUT_US 100000 - -static int check_value_inner(int offset, int expected_bits, - int timeout_us, int negation) -{ - do { - int val = readl(offset) & expected_bits; - if (negation ? !val : val) - return 1; - udelay(1); - } while (--timeout_us); - - return 0; -} - -static inline int check_value(int offset, int expected_bits, - int timeout_us) -{ - return check_value_inner(offset, expected_bits, timeout_us, 0); -} - -static inline int check_value_negated(int offset, int unexpected_bits, - int timeout_us) -{ - return check_value_inner(offset, unexpected_bits, timeout_us, 1); -} - -static int nand_wait_cmd_fifo_empty(void) -{ - if (!check_value_negated(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_FIFO_STAT, - DEFAULT_TIMEOUT_US)) { - printf("nand: timeout waiting for empty cmd FIFO\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int nand_wait_int(void) -{ - if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, - DEFAULT_TIMEOUT_US)) { - printf("nand: timeout waiting for interruption\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int nand_exec_cmd(u32 cmd) -{ - int ret; - - ret = nand_wait_cmd_fifo_empty(); - if (ret) - return ret; - - writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); - writel(cmd, SUNXI_NFC_BASE + NFC_CMD); - - return nand_wait_int(); -} - -void nand_init(void) -{ - uint32_t val; - - board_nand_init(); - - val = readl(SUNXI_NFC_BASE + NFC_CTL); - /* enable and reset CTL */ - writel(val | NFC_CTL_EN | NFC_CTL_RESET, - SUNXI_NFC_BASE + NFC_CTL); - - if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL, - NFC_CTL_RESET, DEFAULT_TIMEOUT_US)) { - printf("Couldn't initialize nand\n"); - } - - /* reset NAND */ - nand_exec_cmd(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET); -} - -static void nand_apply_config(const struct nfc_config *conf) -{ - u32 val; - - nand_wait_cmd_fifo_empty(); - - val = readl(SUNXI_NFC_BASE + NFC_CTL); - val &= ~NFC_CTL_PAGE_SIZE_MASK; - writel(val | NFC_CTL_RAM_METHOD | NFC_CTL_PAGE_SIZE(conf->page_size), - SUNXI_NFC_BASE + NFC_CTL); - writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT); - writel(conf->page_size, SUNXI_NFC_BASE + NFC_SPARE_AREA); -} - -static int nand_load_page(const struct nfc_config *conf, u32 offs) -{ - int page = offs / conf->page_size; - - writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | - (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | - (NFC_CMD_READSTART << NFC_READ_CMD_OFFSET), - SUNXI_NFC_BASE + NFC_RCMD_SET); - writel(((page & 0xFFFF) << 16), SUNXI_NFC_BASE + NFC_ADDR_LOW); - writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH); - - return nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | - NFC_SEND_ADDR | NFC_WAIT_FLAG | - ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET)); -} - -static int nand_change_column(u16 column) -{ - int ret; - - writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | - (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | - (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET), - SUNXI_NFC_BASE + NFC_RCMD_SET); - writel(column, SUNXI_NFC_BASE + NFC_ADDR_LOW); - - ret = nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | - (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | - NFC_CMD_RNDOUT); - if (ret) - return ret; - - /* Ensure tCCS has passed before reading data */ - udelay(1); - - return 0; -} - -static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116}; - -static int nand_read_page(const struct nfc_config *conf, u32 offs, - void *dest, int len) -{ - int nsectors = len / conf->ecc_size; - u16 rand_seed = 0; - int oob_chunk_sz = ecc_bytes[conf->ecc_strength]; - int page = offs / conf->page_size; - u32 ecc_st; - int i; - - if (offs % conf->page_size || len % conf->ecc_size || - len > conf->page_size || len < 0) - return -EINVAL; - - /* Choose correct seed if randomized */ - if (conf->randomize) - rand_seed = random_seed[page % conf->nseeds]; - - /* Retrieve data from SRAM (PIO) */ - for (i = 0; i < nsectors; i++) { - int data_off = i * conf->ecc_size; - int oob_off = conf->page_size + (i * oob_chunk_sz); - u8 *data = dest + data_off; - - /* Clear ECC status and restart ECC engine */ - writel(0, SUNXI_NFC_BASE + NFC_ECC_ST); - writel((rand_seed << 16) | (conf->ecc_strength << 12) | - (conf->randomize ? NFC_ECC_RANDOM_EN : 0) | - (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) | - NFC_ECC_EN | NFC_ECC_EXCEPTION, - SUNXI_NFC_BASE + NFC_ECC_CTL); - - /* Move the data in SRAM */ - nand_change_column(data_off); - writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT); - nand_exec_cmd(NFC_DATA_TRANS); - - /* - * Let the ECC engine consume the ECC bytes and possibly correct - * the data. - */ - nand_change_column(oob_off); - nand_exec_cmd(NFC_DATA_TRANS | NFC_ECC_CMD); - - /* Get the ECC status */ - ecc_st = readl(SUNXI_NFC_BASE + NFC_ECC_ST); - - /* ECC error detected. */ - if (ecc_st & 0xffff) - return -EIO; - - /* - * Return 1 if the first chunk is empty (needed for - * configuration detection). - */ - if (!i && (ecc_st & 0x10000)) - return 1; - - /* Retrieve the data from SRAM */ - memcpy_fromio(data, SUNXI_NFC_BASE + NFC_RAM0_BASE, - conf->ecc_size); - - /* Stop the ECC engine */ - writel(readl(SUNXI_NFC_BASE + NFC_ECC_CTL) & ~NFC_ECC_EN, - SUNXI_NFC_BASE + NFC_ECC_CTL); - - if (data_off + conf->ecc_size >= len) - break; - } - - return 0; -} - -static int nand_max_ecc_strength(struct nfc_config *conf) -{ - int max_oobsize, max_ecc_bytes; - int nsectors = conf->page_size / conf->ecc_size; - int i; - - /* - * ECC strength is limited by the size of the OOB area which is - * correlated with the page size. - */ - switch (conf->page_size) { - case 2048: - max_oobsize = 64; - break; - case 4096: - max_oobsize = 256; - break; - case 8192: - max_oobsize = 640; - break; - case 16384: - max_oobsize = 1664; - break; - default: - return -EINVAL; - } - - max_ecc_bytes = max_oobsize / nsectors; - - for (i = 0; i < ARRAY_SIZE(ecc_bytes); i++) { - if (ecc_bytes[i] > max_ecc_bytes) - break; - } - - if (!i) - return -EINVAL; - - return i - 1; -} - -static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs, - void *dest) -{ - /* NAND with pages > 4k will likely require 1k sector size. */ - int min_ecc_size = conf->page_size > 4096 ? 1024 : 512; - int page = offs / conf->page_size; - int ret; - - /* - * In most cases, 1k sectors are preferred over 512b ones, start - * testing this config first. - */ - for (conf->ecc_size = 1024; conf->ecc_size >= min_ecc_size; - conf->ecc_size >>= 1) { - int max_ecc_strength = nand_max_ecc_strength(conf); - - nand_apply_config(conf); - - /* - * We are starting from the maximum ECC strength because - * most of the time NAND vendors provide an OOB area that - * barely meets the ECC requirements. - */ - for (conf->ecc_strength = max_ecc_strength; - conf->ecc_strength >= 0; - conf->ecc_strength--) { - conf->randomize = false; - if (nand_change_column(0)) - return -EIO; - - /* - * Only read the first sector to speedup detection. - */ - ret = nand_read_page(conf, offs, dest, conf->ecc_size); - if (!ret) { - return 0; - } else if (ret > 0) { - /* - * If page is empty we can't deduce anything - * about the ECC config => stop the detection. - */ - return -EINVAL; - } - - conf->randomize = true; - conf->nseeds = ARRAY_SIZE(random_seed); - do { - if (nand_change_column(0)) - return -EIO; - - if (!nand_read_page(conf, offs, dest, - conf->ecc_size)) - return 0; - - /* - * Find the next ->nseeds value that would - * change the randomizer seed for the page - * we're trying to read. - */ - while (conf->nseeds >= 16) { - int seed = page % conf->nseeds; - - conf->nseeds >>= 1; - if (seed != page % conf->nseeds) - break; - } - } while (conf->nseeds >= 16); - } - } - - return -EINVAL; -} - -static int nand_detect_config(struct nfc_config *conf, u32 offs, void *dest) -{ - if (conf->valid) - return 0; - - /* - * Modern NANDs are more likely than legacy ones, so we start testing - * with 5 address cycles. - */ - for (conf->addr_cycles = 5; - conf->addr_cycles >= 4; - conf->addr_cycles--) { - int max_page_size = conf->addr_cycles == 4 ? 2048 : 16384; - - /* - * Ignoring 1k pages cause I'm not even sure this case exist - * in the real world. - */ - for (conf->page_size = 2048; conf->page_size <= max_page_size; - conf->page_size <<= 1) { - if (nand_load_page(conf, offs)) - return -1; - - if (!nand_detect_ecc_config(conf, offs, dest)) { - conf->valid = true; - return 0; - } - } - } - - return -EINVAL; -} - -static int nand_read_buffer(struct nfc_config *conf, uint32_t offs, - unsigned int size, void *dest) -{ - int first_seed = 0, page, ret; - - size = ALIGN(size, conf->page_size); - page = offs / conf->page_size; - if (conf->randomize) - first_seed = page % conf->nseeds; - - for (; size; size -= conf->page_size) { - if (nand_load_page(conf, offs)) - return -1; - - ret = nand_read_page(conf, offs, dest, conf->page_size); - /* - * The ->nseeds value should be equal to the number of pages - * in an eraseblock. Since we don't know this information in - * advance we might have picked a wrong value. - */ - if (ret < 0 && conf->randomize) { - int cur_seed = page % conf->nseeds; - - /* - * We already tried all the seed values => we are - * facing a real corruption. - */ - if (cur_seed < first_seed) - return -EIO; - - /* Try to adjust ->nseeds and read the page again... */ - conf->nseeds = cur_seed; - - if (nand_change_column(0)) - return -EIO; - - /* ... it still fails => it's a real corruption. */ - if (nand_read_page(conf, offs, dest, conf->page_size)) - return -EIO; - } else if (ret && conf->randomize) { - memset(dest, 0xff, conf->page_size); - } - - page++; - offs += conf->page_size; - dest += conf->page_size; - } - - return 0; -} - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) -{ - static struct nfc_config conf = { }; - int ret; - - ret = nand_detect_config(&conf, offs, dest); - if (ret) - return ret; - - return nand_read_buffer(&conf, offs, size, dest); -} - -void nand_deselect(void) -{ - struct sunxi_ccm_reg *const ccm = - (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - - clrbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0)); -#ifdef CONFIG_MACH_SUN9I - clrbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); -#else - clrbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); -#endif - clrbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1); -} diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c deleted file mode 100644 index 74acdfb308..0000000000 --- a/drivers/mtd/nand/tegra_nand.c +++ /dev/null @@ -1,1002 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2011 The Chromium OS Authors. - * (C) Copyright 2011 NVIDIA Corporation - * (C) Copyright 2006 Detlev Zundel, dzu@denx.de - * (C) Copyright 2006 DENX Software Engineering - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tegra_nand.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define NAND_CMD_TIMEOUT_MS 10 - -#define SKIPPED_SPARE_BYTES 4 - -/* ECC bytes to be generated for tag data */ -#define TAG_ECC_BYTES 4 - -static const struct udevice_id tegra_nand_dt_ids[] = { - { - .compatible = "nvidia,tegra20-nand", - }, - { /* sentinel */ } -}; - -/* 64 byte oob block info for large page (== 2KB) device - * - * OOB flash layout for Tegra with Reed-Solomon 4 symbol correct ECC: - * Skipped bytes(4) - * Main area Ecc(36) - * Tag data(20) - * Tag data Ecc(4) - * - * Yaffs2 will use 16 tag bytes. - */ -static struct nand_ecclayout eccoob = { - .eccbytes = 36, - .eccpos = { - 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, - }, - .oobavail = 20, - .oobfree = { - { - .offset = 40, - .length = 20, - }, - } -}; - -enum { - ECC_OK, - ECC_TAG_ERROR = 1 << 0, - ECC_DATA_ERROR = 1 << 1 -}; - -/* Timing parameters */ -enum { - FDT_NAND_MAX_TRP_TREA, - FDT_NAND_TWB, - FDT_NAND_MAX_TCR_TAR_TRR, - FDT_NAND_TWHR, - FDT_NAND_MAX_TCS_TCH_TALS_TALH, - FDT_NAND_TWH, - FDT_NAND_TWP, - FDT_NAND_TRH, - FDT_NAND_TADL, - - FDT_NAND_TIMING_COUNT -}; - -/* Information about an attached NAND chip */ -struct fdt_nand { - struct nand_ctlr *reg; - int enabled; /* 1 to enable, 0 to disable */ - struct gpio_desc wp_gpio; /* write-protect GPIO */ - s32 width; /* bit width, normally 8 */ - u32 timing[FDT_NAND_TIMING_COUNT]; -}; - -struct nand_drv { - struct nand_ctlr *reg; - struct fdt_nand config; -}; - -struct tegra_nand_info { - struct udevice *dev; - struct nand_drv nand_ctrl; - struct nand_chip nand_chip; -}; - -/** - * Wait for command completion - * - * @param reg nand_ctlr structure - * @return - * 1 - Command completed - * 0 - Timeout - */ -static int nand_waitfor_cmd_completion(struct nand_ctlr *reg) -{ - u32 reg_val; - int running; - int i; - - for (i = 0; i < NAND_CMD_TIMEOUT_MS * 1000; i++) { - if ((readl(®->command) & CMD_GO) || - !(readl(®->status) & STATUS_RBSY0) || - !(readl(®->isr) & ISR_IS_CMD_DONE)) { - udelay(1); - continue; - } - reg_val = readl(®->dma_mst_ctrl); - /* - * If DMA_MST_CTRL_EN_A_ENABLE or DMA_MST_CTRL_EN_B_ENABLE - * is set, that means DMA engine is running. - * - * Then we have to wait until DMA_MST_CTRL_IS_DMA_DONE - * is cleared, indicating DMA transfer completion. - */ - running = reg_val & (DMA_MST_CTRL_EN_A_ENABLE | - DMA_MST_CTRL_EN_B_ENABLE); - if (!running || (reg_val & DMA_MST_CTRL_IS_DMA_DONE)) - return 1; - udelay(1); - } - return 0; -} - -/** - * Read one byte from the chip - * - * @param mtd MTD device structure - * @return data byte - * - * Read function for 8bit bus-width - */ -static uint8_t read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_drv *info; - - info = (struct nand_drv *)nand_get_controller_data(chip); - - writel(CMD_GO | CMD_PIO | CMD_RX | CMD_CE0 | CMD_A_VALID, - &info->reg->command); - if (!nand_waitfor_cmd_completion(info->reg)) - printf("Command timeout\n"); - - return (uint8_t)readl(&info->reg->resp); -} - -/** - * Read len bytes from the chip into a buffer - * - * @param mtd MTD device structure - * @param buf buffer to store data to - * @param len number of bytes to read - * - * Read function for 8bit bus-width - */ -static void read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i, s; - unsigned int reg; - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_drv *info = (struct nand_drv *)nand_get_controller_data(chip); - - for (i = 0; i < len; i += 4) { - s = (len - i) > 4 ? 4 : len - i; - writel(CMD_PIO | CMD_RX | CMD_A_VALID | CMD_CE0 | - ((s - 1) << CMD_TRANS_SIZE_SHIFT) | CMD_GO, - &info->reg->command); - if (!nand_waitfor_cmd_completion(info->reg)) - puts("Command timeout during read_buf\n"); - reg = readl(&info->reg->resp); - memcpy(buf + i, ®, s); - } -} - -/** - * Check NAND status to see if it is ready or not - * - * @param mtd MTD device structure - * @return - * 1 - ready - * 0 - not ready - */ -static int nand_dev_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int reg_val; - struct nand_drv *info; - - info = (struct nand_drv *)nand_get_controller_data(chip); - - reg_val = readl(&info->reg->status); - if (reg_val & STATUS_RBSY0) - return 1; - else - return 0; -} - -/* Dummy implementation: we don't support multiple chips */ -static void nand_select_chip(struct mtd_info *mtd, int chipnr) -{ - switch (chipnr) { - case -1: - case 0: - break; - - default: - BUG(); - } -} - -/** - * Clear all interrupt status bits - * - * @param reg nand_ctlr structure - */ -static void nand_clear_interrupt_status(struct nand_ctlr *reg) -{ - u32 reg_val; - - /* Clear interrupt status */ - reg_val = readl(®->isr); - writel(reg_val, ®->isr); -} - -/** - * Send command to NAND device - * - * @param mtd MTD device structure - * @param command the command to be sent - * @param column the column address for this command, -1 if none - * @param page_addr the page address for this command, -1 if none - */ -static void nand_command(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_drv *info; - - info = (struct nand_drv *)nand_get_controller_data(chip); - - /* - * Write out the command to the device. - * - * Only command NAND_CMD_RESET or NAND_CMD_READID will come - * here before mtd->writesize is initialized. - */ - - /* Emulate NAND_CMD_READOOB */ - if (command == NAND_CMD_READOOB) { - assert(mtd->writesize != 0); - column += mtd->writesize; - command = NAND_CMD_READ0; - } - - /* Adjust columns for 16 bit bus-width */ - if (column != -1 && (chip->options & NAND_BUSWIDTH_16)) - column >>= 1; - - nand_clear_interrupt_status(info->reg); - - /* Stop DMA engine, clear DMA completion status */ - writel(DMA_MST_CTRL_EN_A_DISABLE - | DMA_MST_CTRL_EN_B_DISABLE - | DMA_MST_CTRL_IS_DMA_DONE, - &info->reg->dma_mst_ctrl); - - /* - * Program and erase have their own busy handlers - * status and sequential in needs no delay - */ - switch (command) { - case NAND_CMD_READID: - writel(NAND_CMD_READID, &info->reg->cmd_reg1); - writel(column & 0xFF, &info->reg->addr_reg1); - writel(CMD_GO | CMD_CLE | CMD_ALE | CMD_CE0, - &info->reg->command); - break; - case NAND_CMD_PARAM: - writel(NAND_CMD_PARAM, &info->reg->cmd_reg1); - writel(column & 0xFF, &info->reg->addr_reg1); - writel(CMD_GO | CMD_CLE | CMD_ALE | CMD_CE0, - &info->reg->command); - break; - case NAND_CMD_READ0: - writel(NAND_CMD_READ0, &info->reg->cmd_reg1); - writel(NAND_CMD_READSTART, &info->reg->cmd_reg2); - writel((page_addr << 16) | (column & 0xFFFF), - &info->reg->addr_reg1); - writel(page_addr >> 16, &info->reg->addr_reg2); - return; - case NAND_CMD_SEQIN: - writel(NAND_CMD_SEQIN, &info->reg->cmd_reg1); - writel(NAND_CMD_PAGEPROG, &info->reg->cmd_reg2); - writel((page_addr << 16) | (column & 0xFFFF), - &info->reg->addr_reg1); - writel(page_addr >> 16, - &info->reg->addr_reg2); - return; - case NAND_CMD_PAGEPROG: - return; - case NAND_CMD_ERASE1: - writel(NAND_CMD_ERASE1, &info->reg->cmd_reg1); - writel(NAND_CMD_ERASE2, &info->reg->cmd_reg2); - writel(page_addr, &info->reg->addr_reg1); - writel(CMD_GO | CMD_CLE | CMD_ALE | - CMD_SEC_CMD | CMD_CE0 | CMD_ALE_BYTES3, - &info->reg->command); - break; - case NAND_CMD_ERASE2: - return; - case NAND_CMD_STATUS: - writel(NAND_CMD_STATUS, &info->reg->cmd_reg1); - writel(CMD_GO | CMD_CLE | CMD_PIO | CMD_RX - | ((1 - 0) << CMD_TRANS_SIZE_SHIFT) - | CMD_CE0, - &info->reg->command); - break; - case NAND_CMD_RESET: - writel(NAND_CMD_RESET, &info->reg->cmd_reg1); - writel(CMD_GO | CMD_CLE | CMD_CE0, - &info->reg->command); - break; - case NAND_CMD_RNDOUT: - default: - printf("%s: Unsupported command %d\n", __func__, command); - return; - } - if (!nand_waitfor_cmd_completion(info->reg)) - printf("Command 0x%02X timeout\n", command); -} - -/** - * Check whether the pointed buffer are all 0xff (blank). - * - * @param buf data buffer for blank check - * @param len length of the buffer in byte - * @return - * 1 - blank - * 0 - non-blank - */ -static int blank_check(u8 *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) - if (buf[i] != 0xFF) - return 0; - return 1; -} - -/** - * After a DMA transfer for read, we call this function to see whether there - * is any uncorrectable error on the pointed data buffer or oob buffer. - * - * @param reg nand_ctlr structure - * @param databuf data buffer - * @param a_len data buffer length - * @param oobbuf oob buffer - * @param b_len oob buffer length - * @return - * ECC_OK - no ECC error or correctable ECC error - * ECC_TAG_ERROR - uncorrectable tag ECC error - * ECC_DATA_ERROR - uncorrectable data ECC error - * ECC_DATA_ERROR + ECC_TAG_ERROR - uncorrectable data+tag ECC error - */ -static int check_ecc_error(struct nand_ctlr *reg, u8 *databuf, - int a_len, u8 *oobbuf, int b_len) -{ - int return_val = ECC_OK; - u32 reg_val; - - if (!(readl(®->isr) & ISR_IS_ECC_ERR)) - return ECC_OK; - - /* - * Area A is used for the data block (databuf). Area B is used for - * the spare block (oobbuf) - */ - reg_val = readl(®->dec_status); - if ((reg_val & DEC_STATUS_A_ECC_FAIL) && databuf) { - reg_val = readl(®->bch_dec_status_buf); - /* - * If uncorrectable error occurs on data area, then see whether - * they are all FF. If all are FF, it's a blank page. - * Not error. - */ - if ((reg_val & BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK) && - !blank_check(databuf, a_len)) - return_val |= ECC_DATA_ERROR; - } - - if ((reg_val & DEC_STATUS_B_ECC_FAIL) && oobbuf) { - reg_val = readl(®->bch_dec_status_buf); - /* - * If uncorrectable error occurs on tag area, then see whether - * they are all FF. If all are FF, it's a blank page. - * Not error. - */ - if ((reg_val & BCH_DEC_STATUS_FAIL_TAG_MASK) && - !blank_check(oobbuf, b_len)) - return_val |= ECC_TAG_ERROR; - } - - return return_val; -} - -/** - * Set GO bit to send command to device - * - * @param reg nand_ctlr structure - */ -static void start_command(struct nand_ctlr *reg) -{ - u32 reg_val; - - reg_val = readl(®->command); - reg_val |= CMD_GO; - writel(reg_val, ®->command); -} - -/** - * Clear command GO bit, DMA GO bit, and DMA completion status - * - * @param reg nand_ctlr structure - */ -static void stop_command(struct nand_ctlr *reg) -{ - /* Stop command */ - writel(0, ®->command); - - /* Stop DMA engine and clear DMA completion status */ - writel(DMA_MST_CTRL_GO_DISABLE - | DMA_MST_CTRL_IS_DMA_DONE, - ®->dma_mst_ctrl); -} - -/** - * Set up NAND bus width and page size - * - * @param info nand_info structure - * @param *reg_val address of reg_val - * @return 0 if ok, -1 on error - */ -static int set_bus_width_page_size(struct mtd_info *our_mtd, - struct fdt_nand *config, u32 *reg_val) -{ - if (config->width == 8) - *reg_val = CFG_BUS_WIDTH_8BIT; - else if (config->width == 16) - *reg_val = CFG_BUS_WIDTH_16BIT; - else { - debug("%s: Unsupported bus width %d\n", __func__, - config->width); - return -1; - } - - if (our_mtd->writesize == 512) - *reg_val |= CFG_PAGE_SIZE_512; - else if (our_mtd->writesize == 2048) - *reg_val |= CFG_PAGE_SIZE_2048; - else if (our_mtd->writesize == 4096) - *reg_val |= CFG_PAGE_SIZE_4096; - else { - debug("%s: Unsupported page size %d\n", __func__, - our_mtd->writesize); - return -1; - } - - return 0; -} - -/** - * Page read/write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf data buffer - * @param page page number - * @param with_ecc 1 to enable ECC, 0 to disable ECC - * @param is_writing 0 for read, 1 for write - * @return 0 when successfully completed - * -EIO when command timeout - */ -static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page, int with_ecc, int is_writing) -{ - u32 reg_val; - int tag_size; - struct nand_oobfree *free = chip->ecc.layout->oobfree; - /* 4*128=512 (byte) is the value that our HW can support. */ - ALLOC_CACHE_ALIGN_BUFFER(u32, tag_buf, 128); - char *tag_ptr; - struct nand_drv *info; - struct fdt_nand *config; - unsigned int bbflags; - struct bounce_buffer bbstate, bbstate_oob; - - if ((uintptr_t)buf & 0x03) { - printf("buf %p has to be 4-byte aligned\n", buf); - return -EINVAL; - } - - info = (struct nand_drv *)nand_get_controller_data(chip); - config = &info->config; - if (set_bus_width_page_size(mtd, config, ®_val)) - return -EINVAL; - - /* Need to be 4-byte aligned */ - tag_ptr = (char *)tag_buf; - - stop_command(info->reg); - - if (is_writing) - bbflags = GEN_BB_READ; - else - bbflags = GEN_BB_WRITE; - - bounce_buffer_start(&bbstate, (void *)buf, 1 << chip->page_shift, - bbflags); - writel((1 << chip->page_shift) - 1, &info->reg->dma_cfg_a); - writel(virt_to_phys(bbstate.bounce_buffer), &info->reg->data_block_ptr); - - /* Set ECC selection, configure ECC settings */ - if (with_ecc) { - if (is_writing) - memcpy(tag_ptr, chip->oob_poi + free->offset, - chip->ecc.layout->oobavail + TAG_ECC_BYTES); - tag_size = chip->ecc.layout->oobavail + TAG_ECC_BYTES; - reg_val |= (CFG_SKIP_SPARE_SEL_4 - | CFG_SKIP_SPARE_ENABLE - | CFG_HW_ECC_CORRECTION_ENABLE - | CFG_ECC_EN_TAG_DISABLE - | CFG_HW_ECC_SEL_RS - | CFG_HW_ECC_ENABLE - | CFG_TVAL4 - | (tag_size - 1)); - - if (!is_writing) - tag_size += SKIPPED_SPARE_BYTES; - bounce_buffer_start(&bbstate_oob, (void *)tag_ptr, tag_size, - bbflags); - } else { - tag_size = mtd->oobsize; - reg_val |= (CFG_SKIP_SPARE_DISABLE - | CFG_HW_ECC_CORRECTION_DISABLE - | CFG_ECC_EN_TAG_DISABLE - | CFG_HW_ECC_DISABLE - | (tag_size - 1)); - bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi, - tag_size, bbflags); - } - writel(reg_val, &info->reg->config); - writel(virt_to_phys(bbstate_oob.bounce_buffer), &info->reg->tag_ptr); - writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); - writel(tag_size - 1, &info->reg->dma_cfg_b); - - nand_clear_interrupt_status(info->reg); - - reg_val = CMD_CLE | CMD_ALE - | CMD_SEC_CMD - | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT) - | CMD_A_VALID - | CMD_B_VALID - | (CMD_TRANS_SIZE_PAGE << CMD_TRANS_SIZE_SHIFT) - | CMD_CE0; - if (!is_writing) - reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX); - else - reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX); - writel(reg_val, &info->reg->command); - - /* Setup DMA engine */ - reg_val = DMA_MST_CTRL_GO_ENABLE - | DMA_MST_CTRL_BURST_8WORDS - | DMA_MST_CTRL_EN_A_ENABLE - | DMA_MST_CTRL_EN_B_ENABLE; - - if (!is_writing) - reg_val |= DMA_MST_CTRL_DIR_READ; - else - reg_val |= DMA_MST_CTRL_DIR_WRITE; - - writel(reg_val, &info->reg->dma_mst_ctrl); - - start_command(info->reg); - - if (!nand_waitfor_cmd_completion(info->reg)) { - if (!is_writing) - printf("Read Page 0x%X timeout ", page); - else - printf("Write Page 0x%X timeout ", page); - if (with_ecc) - printf("with ECC"); - else - printf("without ECC"); - printf("\n"); - return -EIO; - } - - bounce_buffer_stop(&bbstate_oob); - bounce_buffer_stop(&bbstate); - - if (with_ecc && !is_writing) { - memcpy(chip->oob_poi, tag_ptr, - SKIPPED_SPARE_BYTES); - memcpy(chip->oob_poi + free->offset, - tag_ptr + SKIPPED_SPARE_BYTES, - chip->ecc.layout->oobavail); - reg_val = (u32)check_ecc_error(info->reg, (u8 *)buf, - 1 << chip->page_shift, - (u8 *)(tag_ptr + SKIPPED_SPARE_BYTES), - chip->ecc.layout->oobavail); - if (reg_val & ECC_TAG_ERROR) - printf("Read Page 0x%X tag ECC error\n", page); - if (reg_val & ECC_DATA_ERROR) - printf("Read Page 0x%X data ECC error\n", - page); - if (reg_val & (ECC_DATA_ERROR | ECC_TAG_ERROR)) - return -EIO; - } - return 0; -} - -/** - * Hardware ecc based page read function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf buffer to store read data - * @param page page number to read - * @return 0 when successfully completed - * -EIO when command timeout - */ -static int nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -{ - return nand_rw_page(mtd, chip, buf, page, 1, 0); -} - -/** - * Hardware ecc based page write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf data buffer - */ -static int nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required, - int page) -{ - nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1); - return 0; -} - - -/** - * Read raw page data without ecc - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf buffer to store read data - * @param page page number to read - * @return 0 when successfully completed - * -EINVAL when chip->oob_poi is not double-word aligned - * -EIO when command timeout - */ -static int nand_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -{ - return nand_rw_page(mtd, chip, buf, page, 0, 0); -} - -/** - * Raw page write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf data buffer - */ -static int nand_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, - int oob_required, int page) -{ - nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1); - return 0; -} - -/** - * OOB data read/write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param page page number to read - * @param with_ecc 1 to enable ECC, 0 to disable ECC - * @param is_writing 0 for read, 1 for write - * @return 0 when successfully completed - * -EINVAL when chip->oob_poi is not double-word aligned - * -EIO when command timeout - */ -static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page, int with_ecc, int is_writing) -{ - u32 reg_val; - int tag_size; - struct nand_oobfree *free = chip->ecc.layout->oobfree; - struct nand_drv *info; - unsigned int bbflags; - struct bounce_buffer bbstate_oob; - - if (((int)chip->oob_poi) & 0x03) - return -EINVAL; - info = (struct nand_drv *)nand_get_controller_data(chip); - if (set_bus_width_page_size(mtd, &info->config, ®_val)) - return -EINVAL; - - stop_command(info->reg); - - /* Set ECC selection */ - tag_size = mtd->oobsize; - if (with_ecc) - reg_val |= CFG_ECC_EN_TAG_ENABLE; - else - reg_val |= (CFG_ECC_EN_TAG_DISABLE); - - reg_val |= ((tag_size - 1) | - CFG_SKIP_SPARE_DISABLE | - CFG_HW_ECC_CORRECTION_DISABLE | - CFG_HW_ECC_DISABLE); - writel(reg_val, &info->reg->config); - - if (is_writing && with_ecc) - tag_size -= TAG_ECC_BYTES; - - if (is_writing) - bbflags = GEN_BB_READ; - else - bbflags = GEN_BB_WRITE; - - bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi, tag_size, - bbflags); - writel(virt_to_phys(bbstate_oob.bounce_buffer), &info->reg->tag_ptr); - - writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); - - writel(tag_size - 1, &info->reg->dma_cfg_b); - - nand_clear_interrupt_status(info->reg); - - reg_val = CMD_CLE | CMD_ALE - | CMD_SEC_CMD - | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT) - | CMD_B_VALID - | CMD_CE0; - if (!is_writing) - reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX); - else - reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX); - writel(reg_val, &info->reg->command); - - /* Setup DMA engine */ - reg_val = DMA_MST_CTRL_GO_ENABLE - | DMA_MST_CTRL_BURST_8WORDS - | DMA_MST_CTRL_EN_B_ENABLE; - if (!is_writing) - reg_val |= DMA_MST_CTRL_DIR_READ; - else - reg_val |= DMA_MST_CTRL_DIR_WRITE; - - writel(reg_val, &info->reg->dma_mst_ctrl); - - start_command(info->reg); - - if (!nand_waitfor_cmd_completion(info->reg)) { - if (!is_writing) - printf("Read OOB of Page 0x%X timeout\n", page); - else - printf("Write OOB of Page 0x%X timeout\n", page); - return -EIO; - } - - bounce_buffer_stop(&bbstate_oob); - - if (with_ecc && !is_writing) { - reg_val = (u32)check_ecc_error(info->reg, 0, 0, - (u8 *)(chip->oob_poi + free->offset), - chip->ecc.layout->oobavail); - if (reg_val & ECC_TAG_ERROR) - printf("Read OOB of Page 0x%X tag ECC error\n", page); - } - return 0; -} - -/** - * OOB data read function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param page page number to read - */ -static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - nand_rw_oob(mtd, chip, page, 0, 0); - return 0; -} - -/** - * OOB data write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param page page number to write - * @return 0 when successfully completed - * -EINVAL when chip->oob_poi is not double-word aligned - * -EIO when command timeout - */ -static int nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - - return nand_rw_oob(mtd, chip, page, 0, 1); -} - -/** - * Set up NAND memory timings according to the provided parameters - * - * @param timing Timing parameters - * @param reg NAND controller register address - */ -static void setup_timing(unsigned timing[FDT_NAND_TIMING_COUNT], - struct nand_ctlr *reg) -{ - u32 reg_val, clk_rate, clk_period, time_val; - - clk_rate = (u32)clock_get_periph_rate(PERIPH_ID_NDFLASH, - CLOCK_ID_PERIPH) / 1000000; - clk_period = 1000 / clk_rate; - reg_val = ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) << - TIMING_TRP_RESP_CNT_SHIFT) & TIMING_TRP_RESP_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TWB] / clk_period) << - TIMING_TWB_CNT_SHIFT) & TIMING_TWB_CNT_MASK; - time_val = timing[FDT_NAND_MAX_TCR_TAR_TRR] / clk_period; - if (time_val > 2) - reg_val |= ((time_val - 2) << TIMING_TCR_TAR_TRR_CNT_SHIFT) & - TIMING_TCR_TAR_TRR_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TWHR] / clk_period) << - TIMING_TWHR_CNT_SHIFT) & TIMING_TWHR_CNT_MASK; - time_val = timing[FDT_NAND_MAX_TCS_TCH_TALS_TALH] / clk_period; - if (time_val > 1) - reg_val |= ((time_val - 1) << TIMING_TCS_CNT_SHIFT) & - TIMING_TCS_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TWH] / clk_period) << - TIMING_TWH_CNT_SHIFT) & TIMING_TWH_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TWP] / clk_period) << - TIMING_TWP_CNT_SHIFT) & TIMING_TWP_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TRH] / clk_period) << - TIMING_TRH_CNT_SHIFT) & TIMING_TRH_CNT_MASK; - reg_val |= ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) << - TIMING_TRP_CNT_SHIFT) & TIMING_TRP_CNT_MASK; - writel(reg_val, ®->timing); - - reg_val = 0; - time_val = timing[FDT_NAND_TADL] / clk_period; - if (time_val > 2) - reg_val = (time_val - 2) & TIMING2_TADL_CNT_MASK; - writel(reg_val, ®->timing2); -} - -/** - * Decode NAND parameters from the device tree - * - * @param dev Driver model device - * @param config Device tree NAND configuration - * @return 0 if ok, -ve on error (FDT_ERR_...) - */ -static int fdt_decode_nand(struct udevice *dev, struct fdt_nand *config) -{ - int err; - - config->reg = (struct nand_ctlr *)dev_read_addr(dev); - config->enabled = dev_read_enabled(dev); - config->width = dev_read_u32_default(dev, "nvidia,nand-width", 8); - err = gpio_request_by_name(dev, "nvidia,wp-gpios", 0, &config->wp_gpio, - GPIOD_IS_OUT); - if (err) - return err; - err = dev_read_u32_array(dev, "nvidia,timing", config->timing, - FDT_NAND_TIMING_COUNT); - if (err < 0) - return err; - - return 0; -} - -static int tegra_probe(struct udevice *dev) -{ - struct tegra_nand_info *tegra = dev_get_priv(dev); - struct nand_chip *nand = &tegra->nand_chip; - struct nand_drv *info = &tegra->nand_ctrl; - struct fdt_nand *config = &info->config; - struct mtd_info *our_mtd; - int ret; - - if (fdt_decode_nand(dev, config)) { - printf("Could not decode nand-flash in device tree\n"); - return -1; - } - if (!config->enabled) - return -1; - info->reg = config->reg; - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.layout = &eccoob; - - nand->options = LP_OPTIONS; - nand->cmdfunc = nand_command; - nand->read_byte = read_byte; - nand->read_buf = read_buf; - nand->ecc.read_page = nand_read_page_hwecc; - nand->ecc.write_page = nand_write_page_hwecc; - nand->ecc.read_page_raw = nand_read_page_raw; - nand->ecc.write_page_raw = nand_write_page_raw; - nand->ecc.read_oob = nand_read_oob; - nand->ecc.write_oob = nand_write_oob; - nand->ecc.strength = 1; - nand->select_chip = nand_select_chip; - nand->dev_ready = nand_dev_ready; - nand_set_controller_data(nand, &tegra->nand_ctrl); - - /* Disable subpage writes as we do not provide ecc->hwctl */ - nand->options |= NAND_NO_SUBPAGE_WRITE; - - /* Adjust controller clock rate */ - clock_start_periph_pll(PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH, 52000000); - - /* Adjust timing for NAND device */ - setup_timing(config->timing, info->reg); - - dm_gpio_set_value(&config->wp_gpio, 1); - - our_mtd = nand_to_mtd(nand); - ret = nand_scan_ident(our_mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL); - if (ret) - return ret; - - nand->ecc.size = our_mtd->writesize; - nand->ecc.bytes = our_mtd->oobsize; - - ret = nand_scan_tail(our_mtd); - if (ret) - return ret; - - ret = nand_register(0, our_mtd); - if (ret) { - dev_err(dev, "Failed to register MTD: %d\n", ret); - return ret; - } - - return 0; -} - -U_BOOT_DRIVER(tegra_nand) = { - .name = "tegra-nand", - .id = UCLASS_MTD, - .of_match = tegra_nand_dt_ids, - .probe = tegra_probe, - .priv_auto_alloc_size = sizeof(struct tegra_nand_info), -}; - -void board_nand_init(void) -{ - struct udevice *dev; - int ret; - - ret = uclass_get_device_by_driver(UCLASS_MTD, - DM_GET_DRIVER(tegra_nand), &dev); - if (ret && ret != -ENODEV) - pr_err("Failed to initialize %s. (error %d)\n", dev->name, - ret); -} diff --git a/drivers/mtd/nand/tegra_nand.h b/drivers/mtd/nand/tegra_nand.h deleted file mode 100644 index 7740160661..0000000000 --- a/drivers/mtd/nand/tegra_nand.h +++ /dev/null @@ -1,240 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * (C) Copyright 2011 NVIDIA Corporation - */ - -/* register offset */ -#define COMMAND_0 0x00 -#define CMD_GO (1 << 31) -#define CMD_CLE (1 << 30) -#define CMD_ALE (1 << 29) -#define CMD_PIO (1 << 28) -#define CMD_TX (1 << 27) -#define CMD_RX (1 << 26) -#define CMD_SEC_CMD (1 << 25) -#define CMD_AFT_DAT_MASK (1 << 24) -#define CMD_AFT_DAT_DISABLE 0 -#define CMD_AFT_DAT_ENABLE (1 << 24) -#define CMD_TRANS_SIZE_SHIFT 20 -#define CMD_TRANS_SIZE_PAGE 8 -#define CMD_A_VALID (1 << 19) -#define CMD_B_VALID (1 << 18) -#define CMD_RD_STATUS_CHK (1 << 17) -#define CMD_R_BSY_CHK (1 << 16) -#define CMD_CE7 (1 << 15) -#define CMD_CE6 (1 << 14) -#define CMD_CE5 (1 << 13) -#define CMD_CE4 (1 << 12) -#define CMD_CE3 (1 << 11) -#define CMD_CE2 (1 << 10) -#define CMD_CE1 (1 << 9) -#define CMD_CE0 (1 << 8) -#define CMD_CLE_BYTE_SIZE_SHIFT 4 -enum { - CMD_CLE_BYTES1 = 0, - CMD_CLE_BYTES2, - CMD_CLE_BYTES3, - CMD_CLE_BYTES4, -}; -#define CMD_ALE_BYTE_SIZE_SHIFT 0 -enum { - CMD_ALE_BYTES1 = 0, - CMD_ALE_BYTES2, - CMD_ALE_BYTES3, - CMD_ALE_BYTES4, - CMD_ALE_BYTES5, - CMD_ALE_BYTES6, - CMD_ALE_BYTES7, - CMD_ALE_BYTES8 -}; - -#define STATUS_0 0x04 -#define STATUS_RBSY0 (1 << 8) - -#define ISR_0 0x08 -#define ISR_IS_CMD_DONE (1 << 5) -#define ISR_IS_ECC_ERR (1 << 4) - -#define IER_0 0x0C - -#define CFG_0 0x10 -#define CFG_HW_ECC_MASK (1 << 31) -#define CFG_HW_ECC_DISABLE 0 -#define CFG_HW_ECC_ENABLE (1 << 31) -#define CFG_HW_ECC_SEL_MASK (1 << 30) -#define CFG_HW_ECC_SEL_HAMMING 0 -#define CFG_HW_ECC_SEL_RS (1 << 30) -#define CFG_HW_ECC_CORRECTION_MASK (1 << 29) -#define CFG_HW_ECC_CORRECTION_DISABLE 0 -#define CFG_HW_ECC_CORRECTION_ENABLE (1 << 29) -#define CFG_PIPELINE_EN_MASK (1 << 28) -#define CFG_PIPELINE_EN_DISABLE 0 -#define CFG_PIPELINE_EN_ENABLE (1 << 28) -#define CFG_ECC_EN_TAG_MASK (1 << 27) -#define CFG_ECC_EN_TAG_DISABLE 0 -#define CFG_ECC_EN_TAG_ENABLE (1 << 27) -#define CFG_TVALUE_MASK (3 << 24) -enum { - CFG_TVAL4 = 0 << 24, - CFG_TVAL6 = 1 << 24, - CFG_TVAL8 = 2 << 24 -}; -#define CFG_SKIP_SPARE_MASK (1 << 23) -#define CFG_SKIP_SPARE_DISABLE 0 -#define CFG_SKIP_SPARE_ENABLE (1 << 23) -#define CFG_COM_BSY_MASK (1 << 22) -#define CFG_COM_BSY_DISABLE 0 -#define CFG_COM_BSY_ENABLE (1 << 22) -#define CFG_BUS_WIDTH_MASK (1 << 21) -#define CFG_BUS_WIDTH_8BIT 0 -#define CFG_BUS_WIDTH_16BIT (1 << 21) -#define CFG_LPDDR1_MODE_MASK (1 << 20) -#define CFG_LPDDR1_MODE_DISABLE 0 -#define CFG_LPDDR1_MODE_ENABLE (1 << 20) -#define CFG_EDO_MODE_MASK (1 << 19) -#define CFG_EDO_MODE_DISABLE 0 -#define CFG_EDO_MODE_ENABLE (1 << 19) -#define CFG_PAGE_SIZE_SEL_MASK (7 << 16) -enum { - CFG_PAGE_SIZE_256 = 0 << 16, - CFG_PAGE_SIZE_512 = 1 << 16, - CFG_PAGE_SIZE_1024 = 2 << 16, - CFG_PAGE_SIZE_2048 = 3 << 16, - CFG_PAGE_SIZE_4096 = 4 << 16 -}; -#define CFG_SKIP_SPARE_SEL_MASK (3 << 14) -enum { - CFG_SKIP_SPARE_SEL_4 = 0 << 14, - CFG_SKIP_SPARE_SEL_8 = 1 << 14, - CFG_SKIP_SPARE_SEL_12 = 2 << 14, - CFG_SKIP_SPARE_SEL_16 = 3 << 14 -}; -#define CFG_TAG_BYTE_SIZE_MASK 0x1FF - -#define TIMING_0 0x14 -#define TIMING_TRP_RESP_CNT_SHIFT 28 -#define TIMING_TRP_RESP_CNT_MASK (0xf << TIMING_TRP_RESP_CNT_SHIFT) -#define TIMING_TWB_CNT_SHIFT 24 -#define TIMING_TWB_CNT_MASK (0xf << TIMING_TWB_CNT_SHIFT) -#define TIMING_TCR_TAR_TRR_CNT_SHIFT 20 -#define TIMING_TCR_TAR_TRR_CNT_MASK (0xf << TIMING_TCR_TAR_TRR_CNT_SHIFT) -#define TIMING_TWHR_CNT_SHIFT 16 -#define TIMING_TWHR_CNT_MASK (0xf << TIMING_TWHR_CNT_SHIFT) -#define TIMING_TCS_CNT_SHIFT 14 -#define TIMING_TCS_CNT_MASK (3 << TIMING_TCS_CNT_SHIFT) -#define TIMING_TWH_CNT_SHIFT 12 -#define TIMING_TWH_CNT_MASK (3 << TIMING_TWH_CNT_SHIFT) -#define TIMING_TWP_CNT_SHIFT 8 -#define TIMING_TWP_CNT_MASK (0xf << TIMING_TWP_CNT_SHIFT) -#define TIMING_TRH_CNT_SHIFT 4 -#define TIMING_TRH_CNT_MASK (3 << TIMING_TRH_CNT_SHIFT) -#define TIMING_TRP_CNT_SHIFT 0 -#define TIMING_TRP_CNT_MASK (0xf << TIMING_TRP_CNT_SHIFT) - -#define RESP_0 0x18 - -#define TIMING2_0 0x1C -#define TIMING2_TADL_CNT_SHIFT 0 -#define TIMING2_TADL_CNT_MASK (0xf << TIMING2_TADL_CNT_SHIFT) - -#define CMD_REG1_0 0x20 -#define CMD_REG2_0 0x24 -#define ADDR_REG1_0 0x28 -#define ADDR_REG2_0 0x2C - -#define DMA_MST_CTRL_0 0x30 -#define DMA_MST_CTRL_GO_MASK (1 << 31) -#define DMA_MST_CTRL_GO_DISABLE 0 -#define DMA_MST_CTRL_GO_ENABLE (1 << 31) -#define DMA_MST_CTRL_DIR_MASK (1 << 30) -#define DMA_MST_CTRL_DIR_READ 0 -#define DMA_MST_CTRL_DIR_WRITE (1 << 30) -#define DMA_MST_CTRL_PERF_EN_MASK (1 << 29) -#define DMA_MST_CTRL_PERF_EN_DISABLE 0 -#define DMA_MST_CTRL_PERF_EN_ENABLE (1 << 29) -#define DMA_MST_CTRL_REUSE_BUFFER_MASK (1 << 27) -#define DMA_MST_CTRL_REUSE_BUFFER_DISABLE 0 -#define DMA_MST_CTRL_REUSE_BUFFER_ENABLE (1 << 27) -#define DMA_MST_CTRL_BURST_SIZE_SHIFT 24 -#define DMA_MST_CTRL_BURST_SIZE_MASK (7 << DMA_MST_CTRL_BURST_SIZE_SHIFT) -enum { - DMA_MST_CTRL_BURST_1WORDS = 2 << DMA_MST_CTRL_BURST_SIZE_SHIFT, - DMA_MST_CTRL_BURST_4WORDS = 3 << DMA_MST_CTRL_BURST_SIZE_SHIFT, - DMA_MST_CTRL_BURST_8WORDS = 4 << DMA_MST_CTRL_BURST_SIZE_SHIFT, - DMA_MST_CTRL_BURST_16WORDS = 5 << DMA_MST_CTRL_BURST_SIZE_SHIFT -}; -#define DMA_MST_CTRL_IS_DMA_DONE (1 << 20) -#define DMA_MST_CTRL_EN_A_MASK (1 << 2) -#define DMA_MST_CTRL_EN_A_DISABLE 0 -#define DMA_MST_CTRL_EN_A_ENABLE (1 << 2) -#define DMA_MST_CTRL_EN_B_MASK (1 << 1) -#define DMA_MST_CTRL_EN_B_DISABLE 0 -#define DMA_MST_CTRL_EN_B_ENABLE (1 << 1) - -#define DMA_CFG_A_0 0x34 -#define DMA_CFG_B_0 0x38 -#define FIFO_CTRL_0 0x3C -#define DATA_BLOCK_PTR_0 0x40 -#define TAG_PTR_0 0x44 -#define ECC_PTR_0 0x48 - -#define DEC_STATUS_0 0x4C -#define DEC_STATUS_A_ECC_FAIL (1 << 1) -#define DEC_STATUS_B_ECC_FAIL (1 << 0) - -#define BCH_CONFIG_0 0xCC -#define BCH_CONFIG_BCH_TVALUE_SHIFT 4 -#define BCH_CONFIG_BCH_TVALUE_MASK (3 << BCH_CONFIG_BCH_TVALUE_SHIFT) -enum { - BCH_CONFIG_BCH_TVAL4 = 0 << BCH_CONFIG_BCH_TVALUE_SHIFT, - BCH_CONFIG_BCH_TVAL8 = 1 << BCH_CONFIG_BCH_TVALUE_SHIFT, - BCH_CONFIG_BCH_TVAL14 = 2 << BCH_CONFIG_BCH_TVALUE_SHIFT, - BCH_CONFIG_BCH_TVAL16 = 3 << BCH_CONFIG_BCH_TVALUE_SHIFT -}; -#define BCH_CONFIG_BCH_ECC_MASK (1 << 0) -#define BCH_CONFIG_BCH_ECC_DISABLE 0 -#define BCH_CONFIG_BCH_ECC_ENABLE (1 << 0) - -#define BCH_DEC_RESULT_0 0xD0 -#define BCH_DEC_RESULT_CORRFAIL_ERR_MASK (1 << 8) -#define BCH_DEC_RESULT_PAGE_COUNT_MASK 0xFF - -#define BCH_DEC_STATUS_BUF_0 0xD4 -#define BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK 0xFF000000 -#define BCH_DEC_STATUS_CORR_SEC_FLAG_MASK 0x00FF0000 -#define BCH_DEC_STATUS_FAIL_TAG_MASK (1 << 14) -#define BCH_DEC_STATUS_CORR_TAG_MASK (1 << 13) -#define BCH_DEC_STATUS_MAX_CORR_CNT_MASK (0x1f << 8) -#define BCH_DEC_STATUS_PAGE_NUMBER_MASK 0xFF - -#define LP_OPTIONS 0 - -struct nand_ctlr { - u32 command; /* offset 00h */ - u32 status; /* offset 04h */ - u32 isr; /* offset 08h */ - u32 ier; /* offset 0Ch */ - u32 config; /* offset 10h */ - u32 timing; /* offset 14h */ - u32 resp; /* offset 18h */ - u32 timing2; /* offset 1Ch */ - u32 cmd_reg1; /* offset 20h */ - u32 cmd_reg2; /* offset 24h */ - u32 addr_reg1; /* offset 28h */ - u32 addr_reg2; /* offset 2Ch */ - u32 dma_mst_ctrl; /* offset 30h */ - u32 dma_cfg_a; /* offset 34h */ - u32 dma_cfg_b; /* offset 38h */ - u32 fifo_ctrl; /* offset 3Ch */ - u32 data_block_ptr; /* offset 40h */ - u32 tag_ptr; /* offset 44h */ - u32 resv1; /* offset 48h */ - u32 dec_status; /* offset 4Ch */ - u32 hwstatus_cmd; /* offset 50h */ - u32 hwstatus_mask; /* offset 54h */ - u32 resv2[29]; - u32 bch_config; /* offset CCh */ - u32 bch_dec_result; /* offset D0h */ - u32 bch_dec_status_buf; - /* offset D4h */ -}; diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c deleted file mode 100644 index 619d0403e9..0000000000 --- a/drivers/mtd/nand/vf610_nfc.c +++ /dev/null @@ -1,768 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2009-2015 Freescale Semiconductor, Inc. and others - * - * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver. - * Ported to U-Boot by Stefan Agner - * Based on RFC driver posted on Kernel Mailing list by Bill Pringlemeir - * Jason ported to M54418TWR and MVFA5. - * Authors: Stefan Agner - * Bill Pringlemeir - * Shaohui Xie - * Jason Jin - * - * Based on original driver mpc5121_nfc.c. - * - * 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 -#include - -#include -#include -#include - -#include -#include -#include - -/* 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] values. See section: - * - 31.4.7 Flash Command Code Description, Vybrid manual - * - 23.8.6 Flash Command Sequencer, MPC5125 manual - * - * Briefly these are bitmasks of controller cycles. - */ -#define READ_PAGE_CMD_CODE 0x7EE0 -#define READ_ONFI_PARAM_CMD_CODE 0x4860 -#define PROGRAM_PAGE_CMD_CODE 0x7FC0 -#define ERASE_CMD_CODE 0x4EC0 -#define READ_ID_CMD_CODE 0x4804 -#define RESET_CMD_CODE 0x4040 -#define STATUS_READ_CMD_CODE 0x4068 - -/* 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 (1<<0) - -/* NFC_COL_ADDR Field */ -#define COL_ADDR_MASK 0x0000FFFF -#define COL_ADDR_SHIFT 0 - -/* NFC_ROW_ADDR Field */ -#define ROW_ADDR_MASK 0x00FFFFFF -#define ROW_ADDR_SHIFT 0 -#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 (1<<21) -#define CONFIG_DMA_REQ_BIT (1<<20) -#define CONFIG_ECC_MODE_MASK 0x000E0000 -#define CONFIG_ECC_MODE_SHIFT 17 -#define CONFIG_FAST_FLASH_BIT (1<<16) -#define CONFIG_16BIT (1<<7) -#define CONFIG_BOOT_MODE_BIT (1<<6) -#define CONFIG_ADDR_AUTO_INCR_BIT (1<<5) -#define CONFIG_BUFNO_AUTO_INCR_BIT (1<<4) -#define CONFIG_PAGE_CNT_MASK 0xF -#define CONFIG_PAGE_CNT_SHIFT 0 - -/* NFC_IRQ_STATUS Field */ -#define IDLE_IRQ_BIT (1<<29) -#define IDLE_EN_BIT (1<<20) -#define CMD_DONE_CLEAR_BIT (1<<18) -#define IDLE_CLEAR_BIT (1<<17) - -#define NFC_TIMEOUT (1000) - -/* - * 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_alt_buf { - ALT_BUF_DATA = 0, - ALT_BUF_ID = 1, - ALT_BUF_STAT = 2, - ALT_BUF_ONFI = 3, -}; - -struct vf610_nfc { - struct nand_chip chip; - void __iomem *regs; - uint buf_offset; - int write_sz; - /* Status and ID are in alternate locations. */ - enum vf610_nfc_alt_buf alt_buf; -}; - -#define mtd_to_nfc(_mtd) nand_get_controller_data(mtd_to_nand(_mtd)) - -#if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES) -#define ECC_HW_MODE ECC_45_BYTE - -static struct nand_ecclayout vf610_nfc_ecc = { - .eccbytes = 45, - .eccpos = {19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63}, - .oobfree = { - {.offset = 2, - .length = 17} } -}; -#elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES) -#define ECC_HW_MODE ECC_60_BYTE - -static struct nand_ecclayout vf610_nfc_ecc = { - .eccbytes = 60, - .eccpos = { 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63 }, - .oobfree = { - {.offset = 2, - .length = 2} } -}; -#endif - -static inline u32 vf610_nfc_read(struct mtd_info *mtd, uint reg) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - - return readl(nfc->regs + reg); -} - -static inline void vf610_nfc_write(struct mtd_info *mtd, uint reg, u32 val) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - - writel(val, nfc->regs + reg); -} - -static inline void vf610_nfc_set(struct mtd_info *mtd, uint reg, u32 bits) -{ - vf610_nfc_write(mtd, reg, vf610_nfc_read(mtd, reg) | bits); -} - -static inline void vf610_nfc_clear(struct mtd_info *mtd, uint reg, u32 bits) -{ - vf610_nfc_write(mtd, reg, vf610_nfc_read(mtd, reg) & ~bits); -} - -static inline void vf610_nfc_set_field(struct mtd_info *mtd, u32 reg, - u32 mask, u32 shift, u32 val) -{ - vf610_nfc_write(mtd, reg, - (vf610_nfc_read(mtd, reg) & (~mask)) | val << shift); -} - -static inline void vf610_nfc_memcpy(void *dst, const void *src, size_t n) -{ - /* - * 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. - * - * For the time being, use memcpy - */ - memcpy(dst, src, n); -} - -/* Clear flags for upcoming command */ -static inline void vf610_nfc_clear_status(void __iomem *regbase) -{ - void __iomem *reg = regbase + NFC_IRQ_STATUS; - u32 tmp = __raw_readl(reg); - tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT; - __raw_writel(tmp, reg); -} - -/* Wait for complete operation */ -static void vf610_nfc_done(struct mtd_info *mtd) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - uint start; - - /* - * 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(mtd, NFC_FLASH_CMD2, START_BIT); - - start = get_timer(0); - - while (!(vf610_nfc_read(mtd, NFC_IRQ_STATUS) & IDLE_IRQ_BIT)) { - if (get_timer(start) > NFC_TIMEOUT) { - printf("Timeout while waiting for IDLE.\n"); - return; - } - } - vf610_nfc_clear_status(nfc->regs); -} - -static u8 vf610_nfc_get_id(struct mtd_info *mtd, int col) -{ - u32 flash_id; - - if (col < 4) { - flash_id = vf610_nfc_read(mtd, NFC_FLASH_STATUS1); - flash_id >>= (3 - col) * 8; - } else { - flash_id = vf610_nfc_read(mtd, NFC_FLASH_STATUS2); - flash_id >>= 24; - } - - return flash_id & 0xff; -} - -static u8 vf610_nfc_get_status(struct mtd_info *mtd) -{ - return vf610_nfc_read(mtd, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK; -} - -/* Single command */ -static void vf610_nfc_send_command(void __iomem *regbase, u32 cmd_byte1, - u32 cmd_code) -{ - void __iomem *reg = regbase + NFC_FLASH_CMD2; - u32 tmp; - vf610_nfc_clear_status(regbase); - - tmp = __raw_readl(reg); - tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK); - tmp |= cmd_byte1 << CMD_BYTE1_SHIFT; - tmp |= cmd_code << CMD_CODE_SHIFT; - __raw_writel(tmp, reg); -} - -/* Two commands */ -static void vf610_nfc_send_commands(void __iomem *regbase, u32 cmd_byte1, - u32 cmd_byte2, u32 cmd_code) -{ - void __iomem *reg = regbase + NFC_FLASH_CMD1; - u32 tmp; - vf610_nfc_send_command(regbase, cmd_byte1, cmd_code); - - tmp = __raw_readl(reg); - tmp &= ~CMD_BYTE2_MASK; - tmp |= cmd_byte2 << CMD_BYTE2_SHIFT; - __raw_writel(tmp, reg); -} - -static void vf610_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) -{ - if (column != -1) { - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - if (nfc->chip.options & NAND_BUSWIDTH_16) - column = column / 2; - vf610_nfc_set_field(mtd, NFC_COL_ADDR, COL_ADDR_MASK, - COL_ADDR_SHIFT, column); - } - if (page != -1) - vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK, - ROW_ADDR_SHIFT, page); -} - -static inline void vf610_nfc_ecc_mode(struct mtd_info *mtd, int ecc_mode) -{ - vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG, - CONFIG_ECC_MODE_MASK, - CONFIG_ECC_MODE_SHIFT, ecc_mode); -} - -static inline void vf610_nfc_transfer_size(void __iomem *regbase, int size) -{ - __raw_writel(size, regbase + NFC_SECTOR_SIZE); -} - -/* Send command to NAND chip */ -static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, - int column, int page) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0; - - nfc->buf_offset = max(column, 0); - nfc->alt_buf = ALT_BUF_DATA; - - switch (command) { - case NAND_CMD_SEQIN: - /* Use valid column/page from preread... */ - vf610_nfc_addr_cycle(mtd, column, page); - nfc->buf_offset = 0; - - /* - * SEQIN => data => PAGEPROG sequence is done by the controller - * hence we do not need to issue the command here... - */ - return; - case NAND_CMD_PAGEPROG: - trfr_sz += nfc->write_sz; - vf610_nfc_ecc_mode(mtd, ECC_HW_MODE); - vf610_nfc_transfer_size(nfc->regs, trfr_sz); - vf610_nfc_send_commands(nfc->regs, NAND_CMD_SEQIN, - command, PROGRAM_PAGE_CMD_CODE); - break; - - case NAND_CMD_RESET: - vf610_nfc_transfer_size(nfc->regs, 0); - vf610_nfc_send_command(nfc->regs, command, RESET_CMD_CODE); - break; - - case NAND_CMD_READOOB: - trfr_sz += mtd->oobsize; - column = mtd->writesize; - vf610_nfc_transfer_size(nfc->regs, trfr_sz); - vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0, - NAND_CMD_READSTART, READ_PAGE_CMD_CODE); - vf610_nfc_addr_cycle(mtd, column, page); - vf610_nfc_ecc_mode(mtd, ECC_BYPASS); - break; - - case NAND_CMD_READ0: - trfr_sz += mtd->writesize + mtd->oobsize; - vf610_nfc_transfer_size(nfc->regs, trfr_sz); - vf610_nfc_ecc_mode(mtd, ECC_HW_MODE); - vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0, - NAND_CMD_READSTART, READ_PAGE_CMD_CODE); - vf610_nfc_addr_cycle(mtd, column, page); - break; - - case NAND_CMD_PARAM: - nfc->alt_buf = ALT_BUF_ONFI; - trfr_sz = 3 * sizeof(struct nand_onfi_params); - vf610_nfc_transfer_size(nfc->regs, trfr_sz); - vf610_nfc_send_command(nfc->regs, NAND_CMD_PARAM, - READ_ONFI_PARAM_CMD_CODE); - vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK, - ROW_ADDR_SHIFT, column); - vf610_nfc_ecc_mode(mtd, ECC_BYPASS); - break; - - case NAND_CMD_ERASE1: - vf610_nfc_transfer_size(nfc->regs, 0); - vf610_nfc_send_commands(nfc->regs, command, - NAND_CMD_ERASE2, ERASE_CMD_CODE); - vf610_nfc_addr_cycle(mtd, column, page); - break; - - case NAND_CMD_READID: - nfc->alt_buf = ALT_BUF_ID; - nfc->buf_offset = 0; - vf610_nfc_transfer_size(nfc->regs, 0); - vf610_nfc_send_command(nfc->regs, command, READ_ID_CMD_CODE); - vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK, - ROW_ADDR_SHIFT, column); - break; - - case NAND_CMD_STATUS: - nfc->alt_buf = ALT_BUF_STAT; - vf610_nfc_transfer_size(nfc->regs, 0); - vf610_nfc_send_command(nfc->regs, command, STATUS_READ_CMD_CODE); - break; - default: - return; - } - - vf610_nfc_done(mtd); - - nfc->write_sz = 0; -} - -/* Read data from NFC buffers */ -static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - uint c = nfc->buf_offset; - - /* Alternate buffers are only supported through read_byte */ - if (nfc->alt_buf) - return; - - vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len); - - nfc->buf_offset += len; -} - -/* Write data to NFC buffers */ -static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - uint c = nfc->buf_offset; - uint l; - - l = min_t(uint, len, mtd->writesize + mtd->oobsize - c); - vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l); - - nfc->write_sz += l; - nfc->buf_offset += l; -} - -/* Read byte from NFC buffers */ -static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd) -{ - struct vf610_nfc *nfc = mtd_to_nfc(mtd); - u8 tmp; - uint c = nfc->buf_offset; - - switch (nfc->alt_buf) { - case ALT_BUF_ID: - tmp = vf610_nfc_get_id(mtd, c); - break; - case ALT_BUF_STAT: - tmp = vf610_nfc_get_status(mtd); - break; -#ifdef __LITTLE_ENDIAN - case ALT_BUF_ONFI: - /* Reverse byte since the controller uses big endianness */ - c = nfc->buf_offset ^ 0x3; - /* fall-through */ -#endif - default: - tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c)); - break; - } - nfc->buf_offset++; - return tmp; -} - -/* Read word from NFC buffers */ -static u16 vf610_nfc_read_word(struct mtd_info *mtd) -{ - u16 tmp; - - vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp)); - return tmp; -} - -/* If not provided, upper layers apply a fixed delay. */ -static int vf610_nfc_dev_ready(struct mtd_info *mtd) -{ - /* NFC handles R/B internally; always ready. */ - return 1; -} - -/* - * 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) -{ -#ifdef CONFIG_VF610 - u32 tmp = vf610_nfc_read(mtd, NFC_ROW_ADDR); - tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK); - - if (chip >= 0) { - tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT; - tmp |= (1 << chip) << ROW_ADDR_CHIP_SEL_SHIFT; - } - - vf610_nfc_write(mtd, NFC_ROW_ADDR, tmp); -#endif -} - -/* Count the number of 0's in buff upto max_bits */ -static inline int count_written_bits(uint8_t *buff, int size, int max_bits) -{ - uint32_t *buff32 = (uint32_t *)buff; - int k, written_bits = 0; - - for (k = 0; k < (size / 4); k++) { - written_bits += hweight32(~buff32[k]); - if (written_bits > max_bits) - break; - } - - return written_bits; -} - -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; - int flips_threshold = nfc->chip.ecc.strength / 2; - - ecc_status = vf610_nfc_read(mtd, ecc_status_off) & 0xff; - ecc_count = ecc_status & ECC_STATUS_ERR_COUNT; - - if (!(ecc_status & ECC_STATUS_MASK)) - return ecc_count; - - /* Read OOB without ECC unit enabled */ - vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page); - vf610_nfc_read_buf(mtd, oob, mtd->oobsize); - - /* - * On an erased page, bit count (including OOB) should be zero or - * at least less then half of the ECC strength. - */ - flips = count_written_bits(dat, nfc->chip.ecc.size, flips_threshold); - flips += count_written_bits(oob, mtd->oobsize, flips_threshold); - - if (unlikely(flips > flips_threshold)) - return -EINVAL; - - /* Erased page. */ - memset(dat, 0xff, nfc->chip.ecc.size); - memset(oob, 0xff, mtd->oobsize); - return flips; -} - -static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int eccsize = chip->ecc.size; - int stat; - - vf610_nfc_read_buf(mtd, buf, eccsize); - if (oob_required) - vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize); - - 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; - } -} - -/* - * ECC will be calculated automatically - */ -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); - - vf610_nfc_write_buf(mtd, buf, mtd->writesize); - if (oob_required) - vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - /* Always write whole page including OOB due to HW ECC */ - nfc->write_sz = mtd->writesize + mtd->oobsize; - - return 0; -} - -struct vf610_nfc_config { - int hardware_ecc; - int width; - int flash_bbt; -}; - -static int vf610_nfc_nand_init(int devnum, void __iomem *addr) -{ - struct mtd_info *mtd; - struct nand_chip *chip; - struct vf610_nfc *nfc; - int err = 0; - struct vf610_nfc_config cfg = { - .hardware_ecc = 1, -#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT - .width = 16, -#else - .width = 8, -#endif - .flash_bbt = 1, - }; - - nfc = malloc(sizeof(*nfc)); - if (!nfc) { - printf(KERN_ERR "%s: Memory exhausted!\n", __func__); - return -ENOMEM; - } - - chip = &nfc->chip; - nfc->regs = addr; - - mtd = nand_to_mtd(chip); - nand_set_controller_data(chip, nfc); - - if (cfg.width == 16) - chip->options |= NAND_BUSWIDTH_16; - - chip->dev_ready = vf610_nfc_dev_ready; - chip->cmdfunc = vf610_nfc_command; - chip->read_byte = vf610_nfc_read_byte; - chip->read_word = vf610_nfc_read_word; - chip->read_buf = vf610_nfc_read_buf; - chip->write_buf = vf610_nfc_write_buf; - chip->select_chip = vf610_nfc_select_chip; - - chip->options |= NAND_NO_SUBPAGE_WRITE; - - chip->ecc.size = PAGE_2K; - - /* Set configuration register. */ - vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); - vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT); - vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT); - vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT); - vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT); - vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT); - - /* Disable virtual pages, only one elementary transfer unit */ - vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK, - CONFIG_PAGE_CNT_SHIFT, 1); - - /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) { - err = -ENXIO; - goto error; - } - - if (cfg.width == 16) - vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); - - /* Bad block options. */ - if (cfg.flash_bbt) - chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB | - NAND_BBT_CREATE; - - /* 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 error; - } - - if (cfg.hardware_ecc) { - if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) { - dev_err(nfc->dev, "Unsupported flash with hwecc\n"); - err = -ENXIO; - goto error; - } - - if (chip->ecc.size != mtd->writesize) { - dev_err(nfc->dev, "ecc size: %d\n", chip->ecc.size); - dev_err(nfc->dev, "Step size needs to be page size\n"); - err = -ENXIO; - goto error; - } - - /* Current HW ECC layouts only use 64 bytes of OOB */ - if (mtd->oobsize > 64) - mtd->oobsize = 64; - - /* propagate ecc.layout to mtd_info */ - mtd->ecclayout = chip->ecc.layout; - chip->ecc.read_page = vf610_nfc_read_page; - chip->ecc.write_page = vf610_nfc_write_page; - chip->ecc.mode = NAND_ECC_HW; - - chip->ecc.size = PAGE_2K; - chip->ecc.layout = &vf610_nfc_ecc; -#if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES) - chip->ecc.strength = 24; - chip->ecc.bytes = 45; -#elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES) - chip->ecc.strength = 32; - chip->ecc.bytes = 60; -#endif - - /* Set ECC_STATUS offset */ - vf610_nfc_set_field(mtd, 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(mtd, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT); - } - - /* second phase scan */ - err = nand_scan_tail(mtd); - if (err) - return err; - - err = nand_register(devnum, mtd); - if (err) - return err; - - return 0; - -error: - return err; -} - -void board_nand_init(void) -{ - int err = vf610_nfc_nand_init(0, (void __iomem *)CONFIG_SYS_NAND_BASE); - if (err) - printf("VF610 NAND init failed (err %d)\n", err); -} diff --git a/drivers/mtd/nand/zynq_nand.c b/drivers/mtd/nand/zynq_nand.c deleted file mode 100644 index e932a58bf6..0000000000 --- a/drivers/mtd/nand/zynq_nand.c +++ /dev/null @@ -1,1254 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2016 Xilinx, Inc. - * - * Xilinx Zynq NAND Flash Controller Driver - * This driver is based on plat_nand.c and mxc_nand.c drivers - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* The NAND flash driver defines */ -#define ZYNQ_NAND_CMD_PHASE 1 -#define ZYNQ_NAND_DATA_PHASE 2 -#define ZYNQ_NAND_ECC_SIZE 512 -#define ZYNQ_NAND_SET_OPMODE_8BIT (0 << 0) -#define ZYNQ_NAND_SET_OPMODE_16BIT (1 << 0) -#define ZYNQ_NAND_ECC_STATUS (1 << 6) -#define ZYNQ_MEMC_CLRCR_INT_CLR1 (1 << 4) -#define ZYNQ_MEMC_SR_RAW_INT_ST1 (1 << 6) -#define ZYNQ_MEMC_SR_INT_ST1 (1 << 4) -#define ZYNQ_MEMC_NAND_ECC_MODE_MASK 0xC - -/* Flash memory controller operating parameters */ -#define ZYNQ_NAND_CLR_CONFIG ((0x1 << 1) | /* Disable interrupt */ \ - (0x1 << 4) | /* Clear interrupt */ \ - (0x1 << 6)) /* Disable ECC interrupt */ - -#ifndef CONFIG_NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS - -/* Assuming 50MHz clock (20ns cycle time) and 3V operation */ -#define ZYNQ_NAND_SET_CYCLES ((0x2 << 20) | /* t_rr from nand_cycles */ \ - (0x2 << 17) | /* t_ar from nand_cycles */ \ - (0x1 << 14) | /* t_clr from nand_cycles */ \ - (0x3 << 11) | /* t_wp from nand_cycles */ \ - (0x2 << 8) | /* t_rea from nand_cycles */ \ - (0x5 << 4) | /* t_wc from nand_cycles */ \ - (0x5 << 0)) /* t_rc from nand_cycles */ -#endif - - -#define ZYNQ_NAND_DIRECT_CMD ((0x4 << 23) | /* Chip 0 from interface 1 */ \ - (0x2 << 21)) /* UpdateRegs operation */ - -#define ZYNQ_NAND_ECC_CONFIG ((0x1 << 2) | /* ECC available on APB */ \ - (0x1 << 4) | /* ECC read at end of page */ \ - (0x0 << 5)) /* No Jumping */ - -#define ZYNQ_NAND_ECC_CMD1 ((0x80) | /* Write command */ \ - (0x00 << 8) | /* Read command */ \ - (0x30 << 16) | /* Read End command */ \ - (0x1 << 24)) /* Read End command calid */ - -#define ZYNQ_NAND_ECC_CMD2 ((0x85) | /* Write col change cmd */ \ - (0x05 << 8) | /* Read col change cmd */ \ - (0xE0 << 16) | /* Read col change end cmd */ \ - (0x1 << 24)) /* Read col change - end cmd valid */ -/* AXI Address definitions */ -#define START_CMD_SHIFT 3 -#define END_CMD_SHIFT 11 -#define END_CMD_VALID_SHIFT 20 -#define ADDR_CYCLES_SHIFT 21 -#define CLEAR_CS_SHIFT 21 -#define ECC_LAST_SHIFT 10 -#define COMMAND_PHASE (0 << 19) -#define DATA_PHASE (1 << 19) -#define ONDIE_ECC_FEATURE_ADDR 0x90 -#define ONDIE_ECC_FEATURE_ENABLE 0x08 - -#define ZYNQ_NAND_ECC_LAST (1 << ECC_LAST_SHIFT) /* Set ECC_Last */ -#define ZYNQ_NAND_CLEAR_CS (1 << CLEAR_CS_SHIFT) /* Clear chip select */ - -/* ECC block registers bit position and bit mask */ -#define ZYNQ_NAND_ECC_BUSY (1 << 6) /* ECC block is busy */ -#define ZYNQ_NAND_ECC_MASK 0x00FFFFFF /* ECC value mask */ - -#define ZYNQ_NAND_ROW_ADDR_CYCL_MASK 0x0F -#define ZYNQ_NAND_COL_ADDR_CYCL_MASK 0xF0 - -#define ZYNQ_NAND_MIO_NUM_NAND_8BIT 13 -#define ZYNQ_NAND_MIO_NUM_NAND_16BIT 8 - -enum zynq_nand_bus_width { - NAND_BW_UNKNOWN = -1, - NAND_BW_8BIT, - NAND_BW_16BIT, -}; - -#ifndef NAND_CMD_LOCK_TIGHT -#define NAND_CMD_LOCK_TIGHT 0x2c -#endif - -#ifndef NAND_CMD_LOCK_STATUS -#define NAND_CMD_LOCK_STATUS 0x7a -#endif - -/* SMC register set */ -struct zynq_nand_smc_regs { - u32 csr; /* 0x00 */ - u32 reserved0[2]; - u32 cfr; /* 0x0C */ - u32 dcr; /* 0x10 */ - u32 scr; /* 0x14 */ - u32 sor; /* 0x18 */ - u32 reserved1[249]; - u32 esr; /* 0x400 */ - u32 emcr; /* 0x404 */ - u32 emcmd1r; /* 0x408 */ - u32 emcmd2r; /* 0x40C */ - u32 reserved2[2]; - u32 eval0r; /* 0x418 */ -}; -#define zynq_nand_smc_base ((struct zynq_nand_smc_regs __iomem *)\ - ZYNQ_SMC_BASEADDR) - -/* - * struct zynq_nand_info - Defines the NAND flash driver instance - * @parts: Pointer to the mtd_partition structure - * @nand_base: Virtual address of the NAND flash device - * @end_cmd_pending: End command is pending - * @end_cmd: End command - */ -struct zynq_nand_info { - void __iomem *nand_base; - u8 end_cmd_pending; - u8 end_cmd; -}; - -/* - * struct zynq_nand_command_format - Defines NAND flash command format - * @start_cmd: First cycle command (Start command) - * @end_cmd: Second cycle command (Last command) - * @addr_cycles: Number of address cycles required to send the address - * @end_cmd_valid: The second cycle command is valid for cmd or data phase - */ -struct zynq_nand_command_format { - u8 start_cmd; - u8 end_cmd; - u8 addr_cycles; - u8 end_cmd_valid; -}; - -/* The NAND flash operations command format */ -static const struct zynq_nand_command_format zynq_nand_commands[] = { - {NAND_CMD_READ0, NAND_CMD_READSTART, 5, ZYNQ_NAND_CMD_PHASE}, - {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, ZYNQ_NAND_CMD_PHASE}, - {NAND_CMD_READID, NAND_CMD_NONE, 1, 0}, - {NAND_CMD_STATUS, NAND_CMD_NONE, 0, 0}, - {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5, ZYNQ_NAND_DATA_PHASE}, - {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, 0}, - {NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3, ZYNQ_NAND_CMD_PHASE}, - {NAND_CMD_RESET, NAND_CMD_NONE, 0, 0}, - {NAND_CMD_PARAM, NAND_CMD_NONE, 1, 0}, - {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, 0}, - {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, 0}, - {NAND_CMD_LOCK, NAND_CMD_NONE, 0, 0}, - {NAND_CMD_LOCK_TIGHT, NAND_CMD_NONE, 0, 0}, - {NAND_CMD_UNLOCK1, NAND_CMD_NONE, 3, 0}, - {NAND_CMD_UNLOCK2, NAND_CMD_NONE, 3, 0}, - {NAND_CMD_LOCK_STATUS, NAND_CMD_NONE, 3, 0}, - {NAND_CMD_NONE, NAND_CMD_NONE, 0, 0}, - /* Add all the flash commands supported by the flash device */ -}; - -/* Define default oob placement schemes for large and small page devices */ -static struct nand_ecclayout nand_oob_16 = { - .eccbytes = 3, - .eccpos = {0, 1, 2}, - .oobfree = { - { .offset = 8, .length = 8 } - } -}; - -static struct nand_ecclayout nand_oob_64 = { - .eccbytes = 12, - .eccpos = { - 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63}, - .oobfree = { - { .offset = 2, .length = 50 } - } -}; - -static struct nand_ecclayout ondie_nand_oob_64 = { - .eccbytes = 32, - - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 24, 25, 26, 27, 28, 29, 30, 31, - 40, 41, 42, 43, 44, 45, 46, 47, - 56, 57, 58, 59, 60, 61, 62, 63 - }, - - .oobfree = { - { .offset = 4, .length = 4 }, - { .offset = 20, .length = 4 }, - { .offset = 36, .length = 4 }, - { .offset = 52, .length = 4 } - } -}; - -/* bbt decriptors for chips with on-die ECC and - chips with 64-byte OOB */ -static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; -static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 4, - .len = 4, - .veroffs = 20, - .maxblocks = 4, - .pattern = bbt_pattern -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 4, - .len = 4, - .veroffs = 20, - .maxblocks = 4, - .pattern = mirror_pattern -}; - -/* - * zynq_nand_waitfor_ecc_completion - Wait for ECC completion - * - * returns: status for command completion, -1 for Timeout - */ -static int zynq_nand_waitfor_ecc_completion(void) -{ - unsigned long timeout; - u32 status; - - /* Wait max 10us */ - timeout = 10; - status = readl(&zynq_nand_smc_base->esr); - while (status & ZYNQ_NAND_ECC_BUSY) { - status = readl(&zynq_nand_smc_base->esr); - if (timeout == 0) - return -1; - timeout--; - udelay(1); - } - - return status; -} - -/* - * zynq_nand_init_nand_flash - Initialize NAND controller - * @option: Device property flags - * - * This function initializes the NAND flash interface on the NAND controller. - * - * returns: 0 on success or error value on failure - */ -static int zynq_nand_init_nand_flash(int option) -{ - u32 status; - - /* disable interrupts */ - writel(ZYNQ_NAND_CLR_CONFIG, &zynq_nand_smc_base->cfr); -#ifndef CONFIG_NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS - /* Initialize the NAND interface by setting cycles and operation mode */ - writel(ZYNQ_NAND_SET_CYCLES, &zynq_nand_smc_base->scr); -#endif - if (option & NAND_BUSWIDTH_16) - writel(ZYNQ_NAND_SET_OPMODE_16BIT, &zynq_nand_smc_base->sor); - else - writel(ZYNQ_NAND_SET_OPMODE_8BIT, &zynq_nand_smc_base->sor); - - writel(ZYNQ_NAND_DIRECT_CMD, &zynq_nand_smc_base->dcr); - - /* Wait till the ECC operation is complete */ - status = zynq_nand_waitfor_ecc_completion(); - if (status < 0) { - printf("%s: Timeout\n", __func__); - return status; - } - - /* Set the command1 and command2 register */ - writel(ZYNQ_NAND_ECC_CMD1, &zynq_nand_smc_base->emcmd1r); - writel(ZYNQ_NAND_ECC_CMD2, &zynq_nand_smc_base->emcmd2r); - - return 0; -} - -/* - * zynq_nand_calculate_hwecc - Calculate Hardware ECC - * @mtd: Pointer to the mtd_info structure - * @data: Pointer to the page data - * @ecc_code: Pointer to the ECC buffer where ECC data needs to be stored - * - * This function retrieves the Hardware ECC data from the controller and returns - * ECC data back to the MTD subsystem. - * - * returns: 0 on success or error value on failure - */ -static int zynq_nand_calculate_hwecc(struct mtd_info *mtd, const u8 *data, - u8 *ecc_code) -{ - u32 ecc_value = 0; - u8 ecc_reg, ecc_byte; - u32 ecc_status; - - /* Wait till the ECC operation is complete */ - ecc_status = zynq_nand_waitfor_ecc_completion(); - if (ecc_status < 0) { - printf("%s: Timeout\n", __func__); - return ecc_status; - } - - for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) { - /* Read ECC value for each block */ - ecc_value = readl(&zynq_nand_smc_base->eval0r + ecc_reg); - - /* Get the ecc status from ecc read value */ - ecc_status = (ecc_value >> 24) & 0xFF; - - /* ECC value valid */ - if (ecc_status & ZYNQ_NAND_ECC_STATUS) { - for (ecc_byte = 0; ecc_byte < 3; ecc_byte++) { - /* Copy ECC bytes to MTD buffer */ - *ecc_code = ecc_value & 0xFF; - ecc_value = ecc_value >> 8; - ecc_code++; - } - } else { - debug("%s: ecc status failed\n", __func__); - } - } - - return 0; -} - -/* - * onehot - onehot function - * @value: value to check for onehot - * - * This function checks whether a value is onehot or not. - * onehot is if and only if one bit is set. - * - * FIXME: Try to move this in common.h - */ -static bool onehot(unsigned short value) -{ - bool onehot; - - onehot = value && !(value & (value - 1)); - return onehot; -} - -/* - * zynq_nand_correct_data - ECC correction function - * @mtd: Pointer to the mtd_info structure - * @buf: Pointer to the page data - * @read_ecc: Pointer to the ECC value read from spare data area - * @calc_ecc: Pointer to the calculated ECC value - * - * This function corrects the ECC single bit errors & detects 2-bit errors. - * - * returns: 0 if no ECC errors found - * 1 if single bit error found and corrected. - * -1 if multiple ECC errors found. - */ -static int zynq_nand_correct_data(struct mtd_info *mtd, unsigned char *buf, - unsigned char *read_ecc, unsigned char *calc_ecc) -{ - unsigned char bit_addr; - unsigned int byte_addr; - unsigned short ecc_odd, ecc_even; - unsigned short read_ecc_lower, read_ecc_upper; - unsigned short calc_ecc_lower, calc_ecc_upper; - - read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) & 0xfff; - read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) & 0xfff; - - calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) & 0xfff; - calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) & 0xfff; - - ecc_odd = read_ecc_lower ^ calc_ecc_lower; - ecc_even = read_ecc_upper ^ calc_ecc_upper; - - if ((ecc_odd == 0) && (ecc_even == 0)) - return 0; /* no error */ - - if (ecc_odd == (~ecc_even & 0xfff)) { - /* bits [11:3] of error code is byte offset */ - byte_addr = (ecc_odd >> 3) & 0x1ff; - /* bits [2:0] of error code is bit offset */ - bit_addr = ecc_odd & 0x7; - /* Toggling error bit */ - buf[byte_addr] ^= (1 << bit_addr); - return 1; - } - - if (onehot(ecc_odd | ecc_even)) - return 1; /* one error in parity */ - - return -1; /* Uncorrectable error */ -} - -/* - * zynq_nand_read_oob - [REPLACABLE] the most common OOB data read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * @sndcmd: flag whether to issue read command or not - */ -static int zynq_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - unsigned long data_phase_addr = 0; - int data_width = 4; - u8 *p; - - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - - p = chip->oob_poi; - chip->read_buf(mtd, p, (mtd->oobsize - data_width)); - p += mtd->oobsize - data_width; - - data_phase_addr = (unsigned long)chip->IO_ADDR_R; - data_phase_addr |= ZYNQ_NAND_CLEAR_CS; - chip->IO_ADDR_R = (void __iomem *)data_phase_addr; - chip->read_buf(mtd, p, data_width); - - return 0; -} - -/* - * zynq_nand_write_oob - [REPLACABLE] the most common OOB data write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write - */ -static int zynq_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - int status = 0, data_width = 4; - const u8 *buf = chip->oob_poi; - unsigned long data_phase_addr = 0; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - - chip->write_buf(mtd, buf, (mtd->oobsize - data_width)); - buf += mtd->oobsize - data_width; - - data_phase_addr = (unsigned long)chip->IO_ADDR_W; - data_phase_addr |= ZYNQ_NAND_CLEAR_CS; - data_phase_addr |= (1 << END_CMD_VALID_SHIFT); - chip->IO_ADDR_W = (void __iomem *)data_phase_addr; - chip->write_buf(mtd, buf, data_width); - - /* Send command to program the OOB data */ - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - - return status & NAND_STATUS_FAIL ? -EIO : 0; -} - -/* - * zynq_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: must write chip->oob_poi to OOB - * @page: page number to read - */ -static int zynq_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - u8 *buf, int oob_required, int page) -{ - unsigned long data_width = 4; - unsigned long data_phase_addr = 0; - u8 *p; - - chip->read_buf(mtd, buf, mtd->writesize); - - p = chip->oob_poi; - chip->read_buf(mtd, p, (mtd->oobsize - data_width)); - p += (mtd->oobsize - data_width); - - data_phase_addr = (unsigned long)chip->IO_ADDR_R; - data_phase_addr |= ZYNQ_NAND_CLEAR_CS; - chip->IO_ADDR_R = (void __iomem *)data_phase_addr; - - chip->read_buf(mtd, p, data_width); - return 0; -} - -static int zynq_nand_read_page_raw_nooob(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, int oob_required, int page) -{ - chip->read_buf(mtd, buf, mtd->writesize); - return 0; -} - -static int zynq_nand_read_subpage_raw(struct mtd_info *mtd, - struct nand_chip *chip, u32 data_offs, - u32 readlen, u8 *buf, int page) -{ - if (data_offs != 0) { - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_offs, -1); - buf += data_offs; - } - chip->read_buf(mtd, buf, readlen); - - return 0; -} - -/* - * zynq_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 - */ -static int zynq_nand_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, int oob_required, int page) -{ - unsigned long data_width = 4; - unsigned long data_phase_addr = 0; - u8 *p; - - chip->write_buf(mtd, buf, mtd->writesize); - - p = chip->oob_poi; - chip->write_buf(mtd, p, (mtd->oobsize - data_width)); - p += (mtd->oobsize - data_width); - - data_phase_addr = (unsigned long)chip->IO_ADDR_W; - data_phase_addr |= ZYNQ_NAND_CLEAR_CS; - data_phase_addr |= (1 << END_CMD_VALID_SHIFT); - chip->IO_ADDR_W = (void __iomem *)data_phase_addr; - - chip->write_buf(mtd, p, data_width); - - return 0; -} - -/* - * nand_write_page_hwecc - Hardware ECC based page write function - * @mtd: Pointer to the mtd info structure - * @chip: Pointer to the NAND chip info structure - * @buf: Pointer to the data buffer - * @oob_required: must write chip->oob_poi to OOB - * - * This functions writes data and hardware generated ECC values in to the page. - */ -static int zynq_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, int oob_required, int page) -{ - int i, eccsteps, eccsize = chip->ecc.size; - u8 *ecc_calc = chip->buffers->ecccalc; - const u8 *p = buf; - u32 *eccpos = chip->ecc.layout->eccpos; - unsigned long data_phase_addr = 0; - unsigned long data_width = 4; - u8 *oob_ptr; - - for (eccsteps = chip->ecc.steps; (eccsteps - 1); eccsteps--) { - chip->write_buf(mtd, p, eccsize); - p += eccsize; - } - chip->write_buf(mtd, p, (eccsize - data_width)); - p += eccsize - data_width; - - /* Set ECC Last bit to 1 */ - data_phase_addr = (unsigned long) chip->IO_ADDR_W; - data_phase_addr |= ZYNQ_NAND_ECC_LAST; - chip->IO_ADDR_W = (void __iomem *)data_phase_addr; - chip->write_buf(mtd, p, data_width); - - /* Wait for ECC to be calculated and read the error values */ - p = buf; - chip->ecc.calculate(mtd, p, &ecc_calc[0]); - - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]); - - /* Clear ECC last bit */ - data_phase_addr = (unsigned long)chip->IO_ADDR_W; - data_phase_addr &= ~ZYNQ_NAND_ECC_LAST; - chip->IO_ADDR_W = (void __iomem *)data_phase_addr; - - /* Write the spare area with ECC bytes */ - oob_ptr = chip->oob_poi; - chip->write_buf(mtd, oob_ptr, (mtd->oobsize - data_width)); - - data_phase_addr = (unsigned long)chip->IO_ADDR_W; - data_phase_addr |= ZYNQ_NAND_CLEAR_CS; - data_phase_addr |= (1 << END_CMD_VALID_SHIFT); - chip->IO_ADDR_W = (void __iomem *)data_phase_addr; - oob_ptr += (mtd->oobsize - data_width); - chip->write_buf(mtd, oob_ptr, data_width); - - return 0; -} - -/* - * zynq_nand_write_page_swecc - [REPLACABLE] 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 - */ -static int zynq_nand_write_page_swecc(struct mtd_info *mtd, - struct nand_chip *chip, const u8 *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - u8 *ecc_calc = chip->buffers->ecccalc; - const u8 *p = buf; - u32 *eccpos = chip->ecc.layout->eccpos; - - /* Software ecc calculation */ - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - return chip->ecc.write_page_raw(mtd, chip, buf, 1, page); -} - -/* - * nand_read_page_hwecc - Hardware ECC based page read function - * @mtd: Pointer to the mtd info structure - * @chip: Pointer to the NAND chip info structure - * @buf: Pointer to the buffer to store read data - * @oob_required: must write chip->oob_poi to OOB - * @page: page number to read - * - * This functions reads data and checks the data integrity by comparing hardware - * generated ECC values and read ECC values from spare area. - * - * returns: 0 always and updates ECC operation status in to MTD structure - */ -static int zynq_nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, int oob_required, int page) -{ - int i, stat, eccsteps, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - u8 *p = buf; - u8 *ecc_calc = chip->buffers->ecccalc; - u8 *ecc_code = chip->buffers->ecccode; - u32 *eccpos = chip->ecc.layout->eccpos; - unsigned long data_phase_addr = 0; - unsigned long data_width = 4; - u8 *oob_ptr; - - for (eccsteps = chip->ecc.steps; (eccsteps - 1); eccsteps--) { - chip->read_buf(mtd, p, eccsize); - p += eccsize; - } - chip->read_buf(mtd, p, (eccsize - data_width)); - p += eccsize - data_width; - - /* Set ECC Last bit to 1 */ - data_phase_addr = (unsigned long)chip->IO_ADDR_R; - data_phase_addr |= ZYNQ_NAND_ECC_LAST; - chip->IO_ADDR_R = (void __iomem *)data_phase_addr; - chip->read_buf(mtd, p, data_width); - - /* Read the calculated ECC value */ - p = buf; - chip->ecc.calculate(mtd, p, &ecc_calc[0]); - - /* Clear ECC last bit */ - data_phase_addr = (unsigned long)chip->IO_ADDR_R; - data_phase_addr &= ~ZYNQ_NAND_ECC_LAST; - chip->IO_ADDR_R = (void __iomem *)data_phase_addr; - - /* Read the stored ECC value */ - oob_ptr = chip->oob_poi; - chip->read_buf(mtd, oob_ptr, (mtd->oobsize - data_width)); - - /* de-assert chip select */ - data_phase_addr = (unsigned long)chip->IO_ADDR_R; - data_phase_addr |= ZYNQ_NAND_CLEAR_CS; - chip->IO_ADDR_R = (void __iomem *)data_phase_addr; - - oob_ptr += (mtd->oobsize - data_width); - chip->read_buf(mtd, oob_ptr, data_width); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = ~(chip->oob_poi[eccpos[i]]); - - eccsteps = chip->ecc.steps; - p = buf; - - /* Check ECC error for all blocks and correct if it is correctable */ - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} - -/* - * zynq_nand_read_page_swecc - [REPLACABLE] software ecc based page - * read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read - */ -static int zynq_nand_read_page_swecc(struct mtd_info *mtd, - struct nand_chip *chip, u8 *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - u8 *p = buf; - u8 *ecc_calc = chip->buffers->ecccalc; - u8 *ecc_code = chip->buffers->ecccode; - u32 *eccpos = chip->ecc.layout->eccpos; - - chip->ecc.read_page_raw(mtd, chip, buf, 1, page); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - eccsteps = chip->ecc.steps; - p = buf; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} - -/* - * zynq_nand_select_chip - Select the flash device - * @mtd: Pointer to the mtd_info structure - * @chip: Chip number to be selected - * - * This function is empty as the NAND controller handles chip select line - * internally based on the chip address passed in command and data phase. - */ -static void zynq_nand_select_chip(struct mtd_info *mtd, int chip) -{ - /* Not support multiple chips yet */ -} - -/* - * zynq_nand_cmd_function - Send command to NAND device - * @mtd: Pointer to the mtd_info structure - * @command: The command to be sent to the flash device - * @column: The column address for this command, -1 if none - * @page_addr: The page address for this command, -1 if none - */ -static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - struct nand_chip *chip = mtd->priv; - const struct zynq_nand_command_format *curr_cmd = NULL; - u8 addr_cycles = 0; - struct zynq_nand_info *xnand = (struct zynq_nand_info *)chip->priv; - void *cmd_addr; - unsigned long cmd_data = 0; - unsigned long cmd_phase_addr = 0; - unsigned long data_phase_addr = 0; - u8 end_cmd = 0; - u8 end_cmd_valid = 0; - u32 index; - - if (xnand->end_cmd_pending) { - /* Check for end command if this command request is same as the - * pending command then return - */ - if (xnand->end_cmd == command) { - xnand->end_cmd = 0; - xnand->end_cmd_pending = 0; - return; - } - } - - /* Emulate NAND_CMD_READOOB for large page device */ - if ((mtd->writesize > ZYNQ_NAND_ECC_SIZE) && - (command == NAND_CMD_READOOB)) { - column += mtd->writesize; - command = NAND_CMD_READ0; - } - - /* Get the command format */ - for (index = 0; index < ARRAY_SIZE(zynq_nand_commands); index++) - if (command == zynq_nand_commands[index].start_cmd) - break; - - if (index == ARRAY_SIZE(zynq_nand_commands)) { - printf("%s: Unsupported start cmd %02x\n", __func__, command); - return; - } - curr_cmd = &zynq_nand_commands[index]; - - /* Clear interrupt */ - writel(ZYNQ_MEMC_CLRCR_INT_CLR1, &zynq_nand_smc_base->cfr); - - /* Get the command phase address */ - if (curr_cmd->end_cmd_valid == ZYNQ_NAND_CMD_PHASE) - end_cmd_valid = 1; - - if (curr_cmd->end_cmd == NAND_CMD_NONE) - end_cmd = 0x0; - else - end_cmd = curr_cmd->end_cmd; - - if (command == NAND_CMD_READ0 || - command == NAND_CMD_SEQIN) { - addr_cycles = chip->onfi_params.addr_cycles & - ZYNQ_NAND_ROW_ADDR_CYCL_MASK; - addr_cycles += ((chip->onfi_params.addr_cycles & - ZYNQ_NAND_COL_ADDR_CYCL_MASK) >> 4); - } else { - addr_cycles = curr_cmd->addr_cycles; - } - - cmd_phase_addr = (unsigned long)xnand->nand_base | - (addr_cycles << ADDR_CYCLES_SHIFT) | - (end_cmd_valid << END_CMD_VALID_SHIFT) | - (COMMAND_PHASE) | - (end_cmd << END_CMD_SHIFT) | - (curr_cmd->start_cmd << START_CMD_SHIFT); - - cmd_addr = (void __iomem *)cmd_phase_addr; - - /* Get the data phase address */ - end_cmd_valid = 0; - - data_phase_addr = (unsigned long)xnand->nand_base | - (0x0 << CLEAR_CS_SHIFT) | - (end_cmd_valid << END_CMD_VALID_SHIFT) | - (DATA_PHASE) | - (end_cmd << END_CMD_SHIFT) | - (0x0 << ECC_LAST_SHIFT); - - chip->IO_ADDR_R = (void __iomem *)data_phase_addr; - chip->IO_ADDR_W = chip->IO_ADDR_R; - - /* Command phase AXI Read & Write */ - if (column != -1 && page_addr != -1) { - /* Adjust columns for 16 bit bus width */ - if (chip->options & NAND_BUSWIDTH_16) - column >>= 1; - cmd_data = column; - if (mtd->writesize > ZYNQ_NAND_ECC_SIZE) { - cmd_data |= page_addr << 16; - /* Another address cycle for devices > 128MiB */ - if (chip->chipsize > (128 << 20)) { - writel(cmd_data, cmd_addr); - cmd_data = (page_addr >> 16); - } - } else { - cmd_data |= page_addr << 8; - } - } else if (page_addr != -1) { /* Erase */ - cmd_data = page_addr; - } else if (column != -1) { /* Change read/write column, read id etc */ - /* Adjust columns for 16 bit bus width */ - if ((chip->options & NAND_BUSWIDTH_16) && - ((command == NAND_CMD_READ0) || - (command == NAND_CMD_SEQIN) || - (command == NAND_CMD_RNDOUT) || - (command == NAND_CMD_RNDIN))) - column >>= 1; - cmd_data = column; - } - - writel(cmd_data, cmd_addr); - - if (curr_cmd->end_cmd_valid) { - xnand->end_cmd = curr_cmd->end_cmd; - xnand->end_cmd_pending = 1; - } - - ndelay(100); - - if ((command == NAND_CMD_READ0) || - (command == NAND_CMD_RESET) || - (command == NAND_CMD_PARAM) || - (command == NAND_CMD_GET_FEATURES)) - /* wait until command is processed */ - nand_wait_ready(mtd); -} - -/* - * zynq_nand_read_buf - read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read - */ -static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - - /* Make sure that buf is 32 bit aligned */ - if (((unsigned long)buf & 0x3) != 0) { - if (((unsigned long)buf & 0x1) != 0) { - if (len) { - *buf = readb(chip->IO_ADDR_R); - buf += 1; - len--; - } - } - - if (((unsigned long)buf & 0x3) != 0) { - if (len >= 2) { - *(u16 *)buf = readw(chip->IO_ADDR_R); - buf += 2; - len -= 2; - } - } - } - - /* copy aligned data */ - while (len >= 4) { - *(u32 *)buf = readl(chip->IO_ADDR_R); - buf += 4; - len -= 4; - } - - /* mop up any remaining bytes */ - if (len) { - if (len >= 2) { - *(u16 *)buf = readw(chip->IO_ADDR_R); - buf += 2; - len -= 2; - } - if (len) - *buf = readb(chip->IO_ADDR_R); - } -} - -/* - * zynq_nand_write_buf - write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write - */ -static void zynq_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - const u32 *nand = chip->IO_ADDR_W; - - /* Make sure that buf is 32 bit aligned */ - if (((unsigned long)buf & 0x3) != 0) { - if (((unsigned long)buf & 0x1) != 0) { - if (len) { - writeb(*buf, nand); - buf += 1; - len--; - } - } - - if (((unsigned long)buf & 0x3) != 0) { - if (len >= 2) { - writew(*(u16 *)buf, nand); - buf += 2; - len -= 2; - } - } - } - - /* copy aligned data */ - while (len >= 4) { - writel(*(u32 *)buf, nand); - buf += 4; - len -= 4; - } - - /* mop up any remaining bytes */ - if (len) { - if (len >= 2) { - writew(*(u16 *)buf, nand); - buf += 2; - len -= 2; - } - - if (len) - writeb(*buf, nand); - } -} - -/* - * zynq_nand_device_ready - Check device ready/busy line - * @mtd: Pointer to the mtd_info structure - * - * returns: 0 on busy or 1 on ready state - */ -static int zynq_nand_device_ready(struct mtd_info *mtd) -{ - u32 csr_val; - - csr_val = readl(&zynq_nand_smc_base->csr); - /* Check the raw_int_status1 bit */ - if (csr_val & ZYNQ_MEMC_SR_RAW_INT_ST1) { - /* Clear the interrupt condition */ - writel(ZYNQ_MEMC_SR_INT_ST1, &zynq_nand_smc_base->cfr); - return 1; - } - - return 0; -} - -static int zynq_nand_check_is_16bit_bw_flash(void) -{ - int is_16bit_bw = NAND_BW_UNKNOWN; - int mio_num_8bit = 0, mio_num_16bit = 0; - - mio_num_8bit = zynq_slcr_get_mio_pin_status("nand8"); - if (mio_num_8bit == ZYNQ_NAND_MIO_NUM_NAND_8BIT) - is_16bit_bw = NAND_BW_8BIT; - - mio_num_16bit = zynq_slcr_get_mio_pin_status("nand16"); - if (mio_num_8bit == ZYNQ_NAND_MIO_NUM_NAND_8BIT && - mio_num_16bit == ZYNQ_NAND_MIO_NUM_NAND_16BIT) - is_16bit_bw = NAND_BW_16BIT; - - return is_16bit_bw; -} - -static int zynq_nand_init(struct nand_chip *nand_chip, int devnum) -{ - struct zynq_nand_info *xnand; - struct mtd_info *mtd; - unsigned long ecc_page_size; - u8 maf_id, dev_id, i; - u8 get_feature[4]; - u8 set_feature[4] = {ONDIE_ECC_FEATURE_ENABLE, 0x00, 0x00, 0x00}; - unsigned long ecc_cfg; - int ondie_ecc_enabled = 0; - int err = -1; - int is_16bit_bw; - - xnand = calloc(1, sizeof(struct zynq_nand_info)); - if (!xnand) { - printf("%s: failed to allocate\n", __func__); - goto fail; - } - - xnand->nand_base = (void __iomem *)ZYNQ_NAND_BASEADDR; - mtd = nand_to_mtd(nand_chip); - - nand_chip->priv = xnand; - mtd->priv = nand_chip; - - /* Set address of NAND IO lines */ - nand_chip->IO_ADDR_R = xnand->nand_base; - nand_chip->IO_ADDR_W = xnand->nand_base; - - /* Set the driver entry points for MTD */ - nand_chip->cmdfunc = zynq_nand_cmd_function; - nand_chip->dev_ready = zynq_nand_device_ready; - nand_chip->select_chip = zynq_nand_select_chip; - - /* If we don't set this delay driver sets 20us by default */ - nand_chip->chip_delay = 30; - - /* Buffer read/write routines */ - nand_chip->read_buf = zynq_nand_read_buf; - nand_chip->write_buf = zynq_nand_write_buf; - - is_16bit_bw = zynq_nand_check_is_16bit_bw_flash(); - if (is_16bit_bw == NAND_BW_UNKNOWN) { - printf("%s: Unable detect NAND based on MIO settings\n", - __func__); - goto fail; - } - - if (is_16bit_bw == NAND_BW_16BIT) - nand_chip->options = NAND_BUSWIDTH_16; - - nand_chip->bbt_options = NAND_BBT_USE_FLASH; - - /* Initialize the NAND flash interface on NAND controller */ - if (zynq_nand_init_nand_flash(nand_chip->options) < 0) { - printf("%s: nand flash init failed\n", __func__); - goto fail; - } - - /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1, NULL)) { - printf("%s: nand_scan_ident failed\n", __func__); - goto fail; - } - /* Send the command for reading device ID */ - nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - /* Read manufacturer and device IDs */ - maf_id = nand_chip->read_byte(mtd); - dev_id = nand_chip->read_byte(mtd); - - if ((maf_id == 0x2c) && ((dev_id == 0xf1) || - (dev_id == 0xa1) || (dev_id == 0xb1) || - (dev_id == 0xaa) || (dev_id == 0xba) || - (dev_id == 0xda) || (dev_id == 0xca) || - (dev_id == 0xac) || (dev_id == 0xbc) || - (dev_id == 0xdc) || (dev_id == 0xcc) || - (dev_id == 0xa3) || (dev_id == 0xb3) || - (dev_id == 0xd3) || (dev_id == 0xc3))) { - nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, - ONDIE_ECC_FEATURE_ADDR, -1); - for (i = 0; i < 4; i++) - writeb(set_feature[i], nand_chip->IO_ADDR_W); - - /* Wait for 1us after writing data with SET_FEATURES command */ - ndelay(1000); - - nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, - ONDIE_ECC_FEATURE_ADDR, -1); - nand_chip->read_buf(mtd, get_feature, 4); - - if (get_feature[0] & ONDIE_ECC_FEATURE_ENABLE) { - debug("%s: OnDie ECC flash\n", __func__); - ondie_ecc_enabled = 1; - } else { - printf("%s: Unable to detect OnDie ECC\n", __func__); - } - } - - if (ondie_ecc_enabled) { - /* Bypass the controller ECC block */ - ecc_cfg = readl(&zynq_nand_smc_base->emcr); - ecc_cfg &= ~ZYNQ_MEMC_NAND_ECC_MODE_MASK; - writel(ecc_cfg, &zynq_nand_smc_base->emcr); - - /* The software ECC routines won't work - * with the SMC controller - */ - nand_chip->ecc.mode = NAND_ECC_HW; - nand_chip->ecc.strength = 1; - nand_chip->ecc.read_page = zynq_nand_read_page_raw_nooob; - nand_chip->ecc.read_subpage = zynq_nand_read_subpage_raw; - nand_chip->ecc.write_page = zynq_nand_write_page_raw; - nand_chip->ecc.read_page_raw = zynq_nand_read_page_raw; - nand_chip->ecc.write_page_raw = zynq_nand_write_page_raw; - nand_chip->ecc.read_oob = zynq_nand_read_oob; - nand_chip->ecc.write_oob = zynq_nand_write_oob; - nand_chip->ecc.size = mtd->writesize; - nand_chip->ecc.bytes = 0; - - /* NAND with on-die ECC supports subpage reads */ - nand_chip->options |= NAND_SUBPAGE_READ; - - /* On-Die ECC spare bytes offset 8 is used for ECC codes */ - if (ondie_ecc_enabled) { - nand_chip->ecc.layout = &ondie_nand_oob_64; - /* Use the BBT pattern descriptors */ - nand_chip->bbt_td = &bbt_main_descr; - nand_chip->bbt_md = &bbt_mirror_descr; - } - } else { - /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ - nand_chip->ecc.mode = NAND_ECC_HW; - nand_chip->ecc.strength = 1; - nand_chip->ecc.size = ZYNQ_NAND_ECC_SIZE; - nand_chip->ecc.bytes = 3; - nand_chip->ecc.calculate = zynq_nand_calculate_hwecc; - nand_chip->ecc.correct = zynq_nand_correct_data; - nand_chip->ecc.hwctl = NULL; - nand_chip->ecc.read_page = zynq_nand_read_page_hwecc; - nand_chip->ecc.write_page = zynq_nand_write_page_hwecc; - nand_chip->ecc.read_page_raw = zynq_nand_read_page_raw; - nand_chip->ecc.write_page_raw = zynq_nand_write_page_raw; - nand_chip->ecc.read_oob = zynq_nand_read_oob; - nand_chip->ecc.write_oob = zynq_nand_write_oob; - - switch (mtd->writesize) { - case 512: - ecc_page_size = 0x1; - /* Set the ECC memory config register */ - writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size), - &zynq_nand_smc_base->emcr); - break; - case 1024: - ecc_page_size = 0x2; - /* Set the ECC memory config register */ - writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size), - &zynq_nand_smc_base->emcr); - break; - case 2048: - ecc_page_size = 0x3; - /* Set the ECC memory config register */ - writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size), - &zynq_nand_smc_base->emcr); - break; - default: - nand_chip->ecc.mode = NAND_ECC_SOFT; - nand_chip->ecc.calculate = nand_calculate_ecc; - nand_chip->ecc.correct = nand_correct_data; - nand_chip->ecc.read_page = zynq_nand_read_page_swecc; - nand_chip->ecc.write_page = zynq_nand_write_page_swecc; - nand_chip->ecc.size = 256; - break; - } - - if (mtd->oobsize == 16) - nand_chip->ecc.layout = &nand_oob_16; - else if (mtd->oobsize == 64) - nand_chip->ecc.layout = &nand_oob_64; - else - printf("%s: No oob layout found\n", __func__); - } - - /* Second phase scan */ - if (nand_scan_tail(mtd)) { - printf("%s: nand_scan_tail failed\n", __func__); - goto fail; - } - if (nand_register(devnum, mtd)) - goto fail; - return 0; -fail: - free(xnand); - return err; -} - -static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; - -void board_nand_init(void) -{ - struct nand_chip *nand = &nand_chip[0]; - - if (zynq_nand_init(nand, 0)) - puts("ZYNQ NAND init failed\n"); -} diff --git a/include/configs/MPC8313ERDB.h b/include/configs/MPC8313ERDB.h index 884dd4125e..5b5c38f2c9 100644 --- a/include/configs/MPC8313ERDB.h +++ b/include/configs/MPC8313ERDB.h @@ -240,7 +240,7 @@ /* LB refresh timer prescal, 266MHz/32 */ #define CONFIG_SYS_LBC_MRTPR 0x20000000 /*TODO */ -/* drivers/mtd/nand/nand.c */ +/* drivers/mtd/nand/raw/nand.c */ #if defined(CONFIG_NAND) && defined(CONFIG_SPL_BUILD) #define CONFIG_SYS_NAND_BASE 0xFFF00000 #else