Core changes:

* Prepare arrival of the SPI NAND subsystem by implementing a generic
   (interface-agnostic) layer to ease manipulation of NAND devices
 * Move onenand code base to the drivers/mtd/nand/ dir
 * Rework timing mode selection
 * Provide a generic way for NAND chip drivers to flag a specific
   GET/SET FEATURE operation as supported/unsupported
 * Stop embedding ONFI/JEDEC param page in nand_chip
 
 Driver changes:
 * Rework/cleanup of the mxc driver
 * Various cleanups in the vf610 driver
 * Migrate the fsmc and vf610 to ->exec_op()
 * Get rid of the pxa driver (replaced by marvell_nand)
 * Support ->setup_data_interface() in the GPMI driver
 * Fix probe error path in several drivers
 * Remove support for unused hw_syndrome mode in sunxi_nand
 * Various minor improvements
 -----BEGIN PGP SIGNATURE-----
 
 iQI5BAABCAAjBQJavURPHBxib3Jpcy5icmV6aWxsb25AYm9vdGxpbi5jb20ACgkQ
 Ze02AX4ItwDzsw//YqnrDG6JzEBGEEJ0c1I6O/2Zk9eDrXhDeKk2S4G292QGQ4by
 8bKYpHo3al9TxTBb/to6+BexoP717tSwbn+AcW5W2YqGpIAeSGaw1POGau9E7l71
 wQh1aECOXCpLVLKbv/JFspiKMJYj+irxoTjdR6/3FjawDx0ruLwCCLlvOFlfkUOM
 ESv+hZv9364jcq/SsydYTYaIc95IsfBOUZVYcXRRdtaI7hvD9ljfXRSGNh+Guovc
 Bmvyiv9VuUBRg/v26gdQjESVfs3k37YV6LfS5eQSPuCHs2WGaZa5S6mBpHunAxTN
 bhbd+vVwzMaDSmX29Xsml+isJnmTdBBJRcg4qusY/nBjeUHtY2nj5J3bq+CuhSwj
 q2MB6YyBStqeagzBvctt3wzG9S7ZsVGU+PMtpMkH4T8BY+Bff9yFCPmRZwTUOorK
 iVuVhS2NImvJZ05/hc9VchAmSqd4PozHM08oW0NC6FqnF63hinkzw0J3K6FXycFF
 q/6lioZFHE8qJbD3LhDqCrLJoRDQDpxVQmZP9RCL1iozW7GNIYD7/IrPrsgqSQNa
 P10PvPt8lbBNq3GU3mIMtajTVihRJmH4Kdxd2i08dRp4hxIakF9Zx3MOhw5gZc0b
 C0xoFgaEvxbyb5P3VGVy7LYTvTfvJ9KsacntTSn7LrIU3D7meXmwnHynq5A=
 =uvio
 -----END PGP SIGNATURE-----

Merge tag 'nand/for-4.17' of git://git.infradead.org/linux-mtd into mtd/next

Core changes:
* Prepare arrival of the SPI NAND subsystem by implementing a generic
  (interface-agnostic) layer to ease manipulation of NAND devices
* Move onenand code base to the drivers/mtd/nand/ dir
* Rework timing mode selection
* Provide a generic way for NAND chip drivers to flag a specific
  GET/SET FEATURE operation as supported/unsupported
* Stop embedding ONFI/JEDEC param page in nand_chip

Driver changes:
* Rework/cleanup of the mxc driver
* Various cleanups in the vf610 driver
* Migrate the fsmc and vf610 to ->exec_op()
* Get rid of the pxa driver (replaced by marvell_nand)
* Support ->setup_data_interface() in the GPMI driver
* Fix probe error path in several drivers
* Remove support for unused hw_syndrome mode in sunxi_nand
* Various minor improvements
This commit is contained in:
Boris Brezillon 2018-04-04 22:11:36 +02:00
commit a88b5f3833
137 changed files with 3425 additions and 5746 deletions

View File

@ -33,9 +33,9 @@ Axel Lin <axel.lin@gmail.com>
Ben Gardner <bgardner@wabtec.com>
Ben M Cahill <ben.m.cahill@intel.com>
Björn Steinbrink <B.Steinbrink@gmx.de>
Boris Brezillon <boris.brezillon@free-electrons.com>
Boris Brezillon <boris.brezillon@free-electrons.com> <b.brezillon.dev@gmail.com>
Boris Brezillon <boris.brezillon@free-electrons.com> <b.brezillon@overkiz.com>
Boris Brezillon <boris.brezillon@bootlin.com> <boris.brezillon@free-electrons.com>
Boris Brezillon <boris.brezillon@bootlin.com> <b.brezillon.dev@gmail.com>
Boris Brezillon <boris.brezillon@bootlin.com> <b.brezillon@overkiz.com>
Brian Avery <b.avery@hp.com>
Brian King <brking@us.ibm.com>
Christoph Hellwig <hch@lst.de>
@ -126,6 +126,7 @@ Mayuresh Janorkar <mayur@ti.com>
Michael Buesch <m@bues.ch>
Michel Dänzer <michel@tungstengraphics.com>
Miodrag Dinic <miodrag.dinic@mips.com> <miodrag.dinic@imgtec.com>
Miquel Raynal <miquel.raynal@bootlin.com> <miquel.raynal@free-electrons.com>
Mitesh shah <mshah@teja.com>
Mohit Kumar <mohit.kumar@st.com> <mohit.kumar.dhaka@gmail.com>
Morten Welinder <terra@gnome.org>

View File

@ -46,7 +46,7 @@ NAND
----
The NAND hardware is similar to the S3C2440, and is supported by the
s3c2410 driver in the drivers/mtd/nand directory.
s3c2410 driver in the drivers/mtd/nand/raw directory.
USB Host

View File

@ -14,7 +14,10 @@ Required properties:
- #address-cells: shall be set to 1. Encode the NAND CS.
- #size-cells: shall be set to 0.
- interrupts: shall define the NAND controller interrupt.
- clocks: shall reference the NAND controller clock.
- clocks: shall reference the NAND controller clocks, the second one is
is only needed for the Armada 7K/8K SoCs
- clock-names: mandatory if there is a second clock, in this case there
should be one clock named "core" and another one named "reg"
- marvell,system-controller: Set to retrieve the syscon node that handles
NAND controller related registers (only required with the
"marvell,armada-8k-nand[-controller]" compatibles).

View File

@ -1,50 +0,0 @@
PXA3xx NAND DT bindings
Required properties:
- compatible: Should be set to one of the following:
marvell,pxa3xx-nand
marvell,armada370-nand
marvell,armada-8k-nand
- reg: The register base for the controller
- interrupts: The interrupt to map
- #address-cells: Set to <1> if the node includes partitions
- marvell,system-controller: Set to retrieve the syscon node that handles
NAND controller related registers (only required
with marvell,armada-8k-nand compatible).
Optional properties:
- dmas: dma data channel, see dma.txt binding doc
- marvell,nand-enable-arbiter: Set to enable the bus arbiter
- marvell,nand-keep-config: Set to keep the NAND controller config as set
by the bootloader
- num-cs: Number of chipselect lines to use
- nand-on-flash-bbt: boolean to enable on flash bbt option if
not present false
- nand-ecc-strength: number of bits to correct per ECC step
- nand-ecc-step-size: number of data bytes covered by a single ECC step
The following ECC strength and step size are currently supported:
- nand-ecc-strength = <1>, nand-ecc-step-size = <512>
- nand-ecc-strength = <4>, nand-ecc-step-size = <512>
- nand-ecc-strength = <8>, nand-ecc-step-size = <512>
Example:
nand0: nand@43100000 {
compatible = "marvell,pxa3xx-nand";
reg = <0x43100000 90>;
interrupts = <45>;
dmas = <&pdma 97 0>;
dma-names = "data";
#address-cells = <1>;
marvell,nand-enable-arbiter;
marvell,nand-keep-config;
num-cs = <1>;
/* partitions (optional) */
};

View File

@ -24,8 +24,8 @@ Optional properties:
- allwinner,rb : shall contain the native Ready/Busy ids.
or
- rb-gpios : shall contain the gpios used as R/B pins.
- nand-ecc-mode : one of the supported ECC modes ("hw", "hw_syndrome", "soft",
"soft_bch" or "none")
- nand-ecc-mode : one of the supported ECC modes ("hw", "soft", "soft_bch" or
"none")
see Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.

View File

@ -967,10 +967,10 @@ API functions which are exported. Each function has a short description
which is marked with an [XXX] identifier. See the chapter "Documentation
hints" for an explanation.
.. kernel-doc:: drivers/mtd/nand/nand_base.c
.. kernel-doc:: drivers/mtd/nand/raw/nand_base.c
:export:
.. kernel-doc:: drivers/mtd/nand/nand_ecc.c
.. kernel-doc:: drivers/mtd/nand/raw/nand_ecc.c
:export:
Internal Functions Provided
@ -982,10 +982,10 @@ marked with an [XXX] identifier. See the chapter "Documentation hints"
for an explanation. The functions marked with [DEFAULT] might be
relevant for a board driver developer.
.. kernel-doc:: drivers/mtd/nand/nand_base.c
.. kernel-doc:: drivers/mtd/nand/raw/nand_base.c
:internal:
.. kernel-doc:: drivers/mtd/nand/nand_bbt.c
.. kernel-doc:: drivers/mtd/nand/raw/nand_bbt.c
:internal:
Credits

View File

@ -74,8 +74,8 @@ hardware descriptions such as device tree or ACPI:
it from 1-to-0-to-1. If that hardware does not receive its "ping"
periodically, it will reset the system.
- gpio-nand: drivers/mtd/nand/gpio.c is used to connect a NAND flash chip to
a set of simple GPIO lines: RDY, NCE, ALE, CLE, NWP. It interacts with the
- gpio-nand: drivers/mtd/nand/raw/gpio.c is used to connect a NAND flash chip
to a set of simple GPIO lines: RDY, NCE, ALE, CLE, NWP. It interacts with the
NAND flash MTD subsystem and provides chip access and partition parsing like
any other NAND driving hardware.

View File

@ -1232,7 +1232,7 @@ F: arch/arm/boot/dts/aspeed-*
F: drivers/*/*aspeed*
ARM/ATMEL AT91 Clock Support
M: Boris Brezillon <boris.brezillon@free-electrons.com>
M: Boris Brezillon <boris.brezillon@bootlin.com>
S: Maintained
F: drivers/clk/at91
@ -1710,7 +1710,7 @@ F: drivers/input/keyboard/w90p910_keypad.c
F: drivers/input/touchscreen/w90p910_ts.c
F: drivers/watchdog/nuc900_wdt.c
F: drivers/net/ethernet/nuvoton/w90p910_ether.c
F: drivers/mtd/nand/nuc900_nand.c
F: drivers/mtd/nand/raw/nuc900_nand.c
F: drivers/rtc/rtc-nuc900.c
F: drivers/spi/spi-nuc900.c
F: drivers/usb/host/ehci-w90x900.c
@ -3014,7 +3014,7 @@ M: Kamal Dasu <kdasu.kdev@gmail.com>
L: linux-mtd@lists.infradead.org
L: bcm-kernel-feedback-list@broadcom.com
S: Maintained
F: drivers/mtd/nand/brcmnand/
F: drivers/mtd/nand/raw/brcmnand/
BROADCOM STB DPFE DRIVER
M: Markus Mayer <mmayer@broadcom.com>
@ -4116,7 +4116,7 @@ DENALI NAND DRIVER
M: Masahiro Yamada <yamada.masahiro@socionext.com>
L: linux-mtd@lists.infradead.org
S: Supported
F: drivers/mtd/nand/denali*
F: drivers/mtd/nand/raw/denali*
DESIGNWARE USB2 DRD IP DRIVER
M: John Youn <johnyoun@synopsys.com>
@ -4644,7 +4644,7 @@ F: Documentation/gpu/meson.rst
T: git git://anongit.freedesktop.org/drm/drm-misc
DRM DRIVERS FOR ATMEL HLCDC
M: Boris Brezillon <boris.brezillon@free-electrons.com>
M: Boris Brezillon <boris.brezillon@bootlin.com>
L: dri-devel@lists.freedesktop.org
S: Supported
F: drivers/gpu/drm/atmel-hlcdc/
@ -5646,7 +5646,7 @@ FREESCALE GPMI NAND DRIVER
M: Han Xu <han.xu@nxp.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/gpmi-nand/*
F: drivers/mtd/nand/raw/gpmi-nand/*
FREESCALE I2C CPM DRIVER
M: Jochen Friedrich <jochen@scram.de>
@ -6955,7 +6955,7 @@ INGENIC JZ4780 NAND DRIVER
M: Harvey Hunt <harveyhuntnexus@gmail.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/jz4780_*
F: drivers/mtd/nand/raw/jz4780_*
INOTIFY
M: Jan Kara <jack@suse.cz>
@ -8412,7 +8412,7 @@ F: include/uapi/drm/armada_drm.h
F: Documentation/devicetree/bindings/display/armada/
MARVELL CRYPTO DRIVER
M: Boris Brezillon <boris.brezillon@free-electrons.com>
M: Boris Brezillon <boris.brezillon@bootlin.com>
M: Arnaud Ebalard <arno@natisbad.org>
F: drivers/crypto/marvell/
S: Maintained
@ -8471,10 +8471,10 @@ S: Odd Fixes
F: drivers/net/wireless/marvell/mwl8k.c
MARVELL NAND CONTROLLER DRIVER
M: Miquel Raynal <miquel.raynal@free-electrons.com>
M: Miquel Raynal <miquel.raynal@bootlin.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/marvell_nand.c
F: drivers/mtd/nand/raw/marvell_nand.c
F: Documentation/devicetree/bindings/mtd/marvell-nand.txt
MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
@ -9034,7 +9034,7 @@ F: mm/
MEMORY TECHNOLOGY DEVICES (MTD)
M: David Woodhouse <dwmw2@infradead.org>
M: Brian Norris <computersforpeace@gmail.com>
M: Boris Brezillon <boris.brezillon@free-electrons.com>
M: Boris Brezillon <boris.brezillon@bootlin.com>
M: Marek Vasut <marek.vasut@gmail.com>
M: Richard Weinberger <richard@nod.at>
L: linux-mtd@lists.infradead.org
@ -9135,7 +9135,7 @@ M: Wenyou Yang <wenyou.yang@microchip.com>
M: Josh Wu <rainyfeeling@outlook.com>
L: linux-mtd@lists.infradead.org
S: Supported
F: drivers/mtd/nand/atmel/*
F: drivers/mtd/nand/raw/atmel/*
F: Documentation/devicetree/bindings/mtd/atmel-nand.txt
MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER
@ -9451,7 +9451,7 @@ S: Supported
F: drivers/net/ethernet/myricom/myri10ge/
NAND FLASH SUBSYSTEM
M: Boris Brezillon <boris.brezillon@free-electrons.com>
M: Boris Brezillon <boris.brezillon@bootlin.com>
R: Richard Weinberger <richard@nod.at>
L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/
@ -10205,7 +10205,7 @@ ONENAND FLASH DRIVER
M: Kyungmin Park <kyungmin.park@samsung.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/onenand/
F: drivers/mtd/nand/onenand/
F: include/linux/mtd/onenand*.h
ONSTREAM SCSI TAPE DRIVER
@ -11326,12 +11326,6 @@ F: include/sound/pxa2xx-lib.h
F: sound/arm/pxa*
F: sound/soc/pxa/
PXA3xx NAND FLASH DRIVER
M: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/pxa3xx_nand.c
QAT DRIVER
M: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
L: qat-linux@intel.com
@ -11814,8 +11808,8 @@ F: drivers/memstick/host/r592.*
RICOH SMARTMEDIA/XD DRIVER
M: Maxim Levitsky <maximlevitsky@gmail.com>
S: Maintained
F: drivers/mtd/nand/r852.c
F: drivers/mtd/nand/r852.h
F: drivers/mtd/nand/raw/r852.c
F: drivers/mtd/nand/raw/r852.h
RISC-V ARCHITECTURE
M: Palmer Dabbelt <palmer@sifive.com>
@ -14633,7 +14627,7 @@ VF610 NAND DRIVER
M: Stefan Agner <stefan@agner.ch>
L: linux-mtd@lists.infradead.org
S: Supported
F: drivers/mtd/nand/vf610_nfc.c
F: drivers/mtd/nand/raw/vf610_nfc.c
VFAT/FAT/MSDOS FILESYSTEM
M: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

View File

@ -117,15 +117,15 @@ pwri2c: i2c@40f500c0 {
status = "disabled";
};
nand0: nand@43100000 {
compatible = "marvell,pxa3xx-nand";
nand_controller: nand-controller@43100000 {
compatible = "marvell,pxa3xx-nand-controller";
reg = <0x43100000 90>;
interrupts = <45>;
clocks = <&clks CLK_NAND>;
dmas = <&pdma 97 3>;
dma-names = "data";
#address-cells = <1>;
#size-cells = <1>;
#size-cells = <0>;
status = "disabled";
};

View File

@ -49,7 +49,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_PXA3xx=y
CONFIG_MTD_NAND_MARVELL=y
CONFIG_MTD_UBI=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y

View File

@ -32,8 +32,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_PXA3xx=y
CONFIG_MTD_NAND_PXA3xx_BUILTIN=y
CONFIG_MTD_NAND_MARVELL=y
CONFIG_MTD_ONENAND=y
CONFIG_MTD_ONENAND_VERIFY_WRITE=y
CONFIG_MTD_ONENAND_GENERIC=y

View File

@ -197,7 +197,7 @@ CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x4000000
CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH=y
CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
CONFIG_MTD_NAND_SHARPSL=m
CONFIG_MTD_NAND_PXA3xx=m
CONFIG_MTD_NAND_MARVELL=m
CONFIG_MTD_NAND_CM_X270=m
CONFIG_MTD_NAND_TMIO=m
CONFIG_MTD_NAND_BRCMNAND=m

View File

@ -33,7 +33,7 @@ CONFIG_NFTL=y
CONFIG_NFTL_RW=y
CONFIG_MTD_BLOCK2MTD=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_PXA3xx=y
CONFIG_MTD_NAND_MARVELL=y
CONFIG_MTD_UBI=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_ISL29003=y

View File

@ -172,10 +172,8 @@ static struct mtd_partition aspenite_nand_partitions[] = {
};
static struct pxa3xx_nand_platform_data aspenite_nand_info = {
.enable_arbiter = 1,
.num_cs = 1,
.parts[0] = aspenite_nand_partitions,
.nr_parts[0] = ARRAY_SIZE(aspenite_nand_partitions),
.parts = aspenite_nand_partitions,
.nr_parts = ARRAY_SIZE(aspenite_nand_partitions),
};
static struct i2c_board_info aspenite_i2c_info[] __initdata = {

View File

@ -178,11 +178,8 @@ static struct mv_usb_platform_data ttc_usb_pdata = {
#endif
#endif
#if IS_ENABLED(CONFIG_MTD_NAND_PXA3xx)
static struct pxa3xx_nand_platform_data dkb_nand_info = {
.enable_arbiter = 1,
.num_cs = 1,
};
#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
static struct pxa3xx_nand_platform_data dkb_nand_info = {};
#endif
#if IS_ENABLED(CONFIG_MMP_DISP)
@ -275,7 +272,7 @@ static void __init ttc_dkb_init(void)
/* on-chip devices */
pxa910_add_uart(1);
#if IS_ENABLED(CONFIG_MTD_NAND_PXA3xx)
#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
pxa910_add_nand(&dkb_nand_info);
#endif

View File

