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:
commit
a88b5f3833
7
.mailmap
7
.mailmap
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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) */
|
||||
};
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
40
MAINTAINERS
40
MAINTAINERS
|
@ -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>
|
||||
|
|
|
@ -117,15 +117,15 @@
|
|||
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";
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
|
@ -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");
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* linux/drivers/mtd/onenand/generic.c
|
||||
*
|
||||
* Copyright (c) 2005 Samsung Electronics
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* linux/drivers/mtd/onenand/omap2.c
|
||||
*
|
||||
* OneNAND driver for OMAP2 / OMAP3
|
||||
*
|
||||
* Copyright © 2005-2006 Nokia Corporation
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* linux/drivers/mtd/onenand/onenand_base.c
|
||||
*
|
||||
* Copyright © 2005-2009 Samsung Electronics
|
||||
* Copyright © 2007 Nokia Corporation
|
||||
*
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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;
|
|
@ -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)
|
||||
*
|
||||
*
|
|
@ -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
|
|
@ -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)
|
||||
*
|
||||
*
|
|
@ -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
|
|
@ -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;
|
|
@ -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,
|
|
@ -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,8 +751,8 @@ 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",
|
||||
mtd->writesize);
|
||||
pr_warn("Unexpected NAND flash writesize %d. Aborting\n",
|
||||
mtd->writesize);
|
||||
goto out_free_dma;
|
||||
}
|
||||
cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||
|
@ -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:
|
|
@ -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)
|
||||
*
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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:
|
|
@ -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,11 +1067,11 @@ 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"
|
||||
" NumEraseUnits = %d\n"
|
||||
" FirstPhysicalEUN = %d\n"
|
||||
" FormattedSize = %d\n"
|
||||
" UnitSizeFactor = %d\n",
|
||||
pr_info(" DataOrgID = %s\n"
|
||||
" NumEraseUnits = %d\n"
|
||||
" FirstPhysicalEUN = %d\n"
|
||||
" FormattedSize = %d\n"
|
||||
" UnitSizeFactor = %d\n",
|
||||
mh->DataOrgID, mh->NumEraseUnits,
|
||||
mh->FirstPhysicalEUN, mh->FormattedSize,
|
||||
mh->UnitSizeFactor);
|
||||
|
@ -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,14 +1179,14 @@ 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"
|
||||
" NoOfBootImageBlocks = %d\n"
|
||||
" NoOfBinaryPartitions = %d\n"
|
||||
" NoOfBDTLPartitions = %d\n"
|
||||
" BlockMultiplerBits = %d\n"
|
||||
" FormatFlgs = %d\n"
|
||||
" OsakVersion = %d.%d.%d.%d\n"
|
||||
" PercentUsed = %d\n",
|
||||
pr_info(" bootRecordID = %s\n"
|
||||
" NoOfBootImageBlocks = %d\n"
|
||||
" NoOfBinaryPartitions = %d\n"
|
||||
" NoOfBDTLPartitions = %d\n"
|
||||
" BlockMultiplerBits = %d\n"
|
||||
" FormatFlgs = %d\n"
|
||||
" OsakVersion = %d.%d.%d.%d\n"
|
||||
" PercentUsed = %d\n",
|
||||
mh->bootRecordID, mh->NoOfBootImageBlocks,
|
||||
mh->NoOfBinaryPartitions,
|
||||
mh->NoOfBDTLPartitions,
|
||||
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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,8 +929,8 @@ 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",
|
||||
(unsigned long long)res.start, priv->bank);
|
||||
pr_info("eLBC NAND device at 0x%llx, bank %d\n",
|
||||
(unsigned long long)res.start, priv->bank);
|
||||
return 0;
|
||||
|
||||
err:
|
|
@ -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;
|
|
@ -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 @@ unmap_dma:
|
|||
*/
|
||||
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)
|
|
@ -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>
|
|
@ -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 @@ err_clk:
|
|||
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 @@ err_out:
|
|||
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,13 +362,10 @@ return_results:
|
|||
* 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:
|
||||
* tRP = (GPMI-clock-period) * 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:
|
||||
* Delay = RDN_DELAY * 0.125 * RP {2}
|
||||
|
@ -843,239 +378,137 @@ return_results:
|
|||
*
|
||||
* 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. */
|
|
@ -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 */
|
|
@ -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 *,
|
|
@ -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
|
|
@ -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);
|
||||
|
|
@ -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 */
|
||||
nfc_tmg.tR = TO_CYCLES(sdr->tWB_max, period_ns);
|
||||
/*
|
||||
* 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;
|
||||
}
|
|
@ -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;
|
|
@ -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,
|
||||
host->pdata.parts,
|
||||
host->pdata.nr_parts);
|
||||
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);
|
|
@ -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,
|
||||
tmode_param);
|
||||
/* 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 @@ ext_out:
|
|||
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 @@ ident_done:
|
|||
|
||||
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);
|
||||
|
||||
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
|
||||
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;
|
||||
}
|
|
@ -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,8 +151,8 @@ 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",
|
||||
eccbytes, nbc->bch->ecc_bytes);
|
||||
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;
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue