mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:02:20 +00:00
MTD updates for 3.14:
- Add me (Brian Norris) as an additional MTD maintainer (it'd be nice to get David's "ack" for this; I'm sure he approves, but he's been pretty silent lately) - Add Ezequiel Garcie as maintainer for the pxa3xx NAND driver - Last (?) round of pxa3xx improvements for supporting Armada 370/XP - Typical churn in driver boilerplate (OOM messages, printk()'s, devm_*, etc.) - Quad read mode support for SPI NOR driver (m25p80) - Update Davinci NAND driver to prepare for use on new platforms - Begin to kill off NAND_MAX_{PAGE,OOB}SIZE macros; more work is pending - Miscellaneous NAND device support (new IDs) - Add READ RETRY support for Micron MLC NAND - Support new GPMI NAND ECC layout device-tree binding - Avoid mapping stack/vmalloc() memory for GPMI NAND DMA -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJS50wMAAoJEFySrpd9RFgt1I0P/3fxzmHMmTRPjNRmtVqE5buW L3CjI1sPypA5PgCjjwABQdiw8WztBt6KVlMv5Gs6gaoi/WYAyAWz40PfwuBWFklD L8+cuKuuslsFfqh+gdkrBkNKnrFfMJpTDx57E5+dciInmWWB1w14sHMAYk5A/ZHK MBfXCcgfIECeQp1zSKmBtQxkhqn20hOS232gsCRWu2NWWu4UCzEcRLHGCBP1qqi3 6joQhrICiQJwH09D+I9YfyS/oisM+75Df+79xephcjMaJYAAE3tLVrKM84CBso+R R/wjOvX+xFVyvf3n+CftxbmbFVXtRAWqCEEHu2yKffiF9oipp9xOm6gqJb9SYX/7 n54fexx5cM1AE8OeDCxgbVCNfgoqDS6hk03d5oVMRmASShr0Ye4irG77Dy/KTMGC UdB2gb5HoKPC2N2IWWRlpwRoyLR9Xhf/+iCHjac0kB7oYQ0IdMyC0d4h7Prp5r/4 zaz/pBNNr1lL8DOFrIog02U1DL7jOBtMmlaCUnfrPkXOiwG04Inkfy7Gfug0uTIh o1JhwCWmrY/CLYmpMqKFK9V4gr72CZTGIjMeNpb2NUAM0XlRbf3AQ8x7P7Q9UjK6 ARZC/3lPrkSE8BDgSP8cT/oXB5zsIAU0jJbu3yIixD/v9WwMyKjoS4E8crl7qVB4 KDAzQNR3rjwmE9lOjtsx =3nT9 -----END PGP SIGNATURE----- Merge tag 'for-linus-20140127' of git://git.infradead.org/linux-mtd Pull MTD updates from Brian Norris: - Add me (Brian Norris) as an additional MTD maintainer (it'd be nice to get David's "ack" for this; I'm sure he approves, but he's been pretty silent lately) - Add Ezequiel Garcie as maintainer for the pxa3xx NAND driver - Last (?) round of pxa3xx improvements for supporting Armada 370/XP - Typical churn in driver boilerplate (OOM messages, printk()'s, devm_*, etc.) - Quad read mode support for SPI NOR driver (m25p80) - Update Davinci NAND driver to prepare for use on new platforms - Begin to kill off NAND_MAX_{PAGE,OOB}SIZE macros; more work is pending - Miscellaneous NAND device support (new IDs) - Add READ RETRY support for Micron MLC NAND - Support new GPMI NAND ECC layout device-tree binding - Avoid mapping stack/vmalloc() memory for GPMI NAND DMA * tag 'for-linus-20140127' of git://git.infradead.org/linux-mtd: (151 commits) mtd: gpmi: add sanity check when mapping DMA for read_buf/write_buf mtd: gpmi: allocate a proper buffer for non ECC read/write mtd: m25p80: Set rx_nbits for Quad SPI transfers mtd: m25p80: Enable Quad SPI read transfers for s25fl512s mtd: s3c2410: Merge plat/regs-nand.h into s3c2410.c mtd: mtdram: add missing 'const' mtd: m25p80: assign default read command mtd: nuc900_nand: remove redundant return value check of platform_get_resource() mtd: plat_nand: remove redundant return value check of platform_get_resource() mtd: nand: add Intel manufacturer ID mtd: nand: add SanDisk manufacturer ID mtd: nand: add support for Samsung K9LCG08U0B mtd: nand: pxa3xx: Add support for 2048 bytes page size devices mtd: m25p80: Use OPCODE_QUAD_READ_4B for 4-byte addressing mtd: nand: don't use {read,write}_buf for 8-bit transfers mtd: nand: use __packed shorthand mtd: nand: support Micron READ RETRY mtd: nand: add generic READ RETRY support mtd: nand: add ONFI vendor block for Micron mtd: nand: localize ECC failures per page ...
This commit is contained in:
commit
0e47c969c6
@ -1,46 +0,0 @@
|
||||
* Texas Instruments Davinci NAND
|
||||
|
||||
This file provides information, what the device node for the
|
||||
davinci nand interface contain.
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,davinci-nand";
|
||||
- reg : contain 2 offset/length values:
|
||||
- offset and length for the access window
|
||||
- offset and length for accessing the aemif control registers
|
||||
- ti,davinci-chipselect: Indicates on the davinci_nand driver which
|
||||
chipselect is used for accessing the nand.
|
||||
|
||||
Recommended properties :
|
||||
- ti,davinci-mask-ale: mask for ale
|
||||
- ti,davinci-mask-cle: mask for cle
|
||||
- ti,davinci-mask-chipsel: mask for chipselect
|
||||
- ti,davinci-ecc-mode: ECC mode valid values for davinci driver:
|
||||
- "none"
|
||||
- "soft"
|
||||
- "hw"
|
||||
- ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4.
|
||||
- ti,davinci-nand-buswidth: buswidth 8 or 16
|
||||
- ti,davinci-nand-use-bbt: use flash based bad block table support.
|
||||
|
||||
nand device bindings may contain additional sub-nodes describing
|
||||
partitions of the address space. See partition.txt for more detail.
|
||||
|
||||
Example(da850 EVM ):
|
||||
nand_cs3@62000000 {
|
||||
compatible = "ti,davinci-nand";
|
||||
reg = <0x62000000 0x807ff
|
||||
0x68000000 0x8000>;
|
||||
ti,davinci-chipselect = <1>;
|
||||
ti,davinci-mask-ale = <0>;
|
||||
ti,davinci-mask-cle = <0>;
|
||||
ti,davinci-mask-chipsel = <0>;
|
||||
ti,davinci-ecc-mode = "hw";
|
||||
ti,davinci-ecc-bits = <4>;
|
||||
ti,davinci-nand-use-bbt;
|
||||
|
||||
partition@180000 {
|
||||
label = "ubifs";
|
||||
reg = <0x180000 0x7e80000>;
|
||||
};
|
||||
};
|
94
Documentation/devicetree/bindings/mtd/davinci-nand.txt
Normal file
94
Documentation/devicetree/bindings/mtd/davinci-nand.txt
Normal file
@ -0,0 +1,94 @@
|
||||
Device tree bindings for Texas instruments Davinci/Keystone NAND controller
|
||||
|
||||
This file provides information, what the device node for the davinci/keystone
|
||||
NAND interface contains.
|
||||
|
||||
Documentation:
|
||||
Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf
|
||||
Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "ti,davinci-nand"
|
||||
"ti,keystone-nand"
|
||||
|
||||
- reg: Contains 2 offset/length values:
|
||||
- offset and length for the access window.
|
||||
- offset and length for accessing the AEMIF
|
||||
control registers.
|
||||
|
||||
- ti,davinci-chipselect: number of chipselect. Indicates on the
|
||||
davinci_nand driver which chipselect is used
|
||||
for accessing the nand.
|
||||
Can be in the range [0-3].
|
||||
|
||||
Recommended properties :
|
||||
|
||||
- ti,davinci-mask-ale: mask for ALE. Needed for executing address
|
||||
phase. These offset will be added to the base
|
||||
address for the chip select space the NAND Flash
|
||||
device is connected to.
|
||||
If not set equal to 0x08.
|
||||
|
||||
- ti,davinci-mask-cle: mask for CLE. Needed for executing command
|
||||
phase. These offset will be added to the base
|
||||
address for the chip select space the NAND Flash
|
||||
device is connected to.
|
||||
If not set equal to 0x10.
|
||||
|
||||
- ti,davinci-mask-chipsel: mask for chipselect address. Needed to mask
|
||||
addresses for given chipselect.
|
||||
|
||||
- nand-ecc-mode: operation mode of the NAND ecc mode. ECC mode
|
||||
valid values for davinci driver:
|
||||
- "none"
|
||||
- "soft"
|
||||
- "hw"
|
||||
|
||||
- ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4.
|
||||
|
||||
- nand-bus-width: buswidth 8 or 16. If not present 8.
|
||||
|
||||
- nand-on-flash-bbt: use flash based bad block table support. OOB
|
||||
identifier is saved in OOB area. If not present
|
||||
false.
|
||||
|
||||
Deprecated properties:
|
||||
|
||||
- ti,davinci-ecc-mode: operation mode of the NAND ecc mode. ECC mode
|
||||
valid values for davinci driver:
|
||||
- "none"
|
||||
- "soft"
|
||||
- "hw"
|
||||
|
||||
- ti,davinci-nand-buswidth: buswidth 8 or 16. If not present 8.
|
||||
|
||||
- ti,davinci-nand-use-bbt: use flash based bad block table support. OOB
|
||||
identifier is saved in OOB area. If not present
|
||||
false.
|
||||
|
||||
Nand device bindings may contain additional sub-nodes describing partitions of
|
||||
the address space. See partition.txt for more detail. The NAND Flash timing
|
||||
values must be programmed in the chip select’s node of AEMIF
|
||||
memory-controller (see Documentation/devicetree/bindings/memory-controllers/
|
||||
davinci-aemif.txt).
|
||||
|
||||
Example(da850 EVM ):
|
||||
|
||||
nand_cs3@62000000 {
|
||||
compatible = "ti,davinci-nand";
|
||||
reg = <0x62000000 0x807ff
|
||||
0x68000000 0x8000>;
|
||||
ti,davinci-chipselect = <1>;
|
||||
ti,davinci-mask-ale = <0>;
|
||||
ti,davinci-mask-cle = <0>;
|
||||
ti,davinci-mask-chipsel = <0>;
|
||||
nand-ecc-mode = "hw";
|
||||
ti,davinci-ecc-bits = <4>;
|
||||
nand-on-flash-bbt;
|
||||
|
||||
partition@180000 {
|
||||
label = "ubifs";
|
||||
reg = <0x180000 0x7e80000>;
|
||||
};
|
||||
};
|
@ -17,6 +17,14 @@ Required properties:
|
||||
Optional properties:
|
||||
- nand-on-flash-bbt: boolean to enable on flash bbt option if not
|
||||
present false
|
||||
- fsl,use-minimum-ecc: Protect this NAND flash with the minimum ECC
|
||||
strength required. The required ECC strength is
|
||||
automatically discoverable for some flash
|
||||
(e.g., according to the ONFI standard).
|
||||
However, note that if this strength is not
|
||||
discoverable or this property is not enabled,
|
||||
the software may chooses an implementation-defined
|
||||
ECC scheme.
|
||||
|
||||
The device tree may optionally contain sub-nodes describing partitions of the
|
||||
address space. See partition.txt for more detail.
|
||||
|
@ -2,7 +2,9 @@ PXA3xx NAND DT bindings
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should be "marvell,pxa3xx-nand"
|
||||
- compatible: Should be set to one of the following:
|
||||
marvell,pxa3xx-nand
|
||||
marvell,armada370-nand
|
||||
- reg: The register base for the controller
|
||||
- interrupts: The interrupt to map
|
||||
- #address-cells: Set to <1> if the node includes partitions
|
||||
@ -13,6 +15,8 @@ Optional properties:
|
||||
- marvell,nand-keep-config: Set to keep the NAND controller config as set
|
||||
by the bootloader
|
||||
- num-cs: Number of chipselect lines to usw
|
||||
- nand-on-flash-bbt: boolean to enable on flash bbt option if
|
||||
not present false
|
||||
|
||||
Example:
|
||||
|
||||
|
113
Documentation/mtd/nand/pxa3xx-nand.txt
Normal file
113
Documentation/mtd/nand/pxa3xx-nand.txt
Normal file
@ -0,0 +1,113 @@
|
||||
|
||||
About this document
|
||||
===================
|
||||
|
||||
Some notes about Marvell's NAND controller available in PXA and Armada 370/XP
|
||||
SoC (aka NFCv1 and NFCv2), with an emphasis on the latter.
|
||||
|
||||
NFCv2 controller background
|
||||
===========================
|
||||
|
||||
The controller has a 2176 bytes FIFO buffer. Therefore, in order to support
|
||||
larger pages, I/O operations on 4 KiB and 8 KiB pages is done with a set of
|
||||
chunked transfers.
|
||||
|
||||
For instance, if we choose a 2048 data chunk and set "BCH" ECC (see below)
|
||||
we'll have this layout in the pages:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
| 2048B data | 32B spare | 30B ECC || 2048B data | 32B spare | 30B ECC | ... |
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
The driver reads the data and spare portions independently and builds an internal
|
||||
buffer with this layout (in the 4 KiB page case):
|
||||
|
||||
------------------------------------------
|
||||
| 4096B data | 64B spare |
|
||||
------------------------------------------
|
||||
|
||||
Also, for the READOOB command the driver disables the ECC and reads a 'spare + ECC'
|
||||
OOB, one per chunk read.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
| 4096B data | 32B spare | 30B ECC | 32B spare | 30B ECC |
|
||||
-------------------------------------------------------------------
|
||||
|
||||
So, in order to achieve reading (for instance), we issue several READ0 commands
|
||||
(with some additional controller-specific magic) and read two chunks of 2080B
|
||||
(2048 data + 32 spare) each.
|
||||
The driver accommodates this data to expose the NAND core a contiguous buffer
|
||||
(4096 data + spare) or (4096 + spare + ECC + spare + ECC).
|
||||
|
||||
ECC
|
||||
===
|
||||
|
||||
The controller has built-in hardware ECC capabilities. In addition it is
|
||||
configurable between two modes: 1) Hamming, 2) BCH.
|
||||
|
||||
Note that the actual BCH mode: BCH-4 or BCH-8 will depend on the way
|
||||
the controller is configured to transfer the data.
|
||||
|
||||
In the BCH mode the ECC code will be calculated for each transfered chunk
|
||||
and expected to be located (when reading/programming) right after the spare
|
||||
bytes as the figure above shows.
|
||||
|
||||
So, repeating the above scheme, a 2048B data chunk will be followed by 32B
|
||||
spare, and then the ECC controller will read/write the ECC code (30B in
|
||||
this case):
|
||||
|
||||
------------------------------------
|
||||
| 2048B data | 32B spare | 30B ECC |
|
||||
------------------------------------
|
||||
|
||||
If the ECC mode is 'BCH' then the ECC is *always* 30 bytes long.
|
||||
If the ECC mode is 'Hamming' the ECC is 6 bytes long, for each 512B block.
|
||||
So in Hamming mode, a 2048B page will have a 24B ECC.
|
||||
|
||||
Despite all of the above, the controller requires the driver to only read or
|
||||
write in multiples of 8-bytes, because the data buffer is 64-bits.
|
||||
|
||||
OOB
|
||||
===
|
||||
|
||||
Because of the above scheme, and because the "spare" OOB is really located in
|
||||
the middle of a page, spare OOB cannot be read or write independently of the
|
||||
data area. In other words, in order to read the OOB (aka READOOB), the entire
|
||||
page (aka READ0) has to be read.
|
||||
|
||||
In the same sense, in order to write to the spare OOB the driver has to write
|
||||
an *entire* page.
|
||||
|
||||
Factory bad blocks handling
|
||||
===========================
|
||||
|
||||
Given the ECC BCH requires to layout the device's pages in a split
|
||||
data/OOB/data/OOB way, the controller has a view of the flash page that's
|
||||
different from the specified (aka the manufacturer's) view. In other words,
|
||||
|
||||
Factory view:
|
||||
|
||||
-----------------------------------------------
|
||||
| Data |x OOB |
|
||||
-----------------------------------------------
|
||||
|
||||
Driver's view:
|
||||
|
||||
-----------------------------------------------
|
||||
| Data | OOB | Data x | OOB |
|
||||
-----------------------------------------------
|
||||
|
||||
It can be seen from the above, that the factory bad block marker must be
|
||||
searched within the 'data' region, and not in the usual OOB region.
|
||||
|
||||
In addition, this means under regular usage the driver will write such
|
||||
position (since it belongs to the data region) and every used block is
|
||||
likely to be marked as bad.
|
||||
|
||||
For this reason, marking the block as bad in the OOB is explicitly
|
||||
disabled by using the NAND_BBT_NO_OOB_BBM option in the driver. The rationale
|
||||
for this is that there's no point in marking a block as bad, because good
|
||||
blocks are also 'marked as bad' (in the OOB BBM sense) under normal usage.
|
||||
|
||||
Instead, the driver relies on the bad block table alone, and should only perform
|
||||
the bad block scan on the very first time (when the device hasn't been used).
|
@ -5622,10 +5622,11 @@ F: mm/page_cgroup.c
|
||||
|
||||
MEMORY TECHNOLOGY DEVICES (MTD)
|
||||
M: David Woodhouse <dwmw2@infradead.org>
|
||||
M: Brian Norris <computersforpeace@gmail.com>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
W: http://www.linux-mtd.infradead.org/
|
||||
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
|
||||
T: git git://git.infradead.org/mtd-2.6.git
|
||||
T: git git://git.infradead.org/linux-mtd.git
|
||||
S: Maintained
|
||||
F: drivers/mtd/
|
||||
F: include/linux/mtd/
|
||||
@ -6942,6 +6943,12 @@ 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
|
||||
|
||||
MMP SUPPORT
|
||||
M: Eric Miao <eric.y.miao@gmail.com>
|
||||
M: Haojian Zhuang <haojian.zhuang@gmail.com>
|
||||
|
@ -1,123 +0,0 @@
|
||||
/* arch/arm/mach-s3c2410/include/mach/regs-nand.h
|
||||
*
|
||||
* Copyright (c) 2004-2005 Simtec Electronics <linux@simtec.co.uk>
|
||||
* http://www.simtec.co.uk/products/SWLINUX/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* S3C2410 NAND register definitions
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARM_REGS_NAND
|
||||
#define __ASM_ARM_REGS_NAND
|
||||
|
||||
|
||||
#define S3C2410_NFREG(x) (x)
|
||||
|
||||
#define S3C2410_NFCONF S3C2410_NFREG(0x00)
|
||||
#define S3C2410_NFCMD S3C2410_NFREG(0x04)
|
||||
#define S3C2410_NFADDR S3C2410_NFREG(0x08)
|
||||
#define S3C2410_NFDATA S3C2410_NFREG(0x0C)
|
||||
#define S3C2410_NFSTAT S3C2410_NFREG(0x10)
|
||||
#define S3C2410_NFECC S3C2410_NFREG(0x14)
|
||||
|
||||
#define S3C2440_NFCONT S3C2410_NFREG(0x04)
|
||||
#define S3C2440_NFCMD S3C2410_NFREG(0x08)
|
||||
#define S3C2440_NFADDR S3C2410_NFREG(0x0C)
|
||||
#define S3C2440_NFDATA S3C2410_NFREG(0x10)
|
||||
#define S3C2440_NFECCD0 S3C2410_NFREG(0x14)
|
||||
#define S3C2440_NFECCD1 S3C2410_NFREG(0x18)
|
||||
#define S3C2440_NFECCD S3C2410_NFREG(0x1C)
|
||||
#define S3C2440_NFSTAT S3C2410_NFREG(0x20)
|
||||
#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24)
|
||||
#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28)
|
||||
#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C)
|
||||
#define S3C2440_NFMECC1 S3C2410_NFREG(0x30)
|
||||
#define S3C2440_NFSECC S3C2410_NFREG(0x34)
|
||||
#define S3C2440_NFSBLK S3C2410_NFREG(0x38)
|
||||
#define S3C2440_NFEBLK S3C2410_NFREG(0x3C)
|
||||
|
||||
#define S3C2412_NFSBLK S3C2410_NFREG(0x20)
|
||||
#define S3C2412_NFEBLK S3C2410_NFREG(0x24)
|
||||
#define S3C2412_NFSTAT S3C2410_NFREG(0x28)
|
||||
#define S3C2412_NFMECC_ERR0 S3C2410_NFREG(0x2C)
|
||||
#define S3C2412_NFMECC_ERR1 S3C2410_NFREG(0x30)
|
||||
#define S3C2412_NFMECC0 S3C2410_NFREG(0x34)
|
||||
#define S3C2412_NFMECC1 S3C2410_NFREG(0x38)
|
||||
#define S3C2412_NFSECC S3C2410_NFREG(0x3C)
|
||||
|
||||
#define S3C2410_NFCONF_EN (1<<15)
|
||||
#define S3C2410_NFCONF_512BYTE (1<<14)
|
||||
#define S3C2410_NFCONF_4STEP (1<<13)
|
||||
#define S3C2410_NFCONF_INITECC (1<<12)
|
||||
#define S3C2410_NFCONF_nFCE (1<<11)
|
||||
#define S3C2410_NFCONF_TACLS(x) ((x)<<8)
|
||||
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
|
||||
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
|
||||
|
||||
#define S3C2410_NFSTAT_BUSY (1<<0)
|
||||
|
||||
#define S3C2440_NFCONF_BUSWIDTH_8 (0<<0)
|
||||
#define S3C2440_NFCONF_BUSWIDTH_16 (1<<0)
|
||||
#define S3C2440_NFCONF_ADVFLASH (1<<3)
|
||||
#define S3C2440_NFCONF_TACLS(x) ((x)<<12)
|
||||
#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8)
|
||||
#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4)
|
||||
|
||||
#define S3C2440_NFCONT_LOCKTIGHT (1<<13)
|
||||
#define S3C2440_NFCONT_SOFTLOCK (1<<12)
|
||||
#define S3C2440_NFCONT_ILLEGALACC_EN (1<<10)
|
||||
#define S3C2440_NFCONT_RNBINT_EN (1<<9)
|
||||
#define S3C2440_NFCONT_RN_FALLING (1<<8)
|
||||
#define S3C2440_NFCONT_SPARE_ECCLOCK (1<<6)
|
||||
#define S3C2440_NFCONT_MAIN_ECCLOCK (1<<5)
|
||||
#define S3C2440_NFCONT_INITECC (1<<4)
|
||||
#define S3C2440_NFCONT_nFCE (1<<1)
|
||||
#define S3C2440_NFCONT_ENABLE (1<<0)
|
||||
|
||||
#define S3C2440_NFSTAT_READY (1<<0)
|
||||
#define S3C2440_NFSTAT_nCE (1<<1)
|
||||
#define S3C2440_NFSTAT_RnB_CHANGE (1<<2)
|
||||
#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1<<3)
|
||||
|
||||
#define S3C2412_NFCONF_NANDBOOT (1<<31)
|
||||
#define S3C2412_NFCONF_ECCCLKCON (1<<30)
|
||||
#define S3C2412_NFCONF_ECC_MLC (1<<24)
|
||||
#define S3C2412_NFCONF_TACLS_MASK (7<<12) /* 1 extra bit of Tacls */
|
||||
|
||||
#define S3C2412_NFCONT_ECC4_DIRWR (1<<18)
|
||||
#define S3C2412_NFCONT_LOCKTIGHT (1<<17)
|
||||
#define S3C2412_NFCONT_SOFTLOCK (1<<16)
|
||||
#define S3C2412_NFCONT_ECC4_ENCINT (1<<13)
|
||||
#define S3C2412_NFCONT_ECC4_DECINT (1<<12)
|
||||
#define S3C2412_NFCONT_MAIN_ECC_LOCK (1<<7)
|
||||
#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5)
|
||||
#define S3C2412_NFCONT_nFCE1 (1<<2)
|
||||
#define S3C2412_NFCONT_nFCE0 (1<<1)
|
||||
|
||||
#define S3C2412_NFSTAT_ECC_ENCDONE (1<<7)
|
||||
#define S3C2412_NFSTAT_ECC_DECDONE (1<<6)
|
||||
#define S3C2412_NFSTAT_ILLEGAL_ACCESS (1<<5)
|
||||
#define S3C2412_NFSTAT_RnB_CHANGE (1<<4)
|
||||
#define S3C2412_NFSTAT_nFCE1 (1<<3)
|
||||
#define S3C2412_NFSTAT_nFCE0 (1<<2)
|
||||
#define S3C2412_NFSTAT_Res1 (1<<1)
|
||||
#define S3C2412_NFSTAT_READY (1<<0)
|
||||
|
||||
#define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf)
|
||||
#define S3C2412_NFECCERR_SERRBIT(x) (((x) >> 18) & 0x7)
|
||||
#define S3C2412_NFECCERR_MERRDATA(x) (((x) >> 7) & 0x3ff)
|
||||
#define S3C2412_NFECCERR_MERRBIT(x) (((x) >> 4) & 0x7)
|
||||
#define S3C2412_NFECCERR_SPARE_ERR(x) (((x) >> 2) & 0x3)
|
||||
#define S3C2412_NFECCERR_MAIN_ERR(x) (((x) >> 2) & 0x3)
|
||||
#define S3C2412_NFECCERR_NONE (0)
|
||||
#define S3C2412_NFECCERR_1BIT (1)
|
||||
#define S3C2412_NFECCERR_MULTIBIT (2)
|
||||
#define S3C2412_NFECCERR_ECCAREA (3)
|
||||
|
||||
|
||||
|
||||
#endif /* __ASM_ARM_REGS_NAND */
|
||||
|
@ -157,10 +157,11 @@ config MTD_BCM47XX_PARTS
|
||||
|
||||
comment "User Modules And Translation Layers"
|
||||
|
||||
#
|
||||
# MTD block device support is select'ed if needed
|
||||
#
|
||||
config MTD_BLKDEVS
|
||||
tristate "Common interface to block layer for MTD 'translation layers'"
|
||||
depends on BLOCK
|
||||
default n
|
||||
tristate
|
||||
|
||||
config MTD_BLOCK
|
||||
tristate "Caching block device access to MTD devices"
|
||||
|
@ -264,7 +264,8 @@ static struct mtd_part_parser afs_parser = {
|
||||
|
||||
static int __init afs_parser_init(void)
|
||||
{
|
||||
return register_mtd_parser(&afs_parser);
|
||||
register_mtd_parser(&afs_parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit afs_parser_exit(void)
|
||||
|
@ -139,7 +139,8 @@ static struct mtd_part_parser ar7_parser = {
|
||||
|
||||
static int __init ar7_parser_init(void)
|
||||
{
|
||||
return register_mtd_parser(&ar7_parser);
|
||||
register_mtd_parser(&ar7_parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ar7_parser_exit(void)
|
||||
|
@ -23,10 +23,12 @@
|
||||
* Amount of bytes we read when analyzing each block of flash memory.
|
||||
* Set it big enough to allow detecting partition and reading important data.
|
||||
*/
|
||||
#define BCM47XXPART_BYTES_TO_READ 0x404
|
||||
#define BCM47XXPART_BYTES_TO_READ 0x4e8
|
||||
|
||||
/* Magics */
|
||||
#define BOARD_DATA_MAGIC 0x5246504D /* MPFR */
|
||||
#define BOARD_DATA_MAGIC2 0xBD0D0BBD
|
||||
#define CFE_MAGIC 0x43464531 /* 1EFC */
|
||||
#define FACTORY_MAGIC 0x59544346 /* FCTY */
|
||||
#define POT_MAGIC1 0x54544f50 /* POTT */
|
||||
#define POT_MAGIC2 0x504f /* OP */
|
||||
@ -102,8 +104,9 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* CFE has small NVRAM at 0x400 */
|
||||
if (buf[0x400 / 4] == NVRAM_HEADER) {
|
||||
/* Magic or small NVRAM at 0x400 */
|
||||
if ((buf[0x4e0 / 4] == CFE_MAGIC && buf[0x4e4 / 4] == CFE_MAGIC) ||
|
||||
(buf[0x400 / 4] == NVRAM_HEADER)) {
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "boot",
|
||||
offset, MTD_WRITEABLE);
|
||||
continue;
|
||||
@ -190,6 +193,21 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
||||
offset, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read middle of the block */
|
||||
if (mtd_read(master, offset + 0x8000, 0x4,
|
||||
&bytes_read, (uint8_t *)buf) < 0) {
|
||||
pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
|
||||
offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */
|
||||
if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) {
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "board_data",
|
||||
offset, MTD_WRITEABLE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for NVRAM at the end of the last block. */
|
||||
@ -243,7 +261,8 @@ static struct mtd_part_parser bcm47xxpart_mtd_parser = {
|
||||
|
||||
static int __init bcm47xxpart_init(void)
|
||||
{
|
||||
return register_mtd_parser(&bcm47xxpart_mtd_parser);
|
||||
register_mtd_parser(&bcm47xxpart_mtd_parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit bcm47xxpart_exit(void)
|
||||
|
@ -221,7 +221,8 @@ static struct mtd_part_parser bcm63xx_cfe_parser = {
|
||||
|
||||
static int __init bcm63xx_cfe_parser_init(void)
|
||||
{
|
||||
return register_mtd_parser(&bcm63xx_cfe_parser);
|
||||
register_mtd_parser(&bcm63xx_cfe_parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit bcm63xx_cfe_parser_exit(void)
|
||||
|
@ -395,7 +395,8 @@ static int __init cmdline_parser_init(void)
|
||||
{
|
||||
if (mtdparts)
|
||||
mtdpart_setup(mtdparts);
|
||||
return register_mtd_parser(&cmdline_parser);
|
||||
register_mtd_parser(&cmdline_parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cmdline_parser_exit(void)
|
||||
|
@ -2047,21 +2047,21 @@ static int __init docg3_probe(struct platform_device *pdev)
|
||||
ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!ress) {
|
||||
dev_err(dev, "No I/O memory resource defined\n");
|
||||
goto noress;
|
||||
return ret;
|
||||
}
|
||||
base = ioremap(ress->start, DOC_IOSPACE_SIZE);
|
||||
base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE);
|
||||
|
||||
ret = -ENOMEM;
|
||||
cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS,
|
||||
GFP_KERNEL);
|
||||
cascade = devm_kzalloc(dev, sizeof(*cascade) * DOC_MAX_NBFLOORS,
|
||||
GFP_KERNEL);
|
||||
if (!cascade)
|
||||
goto nomem1;
|
||||
return ret;
|
||||
cascade->base = base;
|
||||
mutex_init(&cascade->lock);
|
||||
cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
|
||||
DOC_ECC_BCH_PRIMPOLY);
|
||||
if (!cascade->bch)
|
||||
goto nomem2;
|
||||
return ret;
|
||||
|
||||
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
|
||||
mtd = doc_probe_device(cascade, floor, dev);
|
||||
@ -2101,11 +2101,6 @@ err_probe:
|
||||
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
|
||||
if (cascade->floors[floor])
|
||||
doc_release_device(cascade->floors[floor]);
|
||||
nomem2:
|
||||
kfree(cascade);
|
||||
nomem1:
|
||||
iounmap(base);
|
||||
noress:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2119,7 +2114,6 @@ static int __exit docg3_release(struct platform_device *pdev)
|
||||
{
|
||||
struct docg3_cascade *cascade = platform_get_drvdata(pdev);
|
||||
struct docg3 *docg3 = cascade->floors[0]->priv;
|
||||
void __iomem *base = cascade->base;
|
||||
int floor;
|
||||
|
||||
doc_unregister_sysfs(pdev, cascade);
|
||||
@ -2129,8 +2123,6 @@ static int __exit docg3_release(struct platform_device *pdev)
|
||||
doc_release_device(cascade->floors[floor]);
|
||||
|
||||
free_bch(docg3->cascade->bch);
|
||||
kfree(cascade);
|
||||
iounmap(base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
#define OPCODE_WRSR 0x01 /* Write status register 1 byte */
|
||||
#define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */
|
||||
#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
|
||||
#define OPCODE_QUAD_READ 0x6b /* Read data bytes */
|
||||
#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
|
||||
#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
|
||||
#define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
|
||||
@ -48,10 +49,12 @@
|
||||
#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
|
||||
#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
|
||||
#define OPCODE_RDID 0x9f /* Read JEDEC ID */
|
||||
#define OPCODE_RDCR 0x35 /* Read configuration register */
|
||||
|
||||
/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
|
||||
#define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */
|
||||
#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */
|
||||
#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */
|
||||
#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */
|
||||
#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */
|
||||
|
||||
@ -76,6 +79,11 @@
|
||||
#define SR_BP2 0x10 /* Block protect 2 */
|
||||
#define SR_SRWD 0x80 /* SR write protect */
|
||||
|
||||
#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */
|
||||
|
||||
/* Configuration Register bits. */
|
||||
#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */
|
||||
|
||||
/* Define max times to check status register before we give up. */
|
||||
#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
|
||||
#define MAX_CMD_SIZE 6
|
||||
@ -84,6 +92,12 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
enum read_type {
|
||||
M25P80_NORMAL = 0,
|
||||
M25P80_FAST,
|
||||
M25P80_QUAD,
|
||||
};
|
||||
|
||||
struct m25p {
|
||||
struct spi_device *spi;
|
||||
struct mutex lock;
|
||||
@ -94,7 +108,7 @@ struct m25p {
|
||||
u8 read_opcode;
|
||||
u8 program_opcode;
|
||||
u8 *command;
|
||||
bool fast_read;
|
||||
enum read_type flash_read;
|
||||
};
|
||||
|
||||
static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
|
||||
@ -130,6 +144,26 @@ static int read_sr(struct m25p *flash)
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read configuration register, returning its value in the
|
||||
* location. Return the configuration register value.
|
||||
* Returns negative if error occured.
|
||||
*/
|
||||
static int read_cr(struct m25p *flash)
|
||||
{
|
||||
u8 code = OPCODE_RDCR;
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
ret = spi_write_then_read(flash->spi, &code, 1, &val, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&flash->spi->dev, "error %d reading CR\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write status register 1 byte
|
||||
* Returns negative if error occurred.
|
||||
@ -219,6 +253,93 @@ static int wait_till_ready(struct m25p *flash)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write status Register and configuration register with 2 bytes
|
||||
* The first byte will be written to the status register, while the
|
||||
* second byte will be written to the configuration register.
|
||||
* Return negative if error occured.
|
||||
*/
|
||||
static int write_sr_cr(struct m25p *flash, u16 val)
|
||||
{
|
||||
flash->command[0] = OPCODE_WRSR;
|
||||
flash->command[1] = val & 0xff;
|
||||
flash->command[2] = (val >> 8);
|
||||
|
||||
return spi_write(flash->spi, flash->command, 3);
|
||||
}
|
||||
|
||||
static int macronix_quad_enable(struct m25p *flash)
|
||||
{
|
||||
int ret, val;
|
||||
u8 cmd[2];
|
||||
cmd[0] = OPCODE_WRSR;
|
||||
|
||||
val = read_sr(flash);
|
||||
cmd[1] = val | SR_QUAD_EN_MX;
|
||||
write_enable(flash);
|
||||
|
||||
spi_write(flash->spi, &cmd, 2);
|
||||
|
||||
if (wait_till_ready(flash))
|
||||
return 1;
|
||||
|
||||
ret = read_sr(flash);
|
||||
if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
|
||||
dev_err(&flash->spi->dev, "Macronix Quad bit not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spansion_quad_enable(struct m25p *flash)
|
||||
{
|
||||
int ret;
|
||||
int quad_en = CR_QUAD_EN_SPAN << 8;
|
||||
|
||||
write_enable(flash);
|
||||
|
||||
ret = write_sr_cr(flash, quad_en);
|
||||
if (ret < 0) {
|
||||
dev_err(&flash->spi->dev,
|
||||
"error while writing configuration register\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* read back and check it */
|
||||
ret = read_cr(flash);
|
||||
if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
|
||||
dev_err(&flash->spi->dev, "Spansion Quad bit not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_quad_mode(struct m25p *flash, u32 jedec_id)
|
||||
{
|
||||
int status;
|
||||
|
||||
switch (JEDEC_MFR(jedec_id)) {
|
||||
case CFI_MFR_MACRONIX:
|
||||
status = macronix_quad_enable(flash);
|
||||
if (status) {
|
||||
dev_err(&flash->spi->dev,
|
||||
"Macronix quad-read not enabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return status;
|
||||
default:
|
||||
status = spansion_quad_enable(flash);
|
||||
if (status) {
|
||||
dev_err(&flash->spi->dev,
|
||||
"Spansion quad-read not enabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Erase the whole flash memory
|
||||
*
|
||||
@ -349,6 +470,35 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy Cycle calculation for different type of read.
|
||||
* It can be used to support more commands with
|
||||
* different dummy cycle requirements.
|
||||
*/
|
||||
static inline int m25p80_dummy_cycles_read(struct m25p *flash)
|
||||
{
|
||||
switch (flash->flash_read) {
|
||||
case M25P80_FAST:
|
||||
case M25P80_QUAD:
|
||||
return 1;
|
||||
case M25P80_NORMAL:
|
||||
return 0;
|
||||
default:
|
||||
dev_err(&flash->spi->dev, "No valid read type supported\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int m25p80_rx_nbits(const struct m25p *flash)
|
||||
{
|
||||
switch (flash->flash_read) {
|
||||
case M25P80_QUAD:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an address range from the flash chip. The address range
|
||||
* may be any size provided it is within the physical boundaries.
|
||||
@ -360,6 +510,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
struct spi_transfer t[2];
|
||||
struct spi_message m;
|
||||
uint8_t opcode;
|
||||
int dummy;
|
||||
|
||||
pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
|
||||
__func__, (u32)from, len);
|
||||
@ -367,11 +518,18 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
spi_message_init(&m);
|
||||
memset(t, 0, (sizeof t));
|
||||
|
||||
dummy = m25p80_dummy_cycles_read(flash);
|
||||
if (dummy < 0) {
|
||||
dev_err(&flash->spi->dev, "No valid read command supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
t[0].tx_buf = flash->command;
|
||||
t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0);
|
||||
t[0].len = m25p_cmdsz(flash) + dummy;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
|
||||
t[1].rx_buf = buf;
|
||||
t[1].rx_nbits = m25p80_rx_nbits(flash);
|
||||
t[1].len = len;
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
|
||||
@ -391,8 +549,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
|
||||
spi_sync(flash->spi, &m);
|
||||
|
||||
*retlen = m.actual_length - m25p_cmdsz(flash) -
|
||||
(flash->fast_read ? 1 : 0);
|
||||
*retlen = m.actual_length - m25p_cmdsz(flash) - dummy;
|
||||
|
||||
mutex_unlock(&flash->lock);
|
||||
|
||||
@ -698,6 +855,7 @@ struct flash_info {
|
||||
#define SST_WRITE 0x04 /* use SST byte programming */
|
||||
#define M25P_NO_FR 0x08 /* Can't do fastread */
|
||||
#define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */
|
||||
#define M25P80_QUAD_READ 0x20 /* Flash supports Quad Read */
|
||||
};
|
||||
|
||||
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
|
||||
@ -775,7 +933,7 @@ static const struct spi_device_id m25p_ids[] = {
|
||||
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
|
||||
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
|
||||
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
|
||||
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 0) },
|
||||
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) },
|
||||
|
||||
/* Micron */
|
||||
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
|
||||
@ -795,8 +953,8 @@ static const struct spi_device_id m25p_ids[] = {
|
||||
{ "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) },
|
||||
{ "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) },
|
||||
{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
|
||||
{ "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, 0) },
|
||||
{ "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) },
|
||||
{ "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, M25P80_QUAD_READ) },
|
||||
{ "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_QUAD_READ) },
|
||||
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
|
||||
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
|
||||
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
|
||||
@ -851,6 +1009,7 @@ static const struct spi_device_id m25p_ids[] = {
|
||||
{ "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) },
|
||||
{ "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) },
|
||||
|
||||
{ "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) },
|
||||
{ "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) },
|
||||
@ -937,6 +1096,7 @@ static int m25p_probe(struct spi_device *spi)
|
||||
unsigned i;
|
||||
struct mtd_part_parser_data ppdata;
|
||||
struct device_node *np = spi->dev.of_node;
|
||||
int ret;
|
||||
|
||||
/* Platform data helps sort out which chip type we have, as
|
||||
* well as how this board partitions it. If we don't have
|
||||
@ -1051,22 +1211,46 @@ static int m25p_probe(struct spi_device *spi)
|
||||
flash->page_size = info->page_size;
|
||||
flash->mtd.writebufsize = flash->page_size;
|
||||
|
||||
if (np)
|
||||
if (np) {
|
||||
/* If we were instantiated by DT, use it */
|
||||
flash->fast_read = of_property_read_bool(np, "m25p,fast-read");
|
||||
else
|
||||
if (of_property_read_bool(np, "m25p,fast-read"))
|
||||
flash->flash_read = M25P80_FAST;
|
||||
else
|
||||
flash->flash_read = M25P80_NORMAL;
|
||||
} else {
|
||||
/* If we weren't instantiated by DT, default to fast-read */
|
||||
flash->fast_read = true;
|
||||
flash->flash_read = M25P80_FAST;
|
||||
}
|
||||
|
||||
/* Some devices cannot do fast-read, no matter what DT tells us */
|
||||
if (info->flags & M25P_NO_FR)
|
||||
flash->fast_read = false;
|
||||
flash->flash_read = M25P80_NORMAL;
|
||||
|
||||
/* Quad-read mode takes precedence over fast/normal */
|
||||
if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) {
|
||||
ret = set_quad_mode(flash, info->jedec_id);
|
||||
if (ret) {
|
||||
dev_err(&flash->spi->dev, "quad mode not supported\n");
|
||||
return ret;
|
||||
}
|
||||
flash->flash_read = M25P80_QUAD;
|
||||
}
|
||||
|
||||
/* Default commands */
|
||||
if (flash->fast_read)
|
||||
switch (flash->flash_read) {
|
||||
case M25P80_QUAD:
|
||||
flash->read_opcode = OPCODE_QUAD_READ;
|
||||
break;
|
||||
case M25P80_FAST:
|
||||
flash->read_opcode = OPCODE_FAST_READ;
|
||||
else
|
||||
break;
|
||||
case M25P80_NORMAL:
|
||||
flash->read_opcode = OPCODE_NORM_READ;
|
||||
break;
|
||||
default:
|
||||
dev_err(&flash->spi->dev, "No Read opcode defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flash->program_opcode = OPCODE_PP;
|
||||
|
||||
@ -1077,9 +1261,17 @@ static int m25p_probe(struct spi_device *spi)
|
||||
flash->addr_width = 4;
|
||||
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
|
||||
/* Dedicated 4-byte command set */
|
||||
flash->read_opcode = flash->fast_read ?
|
||||
OPCODE_FAST_READ_4B :
|
||||
OPCODE_NORM_READ_4B;
|
||||
switch (flash->flash_read) {
|
||||
case M25P80_QUAD:
|
||||
flash->read_opcode = OPCODE_QUAD_READ_4B;
|
||||
break;
|
||||
case M25P80_FAST:
|
||||
flash->read_opcode = OPCODE_FAST_READ_4B;
|
||||
break;
|
||||
case M25P80_NORMAL:
|
||||
flash->read_opcode = OPCODE_NORM_READ_4B;
|
||||
break;
|
||||
}
|
||||
flash->program_opcode = OPCODE_PP_4B;
|
||||
/* No small sector erase for 4-byte command set */
|
||||
flash->erase_opcode = OPCODE_SE_4B;
|
||||
|
@ -205,7 +205,7 @@ static int __init ms02nv_init_one(ulong addr)
|
||||
mtd->type = MTD_RAM;
|
||||
mtd->flags = MTD_CAP_RAM;
|
||||
mtd->size = fixsize;
|
||||
mtd->name = (char *)ms02nv_name;
|
||||
mtd->name = ms02nv_name;
|
||||
mtd->owner = THIS_MODULE;
|
||||
mtd->_read = ms02nv_read;
|
||||
mtd->_write = ms02nv_write;
|
||||
|
@ -669,7 +669,6 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
spi_set_drvdata(spi, NULL);
|
||||
kfree(priv);
|
||||
return err;
|
||||
}
|
||||
@ -899,10 +898,8 @@ static int dataflash_remove(struct spi_device *spi)
|
||||
pr_debug("%s: remove\n", dev_name(&spi->dev));
|
||||
|
||||
status = mtd_device_unregister(&flash->mtd);
|
||||
if (status == 0) {
|
||||
spi_set_drvdata(spi, NULL);
|
||||
if (status == 0)
|
||||
kfree(flash);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ static void __exit cleanup_mtdram(void)
|
||||
}
|
||||
|
||||
int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
|
||||
unsigned long size, char *name)
|
||||
unsigned long size, const char *name)
|
||||
{
|
||||
memset(mtd, 0, sizeof(*mtd));
|
||||
|
||||
|
@ -388,7 +388,7 @@ static void put_chip(struct map_info *map, struct flchip *chip)
|
||||
wake_up(&chip->wq);
|
||||
}
|
||||
|
||||
int do_write_buffer(struct map_info *map, struct flchip *chip,
|
||||
static int do_write_buffer(struct map_info *map, struct flchip *chip,
|
||||
unsigned long adr, const struct kvec **pvec,
|
||||
unsigned long *pvec_seek, int len)
|
||||
{
|
||||
@ -469,7 +469,7 @@ int do_write_buffer(struct map_info *map, struct flchip *chip,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
|
||||
static int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
|
||||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
struct lpddr_private *lpddr = map->fldrv_priv;
|
||||
@ -748,34 +748,6 @@ static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK);
|
||||
}
|
||||
|
||||
int word_program(struct map_info *map, loff_t adr, uint32_t curval)
|
||||
{
|
||||
int ret;
|
||||
struct lpddr_private *lpddr = map->fldrv_priv;
|
||||
int chipnum = adr >> lpddr->chipshift;
|
||||
struct flchip *chip = &lpddr->chips[chipnum];
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
ret = get_chip(map, chip, FL_WRITING);
|
||||
if (ret) {
|
||||
mutex_unlock(&chip->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval);
|
||||
|
||||
ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->SingleWordProgTime));
|
||||
if (ret) {
|
||||
printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n",
|
||||
map->name, adr, curval);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out: put_chip(map, chip);
|
||||
mutex_unlock(&chip->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>");
|
||||
MODULE_DESCRIPTION("MTD driver for LPDDR flash chips");
|
||||
|
@ -13,6 +13,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
@ -162,13 +163,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev)
|
||||
mtd_device_unregister(info->mtd);
|
||||
map_destroy(info->mtd);
|
||||
}
|
||||
if (info->map.virt)
|
||||
iounmap(info->map.virt);
|
||||
|
||||
if (info->res) {
|
||||
release_resource(info->res);
|
||||
kfree(info->res);
|
||||
}
|
||||
|
||||
if (plat->exit)
|
||||
plat->exit();
|
||||
@ -194,7 +188,8 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
info = kzalloc(sizeof(struct ixp4xx_flash_info), GFP_KERNEL);
|
||||
info = devm_kzalloc(&dev->dev, sizeof(struct ixp4xx_flash_info),
|
||||
GFP_KERNEL);
|
||||
if(!info) {
|
||||
err = -ENOMEM;
|
||||
goto Error;
|
||||
@ -220,20 +215,9 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
|
||||
info->map.write = ixp4xx_probe_write16;
|
||||
info->map.copy_from = ixp4xx_copy_from;
|
||||
|
||||
info->res = request_mem_region(dev->resource->start,
|
||||
resource_size(dev->resource),
|
||||
"IXP4XXFlash");
|
||||
if (!info->res) {
|
||||
printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n");
|
||||
err = -ENOMEM;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
info->map.virt = ioremap(dev->resource->start,
|
||||
resource_size(dev->resource));
|
||||
if (!info->map.virt) {
|
||||
printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n");
|
||||
err = -EIO;
|
||||
info->map.virt = devm_ioremap_resource(&dev->dev, dev->resource);
|
||||
if (IS_ERR(info->map.virt)) {
|
||||
err = PTR_ERR(info->map.virt);
|
||||
goto Error;
|
||||
}
|
||||
|
||||
|
@ -123,24 +123,28 @@ ltq_mtd_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL);
|
||||
ltq_mtd = devm_kzalloc(&pdev->dev, sizeof(struct ltq_mtd), GFP_KERNEL);
|
||||
if (!ltq_mtd)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ltq_mtd);
|
||||
|
||||
ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!ltq_mtd->res) {
|
||||
dev_err(&pdev->dev, "failed to get memory resource\n");
|
||||
err = -ENOENT;
|
||||
goto err_out;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL);
|
||||
ltq_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info),
|
||||
GFP_KERNEL);
|
||||
if (!ltq_mtd->map)
|
||||
return -ENOMEM;
|
||||
|
||||
ltq_mtd->map->phys = ltq_mtd->res->start;
|
||||
ltq_mtd->map->size = resource_size(ltq_mtd->res);
|
||||
ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res);
|
||||
if (IS_ERR(ltq_mtd->map->virt)) {
|
||||
err = PTR_ERR(ltq_mtd->map->virt);
|
||||
goto err_out;
|
||||
}
|
||||
if (IS_ERR(ltq_mtd->map->virt))
|
||||
return PTR_ERR(ltq_mtd->map->virt);
|
||||
|
||||
ltq_mtd->map->name = ltq_map_name;
|
||||
ltq_mtd->map->bankwidth = 2;
|
||||
@ -155,8 +159,7 @@ ltq_mtd_probe(struct platform_device *pdev)
|
||||
|
||||
if (!ltq_mtd->mtd) {
|
||||
dev_err(&pdev->dev, "probing failed\n");
|
||||
err = -ENXIO;
|
||||
goto err_free;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ltq_mtd->mtd->owner = THIS_MODULE;
|
||||
@ -177,10 +180,6 @@ ltq_mtd_probe(struct platform_device *pdev)
|
||||
|
||||
err_destroy:
|
||||
map_destroy(ltq_mtd->mtd);
|
||||
err_free:
|
||||
kfree(ltq_mtd->map);
|
||||
err_out:
|
||||
kfree(ltq_mtd);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -189,13 +188,9 @@ ltq_mtd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
|
||||
|
||||
if (ltq_mtd) {
|
||||
if (ltq_mtd->mtd) {
|
||||
mtd_device_unregister(ltq_mtd->mtd);
|
||||
map_destroy(ltq_mtd->mtd);
|
||||
}
|
||||
kfree(ltq_mtd->map);
|
||||
kfree(ltq_mtd);
|
||||
if (ltq_mtd && ltq_mtd->mtd) {
|
||||
mtd_device_unregister(ltq_mtd->mtd);
|
||||
map_destroy(ltq_mtd->mtd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev)
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->map.name = (char *) flash->name;
|
||||
info->map.name = flash->name;
|
||||
info->map.bankwidth = flash->width;
|
||||
info->map.phys = res->start;
|
||||
info->map.size = resource_size(res);
|
||||
|
@ -75,7 +75,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp)
|
||||
|
||||
up->name = of_get_property(dp, "model", NULL);
|
||||
if (up->name && 0 < strlen(up->name))
|
||||
up->map.name = (char *)up->name;
|
||||
up->map.name = up->name;
|
||||
|
||||
up->map.phys = op->resource[0].start;
|
||||
|
||||
|
@ -313,15 +313,7 @@ static struct attribute *mtd_attrs[] = {
|
||||
&dev_attr_bitflip_threshold.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group mtd_group = {
|
||||
.attrs = mtd_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *mtd_groups[] = {
|
||||
&mtd_group,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(mtd);
|
||||
|
||||
static struct device_type mtd_devtype = {
|
||||
.name = "mtd",
|
||||
|
@ -534,7 +534,7 @@ out_register:
|
||||
return slave;
|
||||
}
|
||||
|
||||
int mtd_add_partition(struct mtd_info *master, char *name,
|
||||
int mtd_add_partition(struct mtd_info *master, const char *name,
|
||||
long long offset, long long length)
|
||||
{
|
||||
struct mtd_partition part;
|
||||
@ -672,22 +672,19 @@ static struct mtd_part_parser *get_partition_parser(const char *name)
|
||||
|
||||
#define put_partition_parser(p) do { module_put((p)->owner); } while (0)
|
||||
|
||||
int register_mtd_parser(struct mtd_part_parser *p)
|
||||
void register_mtd_parser(struct mtd_part_parser *p)
|
||||
{
|
||||
spin_lock(&part_parser_lock);
|
||||
list_add(&p->list, &part_parsers);
|
||||
spin_unlock(&part_parser_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_mtd_parser);
|
||||
|
||||
int deregister_mtd_parser(struct mtd_part_parser *p)
|
||||
void deregister_mtd_parser(struct mtd_part_parser *p)
|
||||
{
|
||||
spin_lock(&part_parser_lock);
|
||||
list_del(&p->list);
|
||||
spin_unlock(&part_parser_lock);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(deregister_mtd_parser);
|
||||
|
||||
|
@ -95,7 +95,7 @@ config MTD_NAND_OMAP2
|
||||
platforms.
|
||||
|
||||
config MTD_NAND_OMAP_BCH
|
||||
depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3
|
||||
depends on MTD_NAND_OMAP2
|
||||
tristate "Support hardware based BCH error correction"
|
||||
default n
|
||||
select BCH
|
||||
@ -326,11 +326,11 @@ config MTD_NAND_ATMEL
|
||||
on Atmel AT91 and AVR32 processors.
|
||||
|
||||
config MTD_NAND_PXA3xx
|
||||
tristate "Support for NAND flash devices on PXA3xx"
|
||||
tristate "NAND support on PXA3xx and Armada 370/XP"
|
||||
depends on PXA3xx || ARCH_MMP || PLAT_ORION
|
||||
help
|
||||
This enables the driver for the NAND flash device found on
|
||||
PXA3xx processors
|
||||
PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
|
||||
|
||||
config MTD_NAND_SLC_LPC32XX
|
||||
tristate "NXP LPC32xx SLC Controller"
|
||||
@ -458,17 +458,17 @@ config MTD_NAND_MXC
|
||||
|
||||
config MTD_NAND_SH_FLCTL
|
||||
tristate "Support for NAND on Renesas SuperH FLCTL"
|
||||
depends on SUPERH || ARCH_SHMOBILE
|
||||
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
|
||||
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 SoC"
|
||||
depends on ARCH_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 processors.
|
||||
DaVinci/Keystone processors.
|
||||
|
||||
config MTD_NAND_TXX9NDFMC
|
||||
tristate "NAND Flash support for TXx9 SoC"
|
||||
|
@ -1961,10 +1961,8 @@ static int atmel_nand_probe(struct platform_device *pdev)
|
||||
|
||||
/* Allocate memory for the device structure (and zero it) */
|
||||
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
|
||||
if (!host) {
|
||||
printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = platform_driver_register(&atmel_nand_nfc_driver);
|
||||
if (res)
|
||||
@ -2062,14 +2060,14 @@ static int atmel_nand_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
if (gpio_get_value(host->board.det_pin)) {
|
||||
printk(KERN_INFO "No SmartMedia card inserted.\n");
|
||||
dev_info(&pdev->dev, "No SmartMedia card inserted.\n");
|
||||
res = -ENXIO;
|
||||
goto err_no_card;
|
||||
}
|
||||
}
|
||||
|
||||
if (host->board.on_flash_bbt || on_flash_bbt) {
|
||||
printk(KERN_INFO "atmel_nand: Use On Flash BBT\n");
|
||||
dev_info(&pdev->dev, "Use On Flash BBT\n");
|
||||
nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
|
||||
}
|
||||
|
||||
|
@ -418,10 +418,8 @@ static int au1550nd_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx) {
|
||||
dev_err(&pdev->dev, "no memory for NAND context\n");
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
@ -480,6 +478,8 @@ static int au1550nd_probe(struct platform_device *pdev)
|
||||
|
||||
mtd_device_register(&ctx->info, pd->parts, pd->num_parts);
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
return 0;
|
||||
|
||||
out3:
|
||||
|
@ -745,7 +745,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (info == NULL) {
|
||||
dev_err(&pdev->dev, "no memory for flash info\n");
|
||||
err = -ENOMEM;
|
||||
goto out_err_kzalloc;
|
||||
}
|
||||
|
@ -640,10 +640,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
|
||||
pci_set_master(pdev);
|
||||
|
||||
mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL);
|
||||
if (!mtd) {
|
||||
dev_warn(&pdev->dev, "failed to alloc mtd_info\n");
|
||||
if (!mtd)
|
||||
return -ENOMEM;
|
||||
}
|
||||
cafe = (void *)(&mtd[1]);
|
||||
|
||||
mtd->dev.parent = &pdev->dev;
|
||||
|
@ -164,7 +164,6 @@ static int __init cmx270_init(void)
|
||||
sizeof(struct nand_chip),
|
||||
GFP_KERNEL);
|
||||
if (!cmx270_nand_mtd) {
|
||||
pr_debug("Unable to allocate CM-X270 NAND MTD device structure.\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_kzalloc;
|
||||
}
|
||||
|
@ -199,7 +199,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
|
||||
/* Allocate memory for MTD device structure and private data */
|
||||
new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
|
||||
if (!new_mtd) {
|
||||
printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n");
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_mtd.h>
|
||||
|
||||
#include <linux/platform_data/mtd-davinci.h>
|
||||
#include <linux/platform_data/mtd-davinci-aemif.h>
|
||||
@ -487,7 +488,7 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
|
||||
* ten ECC bytes plus the manufacturer's bad block marker byte, and
|
||||
* and not overlapping the default BBT markers.
|
||||
*/
|
||||
static struct nand_ecclayout hwecc4_small __initconst = {
|
||||
static struct nand_ecclayout hwecc4_small = {
|
||||
.eccbytes = 10,
|
||||
.eccpos = { 0, 1, 2, 3, 4,
|
||||
/* offset 5 holds the badblock marker */
|
||||
@ -503,7 +504,7 @@ static struct nand_ecclayout hwecc4_small __initconst = {
|
||||
* storing ten ECC bytes plus the manufacturer's bad block marker byte,
|
||||
* and not overlapping the default BBT markers.
|
||||
*/
|
||||
static struct nand_ecclayout hwecc4_2048 __initconst = {
|
||||
static struct nand_ecclayout hwecc4_2048 = {
|
||||
.eccbytes = 40,
|
||||
.eccpos = {
|
||||
/* at the end of spare sector */
|
||||
@ -534,17 +535,19 @@ static struct davinci_nand_pdata
|
||||
struct davinci_nand_pdata *pdata;
|
||||
const char *mode;
|
||||
u32 prop;
|
||||
int len;
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct davinci_nand_pdata),
|
||||
GFP_KERNEL);
|
||||
pdev->dev.platform_data = pdata;
|
||||
if (!pdata)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!of_property_read_u32(pdev->dev.of_node,
|
||||
"ti,davinci-chipselect", &prop))
|
||||
pdev->id = prop;
|
||||
else
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!of_property_read_u32(pdev->dev.of_node,
|
||||
"ti,davinci-mask-ale", &prop))
|
||||
pdata->mask_ale = prop;
|
||||
@ -555,6 +558,8 @@ static struct davinci_nand_pdata
|
||||
"ti,davinci-mask-chipsel", &prop))
|
||||
pdata->mask_chipsel = prop;
|
||||
if (!of_property_read_string(pdev->dev.of_node,
|
||||
"nand-ecc-mode", &mode) ||
|
||||
!of_property_read_string(pdev->dev.of_node,
|
||||
"ti,davinci-ecc-mode", &mode)) {
|
||||
if (!strncmp("none", mode, 4))
|
||||
pdata->ecc_mode = NAND_ECC_NONE;
|
||||
@ -566,12 +571,16 @@ static struct davinci_nand_pdata
|
||||
if (!of_property_read_u32(pdev->dev.of_node,
|
||||
"ti,davinci-ecc-bits", &prop))
|
||||
pdata->ecc_bits = prop;
|
||||
if (!of_property_read_u32(pdev->dev.of_node,
|
||||
|
||||
prop = of_get_nand_bus_width(pdev->dev.of_node);
|
||||
if (0 < prop || !of_property_read_u32(pdev->dev.of_node,
|
||||
"ti,davinci-nand-buswidth", &prop))
|
||||
if (prop == 16)
|
||||
pdata->options |= NAND_BUSWIDTH_16;
|
||||
if (of_find_property(pdev->dev.of_node,
|
||||
"ti,davinci-nand-use-bbt", &len))
|
||||
if (of_property_read_bool(pdev->dev.of_node,
|
||||
"nand-on-flash-bbt") ||
|
||||
of_property_read_bool(pdev->dev.of_node,
|
||||
"ti,davinci-nand-use-bbt"))
|
||||
pdata->bbt_options = NAND_BBT_USE_FLASH;
|
||||
}
|
||||
|
||||
@ -585,7 +594,7 @@ static struct davinci_nand_pdata
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
static int nand_davinci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_nand_pdata *pdata;
|
||||
struct davinci_nand_info *info;
|
||||
@ -598,6 +607,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
nand_ecc_modes_t ecc_mode;
|
||||
|
||||
pdata = nand_davinci_get_pdata(pdev);
|
||||
if (IS_ERR(pdata))
|
||||
return PTR_ERR(pdata);
|
||||
|
||||
/* insist on board-specific configuration */
|
||||
if (!pdata)
|
||||
return -ENODEV;
|
||||
@ -607,11 +619,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
dev_err(&pdev->dev, "unable to allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_nomem;
|
||||
}
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
@ -619,19 +628,23 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res1 || !res2) {
|
||||
dev_err(&pdev->dev, "resource missing\n");
|
||||
ret = -EINVAL;
|
||||
goto err_nomem;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vaddr = devm_ioremap_resource(&pdev->dev, res1);
|
||||
if (IS_ERR(vaddr)) {
|
||||
ret = PTR_ERR(vaddr);
|
||||
goto err_ioremap;
|
||||
}
|
||||
base = devm_ioremap_resource(&pdev->dev, res2);
|
||||
if (IS_ERR(base)) {
|
||||
ret = PTR_ERR(base);
|
||||
goto err_ioremap;
|
||||
if (IS_ERR(vaddr))
|
||||
return PTR_ERR(vaddr);
|
||||
|
||||
/*
|
||||
* This registers range is used to setup NAND settings. In case with
|
||||
* TI AEMIF driver, the same memory address range is requested already
|
||||
* by AEMIF, so we cannot request it twice, just ioremap.
|
||||
* The AEMIF and NAND drivers not use the same registers in this range.
|
||||
*/
|
||||
base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2));
|
||||
if (!base) {
|
||||
dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
info->dev = &pdev->dev;
|
||||
@ -699,7 +712,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
spin_unlock_irq(&davinci_nand_lock);
|
||||
|
||||
if (ret == -EBUSY)
|
||||
goto err_ecc;
|
||||
return ret;
|
||||
|
||||
info->chip.ecc.calculate = nand_davinci_calculate_4bit;
|
||||
info->chip.ecc.correct = nand_davinci_correct_4bit;
|
||||
@ -715,8 +728,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
info->chip.ecc.strength = pdata->ecc_bits;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err_ecc;
|
||||
return -EINVAL;
|
||||
}
|
||||
info->chip.ecc.mode = ecc_mode;
|
||||
|
||||
@ -724,7 +736,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(info->clk)) {
|
||||
ret = PTR_ERR(info->clk);
|
||||
dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
|
||||
goto err_clk;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
@ -753,7 +765,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
info->core_chipsel);
|
||||
if (ret < 0) {
|
||||
dev_dbg(&pdev->dev, "NAND timing values setup fail\n");
|
||||
goto err_timing;
|
||||
goto err;
|
||||
}
|
||||
|
||||
spin_lock_irq(&davinci_nand_lock);
|
||||
@ -769,7 +781,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL);
|
||||
if (ret < 0) {
|
||||
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
|
||||
goto err_scan;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Update ECC layout if needed ... for 1-bit HW ECC, the default
|
||||
@ -783,7 +795,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
if (!chunks || info->mtd.oobsize < 16) {
|
||||
dev_dbg(&pdev->dev, "too small\n");
|
||||
ret = -EINVAL;
|
||||
goto err_scan;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* For small page chips, preserve the manufacturer's
|
||||
@ -814,7 +826,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
||||
dev_warn(&pdev->dev, "no 4-bit ECC support yet "
|
||||
"for 4KiB-page NAND\n");
|
||||
ret = -EIO;
|
||||
goto err_scan;
|
||||
goto err;
|
||||
|
||||
syndrome_done:
|
||||
info->chip.ecc.layout = &info->ecclayout;
|
||||
@ -822,7 +834,7 @@ syndrome_done:
|
||||
|
||||
ret = nand_scan_tail(&info->mtd);
|
||||
if (ret < 0)
|
||||
goto err_scan;
|
||||
goto err;
|
||||
|
||||
if (pdata->parts)
|
||||
ret = mtd_device_parse_register(&info->mtd, NULL, NULL,
|
||||
@ -835,7 +847,7 @@ syndrome_done:
|
||||
NULL, 0);
|
||||
}
|
||||
if (ret < 0)
|
||||
goto err_scan;
|
||||
goto err;
|
||||
|
||||
val = davinci_nand_readl(info, NRCSR_OFFSET);
|
||||
dev_info(&pdev->dev, "controller rev. %d.%d\n",
|
||||
@ -843,8 +855,7 @@ syndrome_done:
|
||||
|
||||
return 0;
|
||||
|
||||
err_scan:
|
||||
err_timing:
|
||||
err:
|
||||
clk_disable_unprepare(info->clk);
|
||||
|
||||
err_clk_enable:
|
||||
@ -852,15 +863,10 @@ err_clk_enable:
|
||||
if (ecc_mode == NAND_ECC_HW_SYNDROME)
|
||||
ecc4_busy = false;
|
||||
spin_unlock_irq(&davinci_nand_lock);
|
||||
|
||||
err_ecc:
|
||||
err_clk:
|
||||
err_ioremap:
|
||||
err_nomem:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit nand_davinci_remove(struct platform_device *pdev)
|
||||
static int nand_davinci_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_nand_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
@ -877,7 +883,8 @@ static int __exit nand_davinci_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static struct platform_driver nand_davinci_driver = {
|
||||
.remove = __exit_p(nand_davinci_remove),
|
||||
.probe = nand_davinci_probe,
|
||||
.remove = nand_davinci_remove,
|
||||
.driver = {
|
||||
.name = "davinci_nand",
|
||||
.owner = THIS_MODULE,
|
||||
@ -886,7 +893,7 @@ static struct platform_driver nand_davinci_driver = {
|
||||
};
|
||||
MODULE_ALIAS("platform:davinci_nand");
|
||||
|
||||
module_platform_driver_probe(nand_davinci_driver, nand_davinci_probe);
|
||||
module_platform_driver(nand_davinci_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Texas Instruments");
|
||||
|
@ -125,7 +125,6 @@ static void reset_buf(struct denali_nand_info *denali)
|
||||
|
||||
static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte)
|
||||
{
|
||||
BUG_ON(denali->buf.tail >= sizeof(denali->buf.buf));
|
||||
denali->buf.buf[denali->buf.tail++] = byte;
|
||||
}
|
||||
|
||||
@ -897,7 +896,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
|
||||
/* this function examines buffers to see if they contain data that
|
||||
* indicate that the buffer is part of an erased region of flash.
|
||||
*/
|
||||
bool is_erased(uint8_t *buf, int len)
|
||||
static bool is_erased(uint8_t *buf, int len)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
@ -1429,20 +1428,12 @@ int denali_init(struct denali_nand_info *denali)
|
||||
}
|
||||
}
|
||||
|
||||
/* Is 32-bit DMA supported? */
|
||||
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
|
||||
if (ret) {
|
||||
pr_err("Spectra: no usable DMA configuration\n");
|
||||
return ret;
|
||||
}
|
||||
denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
|
||||
DENALI_BUF_SIZE,
|
||||
DMA_BIDIRECTIONAL);
|
||||
/* allocate a temporary buffer for nand_scan_ident() */
|
||||
denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE,
|
||||
GFP_DMA | GFP_KERNEL);
|
||||
if (!denali->buf.buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
|
||||
dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
|
||||
return -EIO;
|
||||
}
|
||||
denali->mtd.dev.parent = denali->dev;
|
||||
denali_hw_init(denali);
|
||||
denali_drv_init(denali);
|
||||
@ -1475,12 +1466,29 @@ int denali_init(struct denali_nand_info *denali)
|
||||
goto failed_req_irq;
|
||||
}
|
||||
|
||||
/* MTD supported page sizes vary by kernel. We validate our
|
||||
* kernel supports the device here.
|
||||
*/
|
||||
if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) {
|
||||
ret = -ENODEV;
|
||||
pr_err("Spectra: device size not supported by this version of MTD.");
|
||||
/* allocate the right size buffer now */
|
||||
devm_kfree(denali->dev, denali->buf.buf);
|
||||
denali->buf.buf = devm_kzalloc(denali->dev,
|
||||
denali->mtd.writesize + denali->mtd.oobsize,
|
||||
GFP_KERNEL);
|
||||
if (!denali->buf.buf) {
|
||||
ret = -ENOMEM;
|
||||
goto failed_req_irq;
|
||||
}
|
||||
|
||||
/* Is 32-bit DMA supported? */
|
||||
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
|
||||
if (ret) {
|
||||
pr_err("Spectra: no usable DMA configuration\n");
|
||||
goto failed_req_irq;
|
||||
}
|
||||
|
||||
denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
|
||||
denali->mtd.writesize + denali->mtd.oobsize,
|
||||
DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
|
||||
dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
|
||||
ret = -EIO;
|
||||
goto failed_req_irq;
|
||||
}
|
||||
|
||||
@ -1602,7 +1610,8 @@ EXPORT_SYMBOL(denali_init);
|
||||
void denali_remove(struct denali_nand_info *denali)
|
||||
{
|
||||
denali_irq_cleanup(denali->irq, denali);
|
||||
dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
|
||||
dma_unmap_single(denali->dev, denali->buf.dma_buf,
|
||||
denali->mtd.writesize + denali->mtd.oobsize,
|
||||
DMA_BIDIRECTIONAL);
|
||||
}
|
||||
EXPORT_SYMBOL(denali_remove);
|
||||
|
@ -455,12 +455,10 @@
|
||||
|
||||
#define ECC_SECTOR_SIZE 512
|
||||
|
||||
#define DENALI_BUF_SIZE (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE)
|
||||
|
||||
struct nand_buf {
|
||||
int head;
|
||||
int tail;
|
||||
uint8_t buf[DENALI_BUF_SIZE];
|
||||
uint8_t *buf;
|
||||
dma_addr_t dma_buf;
|
||||
};
|
||||
|
||||
|
@ -108,7 +108,7 @@ static int denali_dt_probe(struct platform_device *ofdev)
|
||||
denali->dev->dma_mask = NULL;
|
||||
}
|
||||
|
||||
dt->clk = clk_get(&ofdev->dev, NULL);
|
||||
dt->clk = devm_clk_get(&ofdev->dev, NULL);
|
||||
if (IS_ERR(dt->clk)) {
|
||||
dev_err(&ofdev->dev, "no clk available\n");
|
||||
return PTR_ERR(dt->clk);
|
||||
@ -124,7 +124,6 @@ static int denali_dt_probe(struct platform_device *ofdev)
|
||||
|
||||
out_disable_clk:
|
||||
clk_disable_unprepare(dt->clk);
|
||||
clk_put(dt->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -135,7 +134,6 @@ static int denali_dt_remove(struct platform_device *ofdev)
|
||||
|
||||
denali_remove(&dt->denali);
|
||||
clk_disable(dt->clk);
|
||||
clk_put(dt->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
#define DENALI_NAND_NAME "denali-nand-pci"
|
||||
|
||||
/* List of platforms this NAND controller has be integrated into */
|
||||
static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = {
|
||||
static const struct pci_device_id denali_pci_ids[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
|
||||
{ PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
|
||||
{ /* end: all zeroes */ }
|
||||
@ -131,7 +131,6 @@ static struct pci_driver denali_pci_driver = {
|
||||
|
||||
static int denali_init_pci(void)
|
||||
{
|
||||
pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__);
|
||||
return pci_register_driver(&denali_pci_driver);
|
||||
}
|
||||
module_init(denali_init_pci);
|
||||
|
@ -1058,7 +1058,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
|
||||
|
||||
buf = kmalloc(mtd->writesize, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
|
||||
return 0;
|
||||
}
|
||||
if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
|
||||
@ -1166,7 +1165,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
|
||||
|
||||
buf = kmalloc(mtd->writesize, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1440,10 +1438,13 @@ static int __init doc_probe(unsigned long physadr)
|
||||
int reg, len, numchips;
|
||||
int ret = 0;
|
||||
|
||||
if (!request_mem_region(physadr, DOC_IOREMAP_LEN, NULL))
|
||||
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);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto error_ioremap;
|
||||
}
|
||||
|
||||
/* It's not possible to cleanly detect the DiskOnChip - the
|
||||
@ -1561,7 +1562,6 @@ static int __init doc_probe(unsigned long physadr)
|
||||
sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));
|
||||
mtd = kzalloc(len, GFP_KERNEL);
|
||||
if (!mtd) {
|
||||
printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@ -1629,6 +1629,10 @@ static int __init doc_probe(unsigned long physadr)
|
||||
WriteDOC(save_control, virtadr, DOCControl);
|
||||
fail:
|
||||
iounmap(virtadr);
|
||||
|
||||
error_ioremap:
|
||||
release_mem_region(physadr, DOC_IOREMAP_LEN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1645,6 +1649,7 @@ static void release_nanddoc(void)
|
||||
nextmtd = doc->nextdoc;
|
||||
nand_release(mtd);
|
||||
iounmap(doc->virtadr);
|
||||
release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
|
||||
kfree(mtd);
|
||||
}
|
||||
}
|
||||
|
@ -847,7 +847,6 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
|
||||
if (!fsl_lbc_ctrl_dev->nand) {
|
||||
elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
|
||||
if (!elbc_fcm_ctrl) {
|
||||
dev_err(dev, "failed to allocate memory\n");
|
||||
mutex_unlock(&fsl_elbc_nand_mutex);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
@ -875,7 +874,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start);
|
||||
priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
|
||||
if (!priv->mtd.name) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
|
@ -1060,7 +1060,6 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
|
||||
if (!fsl_ifc_ctrl_dev->nand) {
|
||||
ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
|
||||
if (!ifc_nand_ctrl) {
|
||||
dev_err(&dev->dev, "failed to allocate memory\n");
|
||||
mutex_unlock(&fsl_ifc_nand_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -1101,7 +1100,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
|
||||
IFC_NAND_EVTER_INTR_FTOERIR_EN |
|
||||
IFC_NAND_EVTER_INTR_WPERIR_EN,
|
||||
&ifc->ifc_nand.nand_evter_intr_en);
|
||||
priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start);
|
||||
priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
|
||||
if (!priv->mtd.name) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
|
@ -889,10 +889,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
|
||||
|
||||
pdata->nand_timings = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*pdata->nand_timings), GFP_KERNEL);
|
||||
if (!pdata->nand_timings) {
|
||||
dev_err(&pdev->dev, "no memory for nand_timing\n");
|
||||
if (!pdata->nand_timings)
|
||||
return -ENOMEM;
|
||||
}
|
||||
of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
|
||||
sizeof(*pdata->nand_timings));
|
||||
|
||||
@ -950,10 +948,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
|
||||
|
||||
/* Allocate memory for the device structure (and zero it) */
|
||||
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
|
||||
if (!host) {
|
||||
dev_err(&pdev->dev, "failed to allocate device structure\n");
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
|
||||
host->data_va = devm_ioremap_resource(&pdev->dev, res);
|
||||
@ -1108,8 +1104,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
|
||||
host->ecc_place = &fsmc_ecc4_lp_place;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "No oob scheme defined for "
|
||||
"oobsize %d\n", mtd->oobsize);
|
||||
dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
|
||||
mtd->oobsize);
|
||||
BUG();
|
||||
}
|
||||
} else {
|
||||
@ -1124,8 +1120,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
|
||||
nand->ecc.layout = &fsmc_ecc1_128_layout;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "No oob scheme defined for "
|
||||
"oobsize %d\n", mtd->oobsize);
|
||||
dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
|
||||
mtd->oobsize);
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
@ -132,13 +132,17 @@ static int gpio_nand_get_config_of(const struct device *dev,
|
||||
|
||||
static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
|
||||
struct resource *r;
|
||||
u64 addr;
|
||||
|
||||
if (!r || of_property_read_u64(pdev->dev.of_node,
|
||||
if (of_property_read_u64(pdev->dev.of_node,
|
||||
"gpio-control-nand,io-sync-reg", &addr))
|
||||
return NULL;
|
||||
|
||||
r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
r->start = addr;
|
||||
r->end = r->start + 0x3;
|
||||
r->flags = IORESOURCE_MEM;
|
||||
@ -211,10 +215,8 @@ static int gpio_nand_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
|
||||
gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
|
||||
if (!gpiomtd) {
|
||||
dev_err(&pdev->dev, "failed to create NAND MTD\n");
|
||||
if (!gpiomtd)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chip = &gpiomtd->nand_chip;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "gpmi-nand.h"
|
||||
#include "gpmi-regs.h"
|
||||
@ -207,30 +208,41 @@ void gpmi_dump_info(struct gpmi_nand_data *this)
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
pr_err("Show GPMI registers :\n");
|
||||
dev_err(this->dev, "Show GPMI registers :\n");
|
||||
for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
|
||||
reg = readl(r->gpmi_regs + i * 0x10);
|
||||
pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
|
||||
dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
|
||||
}
|
||||
|
||||
/* start to print out the BCH info */
|
||||
pr_err("Show BCH registers :\n");
|
||||
dev_err(this->dev, "Show BCH registers :\n");
|
||||
for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
|
||||
reg = readl(r->bch_regs + i * 0x10);
|
||||
pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
|
||||
dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
|
||||
}
|
||||
pr_err("BCH Geometry :\n");
|
||||
pr_err("GF length : %u\n", geo->gf_len);
|
||||
pr_err("ECC Strength : %u\n", geo->ecc_strength);
|
||||
pr_err("Page Size in Bytes : %u\n", geo->page_size);
|
||||
pr_err("Metadata Size in Bytes : %u\n", geo->metadata_size);
|
||||
pr_err("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size);
|
||||
pr_err("ECC Chunk Count : %u\n", geo->ecc_chunk_count);
|
||||
pr_err("Payload Size in Bytes : %u\n", geo->payload_size);
|
||||
pr_err("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size);
|
||||
pr_err("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset);
|
||||
pr_err("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset);
|
||||
pr_err("Block Mark Bit Offset : %u\n", geo->block_mark_bit_offset);
|
||||
dev_err(this->dev, "BCH Geometry :\n"
|
||||
"GF length : %u\n"
|
||||
"ECC Strength : %u\n"
|
||||
"Page Size in Bytes : %u\n"
|
||||
"Metadata Size in Bytes : %u\n"
|
||||
"ECC Chunk Size in Bytes: %u\n"
|
||||
"ECC Chunk Count : %u\n"
|
||||
"Payload Size in Bytes : %u\n"
|
||||
"Auxiliary Size in Bytes: %u\n"
|
||||
"Auxiliary Status Offset: %u\n"
|
||||
"Block Mark Byte Offset : %u\n"
|
||||
"Block Mark Bit Offset : %u\n",
|
||||
geo->gf_len,
|
||||
geo->ecc_strength,
|
||||
geo->page_size,
|
||||
geo->metadata_size,
|
||||
geo->ecc_chunk_size,
|
||||
geo->ecc_chunk_count,
|
||||
geo->payload_size,
|
||||
geo->auxiliary_size,
|
||||
geo->auxiliary_status_offset,
|
||||
geo->block_mark_byte_offset,
|
||||
geo->block_mark_bit_offset);
|
||||
}
|
||||
|
||||
/* Configures the geometry for BCH. */
|
||||
@ -265,8 +277,8 @@ int bch_set_geometry(struct gpmi_nand_data *this)
|
||||
* chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
|
||||
* On the other hand, the MX28 needs the reset, because one case has been
|
||||
* seen where the BCH produced ECC errors constantly after 10000
|
||||
* consecutive reboots. The latter case has not been seen on the MX23 yet,
|
||||
* still we don't know if it could happen there as well.
|
||||
* consecutive reboots. The latter case has not been seen on the MX23
|
||||
* yet, still we don't know if it could happen there as well.
|
||||
*/
|
||||
ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
|
||||
if (ret)
|
||||
@ -353,7 +365,7 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
|
||||
improved_timing_is_available =
|
||||
(target.tREA_in_ns >= 0) &&
|
||||
(target.tRLOH_in_ns >= 0) &&
|
||||
(target.tRHOH_in_ns >= 0) ;
|
||||
(target.tRHOH_in_ns >= 0);
|
||||
|
||||
/* Inspect the clock. */
|
||||
nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
|
||||
@ -911,10 +923,14 @@ 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 = &this->mtd;
|
||||
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
|
||||
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 commond to NAND */
|
||||
@ -942,11 +958,13 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
|
||||
|
||||
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;
|
||||
}
|
||||
@ -986,7 +1004,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
|
||||
/* Enable the clock. */
|
||||
ret = gpmi_enable_clk(this);
|
||||
if (ret) {
|
||||
pr_err("We failed in enable the clk\n");
|
||||
dev_err(this->dev, "We failed in enable the clk\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
@ -1003,7 +1021,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
|
||||
/* [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) ;
|
||||
BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles);
|
||||
|
||||
writel(reg, gpmi_regs + HW_GPMI_TIMING0);
|
||||
|
||||
@ -1090,7 +1108,7 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
|
||||
mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
|
||||
reg = readl(r->gpmi_regs + HW_GPMI_STAT);
|
||||
} else
|
||||
pr_err("unknow arch.\n");
|
||||
dev_err(this->dev, "unknow arch.\n");
|
||||
return reg & mask;
|
||||
}
|
||||
|
||||
@ -1121,10 +1139,8 @@ int gpmi_send_command(struct gpmi_nand_data *this)
|
||||
desc = dmaengine_prep_slave_sg(channel,
|
||||
(struct scatterlist *)pio,
|
||||
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
|
||||
if (!desc) {
|
||||
pr_err("step 1 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* [2] send out the COMMAND + ADDRESS string stored in @buffer */
|
||||
sgl = &this->cmd_sgl;
|
||||
@ -1134,11 +1150,8 @@ int gpmi_send_command(struct gpmi_nand_data *this)
|
||||
desc = dmaengine_prep_slave_sg(channel,
|
||||
sgl, 1, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
|
||||
if (!desc) {
|
||||
pr_err("step 2 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* [3] submit the DMA */
|
||||
set_dma_type(this, DMA_FOR_COMMAND);
|
||||
@ -1167,20 +1180,17 @@ int gpmi_send_data(struct gpmi_nand_data *this)
|
||||
pio[1] = 0;
|
||||
desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
|
||||
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
|
||||
if (!desc) {
|
||||
pr_err("step 1 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* [2] send DMA request */
|
||||
prepare_data_dma(this, DMA_TO_DEVICE);
|
||||
desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
|
||||
1, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
pr_err("step 2 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* [3] submit the DMA */
|
||||
set_dma_type(this, DMA_FOR_WRITE_DATA);
|
||||
return start_dma_without_bch_irq(this, desc);
|
||||
@ -1204,20 +1214,16 @@ int gpmi_read_data(struct gpmi_nand_data *this)
|
||||
desc = dmaengine_prep_slave_sg(channel,
|
||||
(struct scatterlist *)pio,
|
||||
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
|
||||
if (!desc) {
|
||||
pr_err("step 1 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* [2] : send DMA request */
|
||||
prepare_data_dma(this, DMA_FROM_DEVICE);
|
||||
desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
|
||||
1, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
pr_err("step 2 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* [3] : submit the DMA */
|
||||
set_dma_type(this, DMA_FOR_READ_DATA);
|
||||
@ -1262,10 +1268,9 @@ int gpmi_send_page(struct gpmi_nand_data *this,
|
||||
(struct scatterlist *)pio,
|
||||
ARRAY_SIZE(pio), DMA_TRANS_NONE,
|
||||
DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
pr_err("step 2 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE);
|
||||
return start_dma_with_bch_irq(this, desc);
|
||||
}
|
||||
@ -1297,10 +1302,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
|
||||
desc = dmaengine_prep_slave_sg(channel,
|
||||
(struct scatterlist *)pio, 2,
|
||||
DMA_TRANS_NONE, 0);
|
||||
if (!desc) {
|
||||
pr_err("step 1 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* [2] Enable the BCH block and read. */
|
||||
command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
|
||||
@ -1327,10 +1330,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
|
||||
(struct scatterlist *)pio,
|
||||
ARRAY_SIZE(pio), DMA_TRANS_NONE,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
pr_err("step 2 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* [3] Disable the BCH block */
|
||||
command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
|
||||
@ -1348,10 +1349,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
|
||||
(struct scatterlist *)pio, 3,
|
||||
DMA_TRANS_NONE,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
pr_err("step 3 error\n");
|
||||
return -1;
|
||||
}
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* [4] submit the DMA */
|
||||
set_dma_type(this, DMA_FOR_READ_ECC_PAGE);
|
||||
|
@ -18,9 +18,6 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -352,6 +349,9 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
|
||||
|
||||
int common_nfc_set_geometry(struct gpmi_nand_data *this)
|
||||
{
|
||||
if (of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc")
|
||||
&& set_geometry_by_ecc_info(this))
|
||||
return 0;
|
||||
return legacy_set_geometry(this);
|
||||
}
|
||||
|
||||
@ -367,25 +367,28 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
|
||||
struct scatterlist *sgl = &this->data_sgl;
|
||||
int ret;
|
||||
|
||||
this->direct_dma_map_ok = true;
|
||||
|
||||
/* first try to map the upper buffer directly */
|
||||
sg_init_one(sgl, this->upper_buf, this->upper_len);
|
||||
ret = dma_map_sg(this->dev, sgl, 1, dr);
|
||||
if (ret == 0) {
|
||||
/* We have to use our own DMA buffer. */
|
||||
sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE);
|
||||
|
||||
if (dr == DMA_TO_DEVICE)
|
||||
memcpy(this->data_buffer_dma, this->upper_buf,
|
||||
this->upper_len);
|
||||
|
||||
if (virt_addr_valid(this->upper_buf) &&
|
||||
!object_is_on_stack(this->upper_buf)) {
|
||||
sg_init_one(sgl, this->upper_buf, this->upper_len);
|
||||
ret = dma_map_sg(this->dev, sgl, 1, dr);
|
||||
if (ret == 0)
|
||||
pr_err("DMA mapping failed.\n");
|
||||
goto map_fail;
|
||||
|
||||
this->direct_dma_map_ok = false;
|
||||
this->direct_dma_map_ok = true;
|
||||
return;
|
||||
}
|
||||
|
||||
map_fail:
|
||||
/* We have to use our own DMA buffer. */
|
||||
sg_init_one(sgl, this->data_buffer_dma, this->upper_len);
|
||||
|
||||
if (dr == DMA_TO_DEVICE)
|
||||
memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len);
|
||||
|
||||
dma_map_sg(this->dev, sgl, 1, dr);
|
||||
|
||||
this->direct_dma_map_ok = false;
|
||||
}
|
||||
|
||||
/* This will be called after the DMA operation is finished. */
|
||||
@ -416,7 +419,7 @@ static void dma_irq_callback(void *param)
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("in wrong DMA operation.\n");
|
||||
dev_err(this->dev, "in wrong DMA operation.\n");
|
||||
}
|
||||
|
||||
complete(dma_c);
|
||||
@ -438,7 +441,8 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this,
|
||||
/* Wait for the interrupt from the DMA block. */
|
||||
err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
|
||||
if (!err) {
|
||||
pr_err("DMA timeout, last DMA :%d\n", this->last_dma_type);
|
||||
dev_err(this->dev, "DMA timeout, last DMA :%d\n",
|
||||
this->last_dma_type);
|
||||
gpmi_dump_info(this);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@ -467,7 +471,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this,
|
||||
/* Wait for the interrupt from the BCH block. */
|
||||
err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
|
||||
if (!err) {
|
||||
pr_err("BCH timeout, last DMA :%d\n", this->last_dma_type);
|
||||
dev_err(this->dev, "BCH timeout, last DMA :%d\n",
|
||||
this->last_dma_type);
|
||||
gpmi_dump_info(this);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@ -483,70 +488,38 @@ static int acquire_register_block(struct gpmi_nand_data *this,
|
||||
void __iomem *p;
|
||||
|
||||
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
|
||||
if (!r) {
|
||||
pr_err("Can't get resource for %s\n", res_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
p = ioremap(r->start, resource_size(r));
|
||||
if (!p) {
|
||||
pr_err("Can't remap %s\n", res_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
p = devm_ioremap_resource(&pdev->dev, r);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
|
||||
if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME))
|
||||
res->gpmi_regs = p;
|
||||
else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME))
|
||||
res->bch_regs = p;
|
||||
else
|
||||
pr_err("unknown resource name : %s\n", res_name);
|
||||
dev_err(this->dev, "unknown resource name : %s\n", res_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release_register_block(struct gpmi_nand_data *this)
|
||||
{
|
||||
struct resources *res = &this->resources;
|
||||
if (res->gpmi_regs)
|
||||
iounmap(res->gpmi_regs);
|
||||
if (res->bch_regs)
|
||||
iounmap(res->bch_regs);
|
||||
res->gpmi_regs = NULL;
|
||||
res->bch_regs = NULL;
|
||||
}
|
||||
|
||||
static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
|
||||
{
|
||||
struct platform_device *pdev = this->pdev;
|
||||
struct resources *res = &this->resources;
|
||||
const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME;
|
||||
struct resource *r;
|
||||
int err;
|
||||
|
||||
r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
|
||||
if (!r) {
|
||||
pr_err("Can't get resource for %s\n", res_name);
|
||||
dev_err(this->dev, "Can't get resource for %s\n", res_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = request_irq(r->start, irq_h, 0, res_name, this);
|
||||
if (err) {
|
||||
pr_err("Can't own %s\n", res_name);
|
||||
return err;
|
||||
}
|
||||
err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this);
|
||||
if (err)
|
||||
dev_err(this->dev, "error requesting BCH IRQ\n");
|
||||
|
||||
res->bch_low_interrupt = r->start;
|
||||
res->bch_high_interrupt = r->end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release_bch_irq(struct gpmi_nand_data *this)
|
||||
{
|
||||
struct resources *res = &this->resources;
|
||||
int i = res->bch_low_interrupt;
|
||||
|
||||
for (; i <= res->bch_high_interrupt; i++)
|
||||
free_irq(i, this);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void release_dma_channels(struct gpmi_nand_data *this)
|
||||
@ -567,7 +540,7 @@ static int acquire_dma_channels(struct gpmi_nand_data *this)
|
||||
/* request dma channel */
|
||||
dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx");
|
||||
if (!dma_chan) {
|
||||
pr_err("Failed to request DMA channel.\n");
|
||||
dev_err(this->dev, "Failed to request DMA channel.\n");
|
||||
goto acquire_err;
|
||||
}
|
||||
|
||||
@ -579,21 +552,6 @@ acquire_err:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void gpmi_put_clks(struct gpmi_nand_data *this)
|
||||
{
|
||||
struct resources *r = &this->resources;
|
||||
struct clk *clk;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GPMI_CLK_MAX; i++) {
|
||||
clk = r->clock[i];
|
||||
if (clk) {
|
||||
clk_put(clk);
|
||||
r->clock[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
|
||||
"gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
|
||||
};
|
||||
@ -606,7 +564,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
|
||||
int err, i;
|
||||
|
||||
/* The main clock is stored in the first. */
|
||||
r->clock[0] = clk_get(this->dev, "gpmi_io");
|
||||
r->clock[0] = devm_clk_get(this->dev, "gpmi_io");
|
||||
if (IS_ERR(r->clock[0])) {
|
||||
err = PTR_ERR(r->clock[0]);
|
||||
goto err_clock;
|
||||
@ -622,7 +580,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
|
||||
if (extra_clks[i - 1] == NULL)
|
||||
break;
|
||||
|
||||
clk = clk_get(this->dev, extra_clks[i - 1]);
|
||||
clk = devm_clk_get(this->dev, extra_clks[i - 1]);
|
||||
if (IS_ERR(clk)) {
|
||||
err = PTR_ERR(clk);
|
||||
goto err_clock;
|
||||
@ -644,7 +602,6 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
|
||||
|
||||
err_clock:
|
||||
dev_dbg(this->dev, "failed in finding the clocks.\n");
|
||||
gpmi_put_clks(this);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -666,7 +623,7 @@ static int acquire_resources(struct gpmi_nand_data *this)
|
||||
|
||||
ret = acquire_dma_channels(this);
|
||||
if (ret)
|
||||
goto exit_dma_channels;
|
||||
goto exit_regs;
|
||||
|
||||
ret = gpmi_get_clks(this);
|
||||
if (ret)
|
||||
@ -675,18 +632,12 @@ static int acquire_resources(struct gpmi_nand_data *this)
|
||||
|
||||
exit_clock:
|
||||
release_dma_channels(this);
|
||||
exit_dma_channels:
|
||||
release_bch_irq(this);
|
||||
exit_regs:
|
||||
release_register_block(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void release_resources(struct gpmi_nand_data *this)
|
||||
{
|
||||
gpmi_put_clks(this);
|
||||
release_register_block(this);
|
||||
release_bch_irq(this);
|
||||
release_dma_channels(this);
|
||||
}
|
||||
|
||||
@ -732,8 +683,7 @@ static int read_page_prepare(struct gpmi_nand_data *this,
|
||||
length, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, dest_phys)) {
|
||||
if (alt_size < length) {
|
||||
pr_err("%s, Alternate buffer is too small\n",
|
||||
__func__);
|
||||
dev_err(dev, "Alternate buffer is too small\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
goto map_failed;
|
||||
@ -783,8 +733,7 @@ static int send_page_prepare(struct gpmi_nand_data *this,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(dev, source_phys)) {
|
||||
if (alt_size < length) {
|
||||
pr_err("%s, Alternate buffer is too small\n",
|
||||
__func__);
|
||||
dev_err(dev, "Alternate buffer is too small\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
goto map_failed;
|
||||
@ -837,14 +786,23 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
|
||||
{
|
||||
struct bch_geometry *geo = &this->bch_geometry;
|
||||
struct device *dev = this->dev;
|
||||
struct mtd_info *mtd = &this->mtd;
|
||||
|
||||
/* [1] Allocate a command buffer. PAGE_SIZE is enough. */
|
||||
this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
|
||||
if (this->cmd_buffer == NULL)
|
||||
goto error_alloc;
|
||||
|
||||
/* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */
|
||||
this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
|
||||
/*
|
||||
* [2] Allocate a read/write data buffer.
|
||||
* The gpmi_alloc_dma_buffer can be called twice.
|
||||
* We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
|
||||
* is called before the nand_scan_ident; and we allocate a buffer
|
||||
* of the real NAND page size when the gpmi_alloc_dma_buffer is
|
||||
* called after the nand_scan_ident.
|
||||
*/
|
||||
this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
|
||||
GFP_DMA | GFP_KERNEL);
|
||||
if (this->data_buffer_dma == NULL)
|
||||
goto error_alloc;
|
||||
|
||||
@ -872,7 +830,6 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
|
||||
|
||||
error_alloc:
|
||||
gpmi_free_dma_buffer(this);
|
||||
pr_err("Error allocating DMA buffers!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -904,7 +861,8 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
|
||||
|
||||
ret = gpmi_send_command(this);
|
||||
if (ret)
|
||||
pr_err("Chip: %u, Error %d\n", this->current_chip, ret);
|
||||
dev_err(this->dev, "Chip: %u, Error %d\n",
|
||||
this->current_chip, ret);
|
||||
|
||||
this->command_length = 0;
|
||||
}
|
||||
@ -935,7 +893,7 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct gpmi_nand_data *this = chip->priv;
|
||||
|
||||
pr_debug("len is %d\n", len);
|
||||
dev_dbg(this->dev, "len is %d\n", len);
|
||||
this->upper_buf = buf;
|
||||
this->upper_len = len;
|
||||
|
||||
@ -947,7 +905,7 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct gpmi_nand_data *this = chip->priv;
|
||||
|
||||
pr_debug("len is %d\n", len);
|
||||
dev_dbg(this->dev, "len is %d\n", len);
|
||||
this->upper_buf = (uint8_t *)buf;
|
||||
this->upper_len = len;
|
||||
|
||||
@ -1026,13 +984,13 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
unsigned int max_bitflips = 0;
|
||||
int ret;
|
||||
|
||||
pr_debug("page number is : %d\n", page);
|
||||
dev_dbg(this->dev, "page number is : %d\n", page);
|
||||
ret = read_page_prepare(this, buf, mtd->writesize,
|
||||
this->payload_virt, this->payload_phys,
|
||||
nfc_geo->payload_size,
|
||||
&payload_virt, &payload_phys);
|
||||
if (ret) {
|
||||
pr_err("Inadequate DMA buffer\n");
|
||||
dev_err(this->dev, "Inadequate DMA buffer\n");
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
@ -1046,7 +1004,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
nfc_geo->payload_size,
|
||||
payload_virt, payload_phys);
|
||||
if (ret) {
|
||||
pr_err("Error in ECC-based read: %d\n", ret);
|
||||
dev_err(this->dev, "Error in ECC-based read: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1102,7 +1060,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
dma_addr_t auxiliary_phys;
|
||||
int ret;
|
||||
|
||||
pr_debug("ecc write page.\n");
|
||||
dev_dbg(this->dev, "ecc write page.\n");
|
||||
if (this->swap_block_mark) {
|
||||
/*
|
||||
* If control arrives here, we're doing block mark swapping.
|
||||
@ -1132,7 +1090,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
nfc_geo->payload_size,
|
||||
&payload_virt, &payload_phys);
|
||||
if (ret) {
|
||||
pr_err("Inadequate payload DMA buffer\n");
|
||||
dev_err(this->dev, "Inadequate payload DMA buffer\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1142,7 +1100,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
nfc_geo->auxiliary_size,
|
||||
&auxiliary_virt, &auxiliary_phys);
|
||||
if (ret) {
|
||||
pr_err("Inadequate auxiliary DMA buffer\n");
|
||||
dev_err(this->dev, "Inadequate auxiliary DMA buffer\n");
|
||||
goto exit_auxiliary;
|
||||
}
|
||||
}
|
||||
@ -1150,7 +1108,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
/* Ask the NFC. */
|
||||
ret = gpmi_send_page(this, payload_phys, auxiliary_phys);
|
||||
if (ret)
|
||||
pr_err("Error in ECC-based write: %d\n", ret);
|
||||
dev_err(this->dev, "Error in ECC-based write: %d\n", ret);
|
||||
|
||||
if (!this->swap_block_mark) {
|
||||
send_page_end(this, chip->oob_poi, mtd->oobsize,
|
||||
@ -1240,7 +1198,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
{
|
||||
struct gpmi_nand_data *this = chip->priv;
|
||||
|
||||
pr_debug("page number is %d\n", page);
|
||||
dev_dbg(this->dev, "page number is %d\n", page);
|
||||
/* clear the OOB buffer */
|
||||
memset(chip->oob_poi, ~0, mtd->oobsize);
|
||||
|
||||
@ -1453,7 +1411,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
|
||||
|
||||
/* Write the NCB fingerprint into the page buffer. */
|
||||
memset(buffer, ~0, mtd->writesize);
|
||||
memset(chip->oob_poi, ~0, mtd->oobsize);
|
||||
memcpy(buffer + 12, fingerprint, strlen(fingerprint));
|
||||
|
||||
/* Loop through the first search area, writing NCB fingerprints. */
|
||||
@ -1568,7 +1525,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
|
||||
/* Set up the NFC geometry which is used by BCH. */
|
||||
ret = bch_set_geometry(this);
|
||||
if (ret) {
|
||||
pr_err("Error setting BCH geometry : %d\n", ret);
|
||||
dev_err(this->dev, "Error setting BCH geometry : %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1576,20 +1533,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
|
||||
return gpmi_alloc_dma_buffer(this);
|
||||
}
|
||||
|
||||
static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this)
|
||||
{
|
||||
/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
|
||||
if (GPMI_IS_MX23(this))
|
||||
this->swap_block_mark = false;
|
||||
else
|
||||
this->swap_block_mark = true;
|
||||
|
||||
/* Set up the medium geometry */
|
||||
return gpmi_set_geometry(this);
|
||||
|
||||
}
|
||||
|
||||
static void gpmi_nfc_exit(struct gpmi_nand_data *this)
|
||||
static void gpmi_nand_exit(struct gpmi_nand_data *this)
|
||||
{
|
||||
nand_release(&this->mtd);
|
||||
gpmi_free_dma_buffer(this);
|
||||
@ -1603,8 +1547,11 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
|
||||
struct bch_geometry *bch_geo = &this->bch_geometry;
|
||||
int ret;
|
||||
|
||||
/* Prepare for the BBT scan. */
|
||||
ret = gpmi_pre_bbt_scan(this);
|
||||
/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
|
||||
this->swap_block_mark = !GPMI_IS_MX23(this);
|
||||
|
||||
/* Set up the medium geometry */
|
||||
ret = gpmi_set_geometry(this);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1629,7 +1576,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpmi_nfc_init(struct gpmi_nand_data *this)
|
||||
static int gpmi_nand_init(struct gpmi_nand_data *this)
|
||||
{
|
||||
struct mtd_info *mtd = &this->mtd;
|
||||
struct nand_chip *chip = &this->nand;
|
||||
@ -1693,7 +1640,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
gpmi_nfc_exit(this);
|
||||
gpmi_nand_exit(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1728,15 +1675,13 @@ static int gpmi_nand_probe(struct platform_device *pdev)
|
||||
if (of_id) {
|
||||
pdev->id_entry = of_id->data;
|
||||
} else {
|
||||
pr_err("Failed to find the right device id.\n");
|
||||
dev_err(&pdev->dev, "Failed to find the right device id.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
|
||||
if (!this) {
|
||||
pr_err("Failed to allocate per-device memory\n");
|
||||
if (!this)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, this);
|
||||
this->pdev = pdev;
|
||||
@ -1750,7 +1695,7 @@ static int gpmi_nand_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto exit_nfc_init;
|
||||
|
||||
ret = gpmi_nfc_init(this);
|
||||
ret = gpmi_nand_init(this);
|
||||
if (ret)
|
||||
goto exit_nfc_init;
|
||||
|
||||
@ -1770,7 +1715,7 @@ static int gpmi_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
|
||||
|
||||
gpmi_nfc_exit(this);
|
||||
gpmi_nand_exit(this);
|
||||
release_resources(this);
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,8 +26,6 @@
|
||||
struct resources {
|
||||
void __iomem *gpmi_regs;
|
||||
void __iomem *bch_regs;
|
||||
unsigned int bch_low_interrupt;
|
||||
unsigned int bch_high_interrupt;
|
||||
unsigned int dma_low_channel;
|
||||
unsigned int dma_high_channel;
|
||||
struct clk *clock[GPMI_CLK_MAX];
|
||||
|
@ -416,10 +416,8 @@ static int jz_nand_probe(struct platform_device *pdev)
|
||||
uint8_t nand_maf_id = 0, nand_dev_id = 0;
|
||||
|
||||
nand = kzalloc(sizeof(*nand), GFP_KERNEL);
|
||||
if (!nand) {
|
||||
dev_err(&pdev->dev, "Failed to allocate device structure.\n");
|
||||
if (!nand)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
|
||||
if (ret)
|
||||
|
@ -539,20 +539,6 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint32_t offset, int data_len, const uint8_t *buf,
|
||||
int oob_required, int page, int cached, int raw)
|
||||
{
|
||||
int res;
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
|
||||
res = lpc32xx_write_page_lowlevel(mtd, chip, buf, oob_required);
|
||||
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
||||
lpc32xx_waitfunc(mtd, chip);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
{
|
||||
@ -627,10 +613,8 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
|
||||
if (!ncfg) {
|
||||
dev_err(dev, "could not allocate memory for platform data\n");
|
||||
if (!ncfg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay);
|
||||
of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_delay);
|
||||
@ -666,10 +650,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
|
||||
/* Allocate memory for the device structure (and zero it) */
|
||||
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
|
||||
if (!host) {
|
||||
dev_err(&pdev->dev, "failed to allocate device structure.\n");
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
host->io_base = devm_ioremap_resource(&pdev->dev, rc);
|
||||
@ -732,9 +714,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
nand_chip->ecc.write_oob = lpc32xx_write_oob;
|
||||
nand_chip->ecc.read_oob = lpc32xx_read_oob;
|
||||
nand_chip->ecc.strength = 4;
|
||||
nand_chip->write_page = lpc32xx_write_page;
|
||||
nand_chip->waitfunc = lpc32xx_waitfunc;
|
||||
|
||||
nand_chip->options = NAND_NO_SUBPAGE_WRITE;
|
||||
nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
|
||||
nand_chip->bbt_td = &lpc32xx_nand_bbt;
|
||||
nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror;
|
||||
@ -764,14 +746,12 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
|
||||
host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
|
||||
if (!host->dma_buf) {
|
||||
dev_err(&pdev->dev, "Error allocating dma_buf memory\n");
|
||||
res = -ENOMEM;
|
||||
goto err_exit3;
|
||||
}
|
||||
|
||||
host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
|
||||
if (!host->dummy_buf) {
|
||||
dev_err(&pdev->dev, "Error allocating dummy_buf memory\n");
|
||||
res = -ENOMEM;
|
||||
goto err_exit3;
|
||||
}
|
||||
|
@ -725,10 +725,8 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
|
||||
if (!ncfg) {
|
||||
dev_err(dev, "could not allocate memory for NAND config\n");
|
||||
if (!ncfg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks);
|
||||
of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth);
|
||||
@ -772,10 +770,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
|
||||
/* Allocate memory for the device structure (and zero it) */
|
||||
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
|
||||
if (!host) {
|
||||
dev_err(&pdev->dev, "failed to allocate device structure\n");
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
}
|
||||
host->io_base_dma = rc->start;
|
||||
|
||||
host->io_base = devm_ioremap_resource(&pdev->dev, rc);
|
||||
@ -791,8 +787,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
}
|
||||
if (host->ncfg->wp_gpio == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
if (gpio_is_valid(host->ncfg->wp_gpio) &&
|
||||
gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
|
||||
if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev,
|
||||
host->ncfg->wp_gpio, "NAND WP")) {
|
||||
dev_err(&pdev->dev, "GPIO not available\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -808,7 +804,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
mtd->dev.parent = &pdev->dev;
|
||||
|
||||
/* Get NAND clock */
|
||||
host->clk = clk_get(&pdev->dev, NULL);
|
||||
host->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(host->clk)) {
|
||||
dev_err(&pdev->dev, "Clock failure\n");
|
||||
res = -ENOENT;
|
||||
@ -858,7 +854,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
|
||||
GFP_KERNEL);
|
||||
if (host->data_buf == NULL) {
|
||||
dev_err(&pdev->dev, "Error allocating memory\n");
|
||||
res = -ENOMEM;
|
||||
goto err_exit2;
|
||||
}
|
||||
@ -927,10 +922,8 @@ err_exit3:
|
||||
dma_release_channel(host->dma_chan);
|
||||
err_exit2:
|
||||
clk_disable(host->clk);
|
||||
clk_put(host->clk);
|
||||
err_exit1:
|
||||
lpc32xx_wp_enable(host);
|
||||
gpio_free(host->ncfg->wp_gpio);
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -953,9 +946,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
|
||||
writel(tmp, SLC_CTRL(host->io_base));
|
||||
|
||||
clk_disable(host->clk);
|
||||
clk_put(host->clk);
|
||||
lpc32xx_wp_enable(host);
|
||||
gpio_free(host->ncfg->wp_gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -653,10 +653,8 @@ static int mpc5121_nfc_probe(struct platform_device *op)
|
||||
}
|
||||
|
||||
prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
|
||||
if (!prv) {
|
||||
dev_err(dev, "Memory exhausted!\n");
|
||||
if (!prv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mtd = &prv->mtd;
|
||||
chip = &prv->chip;
|
||||
@ -786,7 +784,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
|
||||
/* Detect NAND chips */
|
||||
if (nand_scan(mtd, be32_to_cpup(chips_no))) {
|
||||
dev_err(dev, "NAND Flash not found !\n");
|
||||
devm_free_irq(dev, prv->irq, mtd);
|
||||
retval = -ENXIO;
|
||||
goto error;
|
||||
}
|
||||
@ -811,7 +808,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
|
||||
|
||||
default:
|
||||
dev_err(dev, "Unsupported NAND flash!\n");
|
||||
devm_free_irq(dev, prv->irq, mtd);
|
||||
retval = -ENXIO;
|
||||
goto error;
|
||||
}
|
||||
@ -822,7 +818,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
|
||||
retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
|
||||
if (retval) {
|
||||
dev_err(dev, "Error adding MTD device!\n");
|
||||
devm_free_irq(dev, prv->irq, mtd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -836,11 +831,8 @@ static int mpc5121_nfc_remove(struct platform_device *op)
|
||||
{
|
||||
struct device *dev = &op->dev;
|
||||
struct mtd_info *mtd = dev_get_drvdata(dev);
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mpc5121_nfc_prv *prv = chip->priv;
|
||||
|
||||
nand_release(mtd);
|
||||
devm_free_irq(dev, prv->irq, mtd);
|
||||
mpc5121_nfc_free(dev, mtd);
|
||||
|
||||
return 0;
|
||||
|
@ -677,7 +677,6 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
|
||||
ecc_stat >>= 4;
|
||||
} while (--no_subpages);
|
||||
|
||||
mtd->ecc_stats.corrected += ret;
|
||||
pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
|
||||
|
||||
return ret;
|
||||
@ -1400,12 +1399,15 @@ static int mxcnd_probe(struct platform_device *pdev)
|
||||
int err = 0;
|
||||
|
||||
/* Allocate memory for MTD device structure and private data */
|
||||
host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) +
|
||||
NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL);
|
||||
host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
|
||||
GFP_KERNEL);
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
|
||||
host->data_buf = (uint8_t *)(host + 1);
|
||||
/* allocate a temporary buffer for the nand_scan_ident() */
|
||||
host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
|
||||
if (!host->data_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
host->dev = &pdev->dev;
|
||||
/* structures must be linked */
|
||||
@ -1512,7 +1514,9 @@ static int mxcnd_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
clk_prepare_enable(host->clk);
|
||||
err = clk_prepare_enable(host->clk);
|
||||
if (err)
|
||||
return err;
|
||||
host->clk_act = 1;
|
||||
|
||||
/*
|
||||
@ -1531,6 +1535,15 @@ static int mxcnd_probe(struct platform_device *pdev)
|
||||
goto escan;
|
||||
}
|
||||
|
||||
/* allocate the right size buffer now */
|
||||
devm_kfree(&pdev->dev, (void *)host->data_buf);
|
||||
host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
|
||||
GFP_KERNEL);
|
||||
if (!host->data_buf) {
|
||||
err = -ENOMEM;
|
||||
goto escan;
|
||||
}
|
||||
|
||||
/* Call preset again, with correct writesize this time */
|
||||
host->devtype_data->preset(mtd);
|
||||
|
||||
@ -1576,6 +1589,8 @@ static int mxcnd_remove(struct platform_device *pdev)
|
||||
struct mxc_nand_host *host = platform_get_drvdata(pdev);
|
||||
|
||||
nand_release(&host->mtd);
|
||||
if (host->clk_act)
|
||||
clk_disable_unprepare(host->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,6 +29,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
@ -201,6 +203,51 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_write_byte - [DEFAULT] write single byte to chip
|
||||
* @mtd: MTD device structure
|
||||
* @byte: value to write
|
||||
*
|
||||
* Default function to write a byte to I/O[7:0]
|
||||
*/
|
||||
static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
|
||||
chip->write_buf(mtd, &byte, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
|
||||
* @mtd: MTD device structure
|
||||
* @byte: value to write
|
||||
*
|
||||
* Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
|
||||
*/
|
||||
static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
uint16_t word = byte;
|
||||
|
||||
/*
|
||||
* It's not entirely clear what should happen to I/O[15:8] when writing
|
||||
* a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
|
||||
*
|
||||
* When the host supports a 16-bit bus width, only data is
|
||||
* transferred at the 16-bit width. All address and command line
|
||||
* transfers shall use only the lower 8-bits of the data bus. During
|
||||
* command transfers, the host may place any value on the upper
|
||||
* 8-bits of the data bus. During address transfers, the host shall
|
||||
* set the upper 8-bits of the data bus to 00h.
|
||||
*
|
||||
* One user of the write_byte callback is nand_onfi_set_features. The
|
||||
* four parameters are specified to be written to I/O[7:0], but this is
|
||||
* neither an address nor a command transfer. Let's assume a 0 on the
|
||||
* upper I/O lines is OK.
|
||||
*/
|
||||
chip->write_buf(mtd, (uint8_t *)&word, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_write_buf - [DEFAULT] write buffer to chip
|
||||
* @mtd: MTD device structure
|
||||
@ -1407,6 +1454,30 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_setup_read_retry - [INTERN] Set the READ RETRY mode
|
||||
* @mtd: MTD device structure
|
||||
* @retry_mode: the retry mode to use
|
||||
*
|
||||
* Some vendors supply a special command to shift the Vt threshold, to be used
|
||||
* when there are too many bitflips in a page (i.e., ECC error). After setting
|
||||
* a new threshold, the host should retry reading the page.
|
||||
*/
|
||||
static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
|
||||
pr_debug("setting READ RETRY mode %d\n", retry_mode);
|
||||
|
||||
if (retry_mode >= chip->read_retries)
|
||||
return -EINVAL;
|
||||
|
||||
if (!chip->setup_read_retry)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return chip->setup_read_retry(mtd, retry_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_do_read_ops - [INTERN] Read data with ECC
|
||||
* @mtd: MTD device structure
|
||||
@ -1420,7 +1491,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
{
|
||||
int chipnr, page, realpage, col, bytes, aligned, oob_required;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct mtd_ecc_stats stats;
|
||||
int ret = 0;
|
||||
uint32_t readlen = ops->len;
|
||||
uint32_t oobreadlen = ops->ooblen;
|
||||
@ -1429,8 +1499,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
|
||||
uint8_t *bufpoi, *oob, *buf;
|
||||
unsigned int max_bitflips = 0;
|
||||
|
||||
stats = mtd->ecc_stats;
|
||||
int retry_mode = 0;
|
||||
bool ecc_fail = false;
|
||||
|
||||
chipnr = (int)(from >> chip->chip_shift);
|
||||
chip->select_chip(mtd, chipnr);
|
||||
@ -1445,6 +1515,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
oob_required = oob ? 1 : 0;
|
||||
|
||||
while (1) {
|
||||
unsigned int ecc_failures = mtd->ecc_stats.failed;
|
||||
|
||||
bytes = min(mtd->writesize - col, readlen);
|
||||
aligned = (bytes == mtd->writesize);
|
||||
|
||||
@ -1452,6 +1524,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
if (realpage != chip->pagebuf || oob) {
|
||||
bufpoi = aligned ? buf : chip->buffers->databuf;
|
||||
|
||||
read_retry:
|
||||
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
||||
|
||||
/*
|
||||
@ -1481,7 +1554,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
/* Transfer not aligned data */
|
||||
if (!aligned) {
|
||||
if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
|
||||
!(mtd->ecc_stats.failed - stats.failed) &&
|
||||
!(mtd->ecc_stats.failed - ecc_failures) &&
|
||||
(ops->mode != MTD_OPS_RAW)) {
|
||||
chip->pagebuf = realpage;
|
||||
chip->pagebuf_bitflips = ret;
|
||||
@ -1492,8 +1565,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
memcpy(buf, chip->buffers->databuf + col, bytes);
|
||||
}
|
||||
|
||||
buf += bytes;
|
||||
|
||||
if (unlikely(oob)) {
|
||||
int toread = min(oobreadlen, max_oobsize);
|
||||
|
||||
@ -1511,6 +1582,25 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
else
|
||||
nand_wait_ready(mtd);
|
||||
}
|
||||
|
||||
if (mtd->ecc_stats.failed - ecc_failures) {
|
||||
if (retry_mode + 1 <= chip->read_retries) {
|
||||
retry_mode++;
|
||||
ret = nand_setup_read_retry(mtd,
|
||||
retry_mode);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
/* Reset failures; retry */
|
||||
mtd->ecc_stats.failed = ecc_failures;
|
||||
goto read_retry;
|
||||
} else {
|
||||
/* No more retry modes; real failure */
|
||||
ecc_fail = true;
|
||||
}
|
||||
}
|
||||
|
||||
buf += bytes;
|
||||
} else {
|
||||
memcpy(buf, chip->buffers->databuf + col, bytes);
|
||||
buf += bytes;
|
||||
@ -1520,6 +1610,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
|
||||
readlen -= bytes;
|
||||
|
||||
/* Reset to retry mode 0 */
|
||||
if (retry_mode) {
|
||||
ret = nand_setup_read_retry(mtd, 0);
|
||||
if (ret < 0)
|
||||
break;
|
||||
retry_mode = 0;
|
||||
}
|
||||
|
||||
if (!readlen)
|
||||
break;
|
||||
|
||||
@ -1545,7 +1643,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (mtd->ecc_stats.failed - stats.failed)
|
||||
if (ecc_fail)
|
||||
return -EBADMSG;
|
||||
|
||||
return max_bitflips;
|
||||
@ -2716,6 +2814,7 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int addr, uint8_t *subfeature_param)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
|
||||
if (!chip->onfi_version ||
|
||||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
|
||||
@ -2723,7 +2822,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
return -EINVAL;
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
|
||||
chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);
|
||||
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
|
||||
chip->write_byte(mtd, subfeature_param[i]);
|
||||
|
||||
status = chip->waitfunc(mtd, chip);
|
||||
if (status & NAND_STATUS_FAIL)
|
||||
return -EIO;
|
||||
@ -2740,6 +2841,8 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int addr, uint8_t *subfeature_param)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!chip->onfi_version ||
|
||||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
|
||||
& ONFI_OPT_CMD_SET_GET_FEATURES))
|
||||
@ -2749,7 +2852,8 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
|
||||
chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);
|
||||
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
|
||||
*subfeature_param++ = chip->read_byte(mtd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2812,6 +2916,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
|
||||
chip->block_markbad = nand_default_block_markbad;
|
||||
if (!chip->write_buf || chip->write_buf == nand_write_buf)
|
||||
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
|
||||
if (!chip->write_byte || chip->write_byte == nand_write_byte)
|
||||
chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
|
||||
if (!chip->read_buf || chip->read_buf == nand_read_buf)
|
||||
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
|
||||
if (!chip->scan_bbt)
|
||||
@ -2926,6 +3032,30 @@ ext_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
|
||||
|
||||
return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
|
||||
feature);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure chip properties from Micron vendor-specific ONFI table
|
||||
*/
|
||||
static void nand_onfi_detect_micron(struct nand_chip *chip,
|
||||
struct nand_onfi_params *p)
|
||||
{
|
||||
struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
|
||||
|
||||
if (le16_to_cpu(p->vendor_revision) < 1)
|
||||
return;
|
||||
|
||||
chip->read_retries = micron->read_retry_options;
|
||||
chip->setup_read_retry = nand_setup_read_retry_micron;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
|
||||
*/
|
||||
@ -2979,7 +3109,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
chip->onfi_version = 10;
|
||||
|
||||
if (!chip->onfi_version) {
|
||||
pr_info("%s: unsupported ONFI version: %d\n", __func__, val);
|
||||
pr_info("unsupported ONFI version: %d\n", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3032,6 +3162,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
pr_warn("Could not retrieve ONFI ECC requirements\n");
|
||||
}
|
||||
|
||||
if (p->jedec_id == NAND_MFR_MICRON)
|
||||
nand_onfi_detect_micron(chip, p);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3152,9 +3285,12 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
mtd->oobsize = 512;
|
||||
break;
|
||||
case 6:
|
||||
default: /* Other cases are "reserved" (unknown) */
|
||||
mtd->oobsize = 640;
|
||||
break;
|
||||
case 7:
|
||||
default: /* Other cases are "reserved" (unknown) */
|
||||
mtd->oobsize = 1024;
|
||||
break;
|
||||
}
|
||||
extid >>= 2;
|
||||
/* Calc blocksize */
|
||||
@ -3325,6 +3461,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
|
||||
*busw = type->options & NAND_BUSWIDTH_16;
|
||||
|
||||
if (!mtd->name)
|
||||
mtd->name = type->name;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -3372,8 +3511,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
id_data[i] = chip->read_byte(mtd);
|
||||
|
||||
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
|
||||
pr_info("%s: second ID read did not match "
|
||||
"%02x,%02x against %02x,%02x\n", __func__,
|
||||
pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
|
||||
*maf_id, *dev_id, id_data[0], id_data[1]);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
@ -3440,10 +3578,10 @@ ident_done:
|
||||
* Check, if buswidth is correct. Hardware drivers should set
|
||||
* chip correct!
|
||||
*/
|
||||
pr_info("NAND device: Manufacturer ID:"
|
||||
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
|
||||
*dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
|
||||
pr_warn("NAND bus width %d instead %d bit\n",
|
||||
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
|
||||
*maf_id, *dev_id);
|
||||
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
|
||||
pr_warn("bus width %d instead %d bit\n",
|
||||
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
|
||||
busw ? 16 : 8);
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -3472,14 +3610,13 @@ ident_done:
|
||||
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
||||
chip->cmdfunc = nand_command_lp;
|
||||
|
||||
pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)\n",
|
||||
*maf_id, *dev_id, nand_manuf_ids[maf_idx].name,
|
||||
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
|
||||
*maf_id, *dev_id);
|
||||
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
||||
chip->onfi_version ? chip->onfi_params.model : type->name);
|
||||
|
||||
pr_info("NAND device: %dMiB, %s, page size: %d, OOB size: %d\n",
|
||||
pr_info("%dMiB, %s, page size: %d, OOB size: %d\n",
|
||||
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
|
||||
mtd->writesize, mtd->oobsize);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -3535,7 +3672,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
|
||||
chip->select_chip(mtd, -1);
|
||||
}
|
||||
if (i > 1)
|
||||
pr_info("%d NAND chips detected\n", i);
|
||||
pr_info("%d chips detected\n", i);
|
||||
|
||||
/* Store the number of chips and calc total size for mtd */
|
||||
chip->numchips = i;
|
||||
|
@ -169,6 +169,8 @@ struct nand_manufacturers nand_manuf_ids[] = {
|
||||
{NAND_MFR_AMD, "AMD/Spansion"},
|
||||
{NAND_MFR_MACRONIX, "Macronix"},
|
||||
{NAND_MFR_EON, "Eon"},
|
||||
{NAND_MFR_SANDISK, "SanDisk"},
|
||||
{NAND_MFR_INTEL, "Intel"},
|
||||
{0x0, "Unknown"}
|
||||
};
|
||||
|
||||
|
@ -241,12 +241,10 @@ static int nuc900_nand_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct nuc900_nand *nuc900_nand;
|
||||
struct nand_chip *chip;
|
||||
int retval;
|
||||
struct resource *res;
|
||||
|
||||
retval = 0;
|
||||
|
||||
nuc900_nand = kzalloc(sizeof(struct nuc900_nand), GFP_KERNEL);
|
||||
nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
|
||||
GFP_KERNEL);
|
||||
if (!nuc900_nand)
|
||||
return -ENOMEM;
|
||||
chip = &(nuc900_nand->chip);
|
||||
@ -255,11 +253,9 @@ static int nuc900_nand_probe(struct platform_device *pdev)
|
||||
nuc900_nand->mtd.owner = THIS_MODULE;
|
||||
spin_lock_init(&nuc900_nand->lock);
|
||||
|
||||
nuc900_nand->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(nuc900_nand->clk)) {
|
||||
retval = -ENOENT;
|
||||
goto fail1;
|
||||
}
|
||||
nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(nuc900_nand->clk))
|
||||
return -ENOENT;
|
||||
clk_enable(nuc900_nand->clk);
|
||||
|
||||
chip->cmdfunc = nuc900_nand_command_lp;
|
||||
@ -272,57 +268,29 @@ static int nuc900_nand_probe(struct platform_device *pdev)
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
retval = -ENXIO;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
|
||||
retval = -EBUSY;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
nuc900_nand->reg = ioremap(res->start, resource_size(res));
|
||||
if (!nuc900_nand->reg) {
|
||||
retval = -ENOMEM;
|
||||
goto fail2;
|
||||
}
|
||||
nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(nuc900_nand->reg))
|
||||
return PTR_ERR(nuc900_nand->reg);
|
||||
|
||||
nuc900_nand_enable(nuc900_nand);
|
||||
|
||||
if (nand_scan(&(nuc900_nand->mtd), 1)) {
|
||||
retval = -ENXIO;
|
||||
goto fail3;
|
||||
}
|
||||
if (nand_scan(&(nuc900_nand->mtd), 1))
|
||||
return -ENXIO;
|
||||
|
||||
mtd_device_register(&(nuc900_nand->mtd), partitions,
|
||||
ARRAY_SIZE(partitions));
|
||||
|
||||
platform_set_drvdata(pdev, nuc900_nand);
|
||||
|
||||
return retval;
|
||||
|
||||
fail3: iounmap(nuc900_nand->reg);
|
||||
fail2: release_mem_region(res->start, resource_size(res));
|
||||
fail1: kfree(nuc900_nand);
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nuc900_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
nand_release(&nuc900_nand->mtd);
|
||||
iounmap(nuc900_nand->reg);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
clk_disable(nuc900_nand->clk);
|
||||
clk_put(nuc900_nand->clk);
|
||||
|
||||
kfree(nuc900_nand);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1730,13 +1730,7 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
break;
|
||||
|
||||
case NAND_OMAP_POLLED:
|
||||
if (nand_chip->options & NAND_BUSWIDTH_16) {
|
||||
nand_chip->read_buf = omap_read_buf16;
|
||||
nand_chip->write_buf = omap_write_buf16;
|
||||
} else {
|
||||
nand_chip->read_buf = omap_read_buf8;
|
||||
nand_chip->write_buf = omap_write_buf8;
|
||||
}
|
||||
/* Use nand_base defaults for {read,write}_buf */
|
||||
break;
|
||||
|
||||
case NAND_OMAP_PREFETCH_DMA:
|
||||
|
@ -87,7 +87,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
|
||||
|
||||
nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
|
||||
if (!nc) {
|
||||
printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");
|
||||
ret = -ENOMEM;
|
||||
goto no_res;
|
||||
}
|
||||
@ -101,7 +100,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
|
||||
|
||||
io_base = ioremap(res->start, resource_size(res));
|
||||
if (!io_base) {
|
||||
printk(KERN_ERR "orion_nand: ioremap failed\n");
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
ret = -EIO;
|
||||
goto no_res;
|
||||
}
|
||||
@ -110,7 +109,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
|
||||
board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
|
||||
GFP_KERNEL);
|
||||
if (!board) {
|
||||
printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
|
||||
ret = -ENOMEM;
|
||||
goto no_res;
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ MODULE_DEVICE_TABLE(of, pasemi_nand_match);
|
||||
static struct platform_driver pasemi_nand_driver =
|
||||
{
|
||||
.driver = {
|
||||
.name = (char*)driver_name,
|
||||
.name = driver_name,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = pasemi_nand_match,
|
||||
},
|
||||
|
@ -9,6 +9,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -47,30 +48,16 @@ static int plat_nand_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENXIO;
|
||||
|
||||
/* Allocate memory for the device structure (and zero it) */
|
||||
data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
dev_err(&pdev->dev, "failed to allocate device structure.\n");
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
dev_name(&pdev->dev))) {
|
||||
dev_err(&pdev->dev, "request_mem_region failed\n");
|
||||
err = -EBUSY;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
data->io_base = ioremap(res->start, resource_size(res));
|
||||
if (data->io_base == NULL) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
err = -EIO;
|
||||
goto out_release_io;
|
||||
}
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->io_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(data->io_base))
|
||||
return PTR_ERR(data->io_base);
|
||||
|
||||
data->chip.priv = &data;
|
||||
data->mtd.priv = &data->chip;
|
||||
@ -122,11 +109,6 @@ static int plat_nand_probe(struct platform_device *pdev)
|
||||
out:
|
||||
if (pdata->ctrl.remove)
|
||||
pdata->ctrl.remove(pdev);
|
||||
iounmap(data->io_base);
|
||||
out_release_io:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
out_free:
|
||||
kfree(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -137,16 +119,10 @@ static int plat_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct plat_nand_data *data = platform_get_drvdata(pdev);
|
||||
struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
nand_release(&data->mtd);
|
||||
if (pdata->ctrl.remove)
|
||||
pdata->ctrl.remove(pdev);
|
||||
iounmap(data->io_base);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -46,9 +46,43 @@
|
||||
#include <linux/mtd/nand_ecc.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#include <plat/regs-nand.h>
|
||||
#include <linux/platform_data/mtd-nand-s3c2410.h>
|
||||
|
||||
#define S3C2410_NFREG(x) (x)
|
||||
|
||||
#define S3C2410_NFCONF S3C2410_NFREG(0x00)
|
||||
#define S3C2410_NFCMD S3C2410_NFREG(0x04)
|
||||
#define S3C2410_NFADDR S3C2410_NFREG(0x08)
|
||||
#define S3C2410_NFDATA S3C2410_NFREG(0x0C)
|
||||
#define S3C2410_NFSTAT S3C2410_NFREG(0x10)
|
||||
#define S3C2410_NFECC S3C2410_NFREG(0x14)
|
||||
#define S3C2440_NFCONT S3C2410_NFREG(0x04)
|
||||
#define S3C2440_NFCMD S3C2410_NFREG(0x08)
|
||||
#define S3C2440_NFADDR S3C2410_NFREG(0x0C)
|
||||
#define S3C2440_NFDATA S3C2410_NFREG(0x10)
|
||||
#define S3C2440_NFSTAT S3C2410_NFREG(0x20)
|
||||
#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C)
|
||||
#define S3C2412_NFSTAT S3C2410_NFREG(0x28)
|
||||
#define S3C2412_NFMECC0 S3C2410_NFREG(0x34)
|
||||
#define S3C2410_NFCONF_EN (1<<15)
|
||||
#define S3C2410_NFCONF_INITECC (1<<12)
|
||||
#define S3C2410_NFCONF_nFCE (1<<11)
|
||||
#define S3C2410_NFCONF_TACLS(x) ((x)<<8)
|
||||
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
|
||||
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
|
||||
#define S3C2410_NFSTAT_BUSY (1<<0)
|
||||
#define S3C2440_NFCONF_TACLS(x) ((x)<<12)
|
||||
#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8)
|
||||
#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4)
|
||||
#define S3C2440_NFCONT_INITECC (1<<4)
|
||||
#define S3C2440_NFCONT_nFCE (1<<1)
|
||||
#define S3C2440_NFCONT_ENABLE (1<<0)
|
||||
#define S3C2440_NFSTAT_READY (1<<0)
|
||||
#define S3C2412_NFCONF_NANDBOOT (1<<31)
|
||||
#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5)
|
||||
#define S3C2412_NFCONT_nFCE0 (1<<1)
|
||||
#define S3C2412_NFSTAT_READY (1<<0)
|
||||
|
||||
/* new oob placement block for use with hardware ecc generation
|
||||
*/
|
||||
|
||||
@ -919,7 +953,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (info == NULL) {
|
||||
dev_err(&pdev->dev, "no memory for flash info\n");
|
||||
err = -ENOMEM;
|
||||
goto exit_error;
|
||||
}
|
||||
@ -974,7 +1007,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
|
||||
size = nr_sets * sizeof(*info->mtds);
|
||||
info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
|
||||
if (info->mtds == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate mtd storage\n");
|
||||
err = -ENOMEM;
|
||||
goto exit_error;
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
|
||||
(void *)pdata->slave_id_fifo0_tx);
|
||||
(void *)(uintptr_t)pdata->slave_id_fifo0_tx);
|
||||
dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
|
||||
flctl->chan_fifo0_tx);
|
||||
|
||||
@ -168,7 +168,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
|
||||
goto err;
|
||||
|
||||
flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
|
||||
(void *)pdata->slave_id_fifo0_rx);
|
||||
(void *)(uintptr_t)pdata->slave_id_fifo0_rx);
|
||||
dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
|
||||
flctl->chan_fifo0_rx);
|
||||
|
||||
@ -1021,7 +1021,6 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
struct flctl_soc_config {
|
||||
unsigned long flcmncr_val;
|
||||
unsigned has_hwecc:1;
|
||||
@ -1059,10 +1058,8 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
dev_err(dev, "%s: failed to allocate config data\n", __func__);
|
||||
if (!pdata)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set SoC specific options */
|
||||
pdata->flcmncr_val = config->flcmncr_val;
|
||||
@ -1080,12 +1077,6 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
|
||||
|
||||
return pdata;
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int flctl_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -1094,38 +1085,30 @@ static int flctl_probe(struct platform_device *pdev)
|
||||
struct mtd_info *flctl_mtd;
|
||||
struct nand_chip *nand;
|
||||
struct sh_flctl_platform_data *pdata;
|
||||
int ret = -ENXIO;
|
||||
int ret;
|
||||
int irq;
|
||||
struct mtd_part_parser_data ppdata = {};
|
||||
|
||||
flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
|
||||
if (!flctl) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL);
|
||||
if (!flctl)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "failed to get I/O memory\n");
|
||||
goto err_iomap;
|
||||
}
|
||||
|
||||
flctl->reg = ioremap(res->start, resource_size(res));
|
||||
if (flctl->reg == NULL) {
|
||||
dev_err(&pdev->dev, "failed to remap I/O memory\n");
|
||||
goto err_iomap;
|
||||
}
|
||||
flctl->reg = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(flctl->reg))
|
||||
return PTR_ERR(flctl->reg);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get flste irq data\n");
|
||||
goto err_flste;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl);
|
||||
ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED,
|
||||
"flste", flctl);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request interrupt failed.\n");
|
||||
goto err_flste;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
@ -1135,8 +1118,7 @@ static int flctl_probe(struct platform_device *pdev)
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no setup data defined\n");
|
||||
ret = -EINVAL;
|
||||
goto err_pdata;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, flctl);
|
||||
@ -1190,12 +1172,6 @@ static int flctl_probe(struct platform_device *pdev)
|
||||
err_chip:
|
||||
flctl_release_dma(flctl);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
err_pdata:
|
||||
free_irq(irq, flctl);
|
||||
err_flste:
|
||||
iounmap(flctl->reg);
|
||||
err_iomap:
|
||||
kfree(flctl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1206,9 +1182,6 @@ static int flctl_remove(struct platform_device *pdev)
|
||||
flctl_release_dma(flctl);
|
||||
nand_release(&flctl->mtd);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
free_irq(platform_get_irq(pdev, 0), flctl);
|
||||
iounmap(flctl->reg);
|
||||
kfree(flctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -121,10 +121,8 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
|
||||
|
||||
/* Allocate memory for MTD device structure and private data */
|
||||
sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
|
||||
if (!sharpsl) {
|
||||
printk("Unable to allocate SharpSL NAND MTD device structure.\n");
|
||||
if (!sharpsl)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
@ -136,7 +134,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
|
||||
/* map physical address */
|
||||
sharpsl->io = ioremap(r->start, resource_size(r));
|
||||
if (!sharpsl->io) {
|
||||
printk("ioremap to access Sharp SL NAND chip failed\n");
|
||||
dev_err(&pdev->dev, "ioremap to access Sharp SL NAND chip failed\n");
|
||||
err = -EIO;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
@ -371,11 +371,9 @@ static int tmio_probe(struct platform_device *dev)
|
||||
if (data == NULL)
|
||||
dev_warn(&dev->dev, "NULL platform data!\n");
|
||||
|
||||
tmio = kzalloc(sizeof *tmio, GFP_KERNEL);
|
||||
if (!tmio) {
|
||||
retval = -ENOMEM;
|
||||
goto err_kzalloc;
|
||||
}
|
||||
tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL);
|
||||
if (!tmio)
|
||||
return -ENOMEM;
|
||||
|
||||
tmio->dev = dev;
|
||||
|
||||
@ -385,22 +383,18 @@ static int tmio_probe(struct platform_device *dev)
|
||||
mtd->priv = nand_chip;
|
||||
mtd->name = "tmio-nand";
|
||||
|
||||
tmio->ccr = ioremap(ccr->start, resource_size(ccr));
|
||||
if (!tmio->ccr) {
|
||||
retval = -EIO;
|
||||
goto err_iomap_ccr;
|
||||
}
|
||||
tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr));
|
||||
if (!tmio->ccr)
|
||||
return -EIO;
|
||||
|
||||
tmio->fcr_base = fcr->start & 0xfffff;
|
||||
tmio->fcr = ioremap(fcr->start, resource_size(fcr));
|
||||
if (!tmio->fcr) {
|
||||
retval = -EIO;
|
||||
goto err_iomap_fcr;
|
||||
}
|
||||
tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr));
|
||||
if (!tmio->fcr)
|
||||
return -EIO;
|
||||
|
||||
retval = tmio_hw_init(dev, tmio);
|
||||
if (retval)
|
||||
goto err_hwinit;
|
||||
return retval;
|
||||
|
||||
/* Set address of NAND IO lines */
|
||||
nand_chip->IO_ADDR_R = tmio->fcr;
|
||||
@ -428,7 +422,8 @@ static int tmio_probe(struct platform_device *dev)
|
||||
/* 15 us command delay time */
|
||||
nand_chip->chip_delay = 15;
|
||||
|
||||
retval = request_irq(irq, &tmio_irq, 0, dev_name(&dev->dev), tmio);
|
||||
retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
|
||||
dev_name(&dev->dev), tmio);
|
||||
if (retval) {
|
||||
dev_err(&dev->dev, "request_irq error %d\n", retval);
|
||||
goto err_irq;
|
||||
@ -440,7 +435,7 @@ static int tmio_probe(struct platform_device *dev)
|
||||
/* Scan to find existence of the device */
|
||||
if (nand_scan(mtd, 1)) {
|
||||
retval = -ENODEV;
|
||||
goto err_scan;
|
||||
goto err_irq;
|
||||
}
|
||||
/* Register the partitions */
|
||||
retval = mtd_device_parse_register(mtd, NULL, NULL,
|
||||
@ -451,18 +446,8 @@ static int tmio_probe(struct platform_device *dev)
|
||||
|
||||
nand_release(mtd);
|
||||
|
||||
err_scan:
|
||||
if (tmio->irq)
|
||||
free_irq(tmio->irq, tmio);
|
||||
err_irq:
|
||||
tmio_hw_stop(dev, tmio);
|
||||
err_hwinit:
|
||||
iounmap(tmio->fcr);
|
||||
err_iomap_fcr:
|
||||
iounmap(tmio->ccr);
|
||||
err_iomap_ccr:
|
||||
kfree(tmio);
|
||||
err_kzalloc:
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -471,12 +456,7 @@ static int tmio_remove(struct platform_device *dev)
|
||||
struct tmio_nand *tmio = platform_get_drvdata(dev);
|
||||
|
||||
nand_release(&tmio->mtd);
|
||||
if (tmio->irq)
|
||||
free_irq(tmio->irq, tmio);
|
||||
tmio_hw_stop(dev, tmio);
|
||||
iounmap(tmio->fcr);
|
||||
iounmap(tmio->ccr);
|
||||
kfree(tmio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -319,11 +319,8 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
|
||||
continue;
|
||||
txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv),
|
||||
GFP_KERNEL);
|
||||
if (!txx9_priv) {
|
||||
dev_err(&dev->dev, "Unable to allocate "
|
||||
"TXx9 NDFMC MTD device structure.\n");
|
||||
if (!txx9_priv)
|
||||
continue;
|
||||
}
|
||||
chip = &txx9_priv->chip;
|
||||
mtd = &txx9_priv->mtd;
|
||||
mtd->owner = THIS_MODULE;
|
||||
|
@ -81,7 +81,7 @@ static int parse_ofpart_partitions(struct mtd_info *master,
|
||||
partname = of_get_property(pp, "label", &len);
|
||||
if (!partname)
|
||||
partname = of_get_property(pp, "name", &len);
|
||||
(*pparts)[i].name = (char *)partname;
|
||||
(*pparts)[i].name = partname;
|
||||
|
||||
if (of_get_property(pp, "read-only", &len))
|
||||
(*pparts)[i].mask_flags |= MTD_WRITEABLE;
|
||||
@ -152,7 +152,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master,
|
||||
if (names && (plen > 0)) {
|
||||
int len = strlen(names) + 1;
|
||||
|
||||
(*pparts)[i].name = (char *)names;
|
||||
(*pparts)[i].name = names;
|
||||
plen -= len;
|
||||
names += len;
|
||||
} else {
|
||||
@ -173,18 +173,9 @@ static struct mtd_part_parser ofoldpart_parser = {
|
||||
|
||||
static int __init ofpart_parser_init(void)
|
||||
{
|
||||
int rc;
|
||||
rc = register_mtd_parser(&ofpart_parser);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = register_mtd_parser(&ofoldpart_parser);
|
||||
if (!rc)
|
||||
return 0;
|
||||
|
||||
deregister_mtd_parser(&ofoldpart_parser);
|
||||
out:
|
||||
return rc;
|
||||
register_mtd_parser(&ofpart_parser);
|
||||
register_mtd_parser(&ofoldpart_parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ofpart_parser_exit(void)
|
||||
|
@ -58,7 +58,7 @@ static int generic_onenand_probe(struct platform_device *pdev)
|
||||
goto out_release_mem_region;
|
||||
}
|
||||
|
||||
info->onenand.mmcontrol = pdata ? pdata->mmcontrol : 0;
|
||||
info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL;
|
||||
info->onenand.irq = platform_get_irq(pdev, 0);
|
||||
|
||||
info->mtd.name = dev_name(&pdev->dev);
|
||||
|
@ -300,7 +300,8 @@ MODULE_ALIAS("RedBoot");
|
||||
|
||||
static int __init redboot_parser_init(void)
|
||||
{
|
||||
return register_mtd_parser(&redboot_parser);
|
||||
register_mtd_parser(&redboot_parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit redboot_parser_exit(void)
|
||||
|
@ -19,7 +19,7 @@
|
||||
* or detected.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE)
|
||||
#if IS_ENABLED(CONFIG_MTD_NAND)
|
||||
|
||||
struct nand_ecc_test {
|
||||
const char *name;
|
||||
|
@ -288,6 +288,8 @@ struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void)
|
||||
struct jffs2_xattr_datum *xd;
|
||||
xd = kmem_cache_zalloc(xattr_datum_cache, GFP_KERNEL);
|
||||
dbg_memalloc("%p\n", xd);
|
||||
if (!xd)
|
||||
return NULL;
|
||||
|
||||
xd->class = RAWNODE_CLASS_XATTR_DATUM;
|
||||
xd->node = (void *)xd;
|
||||
@ -306,6 +308,8 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void)
|
||||
struct jffs2_xattr_ref *ref;
|
||||
ref = kmem_cache_zalloc(xattr_ref_cache, GFP_KERNEL);
|
||||
dbg_memalloc("%p\n", ref);
|
||||
if (!ref)
|
||||
return NULL;
|
||||
|
||||
ref->class = RAWNODE_CLASS_XATTR_REF;
|
||||
ref->node = (void *)ref;
|
||||
|
@ -3,6 +3,6 @@
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
|
||||
unsigned long size, char *name);
|
||||
unsigned long size, const char *name);
|
||||
|
||||
#endif /* __MTD_MTDRAM_H__ */
|
||||
|
@ -219,6 +219,9 @@ struct nand_chip;
|
||||
/* ONFI feature address */
|
||||
#define ONFI_FEATURE_ADDR_TIMING_MODE 0x1
|
||||
|
||||
/* Vendor-specific feature address (Micron) */
|
||||
#define ONFI_FEATURE_ADDR_READ_RETRY 0x89
|
||||
|
||||
/* ONFI subfeature parameters length */
|
||||
#define ONFI_SUBFEATURE_PARAM_LEN 4
|
||||
|
||||
@ -279,16 +282,17 @@ struct nand_onfi_params {
|
||||
__le16 io_pin_capacitance_typ;
|
||||
__le16 input_pin_capacitance_typ;
|
||||
u8 input_pin_capacitance_max;
|
||||
u8 driver_strenght_support;
|
||||
u8 driver_strength_support;
|
||||
__le16 t_int_r;
|
||||
__le16 t_ald;
|
||||
u8 reserved4[7];
|
||||
|
||||
/* vendor */
|
||||
u8 reserved5[90];
|
||||
__le16 vendor_revision;
|
||||
u8 vendor[88];
|
||||
|
||||
__le16 crc;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
#define ONFI_CRC_BASE 0x4F4E
|
||||
|
||||
@ -326,6 +330,26 @@ struct onfi_ext_param_page {
|
||||
*/
|
||||
} __packed;
|
||||
|
||||
struct nand_onfi_vendor_micron {
|
||||
u8 two_plane_read;
|
||||
u8 read_cache;
|
||||
u8 read_unique_id;
|
||||
u8 dq_imped;
|
||||
u8 dq_imped_num_settings;
|
||||
u8 dq_imped_feat_addr;
|
||||
u8 rb_pulldown_strength;
|
||||
u8 rb_pulldown_strength_feat_addr;
|
||||
u8 rb_pulldown_strength_num_settings;
|
||||
u8 otp_mode;
|
||||
u8 otp_page_start;
|
||||
u8 otp_data_prot_addr;
|
||||
u8 otp_num_pages;
|
||||
u8 otp_feat_addr;
|
||||
u8 read_retry_options;
|
||||
u8 reserved[72];
|
||||
u8 param_revision;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
|
||||
* @lock: protection lock
|
||||
@ -432,6 +456,8 @@ struct nand_buffers {
|
||||
* flash device.
|
||||
* @read_byte: [REPLACEABLE] read one byte from the chip
|
||||
* @read_word: [REPLACEABLE] read one word from the chip
|
||||
* @write_byte: [REPLACEABLE] write a single byte to the chip on the
|
||||
* low 8 I/O lines
|
||||
* @write_buf: [REPLACEABLE] write data from the buffer to the chip
|
||||
* @read_buf: [REPLACEABLE] read data from the chip into the buffer
|
||||
* @select_chip: [REPLACEABLE] select chip nr
|
||||
@ -451,6 +477,8 @@ struct nand_buffers {
|
||||
* commands to the chip.
|
||||
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on
|
||||
* ready.
|
||||
* @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for
|
||||
* setting the read-retry mode. Mostly needed for MLC NAND.
|
||||
* @ecc: [BOARDSPECIFIC] ECC control structure
|
||||
* @buffers: buffer structure for read/write
|
||||
* @hwcontrol: platform-specific hardware control structure
|
||||
@ -497,6 +525,7 @@ struct nand_buffers {
|
||||
* non 0 if ONFI supported.
|
||||
* @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is
|
||||
* supported, 0 otherwise.
|
||||
* @read_retries: [INTERN] the number of read retry modes supported
|
||||
* @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
|
||||
* @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
|
||||
* @bbt: [INTERN] bad block table pointer
|
||||
@ -521,6 +550,7 @@ struct nand_chip {
|
||||
|
||||
uint8_t (*read_byte)(struct mtd_info *mtd);
|
||||
u16 (*read_word)(struct mtd_info *mtd);
|
||||
void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
|
||||
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
|
||||
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
|
||||
void (*select_chip)(struct mtd_info *mtd, int chip);
|
||||
@ -544,6 +574,7 @@ struct nand_chip {
|
||||
int feature_addr, uint8_t *subfeature_para);
|
||||
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int feature_addr, uint8_t *subfeature_para);
|
||||
int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
|
||||
|
||||
int chip_delay;
|
||||
unsigned int options;
|
||||
@ -568,6 +599,8 @@ struct nand_chip {
|
||||
int onfi_version;
|
||||
struct nand_onfi_params onfi_params;
|
||||
|
||||
int read_retries;
|
||||
|
||||
flstate_t state;
|
||||
|
||||
uint8_t *oob_poi;
|
||||
@ -600,6 +633,8 @@ struct nand_chip {
|
||||
#define NAND_MFR_AMD 0x01
|
||||
#define NAND_MFR_MACRONIX 0xc2
|
||||
#define NAND_MFR_EON 0x92
|
||||
#define NAND_MFR_SANDISK 0x45
|
||||
#define NAND_MFR_INTEL 0x89
|
||||
|
||||
/* The maximum expected count of bytes in the NAND ID sequence */
|
||||
#define NAND_MAX_ID_LEN 8
|
||||
|
@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
struct mtd_partition {
|
||||
char *name; /* identifier string */
|
||||
const char *name; /* identifier string */
|
||||
uint64_t size; /* partition size */
|
||||
uint64_t offset; /* offset within the master MTD space */
|
||||
uint32_t mask_flags; /* master MTD flags to mask out for this partition */
|
||||
@ -76,11 +76,11 @@ struct mtd_part_parser {
|
||||
struct mtd_part_parser_data *);
|
||||
};
|
||||
|
||||
extern int register_mtd_parser(struct mtd_part_parser *parser);
|
||||
extern int deregister_mtd_parser(struct mtd_part_parser *parser);
|
||||
extern void register_mtd_parser(struct mtd_part_parser *parser);
|
||||
extern void deregister_mtd_parser(struct mtd_part_parser *parser);
|
||||
|
||||
int mtd_is_partition(const struct mtd_info *mtd);
|
||||
int mtd_add_partition(struct mtd_info *master, char *name,
|
||||
int mtd_add_partition(struct mtd_info *master, const char *name,
|
||||
long long offset, long long length);
|
||||
int mtd_del_partition(struct mtd_info *master, int partno);
|
||||
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_OF_MTD_H
|
||||
#define __LINUX_OF_NET_H
|
||||
#define __LINUX_OF_MTD_H
|
||||
|
||||
#ifdef CONFIG_OF_MTD
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
/*
|
||||
* arch/arm/plat-omap/include/mach/nand.h
|
||||
*
|
||||
* Copyright (C) 2006 Micron Technology Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -55,6 +55,9 @@ struct pxa3xx_nand_platform_data {
|
||||
/* indicate how many chip selects will be used */
|
||||
int num_cs;
|
||||
|
||||
/* use an flash-based bad block table */
|
||||
bool flash_bbt;
|
||||
|
||||
const struct mtd_partition *parts[NUM_CHIP_SELECT];
|
||||
unsigned int nr_parts[NUM_CHIP_SELECT];
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
/*
|
||||
* arch/arm/plat-omap/include/mach/onenand.h
|
||||
*
|
||||
* Copyright (C) 2006 Nokia Corporation
|
||||
* Author: Juha Yrjola
|
||||
*
|
||||
|
@ -1,13 +1,11 @@
|
||||
/*
|
||||
* arch/arm/plat-orion/include/plat/orion_nand.h
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#ifndef __PLAT_ORION_NAND_H
|
||||
#define __PLAT_ORION_NAND_H
|
||||
#ifndef __MTD_ORION_NAND_H
|
||||
#define __MTD_ORION_NAND_H
|
||||
|
||||
/*
|
||||
* Device bus NAND private data
|
||||
|
Loading…
Reference in New Issue
Block a user