@ -391,7 +391,7 @@ static void __init cm_x300_init_ac97(void)
static inline void cm_x300_init_ac97(void) {}
#endif
#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
static struct mtd_partition cm_x300_nand_partitions[] = {
[0] = {
.name = "OBM",
@ -429,11 +429,9 @@ static struct mtd_partition cm_x300_nand_partitions[] = {
};
static struct pxa3xx_nand_platform_data cm_x300_nand_info = {
.enable_arbiter = 1,
.keep_config = 1,
.num_cs = 1,
.parts[0] = cm_x300_nand_partitions,
.nr_parts[0] = ARRAY_SIZE(cm_x300_nand_partitions),
.parts = cm_x300_nand_partitions,
.nr_parts = ARRAY_SIZE(cm_x300_nand_partitions),
};
static void __init cm_x300_init_nand(void)

View File

@ -110,7 +110,7 @@ void __init colibri_pxa3xx_init_lcd(int bl_pin)
}
#endif
#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
static struct mtd_partition colibri_nand_partitions[] = {
{
.name = "bootloader",
@ -138,11 +138,9 @@ static struct mtd_partition colibri_nand_partitions[] = {
};
static struct pxa3xx_nand_platform_data colibri_nand_info = {
.enable_arbiter = 1,
.keep_config = 1,
.num_cs = 1,
.parts[0] = colibri_nand_partitions,
.nr_parts[0] = ARRAY_SIZE(colibri_nand_partitions),
.parts = colibri_nand_partitions,
.nr_parts = ARRAY_SIZE(colibri_nand_partitions),
};
void __init colibri_pxa3xx_init_nand(void)

View File

@ -46,7 +46,7 @@ static inline void colibri_pxa3xx_init_lcd(int bl_pin) {}
extern void colibri_pxa3xx_init_eth(struct ax_plat_data *plat_data);
#endif
#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
extern void colibri_pxa3xx_init_nand(void);
#else
static inline void colibri_pxa3xx_init_nand(void) {}

View File

@ -291,7 +291,7 @@ static void __init littleton_init_mmc(void)
static inline void littleton_init_mmc(void) {}
#endif
#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
static struct mtd_partition littleton_nand_partitions[] = {
[0] = {
.name = "Bootloader",
@ -329,10 +329,8 @@ static struct mtd_partition littleton_nand_partitions[] = {
};
static struct pxa3xx_nand_platform_data littleton_nand_info = {
.enable_arbiter = 1,
.num_cs = 1,
.parts[0] = littleton_nand_partitions,
.nr_parts[0] = ARRAY_SIZE(littleton_nand_partitions),
.parts = littleton_nand_partitions,
.nr_parts = ARRAY_SIZE(littleton_nand_partitions),
};
static void __init littleton_init_nand(void)
@ -341,7 +339,7 @@ static void __init littleton_init_nand(void)
}
#else
static inline void littleton_init_nand(void) {}
#endif /* CONFIG_MTD_NAND_PXA3xx || CONFIG_MTD_NAND_PXA3xx_MODULE */
#endif /* IS_ENABLED(CONFIG_MTD_NAND_MARVELL) */
#if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
static struct led_info littleton_da9034_leds[] = {

View File

@ -359,7 +359,7 @@ void __init mxm_8x10_ac97_init(void)
}
/* NAND flash Support */
#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
#define NAND_BLOCK_SIZE SZ_128K
#define NB(x) (NAND_BLOCK_SIZE * (x))
static struct mtd_partition mxm_8x10_nand_partitions[] = {
@ -389,11 +389,9 @@ static struct mtd_partition mxm_8x10_nand_partitions[] = {
};
static struct pxa3xx_nand_platform_data mxm_8x10_nand_info = {
.enable_arbiter = 1,
.keep_config = 1,
.num_cs = 1,
.parts[0] = mxm_8x10_nand_partitions,
.nr_parts[0] = ARRAY_SIZE(mxm_8x10_nand_partitions)
.parts = mxm_8x10_nand_partitions,
.nr_parts = ARRAY_SIZE(mxm_8x10_nand_partitions)
};
static void __init mxm_8x10_nand_init(void)
@ -402,7 +400,7 @@ static void __init mxm_8x10_nand_init(void)
}
#else
static inline void mxm_8x10_nand_init(void) {}
#endif /* CONFIG_MTD_NAND_PXA3xx || CONFIG_MTD_NAND_PXA3xx_MODULE */
#endif /* IS_ENABLED(CONFIG_MTD_NAND_MARVELL) */
/* Ethernet support: Davicom DM9000 */
static struct resource dm9k_resources[] = {

View File

@ -346,11 +346,9 @@ static struct mtd_partition raumfeld_nand_partitions[] = {
};
static struct pxa3xx_nand_platform_data raumfeld_nand_info = {
.enable_arbiter = 1,
.keep_config = 1,
.num_cs = 1,
.parts[0] = raumfeld_nand_partitions,
.nr_parts[0] = ARRAY_SIZE(raumfeld_nand_partitions),
.parts = raumfeld_nand_partitions,
.nr_parts = ARRAY_SIZE(raumfeld_nand_partitions),
};
/**

View File

@ -338,7 +338,7 @@ static void __init zylonite_init_keypad(void)
static inline void zylonite_init_keypad(void) {}
#endif
#if defined(CONFIG_MTD_NAND_PXA3xx) || defined(CONFIG_MTD_NAND_PXA3xx_MODULE)
#if IS_ENABLED(CONFIG_MTD_NAND_MARVELL)
static struct mtd_partition zylonite_nand_partitions[] = {
[0] = {
.name = "Bootloader",
@ -376,10 +376,8 @@ static struct mtd_partition zylonite_nand_partitions[] = {
};
static struct pxa3xx_nand_platform_data zylonite_nand_info = {
.enable_arbiter = 1,
.num_cs = 1,
.parts[0] = zylonite_nand_partitions,
.nr_parts[0] = ARRAY_SIZE(zylonite_nand_partitions),
.parts = zylonite_nand_partitions,
.nr_parts = ARRAY_SIZE(zylonite_nand_partitions),
};
static void __init zylonite_init_nand(void)
@ -388,7 +386,7 @@ static void __init zylonite_init_nand(void)
}
#else
static inline void zylonite_init_nand(void) {}
#endif /* CONFIG_MTD_NAND_PXA3xx || CONFIG_MTD_NAND_PXA3xx_MODULE */
#endif /* IS_ENABLED(CONFIG_MTD_NAND_MARVELL) */
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
static struct pxaohci_platform_data zylonite_ohci_info = {

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2007
*
* Derived from drivers/mtd/nand/spia.c
* Derived from drivers/mtd/nand/spia.c (removed in v3.8)
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
*
* This program is free software; you can redistribute it and/or modify

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2004
*
* Derived from drivers/mtd/nand/spia.c
* Derived from drivers/mtd/nand/spia.c (removed in v3.8)
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
*
* This program is free software; you can redistribute it and/or modify

View File

@ -333,8 +333,6 @@ source "drivers/mtd/devices/Kconfig"
source "drivers/mtd/nand/Kconfig"
source "drivers/mtd/onenand/Kconfig"
source "drivers/mtd/lpddr/Kconfig"
source "drivers/mtd/spi-nor/Kconfig"

View File

@ -32,7 +32,7 @@ obj-$(CONFIG_MTD_SWAP) += mtdswap.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
obj-y += chips/ lpddr/ maps/ devices/ nand/ tests/
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
obj-$(CONFIG_MTD_UBI) += ubi/

View File

@ -1,580 +1,6 @@
config MTD_NAND_ECC
config MTD_NAND_CORE
tristate
config MTD_NAND_ECC_SMC
bool "NAND ECC Smart Media byte order"
depends on MTD_NAND_ECC
default n
help
Software ECC according to the Smart Media Specification.
The original Linux implementation had byte 0 and 1 swapped.
source "drivers/mtd/nand/onenand/Kconfig"
menuconfig MTD_NAND
tristate "NAND Device Support"
depends on MTD
select MTD_NAND_ECC
help
This enables support for accessing all type of NAND flash
devices. For further information see
<http://www.linux-mtd.infradead.org/doc/nand.html>.
if MTD_NAND
config MTD_NAND_BCH
tristate
select BCH
depends on MTD_NAND_ECC_BCH
default MTD_NAND
config MTD_NAND_ECC_BCH
bool "Support software BCH ECC"
default n
help
This enables support for software BCH error correction. Binary BCH
codes are more powerful and cpu intensive than traditional Hamming
ECC codes. They are used with NAND devices requiring more than 1 bit
of error correction.
config MTD_SM_COMMON
tristate
default n
config MTD_NAND_DENALI
tristate
config MTD_NAND_DENALI_PCI
tristate "Support Denali NAND controller on Intel Moorestown"
select MTD_NAND_DENALI
depends on HAS_DMA && PCI
help
Enable the driver for NAND flash on Intel Moorestown, using the
Denali NAND controller core.
config MTD_NAND_DENALI_DT
tristate "Support Denali NAND controller as a DT device"
select MTD_NAND_DENALI
depends on HAS_DMA && HAVE_CLK && OF
help
Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device.
config MTD_NAND_GPIO
tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB || COMPILE_TEST
depends on HAS_IOMEM
help
This enables a NAND flash driver where control signals are
connected to GPIO pins, and commands and data are communicated
via a memory mapped interface.
config MTD_NAND_AMS_DELTA
tristate "NAND Flash device on Amstrad E3"
depends on MACH_AMS_DELTA
default y
help
Support for NAND flash on Amstrad E3 (Delta).
config MTD_NAND_OMAP2
tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
help
Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
and Keystone platforms.
config MTD_NAND_OMAP_BCH
depends on MTD_NAND_OMAP2
bool "Support hardware based BCH error correction"
default n
select BCH
help
This config enables the ELM hardware engine, which can be used to
locate and correct errors when using BCH ECC scheme. This offloads
the cpu from doing ECC error searching and correction. However some
legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
so this is optional for them.
config MTD_NAND_OMAP_BCH_BUILD
def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
config MTD_NAND_RICOH
tristate "Ricoh xD card reader"
default n
depends on PCI
select MTD_SM_COMMON
help
Enable support for Ricoh R5C852 xD card reader
You also need to enable ether
NAND SSFDC (SmartMedia) read only translation layer' or new
expermental, readwrite
'SmartMedia/xD new translation layer'
config MTD_NAND_AU1550
tristate "Au1550/1200 NAND support"
depends on MIPS_ALCHEMY
help
This enables the driver for the NAND flash controller on the
AMD/Alchemy 1550 SOC.
config MTD_NAND_BF5XX
tristate "Blackfin on-chip NAND Flash Controller driver"
depends on BF54x || BF52x
help
This enables the Blackfin on-chip NAND flash controller
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
This driver can also be built as a module. If so, the module
will be called bf5xx-nand.
config MTD_NAND_BF5XX_HWECC
bool "BF5XX NAND Hardware ECC"
default y
depends on MTD_NAND_BF5XX
help
Enable the use of the BF5XX's internal ECC generator when
using NAND.
config MTD_NAND_BF5XX_BOOTROM_ECC
bool "Use Blackfin BootROM ECC Layout"
default n
depends on MTD_NAND_BF5XX_HWECC
help
If you wish to modify NAND pages and allow the Blackfin on-chip
BootROM to boot from them, say Y here. This is only necessary
if you are booting U-Boot out of NAND and you wish to update
U-Boot from Linux' userspace. Otherwise, you should say N here.
If unsure, say N.
config MTD_NAND_S3C2410
tristate "NAND Flash support for Samsung S3C SoCs"
depends on ARCH_S3C24XX || ARCH_S3C64XX
help
This enables the NAND flash controller on the S3C24xx and S3C64xx
SoCs
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_S3C2410_DEBUG
bool "Samsung S3C NAND driver debug"
depends on MTD_NAND_S3C2410
help
Enable debugging of the S3C NAND driver
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on 4xx
select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
config MTD_NAND_S3C2410_CLKSTOP
bool "Samsung S3C NAND IDLE clock stop"
depends on MTD_NAND_S3C2410
default n
help
Stop the clock to the NAND controller when there is no chip
selected to save power. This will mean there is a small delay
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
config MTD_NAND_TANGO
tristate "NAND Flash support for Tango chips"
depends on ARCH_TANGO || COMPILE_TEST
depends on HAS_DMA
help
Enables the NAND Flash controller on Tango chips.
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
depends on HAS_IOMEM
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
This is a reimplementation of M-Systems DiskOnChip 2000,
Millennium and Millennium Plus as a standard NAND device driver,
as opposed to the earlier self-contained MTD device drivers.
This should enable, among other things, proper JFFS2 operation on
these devices.
config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
depends on MTD_NAND_DISKONCHIP
help
This option allows you to specify nonstandard address at which to
probe for a DiskOnChip, or to change the detection options. You
are unlikely to need any of this unless you are using LinuxBIOS.
Say 'N'.
config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
depends on MTD_NAND_DISKONCHIP
default "0"
---help---
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option allows you to specify a single address at which to probe
for the device, which is useful if you have other devices in that
range which get upset when they are probed.
(Note that on PowerPC, the normal probe will only check at
0xE4000000.)
Normally, you should leave this set to zero, to allow the probe at
the normal addresses.
config MTD_NAND_DISKONCHIP_PROBE_HIGH
bool "Probe high addresses"
depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
help
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option changes to make it probe between 0xFFFC8000 and
0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be
useful to you. Say 'N'.
config MTD_NAND_DISKONCHIP_BBTWRITE
bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
depends on MTD_NAND_DISKONCHIP
help
On DiskOnChip devices shipped with the INFTL filesystem (Millennium
and 2000 TSOP/Alon), Linux reserves some space at the end of the
device for the Bad Block Table (BBT). If you have existing INFTL
data on your device (created by non-Linux tools such as M-Systems'
DOS drivers), your data might overlap the area Linux wants to use for
the BBT. If this is a concern for you, leave this option disabled and
Linux will not write BBT data into this area.
The downside of leaving this option disabled is that if bad blocks
are detected by Linux, they will not be recorded in the BBT, which
could cause future problems.
Once you enable this option, new filesystems (INFTL or others, created
in Linux or other operating systems) will not use the reserved area.
The only reason not to enable this option is to prevent damage to
preexisting filesystems.
Even if you leave this disabled, you can enable BBT writes at module
load time (assuming you build diskonchip as a module) with the module
parameter "inftl_bbt_write=1".
config MTD_NAND_DOCG4
tristate "Support for DiskOnChip G4"
depends on HAS_IOMEM
select BCH
select BITREVERSE
help
Support for diskonchip G4 nand flash, found in various smartphones and
PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
Portege G900, Asus P526, and O2 XDA Zinc.
With this driver you will be able to use UBI and create a ubifs on the
device, so you may wish to consider enabling UBI and UBIFS as well.
These devices ship with the Mys/Sandisk SAFTL formatting, for which
there is currently no mtd parser, so you may want to use command line
partitioning to segregate write-protected blocks. On the Treo680, the
first five erase blocks (256KiB each) are write-protected, followed
by the block containing the saftl partition table. This is probably
typical.
config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on ARCH_PXA
config MTD_NAND_CAFE
tristate "NAND support for OLPC CAFÉ chip"
depends on PCI
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
Use NAND flash attached to the CAFÉ chip designed for the OLPC
laptop.
config MTD_NAND_CS553X
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
depends on X86_32
depends on !UML && HAS_IOMEM
help
The CS553x companion chips for the AMD Geode processor
include NAND flash controllers with built-in hardware ECC
capabilities; enabling this option will allow you to use
these. The driver will check the MSRs to verify that the
controller is enabled for NAND, and currently requires that
the controller be in MMIO mode.
If you say "m", the module will be called cs553x_nand.
config MTD_NAND_ATMEL
tristate "Support for NAND Flash / SmartMedia on AT91"
depends on ARCH_AT91
select MFD_ATMEL_SMC
help
Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 processors.
config MTD_NAND_PXA3xx
tristate "NAND support on PXA3xx and Armada 370/XP"
depends on !MTD_NAND_MARVELL
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 32-bit Armada
platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada
platforms (7K, 8K) (NFCv2).
config MTD_NAND_MARVELL
tristate "NAND controller support on Marvell boards"
depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
COMPILE_TEST
depends on HAS_IOMEM
help
This enables the NAND flash controller driver for Marvell boards,
including:
- PXA3xx processors (NFCv1)
- 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2)
- 64-bit Aramda platforms (7k, 8k) (NFCv2)
config MTD_NAND_SLC_LPC32XX
tristate "NXP LPC32xx SLC Controller"
depends on ARCH_LPC32XX
help
Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
chips) NAND controller. This is the default for the PHYTEC 3250
reference board which contains a NAND256R3A2CZA6 chip.
Please check the actual NAND chip connected and its support
by the SLC NAND controller.
config MTD_NAND_MLC_LPC32XX
tristate "NXP LPC32xx MLC Controller"
depends on ARCH_LPC32XX
help
Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
controller. This is the default for the WORK92105 controller
board.
Please check the actual NAND chip connected and its support
by the MLC NAND controller.
config MTD_NAND_CM_X270
tristate "Support for NAND Flash on CM-X270 modules"
depends on MACH_ARMCORE
config MTD_NAND_PASEMI
tristate "NAND support for PA Semi PWRficient"
depends on PPC_PASEMI
help
Enables support for NAND Flash interface on PA Semi PWRficient
based boards
config MTD_NAND_TMIO
tristate "NAND Flash device on Toshiba Mobile IO Controller"
depends on MFD_TMIO
help
Support for NAND flash connected to a Toshiba Mobile IO
Controller in some PDAs, including the Sharp SL6000x.
config MTD_NAND_NANDSIM
tristate "Support for NAND Flash Simulator"
help
The simulator may simulate various NAND flash chips for the
MTD nand layer.
config MTD_NAND_GPMI_NAND
tristate "GPMI NAND Flash Controller driver"
depends on MTD_NAND && MXS_DMA
help
Enables NAND Flash support for IMX23, IMX28 or IMX6.
The GPMI controller is very powerful, with the help of BCH
module, it can do the hardware ECC. The GPMI supports several
NAND flashs at the same time.
config MTD_NAND_BRCMNAND
tristate "Broadcom STB NAND controller"
depends on ARM || ARM64 || MIPS
help
Enables the Broadcom NAND controller driver. The controller was
originally designed for Set-Top Box but is used on various BCM7xxx,
BCM3xxx, BCM63xxx, iProc/Cygnus and more.
config MTD_NAND_BCM47XXNFLASH
tristate "Support for NAND flash on BCM4706 BCMA bus"
depends on BCMA_NFLASH
help
BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for
NAND flash memories. For now only BCM4706 is supported.
config MTD_NAND_PLATFORM
tristate "Support for generic platform NAND driver"
depends on HAS_IOMEM
help
This implements a generic NAND driver for on-SOC platform
devices. You will need to provide platform-specific functions
via platform_data.
config MTD_NAND_ORION
tristate "NAND Flash support for Marvell Orion SoC"
depends on PLAT_ORION
help
This enables the NAND flash controller on Orion machines.
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_OXNAS
tristate "NAND Flash support for Oxford Semiconductor SoC"
depends on ARCH_OXNAS || COMPILE_TEST
depends on HAS_IOMEM
help
This enables the NAND flash controller on Oxford Semiconductor SoCs.
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on FSL_SOC
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
Controller Module with built-in hardware ECC capabilities.
Enabling this option will enable you to use this to control
external NAND devices.
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
select FSL_IFC
select MEMORY
help
Various Freescale chips e.g P1010, include a NAND Flash machine
with built-in hardware ECC capabilities.
Enabling this option will enable you to use this to control
external NAND devices.
config MTD_NAND_FSL_UPM
tristate "Support for NAND on Freescale UPM"
depends on PPC_83xx || PPC_85xx
select FSL_LBC
help
Enables support for NAND Flash chips wired onto Freescale PowerPC
processor localbus with User-Programmable Machine support.
config MTD_NAND_MPC5121_NFC
tristate "MPC5121 built-in NAND Flash Controller support"
depends on PPC_MPC512x
help
This enables the driver for the NAND flash controller on the
MPC5121 SoC.
config MTD_NAND_VF610_NFC
tristate "Support for Freescale NFC for VF610/MPC5125"
depends on (SOC_VF610 || COMPILE_TEST)
depends on HAS_IOMEM
help
Enables support for NAND Flash Controller on some Freescale
processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
The driver supports a maximum 2k page size. With 2k pages and
64 bytes or more of OOB, hardware ECC with up to 32-bit error
correction is supported. Hardware ECC is only enabled through
device tree.
config MTD_NAND_MXC
tristate "MXC NAND support"
depends on ARCH_MXC
help
This enables the driver for the NAND flash controller on the
MXC processors.
config MTD_NAND_SH_FLCTL
tristate "Support for NAND on Renesas SuperH FLCTL"
depends on SUPERH || COMPILE_TEST
depends on HAS_IOMEM
depends on HAS_DMA
help
Several Renesas SuperH CPU has FLCTL. This option enables support
for NAND Flash using FLCTL.
config MTD_NAND_DAVINCI
tristate "Support NAND on DaVinci/Keystone SoC"
depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
help
Enable the driver for NAND flash chips on Texas Instruments
DaVinci/Keystone processors.
config MTD_NAND_TXX9NDFMC
tristate "NAND Flash support for TXx9 SoC"
depends on SOC_TX4938 || SOC_TX4939
help
This enables the NAND flash controller on the TXx9 SoCs.
config MTD_NAND_SOCRATES
tristate "Support for NAND on Socrates board"
depends on SOCRATES
help
Enables support for NAND Flash chips wired onto Socrates board.
config MTD_NAND_NUC900
tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
depends on ARCH_W90X900
help
This enables the driver for the NAND Flash on evaluation board based
on w90p910 / NUC9xx.
config MTD_NAND_JZ4740
tristate "Support for JZ4740 SoC NAND controller"
depends on MACH_JZ4740
help
Enables support for NAND Flash on JZ4740 SoC based boards.
config MTD_NAND_JZ4780
tristate "Support for NAND on JZ4780 SoC"
depends on MACH_JZ4780 && JZ4780_NEMC
help
Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
based boards, using the BCH controller for hardware error correction.
config MTD_NAND_FSMC
tristate "Support for NAND on ST Micros FSMC"
depends on OF
depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
help
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
config MTD_NAND_XWAY
bool "Support for NAND on Lantiq XWAY SoC"
depends on LANTIQ && SOC_TYPE_XWAY
help
Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
to the External Bus Unit (EBU).
config MTD_NAND_SUNXI
tristate "Support for NAND on Allwinner SoCs"
depends on ARCH_SUNXI
help
Enables support for NAND Flash chips on Allwinner SoCs.
config MTD_NAND_HISI504
tristate "Support for NAND controller on Hisilicon SoC Hip04"
depends on ARCH_HISI || COMPILE_TEST
depends on HAS_DMA
help
Enables support for NAND controller on Hisilicon SoC Hip04.
config MTD_NAND_QCOM
tristate "Support for NAND on QCOM SoCs"
depends on ARCH_QCOM
help
Enables support for NAND flash chips on SoCs containing the EBI2 NAND
controller. This controller is found on IPQ806x SoC.
config MTD_NAND_MTK
tristate "Support for NAND controller on MTK SoCs"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_DMA
help
Enables support for NAND controller on MTK SoCs.
This controller is found on mt27xx, mt81xx, mt65xx SoCs.
endif # MTD_NAND
source "drivers/mtd/nand/raw/Kconfig"

View File

@ -1,71 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
#
# linux/drivers/nand/Makefile
#
obj-$(CONFIG_MTD_NAND) += nand.o
obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
nandcore-objs := core.o bbt.o
obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_DENALI) += denali.o
obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel/
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
omap2_nand-objs := omap2.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o
obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o
obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_JZ4780) += jz4780_nand.o jz4780_bch.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_amd.o
nand-objs += nand_hynix.o
nand-objs += nand_macronix.o
nand-objs += nand_micron.o
nand-objs += nand_samsung.o
nand-objs += nand_toshiba.o
obj-y += onenand/
obj-y += raw/

130
drivers/mtd/nand/bbt.c Normal file
View File

@ -0,0 +1,130 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017 Free Electrons
*
* Authors:
* Boris Brezillon <boris.brezillon@free-electrons.com>
* Peter Pan <peterpandong@micron.com>
*/
#define pr_fmt(fmt) "nand-bbt: " fmt
#include <linux/mtd/nand.h>
#include <linux/slab.h>
/**
* nanddev_bbt_init() - Initialize the BBT (Bad Block Table)
* @nand: NAND device
*
* Initialize the in-memory BBT.
*
* Return: 0 in case of success, a negative error code otherwise.
*/
int nanddev_bbt_init(struct nand_device *nand)
{
unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
unsigned int nblocks = nanddev_neraseblocks(nand);
unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
BITS_PER_LONG);
nand->bbt.cache = kzalloc(nwords, GFP_KERNEL);
if (!nand->bbt.cache)
return -ENOMEM;
return 0;
}
EXPORT_SYMBOL_GPL(nanddev_bbt_init);
/**
* nanddev_bbt_cleanup() - Cleanup the BBT (Bad Block Table)
* @nand: NAND device
*
* Undoes what has been done in nanddev_bbt_init()
*/
void nanddev_bbt_cleanup(struct nand_device *nand)
{
kfree(nand->bbt.cache);
}
EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup);
/**
* nanddev_bbt_update() - Update a BBT
* @nand: nand device
*
* Update the BBT. Currently a NOP function since on-flash bbt is not yet
* supported.
*
* Return: 0 in case of success, a negative error code otherwise.
*/
int nanddev_bbt_update(struct nand_device *nand)
{
return 0;
}
EXPORT_SYMBOL_GPL(nanddev_bbt_update);
/**
* nanddev_bbt_get_block_status() - Return the status of an eraseblock
* @nand: nand device
* @entry: the BBT entry
*
* Return: a positive number nand_bbt_block_status status or -%ERANGE if @entry
* is bigger than the BBT size.
*/
int nanddev_bbt_get_block_status(const struct nand_device *nand,
unsigned int entry)
{
unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
unsigned long *pos = nand->bbt.cache +
((entry * bits_per_block) / BITS_PER_LONG);
unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
unsigned long status;
if (entry >= nanddev_neraseblocks(nand))
return -ERANGE;
status = pos[0] >> offs;
if (bits_per_block + offs > BITS_PER_LONG)
status |= pos[1] << (BITS_PER_LONG - offs);
return status & GENMASK(bits_per_block - 1, 0);
}
EXPORT_SYMBOL_GPL(nanddev_bbt_get_block_status);
/**
* nanddev_bbt_set_block_status() - Update the status of an eraseblock in the
* in-memory BBT
* @nand: nand device
* @entry: the BBT entry to update
* @status: the new status
*
* Update an entry of the in-memory BBT. If you want to push the updated BBT
* the NAND you should call nanddev_bbt_update().
*
* Return: 0 in case of success or -%ERANGE if @entry is bigger than the BBT
* size.
*/
int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
enum nand_bbt_block_status status)
{
unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
unsigned long *pos = nand->bbt.cache +
((entry * bits_per_block) / BITS_PER_LONG);
unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
unsigned long val = status & GENMASK(bits_per_block - 1, 0);
if (entry >= nanddev_neraseblocks(nand))
return -ERANGE;
pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs);
pos[0] |= val << offs;
if (bits_per_block + offs > BITS_PER_LONG) {
unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
pos[1] &= ~GENMASK(rbits - 1, 0);
pos[1] |= val >> rbits;
}
return 0;
}
EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status);

View File

