From d4cb37e71662dac72049bf7c55a9038bd7d2bcb5 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 16 May 2017 00:17:42 +0200 Subject: [PATCH 01/51] mtd: nand: Remove support for block locking/unlocking Commit 7d70f334ad2b ("mtd: nand: add lock/unlock routines") introduced support for the Micron LOCK/UNLOCK commands but no one ever used the nand_lock/unlock() functions. Remove support for these vendor-specific operations from the core. If one ever wants to add them back they should be put in nand_micron.c and mtd->_lock/_unlock should be directly assigned from there instead of exporting the functions. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 173 ----------------------------------- include/linux/mtd/nand.h | 10 -- 2 files changed, 183 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5fa5ddc94834..54d6194fb180 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1239,179 +1239,6 @@ int nand_reset(struct nand_chip *chip, int chipnr) return 0; } -/** - * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * @mtd: mtd info - * @ofs: offset to start unlock from - * @len: length to unlock - * @invert: - * - when = 0, unlock the range of blocks within the lower and - * upper boundary address - * - when = 1, unlock the range of blocks outside the boundaries - * of the lower and upper boundary address - * - * Returs unlock status. - */ -static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, - uint64_t len, int invert) -{ - int ret = 0; - int status, page; - struct nand_chip *chip = mtd_to_nand(mtd); - - /* Submit address of first page to unlock */ - page = ofs >> chip->page_shift; - chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); - - /* Submit address of last page to unlock */ - page = (ofs + len) >> chip->page_shift; - chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, - (page | invert) & chip->pagemask); - - /* Call wait ready function */ - status = chip->waitfunc(mtd, chip); - /* See if device thinks it succeeded */ - if (status & NAND_STATUS_FAIL) { - pr_debug("%s: error status = 0x%08x\n", - __func__, status); - ret = -EIO; - } - - return ret; -} - -/** - * nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * @mtd: mtd info - * @ofs: offset to start unlock from - * @len: length to unlock - * - * Returns unlock status. - */ -int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - int ret = 0; - int chipnr; - struct nand_chip *chip = mtd_to_nand(mtd); - - pr_debug("%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)ofs, len); - - if (check_offs_len(mtd, ofs, len)) - return -EINVAL; - - /* Align to last block address if size addresses end of the device */ - if (ofs + len == mtd->size) - len -= mtd->erasesize; - - nand_get_device(mtd, FL_UNLOCKING); - - /* Shift to get chip number */ - chipnr = ofs >> chip->chip_shift; - - /* - * Reset the chip. - * If we want to check the WP through READ STATUS and check the bit 7 - * we must reset the chip - * some operation can also clear the bit 7 of status register - * eg. erase/program a locked block - */ - nand_reset(chip, chipnr); - - 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__); - ret = -EIO; - goto out; - } - - ret = __nand_unlock(mtd, ofs, len, 0); - -out: - chip->select_chip(mtd, -1); - nand_release_device(mtd); - - return ret; -} -EXPORT_SYMBOL(nand_unlock); - -/** - * nand_lock - [REPLACEABLE] locks all blocks present in the device - * @mtd: mtd info - * @ofs: offset to start unlock from - * @len: length to unlock - * - * This feature is not supported in many NAND parts. 'Micron' NAND parts do - * have this feature, but it allows only to lock all blocks, not for specified - * range for block. Implementing 'lock' feature by making use of 'unlock', for - * now. - * - * Returns lock status. - */ -int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - int ret = 0; - int chipnr, status, page; - struct nand_chip *chip = mtd_to_nand(mtd); - - pr_debug("%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)ofs, len); - - if (check_offs_len(mtd, ofs, len)) - return -EINVAL; - - nand_get_device(mtd, FL_LOCKING); - - /* Shift to get chip number */ - chipnr = ofs >> chip->chip_shift; - - /* - * Reset the chip. - * If we want to check the WP through READ STATUS and check the bit 7 - * we must reset the chip - * some operation can also clear the bit 7 of status register - * eg. erase/program a locked block - */ - nand_reset(chip, chipnr); - - 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__); - status = MTD_ERASE_FAILED; - ret = -EIO; - goto out; - } - - /* Submit address of first page to lock */ - page = ofs >> chip->page_shift; - chip->cmdfunc(mtd, NAND_CMD_LOCK, -1, page & chip->pagemask); - - /* Call wait ready function */ - status = chip->waitfunc(mtd, chip); - /* See if device thinks it succeeded */ - if (status & NAND_STATUS_FAIL) { - pr_debug("%s: error status = 0x%08x\n", - __func__, status); - ret = -EIO; - goto out; - } - - ret = __nand_unlock(mtd, ofs, len, 0x1); - -out: - chip->select_chip(mtd, -1); - nand_release_device(mtd); - - return ret; -} -EXPORT_SYMBOL(nand_lock); - /** * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data * @buf: buffer to test diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 892148c448cc..8a6522e82f03 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -44,12 +44,6 @@ void nand_release(struct mtd_info *mtd); /* Internal helper for board drivers which need to override command function */ void nand_wait_ready(struct mtd_info *mtd); -/* locks all blocks present in the device */ -int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); - -/* unlocks specified locked blocks */ -int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); - /* The maximum number of NAND chips in an array */ #define NAND_MAX_CHIPS 8 @@ -89,10 +83,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); #define NAND_CMD_SET_FEATURES 0xef #define NAND_CMD_RESET 0xff -#define NAND_CMD_LOCK 0x2a -#define NAND_CMD_UNLOCK1 0x23 -#define NAND_CMD_UNLOCK2 0x24 - /* Extended commands for large page devices */ #define NAND_CMD_READSTART 0x30 #define NAND_CMD_RNDOUTSTART 0xE0 From d4092d76a4a4e57b65910899948a83cc8646c5a5 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 4 Aug 2017 17:29:10 +0200 Subject: [PATCH 02/51] mtd: nand: Rename nand.h into rawnand.h We are planning to share more code between different NAND based devices (SPI NAND, OneNAND and raw NANDs), but before doing that we need to move the existing include/linux/mtd/nand.h file into include/linux/mtd/rawnand.h so we can later create a nand.h header containing all common structure and function prototypes. Signed-off-by: Boris Brezillon Signed-off-by: Peter Pan Acked-by: Vladimir Zapolskiy Acked-by: Alexander Sverdlin Acked-by: Wenyou Yang Acked-by: Krzysztof Kozlowski Acked-by: Han Xu Acked-by: H Hartley Sweeten Acked-by: Shawn Guo Acked-by: Gregory CLEMENT Acked-by: Neil Armstrong Acked-by: Masahiro Yamada Acked-By: Harvey Hunt Acked-by: Tony Lindgren Acked-by: Krzysztof Halasa --- Documentation/driver-api/mtdnand.rst | 8 ++++---- MAINTAINERS | 2 +- arch/arm/mach-davinci/board-da850-evm.c | 2 +- arch/arm/mach-davinci/board-dm355-evm.c | 2 +- arch/arm/mach-davinci/board-dm355-leopard.c | 2 +- arch/arm/mach-davinci/board-dm365-evm.c | 2 +- arch/arm/mach-davinci/board-dm644x-evm.c | 2 +- arch/arm/mach-davinci/board-dm646x-evm.c | 2 +- arch/arm/mach-davinci/board-sffsdr.c | 2 +- arch/arm/mach-dove/dove-db-setup.c | 2 +- arch/arm/mach-ep93xx/snappercl15.c | 2 +- arch/arm/mach-ep93xx/ts72xx.c | 2 +- arch/arm/mach-imx/mach-qong.c | 2 +- arch/arm/mach-ixp4xx/ixdp425-setup.c | 2 +- arch/arm/mach-mmp/aspenite.c | 2 +- arch/arm/mach-omap1/board-fsample.c | 2 +- arch/arm/mach-omap1/board-h2.c | 2 +- arch/arm/mach-omap1/board-h3.c | 2 +- arch/arm/mach-omap1/board-nand.c | 2 +- arch/arm/mach-omap1/board-perseus2.c | 2 +- arch/arm/mach-orion5x/db88f5281-setup.c | 2 +- arch/arm/mach-orion5x/kurobox_pro-setup.c | 2 +- arch/arm/mach-orion5x/ts209-setup.c | 2 +- arch/arm/mach-orion5x/ts78xx-setup.c | 2 +- arch/arm/mach-pxa/balloon3.c | 2 +- arch/arm/mach-pxa/em-x270.c | 2 +- arch/arm/mach-pxa/eseries.c | 2 +- arch/arm/mach-pxa/palmtx.c | 2 +- arch/arm/mach-pxa/tosa.c | 2 +- arch/arm/mach-s3c24xx/common-smdk.c | 2 +- arch/arm/mach-s3c24xx/mach-anubis.c | 2 +- arch/arm/mach-s3c24xx/mach-at2440evb.c | 2 +- arch/arm/mach-s3c24xx/mach-bast.c | 2 +- arch/arm/mach-s3c24xx/mach-gta02.c | 2 +- arch/arm/mach-s3c24xx/mach-jive.c | 2 +- arch/arm/mach-s3c24xx/mach-mini2440.c | 2 +- arch/arm/mach-s3c24xx/mach-osiris.c | 2 +- arch/arm/mach-s3c24xx/mach-qt2410.c | 2 +- arch/arm/mach-s3c24xx/mach-rx3715.c | 2 +- arch/arm/mach-s3c24xx/mach-vstms.c | 2 +- arch/blackfin/mach-bf537/boards/dnp5370.c | 2 +- arch/blackfin/mach-bf537/boards/stamp.c | 2 +- arch/blackfin/mach-bf561/boards/acvilon.c | 2 +- arch/cris/arch-v32/drivers/mach-a3/nandflash.c | 2 +- arch/cris/arch-v32/drivers/mach-fs/nandflash.c | 2 +- arch/mips/alchemy/devboards/db1200.c | 2 +- arch/mips/alchemy/devboards/db1300.c | 2 +- arch/mips/alchemy/devboards/db1550.c | 2 +- arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 2 +- arch/mips/netlogic/xlr/platform-flash.c | 2 +- arch/mips/pnx833x/common/platform.c | 2 +- arch/mips/rb532/devices.c | 2 +- arch/sh/boards/mach-migor/setup.c | 2 +- drivers/mtd/inftlcore.c | 2 +- drivers/mtd/nand/ams-delta.c | 2 +- drivers/mtd/nand/atmel/nand-controller.c | 2 +- drivers/mtd/nand/atmel/pmecc.c | 2 +- drivers/mtd/nand/au1550nd.c | 2 +- drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h | 2 +- drivers/mtd/nand/bf5xx_nand.c | 2 +- drivers/mtd/nand/brcmnand/brcmnand.c | 2 +- drivers/mtd/nand/cafe_nand.c | 2 +- drivers/mtd/nand/cmx270_nand.c | 2 +- drivers/mtd/nand/cs553x_nand.c | 2 +- drivers/mtd/nand/davinci_nand.c | 2 +- drivers/mtd/nand/denali.h | 2 +- drivers/mtd/nand/diskonchip.c | 2 +- drivers/mtd/nand/docg4.c | 2 +- drivers/mtd/nand/fsl_elbc_nand.c | 2 +- drivers/mtd/nand/fsl_ifc_nand.c | 2 +- drivers/mtd/nand/fsl_upm.c | 2 +- drivers/mtd/nand/fsmc_nand.c | 2 +- drivers/mtd/nand/gpio.c | 2 +- drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 2 +- drivers/mtd/nand/hisi504_nand.c | 2 +- drivers/mtd/nand/jz4740_nand.c | 2 +- drivers/mtd/nand/jz4780_nand.c | 2 +- drivers/mtd/nand/lpc32xx_mlc.c | 2 +- drivers/mtd/nand/lpc32xx_slc.c | 2 +- drivers/mtd/nand/mpc5121_nfc.c | 2 +- drivers/mtd/nand/mtk_nand.c | 2 +- drivers/mtd/nand/mxc_nand.c | 2 +- drivers/mtd/nand/nand_amd.c | 2 +- drivers/mtd/nand/nand_base.c | 2 +- drivers/mtd/nand/nand_bbt.c | 2 +- drivers/mtd/nand/nand_bch.c | 2 +- drivers/mtd/nand/nand_ecc.c | 2 +- drivers/mtd/nand/nand_hynix.c | 2 +- drivers/mtd/nand/nand_ids.c | 2 +- drivers/mtd/nand/nand_macronix.c | 2 +- drivers/mtd/nand/nand_micron.c | 2 +- drivers/mtd/nand/nand_samsung.c | 2 +- drivers/mtd/nand/nand_timings.c | 2 +- drivers/mtd/nand/nand_toshiba.c | 2 +- drivers/mtd/nand/nandsim.c | 2 +- drivers/mtd/nand/ndfc.c | 2 +- drivers/mtd/nand/nuc900_nand.c | 2 +- drivers/mtd/nand/omap2.c | 2 +- drivers/mtd/nand/orion_nand.c | 2 +- drivers/mtd/nand/oxnas_nand.c | 2 +- drivers/mtd/nand/pasemi_nand.c | 2 +- drivers/mtd/nand/plat_nand.c | 2 +- drivers/mtd/nand/pxa3xx_nand.c | 2 +- drivers/mtd/nand/qcom_nandc.c | 2 +- drivers/mtd/nand/r852.h | 2 +- drivers/mtd/nand/s3c2410.c | 2 +- drivers/mtd/nand/sh_flctl.c | 2 +- drivers/mtd/nand/sharpsl.c | 2 +- drivers/mtd/nand/sm_common.c | 2 +- drivers/mtd/nand/socrates_nand.c | 2 +- drivers/mtd/nand/sunxi_nand.c | 2 +- drivers/mtd/nand/tango_nand.c | 2 +- drivers/mtd/nand/tmio_nand.c | 2 +- drivers/mtd/nand/txx9ndfmc.c | 2 +- drivers/mtd/nand/vf610_nfc.c | 2 +- drivers/mtd/nand/xway_nand.c | 2 +- drivers/mtd/nftlcore.c | 2 +- drivers/mtd/nftlmount.c | 2 +- drivers/mtd/ssfdc.c | 2 +- drivers/mtd/tests/nandbiterrs.c | 2 +- drivers/staging/mt29f_spinand/mt29f_spinand.c | 2 +- fs/jffs2/wbuf.c | 2 +- include/linux/mtd/nand-gpio.h | 2 +- include/linux/mtd/{nand.h => rawnand.h} | 8 +++----- include/linux/mtd/sh_flctl.h | 2 +- include/linux/mtd/sharpsl.h | 2 +- include/linux/platform_data/mtd-davinci.h | 2 +- include/linux/platform_data/mtd-nand-s3c2410.h | 2 +- 128 files changed, 133 insertions(+), 135 deletions(-) rename include/linux/mtd/{nand.h => rawnand.h} (99%) diff --git a/Documentation/driver-api/mtdnand.rst b/Documentation/driver-api/mtdnand.rst index e9afa586d15e..2a5191b6d445 100644 --- a/Documentation/driver-api/mtdnand.rst +++ b/Documentation/driver-api/mtdnand.rst @@ -516,7 +516,7 @@ mirrored table is performed. The most important field in the nand_bbt_descr structure is the options field. The options define most of the table properties. Use the -predefined constants from nand.h to define the options. +predefined constants from rawnand.h to define the options. - Number of bits per block @@ -843,7 +843,7 @@ Chip option constants Constants for chip id table ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -These constants are defined in nand.h. They are OR-ed together to +These constants are defined in rawnand.h. They are OR-ed together to describe the chip functionality:: /* Buswitdh is 16 bit */ @@ -865,7 +865,7 @@ describe the chip functionality:: Constants for runtime options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -These constants are defined in nand.h. They are OR-ed together to +These constants are defined in rawnand.h. They are OR-ed together to describe the functionality:: /* The hw ecc generator provides a syndrome instead a ecc value on read @@ -956,7 +956,7 @@ developer. Each struct member has a short description which is marked with an [XXX] identifier. See the chapter "Documentation hints" for an explanation. -.. kernel-doc:: include/linux/mtd/nand.h +.. kernel-doc:: include/linux/mtd/rawnand.h :internal: Public Functions Provided diff --git a/MAINTAINERS b/MAINTAINERS index 205d3977ac46..bffb38373550 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9034,7 +9034,7 @@ T: git git://git.infradead.org/linux-mtd.git nand/fixes T: git git://git.infradead.org/l2-mtd.git nand/next S: Maintained F: drivers/mtd/nand/ -F: include/linux/mtd/nand*.h +F: include/linux/mtd/*nand*.h NATSEMI ETHERNET DRIVER (DP8381x) S: Orphan diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index b5625d009288..f54410388194 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 18296a99c4d2..62e7bc3018f0 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c index 284ff27c1b32..be997243447b 100644 --- a/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 0464999b7137..e75741fb2c1d 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 70e00dbeec96..b07c9b18d427 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 1d76e7480a42..cb0a41e83582 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c index 41c7c9615791..d85accf7f760 100644 --- a/arch/arm/mach-davinci/board-sffsdr.c +++ b/arch/arm/mach-davinci/board-sffsdr.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c index bcb678fd2415..8971c3c0f0fe 100644 --- a/arch/arm/mach-dove/dove-db-setup.c +++ b/arch/arm/mach-dove/dove-db-setup.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c index b2db791b3b38..8b29398f4dc7 100644 --- a/arch/arm/mach-ep93xx/snappercl15.c +++ b/arch/arm/mach-ep93xx/snappercl15.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 55b186ef863a..8745162ec05d 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-imx/mach-qong.c b/arch/arm/mach-imx/mach-qong.c index 8c2cbd693d21..42a700053103 100644 --- a/arch/arm/mach-imx/mach-qong.c +++ b/arch/arm/mach-imx/mach-qong.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index 508c2d7786e2..93b89291c06b 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c index 5db0edf716dd..d2283009a5ff 100644 --- a/arch/arm/mach-mmp/aspenite.c +++ b/arch/arm/mach-mmp/aspenite.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c index fad95b74bb65..b93ad58b0a63 100644 --- a/arch/arm/mach-omap1/board-fsample.c +++ b/arch/arm/mach-omap1/board-fsample.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 675254ee4b1e..a444b139bff5 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index e62f9d454f10..a618a49a30b8 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-nand.c b/arch/arm/mach-omap1/board-nand.c index 7684f9203474..1bffbb4e050f 100644 --- a/arch/arm/mach-omap1/board-nand.c +++ b/arch/arm/mach-omap1/board-nand.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "common.h" diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 150b57ba42bf..e994a78bdd09 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c index 12f74b46e2ff..3f5863de766a 100644 --- a/arch/arm/mach-orion5x/db88f5281-setup.c +++ b/arch/arm/mach-orion5x/db88f5281-setup.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c index 9dc3f59bed9c..83d43cff4bd7 100644 --- a/arch/arm/mach-orion5x/kurobox_pro-setup.c +++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c index 7bd671b2854c..0c315515dd2d 100644 --- a/arch/arm/mach-orion5x/ts209-setup.c +++ b/arch/arm/mach-orion5x/ts209-setup.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c index 7ef80a8304c0..94778739e38f 100644 --- a/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/arch/arm/mach-orion5x/ts78xx-setup.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c index 1467c1d1e541..d6d92f388f14 100644 --- a/arch/arm/mach-pxa/balloon3.c +++ b/arch/arm/mach-pxa/balloon3.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 811a7317f3ea..6d28035ebba5 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c index fa9d71d194f0..91f7c3e40065 100644 --- a/arch/arm/mach-pxa/eseries.c +++ b/arch/arm/mach-pxa/eseries.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c index 36646975b5d2..47e3e38e9bec 100644 --- a/arch/arm/mach-pxa/palmtx.c +++ b/arch/arm/mach-pxa/palmtx.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 13de6602966f..6a386fd6363e 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c index 9e0bc46e90ec..0e116c92bf01 100644 --- a/arch/arm/mach-s3c24xx/common-smdk.c +++ b/arch/arm/mach-s3c24xx/common-smdk.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c index 029ef1b58925..c14cab361922 100644 --- a/arch/arm/mach-s3c24xx/mach-anubis.c +++ b/arch/arm/mach-s3c24xx/mach-anubis.c @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c index 7b28eb623fc1..ebdbafb9382a 100644 --- a/arch/arm/mach-s3c24xx/mach-at2440evb.c +++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c index 5185036765db..704dc84b3480 100644 --- a/arch/arm/mach-s3c24xx/mach-bast.c +++ b/arch/arm/mach-s3c24xx/mach-bast.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c index b0ed401da3a3..afe18baf0c84 100644 --- a/arch/arm/mach-s3c24xx/mach-gta02.c +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@ -50,7 +50,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c index f5b5c49b56ac..17821976f769 100644 --- a/arch/arm/mach-s3c24xx/mach-jive.c +++ b/arch/arm/mach-s3c24xx/mach-jive.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c index 71af8d2fd320..15140d34f927 100644 --- a/arch/arm/mach-s3c24xx/mach-mini2440.c +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c index 70b0eb7d3134..a6657e720430 100644 --- a/arch/arm/mach-s3c24xx/mach-osiris.c +++ b/arch/arm/mach-s3c24xx/mach-osiris.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c index 868c82087403..84e3a9c53184 100644 --- a/arch/arm/mach-s3c24xx/mach-qt2410.c +++ b/arch/arm/mach-s3c24xx/mach-qt2410.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c index a39fb9780dd3..b5ba615cf9dd 100644 --- a/arch/arm/mach-s3c24xx/mach-rx3715.c +++ b/arch/arm/mach-s3c24xx/mach-rx3715.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c index f5e6322145fa..1adc957edf0f 100644 --- a/arch/arm/mach-s3c24xx/mach-vstms.c +++ b/arch/arm/mach-s3c24xx/mach-vstms.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/blackfin/mach-bf537/boards/dnp5370.c b/arch/blackfin/mach-bf537/boards/dnp5370.c index e79b3b810c39..c4a8ffb15417 100644 --- a/arch/blackfin/mach-bf537/boards/dnp5370.c +++ b/arch/blackfin/mach-bf537/boards/dnp5370.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index 7528148dc492..400e6693643e 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/blackfin/mach-bf561/boards/acvilon.c b/arch/blackfin/mach-bf561/boards/acvilon.c index 37f8f25a1347..696cc9d7820a 100644 --- a/arch/blackfin/mach-bf561/boards/acvilon.c +++ b/arch/blackfin/mach-bf561/boards/acvilon.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c index 3f646c787e58..925a98eb6d68 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c index a74540514bdb..53b56a429dde 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c index 992442a03d8b..83831002c832 100644 --- a/arch/mips/alchemy/devboards/db1200.c +++ b/arch/mips/alchemy/devboards/db1200.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c index a5504f57cb00..3e7fbdbdb3c4 100644 --- a/arch/mips/alchemy/devboards/db1300.c +++ b/arch/mips/alchemy/devboards/db1300.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c index 1c01d6eadb08..421bd5793f7e 100644 --- a/arch/mips/alchemy/devboards/db1550.c +++ b/arch/mips/alchemy/devboards/db1550.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h index 7f7b0fc554da..f381d465e768 100644 --- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h +++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h @@ -16,7 +16,7 @@ #ifndef __ASM_MACH_JZ4740_JZ4740_NAND_H__ #define __ASM_MACH_JZ4740_JZ4740_NAND_H__ -#include +#include #include #define JZ_NAND_NUM_BANKS 4 diff --git a/arch/mips/netlogic/xlr/platform-flash.c b/arch/mips/netlogic/xlr/platform-flash.c index f03131fec41d..4d1b4c003376 100644 --- a/arch/mips/netlogic/xlr/platform-flash.c +++ b/arch/mips/netlogic/xlr/platform-flash.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include diff --git a/arch/mips/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c index 7cf4eb50fc72..a7a4e9f5146d 100644 --- a/arch/mips/pnx833x/common/platform.c +++ b/arch/mips/pnx833x/common/platform.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index 0966adccf520..32ea3e6731d6 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 5de60a77eaa1..0bcbe58b11e9 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 8db740d6eb08..57ef1fb42a04 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 5d6c26f3cf7f..dcec9cf4983f 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index d922a88e407f..6606270b9b9b 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -59,7 +59,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/atmel/pmecc.c b/drivers/mtd/nand/atmel/pmecc.c index 55a8ee5306ea..27a969a8f105 100644 --- a/drivers/mtd/nand/atmel/pmecc.c +++ b/drivers/mtd/nand/atmel/pmecc.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 9bf6d9915694..9d4a28fa6b73 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h index 8ea75710a854..c8834767ab6d 100644 --- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h +++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h @@ -6,7 +6,7 @@ #endif #include -#include +#include struct bcm47xxnflash { struct bcma_drv_cc *cc; diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 3962f55bd034..5655dca6ce43 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c index 7419c5ce63f8..e0eb51d8c012 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/brcmnand/brcmnand.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 2fd733eba0a3..bc558c438a57 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -13,7 +13,7 @@ #include #undef DEBUG #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 949b9400dcb7..1fc435f994e1 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -18,7 +18,7 @@ * CM-X270 board. */ -#include +#include #include #include #include diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 594b28684138..d48877540f14 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 7b26e53b95b1..ccc8c43abcff 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 237cc706b0fb..9239e6793e6e 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -21,7 +21,7 @@ #define __DENALI_H__ #include -#include +#include #define DEVICE_RESET 0x0 #define DEVICE_RESET__BANK(bank) BIT(bank) diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index a023ab9e9cbf..c3aa53caab5c 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index a27a84fbfb84..2436cbc71662 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index b9ac16f05057..17db2f90aa2c 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 59408ec2c69f..9e03bac7f34c 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index d85fa2555b68..a88e2cf66e0f 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 9d8b051d3187..eac15d9bf49e 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 85294f150f4f..fd3648952b5a 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 9df0ad64e7e0..a45e4ce13d10 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -17,7 +17,7 @@ #ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H #define __DRIVERS_MTD_NAND_GPMI_NAND_H -#include +#include #include #include #include diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c index 530caa80b1b6..d9ee1a7e6956 100644 --- a/drivers/mtd/nand/hisi504_nand.c +++ b/drivers/mtd/nand/hisi504_nand.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 0d06a1f07d82..ad827d4af3e9 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c index 8bc835f71b26..e69f6ae4c539 100644 --- a/drivers/mtd/nand/jz4780_nand.c +++ b/drivers/mtd/nand/jz4780_nand.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 846a66c1b133..bffa01cd0d38 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index a0669a33f8fe..7c8402f023df 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 0e86fb6277c3..b6b97cc9fba6 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c index f7ae99464375..d86a7d131cc0 100644 --- a/drivers/mtd/nand/mtk_nand.c +++ b/drivers/mtd/nand/mtk_nand.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a764d5ca7536..30c71915fd7b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/nand_amd.c b/drivers/mtd/nand/nand_amd.c index 170403a3bfa8..22f060f38123 100644 --- a/drivers/mtd/nand/nand_amd.c +++ b/drivers/mtd/nand/nand_amd.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include static void amd_nand_decode_id(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5fa5ddc94834..8093df278692 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 7695efea65f2..2915b6739bf8 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -61,7 +61,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index 44763f87eae4..505441c9373b 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index d1770b066396..7613a0388044 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #else diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c index b12dc7325378..b735cc8ec104 100644 --- a/drivers/mtd/nand/nand_hynix.c +++ b/drivers/mtd/nand/nand_hynix.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include #include #include diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 92e2cf8e9ff9..5423c3bb388e 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -6,7 +6,7 @@ * published by the Free Software Foundation. * */ -#include +#include #include #define LP_OPTIONS 0 diff --git a/drivers/mtd/nand/nand_macronix.c b/drivers/mtd/nand/nand_macronix.c index 84855c3e1a02..d290ff2a6d2f 100644 --- a/drivers/mtd/nand/nand_macronix.c +++ b/drivers/mtd/nand/nand_macronix.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include static int macronix_nand_init(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/nand_micron.c b/drivers/mtd/nand/nand_micron.c index c30ab60f8e1b..abf6a3c376e8 100644 --- a/drivers/mtd/nand/nand_micron.c +++ b/drivers/mtd/nand/nand_micron.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include /* * Special Micron status bit that indicates when the block has been diff --git a/drivers/mtd/nand/nand_samsung.c b/drivers/mtd/nand/nand_samsung.c index 1e0755997762..d348f0129ae7 100644 --- a/drivers/mtd/nand/nand_samsung.c +++ b/drivers/mtd/nand/nand_samsung.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include static void samsung_nand_decode_id(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c index f06312df3669..90228b9735bd 100644 --- a/drivers/mtd/nand/nand_timings.c +++ b/drivers/mtd/nand/nand_timings.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include static const struct nand_data_interface onfi_sdr_timings[] = { /* Mode 0 */ diff --git a/drivers/mtd/nand/nand_toshiba.c b/drivers/mtd/nand/nand_toshiba.c index fa787ba38dcd..57df857074e6 100644 --- a/drivers/mtd/nand/nand_toshiba.c +++ b/drivers/mtd/nand/nand_toshiba.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include static void toshiba_nand_decode_id(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 03a0d057bf2f..5ba46354bf0f 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 28e6118362f7..d8a806894937 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -22,7 +22,7 @@ * */ #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 8f64011d32ef..7bb4d2ea9342 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #define REG_FMICSR 0x00 diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 084934a9f19c..54540c8fa1a2 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 209170ed2b76..c48c872f29ee 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c index 1b207aac840c..f14eec3886d9 100644 --- a/drivers/mtd/nand/oxnas_nand.c +++ b/drivers/mtd/nand/oxnas_nand.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 074b8b01289e..a47a7e4bd25a 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 791de3e4bbb6..925a1323604d 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include struct plat_nand_data { diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 74dae4bbdac8..85cff68643e0 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 88af7145a51a..d2751b3a2972 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/r852.h index d042ddb71a8b..8713c57f6207 100644 --- a/drivers/mtd/nand/r852.h +++ b/drivers/mtd/nand/r852.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 9e0c849607b9..4c383eeec6f6 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 891ac7b99305..2637b9052fe7 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 064ca1757589..737efe83cd36 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index 5939dff253c2..c378705c6e2b 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c @@ -7,7 +7,7 @@ * published by the Free Software Foundation. */ #include -#include +#include #include #include #include "sm_common.h" diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index 72369bd079af..575997d0ef8a 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index d0b6f8f9f297..393d5dce633d 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c index 9d40b793b1c4..766906f03943 100644 --- a/drivers/mtd/nand/tango_nand.c +++ b/drivers/mtd/nand/tango_nand.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index fc5e773f8b60..c9dd682fb353 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 0a14fda2e41b..b567d212fe7d 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 744ab10e8962..8ba9b6de5fa6 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/xway_nand.c index ddee4005248c..9926b4e3d69d 100644 --- a/drivers/mtd/nand/xway_nand.c +++ b/drivers/mtd/nand/xway_nand.c @@ -7,7 +7,7 @@ * Copyright © 2016 Hauke Mehrtens */ -#include +#include #include #include diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index e21161353e76..1f1a61168b3d 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index a5dfbfbebfca..184c8fbfe465 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #define SECTORSIZE 512 diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 41b13d1cdcc4..95f0bf95f095 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include struct ssfdcr_record { diff --git a/drivers/mtd/tests/nandbiterrs.c b/drivers/mtd/tests/nandbiterrs.c index f26dec896afa..5f03b8c885a9 100644 --- a/drivers/mtd/tests/nandbiterrs.c +++ b/drivers/mtd/tests/nandbiterrs.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include "mtd_test.h" diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c index a4e3ae8f0c85..13eaf16ecd16 100644 --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include "mt29f_spinand.h" diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index b25d28a21212..48d9522e209c 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/mtd/nand-gpio.h b/include/linux/mtd/nand-gpio.h index 51534e50f7fc..be4f45d89be2 100644 --- a/include/linux/mtd/nand-gpio.h +++ b/include/linux/mtd/nand-gpio.h @@ -1,7 +1,7 @@ #ifndef __LINUX_MTD_NAND_GPIO_H #define __LINUX_MTD_NAND_GPIO_H -#include +#include struct gpio_nand_platdata { int gpio_nce; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/rawnand.h similarity index 99% rename from include/linux/mtd/nand.h rename to include/linux/mtd/rawnand.h index 892148c448cc..b371dc0914a7 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/rawnand.h @@ -1,6 +1,4 @@ /* - * linux/include/linux/mtd/nand.h - * * Copyright © 2000-2010 David Woodhouse * Steven J. Hill * Thomas Gleixner @@ -15,8 +13,8 @@ * Changelog: * See git changelog. */ -#ifndef __LINUX_MTD_NAND_H -#define __LINUX_MTD_NAND_H +#ifndef __LINUX_MTD_RAWNAND_H +#define __LINUX_MTD_RAWNAND_H #include #include @@ -1328,4 +1326,4 @@ void nand_cleanup(struct nand_chip *chip); /* Default extended ID decoding function */ void nand_decode_ext_id(struct nand_chip *chip); -#endif /* __LINUX_MTD_NAND_H */ +#endif /* __LINUX_MTD_RAWNAND_H */ diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 2251add65fa7..c759d403cbc0 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/include/linux/mtd/sharpsl.h b/include/linux/mtd/sharpsl.h index 65e91d0fa981..72a79c7d0e08 100644 --- a/include/linux/mtd/sharpsl.h +++ b/include/linux/mtd/sharpsl.h @@ -8,7 +8,7 @@ * published by the Free Software Foundation. */ -#include +#include #include #include diff --git a/include/linux/platform_data/mtd-davinci.h b/include/linux/platform_data/mtd-davinci.h index 1cf555aef896..f1a2cf655bdb 100644 --- a/include/linux/platform_data/mtd-davinci.h +++ b/include/linux/platform_data/mtd-davinci.h @@ -28,7 +28,7 @@ #ifndef __ARCH_ARM_DAVINCI_NAND_H #define __ARCH_ARM_DAVINCI_NAND_H -#include +#include #define NANDFCR_OFFSET 0x60 #define NANDFSR_OFFSET 0x64 diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h index f01659026b26..f8c553f92655 100644 --- a/include/linux/platform_data/mtd-nand-s3c2410.h +++ b/include/linux/platform_data/mtd-nand-s3c2410.h @@ -12,7 +12,7 @@ #ifndef __MTD_NAND_S3C2410_H #define __MTD_NAND_S3C2410_H -#include +#include /** * struct s3c2410_nand_set - define a set of one or more nand chips From f84674b82af2c3ea68b9032d1244f364e46cc75d Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Jun 2017 12:18:24 +0200 Subject: [PATCH 03/51] mtd: nand: Fix various memory leaks in core The nand_scan_ident() function is not expected to allocate resources, and people are usually not calling nand_cleanup() if something fails between nand_scan_ident() and nand_scan_tail(). Move all functions that may allocate resource to the nand_scan_tail() path to prevent such resource leaks. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 118 +++++++++++++++++------------------ 1 file changed, 56 insertions(+), 62 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 54d6194fb180..abcb15fba484 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3856,7 +3856,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) const struct nand_manufacturer *manufacturer; struct mtd_info *mtd = nand_to_mtd(chip); int busw; - int i, ret; + int i; u8 *id_data = chip->id.data; u8 maf_id, dev_id; @@ -3997,10 +3997,6 @@ ident_done: if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - ret = nand_manufacturer_init(chip); - if (ret) - return ret; - pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", maf_id, dev_id); @@ -4208,23 +4204,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return ret; } - /* Initialize the ->data_interface field. */ - ret = nand_init_data_interface(chip); - if (ret) - goto err_nand_init; - - /* - * 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) - goto err_nand_init; - nand_maf_id = chip->id.data[0]; nand_dev_id = chip->id.data[1]; @@ -4254,12 +4233,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, mtd->size = i * chip->chipsize; return 0; - -err_nand_init: - /* Free manufacturer priv data. */ - nand_manufacturer_cleanup(chip); - - return ret; } EXPORT_SYMBOL(nand_scan_ident); @@ -4646,55 +4619,60 @@ int nand_scan_tail(struct mtd_info *mtd) struct nand_chip *chip = mtd_to_nand(mtd); struct nand_ecc_ctrl *ecc = &chip->ecc; struct nand_buffers *nbuf = NULL; - int ret; + int ret, i; /* New bad blocks should be marked in OOB, flash-based BBT, or both */ if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && !(chip->bbt_options & NAND_BBT_USE_FLASH))) { - ret = -EINVAL; - goto err_ident; + return -EINVAL; } if (invalid_ecc_page_accessors(chip)) { pr_err("Invalid ECC page accessors setup\n"); - ret = -EINVAL; - goto err_ident; + return -EINVAL; } if (!(chip->options & NAND_OWN_BUFFERS)) { nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL); - if (!nbuf) { - ret = -ENOMEM; - goto err_ident; - } + if (!nbuf) + return -ENOMEM; nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL); if (!nbuf->ecccalc) { ret = -ENOMEM; - goto err_free; + goto err_free_nbuf; } nbuf->ecccode = kmalloc(mtd->oobsize, GFP_KERNEL); if (!nbuf->ecccode) { ret = -ENOMEM; - goto err_free; + goto err_free_nbuf; } nbuf->databuf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); if (!nbuf->databuf) { ret = -ENOMEM; - goto err_free; + goto err_free_nbuf; } chip->buffers = nbuf; - } else { - if (!chip->buffers) { - ret = -ENOMEM; - goto err_ident; - } + } else if (!chip->buffers) { + return -ENOMEM; } + /* + * FIXME: some NAND manufacturer drivers expect the first die to be + * selected when manufacturer->init() is called. They should be fixed + * to explictly select the relevant die when interacting with the NAND + * chip. + */ + chip->select_chip(mtd, 0); + ret = nand_manufacturer_init(chip); + chip->select_chip(mtd, -1); + if (ret) + goto err_free_nbuf; + /* Set the internal oob buffer location, just after the page data */ chip->oob_poi = chip->buffers->databuf + mtd->writesize; @@ -4716,7 +4694,7 @@ int nand_scan_tail(struct mtd_info *mtd) WARN(1, "No oob scheme defined for oobsize %d\n", mtd->oobsize); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } } @@ -4731,7 +4709,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (!ecc->calculate || !ecc->correct || !ecc->hwctl) { WARN(1, "No ECC functions supplied; hardware ECC not possible\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } if (!ecc->read_page) ecc->read_page = nand_read_page_hwecc_oob_first; @@ -4763,7 +4741,7 @@ int nand_scan_tail(struct mtd_info *mtd) ecc->write_page == nand_write_page_hwecc)) { WARN(1, "No ECC functions supplied; hardware ECC not possible\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } /* Use standard syndrome read/write page function? */ if (!ecc->read_page) @@ -4783,7 +4761,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (!ecc->strength) { WARN(1, "Driver must set ecc.strength when using hardware ECC\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } break; } @@ -4796,7 +4774,7 @@ int nand_scan_tail(struct mtd_info *mtd) ret = nand_set_ecc_soft_ops(mtd); if (ret) { ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } break; @@ -4804,7 +4782,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (!ecc->read_page || !ecc->write_page) { WARN(1, "No ECC functions supplied; on-die ECC not possible\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } if (!ecc->read_oob) ecc->read_oob = nand_read_oob_std; @@ -4828,7 +4806,7 @@ int nand_scan_tail(struct mtd_info *mtd) default: WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->mode); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } /* For many systems, the standard OOB write also works for raw */ @@ -4849,13 +4827,13 @@ int nand_scan_tail(struct mtd_info *mtd) if (ecc->steps * ecc->size != mtd->writesize) { WARN(1, "Invalid ECC parameters\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } ecc->total = ecc->steps * ecc->bytes; if (ecc->total > mtd->oobsize) { WARN(1, "Total number of ECC bytes exceeded oobsize\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } /* @@ -4937,6 +4915,21 @@ int nand_scan_tail(struct mtd_info *mtd) if (!mtd->bitflip_threshold) mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4); + /* Initialize the ->data_interface field. */ + ret = nand_init_data_interface(chip); + if (ret) + goto err_nand_manuf_cleanup; + + /* Enter fastest possible mode on all dies. */ + for (i = 0; i < chip->numchips; i++) { + chip->select_chip(mtd, i); + ret = nand_setup_data_interface(chip, i); + chip->select_chip(mtd, -1); + + if (ret) + goto err_nand_data_iface_cleanup; + } + /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) return 0; @@ -4944,10 +4937,17 @@ int nand_scan_tail(struct mtd_info *mtd) /* Build bad block table */ ret = chip->scan_bbt(mtd); if (ret) - goto err_free; + goto err_nand_data_iface_cleanup; + return 0; -err_free: +err_nand_data_iface_cleanup: + nand_release_data_interface(chip); + +err_nand_manuf_cleanup: + nand_manufacturer_cleanup(chip); + +err_free_nbuf: if (nbuf) { kfree(nbuf->databuf); kfree(nbuf->ecccode); @@ -4955,12 +4955,6 @@ err_free: kfree(nbuf); } -err_ident: - /* Clean up nand_scan_ident(). */ - - /* Free manufacturer priv data. */ - nand_manufacturer_cleanup(chip); - return ret; } EXPORT_SYMBOL(nand_scan_tail); From 5158bd5597e4c0939db3ecefbcbf492c425e611c Mon Sep 17 00:00:00 2001 From: Jean-Louis Thekekara Date: Thu, 29 Jun 2017 19:08:30 +0200 Subject: [PATCH 04/51] mtd: nand: remove hard-coded NAND ids length This commit removes hard-coded '8' used for looping into struct nand_chip.id.data array. NAND_MAX_ID_LEN has been introduced by Artem Bityutskiy in 53552d22bfe1f for defining ids length in nand_flash_ids[] list. This commit unifies ids length in nand base driver. Signed-off-by: Jean-Louis Thekekara Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 4 ++-- include/linux/mtd/nand.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index abcb15fba484..ab2804379b0d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3886,7 +3886,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read entire ID string */ - for (i = 0; i < 8; i++) + for (i = 0; i < ARRAY_SIZE(chip->id.data); i++) id_data[i] = chip->read_byte(mtd); if (id_data[0] != maf_id || id_data[1] != dev_id) { @@ -3895,7 +3895,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) return -ENODEV; } - chip->id.len = nand_id_len(id_data, 8); + chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data)); /* Try to identify manufacturer */ manufacturer = nand_get_manufacturer(maf_id); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 8a6522e82f03..297684013977 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -439,14 +439,16 @@ struct nand_jedec_params { __le16 crc; } __packed; +/* The maximum expected count of bytes in the NAND ID sequence */ +#define NAND_MAX_ID_LEN 8 + /** * struct nand_id - NAND id structure - * @data: buffer containing the id bytes. Currently 8 bytes large, but can - * be extended if required. + * @data: buffer containing the id bytes. * @len: ID length. */ struct nand_id { - u8 data[8]; + u8 data[NAND_MAX_ID_LEN]; int len; }; @@ -1018,8 +1020,6 @@ static inline void *nand_get_manufacturer_data(struct nand_chip *chip) #define NAND_MFR_ATO 0x9b #define NAND_MFR_WINBOND 0xef -/* The maximum expected count of bytes in the NAND ID sequence */ -#define NAND_MAX_ID_LEN 8 /* * A helper for defining older NAND chips where the second ID byte fully From 03fba86b63b95cf4377dd6cf8eaca9b225ed4a2d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 17 Jul 2017 21:54:07 -0300 Subject: [PATCH 05/51] mtd: nand: vf610: Check the return value from clk_prepare_enable() clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 744ab10e8962..9e496727e781 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -814,12 +814,16 @@ static int vf610_nfc_suspend(struct device *dev) static int vf610_nfc_resume(struct device *dev) { + int err; + struct mtd_info *mtd = dev_get_drvdata(dev); struct vf610_nfc *nfc = mtd_to_nfc(mtd); pinctrl_pm_select_default_state(dev); - clk_prepare_enable(nfc->clk); + err = clk_prepare_enable(nfc->clk); + if (err) + return err; vf610_nfc_preinit_controller(nfc); vf610_nfc_init_controller(nfc); From f7b8103ec33e53b73b60551ca7bb8f5350d06d6d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 17 Jul 2017 21:54:08 -0300 Subject: [PATCH 06/51] mtd: nand: vf610: Remove unneeded pinctrl_pm_select_default_state() pinctrl_pm_select_default_state() is already the default pinctrl state and since pinctrl_pm_select_sleep_state() is not used in this driver, there is no need to explicitly call pinctrl_pm_select_default_state(). Signed-off-by: Fabio Estevam Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 9e496727e781..b88a0c91b455 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -819,8 +818,6 @@ static int vf610_nfc_resume(struct device *dev) struct mtd_info *mtd = dev_get_drvdata(dev); struct vf610_nfc *nfc = mtd_to_nfc(mtd); - pinctrl_pm_select_default_state(dev); - err = clk_prepare_enable(nfc->clk); if (err) return err; From 10777de570016471fd929869c7830a7772893e39 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 3 Aug 2017 17:56:39 +0200 Subject: [PATCH 07/51] mtd: nand: qcom: fix config error for BCH The configuration for BCH is not correct in the current driver. The ECC_CFG_ECC_DISABLE bit defines whether to enable or disable the BCH ECC in which 0x1 : BCH_DISABLED 0x0 : BCH_ENABLED But currently host->bch_enabled is being assigned to BCH_DISABLED. Fixes: c76b78d8ec05a ("mtd: nand: Qualcomm NAND controller driver") Cc: stable@vger.kernel.org Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 88af7145a51a..9c4c1ccb5d0f 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -1893,7 +1893,7 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host) | wide_bus << WIDE_FLASH | 1 << DEV0_CFG1_ECC_DISABLE; - host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE + host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE | 0 << ECC_SW_RESET | host->cw_data << ECC_NUM_DATA_BYTES | 1 << ECC_FORCE_CLK_OPEN From e806423aca5bf52b1e14e83befa9d4bac8c17ee1 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:53 +0530 Subject: [PATCH 08/51] mtd: nand: qcom: remove redundant chip select compatible string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the compatible “qcom,nandcs” is being used for each connected NAND device to support for multiple NAND devices in the same bus. The same thing can be achieved by looking reg property for each sub nodes which contains the chip select number so this patch removes the use of “qcom,nandcs” for specifying NAND device sub nodes. Since there is no user for this driver currently in so changing compatible string is safe. Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 9c4c1ccb5d0f..ec5ec2c4b688 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -2127,22 +2127,20 @@ static int qcom_nandc_probe(struct platform_device *pdev) goto err_setup; for_each_available_child_of_node(dn, child) { - if (of_device_is_compatible(child, "qcom,nandcs")) { - host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); - if (!host) { - of_node_put(child); - ret = -ENOMEM; - goto err_cs_init; - } - - ret = qcom_nand_host_init(nandc, host, child); - if (ret) { - devm_kfree(dev, host); - continue; - } - - list_add_tail(&host->node, &nandc->host_list); + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) { + of_node_put(child); + ret = -ENOMEM; + goto err_cs_init; } + + ret = qcom_nand_host_init(nandc, host, child); + if (ret) { + devm_kfree(dev, host); + continue; + } + + list_add_tail(&host->node, &nandc->host_list); } if (list_empty(&nandc->host_list)) { From 4d4f2121369d5f2a4180a6b64046c8494817619f Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:54 +0530 Subject: [PATCH 09/51] dt-bindings: qcom_nandc: remove chip select compatible string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the compatible “qcom,nandcs” is being used for each connected NAND device to support for multiple NAND devices in the same bus. The same thing can be achieved by looking reg property for each sub nodes which contains the chip select number so this patch removes the use of “qcom,nandcs” for specifying NAND device sub nodes. Since there is no user for this driver currently in so changing compatible string is safe. Signed-off-by: Abhishek Sahu Acked-by: Rob Herring Signed-off-by: Boris Brezillon --- Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt index 70dd5118a324..26360fe51663 100644 --- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt +++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt @@ -26,7 +26,6 @@ chip-selects which (may) contain NAND flash chips. Their properties are as follows. Required properties: -- compatible: should contain "qcom,nandcs" - reg: a single integer representing the chip-select number (e.g., 0, 1, 2, etc.) - #address-cells: see partition.txt @@ -60,7 +59,6 @@ nand@1ac00000 { #size-cells = <0>; nandcs@0 { - compatible = "qcom,nandcs"; reg = <0>; nand-ecc-strength = <4>; From bde4330aad1b775853431f9abe014a909c945726 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:55 +0530 Subject: [PATCH 10/51] mtd: nand: qcom: reorganize nand page read Each NAND page consist of multiple codewords. Following is sequence for NAND page read according to hardware guide. 1. Program Power-up configuration, page row, page column address and flash configuration registers. 2. Write NAND_FLASH_CMD followed by NANC_EXEC_CMD for each codeword. 3. Read NAND_FLASH_STATUS for each codeword. The step 1 should be done once for each page and step 2,3 should be done for each codeword. Currently, all the 3 steps are being done for each codeword which is wrong. Now this patch reorganizes read page functions to configure page specific register once and per codeword specific registers for each NAND ECC step. Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 37 +++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index ec5ec2c4b688..97a4c080ce7a 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -602,15 +602,23 @@ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, } /* - * helper to prepare dma descriptors to configure registers needed for reading a - * codeword/step in a page + * Helper to prepare DMA descriptors for configuring registers + * before reading a NAND page. */ -static void config_cw_read(struct qcom_nand_controller *nandc) +static void config_nand_page_read(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_FLASH_CMD, 3); + write_reg_dma(nandc, NAND_ADDR0, 2); write_reg_dma(nandc, NAND_DEV0_CFG0, 3); write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1); +} +/* + * Helper to prepare DMA descriptors for configuring registers + * before reading each codeword in NAND page. + */ +static void config_nand_cw_read(struct qcom_nand_controller *nandc) +{ + write_reg_dma(nandc, NAND_FLASH_CMD, 1); write_reg_dma(nandc, NAND_EXEC_CMD, 1); read_reg_dma(nandc, NAND_FLASH_STATUS, 2); @@ -618,9 +626,15 @@ static void config_cw_read(struct qcom_nand_controller *nandc) } /* - * helpers to prepare dma descriptors used to configure registers needed for - * writing a codeword/step in a page + * Helper to prepare dma descriptors to configure registers needed for reading a + * single codeword in page */ +static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc) +{ + config_nand_page_read(nandc); + config_nand_cw_read(nandc); +} + static void config_cw_write_pre(struct qcom_nand_controller *nandc) { write_reg_dma(nandc, NAND_FLASH_CMD, 3); @@ -689,7 +703,7 @@ static int nandc_param(struct qcom_nand_host *host) nandc->buf_count = 512; memset(nandc->data_buffer, 0xff, nandc->buf_count); - config_cw_read(nandc); + config_nand_single_cw_page_read(nandc); read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, nandc->buf_count); @@ -1102,6 +1116,8 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, struct nand_ecc_ctrl *ecc = &chip->ecc; int i, ret; + config_nand_page_read(nandc); + /* queue cmd descs for each codeword */ for (i = 0; i < ecc->steps; i++) { int data_size, oob_size; @@ -1115,7 +1131,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, oob_size = host->ecc_bytes_hw + host->spare_bytes; } - config_cw_read(nandc); + config_nand_cw_read(nandc); if (data_buf) read_data_dma(nandc, FLASH_BUF_ACC, data_buf, @@ -1175,7 +1191,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) set_address(host, host->cw_size * (ecc->steps - 1), page); update_rw_regs(host, 1, true); - config_cw_read(nandc); + config_nand_single_cw_page_read(nandc); read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size); @@ -1225,6 +1241,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, host->use_ecc = false; update_rw_regs(host, ecc->steps, true); + config_nand_page_read(nandc); for (i = 0; i < ecc->steps; i++) { int data_size1, data_size2, oob_size1, oob_size2; @@ -1243,7 +1260,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } - config_cw_read(nandc); + config_nand_cw_read(nandc); read_data_dma(nandc, reg_off, data_buf, data_size1); reg_off += data_size1; From 77cc5364770387380dd5353625986576209de21c Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:56 +0530 Subject: [PATCH 11/51] mtd: nand: qcom: reorganize nand page write Each NAND page consist of multiple codewords. Following is sequence for NAND page write according to hardware guide. 1. Program Power-up configuration, page row, page column address and flash configuration registers. 2. Write NAND_FLASH_CMD followed by NANC_EXEC_CMD for each codeword. 3. Read NAND_FLASH_STATUS for each codeword. The step 1 should be done once for each page and step 2,3 should be done for each codeword. Currently, all the 3 steps are being done for each codeword which is wrong. Now this patch reorganizes page write functions to configure page specific register once and per codeword specific registers for each NAND ECC step. Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 97a4c080ce7a..52c0287730e8 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -635,15 +635,24 @@ static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc) config_nand_cw_read(nandc); } -static void config_cw_write_pre(struct qcom_nand_controller *nandc) +/* + * Helper to prepare DMA descriptors used to configure registers needed for + * before writing a NAND page. + */ +static void config_nand_page_write(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_FLASH_CMD, 3); + write_reg_dma(nandc, NAND_ADDR0, 2); write_reg_dma(nandc, NAND_DEV0_CFG0, 3); write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1); } -static void config_cw_write_post(struct qcom_nand_controller *nandc) +/* + * Helper to prepare DMA descriptors for configuring registers + * before writing each codeword in NAND page. + */ +static void config_nand_cw_write(struct qcom_nand_controller *nandc) { + write_reg_dma(nandc, NAND_FLASH_CMD, 1); write_reg_dma(nandc, NAND_EXEC_CMD, 1); read_reg_dma(nandc, NAND_FLASH_STATUS, 1); @@ -1326,6 +1335,7 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, host->use_ecc = true; update_rw_regs(host, ecc->steps, false); + config_nand_page_write(nandc); for (i = 0; i < ecc->steps; i++) { int data_size, oob_size; @@ -1339,7 +1349,6 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, oob_size = ecc->bytes; } - config_cw_write_pre(nandc); write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size); @@ -1357,7 +1366,7 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, oob_buf, oob_size); } - config_cw_write_post(nandc); + config_nand_cw_write(nandc); data_buf += data_size; oob_buf += oob_size; @@ -1390,6 +1399,7 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, host->use_ecc = false; update_rw_regs(host, ecc->steps, false); + config_nand_page_write(nandc); for (i = 0; i < ecc->steps; i++) { int data_size1, data_size2, oob_size1, oob_size2; @@ -1408,8 +1418,6 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } - config_cw_write_pre(nandc); - write_data_dma(nandc, reg_off, data_buf, data_size1); reg_off += data_size1; data_buf += data_size1; @@ -1425,7 +1433,7 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, write_data_dma(nandc, reg_off, oob_buf, oob_size2); oob_buf += oob_size2; - config_cw_write_post(nandc); + config_nand_cw_write(nandc); } ret = submit_descs(nandc); @@ -1475,10 +1483,10 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, set_address(host, host->cw_size * (ecc->steps - 1), page); update_rw_regs(host, 1, false); - config_cw_write_pre(nandc); + config_nand_page_write(nandc); write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, data_size + oob_size); - config_cw_write_post(nandc); + config_nand_cw_write(nandc); ret = submit_descs(nandc); @@ -1560,9 +1568,9 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) set_address(host, host->cw_size * (ecc->steps - 1), page); update_rw_regs(host, 1, false); - config_cw_write_pre(nandc); + config_nand_page_write(nandc); write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, host->cw_size); - config_cw_write_post(nandc); + config_nand_cw_write(nandc); ret = submit_descs(nandc); From eb6df28ef63d0ac9d8bb86483d8840fa95da4a8b Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:57 +0530 Subject: [PATCH 12/51] mtd: nand: qcom: remove memset for clearing read register buffer The memset in clear_read_regs is overhead. All the register data will be filled by DMA during NAND operation so making these register variables zero is not required. Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 52c0287730e8..02be4ac0f101 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -823,8 +823,6 @@ static void free_descs(struct qcom_nand_controller *nandc) static void clear_read_regs(struct qcom_nand_controller *nandc) { nandc->reg_read_pos = 0; - memset(nandc->reg_read_buf, 0, - MAX_REG_RD * sizeof(*nandc->reg_read_buf)); } static void pre_command(struct qcom_nand_host *host, int command) From 89f5127c4b0dcd847a2a0b5d0be37ca7366af9e5 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:58 +0530 Subject: [PATCH 13/51] mtd: nand: qcom: reorganize nand devices probing The NAND controller can support multiple NAND devices having different page sizes. Future code will require us to allocate memory based on the maximum number of codewords among all the devices. We reorganize the NAND device probing such that the ONFI parameters are first read for each connected device to identify the maximum number of codewords possible, and only then proceed with MTD device registration (i.e, call nand_scan_tail and mtd_device_register). This is a reorganization of the existing code and will not change any functionality. Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 88 +++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 02be4ac0f101..0e727d79f2ce 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -2057,14 +2057,67 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc, return ret; ret = qcom_nand_host_setup(host); - if (ret) - return ret; + + return ret; +} + +static int qcom_nand_mtd_register(struct qcom_nand_controller *nandc, + struct qcom_nand_host *host, + struct device_node *dn) +{ + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; ret = nand_scan_tail(mtd); if (ret) return ret; - return mtd_device_register(mtd, NULL, 0); + ret = mtd_device_register(mtd, NULL, 0); + if (ret) + nand_cleanup(mtd_to_nand(mtd)); + + return ret; +} + +static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc) +{ + struct device *dev = nandc->dev; + struct device_node *dn = dev->of_node, *child; + struct qcom_nand_host *host, *tmp; + int ret; + + for_each_available_child_of_node(dn, child) { + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) { + of_node_put(child); + return -ENOMEM; + } + + ret = qcom_nand_host_init(nandc, host, child); + if (ret) { + devm_kfree(dev, host); + continue; + } + + list_add_tail(&host->node, &nandc->host_list); + } + + if (list_empty(&nandc->host_list)) + return -ENODEV; + + list_for_each_entry_safe(host, tmp, &nandc->host_list, node) { + ret = qcom_nand_mtd_register(nandc, host, child); + if (ret) { + list_del(&host->node); + devm_kfree(dev, host); + } + } + + if (list_empty(&nandc->host_list)) + return -ENODEV; + + return 0; } /* parse custom DT properties here */ @@ -2092,10 +2145,8 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) static int qcom_nandc_probe(struct platform_device *pdev) { struct qcom_nand_controller *nandc; - struct qcom_nand_host *host; const void *dev_data; struct device *dev = &pdev->dev; - struct device_node *dn = dev->of_node, *child; struct resource *res; int ret; @@ -2149,33 +2200,12 @@ static int qcom_nandc_probe(struct platform_device *pdev) if (ret) goto err_setup; - for_each_available_child_of_node(dn, child) { - host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); - if (!host) { - of_node_put(child); - ret = -ENOMEM; - goto err_cs_init; - } - - ret = qcom_nand_host_init(nandc, host, child); - if (ret) { - devm_kfree(dev, host); - continue; - } - - list_add_tail(&host->node, &nandc->host_list); - } - - if (list_empty(&nandc->host_list)) { - ret = -ENODEV; - goto err_cs_init; - } + ret = qcom_probe_nand_devices(nandc); + if (ret) + goto err_setup; return 0; -err_cs_init: - list_for_each_entry(host, &nandc->host_list, node) - nand_release(nand_to_mtd(&host->chip)); err_setup: clk_disable_unprepare(nandc->aon_clk); err_aon_clk: From 1498fbaf700ff100486e864776743a9e14e5169c Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 19 Jul 2017 17:31:25 +0200 Subject: [PATCH 14/51] mtd: nand: pxa3xx_nand: enable building on mvebu 64-bit platforms The controller supported by the pxa3xx_nand driver is also available on the mvebu 64-bit SoCs, such as the Armada 7K and Armada 8K SoCs. This patch updates the Kconfig dependency to allow building the kernel for this SoC family too. Signed-off-by: Gregory CLEMENT Signed-off-by: Boris Brezillon --- drivers/mtd/nand/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index dbfa72d61d5a..3f2036f31da4 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -315,7 +315,7 @@ config MTD_NAND_ATMEL config MTD_NAND_PXA3xx tristate "NAND support on PXA3xx and Armada 370/XP" - depends on PXA3xx || ARCH_MMP || PLAT_ORION + depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU help This enables the driver for the NAND flash device found on PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2). From 55bafbc277dcce7aab0ba28563075f3b517e6134 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 21 Jul 2017 22:38:06 +0200 Subject: [PATCH 15/51] mtd: orion-nand: fix build error with ARMv4 orion_nand_read_buf uses an inline assembly with the "ldrd" instruction, which is only available from ARMv5 upwards. This used to be fine, since all users have an ARMv5 or ARMv7 CPU, but now we can also build a multiplatform kernel with ARMv4 support enabled in addition to the "kirkwood" (mvebu) platform. This provides an alternative to call the readsl() function that is supposed to have the same effect and is also optimized for performance. I first posted a version of this patch back in 2014, and there was some discussion about it then. This fixes the bugs identified back then and should be a reasonable alternative for the rare corner case. Link: https://patchwork.kernel.org/patch/4144791/ Cc: Jingoo Han Signed-off-by: Arnd Bergmann Signed-off-by: Boris Brezillon --- drivers/mtd/nand/orion_nand.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 209170ed2b76..41cb7acfc044 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -54,13 +54,16 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { struct nand_chip *chip = mtd_to_nand(mtd); void __iomem *io_base = chip->IO_ADDR_R; +#if __LINUX_ARM_ARCH__ >= 5 uint64_t *buf64; +#endif int i = 0; while (len && (unsigned long)buf & 7) { *buf++ = readb(io_base); len--; } +#if __LINUX_ARM_ARCH__ >= 5 buf64 = (uint64_t *)buf; while (i < len/8) { /* @@ -74,6 +77,10 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) buf64[i++] = x; } i *= 8; +#else + readsl(io_base, buf, len/4); + i = len / 4 * 4; +#endif while (i < len) buf[i++] = readb(io_base); } From c044179ea14db0855edc3d8f82bd998202167368 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:05:09 +0530 Subject: [PATCH 16/51] mtd: nand: denali: Handle return value of clk_prepare_enable. clk_prepare_enable() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali_dt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 47f398edf18f..56e2e177644d 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -118,7 +118,9 @@ static int denali_dt_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no clk available\n"); return PTR_ERR(dt->clk); } - clk_prepare_enable(dt->clk); + ret = clk_prepare_enable(dt->clk); + if (ret) + return ret; denali->clk_x_rate = clk_get_rate(dt->clk); From 24c9cd8f8d26194aa1a4077c62df90d657766235 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:07:27 +0530 Subject: [PATCH 17/51] mtd: oxnas_nand: Handle clk_prepare_enable/clk_disable_unprepare. - clk_prepare_enable() can fail here and we must check its return value. - oxnas_nand_probe() can fail here and we must disable clock. Signed-off-by: Arvind Yadav Acked-by: Neil Armstrong Signed-off-by: Boris Brezillon --- drivers/mtd/nand/oxnas_nand.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c index 1b207aac840c..7061bb2923b4 100644 --- a/drivers/mtd/nand/oxnas_nand.c +++ b/drivers/mtd/nand/oxnas_nand.c @@ -112,14 +112,19 @@ static int oxnas_nand_probe(struct platform_device *pdev) if (count > 1) return -EINVAL; - clk_prepare_enable(oxnas->clk); + err = clk_prepare_enable(oxnas->clk); + if (err) + return err; + device_reset_optional(&pdev->dev); for_each_child_of_node(np, nand_np) { chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; + if (!chip) { + err = -ENOMEM; + goto err_clk_unprepare; + } chip->controller = &oxnas->base; @@ -139,12 +144,12 @@ static int oxnas_nand_probe(struct platform_device *pdev) /* Scan to find existence of the device */ err = nand_scan(mtd, 1); if (err) - return err; + goto err_clk_unprepare; err = mtd_device_register(mtd, NULL, 0); if (err) { nand_release(mtd); - return err; + goto err_clk_unprepare; } oxnas->chips[nchips] = chip; @@ -152,12 +157,18 @@ static int oxnas_nand_probe(struct platform_device *pdev) } /* Exit if no chips found */ - if (!nchips) - return -ENODEV; + if (!nchips) { + err = -ENODEV; + goto err_clk_unprepare; + } platform_set_drvdata(pdev, oxnas); return 0; + +err_clk_unprepare: + clk_disable_unprepare(oxnas->clk); + return err; } static int oxnas_nand_remove(struct platform_device *pdev) From 7c94128127ba6ecbaa1e2085088c7337a99aaf51 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:08:06 +0530 Subject: [PATCH 18/51] mtd: nand: lpc32xx_slc: Handle return value of clk_prepare_enable. clk_prepare_enable() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/nand/lpc32xx_slc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index a0669a33f8fe..80c282914586 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -840,7 +840,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) res = -ENOENT; goto err_exit1; } - clk_prepare_enable(host->clk); + res = clk_prepare_enable(host->clk); + if (res) + goto err_exit1; /* Set NAND IO addresses and command/ready functions */ chip->IO_ADDR_R = SLC_DATA(host->io_base); @@ -972,9 +974,12 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) static int lpc32xx_nand_resume(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + int ret; /* Re-enable NAND clock */ - clk_prepare_enable(host->clk); + ret = clk_prepare_enable(host->clk); + if (ret) + return ret; /* Fresh init of NAND controller */ lpc32xx_nand_setup(host); From 4d26f012ab591d7671237a6b5e990cbbfd50b0b8 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:10:11 +0530 Subject: [PATCH 19/51] mtd: nand: lpc32xx_mlc: Handle return value of clk_prepare_enable. clk_prepare_enable() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/nand/lpc32xx_mlc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 846a66c1b133..91ee369681f0 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -705,7 +705,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) res = -ENOENT; goto err_exit1; } - clk_prepare_enable(host->clk); + res = clk_prepare_enable(host->clk); + if (res) + goto err_exit1; nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; nand_chip->dev_ready = lpc32xx_nand_device_ready; @@ -846,9 +848,12 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) static int lpc32xx_nand_resume(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + int ret; /* Re-enable NAND clock */ - clk_prepare_enable(host->clk); + ret = clk_prepare_enable(host->clk); + if (ret) + return ret; /* Fresh init of NAND controller */ lpc32xx_nand_setup(host); From 481815a6193bb7a1e43f8babecde5155e65f3858 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:10:58 +0530 Subject: [PATCH 20/51] mtd: st_spi_fsm: Handle clk_prepare_enable/clk_disable_unprepare. - clk_prepare_enable() can fail here and we must check its return value. - stfsm_probe() can fail here and we must disable clock. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/devices/st_spi_fsm.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index 21afd94cd904..7bc29d725200 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -2073,15 +2073,17 @@ static int stfsm_probe(struct platform_device *pdev) ret = stfsm_init(fsm); if (ret) { dev_err(&pdev->dev, "Failed to initialise FSM Controller\n"); - return ret; + goto err_clk_unprepare; } stfsm_fetch_platform_configs(pdev); /* Detect SPI FLASH device */ info = stfsm_jedec_probe(fsm); - if (!info) - return -ENODEV; + if (!info) { + ret = -ENODEV; + goto err_clk_unprepare; + } fsm->info = info; /* Use device size to determine address width */ @@ -2095,11 +2097,11 @@ static int stfsm_probe(struct platform_device *pdev) if (info->config) { ret = info->config(fsm); if (ret) - return ret; + goto err_clk_unprepare; } else { ret = stfsm_prepare_rwe_seqs_default(fsm); if (ret) - return ret; + goto err_clk_unprepare; } fsm->mtd.name = info->name; @@ -2124,6 +2126,10 @@ static int stfsm_probe(struct platform_device *pdev) fsm->mtd.erasesize, (fsm->mtd.erasesize >> 10)); return mtd_device_register(&fsm->mtd, NULL, 0); + +err_clk_unprepare: + clk_disable_unprepare(fsm->clk); + return ret; } static int stfsm_remove(struct platform_device *pdev) @@ -2147,9 +2153,7 @@ static int stfsmfsm_resume(struct device *dev) { struct stfsm *fsm = dev_get_drvdata(dev); - clk_prepare_enable(fsm->clk); - - return 0; + return clk_prepare_enable(fsm->clk); } #endif From fcf59f1ff525bc6400a893e2a0820afcf815f4c3 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:25:46 +0200 Subject: [PATCH 21/51] mtd: nand: sunxi: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Boris Brezillon Cc: Richard Weinberger Cc: David Woodhouse Cc: Brian Norris Cc: Marek Vasut Cc: Cyrille Pitchen Cc: Maxime Ripard Cc: Chen-Yu Tsai Cc: linux-mtd@lists.infradead.org Signed-off-by: Philipp Zabel Signed-off-by: Boris Brezillon --- drivers/mtd/nand/sunxi_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index d0b6f8f9f297..6eb97451f485 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -2208,7 +2208,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev) if (ret) goto out_ahb_clk_unprepare; - nfc->reset = devm_reset_control_get_optional(dev, "ahb"); + nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb"); if (IS_ERR(nfc->reset)) { ret = PTR_ERR(nfc->reset); goto out_mod_clk_unprepare; From 3bff08dffe3115a25ce04b95ea75f6d868572c60 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 25 Nov 2016 11:32:32 +0100 Subject: [PATCH 22/51] mtd: nand: mxc: Fix mxc_v1 ooblayout Commit a894cf6c5a82 ("mtd: nand: mxc: switch to mtd_ooblayout_ops") introduced a bug in the OOB layout description. Even if the driver claims that 3 ECC bytes are reserved to protect 512 bytes of data, it's actually 5 ECC bytes to protect 512+6 bytes of data (some OOB bytes are also protected using extra ECC bytes). Fix the mxc_v1_ooblayout_{free,ecc}() functions to reflect this behavior. Signed-off-by: Boris Brezillon Fixes: a894cf6c5a82 ("mtd: nand: mxc: switch to mtd_ooblayout_ops") Cc: Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a764d5ca7536..5bedf7bc3d88 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -876,6 +876,8 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) } } +#define MXC_V1_ECCBYTES 5 + static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { @@ -885,7 +887,7 @@ static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section, return -ERANGE; oobregion->offset = (section * 16) + 6; - oobregion->length = nand_chip->ecc.bytes; + oobregion->length = MXC_V1_ECCBYTES; return 0; } @@ -907,8 +909,7 @@ static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section, oobregion->length = 4; } } else { - oobregion->offset = ((section - 1) * 16) + - nand_chip->ecc.bytes + 6; + oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6; if (section < nand_chip->ecc.steps) oobregion->length = (section * 16) + 6 - oobregion->offset; From fd213b5bae800dc00a2930dcd07f63ab9bbff3f9 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 5 Aug 2017 14:16:24 +0200 Subject: [PATCH 23/51] mtd: nand: hynix: add support for 20nm NAND chips According to the datasheet of the H27UCG8T2BTR the NAND Technology field (6th byte of the "Device Identifier Description", bits 0-2) the following values are possible: - 0x0 = 48nm - 0x1 = 41nm - 0x2 = 32nm - 0x3 = 26nm - 0x4 = 20nm - (all others are reserved) Fix this by extending the mask for this field to allow detecting value 0x4 (20nm) as valid NAND technology. Without this the detection of the ECC requirements fails, because the code assumes that the device is a 48nm device (0x4 & 0x3 = 0x0) and aborts with "Invalid ECC requirements" because it cannot map the "ECC Level". Extending the mask makes the ECC requirement detection code recognize this chip as <= 26nm and sets up the ECC step size and ECC strength correctly. Signed-off-by: Martin Blumenstingl Fixes: 78f3482d7480 ("mtd: nand: hynix: Rework NAND ID decoding to extract more information") Cc: Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_hynix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c index b12dc7325378..bd9a6e343848 100644 --- a/drivers/mtd/nand/nand_hynix.c +++ b/drivers/mtd/nand/nand_hynix.c @@ -477,7 +477,7 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip, * The ECC requirements field meaning depends on the * NAND technology. */ - u8 nand_tech = chip->id.data[5] & 0x3; + u8 nand_tech = chip->id.data[5] & 0x7; if (nand_tech < 3) { /* > 26nm, reference: H27UBG8T2A datasheet */ @@ -533,7 +533,7 @@ static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip, if (nand_tech > 0) chip->options |= NAND_NEED_SCRAMBLING; } else { - nand_tech = chip->id.data[5] & 0x3; + nand_tech = chip->id.data[5] & 0x7; /* < 32nm */ if (nand_tech > 2) From 892dd1831392adbdf4e55d0c284c3aea6ba4d855 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 6 Aug 2017 00:14:28 +0300 Subject: [PATCH 24/51] mtd: nand: atmel: fix of_irq_get() error check of_irq_get() may return 0 as well as negative error number on failure, while the driver only checks for the negative values. The driver would then call devm_request_irq() for IRQ0 in its probe method and never get a valid interrupt. Check for 'nc->irq <= 0' instead and return -ENXIO from the driver's probe if of_irq_get() returned 0. Fixes: f88fc122cc34 ("mtd: nand: Cleanup/rework the atmel_nand driver") Signed-off-by: Sergei Shtylyov Acked-by: Wenyou Yang Signed-off-by: Boris Brezillon --- drivers/mtd/nand/atmel/nand-controller.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index d922a88e407f..6b9d0ba3d707 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -2078,8 +2078,8 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc) } nc->irq = of_irq_get(nand_np, 0); - if (nc->irq < 0) { - ret = nc->irq; + if (nc->irq <= 0) { + ret = nc->irq ?: -ENXIO; if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to get IRQ number (err = %d)\n", ret); @@ -2168,11 +2168,12 @@ atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc) nc->irq = of_irq_get(np, 0); of_node_put(np); - if (nc->irq < 0) { - if (nc->irq != -EPROBE_DEFER) + if (nc->irq <= 0) { + ret = nc->irq ?: -ENXIO; + if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to get IRQ number (err = %d)\n", - nc->irq); - return nc->irq; + ret); + return ret; } np = of_parse_phandle(dev->of_node, "atmel,nfc-io", 0); From dbf5f6424ed92131b2d5bf363a0176d8a9f531ef Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Tue, 8 Aug 2017 22:35:42 +0800 Subject: [PATCH 25/51] mtd: nand: sh_flctl: use dma_mapping_error to check map errors The return value of dma_map_single() should be checked by dma_mapping_error(). However, in function flctl_dma_fifo0_transfer(), its return value is checked against NULL, which could result in failures. Signed-off-by: Pan Bian Signed-off-by: Boris Brezillon --- drivers/mtd/nand/sh_flctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 891ac7b99305..2404d6634bda 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -411,7 +411,7 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf, dma_addr = dma_map_single(chan->device->dev, buf, len, dir); - if (dma_addr) + if (!dma_mapping_error(chan->device->dev, dma_addr)) desc = dmaengine_prep_slave_single(chan, dma_addr, len, tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); From 2192a8ddc11ad7f243bed44eef4add8e37a658fe Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Aug 2017 11:29:21 -0500 Subject: [PATCH 26/51] mtd: nand: sh_flctl: fix error return code in flctl_probe() platform_get_irq() returns an error code, but the sh_flctl driver ignores it and always returns -ENXIO. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Boris Brezillon --- drivers/mtd/nand/sh_flctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 2404d6634bda..d2afd57bc1f2 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -1141,8 +1141,8 @@ static int flctl_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "failed to get flste irq data\n"); - return -ENXIO; + dev_err(&pdev->dev, "failed to get flste irq data: %d\n", irq); + return irq; } ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED, From 238709b22097a16839078530e0a10812dde86f16 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Aug 2017 11:35:21 -0500 Subject: [PATCH 27/51] mtd: nand: mtk: fix error return code in mtk_ecc_probe() platform_get_irq() returns an error code, but the mtk_ecc driver ignores it and always returns -EINVAL. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mtk_ecc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c index 6c3a4aab0b48..7f3b065b6b8f 100644 --- a/drivers/mtd/nand/mtk_ecc.c +++ b/drivers/mtd/nand/mtk_ecc.c @@ -464,8 +464,8 @@ static int mtk_ecc_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "failed to get irq\n"); - return -EINVAL; + dev_err(dev, "failed to get irq: %d\n", irq); + return irq; } ret = dma_set_mask(dev, DMA_BIT_MASK(32)); From d8a9b320a26c1ea28e51e4f3ecfb593d5aac2910 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Fri, 11 Aug 2017 17:09:16 +0530 Subject: [PATCH 28/51] mtd: nand: qcom: fix read failure without complete bootchain The NAND page read fails without complete boot chain since NAND_DEV_CMD_VLD value is not proper. The default power on reset value for this register is 0xe - ERASE_START_VALID | WRITE_START_VALID | READ_STOP_VALID The READ_START_VALID should be enabled for sending PAGE_READ command. READ_STOP_VALID should be cleared since normal NAND page read does not require READ_STOP command. Fixes: c76b78d8ec05a ("mtd: nand: Qualcomm NAND controller driver") Cc: stable@vger.kernel.org Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 0e727d79f2ce..e5cb8f12d5bb 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -109,7 +109,11 @@ #define READ_ADDR 0 /* NAND_DEV_CMD_VLD bits */ -#define READ_START_VLD 0 +#define READ_START_VLD BIT(0) +#define READ_STOP_VLD BIT(1) +#define WRITE_START_VLD BIT(2) +#define ERASE_START_VLD BIT(3) +#define SEQ_READ_START_VLD BIT(4) /* NAND_EBI2_ECC_BUF_CFG bits */ #define NUM_STEPS 0 @@ -148,6 +152,10 @@ #define FETCH_ID 0xb #define RESET_DEVICE 0xd +/* Default Value for NAND_DEV_CMD_VLD */ +#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ + ERASE_START_VLD | SEQ_READ_START_VLD) + /* * the NAND controller performs reads/writes with ECC in 516 byte chunks. * the driver calls the chunks 'step' or 'codeword' interchangeably @@ -695,8 +703,7 @@ static int nandc_param(struct qcom_nand_host *host) /* configure CMD1 and VLD for ONFI param probing */ nandc_set_reg(nandc, NAND_DEV_CMD_VLD, - (nandc->vld & ~(1 << READ_START_VLD)) - | 0 << READ_START_VLD); + (nandc->vld & ~READ_START_VLD)); nandc_set_reg(nandc, NAND_DEV_CMD1, (nandc->cmd1 & ~(0xFF << READ_ADDR)) | NAND_CMD_PARAM << READ_ADDR); @@ -1995,13 +2002,14 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) { /* kill onenand */ nandc_write(nandc, SFLASHC_BURST_CFG, 0); + nandc_write(nandc, NAND_DEV_CMD_VLD, NAND_DEV_CMD_VLD_VAL); /* enable ADM DMA */ nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); /* save the original values of these registers */ nandc->cmd1 = nandc_read(nandc, NAND_DEV_CMD1); - nandc->vld = nandc_read(nandc, NAND_DEV_CMD_VLD); + nandc->vld = NAND_DEV_CMD_VLD_VAL; return 0; } From 58f1f22ac34c39958344cd1ae8a89e1030dcdbbd Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Fri, 11 Aug 2017 17:09:17 +0530 Subject: [PATCH 29/51] mtd: nand: qcom: support for NAND controller properties Currently driver data is being assigned directly with ECC modes. Now, the plan is to add more NAND controller versions which will have different properties. This patch reorganizes the current driver data assignment by creating NAND controller properties structure which will contain all properties specific to NAND controller. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index e5cb8f12d5bb..79f7de82a708 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -240,7 +240,7 @@ struct nandc_regs { * writes. contains the register values to be * written to controller * @cmd1/vld: some fixed controller register values - * @ecc_modes: supported ECC modes by the current controller, + * @props: properties of current NAND controller, * initialized via DT match data */ struct qcom_nand_controller { @@ -271,7 +271,7 @@ struct qcom_nand_controller { struct nandc_regs *regs; u32 cmd1, vld; - u32 ecc_modes; + const struct qcom_nandc_props *props; }; /* @@ -324,6 +324,15 @@ struct qcom_nand_host { u32 clrreadstatus; }; +/* + * This data type corresponds to the NAND controller properties which varies + * among different NAND controllers. + * @ecc_modes - ecc mode for NAND + */ +struct qcom_nandc_props { + u32 ecc_modes; +}; + static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) { return container_of(chip, struct qcom_nand_host, chip); @@ -1824,7 +1833,7 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host) * uses lesser bytes for ECC. If RS is used, the ECC bytes is * always 10 bytes */ - if (nandc->ecc_modes & ECC_BCH_4BIT) { + if (nandc->props->ecc_modes & ECC_BCH_4BIT) { /* BCH */ host->bch_enabled = true; ecc_mode = 0; @@ -2171,7 +2180,7 @@ static int qcom_nandc_probe(struct platform_device *pdev) return -ENODEV; } - nandc->ecc_modes = (unsigned long)dev_data; + nandc->props = dev_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nandc->base = devm_ioremap_resource(dev, res); @@ -2240,15 +2249,18 @@ static int qcom_nandc_remove(struct platform_device *pdev) return 0; } -#define EBI2_NANDC_ECC_MODES (ECC_RS_4BIT | ECC_BCH_8BIT) +static const struct qcom_nandc_props ipq806x_nandc_props = { + .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), +}; /* * data will hold a struct pointer containing more differences once we support * more controller variants */ static const struct of_device_id qcom_nandc_of_match[] = { - { .compatible = "qcom,ipq806x-nand", - .data = (void *)EBI2_NANDC_ECC_MODES, + { + .compatible = "qcom,ipq806x-nand", + .data = &ipq806x_nandc_props, }, {} }; From 8c5d5d6a0bc62bebed37f306b80ab125fa3fbb8d Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Fri, 11 Aug 2017 17:09:18 +0530 Subject: [PATCH 30/51] mtd: nand: qcom: add bam property for QPIC NAND controller The current driver only supports EBI2 NAND controller which uses ADM DMA. The latest QCOM SoC uses QPIC NAND controller with BAM DMA. NAND registers and programming sequence are same for EBI2 and QPIC NAND so the same driver can support QPIC NAND also by adding the BAM DMA support. This patch adds the is_bam in NAND property which will be checked for determining the DMA engine type. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 79f7de82a708..2d44eeba553c 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -328,9 +328,11 @@ struct qcom_nand_host { * This data type corresponds to the NAND controller properties which varies * among different NAND controllers. * @ecc_modes - ecc mode for NAND + * @is_bam - whether NAND controller is using BAM */ struct qcom_nandc_props { u32 ecc_modes; + bool is_bam; }; static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) @@ -2251,6 +2253,7 @@ static int qcom_nandc_remove(struct platform_device *pdev) static const struct qcom_nandc_props ipq806x_nandc_props = { .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), + .is_bam = false, }; /* From 497d7d852a48a28b5f98f1a994195d3c16f591fc Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Fri, 11 Aug 2017 17:09:19 +0530 Subject: [PATCH 31/51] mtd: nand: qcom: add and initialize QPIC DMA resources 1. QPIC NAND controller uses 3 BAM channels: command, data tx and data rx while EBI2 NAND controller uses only single ADM channel. 2. CRCI is only required for ADM DMA and it's not required for BAM DMA. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 86 +++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 2d44eeba553c..59b764a347d3 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -255,9 +255,22 @@ struct qcom_nand_controller { struct clk *core_clk; struct clk *aon_clk; - struct dma_chan *chan; - unsigned int cmd_crci; - unsigned int data_crci; + union { + /* will be used only by QPIC for BAM DMA */ + struct { + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; + struct dma_chan *cmd_chan; + }; + + /* will be used only by EBI2 for ADM DMA */ + struct { + struct dma_chan *chan; + unsigned int cmd_crci; + unsigned int data_crci; + }; + }; + struct list_head desc_list; u8 *data_buffer; @@ -1989,10 +2002,31 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) if (!nandc->reg_read_buf) return -ENOMEM; - nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx"); - if (!nandc->chan) { - dev_err(nandc->dev, "failed to request slave channel\n"); - return -ENODEV; + if (nandc->props->is_bam) { + nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx"); + if (!nandc->tx_chan) { + dev_err(nandc->dev, "failed to request tx channel\n"); + return -ENODEV; + } + + nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx"); + if (!nandc->rx_chan) { + dev_err(nandc->dev, "failed to request rx channel\n"); + return -ENODEV; + } + + nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd"); + if (!nandc->cmd_chan) { + dev_err(nandc->dev, "failed to request cmd channel\n"); + return -ENODEV; + } + } else { + nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx"); + if (!nandc->chan) { + dev_err(nandc->dev, + "failed to request slave channel\n"); + return -ENODEV; + } } INIT_LIST_HEAD(&nandc->desc_list); @@ -2005,7 +2039,19 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) { - dma_release_channel(nandc->chan); + if (nandc->props->is_bam) { + if (nandc->tx_chan) + dma_release_channel(nandc->tx_chan); + + if (nandc->rx_chan) + dma_release_channel(nandc->rx_chan); + + if (nandc->cmd_chan) + dma_release_channel(nandc->cmd_chan); + } else { + if (nandc->chan) + dma_release_channel(nandc->chan); + } } /* one time setup of a few nand controller registers */ @@ -2146,16 +2192,20 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) struct device_node *np = nandc->dev->of_node; int ret; - ret = of_property_read_u32(np, "qcom,cmd-crci", &nandc->cmd_crci); - if (ret) { - dev_err(nandc->dev, "command CRCI unspecified\n"); - return ret; - } + if (!nandc->props->is_bam) { + ret = of_property_read_u32(np, "qcom,cmd-crci", + &nandc->cmd_crci); + if (ret) { + dev_err(nandc->dev, "command CRCI unspecified\n"); + return ret; + } - ret = of_property_read_u32(np, "qcom,data-crci", &nandc->data_crci); - if (ret) { - dev_err(nandc->dev, "data CRCI unspecified\n"); - return ret; + ret = of_property_read_u32(np, "qcom,data-crci", + &nandc->data_crci); + if (ret) { + dev_err(nandc->dev, "data CRCI unspecified\n"); + return ret; + } } return 0; @@ -2205,7 +2255,7 @@ static int qcom_nandc_probe(struct platform_device *pdev) ret = qcom_nandc_alloc(nandc); if (ret) - return ret; + goto err_core_clk; ret = clk_prepare_enable(nandc->core_clk); if (ret) From 6192ff7a44c1806f4db110f09168fb4e84d2770b Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:39 +0530 Subject: [PATCH 32/51] mtd: nand: qcom: DMA mapping support for register read buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The EBI2 NAND controller directly remaps register read buffer with dma_map_sg and DMA address of this buffer will be passed to DMA API’s. While, on QPIC NAND controller, which uses BAM DMA, we read the controller registers by preparing a BAM command descriptor. This command descriptor requires the - controller register address - the DMA address in which we want to store the value read back from the controller register. This command descriptor will be remapped with dma_map_sg and its DMA address will be passed to DMA API’s. Therefore, it's required that we also map our register read buffer for DMA (using dma_map_single). We use the returned DMA address for preparing entries in our command descriptor. This patch adds the DMA mapping support for register read buffer. This buffer will be DMA mapped during allocation time. Before starting of any operation, this buffer will be synced for device operation and after operation completion, it will be synced again for CPU. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 59b764a347d3..590fc1dd556e 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -234,6 +234,7 @@ struct nandc_regs { * by upper layers directly * @buf_size/count/start: markers for chip->read_buf/write_buf functions * @reg_read_buf: local buffer for reading back registers via DMA + * @reg_read_dma: contains dma address for register read buffer * @reg_read_pos: marker for data read in reg_read_buf * * @regs: a contiguous chunk of memory for DMA register @@ -279,6 +280,7 @@ struct qcom_nand_controller { int buf_start; __le32 *reg_read_buf; + dma_addr_t reg_read_dma; int reg_read_pos; struct nandc_regs *regs; @@ -371,6 +373,24 @@ static inline void nandc_write(struct qcom_nand_controller *nandc, int offset, iowrite32(val, nandc->base + offset); } +static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc, + bool is_cpu) +{ + if (!nandc->props->is_bam) + return; + + if (is_cpu) + dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + else + dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); +} + static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset) { switch (offset) { @@ -854,6 +874,7 @@ static void free_descs(struct qcom_nand_controller *nandc) static void clear_read_regs(struct qcom_nand_controller *nandc) { nandc->reg_read_pos = 0; + nandc_read_buffer_sync(nandc, false); } static void pre_command(struct qcom_nand_host *host, int command) @@ -883,6 +904,7 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command) int i; num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1; + nandc_read_buffer_sync(nandc, true); for (i = 0; i < num_cw; i++) { u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]); @@ -904,6 +926,7 @@ static void post_command(struct qcom_nand_host *host, int command) switch (command) { case NAND_CMD_READID: + nandc_read_buffer_sync(nandc, true); memcpy(nandc->data_buffer, nandc->reg_read_buf, nandc->buf_count); break; @@ -1067,6 +1090,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf, int i; buf = (struct read_stats *)nandc->reg_read_buf; + nandc_read_buffer_sync(nandc, true); for (i = 0; i < ecc->steps; i++, buf++) { u32 flash, buffer, erased_cw; @@ -2003,6 +2027,16 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) return -ENOMEM; if (nandc->props->is_bam) { + nandc->reg_read_dma = + dma_map_single(nandc->dev, nandc->reg_read_buf, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) { + dev_err(nandc->dev, "failed to DMA MAP reg buffer\n"); + return -EIO; + } + nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx"); if (!nandc->tx_chan) { dev_err(nandc->dev, "failed to request tx channel\n"); @@ -2040,6 +2074,12 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) { if (nandc->props->is_bam) { + if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) + dma_unmap_single(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + if (nandc->tx_chan) dma_release_channel(nandc->tx_chan); From cb80f1140db6ad2cb6841ad656cc6b779b4b58be Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:40 +0530 Subject: [PATCH 33/51] mtd: nand: qcom: allocate BAM transaction - The BAM transaction is the core data structure which will be used for all the data transfers in QPIC NAND. Since the core framework in nand_base.c is serializing all the NAND requests so allocating BAM transaction before every transfer will be overhead. The memory for it be allocated during probe time and before every transfer, it will be cleared. - The BAM transaction contains the array of command and data scatter gather list and indexes. For every transfer, all the resource will be taken from BAM transaction. - The size of the buffer used for BAM transactions is calculated based on the NAND device with the maximum page size, among all the devices connected to the controller. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 94 +++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 590fc1dd556e..4f8306e84537 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -177,6 +177,32 @@ #define ECC_BCH_4BIT BIT(2) #define ECC_BCH_8BIT BIT(3) +#define QPIC_PER_CW_CMD_SGL 32 +#define QPIC_PER_CW_DATA_SGL 8 + +/* + * This data type corresponds to the BAM transaction which will be used for all + * NAND transfers. + * @cmd_sgl - sgl for NAND BAM command pipe + * @data_sgl - sgl for NAND BAM consumer/producer pipe + * @cmd_sgl_pos - current index in command sgl. + * @cmd_sgl_start - start index in command sgl. + * @tx_sgl_pos - current index in data sgl for tx. + * @tx_sgl_start - start index in data sgl for tx. + * @rx_sgl_pos - current index in data sgl for rx. + * @rx_sgl_start - start index in data sgl for rx. + */ +struct bam_transaction { + struct scatterlist *cmd_sgl; + struct scatterlist *data_sgl; + u32 cmd_sgl_pos; + u32 cmd_sgl_start; + u32 tx_sgl_pos; + u32 tx_sgl_start; + u32 rx_sgl_pos; + u32 rx_sgl_start; +}; + struct desc_info { struct list_head node; @@ -243,6 +269,8 @@ struct nandc_regs { * @cmd1/vld: some fixed controller register values * @props: properties of current NAND controller, * initialized via DT match data + * @max_cwperpage: maximum QPIC codewords required. calculated + * from all connected NAND devices pagesize */ struct qcom_nand_controller { struct nand_hw_control controller; @@ -273,11 +301,13 @@ struct qcom_nand_controller { }; struct list_head desc_list; + struct bam_transaction *bam_txn; u8 *data_buffer; int buf_size; int buf_count; int buf_start; + unsigned int max_cwperpage; __le32 *reg_read_buf; dma_addr_t reg_read_dma; @@ -350,6 +380,44 @@ struct qcom_nandc_props { bool is_bam; }; +/* Frees the BAM transaction memory */ +static void free_bam_transaction(struct qcom_nand_controller *nandc) +{ + struct bam_transaction *bam_txn = nandc->bam_txn; + + devm_kfree(nandc->dev, bam_txn); +} + +/* Allocates and Initializes the BAM transaction */ +static struct bam_transaction * +alloc_bam_transaction(struct qcom_nand_controller *nandc) +{ + struct bam_transaction *bam_txn; + size_t bam_txn_size; + unsigned int num_cw = nandc->max_cwperpage; + void *bam_txn_buf; + + bam_txn_size = + sizeof(*bam_txn) + num_cw * + ((sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) + + (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL)); + + bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL); + if (!bam_txn_buf) + return NULL; + + bam_txn = bam_txn_buf; + bam_txn_buf += sizeof(*bam_txn); + + bam_txn->cmd_sgl = bam_txn_buf; + bam_txn_buf += + sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw; + + bam_txn->data_sgl = bam_txn_buf; + + return bam_txn; +} + static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) { return container_of(chip, struct qcom_nand_host, chip); @@ -1920,6 +1988,8 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host) mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops); cwperpage = mtd->writesize / ecc->size; + nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage, + cwperpage); /* * DATA_UD_BYTES varies based on whether the read/write command protects @@ -2054,6 +2124,20 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) dev_err(nandc->dev, "failed to request cmd channel\n"); return -ENODEV; } + + /* + * Initially allocate BAM transaction to read ONFI param page. + * After detecting all the devices, this BAM transaction will + * be freed and the next BAM tranasction will be allocated with + * maximum codeword size + */ + nandc->max_cwperpage = 1; + nandc->bam_txn = alloc_bam_transaction(nandc); + if (!nandc->bam_txn) { + dev_err(nandc->dev, + "failed to allocate bam transaction\n"); + return -ENOMEM; + } } else { nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx"); if (!nandc->chan) { @@ -2211,6 +2295,16 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc) if (list_empty(&nandc->host_list)) return -ENODEV; + if (nandc->props->is_bam) { + free_bam_transaction(nandc); + nandc->bam_txn = alloc_bam_transaction(nandc); + if (!nandc->bam_txn) { + dev_err(nandc->dev, + "failed to allocate bam transaction\n"); + return -ENOMEM; + } + } + list_for_each_entry_safe(host, tmp, &nandc->host_list, node) { ret = qcom_nand_mtd_register(nandc, host, child); if (ret) { From 381dd24539a85a4bdec155369e3216e6f267df7d Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:41 +0530 Subject: [PATCH 34/51] mtd: nand: qcom: add BAM DMA descriptor handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. prepare_bam_async_desc is the function which will call all the DMA API’s. It will fetch the outstanding scatter gather list for passed channel and will do the DMA descriptor formation. The DMA flag is dependent upon the type of channel. 2. For ADM DMA, the descriptor is being formed for every DMA request so its sgl count will be always 1 while in BAM DMA, the clubbing of descriptor is being done to increase throughput. 3. ADM DMA uses only one channel while in BAM DMA, data descriptors will be submitted to tx channel (for write) or rx channel (for read) and all the registers read/write descriptors in command channel. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 148 +++++++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 4f8306e84537..f52a69252358 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -203,11 +203,27 @@ struct bam_transaction { u32 rx_sgl_start; }; +/* + * This data type corresponds to the nand dma descriptor + * @list - list for desc_info + * @dir - DMA transfer direction + * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by + * ADM + * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM + * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM + * @dma_desc - low level DMA engine descriptor + */ struct desc_info { struct list_head node; enum dma_data_direction dir; - struct scatterlist sgl; + union { + struct scatterlist adm_sgl; + struct { + struct scatterlist *bam_sgl; + int sgl_cnt; + }; + }; struct dma_async_tx_descriptor *dma_desc; }; @@ -568,9 +584,78 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) nandc_set_reg(nandc, NAND_EXEC_CMD, 1); } -static int prep_dma_desc(struct qcom_nand_controller *nandc, bool read, - int reg_off, const void *vaddr, int size, - bool flow_control) +/* + * Maps the scatter gather list for DMA transfer and forms the DMA descriptor + * for BAM. This descriptor will be added in the NAND DMA descriptor queue + * which will be submitted to DMA engine. + */ +static int prepare_bam_async_desc(struct qcom_nand_controller *nandc, + struct dma_chan *chan, + unsigned long flags) +{ + struct desc_info *desc; + struct scatterlist *sgl; + unsigned int sgl_cnt; + int ret; + struct bam_transaction *bam_txn = nandc->bam_txn; + enum dma_transfer_direction dir_eng; + struct dma_async_tx_descriptor *dma_desc; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + + if (chan == nandc->cmd_chan) { + sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start]; + sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start; + bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos; + dir_eng = DMA_MEM_TO_DEV; + desc->dir = DMA_TO_DEVICE; + } else if (chan == nandc->tx_chan) { + sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start]; + sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start; + bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos; + dir_eng = DMA_MEM_TO_DEV; + desc->dir = DMA_TO_DEVICE; + } else { + sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start]; + sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start; + bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos; + dir_eng = DMA_DEV_TO_MEM; + desc->dir = DMA_FROM_DEVICE; + } + + sg_mark_end(sgl + sgl_cnt - 1); + ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir); + if (ret == 0) { + dev_err(nandc->dev, "failure in mapping desc\n"); + kfree(desc); + return -ENOMEM; + } + + desc->sgl_cnt = sgl_cnt; + desc->bam_sgl = sgl; + + dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng, + flags); + + if (!dma_desc) { + dev_err(nandc->dev, "failure in prep desc\n"); + dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir); + kfree(desc); + return -EINVAL; + } + + desc->dma_desc = dma_desc; + + list_add_tail(&desc->node, &nandc->desc_list); + + return 0; +} + +static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, + int reg_off, const void *vaddr, int size, + bool flow_control) { struct desc_info *desc; struct dma_async_tx_descriptor *dma_desc; @@ -583,7 +668,7 @@ static int prep_dma_desc(struct qcom_nand_controller *nandc, bool read, if (!desc) return -ENOMEM; - sgl = &desc->sgl; + sgl = &desc->adm_sgl; sg_init_one(sgl, vaddr, size); @@ -659,7 +744,7 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, vaddr = nandc->reg_read_buf + nandc->reg_read_pos; nandc->reg_read_pos += num_regs; - return prep_dma_desc(nandc, true, first, vaddr, size, flow_control); + return prep_adm_dma_desc(nandc, true, first, vaddr, size, flow_control); } /* @@ -690,7 +775,8 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, size = num_regs * sizeof(u32); - return prep_dma_desc(nandc, false, first, vaddr, size, flow_control); + return prep_adm_dma_desc(nandc, false, first, vaddr, size, + flow_control); } /* @@ -704,7 +790,7 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size) { - return prep_dma_desc(nandc, true, reg_off, vaddr, size, false); + return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); } /* @@ -718,7 +804,7 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size) { - return prep_dma_desc(nandc, false, reg_off, vaddr, size, false); + return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); } /* @@ -917,12 +1003,43 @@ static int submit_descs(struct qcom_nand_controller *nandc) { struct desc_info *desc; dma_cookie_t cookie = 0; + struct bam_transaction *bam_txn = nandc->bam_txn; + int r; + + if (nandc->props->is_bam) { + if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { + r = prepare_bam_async_desc(nandc, nandc->rx_chan, 0); + if (r) + return r; + } + + if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) { + r = prepare_bam_async_desc(nandc, nandc->tx_chan, + DMA_PREP_INTERRUPT); + if (r) + return r; + } + + if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) { + r = prepare_bam_async_desc(nandc, nandc->cmd_chan, 0); + if (r) + return r; + } + } list_for_each_entry(desc, &nandc->desc_list, node) cookie = dmaengine_submit(desc->dma_desc); - if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE) - return -ETIMEDOUT; + if (nandc->props->is_bam) { + dma_async_issue_pending(nandc->tx_chan); + dma_async_issue_pending(nandc->rx_chan); + + if (dma_sync_wait(nandc->cmd_chan, cookie) != DMA_COMPLETE) + return -ETIMEDOUT; + } else { + if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE) + return -ETIMEDOUT; + } return 0; } @@ -933,7 +1050,14 @@ static void free_descs(struct qcom_nand_controller *nandc) list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { list_del(&desc->node); - dma_unmap_sg(nandc->dev, &desc->sgl, 1, desc->dir); + + if (nandc->props->is_bam) + dma_unmap_sg(nandc->dev, desc->bam_sgl, + desc->sgl_cnt, desc->dir); + else + dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1, + desc->dir); + kfree(desc); } } From 67e830aef3f81affe23e50708f16d35550153836 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:42 +0530 Subject: [PATCH 35/51] mtd: nand: qcom: support for passing flags in DMA helper functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QPIC NAND BAM has multiple flags to control the transfer. This patch adds flags parameter in register and data transfer DMA helper functions and modifies all these functions call with appropriate flags using following rule 1. Read and write can’t go in single command descriptor so separate SGL should be used. 2. For some of the requests, NWD flag should be set in BAM DMA descriptor. 3. For Data write, the BAM has internal buffer for each codeword. All write request will modify the data in internal buffer and this buffer will be flushed to NAND device once EOT flag is set. So for all the write requests in single codeword, the EOT should be cleared for all tx data descriptors except the last one. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 129 ++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 52 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index f52a69252358..c9226172c3a3 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -180,6 +180,17 @@ #define QPIC_PER_CW_CMD_SGL 32 #define QPIC_PER_CW_DATA_SGL 8 +/* + * Flags used in DMA descriptor preparation helper functions + * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma) + */ +/* Don't set the EOT in current tx BAM sgl */ +#define NAND_BAM_NO_EOT BIT(0) +/* Set the NWD flag in current BAM sgl */ +#define NAND_BAM_NWD BIT(1) +/* Finish writing in the current BAM sgl and start writing in another BAM sgl */ +#define NAND_BAM_NEXT_SGL BIT(2) + /* * This data type corresponds to the BAM transaction which will be used for all * NAND transfers. @@ -729,9 +740,10 @@ err: * * @first: offset of the first register in the contiguous block * @num_regs: number of registers to read + * @flags: flags to control DMA descriptor preparation */ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, - int num_regs) + int num_regs, unsigned int flags) { bool flow_control = false; void *vaddr; @@ -753,9 +765,10 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, * * @first: offset of the first register in the contiguous block * @num_regs: number of registers to write + * @flags: flags to control DMA descriptor preparation */ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, - int num_regs) + int num_regs, unsigned int flags) { bool flow_control = false; struct nandc_regs *regs = nandc->regs; @@ -767,6 +780,9 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_FLASH_CMD) flow_control = true; + if (first == NAND_EXEC_CMD) + flags |= NAND_BAM_NWD; + if (first == NAND_DEV_CMD1_RESTORE) first = NAND_DEV_CMD1; @@ -786,9 +802,10 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, * @reg_off: offset within the controller's data buffer * @vaddr: virtual address of the buffer we want to write to * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation */ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, - const u8 *vaddr, int size) + const u8 *vaddr, int size, unsigned int flags) { return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); } @@ -800,9 +817,10 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, * @reg_off: offset within the controller's data buffer * @vaddr: virtual address of the buffer we want to read from * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation */ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, - const u8 *vaddr, int size) + const u8 *vaddr, int size, unsigned int flags) { return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); } @@ -813,9 +831,9 @@ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, */ static void config_nand_page_read(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_ADDR0, 2); - write_reg_dma(nandc, NAND_DEV0_CFG0, 3); - write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1); + write_reg_dma(nandc, NAND_ADDR0, 2, 0); + write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); + write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0); } /* @@ -824,11 +842,12 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc) */ static void config_nand_cw_read(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_FLASH_CMD, 1); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 2); - read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1); + read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0); + read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1, + NAND_BAM_NEXT_SGL); } /* @@ -847,9 +866,10 @@ static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc) */ static void config_nand_page_write(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_ADDR0, 2); - write_reg_dma(nandc, NAND_DEV0_CFG0, 3); - write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1); + write_reg_dma(nandc, NAND_ADDR0, 2, 0); + write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); + write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, + NAND_BAM_NEXT_SGL); } /* @@ -858,13 +878,13 @@ static void config_nand_page_write(struct qcom_nand_controller *nandc) */ static void config_nand_cw_write(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_FLASH_CMD, 1); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 1); + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_FLASH_STATUS, 1); - write_reg_dma(nandc, NAND_READ_STATUS, 1); + write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0); + write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); } /* @@ -911,8 +931,8 @@ static int nandc_param(struct qcom_nand_host *host) nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1); nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); - write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1); - write_reg_dma(nandc, NAND_DEV_CMD1, 1); + write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); + write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); nandc->buf_count = 512; memset(nandc->data_buffer, 0xff, nandc->buf_count); @@ -920,11 +940,11 @@ static int nandc_param(struct qcom_nand_host *host) config_nand_single_cw_page_read(nandc); read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, - nandc->buf_count); + nandc->buf_count, 0); /* restore CMD1 and VLD regs */ - write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1); - write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1); + write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0); + write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL); return 0; } @@ -946,14 +966,14 @@ static int erase_block(struct qcom_nand_host *host, int page_addr) nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus); nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus); - write_reg_dma(nandc, NAND_FLASH_CMD, 3); - write_reg_dma(nandc, NAND_DEV0_CFG0, 2); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 1); + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_FLASH_STATUS, 1); - write_reg_dma(nandc, NAND_READ_STATUS, 1); + write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0); + write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); return 0; } @@ -973,10 +993,10 @@ static int read_id(struct qcom_nand_host *host, int column) nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); nandc_set_reg(nandc, NAND_EXEC_CMD, 1); - write_reg_dma(nandc, NAND_FLASH_CMD, 4); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_READ_ID, 1); + read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); return 0; } @@ -990,10 +1010,10 @@ static int reset(struct qcom_nand_host *host) nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE); nandc_set_reg(nandc, NAND_EXEC_CMD, 1); - write_reg_dma(nandc, NAND_FLASH_CMD, 1); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 1); + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); return 0; } @@ -1389,7 +1409,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, if (data_buf) read_data_dma(nandc, FLASH_BUF_ACC, data_buf, - data_size); + data_size, 0); /* * when ecc is enabled, the controller doesn't read the real @@ -1405,7 +1425,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, *oob_buf++ = 0xff; read_data_dma(nandc, FLASH_BUF_ACC + data_size, - oob_buf, oob_size); + oob_buf, oob_size, 0); } if (data_buf) @@ -1447,7 +1467,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) config_nand_single_cw_page_read(nandc); - read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size); + read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0); ret = submit_descs(nandc); if (ret) @@ -1516,19 +1536,19 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, config_nand_cw_read(nandc); - read_data_dma(nandc, reg_off, data_buf, data_size1); + read_data_dma(nandc, reg_off, data_buf, data_size1, 0); reg_off += data_size1; data_buf += data_size1; - read_data_dma(nandc, reg_off, oob_buf, oob_size1); + read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0); reg_off += oob_size1; oob_buf += oob_size1; - read_data_dma(nandc, reg_off, data_buf, data_size2); + read_data_dma(nandc, reg_off, data_buf, data_size2, 0); reg_off += data_size2; data_buf += data_size2; - read_data_dma(nandc, reg_off, oob_buf, oob_size2); + read_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); oob_buf += oob_size2; } @@ -1595,7 +1615,8 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, } - write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size); + write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size, + i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0); /* * when ECC is enabled, we don't really need to write anything @@ -1608,7 +1629,7 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, oob_buf += host->bbm_size; write_data_dma(nandc, FLASH_BUF_ACC + data_size, - oob_buf, oob_size); + oob_buf, oob_size, 0); } config_nand_cw_write(nandc); @@ -1663,19 +1684,22 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } - write_data_dma(nandc, reg_off, data_buf, data_size1); + write_data_dma(nandc, reg_off, data_buf, data_size1, + NAND_BAM_NO_EOT); reg_off += data_size1; data_buf += data_size1; - write_data_dma(nandc, reg_off, oob_buf, oob_size1); + write_data_dma(nandc, reg_off, oob_buf, oob_size1, + NAND_BAM_NO_EOT); reg_off += oob_size1; oob_buf += oob_size1; - write_data_dma(nandc, reg_off, data_buf, data_size2); + write_data_dma(nandc, reg_off, data_buf, data_size2, + NAND_BAM_NO_EOT); reg_off += data_size2; data_buf += data_size2; - write_data_dma(nandc, reg_off, oob_buf, oob_size2); + write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); oob_buf += oob_size2; config_nand_cw_write(nandc); @@ -1729,8 +1753,8 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, update_rw_regs(host, 1, false); config_nand_page_write(nandc); - write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, - data_size + oob_size); + write_data_dma(nandc, FLASH_BUF_ACC, + nandc->data_buffer, data_size + oob_size, 0); config_nand_cw_write(nandc); ret = submit_descs(nandc); @@ -1814,7 +1838,8 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) update_rw_regs(host, 1, false); config_nand_page_write(nandc); - write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, host->cw_size); + write_data_dma(nandc, FLASH_BUF_ACC, + nandc->data_buffer, host->cw_size, 0); config_nand_cw_write(nandc); ret = submit_descs(nandc); From 91af95c143088d4c17d1fad238c4b0e999f4a5e8 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:43 +0530 Subject: [PATCH 36/51] mtd: nand: qcom: support for read location registers In EBI2, all codeword data will be read in FLASH_BUF_ACC buffer and ADM will copy the data from source (FLASH_BUF_ACC) to destination (memory for data read). In QPIC, there is no FLASH_BUF_ACC and all the codeword data will held in QPIC BAM FIFO buffers. It provides multiple READ_LOCATION registers which will be used for copying the data from FIFO to memory. The READ_LOCATION register will be used to read a specific amount of data from a specific offset within the flash buffer. It supports sequential offset requests. Each request is composed of the following fields: a. Offset within the flash buffer from which data should be read b. Amount of data to be read c. Flag bit specifying the last read request from the flash buffer. Following the last read request the NANDc refers to the buffer as empty. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 63 +++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index c9226172c3a3..9d55e8e30ea6 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -53,6 +53,8 @@ #define NAND_VERSION 0xf08 #define NAND_READ_LOCATION_0 0xf20 #define NAND_READ_LOCATION_1 0xf24 +#define NAND_READ_LOCATION_2 0xf28 +#define NAND_READ_LOCATION_3 0xf2c /* dummy register offsets, used by write_reg_dma */ #define NAND_DEV_CMD1_RESTORE 0xdead @@ -135,6 +137,11 @@ #define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED) #define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED) +/* NAND_READ_LOCATION_n bits */ +#define READ_LOCATION_OFFSET 0 +#define READ_LOCATION_SIZE 16 +#define READ_LOCATION_LAST 31 + /* Version Mask */ #define NAND_VERSION_MAJOR_MASK 0xf0000000 #define NAND_VERSION_MAJOR_SHIFT 28 @@ -177,6 +184,12 @@ #define ECC_BCH_4BIT BIT(2) #define ECC_BCH_8BIT BIT(3) +#define nandc_set_read_loc(nandc, reg, offset, size, is_last) \ +nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ + ((offset) << READ_LOCATION_OFFSET) | \ + ((size) << READ_LOCATION_SIZE) | \ + ((is_last) << READ_LOCATION_LAST)) + #define QPIC_PER_CW_CMD_SGL 32 #define QPIC_PER_CW_DATA_SGL 8 @@ -263,6 +276,11 @@ struct nandc_regs { __le32 orig_vld; __le32 ecc_buf_cfg; + __le32 read_location0; + __le32 read_location1; + __le32 read_location2; + __le32 read_location3; + }; /* @@ -519,6 +537,14 @@ static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset) return ®s->orig_vld; case NAND_EBI2_ECC_BUF_CFG: return ®s->ecc_buf_cfg; + case NAND_READ_LOCATION_0: + return ®s->read_location0; + case NAND_READ_LOCATION_1: + return ®s->read_location1; + case NAND_READ_LOCATION_2: + return ®s->read_location2; + case NAND_READ_LOCATION_3: + return ®s->read_location3; default: return NULL; } @@ -593,6 +619,10 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus); nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus); nandc_set_reg(nandc, NAND_EXEC_CMD, 1); + + if (read) + nandc_set_read_loc(nandc, 0, 0, host->use_ecc ? + host->cw_data : host->cw_size, 1); } /* @@ -842,6 +872,10 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc) */ static void config_nand_cw_read(struct qcom_nand_controller *nandc) { + if (nandc->props->is_bam) + write_reg_dma(nandc, NAND_READ_LOCATION_0, 4, + NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); @@ -930,6 +964,7 @@ static int nandc_param(struct qcom_nand_host *host) nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1); nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); + nandc_set_read_loc(nandc, 0, 0, 512, 1); write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); @@ -1405,6 +1440,19 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, oob_size = host->ecc_bytes_hw + host->spare_bytes; } + if (nandc->props->is_bam) { + if (data_buf && oob_buf) { + nandc_set_read_loc(nandc, 0, 0, data_size, 0); + nandc_set_read_loc(nandc, 1, data_size, + oob_size, 1); + } else if (data_buf) { + nandc_set_read_loc(nandc, 0, 0, data_size, 1); + } else { + nandc_set_read_loc(nandc, 0, data_size, + oob_size, 1); + } + } + config_nand_cw_read(nandc); if (data_buf) @@ -1509,6 +1557,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, u8 *data_buf, *oob_buf; struct nand_ecc_ctrl *ecc = &chip->ecc; int i, ret; + int read_loc; data_buf = buf; oob_buf = chip->oob_poi; @@ -1534,6 +1583,20 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } + if (nandc->props->is_bam) { + read_loc = 0; + nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0); + read_loc += data_size1; + + nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0); + read_loc += oob_size1; + + nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0); + read_loc += data_size2; + + nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1); + } + config_nand_cw_read(nandc); read_data_dma(nandc, reg_off, data_buf, data_size1, 0); From a86b9c4f57108a1368b7363bda12de704a7a64ec Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:44 +0530 Subject: [PATCH 37/51] mtd: nand: qcom: erased codeword detection configuration The NAND controller returns ECC failure during read of completely erased codeword. The NAND controller has hardware functionality to detect erased codeword in case of BCH ECC algorithm. The NAND_ERASED_CW_DETECT_CFG register controls the erased codeword/page detection controller. This register should be reset before every page read by setting and clearing bit 0 of NAND_ERASED_CW_DETECT_CFG. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 9d55e8e30ea6..81cfce794ca7 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -203,6 +203,11 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ #define NAND_BAM_NWD BIT(1) /* Finish writing in the current BAM sgl and start writing in another BAM sgl */ #define NAND_BAM_NEXT_SGL BIT(2) +/* + * Erased codeword status is being used two times in single transfer so this + * flag will determine the current value of erased codeword status register + */ +#define NAND_ERASED_CW_SET BIT(4) /* * This data type corresponds to the BAM transaction which will be used for all @@ -281,6 +286,8 @@ struct nandc_regs { __le32 read_location2; __le32 read_location3; + __le32 erased_cw_detect_cfg_clr; + __le32 erased_cw_detect_cfg_set; }; /* @@ -810,6 +817,13 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_FLASH_CMD) flow_control = true; + if (first == NAND_ERASED_CW_DETECT_CFG) { + if (flags & NAND_ERASED_CW_SET) + vaddr = ®s->erased_cw_detect_cfg_set; + else + vaddr = ®s->erased_cw_detect_cfg_clr; + } + if (first == NAND_EXEC_CMD) flags |= NAND_BAM_NWD; @@ -864,6 +878,9 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc) write_reg_dma(nandc, NAND_ADDR0, 2, 0); write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0); + write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0); + write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, + NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); } /* @@ -2264,6 +2281,10 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host) host->clrflashstatus = FS_READY_BSY_N; host->clrreadstatus = 0xc0; + nandc->regs->erased_cw_detect_cfg_clr = + cpu_to_le32(CLR_ERASED_PAGE_DET); + nandc->regs->erased_cw_detect_cfg_set = + cpu_to_le32(SET_ERASED_PAGE_DET); dev_dbg(nandc->dev, "cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n", From 9d43f91569526b60775174115c98768cb48fc828 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:45 +0530 Subject: [PATCH 38/51] mtd: nand: qcom: enable BAM or ADM mode 1. DM_EN is only required for EBI2 NAND controller which uses ADM 2. BAM mode will be disabled after power on reset which needs to be enabled before starting any BAM transfers. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 81cfce794ca7..fd77d592c4ee 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -163,6 +163,9 @@ #define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ ERASE_START_VLD | SEQ_READ_START_VLD) +/* NAND_CTRL bits */ +#define BAM_MODE_EN BIT(0) + /* * the NAND controller performs reads/writes with ECC in 516 byte chunks. * the driver calls the chunks 'step' or 'codeword' interchangeably @@ -1042,7 +1045,8 @@ static int read_id(struct qcom_nand_host *host, int column) nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID); nandc_set_reg(nandc, NAND_ADDR0, column); nandc_set_reg(nandc, NAND_ADDR1, 0); - nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); + nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, + nandc->props->is_bam ? 0 : DM_EN); nandc_set_reg(nandc, NAND_EXEC_CMD, 1); write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); @@ -2414,12 +2418,19 @@ static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) /* one time setup of a few nand controller registers */ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) { + u32 nand_ctrl; + /* kill onenand */ nandc_write(nandc, SFLASHC_BURST_CFG, 0); nandc_write(nandc, NAND_DEV_CMD_VLD, NAND_DEV_CMD_VLD_VAL); - /* enable ADM DMA */ - nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); + /* enable ADM or BAM DMA */ + if (nandc->props->is_bam) { + nand_ctrl = nandc_read(nandc, NAND_CTRL); + nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN); + } else { + nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); + } /* save the original values of these registers */ nandc->cmd1 = nandc_read(nandc, NAND_DEV_CMD1); From 4e2f6c52f4840b0d2ad1a62b71bf139cb0ec0915 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:46 +0530 Subject: [PATCH 39/51] mtd: nand: qcom: QPIC data descriptors handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add the data descriptor preparation function which will be used only by BAM DMA for forming the data SGL’s 2. Add clear BAM transaction and call it before every new request 3. Check DMA mode for ADM or BAM and call the appropriate descriptor formation function. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 76 +++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index fd77d592c4ee..1ff5daf9d619 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -473,6 +473,27 @@ alloc_bam_transaction(struct qcom_nand_controller *nandc) return bam_txn; } +/* Clears the BAM transaction indexes */ +static void clear_bam_transaction(struct qcom_nand_controller *nandc) +{ + struct bam_transaction *bam_txn = nandc->bam_txn; + + if (!nandc->props->is_bam) + return; + + bam_txn->cmd_sgl_pos = 0; + bam_txn->cmd_sgl_start = 0; + bam_txn->tx_sgl_pos = 0; + bam_txn->tx_sgl_start = 0; + bam_txn->rx_sgl_pos = 0; + bam_txn->rx_sgl_start = 0; + + sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * + QPIC_PER_CW_CMD_SGL); + sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage * + QPIC_PER_CW_DATA_SGL); +} + static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) { return container_of(chip, struct qcom_nand_host, chip); @@ -704,6 +725,41 @@ static int prepare_bam_async_desc(struct qcom_nand_controller *nandc, return 0; } +/* + * Prepares the data descriptor for BAM DMA which will be used for NAND + * data reads and writes. + */ +static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, + const void *vaddr, + int size, unsigned int flags) +{ + int ret; + struct bam_transaction *bam_txn = nandc->bam_txn; + + if (read) { + sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos], + vaddr, size); + bam_txn->rx_sgl_pos++; + } else { + sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos], + vaddr, size); + bam_txn->tx_sgl_pos++; + + /* + * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag + * is not set, form the DMA descriptor + */ + if (!(flags & NAND_BAM_NO_EOT)) { + ret = prepare_bam_async_desc(nandc, nandc->tx_chan, + DMA_PREP_INTERRUPT); + if (ret) + return ret; + } + } + + return 0; +} + static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, int reg_off, const void *vaddr, int size, bool flow_control) @@ -854,6 +910,9 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size, unsigned int flags) { + if (nandc->props->is_bam) + return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); + return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); } @@ -869,6 +928,9 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size, unsigned int flags) { + if (nandc->props->is_bam) + return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); + return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); } @@ -1156,6 +1218,10 @@ static void pre_command(struct qcom_nand_host *host, int command) host->last_command = command; clear_read_regs(nandc); + + if (command == NAND_CMD_RESET || command == NAND_CMD_READID || + command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1) + clear_bam_transaction(nandc); } /* @@ -1559,6 +1625,7 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip, data_buf = buf; oob_buf = oob_required ? chip->oob_poi : NULL; + clear_bam_transaction(nandc); ret = read_page_ecc(host, data_buf, oob_buf); if (ret) { dev_err(nandc->dev, "failure to read page\n"); @@ -1584,6 +1651,8 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, oob_buf = chip->oob_poi; host->use_ecc = false; + + clear_bam_transaction(nandc); update_rw_regs(host, ecc->steps, true); config_nand_page_read(nandc); @@ -1655,6 +1724,7 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int ret; clear_read_regs(nandc); + clear_bam_transaction(nandc); host->use_ecc = true; set_address(host, 0, page); @@ -1678,6 +1748,7 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, int i, ret; clear_read_regs(nandc); + clear_bam_transaction(nandc); data_buf = (u8 *)buf; oob_buf = chip->oob_poi; @@ -1743,6 +1814,7 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, int i, ret; clear_read_regs(nandc); + clear_bam_transaction(nandc); data_buf = (u8 *)buf; oob_buf = chip->oob_poi; @@ -1819,11 +1891,13 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, host->use_ecc = true; + clear_bam_transaction(nandc); ret = copy_last_cw(host, page); if (ret) return ret; clear_read_regs(nandc); + clear_bam_transaction(nandc); /* calculate the data and oob size for the last codeword/step */ data_size = ecc->size - ((ecc->steps - 1) << 2); @@ -1876,6 +1950,7 @@ static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs) */ host->use_ecc = false; + clear_bam_transaction(nandc); ret = copy_last_cw(host, page); if (ret) goto err; @@ -1906,6 +1981,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) int page, ret, status = 0; clear_read_regs(nandc); + clear_bam_transaction(nandc); /* * to mark the BBM as bad, we flash the entire last codeword with 0s. From cc409b9a8ec5e88d6f712c535d88b14765f234c4 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:47 +0530 Subject: [PATCH 40/51] mtd: nand: qcom: support for different DEV_CMD register offsets The FLASH_DEV_CMD registers starting offset is not same in different QPIC NAND controller versions. This patch adds the starting offset in NAND controller properties and uses the same for calculating the actual offset of these registers. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 1ff5daf9d619..7977a70a0499 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -193,6 +193,12 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ ((size) << READ_LOCATION_SIZE) | \ ((is_last) << READ_LOCATION_LAST)) +/* + * Returns the actual register address for all NAND_DEV_ registers + * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) + */ +#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg)) + #define QPIC_PER_CW_CMD_SGL 32 #define QPIC_PER_CW_DATA_SGL 8 @@ -429,10 +435,12 @@ struct qcom_nand_host { * among different NAND controllers. * @ecc_modes - ecc mode for NAND * @is_bam - whether NAND controller is using BAM + * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset */ struct qcom_nandc_props { u32 ecc_modes; bool is_bam; + u32 dev_cmd_reg_start; }; /* Frees the BAM transaction memory */ @@ -848,6 +856,9 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_READ_ID || first == NAND_FLASH_STATUS) flow_control = true; + if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1) + first = dev_cmd_reg_addr(nandc, first); + size = num_regs * sizeof(u32); vaddr = nandc->reg_read_buf + nandc->reg_read_pos; nandc->reg_read_pos += num_regs; @@ -886,11 +897,11 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_EXEC_CMD) flags |= NAND_BAM_NWD; - if (first == NAND_DEV_CMD1_RESTORE) - first = NAND_DEV_CMD1; + if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1) + first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1); - if (first == NAND_DEV_CMD_VLD_RESTORE) - first = NAND_DEV_CMD_VLD; + if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD) + first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); size = num_regs * sizeof(u32); @@ -2498,7 +2509,8 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) /* kill onenand */ nandc_write(nandc, SFLASHC_BURST_CFG, 0); - nandc_write(nandc, NAND_DEV_CMD_VLD, NAND_DEV_CMD_VLD_VAL); + nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD), + NAND_DEV_CMD_VLD_VAL); /* enable ADM or BAM DMA */ if (nandc->props->is_bam) { @@ -2509,7 +2521,7 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) } /* save the original values of these registers */ - nandc->cmd1 = nandc_read(nandc, NAND_DEV_CMD1); + nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1)); nandc->vld = NAND_DEV_CMD_VLD_VAL; return 0; @@ -2758,6 +2770,7 @@ static int qcom_nandc_remove(struct platform_device *pdev) static const struct qcom_nandc_props ipq806x_nandc_props = { .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), .is_bam = false, + .dev_cmd_reg_start = 0x0, }; /* From 24d8735708b086a8cfb40d962ea2080af558bd1b Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:50 +0530 Subject: [PATCH 41/51] dt-bindings: qcom_nandc: fix the ipq806x device tree example 1. Correct the compatible string for IPQ806x 2. Change the NAND controller and NAND chip nodes name for more clarity. Acked-by: Rob Herring Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt index 26360fe51663..f475b652d9b8 100644 --- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt +++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt @@ -42,8 +42,8 @@ partition.txt for more detail. Example: -nand@1ac00000 { - compatible = "qcom,ebi2-nandc"; +nand-controller@1ac00000 { + compatible = "qcom,ipq806x-nand"; reg = <0x1ac00000 0x800>; clocks = <&gcc EBI2_CLK>, @@ -58,7 +58,7 @@ nand@1ac00000 { #address-cells = <1>; #size-cells = <0>; - nandcs@0 { + nand@0 { reg = <0>; nand-ecc-strength = <4>; From ec170cc853ad4e8c01ee71e619739b9c379eb643 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:51 +0530 Subject: [PATCH 42/51] dt-bindings: qcom_nandc: IPQ4019 QPIC NAND documentation 1. Qualcom IPQ4019 SoC uses QPIC NAND controller version 1.4.0 which uses BAM DMA Engine while IPQ806x uses EBI2 NAND which uses ADM DMA Engine. 2. QPIC NAND will 3 BAM channels: command, data tx and data rx while EBI2 NAND uses only single ADM channel. 3. CRCI is only required for ADM DMA and its not required for BAM DMA. Acked-by: Rob Herring Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- .../devicetree/bindings/mtd/qcom_nandc.txt | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt index f475b652d9b8..d93b952f4bd6 100644 --- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt +++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt @@ -1,11 +1,18 @@ * Qualcomm NAND controller Required properties: -- compatible: should be "qcom,ipq806x-nand" +- compatible: must be one of the following: + * "qcom,ipq806x-nand" - for EBI2 NAND controller being used in IPQ806x + SoC and it uses ADM DMA + * "qcom,ipq4019-nand" - for QPIC NAND controller v1.4.0 being used in + IPQ4019 SoC and it uses BAM DMA + - reg: MMIO address range - clocks: must contain core clock and always on clock - clock-names: must contain "core" for the core clock and "aon" for the always on clock + +EBI2 specific properties: - dmas: DMA specifier, consisting of a phandle to the ADM DMA controller node and the channel number to be used for NAND. Refer to dma.txt and qcom_adm.txt for more details @@ -16,6 +23,12 @@ Required properties: - qcom,data-crci: must contain the ADM data type CRCI block instance number specified for the NAND controller on the given platform + +QPIC specific properties: +- dmas: DMA specifier, consisting of a phandle to the BAM DMA + and the channel number to be used for NAND. Refer to + dma.txt, qcom_bam_dma.txt for more details +- dma-names: must contain all 3 channel names : "tx", "rx", "cmd" - #address-cells: <1> - subnodes give the chip-select number - #size-cells: <0> @@ -82,3 +95,43 @@ nand-controller@1ac00000 { }; }; }; + +nand-controller@79b0000 { + compatible = "qcom,ipq4019-nand"; + reg = <0x79b0000 0x1000>; + + clocks = <&gcc GCC_QPIC_CLK>, + <&gcc GCC_QPIC_AHB_CLK>; + clock-names = "core", "aon"; + + dmas = <&qpicbam 0>, + <&qpicbam 1>, + <&qpicbam 2>; + dma-names = "tx", "rx", "cmd"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + nand-bus-width = <8>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot-nand"; + reg = <0 0x58a0000>; + }; + + partition@58a0000 { + label = "fs-nand"; + reg = <0x58a0000 0x4000000>; + }; + }; + }; +}; From d440c4d3601d964dc742730a05f2534535a17f0b Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:52 +0530 Subject: [PATCH 43/51] dt-bindings: qcom_nandc: IPQ8074 QPIC NAND documentation Qualcom IPQ8074 SoC uses QPIC NAND controller version 1.5.0 which uses BAM DMA Engine. Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt index d93b952f4bd6..73d336befa08 100644 --- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt +++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt @@ -6,6 +6,8 @@ Required properties: SoC and it uses ADM DMA * "qcom,ipq4019-nand" - for QPIC NAND controller v1.4.0 being used in IPQ4019 SoC and it uses BAM DMA + * "qcom,ipq8074-nand" - for QPIC NAND controller v1.5.0 being used in + IPQ8074 SoC and it uses BAM DMA - reg: MMIO address range - clocks: must contain core clock and always on clock From a06378341eeb809f9df4e80ddb507418b3e36d97 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:53 +0530 Subject: [PATCH 44/51] mtd: nand: qcom: support for IPQ4019 QPIC NAND controller Add the compatible string for IPQ4019 QPIC NAND controller version 1.4.0 which uses BAM DMA. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 7977a70a0499..158076c6ea3e 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -2773,6 +2773,12 @@ static const struct qcom_nandc_props ipq806x_nandc_props = { .dev_cmd_reg_start = 0x0, }; +static const struct qcom_nandc_props ipq4019_nandc_props = { + .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), + .is_bam = true, + .dev_cmd_reg_start = 0x0, +}; + /* * data will hold a struct pointer containing more differences once we support * more controller variants @@ -2782,6 +2788,10 @@ static const struct of_device_id qcom_nandc_of_match[] = { .compatible = "qcom,ipq806x-nand", .data = &ipq806x_nandc_props, }, + { + .compatible = "qcom,ipq4019-nand", + .data = &ipq4019_nandc_props, + }, {} }; MODULE_DEVICE_TABLE(of, qcom_nandc_of_match); From dce84760b09f8c3d6c9e001fe5f37be93d2daa46 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:54 +0530 Subject: [PATCH 45/51] mtd: nand: qcom: Support for IPQ8074 QPIC NAND controller Add the compatible string for IPQ8074 QPIC NAND controller version 1.5.0 which uses BAM DMA and its FLASH_DEV_CMD registers starting offset is 0x7000. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 158076c6ea3e..131738a6e86a 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -2779,6 +2779,12 @@ static const struct qcom_nandc_props ipq4019_nandc_props = { .dev_cmd_reg_start = 0x0, }; +static const struct qcom_nandc_props ipq8074_nandc_props = { + .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), + .is_bam = true, + .dev_cmd_reg_start = 0x7000, +}; + /* * data will hold a struct pointer containing more differences once we support * more controller variants @@ -2792,6 +2798,10 @@ static const struct of_device_id qcom_nandc_of_match[] = { .compatible = "qcom,ipq4019-nand", .data = &ipq4019_nandc_props, }, + { + .compatible = "qcom,ipq8074-nand", + .data = &ipq8074_nandc_props, + }, {} }; MODULE_DEVICE_TABLE(of, qcom_nandc_of_match); From e59ad6ff83b444517067046bd837595a1ab84900 Mon Sep 17 00:00:00 2001 From: Andrea Adami Date: Mon, 14 Aug 2017 22:48:33 +0200 Subject: [PATCH 46/51] mtd: nand: sharpsl: Add partition parsers platform data With the introduction of sharpslpart partition parser we can now read the offsets from NAND: we specify the list of the parsers as platform data, with cmdlinepart and ofpart parsers first allowing to override the part. table written in NAND. This is done in the board files using this driver. Thus, we need to extend sharpsl_nand_platform_data to consider the partition parsers. Signed-off-by: Andrea Adami Signed-off-by: Boris Brezillon --- include/linux/mtd/sharpsl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/mtd/sharpsl.h b/include/linux/mtd/sharpsl.h index 65e91d0fa981..6381a7d6c289 100644 --- a/include/linux/mtd/sharpsl.h +++ b/include/linux/mtd/sharpsl.h @@ -17,4 +17,5 @@ struct sharpsl_nand_platform_data { const struct mtd_ooblayout_ops *ecc_layout; struct mtd_partition *partitions; unsigned int nr_partitions; + const char *const *part_parsers; }; From 482ead931e05b4d5556a5ffd51c2f40cd586f20c Mon Sep 17 00:00:00 2001 From: Andrea Adami Date: Mon, 14 Aug 2017 22:48:35 +0200 Subject: [PATCH 47/51] mtd: nand: sharpsl: Register partitions using the parsers With the introduction of sharpslpart partition parser we can now read the offsets from NAND: we specify the list of the parsers as platform data, with cmdlinepart and ofpart parsers first allowing to override the part. table written in NAND. This is done in the board files using this driver. Use now these parsers. Signed-off-by: Andrea Adami Signed-off-by: Boris Brezillon --- drivers/mtd/nand/sharpsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 064ca1757589..9859546a9207 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -183,7 +183,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev) /* Register the partitions */ mtd->name = "sharpsl-nand"; - err = mtd_device_parse_register(mtd, NULL, NULL, + err = mtd_device_parse_register(mtd, data->part_parsers, NULL, data->partitions, data->nr_partitions); if (err) goto err_add; From 827dba9d626325a65727c4074913b2d3c7e7ea4d Mon Sep 17 00:00:00 2001 From: Andrea Adami Date: Mon, 14 Aug 2017 22:48:34 +0200 Subject: [PATCH 48/51] mfd: tmio: Add partition parsers platform data With the introduction of sharpslpart partition parser we can now read the offsets from NAND: we specify the list of the parsers as platform data, with cmdlinepart and ofpart parsers first allowing to override the part. table written in NAND. This is done in the board files using this driver. Thus, we need to extend tmio_nand_data to consider the partition parsers. Signed-off-by: Andrea Adami Acked-by: Lee Jones Acked-by: Wolfram Sang Signed-off-by: Boris Brezillon --- include/linux/mfd/tmio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 26e8f8c0a6db..357b6cfdf34a 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -139,6 +139,7 @@ struct tmio_nand_data { struct nand_bbt_descr *badblock_pattern; struct mtd_partition *partition; unsigned int num_partitions; + const char *const *part_parsers; }; #define FBIO_TMIO_ACC_WRITE 0x7C639300 From 311bba10cb0e232f2f9b0bace8bec873d7dc32a7 Mon Sep 17 00:00:00 2001 From: Andrea Adami Date: Mon, 14 Aug 2017 22:48:36 +0200 Subject: [PATCH 49/51] mtd: nand: tmio: Register partitions using the parsers With the introduction of sharpslpart partition parser we can now read the offsets from NAND: we specify the list of the parsers as platform data, with cmdlinepart and ofpart parsers first allowing to override the part. table written in NAND. This is done in the board files using this driver. Use now these parsers. Signed-off-by: Andrea Adami Acked-by: Wolfram Sang Signed-off-by: Boris Brezillon --- drivers/mtd/nand/tmio_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index fc5e773f8b60..47f439fb6ae3 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -440,7 +440,9 @@ static int tmio_probe(struct platform_device *dev) goto err_irq; /* Register the partitions */ - retval = mtd_device_parse_register(mtd, NULL, NULL, + retval = mtd_device_parse_register(mtd, + data ? data->part_parsers : NULL, + NULL, data ? data->partition : NULL, data ? data->num_partitions : 0); if (!retval) From 69fc01296c92814b62dbfba1600fe7ed2ed304f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Tue, 29 Aug 2017 12:17:12 +0200 Subject: [PATCH 50/51] mtd: nand: make Samsung SLC NAND usable again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c51d0ac59f24 ("mtd: nand: Move Samsung specific init/detection logic in nand_samsung.c") introduced a regression for Samsung SLC NAND chips. Prior to this commit chip->bits_per_cell was initialized by calling nand_get_bits_per_cell() before using nand_is_slc(). With the offending commit this call is skipped, leaving chip->bits_per_cell cleared to zero when the manufacturer specific '.detect' function calls nand_is_slc() which in turn interprets bits_per_cell != 1 as indication for an MLC chip. The effect is that e.g. a K9F1G08U0F NAND chip is falsely detected as MLC NAND with 4KiB page size rather than SLC with 2KiB page size. Add a call to nand_get_bits_per_cell() before calling the .detect hook function in nand_manufacturer_detect(), so that the nand_is_slc() calls in the manufacturer specific code will return correct results. Fixes: c51d0ac59f24 ("mtd: nand: Move Samsung specific init/detection logic in nand_samsung.c") Cc: Signed-off-by: Lothar Waßmann Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8f4a681fd10e..6ed5392f3798 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3813,10 +3813,13 @@ static void nand_manufacturer_detect(struct nand_chip *chip) * nand_decode_ext_id() otherwise. */ if (chip->manufacturer.desc && chip->manufacturer.desc->ops && - chip->manufacturer.desc->ops->detect) + chip->manufacturer.desc->ops->detect) { + /* The 3rd id byte holds MLC / multichip data */ + chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]); chip->manufacturer.desc->ops->detect(chip); - else + } else { nand_decode_ext_id(chip); + } } /* From 2d2a2b8c080ad8feab7ca87769dedb3c7a83a375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Tue, 29 Aug 2017 12:17:13 +0200 Subject: [PATCH 51/51] mtd: nand: complain loudly when chip->bits_per_cell is not correctly initialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit chip->bits_per_cell which is used to determine the NAND cell type (SLC/MLC) should always have a value != 0. Complain loudly if the value is 0 in nand_is_slc() to catch use before correct initialization. Signed-off-by: Lothar Waßmann Signed-off-by: Boris Brezillon --- include/linux/mtd/rawnand.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 8fb488d586d6..c433f093766a 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1234,6 +1234,8 @@ int onfi_init_data_interface(struct nand_chip *chip, */ static inline bool nand_is_slc(struct nand_chip *chip) { + WARN(chip->bits_per_cell == 0, + "chip->bits_per_cell is used uninitialized\n"); return chip->bits_per_cell == 1; }