@ -1,862 +0,0 @@
/* linux/drivers/mtd/nand/bf5xx_nand.c
*
* Copyright 2006-2008 Analog Devices Inc.
* http://blackfin.uclinux.org/
* Bryan Wu <bryan.wu@analog.com>
*
* Blackfin BF5xx on-chip NAND flash controller driver
*
* Derived from drivers/mtd/nand/s3c2410.c
* Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
*
* Derived from drivers/mtd/nand/cafe.c
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
*
* Changelog:
* 12-Jun-2007 Bryan Wu: Initial version
* 18-Jul-2007 Bryan Wu:
* - ECC_HW and ECC_SW supported
* - DMA supported in ECC_HW
* - YAFFS tested as rootfs in both ECC_HW and ECC_SW
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
#include <asm/blackfin.h>
#include <asm/dma.h>
#include <asm/cacheflush.h>
#include <asm/nand.h>
#include <asm/portmux.h>
#define DRV_NAME "bf5xx-nand"
#define DRV_VERSION "1.2"
#define DRV_AUTHOR "Bryan Wu <bryan.wu@analog.com>"
#define DRV_DESC "BF5xx on-chip NAND FLash Controller Driver"
/* NFC_STAT Masks */
#define NBUSY 0x01 /* Not Busy */
#define WB_FULL 0x02 /* Write Buffer Full */
#define PG_WR_STAT 0x04 /* Page Write Pending */
#define PG_RD_STAT 0x08 /* Page Read Pending */
#define WB_EMPTY 0x10 /* Write Buffer Empty */
/* NFC_IRQSTAT Masks */
#define NBUSYIRQ 0x01 /* Not Busy IRQ */
#define WB_OVF 0x02 /* Write Buffer Overflow */
#define WB_EDGE 0x04 /* Write Buffer Edge Detect */
#define RD_RDY 0x08 /* Read Data Ready */
#define WR_DONE 0x10 /* Page Write Done */
/* NFC_RST Masks */
#define ECC_RST 0x01 /* ECC (and NFC counters) Reset */
/* NFC_PGCTL Masks */
#define PG_RD_START 0x01 /* Page Read Start */
#define PG_WR_START 0x02 /* Page Write Start */
#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
static int hardware_ecc = 1;
#else
static int hardware_ecc;
#endif
static const unsigned short bfin_nfc_pin_req[] =
{P_NAND_CE,
P_NAND_RB,
P_NAND_D0,
P_NAND_D1,
P_NAND_D2,
P_NAND_D3,
P_NAND_D4,
P_NAND_D5,
P_NAND_D6,
P_NAND_D7,
P_NAND_WE,
P_NAND_RE,
P_NAND_CLE,
P_NAND_ALE,
0};
#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
static int bootrom_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 7)
return -ERANGE;
oobregion->offset = section * 8;
oobregion->length = 3;
return 0;
}
static int bootrom_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 7)
return -ERANGE;
oobregion->offset = (section * 8) + 3;
oobregion->length = 5;
return 0;
}
static const struct mtd_ooblayout_ops bootrom_ooblayout_ops = {
.ecc = bootrom_ooblayout_ecc,
.free = bootrom_ooblayout_free,
};
#endif
/*
* Data structures for bf5xx nand flash controller driver
*/
/* bf5xx nand info */
struct bf5xx_nand_info {
/* mtd info */
struct nand_hw_control controller;
struct nand_chip chip;
/* platform info */
struct bf5xx_nand_platform *platform;
/* device info */
struct device *device;
/* DMA stuff */
struct completion dma_completion;
};
/*
* Conversion functions
*/
static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
{
return container_of(mtd_to_nand(mtd), struct bf5xx_nand_info,
chip);
}
static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
{
return platform_get_drvdata(pdev);
}
static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
{
return dev_get_platdata(&pdev->dev);
}
/*
* struct nand_chip interface function pointers
*/
/*
* bf5xx_nand_hwcontrol
*
* Issue command and address cycles to the chip
*/
static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
if (cmd == NAND_CMD_NONE)
return;
while (bfin_read_NFC_STAT() & WB_FULL)
cpu_relax();
if (ctrl & NAND_CLE)
bfin_write_NFC_CMD(cmd);
else if (ctrl & NAND_ALE)
bfin_write_NFC_ADDR(cmd);
SSYNC();
}
/*
* bf5xx_nand_devready()
*
* returns 0 if the nand is busy, 1 if it is ready
*/
static int bf5xx_nand_devready(struct mtd_info *mtd)
{
unsigned short val = bfin_read_NFC_STAT();
if ((val & NBUSY) == NBUSY)
return 1;
else
return 0;
}
/*
* ECC functions
* These allow the bf5xx to use the controller's ECC
* generator block to ECC the data as it passes through
*/
/*
* ECC error correction function
*/
static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
u32 syndrome[5];
u32 calced, stored;
int i;
unsigned short failing_bit, failing_byte;
u_char data;
calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
syndrome[0] = (calced ^ stored);
/*
* syndrome 0: all zero
* No error in data
* No action
*/
if (!syndrome[0] || !calced || !stored)
return 0;
/*
* sysdrome 0: only one bit is one
* ECC data was incorrect
* No action
*/
if (hweight32(syndrome[0]) == 1) {
dev_err(info->device, "ECC data was incorrect!\n");
return -EBADMSG;
}
syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
syndrome[4] = syndrome[2] ^ syndrome[3];
for (i = 0; i < 5; i++)
dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
dev_info(info->device,
"calced[0x%08x], stored[0x%08x]\n",
calced, stored);
/*
* sysdrome 0: exactly 11 bits are one, each parity
* and parity' pair is 1 & 0 or 0 & 1.
* 1-bit correctable error
* Correct the error
*/
if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
dev_info(info->device,
"1-bit correctable error, correct it.\n");
dev_info(info->device,
"syndrome[1] 0x%08x\n", syndrome[1]);
failing_bit = syndrome[1] & 0x7;
failing_byte = syndrome[1] >> 0x3;
data = *(dat + failing_byte);
data = data ^ (0x1 << failing_bit);
*(dat + failing_byte) = data;
return 1;
}
/*
* sysdrome 0: random data
* More than 1-bit error, non-correctable error
* Discard data, mark bad block
*/
dev_err(info->device,
"More than 1-bit error, non-correctable error.\n");
dev_err(info->device,
"Please discard data, mark bad block\n");
return -EBADMSG;
}
static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
struct nand_chip *chip = mtd_to_nand(mtd);
int ret, bitflips = 0;
ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
if (ret < 0)
return ret;
bitflips = ret;
/* If ecc size is 512, correct second 256 bytes */
if (chip->ecc.size == 512) {
dat += 256;
read_ecc += 3;
calc_ecc += 3;
ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
if (ret < 0)
return ret;
bitflips += ret;
}
return bitflips;
}
static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
return;
}
static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
const u_char *dat, u_char *ecc_code)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
struct nand_chip *chip = mtd_to_nand(mtd);
u16 ecc0, ecc1;
u32 code[2];
u8 *p;
/* first 3 bytes ECC code for 256 page size */
ecc0 = bfin_read_NFC_ECC0();
ecc1 = bfin_read_NFC_ECC1();
code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
p = (u8 *) code;
memcpy(ecc_code, p, 3);
/* second 3 bytes ECC code for 512 ecc size */
if (chip->ecc.size == 512) {
ecc0 = bfin_read_NFC_ECC2();
ecc1 = bfin_read_NFC_ECC3();
code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11);
/* second 3 bytes in ecc_code for second 256
* bytes of 512 page size
*/
p = (u8 *) (code + 1);
memcpy((ecc_code + 3), p, 3);
dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
}
return 0;
}
/*
* PIO mode for buffer writing and reading
*/
static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
unsigned short val;
/*
* Data reads are requested by first writing to NFC_DATA_RD
* and then reading back from NFC_READ.
*/
for (i = 0; i < len; i++) {
while (bfin_read_NFC_STAT() & WB_FULL)
cpu_relax();
/* Contents do not matter */
bfin_write_NFC_DATA_RD(0x0000);
SSYNC();
while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
cpu_relax();
buf[i] = bfin_read_NFC_READ();
val = bfin_read_NFC_IRQSTAT();
val |= RD_RDY;
bfin_write_NFC_IRQSTAT(val);
SSYNC();
}
}
static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
{
uint8_t val;
bf5xx_nand_read_buf(mtd, &val, 1);
return val;
}
static void bf5xx_nand_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
int i;
for (i = 0; i < len; i++) {
while (bfin_read_NFC_STAT() & WB_FULL)
cpu_relax();
bfin_write_NFC_DATA_WR(buf[i]);
SSYNC();
}
}
static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
u16 *p = (u16 *) buf;
len >>= 1;
/*
* Data reads are requested by first writing to NFC_DATA_RD
* and then reading back from NFC_READ.
*/
bfin_write_NFC_DATA_RD(0x5555);
SSYNC();
for (i = 0; i < len; i++)
p[i] = bfin_read_NFC_READ();
}
static void bf5xx_nand_write_buf16(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
int i;
u16 *p = (u16 *) buf;
len >>= 1;
for (i = 0; i < len; i++)
bfin_write_NFC_DATA_WR(p[i]);
SSYNC();
}
/*
* DMA functions for buffer writing and reading
*/
static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
{
struct bf5xx_nand_info *info = dev_id;
clear_dma_irqstat(CH_NFC);
disable_dma(CH_NFC);
complete(&info->dma_completion);
return IRQ_HANDLED;
}
static void bf5xx_nand_dma_rw(struct mtd_info *mtd,
uint8_t *buf, int is_read)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
struct nand_chip *chip = mtd_to_nand(mtd);
unsigned short val;
dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
mtd, buf, is_read);
/*
* Before starting a dma transfer, be sure to invalidate/flush
* the cache over the address range of your DMA buffer to
* prevent cache coherency problems. Otherwise very subtle bugs
* can be introduced to your driver.
*/
if (is_read)
invalidate_dcache_range((unsigned int)buf,
(unsigned int)(buf + chip->ecc.size));
else
flush_dcache_range((unsigned int)buf,
(unsigned int)(buf + chip->ecc.size));
/*
* This register must be written before each page is
* transferred to generate the correct ECC register
* values.
*/
bfin_write_NFC_RST(ECC_RST);
SSYNC();
while (bfin_read_NFC_RST() & ECC_RST)
cpu_relax();
disable_dma(CH_NFC);
clear_dma_irqstat(CH_NFC);
/* setup DMA register with Blackfin DMA API */
set_dma_config(CH_NFC, 0x0);
set_dma_start_addr(CH_NFC, (unsigned long) buf);
/* The DMAs have different size on BF52x and BF54x */
#ifdef CONFIG_BF52x
set_dma_x_count(CH_NFC, (chip->ecc.size >> 1));
set_dma_x_modify(CH_NFC, 2);
val = DI_EN | WDSIZE_16;
#endif
#ifdef CONFIG_BF54x
set_dma_x_count(CH_NFC, (chip->ecc.size >> 2));
set_dma_x_modify(CH_NFC, 4);
val = DI_EN | WDSIZE_32;
#endif
/* setup write or read operation */
if (is_read)
val |= WNR;
set_dma_config(CH_NFC, val);
enable_dma(CH_NFC);
/* Start PAGE read/write operation */
if (is_read)
bfin_write_NFC_PGCTL(PG_RD_START);
else
bfin_write_NFC_PGCTL(PG_WR_START);
wait_for_completion(&info->dma_completion);
}
static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
uint8_t *buf, int len)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
struct nand_chip *chip = mtd_to_nand(mtd);
dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
if (len == chip->ecc.size)
bf5xx_nand_dma_rw(mtd, buf, 1);
else
bf5xx_nand_read_buf(mtd, buf, len);
}
static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
struct nand_chip *chip = mtd_to_nand(mtd);
dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
if (len == chip->ecc.size)
bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
else
bf5xx_nand_write_buf(mtd, buf, len);
}
static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
nand_read_page_op(chip, page, 0, NULL, 0);
bf5xx_nand_read_buf(mtd, buf, mtd->writesize);
bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required,
int page)
{
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
/*
* System initialization functions
*/
static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
{
int ret;
/* Do not use dma */
if (!hardware_ecc)
return 0;
init_completion(&info->dma_completion);
/* Request NFC DMA channel */
ret = request_dma(CH_NFC, "BF5XX NFC driver");
if (ret < 0) {
dev_err(info->device, " unable to get DMA channel\n");
return ret;
}
#ifdef CONFIG_BF54x
/* Setup DMAC1 channel mux for NFC which shared with SDH */
bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() & ~1);
SSYNC();
#endif
set_dma_callback(CH_NFC, bf5xx_nand_dma_irq, info);
/* Turn off the DMA channel first */
disable_dma(CH_NFC);
return 0;
}
static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info)
{
/* Free NFC DMA channel */
if (hardware_ecc)
free_dma(CH_NFC);
}
/*
* BF5XX NFC hardware initialization
* - pin mux setup
* - clear interrupt status
*/
static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
{
int err = 0;
unsigned short val;
struct bf5xx_nand_platform *plat = info->platform;
/* setup NFC_CTL register */
dev_info(info->device,
"data_width=%d, wr_dly=%d, rd_dly=%d\n",
(plat->data_width ? 16 : 8),
plat->wr_dly, plat->rd_dly);
val = (1 << NFC_PG_SIZE_OFFSET) |
(plat->data_width << NFC_NWIDTH_OFFSET) |
(plat->rd_dly << NFC_RDDLY_OFFSET) |
(plat->wr_dly << NFC_WRDLY_OFFSET);
dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
bfin_write_NFC_CTL(val);
SSYNC();
/* clear interrupt status */
bfin_write_NFC_IRQMASK(0x0);
SSYNC();
val = bfin_read_NFC_IRQSTAT();
bfin_write_NFC_IRQSTAT(val);
SSYNC();
/* DMA initialization */
if (bf5xx_nand_dma_init(info))
err = -ENXIO;
return err;
}
/*
* Device management interface
*/
static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
{
struct mtd_info *mtd = nand_to_mtd(&info->chip);
struct mtd_partition *parts = info->platform->partitions;
int nr = info->platform->nr_partitions;
return mtd_device_register(mtd, parts, nr);
}
static int bf5xx_nand_remove(struct platform_device *pdev)
{
struct bf5xx_nand_info *info = to_nand_info(pdev);
/* first thing we need to do is release all our mtds
* and their partitions, then go through freeing the
* resources used
*/
nand_release(nand_to_mtd(&info->chip));
peripheral_free_list(bfin_nfc_pin_req);
bf5xx_nand_dma_remove(info);
return 0;
}
static int bf5xx_nand_scan(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
return ret;
if (hardware_ecc) {
/*
* for nand with page size > 512B, think it as several sections with 512B
*/
if (likely(mtd->writesize >= 512)) {
chip->ecc.size = 512;
chip->ecc.bytes = 6;
chip->ecc.strength = 2;
} else {
chip->ecc.size = 256;
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
SSYNC();
}
}
return nand_scan_tail(mtd);
}
/*
* bf5xx_nand_probe
*
* called by device layer when it finds a device matching
* one our driver can handled. This code checks to see if
* it can allocate all necessary resources then calls the
* nand layer to look for devices
*/
static int bf5xx_nand_probe(struct platform_device *pdev)
{
struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
struct bf5xx_nand_info *info = NULL;
struct nand_chip *chip = NULL;
struct mtd_info *mtd = NULL;
int err = 0;
dev_dbg(&pdev->dev, "(%p)\n", pdev);
if (!plat) {
dev_err(&pdev->dev, "no platform specific information\n");
return -EINVAL;
}
if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
dev_err(&pdev->dev, "requesting Peripherals failed\n");
return -EFAULT;
}
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) {
err = -ENOMEM;
goto out_err;
}
platform_set_drvdata(pdev, info);
nand_hw_control_init(&info->controller);
info->device = &pdev->dev;
info->platform = plat;
/* initialise chip data struct */
chip = &info->chip;
mtd = nand_to_mtd(&info->chip);
if (plat->data_width)
chip->options |= NAND_BUSWIDTH_16;
chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
chip->read_buf = (plat->data_width) ?
bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
chip->write_buf = (plat->data_width) ?
bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
chip->read_byte = bf5xx_nand_read_byte;
chip->cmd_ctrl = bf5xx_nand_hwcontrol;
chip->dev_ready = bf5xx_nand_devready;
nand_set_controller_data(chip, mtd);
chip->controller = &info->controller;
chip->IO_ADDR_R = (void __iomem *) NFC_READ;
chip->IO_ADDR_W = (void __iomem *) NFC_DATA_WR;
chip->chip_delay = 0;
/* initialise mtd info data struct */
mtd->dev.parent = &pdev->dev;
/* initialise the hardware */
err = bf5xx_nand_hw_init(info);
if (err)
goto out_err;
/* setup hardware ECC data struct */
if (hardware_ecc) {
#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
mtd_set_ooblayout(mtd, &bootrom_ooblayout_ops);
#endif
chip->read_buf = bf5xx_nand_dma_read_buf;
chip->write_buf = bf5xx_nand_dma_write_buf;
chip->ecc.calculate = bf5xx_nand_calculate_ecc;
chip->ecc.correct = bf5xx_nand_correct_data;
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.hwctl = bf5xx_nand_enable_hwecc;
chip->ecc.read_page_raw = bf5xx_nand_read_page_raw;
chip->ecc.write_page_raw = bf5xx_nand_write_page_raw;
} else {
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
}
/* scan hardware nand chip and setup mtd info data struct */
if (bf5xx_nand_scan(mtd)) {
err = -ENXIO;
goto out_err_nand_scan;
}
#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
chip->badblockpos = 63;
#endif
/* add NAND partition */
bf5xx_nand_add_partition(info);
dev_dbg(&pdev->dev, "initialised ok\n");
return 0;
out_err_nand_scan:
bf5xx_nand_dma_remove(info);
out_err:
peripheral_free_list(bfin_nfc_pin_req);
return err;
}
/* driver device registration */
static struct platform_driver bf5xx_nand_driver = {
.probe = bf5xx_nand_probe,
.remove = bf5xx_nand_remove,
.driver = {
.name = DRV_NAME,
},
};
module_platform_driver(bf5xx_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);
MODULE_ALIAS("platform:" DRV_NAME);

244
drivers/mtd/nand/core.c Normal file
View File

@ -0,0 +1,244 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017 Free Electrons
*
* Authors:
* Boris Brezillon <boris.brezillon@free-electrons.com>
* Peter Pan <peterpandong@micron.com>
*/
#define pr_fmt(fmt) "nand: " fmt
#include <linux/module.h>
#include <linux/mtd/nand.h>
/**
* nanddev_isbad() - Check if a block is bad
* @nand: NAND device
* @pos: position pointing to the block we want to check
*
* Return: true if the block is bad, false otherwise.
*/
bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos)
{
if (nanddev_bbt_is_initialized(nand)) {
unsigned int entry;
int status;
entry = nanddev_bbt_pos_to_entry(nand, pos);
status = nanddev_bbt_get_block_status(nand, entry);
/* Lazy block status retrieval */
if (status == NAND_BBT_BLOCK_STATUS_UNKNOWN) {
if (nand->ops->isbad(nand, pos))
status = NAND_BBT_BLOCK_FACTORY_BAD;
else
status = NAND_BBT_BLOCK_GOOD;
nanddev_bbt_set_block_status(nand, entry, status);
}
if (status == NAND_BBT_BLOCK_WORN ||
status == NAND_BBT_BLOCK_FACTORY_BAD)
return true;
return false;
}
return nand->ops->isbad(nand, pos);
}
EXPORT_SYMBOL_GPL(nanddev_isbad);
/**
* nanddev_markbad() - Mark a block as bad
* @nand: NAND device
* @pos: position of the block to mark bad
*
* Mark a block bad. This function is updating the BBT if available and
* calls the low-level markbad hook (nand->ops->markbad()).
*
* Return: 0 in case of success, a negative error code otherwise.
*/
int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos)
{
struct mtd_info *mtd = nanddev_to_mtd(nand);
unsigned int entry;
int ret = 0;
if (nanddev_isbad(nand, pos))
return 0;
ret = nand->ops->markbad(nand, pos);
if (ret)
pr_warn("failed to write BBM to block @%llx (err = %d)\n",
nanddev_pos_to_offs(nand, pos), ret);
if (!nanddev_bbt_is_initialized(nand))
goto out;
entry = nanddev_bbt_pos_to_entry(nand, pos);
ret = nanddev_bbt_set_block_status(nand, entry, NAND_BBT_BLOCK_WORN);
if (ret)
goto out;
ret = nanddev_bbt_update(nand);
out:
if (!ret)
mtd->ecc_stats.badblocks++;
return ret;
}
EXPORT_SYMBOL_GPL(nanddev_markbad);
/**
* nanddev_isreserved() - Check whether an eraseblock is reserved or not
* @nand: NAND device
* @pos: NAND position to test
*
* Checks whether the eraseblock pointed by @pos is reserved or not.
*
* Return: true if the eraseblock is reserved, false otherwise.
*/
bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos)
{
unsigned int entry;
int status;
if (!nanddev_bbt_is_initialized(nand))
return false;
/* Return info from the table */
entry = nanddev_bbt_pos_to_entry(nand, pos);
status = nanddev_bbt_get_block_status(nand, entry);
return status == NAND_BBT_BLOCK_RESERVED;
}
EXPORT_SYMBOL_GPL(nanddev_isreserved);
/**
* nanddev_erase() - Erase a NAND portion
* @nand: NAND device
* @pos: position of the block to erase
*
* Erases the block if it's not bad.
*
* Return: 0 in case of success, a negative error code otherwise.
*/
int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
{
if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
pr_warn("attempt to erase a bad/reserved block @%llx\n",
nanddev_pos_to_offs(nand, pos));
return -EIO;
}
return nand->ops->erase(nand, pos);
}
EXPORT_SYMBOL_GPL(nanddev_erase);
/**
* nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices
* @mtd: MTD device
* @einfo: erase request
*
* This is a simple mtd->_erase() implementation iterating over all blocks
* concerned by @einfo and calling nand->ops->erase() on each of them.
*
* Note that mtd->_erase should not be directly assigned to this helper,
* because there's no locking here. NAND specialized layers should instead
* implement there own wrapper around nanddev_mtd_erase() taking the
* appropriate lock before calling nanddev_mtd_erase().
*
* Return: 0 in case of success, a negative error code otherwise.
*/
int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
{
struct nand_device *nand = mtd_to_nanddev(mtd);
struct nand_pos pos, last;
int ret;
nanddev_offs_to_pos(nand, einfo->addr, &pos);
nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last);
while (nanddev_pos_cmp(&pos, &last) <= 0) {
ret = nanddev_erase(nand, &pos);
if (ret) {
einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
einfo->state = MTD_ERASE_FAILED;
return ret;
}
nanddev_pos_next_eraseblock(nand, &pos);
}
einfo->state = MTD_ERASE_DONE;
return 0;
}
EXPORT_SYMBOL_GPL(nanddev_mtd_erase);
/**
* nanddev_init() - Initialize a NAND device
* @nand: NAND device
* @ops: NAND device operations
* @owner: NAND device owner
*
* Initializes a NAND device object. Consistency checks are done on @ops and
* @nand->memorg. Also takes care of initializing the BBT.
*
* Return: 0 in case of success, a negative error code otherwise.
*/
int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
struct module *owner)
{
struct mtd_info *mtd = nanddev_to_mtd(nand);
struct nand_memory_organization *memorg = nanddev_get_memorg(nand);
if (!nand || !ops)
return -EINVAL;
if (!ops->erase || !ops->markbad || !ops->isbad)
return -EINVAL;
if (!memorg->bits_per_cell || !memorg->pagesize ||
!memorg->pages_per_eraseblock || !memorg->eraseblocks_per_lun ||
!memorg->planes_per_lun || !memorg->luns_per_target ||
!memorg->ntargets)
return -EINVAL;
nand->rowconv.eraseblock_addr_shift =
fls(memorg->pages_per_eraseblock - 1);
nand->rowconv.lun_addr_shift = fls(memorg->eraseblocks_per_lun - 1) +
nand->rowconv.eraseblock_addr_shift;
nand->ops = ops;
mtd->type = memorg->bits_per_cell == 1 ?
MTD_NANDFLASH : MTD_MLCNANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
mtd->erasesize = memorg->pagesize * memorg->pages_per_eraseblock;
mtd->writesize = memorg->pagesize;
mtd->writebufsize = memorg->pagesize;
mtd->oobsize = memorg->oobsize;
mtd->size = nanddev_size(nand);
mtd->owner = owner;
return nanddev_bbt_init(nand);
}
EXPORT_SYMBOL_GPL(nanddev_init);
/**
* nanddev_cleanup() - Release resources allocated in nanddev_init()
* @nand: NAND device
*
* Basically undoes what has been done in nanddev_init().
*/
void nanddev_cleanup(struct nand_device *nand)
{
if (nanddev_bbt_is_initialized(nand))
nanddev_bbt_cleanup(nand);
}
EXPORT_SYMBOL_GPL(nanddev_cleanup);
MODULE_DESCRIPTION("Generic NAND framework");
MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
MODULE_LICENSE("GPL v2");

View File

@ -1,6 +1,4 @@
/*
* linux/drivers/mtd/onenand/generic.c
*
* Copyright (c) 2005 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*

View File

@ -1,6 +1,4 @@
/*
* linux/drivers/mtd/onenand/omap2.c
*
* OneNAND driver for OMAP2 / OMAP3
*
* Copyright © 2005-2006 Nokia Corporation

View File

@ -1,6 +1,4 @@
/*
* linux/drivers/mtd/onenand/onenand_base.c
*
* Copyright © 2005-2009 Samsung Electronics
* Copyright © 2007 Nokia Corporation
*

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
/*
* linux/drivers/mtd/onenand/onenand_bbt.c
*
* Bad Block Table support for the OneNAND driver
*
* Copyright(c) 2005 Samsung Electronics

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,537 @@
config MTD_NAND_ECC
tristate
config MTD_NAND_ECC_SMC
bool "NAND ECC Smart Media byte order"
depends on MTD_NAND_ECC
default n
help
Software ECC according to the Smart Media Specification.
The original Linux implementation had byte 0 and 1 swapped.
menuconfig MTD_NAND
tristate "Raw/Parallel NAND Device Support"
depends on MTD
select MTD_NAND_ECC
help
This enables support for accessing all type of raw/parallel
NAND flash devices. For further information see
<http://www.linux-mtd.infradead.org/doc/nand.html>.
if MTD_NAND
config MTD_NAND_BCH
tristate
select BCH
depends on MTD_NAND_ECC_BCH
default MTD_NAND
config MTD_NAND_ECC_BCH
bool "Support software BCH ECC"
default n
help
This enables support for software BCH error correction. Binary BCH
codes are more powerful and cpu intensive than traditional Hamming
ECC codes. They are used with NAND devices requiring more than 1 bit
of error correction.
config MTD_SM_COMMON
tristate
default n
config MTD_NAND_DENALI
tristate
config MTD_NAND_DENALI_PCI
tristate "Support Denali NAND controller on Intel Moorestown"
select MTD_NAND_DENALI
depends on HAS_DMA && PCI
help
Enable the driver for NAND flash on Intel Moorestown, using the
Denali NAND controller core.
config MTD_NAND_DENALI_DT
tristate "Support Denali NAND controller as a DT device"
select MTD_NAND_DENALI
depends on HAS_DMA && HAVE_CLK && OF
help
Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device.
config MTD_NAND_GPIO
tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB || COMPILE_TEST
depends on HAS_IOMEM
help
This enables a NAND flash driver where control signals are
connected to GPIO pins, and commands and data are communicated
via a memory mapped interface.
config MTD_NAND_AMS_DELTA
tristate "NAND Flash device on Amstrad E3"
depends on MACH_AMS_DELTA
default y
help
Support for NAND flash on Amstrad E3 (Delta).
config MTD_NAND_OMAP2
tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
help
Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
and Keystone platforms.
config MTD_NAND_OMAP_BCH
depends on MTD_NAND_OMAP2
bool "Support hardware based BCH error correction"
default n
select BCH
help
This config enables the ELM hardware engine, which can be used to
locate and correct errors when using BCH ECC scheme. This offloads
the cpu from doing ECC error searching and correction. However some
legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
so this is optional for them.
config MTD_NAND_OMAP_BCH_BUILD
def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
config MTD_NAND_RICOH
tristate "Ricoh xD card reader"
default n
depends on PCI
select MTD_SM_COMMON
help
Enable support for Ricoh R5C852 xD card reader
You also need to enable ether
NAND SSFDC (SmartMedia) read only translation layer' or new
expermental, readwrite
'SmartMedia/xD new translation layer'
config MTD_NAND_AU1550
tristate "Au1550/1200 NAND support"
depends on MIPS_ALCHEMY
help
This enables the driver for the NAND flash controller on the
AMD/Alchemy 1550 SOC.
config MTD_NAND_S3C2410
tristate "NAND Flash support for Samsung S3C SoCs"
depends on ARCH_S3C24XX || ARCH_S3C64XX
help
This enables the NAND flash controller on the S3C24xx and S3C64xx
SoCs
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_S3C2410_DEBUG
bool "Samsung S3C NAND driver debug"
depends on MTD_NAND_S3C2410
help
Enable debugging of the S3C NAND driver
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on 4xx
select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
config MTD_NAND_S3C2410_CLKSTOP
bool "Samsung S3C NAND IDLE clock stop"
depends on MTD_NAND_S3C2410
default n
help
Stop the clock to the NAND controller when there is no chip
selected to save power. This will mean there is a small delay
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
config MTD_NAND_TANGO
tristate "NAND Flash support for Tango chips"
depends on ARCH_TANGO || COMPILE_TEST
depends on HAS_DMA
help
Enables the NAND Flash controller on Tango chips.
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
depends on HAS_IOMEM
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
This is a reimplementation of M-Systems DiskOnChip 2000,
Millennium and Millennium Plus as a standard NAND device driver,
as opposed to the earlier self-contained MTD device drivers.
This should enable, among other things, proper JFFS2 operation on
these devices.
config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
depends on MTD_NAND_DISKONCHIP
help
This option allows you to specify nonstandard address at which to
probe for a DiskOnChip, or to change the detection options. You
are unlikely to need any of this unless you are using LinuxBIOS.
Say 'N'.
config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
depends on MTD_NAND_DISKONCHIP
default "0"
---help---
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option allows you to specify a single address at which to probe
for the device, which is useful if you have other devices in that
range which get upset when they are probed.
(Note that on PowerPC, the normal probe will only check at
0xE4000000.)
Normally, you should leave this set to zero, to allow the probe at
the normal addresses.
config MTD_NAND_DISKONCHIP_PROBE_HIGH
bool "Probe high addresses"
depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
help
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option changes to make it probe between 0xFFFC8000 and
0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be
useful to you. Say 'N'.
config MTD_NAND_DISKONCHIP_BBTWRITE
bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
depends on MTD_NAND_DISKONCHIP
help
On DiskOnChip devices shipped with the INFTL filesystem (Millennium
and 2000 TSOP/Alon), Linux reserves some space at the end of the
device for the Bad Block Table (BBT). If you have existing INFTL
data on your device (created by non-Linux tools such as M-Systems'
DOS drivers), your data might overlap the area Linux wants to use for
the BBT. If this is a concern for you, leave this option disabled and
Linux will not write BBT data into this area.
The downside of leaving this option disabled is that if bad blocks
are detected by Linux, they will not be recorded in the BBT, which
could cause future problems.
Once you enable this option, new filesystems (INFTL or others, created
in Linux or other operating systems) will not use the reserved area.
The only reason not to enable this option is to prevent damage to
preexisting filesystems.
Even if you leave this disabled, you can enable BBT writes at module
load time (assuming you build diskonchip as a module) with the module
parameter "inftl_bbt_write=1".
config MTD_NAND_DOCG4
tristate "Support for DiskOnChip G4"
depends on HAS_IOMEM
select BCH
select BITREVERSE
help
Support for diskonchip G4 nand flash, found in various smartphones and
PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
Portege G900, Asus P526, and O2 XDA Zinc.
With this driver you will be able to use UBI and create a ubifs on the
device, so you may wish to consider enabling UBI and UBIFS as well.
These devices ship with the Mys/Sandisk SAFTL formatting, for which
there is currently no mtd parser, so you may want to use command line
partitioning to segregate write-protected blocks. On the Treo680, the
first five erase blocks (256KiB each) are write-protected, followed
by the block containing the saftl partition table. This is probably
typical.
config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on ARCH_PXA
config MTD_NAND_CAFE
tristate "NAND support for OLPC CAFÉ chip"
depends on PCI
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
Use NAND flash attached to the CAFÉ chip designed for the OLPC
laptop.
config MTD_NAND_CS553X
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
depends on X86_32
depends on !UML && HAS_IOMEM
help
The CS553x companion chips for the AMD Geode processor
include NAND flash controllers with built-in hardware ECC
capabilities; enabling this option will allow you to use
these. The driver will check the MSRs to verify that the
controller is enabled for NAND, and currently requires that
the controller be in MMIO mode.
If you say "m", the module will be called cs553x_nand.
config MTD_NAND_ATMEL
tristate "Support for NAND Flash / SmartMedia on AT91"
depends on ARCH_AT91
select MFD_ATMEL_SMC
help
Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 processors.
config MTD_NAND_MARVELL
tristate "NAND controller support on Marvell boards"
depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
COMPILE_TEST
depends on HAS_IOMEM
help
This enables the NAND flash controller driver for Marvell boards,
including:
- PXA3xx processors (NFCv1)
- 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2)
- 64-bit Aramda platforms (7k, 8k) (NFCv2)
config MTD_NAND_SLC_LPC32XX
tristate "NXP LPC32xx SLC Controller"
depends on ARCH_LPC32XX
help
Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
chips) NAND controller. This is the default for the PHYTEC 3250
reference board which contains a NAND256R3A2CZA6 chip.
Please check the actual NAND chip connected and its support
by the SLC NAND controller.
config MTD_NAND_MLC_LPC32XX
tristate "NXP LPC32xx MLC Controller"
depends on ARCH_LPC32XX
help
Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
controller. This is the default for the WORK92105 controller
board.
Please check the actual NAND chip connected and its support
by the MLC NAND controller.
config MTD_NAND_CM_X270
tristate "Support for NAND Flash on CM-X270 modules"
depends on MACH_ARMCORE
config MTD_NAND_PASEMI
tristate "NAND support for PA Semi PWRficient"
depends on PPC_PASEMI
help
Enables support for NAND Flash interface on PA Semi PWRficient
based boards
config MTD_NAND_TMIO
tristate "NAND Flash device on Toshiba Mobile IO Controller"
depends on MFD_TMIO
help
Support for NAND flash connected to a Toshiba Mobile IO
Controller in some PDAs, including the Sharp SL6000x.
config MTD_NAND_NANDSIM
tristate "Support for NAND Flash Simulator"
help
The simulator may simulate various NAND flash chips for the
MTD nand layer.
config MTD_NAND_GPMI_NAND
tristate "GPMI NAND Flash Controller driver"
depends on MTD_NAND && MXS_DMA
help
Enables NAND Flash support for IMX23, IMX28 or IMX6.
The GPMI controller is very powerful, with the help of BCH
module, it can do the hardware ECC. The GPMI supports several
NAND flashs at the same time.
config MTD_NAND_BRCMNAND
tristate "Broadcom STB NAND controller"
depends on ARM || ARM64 || MIPS
help
Enables the Broadcom NAND controller driver. The controller was
originally designed for Set-Top Box but is used on various BCM7xxx,
BCM3xxx, BCM63xxx, iProc/Cygnus and more.
config MTD_NAND_BCM47XXNFLASH
tristate "Support for NAND flash on BCM4706 BCMA bus"
depends on BCMA_NFLASH
help
BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for
NAND flash memories. For now only BCM4706 is supported.
config MTD_NAND_PLATFORM
tristate "Support for generic platform NAND driver"
depends on HAS_IOMEM
help
This implements a generic NAND driver for on-SOC platform
devices. You will need to provide platform-specific functions
via platform_data.
config MTD_NAND_ORION
tristate "NAND Flash support for Marvell Orion SoC"
depends on PLAT_ORION
help
This enables the NAND flash controller on Orion machines.
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
config MTD_NAND_OXNAS
tristate "NAND Flash support for Oxford Semiconductor SoC"
depends on ARCH_OXNAS || COMPILE_TEST
depends on HAS_IOMEM
help
This enables the NAND flash controller on Oxford Semiconductor SoCs.
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on FSL_SOC
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
Controller Module with built-in hardware ECC capabilities.
Enabling this option will enable you to use this to control
external NAND devices.
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
select FSL_IFC
select MEMORY
help
Various Freescale chips e.g P1010, include a NAND Flash machine
with built-in hardware ECC capabilities.
Enabling this option will enable you to use this to control
external NAND devices.
config MTD_NAND_FSL_UPM
tristate "Support for NAND on Freescale UPM"
depends on PPC_83xx || PPC_85xx
select FSL_LBC
help
Enables support for NAND Flash chips wired onto Freescale PowerPC
processor localbus with User-Programmable Machine support.
config MTD_NAND_MPC5121_NFC
tristate "MPC5121 built-in NAND Flash Controller support"
depends on PPC_MPC512x
help
This enables the driver for the NAND flash controller on the
MPC5121 SoC.
config MTD_NAND_VF610_NFC
tristate "Support for Freescale NFC for VF610/MPC5125"
depends on (SOC_VF610 || COMPILE_TEST)
depends on HAS_IOMEM
help
Enables support for NAND Flash Controller on some Freescale
processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
The driver supports a maximum 2k page size. With 2k pages and
64 bytes or more of OOB, hardware ECC with up to 32-bit error
correction is supported. Hardware ECC is only enabled through
device tree.
config MTD_NAND_MXC
tristate "MXC NAND support"
depends on ARCH_MXC
help
This enables the driver for the NAND flash controller on the
MXC processors.
config MTD_NAND_SH_FLCTL
tristate "Support for NAND on Renesas SuperH FLCTL"
depends on SUPERH || COMPILE_TEST
depends on HAS_IOMEM
depends on HAS_DMA
help
Several Renesas SuperH CPU has FLCTL. This option enables support
for NAND Flash using FLCTL.
config MTD_NAND_DAVINCI
tristate "Support NAND on DaVinci/Keystone SoC"
depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
help
Enable the driver for NAND flash chips on Texas Instruments
DaVinci/Keystone processors.
config MTD_NAND_TXX9NDFMC
tristate "NAND Flash support for TXx9 SoC"
depends on SOC_TX4938 || SOC_TX4939
help
This enables the NAND flash controller on the TXx9 SoCs.
config MTD_NAND_SOCRATES
tristate "Support for NAND on Socrates board"
depends on SOCRATES
help
Enables support for NAND Flash chips wired onto Socrates board.
config MTD_NAND_NUC900
tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
depends on ARCH_W90X900
help
This enables the driver for the NAND Flash on evaluation board based
on w90p910 / NUC9xx.
config MTD_NAND_JZ4740
tristate "Support for JZ4740 SoC NAND controller"
depends on MACH_JZ4740
help
Enables support for NAND Flash on JZ4740 SoC based boards.
config MTD_NAND_JZ4780
tristate "Support for NAND on JZ4780 SoC"
depends on MACH_JZ4780 && JZ4780_NEMC
help
Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
based boards, using the BCH controller for hardware error correction.
config MTD_NAND_FSMC
tristate "Support for NAND on ST Micros FSMC"
depends on OF
depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
help
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
config MTD_NAND_XWAY
bool "Support for NAND on Lantiq XWAY SoC"
depends on LANTIQ && SOC_TYPE_XWAY
help
Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
to the External Bus Unit (EBU).
config MTD_NAND_SUNXI
tristate "Support for NAND on Allwinner SoCs"
depends on ARCH_SUNXI
help
Enables support for NAND Flash chips on Allwinner SoCs.
config MTD_NAND_HISI504
tristate "Support for NAND controller on Hisilicon SoC Hip04"
depends on ARCH_HISI || COMPILE_TEST
depends on HAS_DMA
help
Enables support for NAND controller on Hisilicon SoC Hip04.
config MTD_NAND_QCOM
tristate "Support for NAND on QCOM SoCs"
depends on ARCH_QCOM
help
Enables support for NAND flash chips on SoCs containing the EBI2 NAND
controller. This controller is found on IPQ806x SoC.
config MTD_NAND_MTK
tristate "Support for NAND controller on MTK SoCs"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_DMA
help
Enables support for NAND controller on MTK SoCs.
This controller is found on mt27xx, mt81xx, mt65xx SoCs.
endif # MTD_NAND

View File

@ -0,0 +1,66 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_MTD_NAND) += nand.o
obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_DENALI) += denali.o
obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel/
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
omap2_nand-objs := omap2.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o
obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o
obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_JZ4780) += jz4780_nand.o jz4780_bch.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_amd.o
nand-objs += nand_hynix.o
nand-objs += nand_macronix.o
nand-objs += nand_micron.o
nand-objs += nand_samsung.o
nand-objs += nand_toshiba.o

View File

@ -1,11 +1,12 @@
/*
* drivers/mtd/nand/ams-delta.c
*
* Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
*
* Derived from drivers/mtd/toto.c
* Derived from drivers/mtd/nand/toto.c (removed in v2.6.28)
* Copyright (c) 2003 Texas Instruments
* Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
*
* Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
* Partially stolen from drivers/mtd/nand/plat_nand.c
* Partially stolen from plat_nand.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -185,7 +186,7 @@ static int ams_delta_init(struct platform_device *pdev)
/* Allocate memory for MTD device structure and private data */
this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
if (!this) {
printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
pr_warn("Unable to allocate E3 NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
@ -219,7 +220,7 @@ static int ams_delta_init(struct platform_device *pdev)
this->dev_ready = ams_delta_nand_ready;
} else {
this->dev_ready = NULL;
printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
pr_notice("Couldn't request gpio for Delta NAND ready.\n");
}
/* 25 us command delay time */
this->chip_delay = 30;

View File

@ -9,10 +9,10 @@
*
* Copyright 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
* Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8)
* Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
* Derived from drivers/mtd/spia.c (removed in v3.8)
* Copyright 2000 Steven J. Hill (sjhill@cotw.com)
*
*

View File

@ -9,10 +9,10 @@
*
* Copyright 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
* Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8)
* Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
* Derived from drivers/mtd/spia.c (removed in v3.8)
* Copyright 2000 Steven J. Hill (sjhill@cotw.com)
*
* Add Hardware ECC support for AT91SAM9260 / AT91SAM9263

View File

@ -9,10 +9,10 @@
*
* Copyright © 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
* Derived from drivers/mtd/nand/autcpu12.c (removed in v3.8)
* Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
* Derived from drivers/mtd/spia.c (removed in v3.8)
* Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
*
*

View File

@ -1,6 +1,4 @@
/*
* drivers/mtd/nand/au1550nd.c
*
* Copyright (C) 2004 Embedded Edge, LLC
*
* This program is free software; you can redistribute it and/or modify

View File

@ -392,8 +392,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
b47n->nand_chip.onfi_set_features = nand_onfi_get_set_features_notsupp;
b47n->nand_chip.onfi_get_features = nand_onfi_get_set_features_notsupp;
b47n->nand_chip.set_features = nand_get_set_features_notsupp;
b47n->nand_chip.get_features = nand_get_set_features_notsupp;
nand_chip->chip_delay = 50;
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;

View File

@ -2297,7 +2297,11 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
if (ret)
return ret;
return mtd_device_register(mtd, NULL, 0);
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
nand_cleanup(chip);
return ret;
}
static void brcmnand_save_restore_cs_config(struct brcmnand_host *host,

View File

@ -645,8 +645,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe->nand.read_buf = cafe_read_buf;
cafe->nand.write_buf = cafe_write_buf;
cafe->nand.select_chip = cafe_select_chip;
cafe->nand.onfi_set_features = nand_onfi_get_set_features_notsupp;
cafe->nand.onfi_get_features = nand_onfi_get_set_features_notsupp;
cafe->nand.set_features = nand_get_set_features_notsupp;
cafe->nand.get_features = nand_get_set_features_notsupp;
cafe->nand.chip_delay = 0;
@ -751,7 +751,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
} else {
printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
pr_warn("Unexpected NAND flash writesize %d. Aborting\n",
mtd->writesize);
goto out_free_dma;
}
@ -774,10 +774,14 @@ static int cafe_nand_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, mtd);
mtd->name = "cafe_nand";
mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
err = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
if (err)
goto out_cleanup_nand;
goto out;
out_cleanup_nand:
nand_cleanup(&cafe->nand);
out_free_dma:
dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
out_irq:

View File

@ -1,10 +1,8 @@
/*
* linux/drivers/mtd/nand/cmx270-nand.c
*
* Copyright (C) 2006 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
*
* Derived from drivers/mtd/nand/h1910.c
* Derived from drivers/mtd/nand/h1910.c (removed in v3.10)
* Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
*

View File

@ -1,6 +1,4 @@
/*
* drivers/mtd/nand/cs553x_nand.c
*
* (C) 2005, 2006 Red Hat Inc.
*
* Author: David Woodhouse <dwmw2@infradead.org>
@ -189,10 +187,11 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
struct nand_chip *this;
struct mtd_info *new_mtd;
printk(KERN_NOTICE "Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n", cs, mmio?"MM":"P", adr);
pr_notice("Probing CS553x NAND controller CS#%d at %sIO 0x%08lx\n",
cs, mmio ? "MM" : "P", adr);
if (!mmio) {
printk(KERN_NOTICE "PIO mode not yet implemented for CS553X NAND controller\n");
pr_notice("PIO mode not yet implemented for CS553X NAND controller\n");
return -ENXIO;
}
@ -211,7 +210,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
/* map physical address */
this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
if (!this->IO_ADDR_R) {
printk(KERN_WARNING "ioremap cs553x NAND @0x%08lx failed\n", adr);
pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr);
err = -EIO;
goto out_mtd;
}
@ -295,7 +294,7 @@ static int __init cs553x_init(void)
/* If it doesn't have the NAND controller enabled, abort */
rdmsrl(MSR_DIVIL_BALL_OPTS, val);
if (val & PIN_OPT_IDE) {
printk(KERN_INFO "CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");
pr_info("CS553x NAND controller: Flash I/O not enabled in MSR_DIVIL_BALL_OPTS.\n");
return -ENXIO;
}

View File

@ -826,7 +826,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
else
ret = mtd_device_register(mtd, NULL, 0);
if (ret < 0)
goto err;
goto err_cleanup_nand;
val = davinci_nand_readl(info, NRCSR_OFFSET);
dev_info(&pdev->dev, "controller rev. %d.%d\n",
@ -834,6 +834,9 @@ static int nand_davinci_probe(struct platform_device *pdev)
return 0;
err_cleanup_nand:
nand_cleanup(&info->chip);
err:
clk_disable_unprepare(info->clk);

View File

@ -1384,10 +1384,12 @@ int denali_init(struct denali_nand_info *denali)
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
goto free_buf;
goto cleanup_nand;
}
return 0;
cleanup_nand:
nand_cleanup(chip);
free_buf:
kfree(denali->buf);
disable_irq:

View File

@ -1,6 +1,4 @@
/*
* drivers/mtd/nand/diskonchip.c
*
* (C) 2003 Red Hat, Inc.
* (C) 2004 Dan Brown <dan_brown@ieee.org>
* (C) 2004 Kalev Lember <kalev@smartlink.ee>
@ -411,7 +409,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
ident.dword = readl(docptr + DoC_2k_CDSN_IO);
if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
pr_info("DiskOnChip 2000 responds to DWORD access\n");
this->read_buf = &doc2000_readbuf_dword;
}
}
@ -438,7 +436,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
break;
}
doc->chips_per_floor = i;
printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
pr_debug("Detected %d chips per floor.\n", i);
}
static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
@ -934,14 +932,15 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
if (ret > 0)
printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
pr_err("doc200x_correct_data corrected %d errors\n",
ret);
}
if (DoC_is_MillenniumPlus(doc))
WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
else
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
if (no_ecc_failures && mtd_is_eccerr(ret)) {
printk(KERN_ERR "suppressing ECC failure\n");
pr_err("suppressing ECC failure\n");
ret = 0;
}
return ret;
@ -1014,11 +1013,11 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
if (retlen != mtd->writesize)
continue;
if (ret) {
printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs);
pr_warn("ECC error scanning DOC at 0x%x\n", offs);
}
if (memcmp(buf, id, 6))
continue;
printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
pr_info("Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
if (doc->mh0_page == -1) {
doc->mh0_page = offs >> this->page_shift;
if (!findmirror)
@ -1029,7 +1028,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
return 2;
}
if (doc->mh0_page == -1) {
printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id);
pr_warn("DiskOnChip %s Media Header not found.\n", id);
return 0;
}
/* Only one mediaheader was found. We want buf to contain a
@ -1038,7 +1037,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch
ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
if (retlen != mtd->writesize) {
/* Insanity. Give up. */
printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
pr_err("Read DiskOnChip Media Header once, but can't reread it???\n");
return 0;
}
return 1;
@ -1068,7 +1067,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
le16_to_cpus(&mh->FirstPhysicalEUN);
le32_to_cpus(&mh->FormattedSize);
printk(KERN_INFO " DataOrgID = %s\n"
pr_info(" DataOrgID = %s\n"
" NumEraseUnits = %d\n"
" FirstPhysicalEUN = %d\n"
" FormattedSize = %d\n"
@ -1092,7 +1091,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
maxblocks = min(32768U, (maxblocks << 1) + psize);
mh->UnitSizeFactor--;
}
printk(KERN_WARNING "UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
pr_warn("UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
}
/* NOTE: The lines below modify internal variables of the NAND and MTD
@ -1103,13 +1102,13 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
if (mh->UnitSizeFactor != 0xff) {
this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);
pr_info("Setting virtual erase size to %d\n", mtd->erasesize);
blocks = mtd->size >> this->bbt_erase_shift;
maxblocks = min(32768U, mtd->erasesize - psize);
}
if (blocks > maxblocks) {
printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor);
pr_err("UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor);
goto out;
}
@ -1180,7 +1179,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
le32_to_cpus(&mh->FormatFlags);
le32_to_cpus(&mh->PercentUsed);
printk(KERN_INFO " bootRecordID = %s\n"
pr_info(" bootRecordID = %s\n"
" NoOfBootImageBlocks = %d\n"
" NoOfBinaryPartitions = %d\n"
" NoOfBDTLPartitions = %d\n"
@ -1202,13 +1201,13 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
blocks = mtd->size >> vshift;
if (blocks > 32768) {
printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits);
pr_err("BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits);
goto out;
}
blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
if (inftl_bbt_write && (blocks > mtd->erasesize)) {
printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n");
pr_err("Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n");
goto out;
}
@ -1222,7 +1221,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
le32_to_cpus(&ip->spareUnits);
le32_to_cpus(&ip->Reserved0);
printk(KERN_INFO " PARTITION[%d] ->\n"
pr_info(" PARTITION[%d] ->\n"
" virtualUnits = %d\n"
" firstUnit = %d\n"
" lastUnit = %d\n"
@ -1308,7 +1307,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
struct mtd_partition parts[5];
if (this->numchips > doc->chips_per_floor) {
printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");
pr_err("Multi-floor INFTL devices not yet supported.\n");
return -EIO;
}
@ -1436,7 +1435,8 @@ static int __init doc_probe(unsigned long physadr)
return -EBUSY;
virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
if (!virtadr) {
printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
pr_err("Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n",
DOC_IOREMAP_LEN, physadr);
ret = -EIO;
goto error_ioremap;
}
@ -1495,7 +1495,7 @@ static int __init doc_probe(unsigned long physadr)
reg = DoC_Mplus_Toggle;
break;
case DOC_ChipID_DocMilPlus32:
printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
default:
ret = -ENODEV;
goto notfound;
@ -1511,7 +1511,7 @@ static int __init doc_probe(unsigned long physadr)
tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
if ((tmp == tmpb) || (tmp != tmpc)) {
printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
pr_warn("Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
ret = -ENODEV;
goto notfound;
}
@ -1545,12 +1545,13 @@ static int __init doc_probe(unsigned long physadr)
}
newval = ~newval;
if (oldval == newval) {
printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);
pr_debug("Found alias of DOC at 0x%lx to 0x%lx\n",
doc->physadr, physadr);
goto notfound;
}
}
printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
pr_notice("DiskOnChip found at 0x%lx\n", physadr);
len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
(2 * sizeof(struct nand_bbt_descr));
@ -1665,12 +1666,13 @@ static int __init init_nanddoc(void)
*/
rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
if (!rs_decoder) {
printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
pr_err("DiskOnChip: Could not create a RS decoder\n");
return -ENOMEM;
}
if (doc_config_location) {
printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
pr_info("Using configured DiskOnChip probe address 0x%lx\n",
doc_config_location);
ret = doc_probe(doc_config_location);
if (ret < 0)
goto outerr;
@ -1682,7 +1684,7 @@ static int __init init_nanddoc(void)
/* No banner message any more. Print a message if no DiskOnChip
found, so the user knows we at least tried. */
if (!doclist) {
printk(KERN_INFO "No valid DiskOnChip devices found\n");
pr_info("No valid DiskOnChip devices found\n");
ret = -ENODEV;
goto outerr;
}

View File

@ -1269,8 +1269,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->read_buf = docg4_read_buf;
nand->write_buf = docg4_write_buf16;
nand->erase = docg4_erase_block;
nand->onfi_set_features = nand_onfi_get_set_features_notsupp;
nand->onfi_get_features = nand_onfi_get_set_features_notsupp;
nand->set_features = nand_get_set_features_notsupp;
nand->get_features = nand_get_set_features_notsupp;
nand->ecc.read_page = docg4_read_page;
nand->ecc.write_page = docg4_write_page;
nand->ecc.read_page_raw = docg4_read_page_raw;

View File

@ -775,8 +775,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->select_chip = fsl_elbc_select_chip;
chip->cmdfunc = fsl_elbc_cmdfunc;
chip->waitfunc = fsl_elbc_wait;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
chip->set_features = nand_get_set_features_notsupp;
chip->get_features = nand_get_set_features_notsupp;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
@ -929,7 +929,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
mtd_device_parse_register(mtd, part_probe_types, NULL,
NULL, 0);
printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n",
pr_info("eLBC NAND device at 0x%llx, bank %d\n",
(unsigned long long)res.start, priv->bank);
return 0;

View File

@ -805,7 +805,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
msecs_to_jiffies(IFC_TIMEOUT_MSECS));
if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n");
pr_err("fsl-ifc: Failed to Initialise SRAM\n");
/* Restore CSOR and CSOR_ext */
ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
@ -838,8 +838,8 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->select_chip = fsl_ifc_select_chip;
chip->cmdfunc = fsl_ifc_cmdfunc;
chip->waitfunc = fsl_ifc_wait;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
chip->set_features = nand_get_set_features_notsupp;
chip->get_features = nand_get_set_features_notsupp;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;

View File

@ -1,6 +1,4 @@
/*
* drivers/mtd/nand/fsmc_nand.c
*
* ST Microelectronics
* Flexible Static Memory Controller (FSMC)
* Driver for NAND portions
@ -9,7 +7,9 @@
* Vipin Kumar <vipin.kumar@st.com>
* Ashish Priyadarshi
*
* Based on drivers/mtd/nand/nomadik_nand.c
* Based on drivers/mtd/nand/nomadik_nand.c (removed in v3.8)
* Copyright © 2007 STMicroelectronics Pvt. Ltd.
* Copyright © 2009 Alessandro Rubini
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@ -103,10 +103,6 @@
#define ECC3 0x1C
#define FSMC_NAND_BANK_SZ 0x20
#define FSMC_NAND_REG(base, bank, reg) (base + FSMC_NOR_REG_SIZE + \
(FSMC_NAND_BANK_SZ * (bank)) + \
reg)
#define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
struct fsmc_nand_timings {
@ -143,7 +139,7 @@ enum access_mode {
* @data_va: NAND port for Data.
* @cmd_va: NAND port for Command.
* @addr_va: NAND port for Address.
* @regs_va: FSMC regs base address.
* @regs_va: Registers base address for a given bank.
*/
struct fsmc_nand_data {
u32 pid;
@ -257,45 +253,6 @@ static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd)
return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand);
}
/*
* fsmc_cmd_ctrl - For facilitaing Hardware access
* This routine allows hardware specific access to control-lines(ALE,CLE)
*/
static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *this = mtd_to_nand(mtd);
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
unsigned int bank = host->bank;
if (ctrl & NAND_CTRL_CHANGE) {
u32 pc;
if (ctrl & NAND_CLE) {
this->IO_ADDR_R = host->cmd_va;
this->IO_ADDR_W = host->cmd_va;
} else if (ctrl & NAND_ALE) {
this->IO_ADDR_R = host->addr_va;
this->IO_ADDR_W = host->addr_va;
} else {
this->IO_ADDR_R = host->data_va;
this->IO_ADDR_W = host->data_va;
}
pc = readl(FSMC_NAND_REG(regs, bank, PC));
if (ctrl & NAND_NCE)
pc |= FSMC_ENABLE;
else
pc &= ~FSMC_ENABLE;
writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC));
}
mb();
if (cmd != NAND_CMD_NONE)
writeb_relaxed(cmd, this->IO_ADDR_W);
}
/*
* fsmc_nand_setup - FSMC (Flexible Static Memory Controller) init routine
*
@ -307,8 +264,6 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host,
{
uint32_t value = FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON;
uint32_t tclr, tar, thiz, thold, twait, tset;
unsigned int bank = host->bank;
void __iomem *regs = host->regs_va;
tclr = (tims->tclr & FSMC_TCLR_MASK) << FSMC_TCLR_SHIFT;
tar = (tims->tar & FSMC_TAR_MASK) << FSMC_TAR_SHIFT;
@ -318,18 +273,14 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host,
tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
if (host->nand.options & NAND_BUSWIDTH_16)
writel_relaxed(value | FSMC_DEVWID_16,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(value | FSMC_DEVWID_16, host->regs_va + PC);
else
writel_relaxed(value | FSMC_DEVWID_8,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + PC);
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(thiz | thold | twait | tset,
FSMC_NAND_REG(regs, bank, COMM));
writel_relaxed(thiz | thold | twait | tset,
FSMC_NAND_REG(regs, bank, ATTRIB));
writel_relaxed(readl(host->regs_va + PC) | tclr | tar,
host->regs_va + PC);
writel_relaxed(thiz | thold | twait | tset, host->regs_va + COMM);
writel_relaxed(thiz | thold | twait | tset, host->regs_va + ATTRIB);
}
static int fsmc_calc_timings(struct fsmc_nand_data *host,
@ -419,15 +370,13 @@ static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
FSMC_NAND_REG(regs, bank, PC));
writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCPLEN_256,
host->regs_va + PC);
writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCEN,
host->regs_va + PC);
writel_relaxed(readl(host->regs_va + PC) | FSMC_ECCEN,
host->regs_va + PC);
}
/*
@ -439,13 +388,11 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
uint8_t *ecc)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
uint32_t ecc_tmp;
unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
do {
if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
if (readl_relaxed(host->regs_va + STS) & FSMC_CODE_RDY)
break;
else
cond_resched();
@ -456,25 +403,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
return -ETIMEDOUT;
}
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
ecc_tmp = readl_relaxed(host->regs_va + ECC1);
ecc[0] = (uint8_t) (ecc_tmp >> 0);
ecc[1] = (uint8_t) (ecc_tmp >> 8);
ecc[2] = (uint8_t) (ecc_tmp >> 16);
ecc[3] = (uint8_t) (ecc_tmp >> 24);
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
ecc_tmp = readl_relaxed(host->regs_va + ECC2);
ecc[4] = (uint8_t) (ecc_tmp >> 0);
ecc[5] = (uint8_t) (ecc_tmp >> 8);
ecc[6] = (uint8_t) (ecc_tmp >> 16);
ecc[7] = (uint8_t) (ecc_tmp >> 24);
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
ecc_tmp = readl_relaxed(host->regs_va + ECC3);
ecc[8] = (uint8_t) (ecc_tmp >> 0);
ecc[9] = (uint8_t) (ecc_tmp >> 8);
ecc[10] = (uint8_t) (ecc_tmp >> 16);
ecc[11] = (uint8_t) (ecc_tmp >> 24);
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
ecc_tmp = readl_relaxed(host->regs_va + STS);
ecc[12] = (uint8_t) (ecc_tmp >> 16);
return 0;
@ -489,11 +436,9 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
uint8_t *ecc)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
uint32_t bank = host->bank;
uint32_t ecc_tmp;
ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
ecc_tmp = readl_relaxed(host->regs_va + ECC1);
ecc[0] = (uint8_t) (ecc_tmp >> 0);
ecc[1] = (uint8_t) (ecc_tmp >> 8);
ecc[2] = (uint8_t) (ecc_tmp >> 16);
@ -598,18 +543,18 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
*/
static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
int i;
struct nand_chip *chip = mtd_to_nand(mtd);
if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
for (i = 0; i < len; i++)
writel_relaxed(p[i], chip->IO_ADDR_W);
writel_relaxed(p[i], host->data_va);
} else {
for (i = 0; i < len; i++)
writeb_relaxed(buf[i], chip->IO_ADDR_W);
writeb_relaxed(buf[i], host->data_va);
}
}
@ -621,18 +566,18 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
*/
static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
int i;
struct nand_chip *chip = mtd_to_nand(mtd);
if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
for (i = 0; i < len; i++)
p[i] = readl_relaxed(chip->IO_ADDR_R);
p[i] = readl_relaxed(host->data_va);
} else {
for (i = 0; i < len; i++)
buf[i] = readb_relaxed(chip->IO_ADDR_R);
buf[i] = readb_relaxed(host->data_va);
}
}
@ -663,6 +608,102 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE);
}
/* fsmc_select_chip - assert or deassert nCE */
static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
u32 pc;
/* Support only one CS */
if (chipnr > 0)
return;
pc = readl(host->regs_va + PC);
if (chipnr < 0)
writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + PC);
else
writel_relaxed(pc | FSMC_ENABLE, host->regs_va + PC);
/* nCE line must be asserted before starting any operation */
mb();
}
/*
* fsmc_exec_op - hook called by the core to execute NAND operations
*
* This controller is simple enough and thus does not need to use the parser
* provided by the core, instead, handle every situation here.
*/
static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
bool check_only)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
const struct nand_op_instr *instr = NULL;
int ret = 0;
unsigned int op_id;
int i;
pr_debug("Executing operation [%d instructions]:\n", op->ninstrs);
for (op_id = 0; op_id < op->ninstrs; op_id++) {
instr = &op->instrs[op_id];
switch (instr->type) {
case NAND_OP_CMD_INSTR:
pr_debug(" ->CMD [0x%02x]\n",
instr->ctx.cmd.opcode);
writeb_relaxed(instr->ctx.cmd.opcode, host->cmd_va);
break;
case NAND_OP_ADDR_INSTR:
pr_debug(" ->ADDR [%d cyc]",
instr->ctx.addr.naddrs);
for (i = 0; i < instr->ctx.addr.naddrs; i++)
writeb_relaxed(instr->ctx.addr.addrs[i],
host->addr_va);
break;
case NAND_OP_DATA_IN_INSTR:
pr_debug(" ->DATA_IN [%d B%s]\n", instr->ctx.data.len,
instr->ctx.data.force_8bit ?
", force 8-bit" : "");
if (host->mode == USE_DMA_ACCESS)
fsmc_read_buf_dma(mtd, instr->ctx.data.buf.in,
instr->ctx.data.len);
else
fsmc_read_buf(mtd, instr->ctx.data.buf.in,
instr->ctx.data.len);
break;
case NAND_OP_DATA_OUT_INSTR:
pr_debug(" ->DATA_OUT [%d B%s]\n", instr->ctx.data.len,
instr->ctx.data.force_8bit ?
", force 8-bit" : "");
if (host->mode == USE_DMA_ACCESS)
fsmc_write_buf_dma(mtd, instr->ctx.data.buf.out,
instr->ctx.data.len);
else
fsmc_write_buf(mtd, instr->ctx.data.buf.out,
instr->ctx.data.len);
break;
case NAND_OP_WAITRDY_INSTR:
pr_debug(" ->WAITRDY [max %d ms]\n",
instr->ctx.waitrdy.timeout_ms);
ret = nand_soft_waitrdy(chip,
instr->ctx.waitrdy.timeout_ms);
break;
}
}
return ret;
}
/*
* fsmc_read_page_hwecc
* @mtd: mtd info structure
@ -754,13 +795,11 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
void __iomem *regs = host->regs_va;
unsigned int bank = host->bank;
uint32_t err_idx[8];
uint32_t num_err, i;
uint32_t ecc1, ecc2, ecc3, ecc4;
num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
num_err = (readl_relaxed(host->regs_va + STS) >> 10) & 0xF;
/* no bit flipping */
if (likely(num_err == 0))
@ -803,10 +842,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
* uint64_t array and error offset indexes are populated in err_idx
* array
*/
ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
ecc1 = readl_relaxed(host->regs_va + ECC1);
ecc2 = readl_relaxed(host->regs_va + ECC2);
ecc3 = readl_relaxed(host->regs_va + ECC3);
ecc4 = readl_relaxed(host->regs_va + STS);
err_idx[0] = (ecc1 >> 0) & 0x1FFF;
err_idx[1] = (ecc1 >> 13) & 0x1FFF;
@ -889,6 +928,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
struct mtd_info *mtd;
struct nand_chip *nand;
struct resource *res;
void __iomem *base;
dma_cap_mask_t mask;
int ret = 0;
u32 pid;
@ -923,9 +963,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
return PTR_ERR(host->cmd_va);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
host->regs_va = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->regs_va))
return PTR_ERR(host->regs_va);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
host->regs_va = base + FSMC_NOR_REG_SIZE +
(host->bank * FSMC_NAND_BANK_SZ);
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk)) {
@ -942,7 +985,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
* AMBA PrimeCell bus. However it is not a PrimeCell.
*/
for (pid = 0, i = 0; i < 4; i++)
pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
pid |= (readl(base + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
host->pid = pid;
dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, "
"revision %02x, config %02x\n",
@ -960,9 +1003,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
nand_set_flash_node(nand, pdev->dev.of_node);
mtd->dev.parent = &pdev->dev;
nand->IO_ADDR_R = host->data_va;
nand->IO_ADDR_W = host->data_va;
nand->cmd_ctrl = fsmc_cmd_ctrl;
nand->exec_op = fsmc_exec_op;
nand->select_chip = fsmc_select_chip;
nand->chip_delay = 30;
/*
@ -974,8 +1016,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
nand->ecc.size = 512;
nand->badblockbits = 7;
switch (host->mode) {
case USE_DMA_ACCESS:
if (host->mode == USE_DMA_ACCESS) {
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
host->read_dma_chan = dma_request_channel(mask, filter, NULL);
@ -988,15 +1029,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Unable to get write dma channel\n");
goto err_req_write_chnl;
}
nand->read_buf = fsmc_read_buf_dma;
nand->write_buf = fsmc_write_buf_dma;
break;
default:
case USE_WORD_ACCESS:
nand->read_buf = fsmc_read_buf;
nand->write_buf = fsmc_write_buf;
break;
}
if (host->dev_timings)

View File

@ -1,6 +1,4 @@
/*
* drivers/mtd/nand/gpio.c
*
* Updated, and converted to generic GPIO based driver by Russell King.
*
* Written by Ben Dooks <ben@simtec.co.uk>

View File

@ -26,15 +26,8 @@
#include "gpmi-regs.h"
#include "bch-regs.h"
static struct timing_threshold timing_default_threshold = {
.max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >>
BP_GPMI_TIMING0_DATA_SETUP),
.internal_data_setup_in_ns = 0,
.max_sample_delay_factor = (BM_GPMI_CTRL1_RDN_DELAY >>
BP_GPMI_CTRL1_RDN_DELAY),
.max_dll_clock_period_in_ns = 32,
.max_dll_delay_in_ns = 16,
};
/* Converts time to clock cycles */
#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period)
#define MXS_SET_ADDR 0x4
#define MXS_CLR_ADDR 0x8
@ -151,8 +144,15 @@ static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
return ret;
}
#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
int gpmi_enable_clk(struct gpmi_nand_data *this)
{
return __gpmi_enable_clk(this, true);
}
int gpmi_disable_clk(struct gpmi_nand_data *this)
{
return __gpmi_enable_clk(this, false);
}
int gpmi_init(struct gpmi_nand_data *this)
{
@ -174,7 +174,6 @@ int gpmi_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
/* Choose NAND mode. */
writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
@ -313,467 +312,6 @@ int bch_set_geometry(struct gpmi_nand_data *this)
return ret;
}
/* Converts time in nanoseconds to cycles. */
static unsigned int ns_to_cycles(unsigned int time,
unsigned int period, unsigned int min)
{
unsigned int k;
k = (time + period - 1) / period;
return max(k, min);
}
#define DEF_MIN_PROP_DELAY 5
#define DEF_MAX_PROP_DELAY 9
/* Apply timing to current hardware conditions. */
static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
struct gpmi_nfc_hardware_timing *hw)
{
struct timing_threshold *nfc = &timing_default_threshold;
struct resources *r = &this->resources;
struct nand_chip *nand = &this->nand;
struct nand_timing target = this->timing;
bool improved_timing_is_available;
unsigned long clock_frequency_in_hz;
unsigned int clock_period_in_ns;
bool dll_use_half_periods;
unsigned int dll_delay_shift;
unsigned int max_sample_delay_in_ns;
unsigned int address_setup_in_cycles;
unsigned int data_setup_in_ns;
unsigned int data_setup_in_cycles;
unsigned int data_hold_in_cycles;
int ideal_sample_delay_in_ns;
unsigned int sample_delay_factor;
int tEYE;
unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
/*
* If there are multiple chips, we need to relax the timings to allow
* for signal distortion due to higher capacitance.
*/
if (nand->numchips > 2) {
target.data_setup_in_ns += 10;
target.data_hold_in_ns += 10;
target.address_setup_in_ns += 10;
} else if (nand->numchips > 1) {
target.data_setup_in_ns += 5;
target.data_hold_in_ns += 5;
target.address_setup_in_ns += 5;
}
/* Check if improved timing information is available. */
improved_timing_is_available =
(target.tREA_in_ns >= 0) &&
(target.tRLOH_in_ns >= 0) &&
(target.tRHOH_in_ns >= 0);
/* Inspect the clock. */
nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
clock_frequency_in_hz = nfc->clock_frequency_in_hz;
clock_period_in_ns = NSEC_PER_SEC / clock_frequency_in_hz;
/*
* The NFC quantizes setup and hold parameters in terms of clock cycles.
* Here, we quantize the setup and hold timing parameters to the
* next-highest clock period to make sure we apply at least the
* specified times.
*
* For data setup and data hold, the hardware interprets a value of zero
* as the largest possible delay. This is not what's intended by a zero
* in the input parameter, so we impose a minimum of one cycle.
*/
data_setup_in_cycles = ns_to_cycles(target.data_setup_in_ns,
clock_period_in_ns, 1);
data_hold_in_cycles = ns_to_cycles(target.data_hold_in_ns,
clock_period_in_ns, 1);
address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns,
clock_period_in_ns, 0);
/*
* The clock's period affects the sample delay in a number of ways:
*
* (1) The NFC HAL tells us the maximum clock period the sample delay
* DLL can tolerate. If the clock period is greater than half that
* maximum, we must configure the DLL to be driven by half periods.
*
* (2) We need to convert from an ideal sample delay, in ns, to a
* "sample delay factor," which the NFC uses. This factor depends on
* whether we're driving the DLL with full or half periods.
* Paraphrasing the reference manual:
*
* AD = SDF x 0.125 x RP
*
* where:
*
* AD is the applied delay, in ns.
* SDF is the sample delay factor, which is dimensionless.
* RP is the reference period, in ns, which is a full clock period
* if the DLL is being driven by full periods, or half that if
* the DLL is being driven by half periods.
*
* Let's re-arrange this in a way that's more useful to us:
*
* 8
* SDF = AD x ----
* RP
*
* The reference period is either the clock period or half that, so this
* is:
*
* 8 AD x DDF
* SDF = AD x ----- = --------
* f x P P
*
* where:
*
* f is 1 or 1/2, depending on how we're driving the DLL.
* P is the clock period.
* DDF is the DLL Delay Factor, a dimensionless value that
* incorporates all the constants in the conversion.
*
* DDF will be either 8 or 16, both of which are powers of two. We can
* reduce the cost of this conversion by using bit shifts instead of
* multiplication or division. Thus:
*
* AD << DDS
* SDF = ---------
* P
*
* or
*
* AD = (SDF >> DDS) x P
*
* where:
*
* DDS is the DLL Delay Shift, the logarithm to base 2 of the DDF.
*/
if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) {
dll_use_half_periods = true;
dll_delay_shift = 3 + 1;
} else {
dll_use_half_periods = false;
dll_delay_shift = 3;
}
/*
* Compute the maximum sample delay the NFC allows, under current
* conditions. If the clock is running too slowly, no sample delay is
* possible.
*/
if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns)
max_sample_delay_in_ns = 0;
else {
/*
* Compute the delay implied by the largest sample delay factor
* the NFC allows.
*/
max_sample_delay_in_ns =
(nfc->max_sample_delay_factor * clock_period_in_ns) >>
dll_delay_shift;
/*
* Check if the implied sample delay larger than the NFC
* actually allows.
*/
if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns)
max_sample_delay_in_ns = nfc->max_dll_delay_in_ns;
}
/*
* Check if improved timing information is available. If not, we have to
* use a less-sophisticated algorithm.
*/
if (!improved_timing_is_available) {
/*
* Fold the read setup time required by the NFC into the ideal
* sample delay.
*/
ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns +
nfc->internal_data_setup_in_ns;
/*
* The ideal sample delay may be greater than the maximum
* allowed by the NFC. If so, we can trade off sample delay time
* for more data setup time.
*
* In each iteration of the following loop, we add a cycle to
* the data setup time and subtract a corresponding amount from
* the sample delay until we've satisified the constraints or
* can't do any better.
*/
while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
data_setup_in_cycles++;
ideal_sample_delay_in_ns -= clock_period_in_ns;
if (ideal_sample_delay_in_ns < 0)
ideal_sample_delay_in_ns = 0;
}
/*
* Compute the sample delay factor that corresponds most closely
* to the ideal sample delay. If the result is too large for the
* NFC, use the maximum value.
*
* Notice that we use the ns_to_cycles function to compute the
* sample delay factor. We do this because the form of the
* computation is the same as that for calculating cycles.
*/
sample_delay_factor =
ns_to_cycles(
ideal_sample_delay_in_ns << dll_delay_shift,
clock_period_in_ns, 0);
if (sample_delay_factor > nfc->max_sample_delay_factor)
sample_delay_factor = nfc->max_sample_delay_factor;
/* Skip to the part where we return our results. */
goto return_results;
}
/*
* If control arrives here, we have more detailed timing information,
* so we can use a better algorithm.
*/
/*
* Fold the read setup time required by the NFC into the maximum
* propagation delay.
*/
max_prop_delay_in_ns += nfc->internal_data_setup_in_ns;
/*
* Earlier, we computed the number of clock cycles required to satisfy
* the data setup time. Now, we need to know the actual nanoseconds.
*/
data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles;
/*
* Compute tEYE, the width of the data eye when reading from the NAND
* Flash. The eye width is fundamentally determined by the data setup
* time, perturbed by propagation delays and some characteristics of the
* NAND Flash device.
*
* start of the eye = max_prop_delay + tREA
* end of the eye = min_prop_delay + tRHOH + data_setup
*/
tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns +
(int)data_setup_in_ns;
tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns;
/*
* The eye must be open. If it's not, we can try to open it by
* increasing its main forcer, the data setup time.
*
* In each iteration of the following loop, we increase the data setup
* time by a single clock cycle. We do this until either the eye is
* open or we run into NFC limits.
*/
while ((tEYE <= 0) &&
(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
/* Give a cycle to data setup. */
data_setup_in_cycles++;
/* Synchronize the data setup time with the cycles. */
data_setup_in_ns += clock_period_in_ns;
/* Adjust tEYE accordingly. */
tEYE += clock_period_in_ns;
}
/*
* When control arrives here, the eye is open. The ideal time to sample
* the data is in the center of the eye:
*
* end of the eye + start of the eye
* --------------------------------- - data_setup
* 2
*
* After some algebra, this simplifies to the code immediately below.
*/
ideal_sample_delay_in_ns =
((int)max_prop_delay_in_ns +
(int)target.tREA_in_ns +
(int)min_prop_delay_in_ns +
(int)target.tRHOH_in_ns -
(int)data_setup_in_ns) >> 1;
/*
* The following figure illustrates some aspects of a NAND Flash read:
*
*
* __ _____________________________________
* RDN \_________________/
*
* <---- tEYE ----->
* /-----------------\
* Read Data ----------------------------< >---------
* \-----------------/
* ^ ^ ^ ^
* | | | |
* |<--Data Setup -->|<--Delay Time -->| |
* | | | |
* | | |
* | |<-- Quantized Delay Time -->|
* | | |
*
*
* We have some issues we must now address:
*
* (1) The *ideal* sample delay time must not be negative. If it is, we
* jam it to zero.
*
* (2) The *ideal* sample delay time must not be greater than that
* allowed by the NFC. If it is, we can increase the data setup
* time, which will reduce the delay between the end of the data
* setup and the center of the eye. It will also make the eye
* larger, which might help with the next issue...
*
* (3) The *quantized* sample delay time must not fall either before the
* eye opens or after it closes (the latter is the problem
* illustrated in the above figure).
*/
/* Jam a negative ideal sample delay to zero. */
if (ideal_sample_delay_in_ns < 0)
ideal_sample_delay_in_ns = 0;
/*
* Extend the data setup as needed to reduce the ideal sample delay
* below the maximum permitted by the NFC.
*/
while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) &&
(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
/* Give a cycle to data setup. */
data_setup_in_cycles++;
/* Synchronize the data setup time with the cycles. */
data_setup_in_ns += clock_period_in_ns;
/* Adjust tEYE accordingly. */
tEYE += clock_period_in_ns;
/*
* Decrease the ideal sample delay by one half cycle, to keep it
* in the middle of the eye.
*/
ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
/* Jam a negative ideal sample delay to zero. */
if (ideal_sample_delay_in_ns < 0)
ideal_sample_delay_in_ns = 0;
}
/*
* Compute the sample delay factor that corresponds to the ideal sample
* delay. If the result is too large, then use the maximum allowed
* value.
*
* Notice that we use the ns_to_cycles function to compute the sample
* delay factor. We do this because the form of the computation is the
* same as that for calculating cycles.
*/
sample_delay_factor =
ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift,
clock_period_in_ns, 0);
if (sample_delay_factor > nfc->max_sample_delay_factor)
sample_delay_factor = nfc->max_sample_delay_factor;
/*
* These macros conveniently encapsulate a computation we'll use to
* continuously evaluate whether or not the data sample delay is inside
* the eye.
*/
#define IDEAL_DELAY ((int) ideal_sample_delay_in_ns)
#define QUANTIZED_DELAY \
((int) ((sample_delay_factor * clock_period_in_ns) >> \
dll_delay_shift))
#define DELAY_ERROR (abs(QUANTIZED_DELAY - IDEAL_DELAY))
#define SAMPLE_IS_NOT_WITHIN_THE_EYE (DELAY_ERROR > (tEYE >> 1))
/*
* While the quantized sample time falls outside the eye, reduce the
* sample delay or extend the data setup to move the sampling point back
* toward the eye. Do not allow the number of data setup cycles to
* exceed the maximum allowed by the NFC.
*/
while (SAMPLE_IS_NOT_WITHIN_THE_EYE &&
(data_setup_in_cycles < nfc->max_data_setup_cycles)) {
/*
* If control arrives here, the quantized sample delay falls
* outside the eye. Check if it's before the eye opens, or after
* the eye closes.
*/
if (QUANTIZED_DELAY > IDEAL_DELAY) {
/*
* If control arrives here, the quantized sample delay
* falls after the eye closes. Decrease the quantized
* delay time and then go back to re-evaluate.
*/
if (sample_delay_factor != 0)
sample_delay_factor--;
continue;
}
/*
* If control arrives here, the quantized sample delay falls
* before the eye opens. Shift the sample point by increasing
* data setup time. This will also make the eye larger.
*/
/* Give a cycle to data setup. */
data_setup_in_cycles++;
/* Synchronize the data setup time with the cycles. */
data_setup_in_ns += clock_period_in_ns;
/* Adjust tEYE accordingly. */
tEYE += clock_period_in_ns;
/*
* Decrease the ideal sample delay by one half cycle, to keep it
* in the middle of the eye.
*/
ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1);
/* ...and one less period for the delay time. */
ideal_sample_delay_in_ns -= clock_period_in_ns;
/* Jam a negative ideal sample delay to zero. */
if (ideal_sample_delay_in_ns < 0)
ideal_sample_delay_in_ns = 0;
/*
* We have a new ideal sample delay, so re-compute the quantized
* delay.
*/
sample_delay_factor =
ns_to_cycles(
ideal_sample_delay_in_ns << dll_delay_shift,
clock_period_in_ns, 0);
if (sample_delay_factor > nfc->max_sample_delay_factor)
sample_delay_factor = nfc->max_sample_delay_factor;
}
/* Control arrives here when we're ready to return our results. */
return_results:
hw->data_setup_in_cycles = data_setup_in_cycles;
hw->data_hold_in_cycles = data_hold_in_cycles;
hw->address_setup_in_cycles = address_setup_in_cycles;
hw->use_half_periods = dll_use_half_periods;
hw->sample_delay_factor = sample_delay_factor;
hw->device_busy_timeout = GPMI_DEFAULT_BUSY_TIMEOUT;
hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
/* Return success. */
return 0;
}
/*
* <1> Firstly, we should know what's the GPMI-clock means.
* The GPMI-clock is the internal clock in the gpmi nand controller.
@ -824,12 +362,9 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
* 4.1) From the aspect of the nand chip pins:
* Delay = (tREA + C - tRP) {1}
*
* tREA : the maximum read access time. From the ONFI nand standards,
* we know that tREA is 16ns in mode 5, tREA is 20ns is mode 4.
* Please check it in : www.onfi.org
* C : a constant for adjust the delay. default is 4.
* tRP : the read pulse width.
* Specified by the HW_GPMI_TIMING0:DATA_SETUP:
* tREA : the maximum read access time.
* C : a constant to adjust the delay. default is 4000ps.
* tRP : the read pulse width, which is exactly:
* tRP = (GPMI-clock-period) * DATA_SETUP
*
* 4.2) From the aspect of the GPMI nand controller:
@ -843,239 +378,137 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
*
* Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
* is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
* is 16ns, but in mx6q, we use 12ns.
* is 16000ps, but in mx6q, we use 12000ps.
*
* 4.3) since {1} equals {2}, we get:
*
* (tREA + 4 - tRP) * 8
* RDN_DELAY = --------------------- {3}
* (tREA + 4000 - tRP) * 8
* RDN_DELAY = ----------------------- {3}
* RP
*
* 4.4) We only support the fastest asynchronous mode of ONFI nand.
* For some ONFI nand, the mode 4 is the fastest mode;
* while for some ONFI nand, the mode 5 is the fastest mode.
* So we only support the mode 4 and mode 5. It is no need to
* support other modes.
*/
static void gpmi_compute_edo_timing(struct gpmi_nand_data *this,
struct gpmi_nfc_hardware_timing *hw)
static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
const struct nand_sdr_timings *sdr)
{
struct resources *r = &this->resources;
unsigned long rate = clk_get_rate(r->clock[0]);
int mode = this->timing_mode;
int dll_threshold = this->devdata->max_chain_delay;
unsigned long delay;
unsigned long clk_period;
int t_rea;
int c = 4;
int t_rp;
int rp;
struct gpmi_nfc_hardware_timing *hw = &this->hw;
unsigned int dll_threshold_ps = this->devdata->max_chain_delay;
unsigned int period_ps, reference_period_ps;
unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles;
unsigned int tRP_ps;
bool use_half_period;
int sample_delay_ps, sample_delay_factor;
u16 busy_timeout_cycles;
u8 wrn_dly_sel;
/*
* [1] for GPMI_HW_GPMI_TIMING0:
* The async mode requires 40MHz for mode 4, 50MHz for mode 5.
* The GPMI can support 100MHz at most. So if we want to
* get the 40MHz or 50MHz, we have to set DS=1, DH=1.
* Set the ADDRESS_SETUP to 0 in mode 4.
*/
hw->data_setup_in_cycles = 1;
hw->data_hold_in_cycles = 1;
hw->address_setup_in_cycles = ((mode == 5) ? 1 : 0);
/* [2] for GPMI_HW_GPMI_TIMING1 */
hw->device_busy_timeout = 0x9000;
/* [3] for GPMI_HW_GPMI_CTRL1 */
hw->wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
/*
* Enlarge 10 times for the numerator and denominator in {3}.
* This make us to get more accurate result.
*/
clk_period = NSEC_PER_SEC / (rate / 10);
dll_threshold *= 10;
t_rea = ((mode == 5) ? 16 : 20) * 10;
c *= 10;
t_rp = clk_period * 1; /* DATA_SETUP is 1 */
if (clk_period > dll_threshold) {
hw->use_half_periods = 1;
rp = clk_period / 2;
if (sdr->tRC_min >= 30000) {
/* ONFI non-EDO modes [0-3] */
hw->clk_rate = 22000000;
wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
} else if (sdr->tRC_min >= 25000) {
/* ONFI EDO mode 4 */
hw->clk_rate = 80000000;
wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
} else {
hw->use_half_periods = 0;
rp = clk_period;
/* ONFI EDO mode 5 */
hw->clk_rate = 100000000;
wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
}
/* SDR core timings are given in picoseconds */
period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate);
addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps);
hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) |
BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) |
BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles);
hw->timing1 = BF_GPMI_TIMING1_BUSY_TIMEOUT(busy_timeout_cycles * 4096);
/*
* Multiply the numerator with 10, we could do a round off:
* 7.8 round up to 8; 7.4 round down to 7.
* Derive NFC ideal delay from {3}:
*
* (tREA + 4000 - tRP) * 8
* RDN_DELAY = -----------------------
* RP
*/
delay = (((t_rea + c - t_rp) * 8) * 10) / rp;
delay = (delay + 5) / 10;
hw->sample_delay_factor = delay;
}
static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
{
struct resources *r = &this->resources;
struct nand_chip *nand = &this->nand;
struct mtd_info *mtd = nand_to_mtd(nand);
uint8_t *feature;
unsigned long rate;
int ret;
feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL);
if (!feature)
return -ENOMEM;
nand->select_chip(mtd, 0);
/* [1] send SET FEATURE command to NAND */
feature[0] = mode;
ret = nand->onfi_set_features(mtd, nand,
ONFI_FEATURE_ADDR_TIMING_MODE, feature);
if (ret)
goto err_out;
/* [2] send GET FEATURE command to double-check the timing mode */
memset(feature, 0, ONFI_SUBFEATURE_PARAM_LEN);
ret = nand->onfi_get_features(mtd, nand,
ONFI_FEATURE_ADDR_TIMING_MODE, feature);
if (ret || feature[0] != mode)
goto err_out;
nand->select_chip(mtd, -1);
/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
rate = (mode == 5) ? 100000000 : 80000000;
clk_set_rate(r->clock[0], rate);
/* Let the gpmi_begin() re-compute the timing again. */
this->flags &= ~GPMI_TIMING_INIT_OK;
this->flags |= GPMI_ASYNC_EDO_ENABLED;
this->timing_mode = mode;
kfree(feature);
dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode);
return 0;
err_out:
nand->select_chip(mtd, -1);
kfree(feature);
dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode);
return -EINVAL;
}
int gpmi_extra_init(struct gpmi_nand_data *this)
{
struct nand_chip *chip = &this->nand;
/* Enable the asynchronous EDO feature. */
if (GPMI_IS_MX6(this) && chip->onfi_version) {
int mode = onfi_get_async_timing_mode(chip);
/* We only support the timing mode 4 and mode 5. */
if (mode & ONFI_TIMING_MODE_5)
mode = 5;
else if (mode & ONFI_TIMING_MODE_4)
mode = 4;
else
return 0;
return enable_edo_mode(this, mode);
if (period_ps > dll_threshold_ps) {
use_half_period = true;
reference_period_ps = period_ps / 2;
} else {
use_half_period = false;
reference_period_ps = period_ps;
}
return 0;
tRP_ps = data_setup_cycles * period_ps;
sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8;
if (sample_delay_ps > 0)
sample_delay_factor = sample_delay_ps / reference_period_ps;
else
sample_delay_factor = 0;
hw->ctrl1n = BF_GPMI_CTRL1_WRN_DLY_SEL(wrn_dly_sel);
if (sample_delay_factor)
hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) |
BM_GPMI_CTRL1_DLL_ENABLE |
(use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
}
/* Begin the I/O */
void gpmi_begin(struct gpmi_nand_data *this)
void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
{
struct gpmi_nfc_hardware_timing *hw = &this->hw;
struct resources *r = &this->resources;
void __iomem *gpmi_regs = r->gpmi_regs;
unsigned int clock_period_in_ns;
uint32_t reg;
unsigned int dll_wait_time_in_us;
struct gpmi_nfc_hardware_timing hw;
int ret;
unsigned int dll_wait_time_us;
/* Enable the clock. */
ret = gpmi_enable_clk(this);
if (ret) {
dev_err(this->dev, "We failed in enable the clk\n");
goto err_out;
}
clk_set_rate(r->clock[0], hw->clk_rate);
/* Only initialize the timing once */
if (this->flags & GPMI_TIMING_INIT_OK)
return;
this->flags |= GPMI_TIMING_INIT_OK;
if (this->flags & GPMI_ASYNC_EDO_ENABLED)
gpmi_compute_edo_timing(this, &hw);
else
gpmi_nfc_compute_hardware_timing(this, &hw);
/* [1] Set HW_GPMI_TIMING0 */
reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) |
BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles) |
BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles);
writel(reg, gpmi_regs + HW_GPMI_TIMING0);
/* [2] Set HW_GPMI_TIMING1 */
writel(BF_GPMI_TIMING1_BUSY_TIMEOUT(hw.device_busy_timeout),
gpmi_regs + HW_GPMI_TIMING1);
/* [3] The following code is to set the HW_GPMI_CTRL1. */
/* Set the WRN_DLY_SEL */
writel(BM_GPMI_CTRL1_WRN_DLY_SEL, gpmi_regs + HW_GPMI_CTRL1_CLR);
writel(BF_GPMI_CTRL1_WRN_DLY_SEL(hw.wrn_dly_sel),
gpmi_regs + HW_GPMI_CTRL1_SET);
/* DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. */
writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR);
/* Clear out the DLL control fields. */
reg = BM_GPMI_CTRL1_RDN_DELAY | BM_GPMI_CTRL1_HALF_PERIOD;
writel(reg, gpmi_regs + HW_GPMI_CTRL1_CLR);
/* If no sample delay is called for, return immediately. */
if (!hw.sample_delay_factor)
return;
/* Set RDN_DELAY or HALF_PERIOD. */
reg = ((hw.use_half_periods) ? BM_GPMI_CTRL1_HALF_PERIOD : 0)
| BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor);
writel(reg, gpmi_regs + HW_GPMI_CTRL1_SET);
/* At last, we enable the DLL. */
writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET);
writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0);
writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1);
/*
* After we enable the GPMI DLL, we have to wait 64 clock cycles before
* we can use the GPMI. Calculate the amount of time we need to wait,
* in microseconds.
* Clear several CTRL1 fields, DLL must be disabled when setting
* RDN_DELAY or HALF_PERIOD.
*/
clock_period_in_ns = NSEC_PER_SEC / clk_get_rate(r->clock[0]);
dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000;
writel(BM_GPMI_CTRL1_CLEAR_MASK, gpmi_regs + HW_GPMI_CTRL1_CLR);
writel(hw->ctrl1n, gpmi_regs + HW_GPMI_CTRL1_SET);
if (!dll_wait_time_in_us)
dll_wait_time_in_us = 1;
/* Wait 64 clock cycles before using the GPMI after enabling the DLL */
dll_wait_time_us = USEC_PER_SEC / hw->clk_rate * 64;
if (!dll_wait_time_us)
dll_wait_time_us = 1;
/* Wait for the DLL to settle. */
udelay(dll_wait_time_in_us);
err_out:
return;
udelay(dll_wait_time_us);
}
void gpmi_end(struct gpmi_nand_data *this)
int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
const struct nand_data_interface *conf)
{
gpmi_disable_clk(this);
struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
const struct nand_sdr_timings *sdr;
/* Retrieve required NAND timings */
sdr = nand_get_sdr_timings(conf);
if (IS_ERR(sdr))
return PTR_ERR(sdr);
/* Only MX6 GPMI controller can reach EDO timings */
if (sdr->tRC_min <= 25000 && !GPMI_IS_MX6(this))
return -ENOTSUPP;
/* Stop here if this call was just a check */
if (chipnr < 0)
return 0;
/* Do the actual derivation of the controller timings */
gpmi_nfc_compute_timings(this, sdr);
this->hw.must_apply_timings = true;
return 0;
}
/* Clears a BCH interrupt. */

View File

@ -94,7 +94,7 @@ static const struct mtd_ooblayout_ops gpmi_ooblayout_ops = {
static const struct gpmi_devdata gpmi_devdata_imx23 = {
.type = IS_MX23,
.bch_max_ecc_strength = 20,
.max_chain_delay = 16,
.max_chain_delay = 16000,
.clks = gpmi_clks_for_mx2x,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
};
@ -102,7 +102,7 @@ static const struct gpmi_devdata gpmi_devdata_imx23 = {
static const struct gpmi_devdata gpmi_devdata_imx28 = {
.type = IS_MX28,
.bch_max_ecc_strength = 20,
.max_chain_delay = 16,
.max_chain_delay = 16000,
.clks = gpmi_clks_for_mx2x,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx2x),
};
@ -114,7 +114,7 @@ static const char * const gpmi_clks_for_mx6[] = {
static const struct gpmi_devdata gpmi_devdata_imx6q = {
.type = IS_MX6Q,
.bch_max_ecc_strength = 40,
.max_chain_delay = 12,
.max_chain_delay = 12000,
.clks = gpmi_clks_for_mx6,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
};
@ -122,7 +122,7 @@ static const struct gpmi_devdata gpmi_devdata_imx6q = {
static const struct gpmi_devdata gpmi_devdata_imx6sx = {
.type = IS_MX6SX,
.bch_max_ecc_strength = 62,
.max_chain_delay = 12,
.max_chain_delay = 12000,
.clks = gpmi_clks_for_mx6,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx6),
};
@ -134,7 +134,7 @@ static const char * const gpmi_clks_for_mx7d[] = {
static const struct gpmi_devdata gpmi_devdata_imx7d = {
.type = IS_MX7D,
.bch_max_ecc_strength = 62,
.max_chain_delay = 12,
.max_chain_delay = 12000,
.clks = gpmi_clks_for_mx7d,
.clks_count = ARRAY_SIZE(gpmi_clks_for_mx7d),
};
@ -695,34 +695,6 @@ static void release_resources(struct gpmi_nand_data *this)
release_dma_channels(this);
}
static int init_hardware(struct gpmi_nand_data *this)
{
int ret;
/*
* This structure contains the "safe" GPMI timing that should succeed
* with any NAND Flash device
* (although, with less-than-optimal performance).
*/
struct nand_timing safe_timing = {
.data_setup_in_ns = 80,
.data_hold_in_ns = 60,
.address_setup_in_ns = 25,
.gpmi_sample_delay_in_ns = 6,
.tREA_in_ns = -1,
.tRLOH_in_ns = -1,
.tRHOH_in_ns = -1,
};
/* Initialize the hardwares. */
ret = gpmi_init(this);
if (ret)
return ret;
this->timing = safe_timing;
return 0;
}
static int read_page_prepare(struct gpmi_nand_data *this,
void *destination, unsigned length,
void *alt_virt, dma_addr_t alt_phys, unsigned alt_size,
@ -938,11 +910,32 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret;
if ((this->current_chip < 0) && (chipnr >= 0))
gpmi_begin(this);
else if ((this->current_chip >= 0) && (chipnr < 0))
gpmi_end(this);
/*
* For power consumption matters, disable/enable the clock each time a
* die is selected/unselected.
*/
if (this->current_chip < 0 && chipnr >= 0) {
ret = gpmi_enable_clk(this);
if (ret)
dev_err(this->dev, "Failed to enable the clock\n");
} else if (this->current_chip >= 0 && chipnr < 0) {
ret = gpmi_disable_clk(this);
if (ret)
dev_err(this->dev, "Failed to disable the clock\n");
}
/*
* This driver currently supports only one NAND chip. Plus, dies share
* the same configuration. So once timings have been applied on the
* controller side, they will not change anymore. When the time will
* come, the check on must_apply_timings will have to be dropped.
*/
if (chipnr >= 0 && this->hw.must_apply_timings) {
this->hw.must_apply_timings = false;
gpmi_nfc_apply_timings(this);
}
this->current_chip = chipnr;
}
@ -1955,14 +1948,6 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
chip->options |= NAND_SUBPAGE_READ;
}
/*
* Can we enable the extra features? such as EDO or Sync mode.
*
* We do not check the return value now. That's means if we fail in
* enable the extra features, we still can run in the normal way.
*/
gpmi_extra_init(this);
return 0;
}
@ -1983,6 +1968,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
nand_set_controller_data(chip, this);
nand_set_flash_node(chip, this->pdev->dev.of_node);
chip->select_chip = gpmi_select_chip;
chip->setup_data_interface = gpmi_setup_data_interface;
chip->cmd_ctrl = gpmi_cmd_ctrl;
chip->dev_ready = gpmi_dev_ready;
chip->read_byte = gpmi_read_byte;
@ -2093,7 +2079,7 @@ static int gpmi_nand_probe(struct platform_device *pdev)
if (ret)
goto exit_acquire_resources;
ret = init_hardware(this);
ret = gpmi_init(this);
if (ret)
goto exit_nfc_init;
@ -2141,7 +2127,6 @@ static int gpmi_pm_resume(struct device *dev)
return ret;
/* re-init the GPMI registers */
this->flags &= ~GPMI_TIMING_INIT_OK;
ret = gpmi_init(this);
if (ret) {
dev_err(this->dev, "Error setting GPMI : %d\n", ret);
@ -2155,9 +2140,6 @@ static int gpmi_pm_resume(struct device *dev)
return ret;
}
/* re-init others */
gpmi_extra_init(this);
return 0;
}
#endif /* CONFIG_PM_SLEEP */

View File

@ -86,39 +86,6 @@ enum dma_ops_type {
DMA_FOR_WRITE_ECC_PAGE
};
/**
* struct nand_timing - Fundamental timing attributes for NAND.
* @data_setup_in_ns: The data setup time, in nanoseconds. Usually the
* maximum of tDS and tWP. A negative value
* indicates this characteristic isn't known.
* @data_hold_in_ns: The data hold time, in nanoseconds. Usually the
* maximum of tDH, tWH and tREH. A negative value
* indicates this characteristic isn't known.
* @address_setup_in_ns: The address setup time, in nanoseconds. Usually
* the maximum of tCLS, tCS and tALS. A negative
* value indicates this characteristic isn't known.
* @gpmi_sample_delay_in_ns: A GPMI-specific timing parameter. A negative value
* indicates this characteristic isn't known.
* @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A
* negative value indicates this characteristic isn't
* known.
* @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A
* negative value indicates this characteristic isn't
* known.
* @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A
* negative value indicates this characteristic isn't
* known.
*/
struct nand_timing {
int8_t data_setup_in_ns;
int8_t data_hold_in_ns;
int8_t address_setup_in_ns;
int8_t gpmi_sample_delay_in_ns;
int8_t tREA_in_ns;
int8_t tRLOH_in_ns;
int8_t tRHOH_in_ns;
};
enum gpmi_type {
IS_MX23,
IS_MX28,
@ -135,11 +102,27 @@ struct gpmi_devdata {
const int clks_count;
};
/**
* struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters.
* @must_apply_timings: Whether controller timings have already been
* applied or not (useful only while there is
* support for only one chip select)
* @clk_rate: The clock rate that must be used to derive the
* following parameters
* @timing0: HW_GPMI_TIMING0 register
* @timing1: HW_GPMI_TIMING1 register
* @ctrl1n: HW_GPMI_CTRL1n register
*/
struct gpmi_nfc_hardware_timing {
bool must_apply_timings;
unsigned long int clk_rate;
u32 timing0;
u32 timing1;
u32 ctrl1n;
};
struct gpmi_nand_data {
/* flags */
#define GPMI_ASYNC_EDO_ENABLED (1 << 0)
#define GPMI_TIMING_INIT_OK (1 << 1)
int flags;
/* Devdata */
const struct gpmi_devdata *devdata;
/* System Interface */
@ -150,8 +133,7 @@ struct gpmi_nand_data {
struct resources resources;
/* Flash Hardware */
struct nand_timing timing;
int timing_mode;
struct gpmi_nfc_hardware_timing hw;
/* BCH */
struct bch_geometry bch_geometry;
@ -204,69 +186,6 @@ struct gpmi_nand_data {
void *private;
};
/**
* struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters.
* @data_setup_in_cycles: The data setup time, in cycles.
* @data_hold_in_cycles: The data hold time, in cycles.
* @address_setup_in_cycles: The address setup time, in cycles.
* @device_busy_timeout: The timeout waiting for NAND Ready/Busy,
* this value is the number of cycles multiplied
* by 4096.
* @use_half_periods: Indicates the clock is running slowly, so the
* NFC DLL should use half-periods.
* @sample_delay_factor: The sample delay factor.
* @wrn_dly_sel: The delay on the GPMI write strobe.
*/
struct gpmi_nfc_hardware_timing {
/* for HW_GPMI_TIMING0 */
uint8_t data_setup_in_cycles;
uint8_t data_hold_in_cycles;
uint8_t address_setup_in_cycles;
/* for HW_GPMI_TIMING1 */
uint16_t device_busy_timeout;
#define GPMI_DEFAULT_BUSY_TIMEOUT 0x500 /* default busy timeout value.*/
/* for HW_GPMI_CTRL1 */
bool use_half_periods;
uint8_t sample_delay_factor;
uint8_t wrn_dly_sel;
};
/**
* struct timing_threshold - Timing threshold
* @max_data_setup_cycles: The maximum number of data setup cycles that
* can be expressed in the hardware.
* @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires
* for data read internal setup. In the Reference
* Manual, see the chapter "High-Speed NAND
* Timing" for more details.
* @max_sample_delay_factor: The maximum sample delay factor that can be
* expressed in the hardware.
* @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the
* sample delay DLL hardware can possibly work
* with (the DLL is unusable with longer periods).
* If the full-cycle period is greater than HALF
* this value, the DLL must be configured to use
* half-periods.
* @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the
* DLL can implement.
* @clock_frequency_in_hz: The clock frequency, in Hz, during the current
* I/O transaction. If no I/O transaction is in
* progress, this is the clock frequency during
* the most recent I/O transaction.
*/
struct timing_threshold {
const unsigned int max_chip_count;
const unsigned int max_data_setup_cycles;
const unsigned int internal_data_setup_in_ns;
const unsigned int max_sample_delay_factor;
const unsigned int max_dll_clock_period_in_ns;
const unsigned int max_dll_delay_in_ns;
unsigned long clock_frequency_in_hz;
};
/* Common Services */
int common_nfc_set_geometry(struct gpmi_nand_data *);
struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
@ -279,14 +198,16 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *,
/* GPMI-NAND helper function library */
int gpmi_init(struct gpmi_nand_data *);
int gpmi_extra_init(struct gpmi_nand_data *);
void gpmi_clear_bch(struct gpmi_nand_data *);
void gpmi_dump_info(struct gpmi_nand_data *);
int bch_set_geometry(struct gpmi_nand_data *);
int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
int gpmi_send_command(struct gpmi_nand_data *);
void gpmi_begin(struct gpmi_nand_data *);
void gpmi_end(struct gpmi_nand_data *);
int gpmi_enable_clk(struct gpmi_nand_data *this);
int gpmi_disable_clk(struct gpmi_nand_data *this);
int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
const struct nand_data_interface *conf);
void gpmi_nfc_apply_timings(struct gpmi_nand_data *this);
int gpmi_read_data(struct gpmi_nand_data *);
int gpmi_send_data(struct gpmi_nand_data *);
int gpmi_send_page(struct gpmi_nand_data *,

View File

@ -147,6 +147,11 @@
#define BM_GPMI_CTRL1_GPMI_MODE (1 << 0)
#define BM_GPMI_CTRL1_CLEAR_MASK (BM_GPMI_CTRL1_WRN_DLY_SEL | \
BM_GPMI_CTRL1_DLL_ENABLE | \
BM_GPMI_CTRL1_RDN_DELAY | \
BM_GPMI_CTRL1_HALF_PERIOD)
#define HW_GPMI_TIMING0 0x00000070
#define BP_GPMI_TIMING0_ADDRESS_SETUP 16

View File

@ -762,8 +762,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
chip->write_buf = hisi_nfc_write_buf;
chip->read_buf = hisi_nfc_read_buf;
chip->chip_delay = HINFC504_CHIP_DELAY;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
chip->set_features = nand_get_set_features_notsupp;
chip->get_features = nand_get_set_features_notsupp;
hisi_nfc_host_init(host);

View File

@ -307,7 +307,8 @@ struct marvell_nfc_caps {
* @controller: Base controller structure
* @dev: Parent device (used to print error messages)
* @regs: NAND controller registers
* @ecc_clk: ECC block clock, two times the NAND controller clock
* @core_clk: Core clock
* @reg_clk: Regiters clock
* @complete: Completion object to wait for NAND controller events
* @assigned_cs: Bitmask describing already assigned CS lines
* @chips: List containing all the NAND chips attached to
@ -320,7 +321,8 @@ struct marvell_nfc {
struct nand_hw_control controller;
struct device *dev;
void __iomem *regs;
struct clk *ecc_clk;
struct clk *core_clk;
struct clk *reg_clk;
struct completion complete;
unsigned long assigned_cs;
struct list_head chips;
@ -379,6 +381,8 @@ struct marvell_nfc_timings {
* return the number of clock periods.
*/
#define TO_CYCLES(ps, period_ns) (DIV_ROUND_UP(ps / 1000, period_ns))
#define TO_CYCLES64(ps, period_ns) (DIV_ROUND_UP_ULL(div_u64(ps, 1000), \
period_ns))
/**
* NAND driver structure filled during the parsing of the ->exec_op() subop
@ -2189,7 +2193,7 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
struct nand_chip *chip = mtd_to_nand(mtd);
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
unsigned int period_ns = 1000000000 / clk_get_rate(nfc->ecc_clk) * 2;
unsigned int period_ns = 1000000000 / clk_get_rate(nfc->core_clk) * 2;
const struct nand_sdr_timings *sdr;
struct marvell_nfc_timings nfc_tmg;
int read_delay;
@ -2236,8 +2240,20 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
nfc_tmg.tRHW = TO_CYCLES(max_t(int, sdr->tRHW_min, sdr->tCCS_min),
period_ns);
/* Use WAIT_MODE (wait for RB line) instead of only relying on delays */
/*
* NFCv2: Use WAIT_MODE (wait for RB line), do not rely only on delays.
* NFCv1: No WAIT_MODE, tR must be maximal.
*/
if (nfc->caps->is_nfcv2) {
nfc_tmg.tR = TO_CYCLES(sdr->tWB_max, period_ns);
} else {
nfc_tmg.tR = TO_CYCLES64(sdr->tWB_max + sdr->tR_max,
period_ns);
if (nfc_tmg.tR + 3 > nfc_tmg.tCH)
nfc_tmg.tR = nfc_tmg.tCH - 3;
else
nfc_tmg.tR = 0;
}
if (chipnr < 0)
return 0;
@ -2249,18 +2265,24 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
NDTR0_TWP(nfc_tmg.tWP) |
NDTR0_TWH(nfc_tmg.tWH) |
NDTR0_TCS(nfc_tmg.tCS) |
NDTR0_TCH(nfc_tmg.tCH) |
NDTR0_RD_CNT_DEL(read_delay) |
NDTR0_SELCNTR |
NDTR0_TADL(nfc_tmg.tADL);
NDTR0_TCH(nfc_tmg.tCH);
marvell_nand->ndtr1 =
NDTR1_TAR(nfc_tmg.tAR) |
NDTR1_TWHR(nfc_tmg.tWHR) |
NDTR1_TRHW(nfc_tmg.tRHW) |
NDTR1_WAIT_MODE |
NDTR1_TR(nfc_tmg.tR);
if (nfc->caps->is_nfcv2) {
marvell_nand->ndtr0 |=
NDTR0_RD_CNT_DEL(read_delay) |
NDTR0_SELCNTR |
NDTR0_TADL(nfc_tmg.tADL);
marvell_nand->ndtr1 |=
NDTR1_TRHW(nfc_tmg.tRHW) |
NDTR1_WAIT_MODE;
}
return 0;
}
@ -2395,8 +2417,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
chip->exec_op = marvell_nfc_exec_op;
chip->select_chip = marvell_nfc_select_chip;
if (nfc->caps->is_nfcv2 &&
!of_property_read_bool(np, "marvell,nand-keep-config"))
if (!of_property_read_bool(np, "marvell,nand-keep-config"))
chip->setup_data_interface = marvell_nfc_setup_data_interface;
mtd = nand_to_mtd(chip);
@ -2520,8 +2541,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
if (pdata)
/* Legacy bindings support only one chip */
ret = mtd_device_register(mtd, pdata->parts[0],
pdata->nr_parts[0]);
ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
else
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
@ -2739,20 +2759,37 @@ static int marvell_nfc_probe(struct platform_device *pdev)
return irq;
}
nfc->ecc_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(nfc->ecc_clk))
return PTR_ERR(nfc->ecc_clk);
nfc->core_clk = devm_clk_get(&pdev->dev, "core");
ret = clk_prepare_enable(nfc->ecc_clk);
/* Managed the legacy case (when the first clock was not named) */
if (nfc->core_clk == ERR_PTR(-ENOENT))
nfc->core_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(nfc->core_clk))
return PTR_ERR(nfc->core_clk);
ret = clk_prepare_enable(nfc->core_clk);
if (ret)
return ret;
nfc->reg_clk = devm_clk_get(&pdev->dev, "reg");
if (PTR_ERR(nfc->reg_clk) != -ENOENT) {
if (!IS_ERR(nfc->reg_clk)) {
ret = clk_prepare_enable(nfc->reg_clk);
if (ret)
goto unprepare_core_clk;
} else {
ret = PTR_ERR(nfc->reg_clk);
goto unprepare_core_clk;
}
}
marvell_nfc_disable_int(nfc, NDCR_ALL_INT);
marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
ret = devm_request_irq(dev, irq, marvell_nfc_isr,
0, "marvell-nfc", nfc);
if (ret)
goto unprepare_clk;
goto unprepare_reg_clk;
/* Get NAND controller capabilities */
if (pdev->id_entry)
@ -2763,24 +2800,26 @@ static int marvell_nfc_probe(struct platform_device *pdev)
if (!nfc->caps) {
dev_err(dev, "Could not retrieve NFC caps\n");
ret = -EINVAL;
goto unprepare_clk;
goto unprepare_reg_clk;
}
/* Init the controller and then probe the chips */
ret = marvell_nfc_init(nfc);
if (ret)
goto unprepare_clk;
goto unprepare_reg_clk;
platform_set_drvdata(pdev, nfc);
ret = marvell_nand_chips_init(dev, nfc);
if (ret)
goto unprepare_clk;
goto unprepare_reg_clk;
return 0;
unprepare_clk:
clk_disable_unprepare(nfc->ecc_clk);
unprepare_reg_clk:
clk_disable_unprepare(nfc->reg_clk);
unprepare_core_clk:
clk_disable_unprepare(nfc->core_clk);
return ret;
}
@ -2796,7 +2835,8 @@ static int marvell_nfc_remove(struct platform_device *pdev)
dma_release_channel(nfc->dma_chan);
}
clk_disable_unprepare(nfc->ecc_clk);
clk_disable_unprepare(nfc->reg_clk);
clk_disable_unprepare(nfc->core_clk);
return 0;
}

View File

@ -6,9 +6,8 @@
* by OSADL membership fees in 2009; for details see www.osadl.org.
*
* Based on original driver from Freescale Semiconductor
* written by John Rigby <jrigby@freescale.com> on basis
* of drivers/mtd/nand/mxc_nand.c. Reworked and extended
* Piotr Ziecik <kosmo@semihalf.com>.
* written by John Rigby <jrigby@freescale.com> on basis of mxc_nand.c.
* Reworked and extended by Piotr Ziecik <kosmo@semihalf.com>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -708,8 +707,8 @@ static int mpc5121_nfc_probe(struct platform_device *op)
chip->read_buf = mpc5121_nfc_read_buf;
chip->write_buf = mpc5121_nfc_write_buf;
chip->select_chip = mpc5121_nfc_select_chip;
chip->onfi_set_features = nand_onfi_get_set_features_notsupp;
chip->onfi_get_features = nand_onfi_get_set_features_notsupp;
chip->set_features = nand_get_set_features_notsupp;
chip->get_features = nand_get_set_features_notsupp;
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;

View File

@ -140,6 +140,8 @@ struct mxc_nand_host;
struct mxc_nand_devtype_data {
void (*preset)(struct mtd_info *);
int (*read_page)(struct nand_chip *chip, void *buf, void *oob, bool ecc,
int page);
void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
void (*send_page)(struct mtd_info *, unsigned int);
@ -150,10 +152,9 @@ struct mxc_nand_devtype_data {
u32 (*get_ecc_status)(struct mxc_nand_host *);
const struct mtd_ooblayout_ops *ooblayout;
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*correct_data)(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc);
int (*setup_data_interface)(struct mtd_info *mtd, int csline,
const struct nand_data_interface *conf);
void (*enable_hwecc)(struct nand_chip *chip, bool enable);
/*
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
@ -252,6 +253,109 @@ static void memcpy16_toio(void __iomem *trg, const void *src, int size)
__raw_writew(*s++, t++);
}
/*
* The controller splits a page into data chunks of 512 bytes + partial oob.
* There are writesize / 512 such chunks, the size of the partial oob parts is
* oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then
* contains additionally the byte lost by rounding (if any).
* This function handles the needed shuffling between host->data_buf (which
* holds a page in natural order, i.e. writesize bytes data + oobsize bytes
* spare) and the NFC buffer.
*/
static void copy_spare(struct mtd_info *mtd, bool bfrom, void *buf)
{
struct nand_chip *this = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(this);
u16 i, oob_chunk_size;
u16 num_chunks = mtd->writesize / 512;
u8 *d = buf;
u8 __iomem *s = host->spare0;
u16 sparebuf_size = host->devtype_data->spare_len;
/* size of oob chunk for all but possibly the last one */
oob_chunk_size = (host->used_oobsize / num_chunks) & ~1;
if (bfrom) {
for (i = 0; i < num_chunks - 1; i++)
memcpy16_fromio(d + i * oob_chunk_size,
s + i * sparebuf_size,
oob_chunk_size);
/* the last chunk */
memcpy16_fromio(d + i * oob_chunk_size,
s + i * sparebuf_size,
host->used_oobsize - i * oob_chunk_size);
} else {
for (i = 0; i < num_chunks - 1; i++)
memcpy16_toio(&s[i * sparebuf_size],
&d[i * oob_chunk_size],
oob_chunk_size);
/* the last chunk */
memcpy16_toio(&s[i * sparebuf_size],
&d[i * oob_chunk_size],
host->used_oobsize - i * oob_chunk_size);
}
}
/*
* MXC NANDFC can only perform full page+spare or spare-only read/write. When
* the upper layers perform a read/write buf operation, the saved column address
* is used to index into the full page. So usually this function is called with
* column == 0 (unless no column cycle is needed indicated by column == -1)
*/
static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
/* Write out column address, if necessary */
if (column != -1) {
host->devtype_data->send_addr(host, column & 0xff,
page_addr == -1);
if (mtd->writesize > 512)
/* another col addr cycle for 2k page */
host->devtype_data->send_addr(host,
(column >> 8) & 0xff,
false);
}
/* Write out page address, if necessary */
if (page_addr != -1) {
/* paddr_0 - p_addr_7 */
host->devtype_data->send_addr(host, (page_addr & 0xff), false);
if (mtd->writesize > 512) {
if (mtd->size >= 0x10000000) {
/* paddr_8 - paddr_15 */
host->devtype_data->send_addr(host,
(page_addr >> 8) & 0xff,
false);
host->devtype_data->send_addr(host,
(page_addr >> 16) & 0xff,
true);
} else
/* paddr_8 - paddr_15 */
host->devtype_data->send_addr(host,
(page_addr >> 8) & 0xff, true);
} else {
if (nand_chip->options & NAND_ROW_ADDR_3) {
/* paddr_8 - paddr_15 */
host->devtype_data->send_addr(host,
(page_addr >> 8) & 0xff,
false);
host->devtype_data->send_addr(host,
(page_addr >> 16) & 0xff,
true);
} else
/* paddr_8 - paddr_15 */
host->devtype_data->send_addr(host,
(page_addr >> 8) & 0xff, true);
}
}
}
static int check_int_v3(struct mxc_nand_host *host)
{
uint32_t tmp;
@ -575,6 +679,42 @@ static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
return ret;
}
static void mxc_nand_enable_hwecc_v1_v2(struct nand_chip *chip, bool enable)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
uint16_t config1;
if (chip->ecc.mode != NAND_ECC_HW)
return;
config1 = readw(NFC_V1_V2_CONFIG1);
if (enable)
config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
else
config1 &= ~NFC_V1_V2_CONFIG1_ECC_EN;
writew(config1, NFC_V1_V2_CONFIG1);
}
static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
uint32_t config2;
if (chip->ecc.mode != NAND_ECC_HW)
return;
config2 = readl(NFC_V3_CONFIG2);
if (enable)
config2 |= NFC_V3_CONFIG2_ECC_EN;
else
config2 &= ~NFC_V3_CONFIG2_ECC_EN;
writel(config2, NFC_V3_CONFIG2);
}
/* This functions is used by upper layer to checks if device is ready */
static int mxc_nand_dev_ready(struct mtd_info *mtd)
{
@ -585,45 +725,90 @@ static int mxc_nand_dev_ready(struct mtd_info *mtd)
return 1;
}
static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob,
bool ecc, int page)
{
/*
* If HW ECC is enabled, we turn it on during init. There is
* no need to enable again here.
*/
}
struct mtd_info *mtd = nand_to_mtd(chip);
struct mxc_nand_host *host = nand_get_controller_data(chip);
unsigned int bitflips_corrected = 0;
int no_subpages;
int i;
static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
host->devtype_data->enable_hwecc(chip, ecc);
/*
* 1-Bit errors are automatically corrected in HW. No need for
* additional correction. 2-Bit errors cannot be corrected by
* HW ECC, so we need to return failure
*/
uint16_t ecc_status = get_ecc_status_v1(host);
host->devtype_data->send_cmd(host, NAND_CMD_READ0, false);
mxc_do_addr_cycle(mtd, 0, page);
if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
dev_dbg(host->dev, "HWECC uncorrectable 2-bit ECC error\n");
return -EBADMSG;
if (mtd->writesize > 512)
host->devtype_data->send_cmd(host, NAND_CMD_READSTART, true);
no_subpages = mtd->writesize >> 9;
for (i = 0; i < no_subpages; i++) {
uint16_t ecc_stats;
/* NANDFC buffer 0 is used for page read/write */
writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
writew(NFC_OUTPUT, NFC_V1_V2_CONFIG2);
/* Wait for operation to complete */
wait_op_done(host, true);
ecc_stats = get_ecc_status_v1(host);
ecc_stats >>= 2;
if (buf && ecc) {
switch (ecc_stats & 0x3) {
case 0:
default:
break;
case 1:
mtd->ecc_stats.corrected++;
bitflips_corrected = 1;
break;
case 2:
mtd->ecc_stats.failed++;
break;
}
}
}
return 0;
if (buf)
memcpy32_fromio(buf, host->main_area0, mtd->writesize);
if (oob)
copy_spare(mtd, true, oob);
return bitflips_corrected;
}
static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf,
void *oob, bool ecc, int page)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
struct mtd_info *mtd = nand_to_mtd(chip);
struct mxc_nand_host *host = nand_get_controller_data(chip);
unsigned int max_bitflips = 0;
u32 ecc_stat, err;
int no_subpages = 1;
int ret = 0;
int no_subpages;
u8 ecc_bit_mask, err_limit;
host->devtype_data->enable_hwecc(chip, ecc);
host->devtype_data->send_cmd(host, NAND_CMD_READ0, false);
mxc_do_addr_cycle(mtd, 0, page);
if (mtd->writesize > 512)
host->devtype_data->send_cmd(host,
NAND_CMD_READSTART, true);
host->devtype_data->send_page(mtd, NFC_OUTPUT);
if (buf)
memcpy32_fromio(buf, host->main_area0, mtd->writesize);
if (oob)
copy_spare(mtd, true, oob);
ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
@ -634,25 +819,99 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
do {
err = ecc_stat & ecc_bit_mask;
if (err > err_limit) {
dev_dbg(host->dev, "UnCorrectable RS-ECC Error\n");
return -EBADMSG;
mtd->ecc_stats.failed++;
} else {
ret += err;
mtd->ecc_stats.corrected += err;
max_bitflips = max_t(unsigned int, max_bitflips, err);
}
ecc_stat >>= 4;
} while (--no_subpages);
dev_dbg(host->dev, "%d Symbol Correctable RS-ECC Error\n", ret);
return ret;
return max_bitflips;
}
static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code)
static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
void *oob_buf;
if (oob_required)
oob_buf = chip->oob_poi;
else
oob_buf = NULL;
return host->devtype_data->read_page(chip, buf, oob_buf, 1, page);
}
static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
void *oob_buf;
if (oob_required)
oob_buf = chip->oob_poi;
else
oob_buf = NULL;
return host->devtype_data->read_page(chip, buf, oob_buf, 0, page);
}
static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
return host->devtype_data->read_page(chip, NULL, chip->oob_poi, 0,
page);
}
static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf,
bool ecc, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct mxc_nand_host *host = nand_get_controller_data(chip);
host->devtype_data->enable_hwecc(chip, ecc);
host->devtype_data->send_cmd(host, NAND_CMD_SEQIN, false);
mxc_do_addr_cycle(mtd, 0, page);
memcpy32_toio(host->main_area0, buf, mtd->writesize);
copy_spare(mtd, false, chip->oob_poi);
host->devtype_data->send_page(mtd, NFC_INPUT);
host->devtype_data->send_cmd(host, NAND_CMD_PAGEPROG, true);
mxc_do_addr_cycle(mtd, 0, page);
return 0;
}
static int mxc_nand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
return mxc_nand_write_page(chip, buf, true, page);
}
static int mxc_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page)
{
return mxc_nand_write_page(chip, buf, false, page);
}
static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
memset(host->data_buf, 0xff, mtd->writesize);
return mxc_nand_write_page(chip, host->data_buf, false, page);
}
static u_char mxc_nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
@ -772,109 +1031,6 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
}
/*
* The controller splits a page into data chunks of 512 bytes + partial oob.
* There are writesize / 512 such chunks, the size of the partial oob parts is
* oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then
* contains additionally the byte lost by rounding (if any).
* This function handles the needed shuffling between host->data_buf (which
* holds a page in natural order, i.e. writesize bytes data + oobsize bytes
* spare) and the NFC buffer.
*/
static void copy_spare(struct mtd_info *mtd, bool bfrom)
{
struct nand_chip *this = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(this);
u16 i, oob_chunk_size;
u16 num_chunks = mtd->writesize / 512;
u8 *d = host->data_buf + mtd->writesize;
u8 __iomem *s = host->spare0;
u16 sparebuf_size = host->devtype_data->spare_len;
/* size of oob chunk for all but possibly the last one */
oob_chunk_size = (host->used_oobsize / num_chunks) & ~1;
if (bfrom) {
for (i = 0; i < num_chunks - 1; i++)
memcpy16_fromio(d + i * oob_chunk_size,
s + i * sparebuf_size,
oob_chunk_size);
/* the last chunk */
memcpy16_fromio(d + i * oob_chunk_size,
s + i * sparebuf_size,
host->used_oobsize - i * oob_chunk_size);
} else {
for (i = 0; i < num_chunks - 1; i++)
memcpy16_toio(&s[i * sparebuf_size],
&d[i * oob_chunk_size],
oob_chunk_size);
/* the last chunk */
memcpy16_toio(&s[i * sparebuf_size],
&d[i * oob_chunk_size],
host->used_oobsize - i * oob_chunk_size);
}
}
/*
* MXC NANDFC can only perform full page+spare or spare-only read/write. When
* the upper layers perform a read/write buf operation, the saved column address
* is used to index into the full page. So usually this function is called with
* column == 0 (unless no column cycle is needed indicated by column == -1)
*/
static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
/* Write out column address, if necessary */
if (column != -1) {
host->devtype_data->send_addr(host, column & 0xff,
page_addr == -1);
if (mtd->writesize > 512)
/* another col addr cycle for 2k page */
host->devtype_data->send_addr(host,
(column >> 8) & 0xff,
false);
}
/* Write out page address, if necessary */
if (page_addr != -1) {
/* paddr_0 - p_addr_7 */
host->devtype_data->send_addr(host, (page_addr & 0xff), false);
if (mtd->writesize > 512) {
if (mtd->size >= 0x10000000) {
/* paddr_8 - paddr_15 */
host->devtype_data->send_addr(host,
(page_addr >> 8) & 0xff,
false);
host->devtype_data->send_addr(host,
(page_addr >> 16) & 0xff,
true);
} else
/* paddr_8 - paddr_15 */
host->devtype_data->send_addr(host,
(page_addr >> 8) & 0xff, true);
} else {
if (nand_chip->options & NAND_ROW_ADDR_3) {
/* paddr_8 - paddr_15 */
host->devtype_data->send_addr(host,
(page_addr >> 8) & 0xff,
false);
host->devtype_data->send_addr(host,
(page_addr >> 16) & 0xff,
true);
} else
/* paddr_8 - paddr_15 */
host->devtype_data->send_addr(host,
(page_addr >> 8) & 0xff, true);
}
}
}
#define MXC_V1_ECCBYTES 5
static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
@ -1235,57 +1391,6 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
mxc_do_addr_cycle(mtd, column, page_addr);
break;
case NAND_CMD_READ0:
case NAND_CMD_READOOB:
if (command == NAND_CMD_READ0)
host->buf_start = column;
else
host->buf_start = column + mtd->writesize;
command = NAND_CMD_READ0; /* only READ0 is valid */
host->devtype_data->send_cmd(host, command, false);
WARN_ONCE(column < 0,
"Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
command, column, page_addr);
mxc_do_addr_cycle(mtd, 0, page_addr);
if (mtd->writesize > 512)
host->devtype_data->send_cmd(host,
NAND_CMD_READSTART, true);
host->devtype_data->send_page(mtd, NFC_OUTPUT);
memcpy32_fromio(host->data_buf, host->main_area0,
mtd->writesize);
copy_spare(mtd, true);
break;
case NAND_CMD_SEQIN:
if (column >= mtd->writesize)
/* call ourself to read a page */
mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
host->buf_start = column;
host->devtype_data->send_cmd(host, command, false);
WARN_ONCE(column < -1,
"Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
command, column, page_addr);
mxc_do_addr_cycle(mtd, 0, page_addr);
break;
case NAND_CMD_PAGEPROG:
memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
copy_spare(mtd, false);
host->devtype_data->send_page(mtd, NFC_INPUT);
host->devtype_data->send_cmd(host, command, true);
WARN_ONCE(column != -1 || page_addr != -1,
"Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
command, column, page_addr);
mxc_do_addr_cycle(mtd, column, page_addr);
break;
case NAND_CMD_READID:
host->devtype_data->send_cmd(host, command, true);
mxc_do_addr_cycle(mtd, column, page_addr);
@ -1316,19 +1421,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
}
}
static int mxc_nand_onfi_set_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
u8 *subfeature_param)
static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, u8 *subfeature_param)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
int i;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
host->buf_start = 0;
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
@ -1342,19 +1441,13 @@ static int mxc_nand_onfi_set_features(struct mtd_info *mtd,
return 0;
}
static int mxc_nand_onfi_get_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
u8 *subfeature_param)
static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, u8 *subfeature_param)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
int i;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
mxc_do_addr_cycle(mtd, addr, -1);
host->devtype_data->send_page(mtd, NFC_OUTPUT);
@ -1397,6 +1490,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
/* v1 + irqpending_quirk: i.MX21 */
static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
.preset = preset_v1,
.read_page = mxc_nand_read_page_v1,
.send_cmd = send_cmd_v1_v2,
.send_addr = send_addr_v1_v2,
.send_page = send_page_v1,
@ -1407,7 +1501,7 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
.get_ecc_status = get_ecc_status_v1,
.ooblayout = &mxc_v1_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v1,
.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
.irqpending_quirk = 1,
.needs_ip = 0,
.regs_offset = 0xe00,
@ -1420,6 +1514,7 @@ static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
/* v1 + !irqpending_quirk: i.MX27, i.MX31 */
static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
.preset = preset_v1,
.read_page = mxc_nand_read_page_v1,
.send_cmd = send_cmd_v1_v2,
.send_addr = send_addr_v1_v2,
.send_page = send_page_v1,
@ -1430,7 +1525,7 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
.get_ecc_status = get_ecc_status_v1,
.ooblayout = &mxc_v1_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v1,
.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
.irqpending_quirk = 0,
.needs_ip = 0,
.regs_offset = 0xe00,
@ -1444,6 +1539,7 @@ static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
/* v21: i.MX25, i.MX35 */
static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.preset = preset_v2,
.read_page = mxc_nand_read_page_v2_v3,
.send_cmd = send_cmd_v1_v2,
.send_addr = send_addr_v1_v2,
.send_page = send_page_v2,
@ -1454,8 +1550,8 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.get_ecc_status = get_ecc_status_v2,
.ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v2,
.correct_data = mxc_nand_correct_data_v2_v3,
.setup_data_interface = mxc_nand_v2_setup_data_interface,
.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
.irqpending_quirk = 0,
.needs_ip = 0,
.regs_offset = 0x1e00,
@ -1469,6 +1565,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
/* v3.2a: i.MX51 */
static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
.preset = preset_v3,
.read_page = mxc_nand_read_page_v2_v3,
.send_cmd = send_cmd_v3,
.send_addr = send_addr_v3,
.send_page = send_page_v3,
@ -1479,7 +1576,7 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
.get_ecc_status = get_ecc_status_v3,
.ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v2_v3,
.enable_hwecc = mxc_nand_enable_hwecc_v3,
.irqpending_quirk = 0,
.needs_ip = 1,
.regs_offset = 0,
@ -1494,6 +1591,7 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
/* v3.2b: i.MX53 */
static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
.preset = preset_v3,
.read_page = mxc_nand_read_page_v2_v3,
.send_cmd = send_cmd_v3,
.send_addr = send_addr_v3,
.send_page = send_page_v3,
@ -1504,7 +1602,7 @@ static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
.get_ecc_status = get_ecc_status_v3,
.ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v1_v3,
.correct_data = mxc_nand_correct_data_v2_v3,
.enable_hwecc = mxc_nand_enable_hwecc_v3,
.irqpending_quirk = 0,
.needs_ip = 1,
.regs_offset = 0,
@ -1642,8 +1740,8 @@ static int mxcnd_probe(struct platform_device *pdev)
this->read_word = mxc_nand_read_word;
this->write_buf = mxc_nand_write_buf;
this->read_buf = mxc_nand_read_buf;
this->onfi_set_features = mxc_nand_onfi_set_features;
this->onfi_get_features = mxc_nand_onfi_get_features;
this->set_features = mxc_nand_set_features;
this->get_features = mxc_nand_get_features;
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
@ -1751,9 +1849,12 @@ static int mxcnd_probe(struct platform_device *pdev)
switch (this->ecc.mode) {
case NAND_ECC_HW:
this->ecc.calculate = mxc_nand_calculate_ecc;
this->ecc.hwctl = mxc_nand_enable_hwecc;
this->ecc.correct = host->devtype_data->correct_data;
this->ecc.read_page = mxc_nand_read_page;
this->ecc.read_page_raw = mxc_nand_read_page_raw;
this->ecc.read_oob = mxc_nand_read_oob;
this->ecc.write_page = mxc_nand_write_page_ecc;
this->ecc.write_page_raw = mxc_nand_write_page_raw;
this->ecc.write_oob = mxc_nand_write_oob;
break;
case NAND_ECC_SOFT:
@ -1810,15 +1911,18 @@ static int mxcnd_probe(struct platform_device *pdev)
goto escan;
/* Register the partitions */
mtd_device_parse_register(mtd, part_probes,
NULL,
err = mtd_device_parse_register(mtd, part_probes, NULL,
host->pdata.parts,
host->pdata.nr_parts);
if (err)
goto cleanup_nand;
platform_set_drvdata(pdev, host);
return 0;
cleanup_nand:
nand_cleanup(this);
escan:
if (host->clk_act)
clk_disable_unprepare(host->clk);

View File

@ -349,7 +349,7 @@ static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
* 8-bits of the data bus. During address transfers, the host shall
* set the upper 8-bits of the data bus to 00h.
*
* One user of the write_byte callback is nand_onfi_set_features. The
* One user of the write_byte callback is nand_set_features. The
* four parameters are specified to be written to I/O[7:0], but this is
* neither an address nor a command transfer. Let's assume a 0 on the
* upper I/O lines is OK.
@ -1159,6 +1159,60 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
return status;
}
static bool nand_supports_get_features(struct nand_chip *chip, int addr)
{
return (chip->parameters.supports_set_get_features &&
test_bit(addr, chip->parameters.get_feature_list));
}
static bool nand_supports_set_features(struct nand_chip *chip, int addr)
{
return (chip->parameters.supports_set_get_features &&
test_bit(addr, chip->parameters.set_feature_list));
}
/**
* nand_get_features - wrapper to perform a GET_FEATURE
* @chip: NAND chip info structure
* @addr: feature address
* @subfeature_param: the subfeature parameters, a four bytes array
*
* Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
* operation cannot be handled.
*/
int nand_get_features(struct nand_chip *chip, int addr,
u8 *subfeature_param)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (!nand_supports_get_features(chip, addr))
return -ENOTSUPP;
return chip->get_features(mtd, chip, addr, subfeature_param);
}
EXPORT_SYMBOL_GPL(nand_get_features);
/**
* nand_set_features - wrapper to perform a SET_FEATURE
* @chip: NAND chip info structure
* @addr: feature address
* @subfeature_param: the subfeature parameters, a four bytes array
*
* Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
* operation cannot be handled.
*/
int nand_set_features(struct nand_chip *chip, int addr,
u8 *subfeature_param)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (!nand_supports_set_features(chip, addr))
return -ENOTSUPP;
return chip->set_features(mtd, chip, addr, subfeature_param);
}
EXPORT_SYMBOL_GPL(nand_set_features);
/**
* nand_reset_data_interface - Reset data interface and timings
* @chip: The NAND chip
@ -1214,31 +1268,59 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
int ret;
if (!chip->setup_data_interface)
return 0;
/*
* Ensure the timing mode has been changed on the chip side
* before changing timings on the controller side.
*/
if (chip->onfi_version &&
(le16_to_cpu(chip->onfi_params.opt_cmd) &
ONFI_OPT_CMD_SET_GET_FEATURES)) {
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
ret = chip->onfi_set_features(mtd, chip,
ONFI_FEATURE_ADDR_TIMING_MODE,
/* Change the mode on the chip side (if supported by the NAND chip) */
if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
chip->select_chip(mtd, chipnr);
ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
tmode_param);
chip->select_chip(mtd, -1);
if (ret)
goto err;
return ret;
}
/* Change the mode on the controller side */
ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
err:
if (ret)
return ret;
/* Check the mode has been accepted by the chip, if supported */
if (!nand_supports_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE))
return 0;
memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
chip->select_chip(mtd, chipnr);
ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
tmode_param);
chip->select_chip(mtd, -1);
if (ret)
goto err_reset_chip;
if (tmode_param[0] != chip->onfi_timing_mode_default) {
pr_warn("timing mode %d not acknowledged by the NAND chip\n",
chip->onfi_timing_mode_default);
goto err_reset_chip;
}
return 0;
err_reset_chip:
/*
* Fallback to mode 0 if the chip explicitly did not ack the chosen
* timing mode.
*/
nand_reset_data_interface(chip, chipnr);
chip->select_chip(mtd, chipnr);
nand_reset_op(chip);
chip->select_chip(mtd, -1);
return ret;
}
@ -2738,10 +2820,18 @@ int nand_reset(struct nand_chip *chip, int chipnr)
if (ret)
return ret;
chip->select_chip(mtd, chipnr);
/*
* A nand_reset_data_interface() put both the NAND chip and the NAND
* controller in timings mode 0. If the default mode for this chip is
* also 0, no need to proceed to the change again. Plus, at probe time,
* nand_setup_data_interface() uses ->set/get_features() which would
* fail anyway as the parameter page is not available yet.
*/
if (!chip->onfi_timing_mode_default)
return 0;
chip->data_interface = saved_data_intf;
ret = nand_setup_data_interface(chip, chipnr);
chip->select_chip(mtd, -1);
if (ret)
return ret;
@ -4760,44 +4850,35 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
}
/**
* nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
* nand_default_set_features- [REPLACEABLE] set NAND chip features
* @mtd: MTD device structure
* @chip: nand chip info structure
* @addr: feature address.
* @subfeature_param: the subfeature parameters, a four bytes array.
*/
static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param)
static int nand_default_set_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
uint8_t *subfeature_param)
{
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
return nand_set_features_op(chip, addr, subfeature_param);
}
/**
* nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand
* nand_default_get_features- [REPLACEABLE] get NAND chip features
* @mtd: MTD device structure
* @chip: nand chip info structure
* @addr: feature address.
* @subfeature_param: the subfeature parameters, a four bytes array.
*/
static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param)
static int nand_default_get_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
uint8_t *subfeature_param)
{
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
return nand_get_features_op(chip, addr, subfeature_param);
}
/**
* nand_onfi_get_set_features_notsupp - set/get features stub returning
* -ENOTSUPP
* nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP
* @mtd: MTD device structure
* @chip: nand chip info structure
* @addr: feature address.
@ -4806,13 +4887,12 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
* Should be used by NAND controller drivers that do not support the SET/GET
* FEATURES operations.
*/
int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
u8 *subfeature_param)
int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
int addr, u8 *subfeature_param)
{
return -ENOTSUPP;
}
EXPORT_SYMBOL(nand_onfi_get_set_features_notsupp);
EXPORT_SYMBOL(nand_get_set_features_notsupp);
/**
* nand_suspend - [MTD Interface] Suspend the NAND flash
@ -4869,10 +4949,10 @@ static void nand_set_defaults(struct nand_chip *chip)
chip->select_chip = nand_select_chip;
/* set for ONFI nand */
if (!chip->onfi_set_features)
chip->onfi_set_features = nand_onfi_set_features;
if (!chip->onfi_get_features)
chip->onfi_get_features = nand_onfi_get_features;
if (!chip->set_features)
chip->set_features = nand_default_set_features;
if (!chip->get_features)
chip->get_features = nand_default_get_features;
/* If called twice, pointers that depend on busw may need to be reset */
if (!chip->read_byte || chip->read_byte == nand_read_byte)
@ -5012,7 +5092,7 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
static int nand_flash_detect_onfi(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_onfi_params *p = &chip->onfi_params;
struct nand_onfi_params *p;
char id[4];
int i, ret, val;
@ -5021,14 +5101,23 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
if (ret || strncmp(id, "ONFI", 4))
return 0;
/* ONFI chip: allocate a buffer to hold its parameter page */
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
ret = nand_read_param_page_op(chip, 0, NULL, 0);
if (ret)
return 0;
if (ret) {
ret = 0;
goto free_onfi_param_page;
}
for (i = 0; i < 3; i++) {
ret = nand_read_data_op(chip, p, sizeof(*p), true);
if (ret)
return 0;
if (ret) {
ret = 0;
goto free_onfi_param_page;
}
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
le16_to_cpu(p->crc)) {
@ -5038,31 +5127,33 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
if (i == 3) {
pr_err("Could not find valid ONFI parameter page; aborting\n");
return 0;
goto free_onfi_param_page;
}
/* Check version */
val = le16_to_cpu(p->revision);
if (val & (1 << 5))
chip->onfi_version = 23;
chip->parameters.onfi.version = 23;
else if (val & (1 << 4))
chip->onfi_version = 22;
chip->parameters.onfi.version = 22;
else if (val & (1 << 3))
chip->onfi_version = 21;
chip->parameters.onfi.version = 21;
else if (val & (1 << 2))
chip->onfi_version = 20;
chip->parameters.onfi.version = 20;
else if (val & (1 << 1))
chip->onfi_version = 10;
chip->parameters.onfi.version = 10;
if (!chip->onfi_version) {
if (!chip->parameters.onfi.version) {
pr_info("unsupported ONFI version: %d\n", val);
return 0;
goto free_onfi_param_page;
} else {
ret = 1;
}
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
if (!mtd->name)
mtd->name = p->model;
strncpy(chip->parameters.model, p->model,
sizeof(chip->parameters.model) - 1);
mtd->writesize = le32_to_cpu(p->byte_per_page);
@ -5084,14 +5175,14 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
chip->options |= NAND_BUSWIDTH_16;
if (p->ecc_bits != 0xff) {
chip->ecc_strength_ds = p->ecc_bits;
chip->ecc_step_ds = 512;
} else if (chip->onfi_version >= 21 &&
(onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
} else if (chip->parameters.onfi.version >= 21 &&
(le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
/*
* The nand_flash_detect_ext_param_page() uses the
@ -5109,7 +5200,28 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
pr_warn("Could not retrieve ONFI ECC requirements\n");
}
return 1;
/* Save some parameters from the parameter page for future use */
if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
chip->parameters.supports_set_get_features = true;
bitmap_set(chip->parameters.get_feature_list,
ONFI_FEATURE_ADDR_TIMING_MODE, 1);
bitmap_set(chip->parameters.set_feature_list,
ONFI_FEATURE_ADDR_TIMING_MODE, 1);
}
chip->parameters.onfi.tPROG = le16_to_cpu(p->t_prog);
chip->parameters.onfi.tBERS = le16_to_cpu(p->t_bers);
chip->parameters.onfi.tR = le16_to_cpu(p->t_r);
chip->parameters.onfi.tCCS = le16_to_cpu(p->t_ccs);
chip->parameters.onfi.async_timing_mode =
le16_to_cpu(p->async_timing_mode);
chip->parameters.onfi.vendor_revision =
le16_to_cpu(p->vendor_revision);
memcpy(chip->parameters.onfi.vendor, p->vendor,
sizeof(p->vendor));
free_onfi_param_page:
kfree(p);
return ret;
}
/*
@ -5118,8 +5230,9 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
static int nand_flash_detect_jedec(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_jedec_params *p = &chip->jedec_params;
struct nand_jedec_params *p;
struct jedec_ecc_info *ecc;
int jedec_version = 0;
char id[5];
int i, val, ret;
@ -5128,14 +5241,23 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
if (ret || strncmp(id, "JEDEC", sizeof(id)))
return 0;
/* JEDEC chip: allocate a buffer to hold its parameter page */
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
if (ret)
return 0;
if (ret) {
ret = 0;
goto free_jedec_param_page;
}
for (i = 0; i < 3; i++) {
ret = nand_read_data_op(chip, p, sizeof(*p), true);
if (ret)
return 0;
if (ret) {
ret = 0;
goto free_jedec_param_page;
}
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
le16_to_cpu(p->crc))
@ -5144,25 +5266,25 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
if (i == 3) {
pr_err("Could not find valid JEDEC parameter page; aborting\n");
return 0;
goto free_jedec_param_page;
}
/* Check version */
val = le16_to_cpu(p->revision);
if (val & (1 << 2))
chip->jedec_version = 10;
jedec_version = 10;
else if (val & (1 << 1))
chip->jedec_version = 1; /* vendor specific version */
jedec_version = 1; /* vendor specific version */
if (!chip->jedec_version) {
if (!jedec_version) {
pr_info("unsupported JEDEC version: %d\n", val);
return 0;
goto free_jedec_param_page;
}
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
if (!mtd->name)
mtd->name = p->model;
strncpy(chip->parameters.model, p->model,
sizeof(chip->parameters.model) - 1);
mtd->writesize = le32_to_cpu(p->byte_per_page);
@ -5177,7 +5299,7 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
chip->bits_per_cell = p->bits_per_cell;
if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
chip->options |= NAND_BUSWIDTH_16;
/* ECC info */
@ -5190,7 +5312,9 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
pr_warn("Invalid codeword size\n");
}
return 1;
free_jedec_param_page:
kfree(p);
return ret;
}
/*
@ -5349,8 +5473,8 @@ static bool find_full_id_nand(struct nand_chip *chip,
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;
if (!mtd->name)
mtd->name = type->name;
strncpy(chip->parameters.model, type->name,
sizeof(chip->parameters.model) - 1);
return true;
}
@ -5489,22 +5613,28 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
}
}
chip->onfi_version = 0;
chip->parameters.onfi.version = 0;
if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
if (nand_flash_detect_onfi(chip))
ret = nand_flash_detect_onfi(chip);
if (ret < 0)
return ret;
else if (ret)
goto ident_done;
/* Check if the chip is JEDEC compliant */
if (nand_flash_detect_jedec(chip))
ret = nand_flash_detect_jedec(chip);
if (ret < 0)
return ret;
else if (ret)
goto ident_done;
}
if (!type->name)
return -ENODEV;
if (!mtd->name)
mtd->name = type->name;
strncpy(chip->parameters.model, type->name,
sizeof(chip->parameters.model) - 1);
chip->chipsize = (uint64_t)type->chipsize << 20;
@ -5517,6 +5647,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
chip->options |= type->options;
ident_done:
if (!mtd->name)
mtd->name = chip->parameters.model;
if (chip->options & NAND_BUSWIDTH_AUTO) {
WARN_ON(busw & NAND_BUSWIDTH_16);
@ -5563,17 +5695,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
maf_id, dev_id);
if (chip->onfi_version)
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
chip->onfi_params.model);
else if (chip->jedec_version)
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
chip->jedec_params.model);
else
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
type->name);
chip->parameters.model);
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
@ -6465,10 +6588,7 @@ int nand_scan_tail(struct mtd_info *mtd)
/* 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_manuf_cleanup;
}

View File

@ -95,7 +95,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
errloc[i]);
}
} else if (count < 0) {
printk(KERN_ERR "ecc unrecoverable error\n");
pr_err("ecc unrecoverable error\n");
count = -EBADMSG;
}
return count;
@ -134,7 +134,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
}
if (!eccsize || !eccbytes) {
printk(KERN_WARNING "ecc parameters not supplied\n");
pr_warn("ecc parameters not supplied\n");
goto fail;
}
@ -151,7 +151,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
/* verify that eccbytes has the expected value */
if (nbc->bch->ecc_bytes != eccbytes) {
printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
pr_warn("invalid eccbytes %u, should be %u\n",
eccbytes, nbc->bch->ecc_bytes);
goto fail;
}
@ -166,7 +166,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
/* sanity checks */
if (8*(eccsize+eccbytes) >= (1 << m)) {
printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
pr_warn("eccsize %u is too large\n", eccsize);
goto fail;
}
@ -181,7 +181,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
nand->ecc.steps = eccsteps;
nand->ecc.total = eccsteps * eccbytes;
if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
printk(KERN_WARNING "invalid ecc layout\n");
pr_warn("invalid ecc layout\n");
goto fail;
}

View File

@ -2,8 +2,6 @@
* This file contains an ECC algorithm that detects and corrects 1 bit
* errors in a 256 byte block of data.
*
* drivers/mtd/nand/nand_ecc.c
*
* Copyright © 2008 Koninklijke Philips Electronics NV.
* Author: Frans Meulenbroeks
*
@ -30,15 +28,6 @@
*
*/
/*
* The STANDALONE macro is useful when running the code outside the kernel
* e.g. when running the code in a testbed or a benchmark program.
* When STANDALONE is used, the module related macros are commented out
* as well as the linux include files.
* Instead a private definition of mtd_info is given to satisfy the compiler
* (the code does not use mtd_info, so the code does not care)
*/
#ifndef STANDALONE
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
@ -46,17 +35,6 @@
#include <linux/mtd/rawnand.h>
#include <linux/mtd/nand_ecc.h>
#include <asm/byteorder.h>
#else
#include <stdint.h>
struct mtd_info;
#define EXPORT_SYMBOL(x) /* x */
#define MODULE_LICENSE(x) /* x */
#define MODULE_AUTHOR(x) /* x */
#define MODULE_DESCRIPTION(x) /* x */
#define pr_err printf
#endif
/*
* invparity is a 256 byte table that contains the odd parity

Some files were not shown because too many files have changed in this diff Show More