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:
Linus Torvalds 2014-01-28 18:56:37 -08:00
commit 0e47c969c6
76 changed files with 1699 additions and 1054 deletions

View File

@ -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>;
};
};

View 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 selects 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>;
};
};

View File

@ -17,6 +17,14 @@ Required properties:
Optional properties: Optional properties:
- nand-on-flash-bbt: boolean to enable on flash bbt option if not - nand-on-flash-bbt: boolean to enable on flash bbt option if not
present false 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 The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail. address space. See partition.txt for more detail.

View File

@ -2,7 +2,9 @@ PXA3xx NAND DT bindings
Required properties: 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 - reg: The register base for the controller
- interrupts: The interrupt to map - interrupts: The interrupt to map
- #address-cells: Set to <1> if the node includes partitions - #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 - marvell,nand-keep-config: Set to keep the NAND controller config as set
by the bootloader by the bootloader
- num-cs: Number of chipselect lines to usw - num-cs: Number of chipselect lines to usw
- nand-on-flash-bbt: boolean to enable on flash bbt option if
not present false
Example: Example:

View 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).

View File

@ -5622,10 +5622,11 @@ F: mm/page_cgroup.c
MEMORY TECHNOLOGY DEVICES (MTD) MEMORY TECHNOLOGY DEVICES (MTD)
M: David Woodhouse <dwmw2@infradead.org> M: David Woodhouse <dwmw2@infradead.org>
M: Brian Norris <computersforpeace@gmail.com>
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/ W: http://www.linux-mtd.infradead.org/
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ 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 S: Maintained
F: drivers/mtd/ F: drivers/mtd/
F: include/linux/mtd/ F: include/linux/mtd/
@ -6942,6 +6943,12 @@ F: include/sound/pxa2xx-lib.h
F: sound/arm/pxa* F: sound/arm/pxa*
F: sound/soc/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 MMP SUPPORT
M: Eric Miao <eric.y.miao@gmail.com> M: Eric Miao <eric.y.miao@gmail.com>
M: Haojian Zhuang <haojian.zhuang@gmail.com> M: Haojian Zhuang <haojian.zhuang@gmail.com>

View File

@ -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 */

View File

@ -157,10 +157,11 @@ config MTD_BCM47XX_PARTS
comment "User Modules And Translation Layers" comment "User Modules And Translation Layers"
#
# MTD block device support is select'ed if needed
#
config MTD_BLKDEVS config MTD_BLKDEVS
tristate "Common interface to block layer for MTD 'translation layers'" tristate
depends on BLOCK
default n
config MTD_BLOCK config MTD_BLOCK
tristate "Caching block device access to MTD devices" tristate "Caching block device access to MTD devices"

View File

@ -264,7 +264,8 @@ static struct mtd_part_parser afs_parser = {
static int __init afs_parser_init(void) 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) static void __exit afs_parser_exit(void)

View File

@ -139,7 +139,8 @@ static struct mtd_part_parser ar7_parser = {
static int __init ar7_parser_init(void) 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) static void __exit ar7_parser_exit(void)

View File

@ -23,10 +23,12 @@
* Amount of bytes we read when analyzing each block of flash memory. * Amount of bytes we read when analyzing each block of flash memory.
* Set it big enough to allow detecting partition and reading important data. * 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 */ /* Magics */
#define BOARD_DATA_MAGIC 0x5246504D /* MPFR */ #define BOARD_DATA_MAGIC 0x5246504D /* MPFR */
#define BOARD_DATA_MAGIC2 0xBD0D0BBD
#define CFE_MAGIC 0x43464531 /* 1EFC */
#define FACTORY_MAGIC 0x59544346 /* FCTY */ #define FACTORY_MAGIC 0x59544346 /* FCTY */
#define POT_MAGIC1 0x54544f50 /* POTT */ #define POT_MAGIC1 0x54544f50 /* POTT */
#define POT_MAGIC2 0x504f /* OP */ #define POT_MAGIC2 0x504f /* OP */
@ -102,8 +104,9 @@ static int bcm47xxpart_parse(struct mtd_info *master,
continue; continue;
} }
/* CFE has small NVRAM at 0x400 */ /* Magic or small NVRAM at 0x400 */
if (buf[0x400 / 4] == NVRAM_HEADER) { if ((buf[0x4e0 / 4] == CFE_MAGIC && buf[0x4e4 / 4] == CFE_MAGIC) ||
(buf[0x400 / 4] == NVRAM_HEADER)) {
bcm47xxpart_add_part(&parts[curr_part++], "boot", bcm47xxpart_add_part(&parts[curr_part++], "boot",
offset, MTD_WRITEABLE); offset, MTD_WRITEABLE);
continue; continue;
@ -190,6 +193,21 @@ static int bcm47xxpart_parse(struct mtd_info *master,
offset, 0); offset, 0);
continue; 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. */ /* 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) 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) static void __exit bcm47xxpart_exit(void)

View File

@ -221,7 +221,8 @@ static struct mtd_part_parser bcm63xx_cfe_parser = {
static int __init bcm63xx_cfe_parser_init(void) 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) static void __exit bcm63xx_cfe_parser_exit(void)

View File

@ -395,7 +395,8 @@ static int __init cmdline_parser_init(void)
{ {
if (mtdparts) if (mtdparts)
mtdpart_setup(mtdparts); mtdpart_setup(mtdparts);
return register_mtd_parser(&cmdline_parser); register_mtd_parser(&cmdline_parser);
return 0;
} }
static void __exit cmdline_parser_exit(void) static void __exit cmdline_parser_exit(void)

View File

@ -2047,21 +2047,21 @@ static int __init docg3_probe(struct platform_device *pdev)
ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!ress) { if (!ress) {
dev_err(dev, "No I/O memory resource defined\n"); 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; ret = -ENOMEM;
cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS, cascade = devm_kzalloc(dev, sizeof(*cascade) * DOC_MAX_NBFLOORS,
GFP_KERNEL); GFP_KERNEL);
if (!cascade) if (!cascade)
goto nomem1; return ret;
cascade->base = base; cascade->base = base;
mutex_init(&cascade->lock); mutex_init(&cascade->lock);
cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
DOC_ECC_BCH_PRIMPOLY); DOC_ECC_BCH_PRIMPOLY);
if (!cascade->bch) if (!cascade->bch)
goto nomem2; return ret;
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
mtd = doc_probe_device(cascade, floor, dev); mtd = doc_probe_device(cascade, floor, dev);
@ -2101,11 +2101,6 @@ err_probe:
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
if (cascade->floors[floor]) if (cascade->floors[floor])
doc_release_device(cascade->floors[floor]); doc_release_device(cascade->floors[floor]);
nomem2:
kfree(cascade);
nomem1:
iounmap(base);
noress:
return ret; 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_cascade *cascade = platform_get_drvdata(pdev);
struct docg3 *docg3 = cascade->floors[0]->priv; struct docg3 *docg3 = cascade->floors[0]->priv;
void __iomem *base = cascade->base;
int floor; int floor;
doc_unregister_sysfs(pdev, cascade); doc_unregister_sysfs(pdev, cascade);
@ -2129,8 +2123,6 @@ static int __exit docg3_release(struct platform_device *pdev)
doc_release_device(cascade->floors[floor]); doc_release_device(cascade->floors[floor]);
free_bch(docg3->cascade->bch); free_bch(docg3->cascade->bch);
kfree(cascade);
iounmap(base);
return 0; return 0;
} }

View File

@ -41,6 +41,7 @@
#define OPCODE_WRSR 0x01 /* Write status register 1 byte */ #define OPCODE_WRSR 0x01 /* Write status register 1 byte */
#define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */
#define OPCODE_FAST_READ 0x0b /* Read data bytes (high 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_PP 0x02 /* Page program (up to 256 bytes) */
#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
#define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ #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_CHIP_ERASE 0xc7 /* Erase whole flash chip */
#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */ #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. */ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
#define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */
#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high 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_PP_4B 0x12 /* Page program (up to 256 bytes) */
#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ #define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */
@ -76,6 +79,11 @@
#define SR_BP2 0x10 /* Block protect 2 */ #define SR_BP2 0x10 /* Block protect 2 */
#define SR_SRWD 0x80 /* SR write protect */ #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 times to check status register before we give up. */
#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
#define MAX_CMD_SIZE 6 #define MAX_CMD_SIZE 6
@ -84,6 +92,12 @@
/****************************************************************************/ /****************************************************************************/
enum read_type {
M25P80_NORMAL = 0,
M25P80_FAST,
M25P80_QUAD,
};
struct m25p { struct m25p {
struct spi_device *spi; struct spi_device *spi;
struct mutex lock; struct mutex lock;
@ -94,7 +108,7 @@ struct m25p {
u8 read_opcode; u8 read_opcode;
u8 program_opcode; u8 program_opcode;
u8 *command; u8 *command;
bool fast_read; enum read_type flash_read;
}; };
static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
@ -130,6 +144,26 @@ static int read_sr(struct m25p *flash)
return val; 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 * Write status register 1 byte
* Returns negative if error occurred. * Returns negative if error occurred.
@ -219,6 +253,93 @@ static int wait_till_ready(struct m25p *flash)
return 1; 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 * Erase the whole flash memory
* *
@ -349,6 +470,35 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
return 0; 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 * Read an address range from the flash chip. The address range
* may be any size provided it is within the physical boundaries. * 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_transfer t[2];
struct spi_message m; struct spi_message m;
uint8_t opcode; uint8_t opcode;
int dummy;
pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
__func__, (u32)from, len); __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); spi_message_init(&m);
memset(t, 0, (sizeof t)); 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].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); spi_message_add_tail(&t[0], &m);
t[1].rx_buf = buf; t[1].rx_buf = buf;
t[1].rx_nbits = m25p80_rx_nbits(flash);
t[1].len = len; t[1].len = len;
spi_message_add_tail(&t[1], &m); 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); spi_sync(flash->spi, &m);
*retlen = m.actual_length - m25p_cmdsz(flash) - *retlen = m.actual_length - m25p_cmdsz(flash) - dummy;
(flash->fast_read ? 1 : 0);
mutex_unlock(&flash->lock); mutex_unlock(&flash->lock);
@ -698,6 +855,7 @@ struct flash_info {
#define SST_WRITE 0x04 /* use SST byte programming */ #define SST_WRITE 0x04 /* use SST byte programming */
#define M25P_NO_FR 0x08 /* Can't do fastread */ #define M25P_NO_FR 0x08 /* Can't do fastread */
#define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */ #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) \ #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) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
{ "mx25l25655e", INFO(0xc22619, 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 */ /* Micron */
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, { "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) }, { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) },
{ "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) },
{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
{ "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, 0) }, { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, M25P80_QUAD_READ) },
{ "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) }, { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_QUAD_READ) },
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 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) }, { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) },
{ "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, { "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", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) },
{ "m25px32-s0", INFO(0x207316, 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) }, { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) },
@ -937,6 +1096,7 @@ static int m25p_probe(struct spi_device *spi)
unsigned i; unsigned i;
struct mtd_part_parser_data ppdata; struct mtd_part_parser_data ppdata;
struct device_node *np = spi->dev.of_node; struct device_node *np = spi->dev.of_node;
int ret;
/* Platform data helps sort out which chip type we have, as /* Platform data helps sort out which chip type we have, as
* well as how this board partitions it. If we don't have * 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->page_size = info->page_size;
flash->mtd.writebufsize = flash->page_size; flash->mtd.writebufsize = flash->page_size;
if (np) if (np) {
/* If we were instantiated by DT, use it */ /* If we were instantiated by DT, use it */
flash->fast_read = of_property_read_bool(np, "m25p,fast-read"); if (of_property_read_bool(np, "m25p,fast-read"))
else flash->flash_read = M25P80_FAST;
else
flash->flash_read = M25P80_NORMAL;
} else {
/* If we weren't instantiated by DT, default to fast-read */ /* 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 */ /* Some devices cannot do fast-read, no matter what DT tells us */
if (info->flags & M25P_NO_FR) 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 */ /* 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; flash->read_opcode = OPCODE_FAST_READ;
else break;
case M25P80_NORMAL:
flash->read_opcode = OPCODE_NORM_READ; 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; flash->program_opcode = OPCODE_PP;
@ -1077,9 +1261,17 @@ static int m25p_probe(struct spi_device *spi)
flash->addr_width = 4; flash->addr_width = 4;
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
/* Dedicated 4-byte command set */ /* Dedicated 4-byte command set */
flash->read_opcode = flash->fast_read ? switch (flash->flash_read) {
OPCODE_FAST_READ_4B : case M25P80_QUAD:
OPCODE_NORM_READ_4B; 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; flash->program_opcode = OPCODE_PP_4B;
/* No small sector erase for 4-byte command set */ /* No small sector erase for 4-byte command set */
flash->erase_opcode = OPCODE_SE_4B; flash->erase_opcode = OPCODE_SE_4B;

View File

@ -205,7 +205,7 @@ static int __init ms02nv_init_one(ulong addr)
mtd->type = MTD_RAM; mtd->type = MTD_RAM;
mtd->flags = MTD_CAP_RAM; mtd->flags = MTD_CAP_RAM;
mtd->size = fixsize; mtd->size = fixsize;
mtd->name = (char *)ms02nv_name; mtd->name = ms02nv_name;
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
mtd->_read = ms02nv_read; mtd->_read = ms02nv_read;
mtd->_write = ms02nv_write; mtd->_write = ms02nv_write;

View File

@ -669,7 +669,6 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
if (!err) if (!err)
return 0; return 0;
spi_set_drvdata(spi, NULL);
kfree(priv); kfree(priv);
return err; return err;
} }
@ -899,10 +898,8 @@ static int dataflash_remove(struct spi_device *spi)
pr_debug("%s: remove\n", dev_name(&spi->dev)); pr_debug("%s: remove\n", dev_name(&spi->dev));
status = mtd_device_unregister(&flash->mtd); status = mtd_device_unregister(&flash->mtd);
if (status == 0) { if (status == 0)
spi_set_drvdata(spi, NULL);
kfree(flash); kfree(flash);
}
return status; return status;
} }

View File

@ -92,7 +92,7 @@ static void __exit cleanup_mtdram(void)
} }
int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 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)); memset(mtd, 0, sizeof(*mtd));

View File

@ -388,7 +388,7 @@ static void put_chip(struct map_info *map, struct flchip *chip)
wake_up(&chip->wq); 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 adr, const struct kvec **pvec,
unsigned long *pvec_seek, int len) unsigned long *pvec_seek, int len)
{ {
@ -469,7 +469,7 @@ int do_write_buffer(struct map_info *map, struct flchip *chip,
return ret; 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 map_info *map = mtd->priv;
struct lpddr_private *lpddr = map->fldrv_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); 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_LICENSE("GPL");
MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>"); MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>");
MODULE_DESCRIPTION("MTD driver for LPDDR flash chips"); MODULE_DESCRIPTION("MTD driver for LPDDR flash chips");

View File

@ -13,6 +13,7 @@
* *
*/ */
#include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
@ -162,13 +163,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev)
mtd_device_unregister(info->mtd); mtd_device_unregister(info->mtd);
map_destroy(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) if (plat->exit)
plat->exit(); plat->exit();
@ -194,7 +188,8 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
return err; 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) { if(!info) {
err = -ENOMEM; err = -ENOMEM;
goto Error; goto Error;
@ -220,20 +215,9 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
info->map.write = ixp4xx_probe_write16; info->map.write = ixp4xx_probe_write16;
info->map.copy_from = ixp4xx_copy_from; info->map.copy_from = ixp4xx_copy_from;
info->res = request_mem_region(dev->resource->start, info->map.virt = devm_ioremap_resource(&dev->dev, dev->resource);
resource_size(dev->resource), if (IS_ERR(info->map.virt)) {
"IXP4XXFlash"); err = PTR_ERR(info->map.virt);
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;
goto Error; goto Error;
} }

View File

@ -123,24 +123,28 @@ ltq_mtd_probe(struct platform_device *pdev)
return -ENODEV; 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); platform_set_drvdata(pdev, ltq_mtd);
ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!ltq_mtd->res) { if (!ltq_mtd->res) {
dev_err(&pdev->dev, "failed to get memory resource\n"); dev_err(&pdev->dev, "failed to get memory resource\n");
err = -ENOENT; return -ENOENT;
goto err_out;
} }
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->phys = ltq_mtd->res->start;
ltq_mtd->map->size = resource_size(ltq_mtd->res); ltq_mtd->map->size = resource_size(ltq_mtd->res);
ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res); ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res);
if (IS_ERR(ltq_mtd->map->virt)) { if (IS_ERR(ltq_mtd->map->virt))
err = PTR_ERR(ltq_mtd->map->virt); return PTR_ERR(ltq_mtd->map->virt);
goto err_out;
}
ltq_mtd->map->name = ltq_map_name; ltq_mtd->map->name = ltq_map_name;
ltq_mtd->map->bankwidth = 2; ltq_mtd->map->bankwidth = 2;
@ -155,8 +159,7 @@ ltq_mtd_probe(struct platform_device *pdev)
if (!ltq_mtd->mtd) { if (!ltq_mtd->mtd) {
dev_err(&pdev->dev, "probing failed\n"); dev_err(&pdev->dev, "probing failed\n");
err = -ENXIO; return -ENXIO;
goto err_free;
} }
ltq_mtd->mtd->owner = THIS_MODULE; ltq_mtd->mtd->owner = THIS_MODULE;
@ -177,10 +180,6 @@ ltq_mtd_probe(struct platform_device *pdev)
err_destroy: err_destroy:
map_destroy(ltq_mtd->mtd); map_destroy(ltq_mtd->mtd);
err_free:
kfree(ltq_mtd->map);
err_out:
kfree(ltq_mtd);
return err; return err;
} }
@ -189,13 +188,9 @@ ltq_mtd_remove(struct platform_device *pdev)
{ {
struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
if (ltq_mtd) { if (ltq_mtd && ltq_mtd->mtd) {
if (ltq_mtd->mtd) { mtd_device_unregister(ltq_mtd->mtd);
mtd_device_unregister(ltq_mtd->mtd); map_destroy(ltq_mtd->mtd);
map_destroy(ltq_mtd->mtd);
}
kfree(ltq_mtd->map);
kfree(ltq_mtd);
} }
return 0; return 0;
} }

View File

@ -61,7 +61,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev)
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
info->map.name = (char *) flash->name; info->map.name = flash->name;
info->map.bankwidth = flash->width; info->map.bankwidth = flash->width;
info->map.phys = res->start; info->map.phys = res->start;
info->map.size = resource_size(res); info->map.size = resource_size(res);

View File

@ -75,7 +75,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp)
up->name = of_get_property(dp, "model", NULL); up->name = of_get_property(dp, "model", NULL);
if (up->name && 0 < strlen(up->name)) 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; up->map.phys = op->resource[0].start;

View File

@ -313,15 +313,7 @@ static struct attribute *mtd_attrs[] = {
&dev_attr_bitflip_threshold.attr, &dev_attr_bitflip_threshold.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(mtd);
static struct attribute_group mtd_group = {
.attrs = mtd_attrs,
};
static const struct attribute_group *mtd_groups[] = {
&mtd_group,
NULL,
};
static struct device_type mtd_devtype = { static struct device_type mtd_devtype = {
.name = "mtd", .name = "mtd",

View File

@ -534,7 +534,7 @@ out_register:
return slave; 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) long long offset, long long length)
{ {
struct mtd_partition part; 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) #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); spin_lock(&part_parser_lock);
list_add(&p->list, &part_parsers); list_add(&p->list, &part_parsers);
spin_unlock(&part_parser_lock); spin_unlock(&part_parser_lock);
return 0;
} }
EXPORT_SYMBOL_GPL(register_mtd_parser); 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); spin_lock(&part_parser_lock);
list_del(&p->list); list_del(&p->list);
spin_unlock(&part_parser_lock); spin_unlock(&part_parser_lock);
return 0;
} }
EXPORT_SYMBOL_GPL(deregister_mtd_parser); EXPORT_SYMBOL_GPL(deregister_mtd_parser);

View File

@ -95,7 +95,7 @@ config MTD_NAND_OMAP2
platforms. platforms.
config MTD_NAND_OMAP_BCH 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" tristate "Support hardware based BCH error correction"
default n default n
select BCH select BCH
@ -326,11 +326,11 @@ config MTD_NAND_ATMEL
on Atmel AT91 and AVR32 processors. on Atmel AT91 and AVR32 processors.
config MTD_NAND_PXA3xx 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 depends on PXA3xx || ARCH_MMP || PLAT_ORION
help help
This enables the driver for the NAND flash device found on 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 config MTD_NAND_SLC_LPC32XX
tristate "NXP LPC32xx SLC Controller" tristate "NXP LPC32xx SLC Controller"
@ -458,17 +458,17 @@ config MTD_NAND_MXC
config MTD_NAND_SH_FLCTL config MTD_NAND_SH_FLCTL
tristate "Support for NAND on Renesas SuperH FLCTL" tristate "Support for NAND on Renesas SuperH FLCTL"
depends on SUPERH || ARCH_SHMOBILE depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
help help
Several Renesas SuperH CPU has FLCTL. This option enables support Several Renesas SuperH CPU has FLCTL. This option enables support
for NAND Flash using FLCTL. for NAND Flash using FLCTL.
config MTD_NAND_DAVINCI config MTD_NAND_DAVINCI
tristate "Support NAND on DaVinci SoC" tristate "Support NAND on DaVinci/Keystone SoC"
depends on ARCH_DAVINCI depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
help help
Enable the driver for NAND flash chips on Texas Instruments Enable the driver for NAND flash chips on Texas Instruments
DaVinci processors. DaVinci/Keystone processors.
config MTD_NAND_TXX9NDFMC config MTD_NAND_TXX9NDFMC
tristate "NAND Flash support for TXx9 SoC" tristate "NAND Flash support for TXx9 SoC"

View File

@ -1961,10 +1961,8 @@ static int atmel_nand_probe(struct platform_device *pdev)
/* Allocate memory for the device structure (and zero it) */ /* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host) { if (!host)
printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
return -ENOMEM; return -ENOMEM;
}
res = platform_driver_register(&atmel_nand_nfc_driver); res = platform_driver_register(&atmel_nand_nfc_driver);
if (res) if (res)
@ -2062,14 +2060,14 @@ static int atmel_nand_probe(struct platform_device *pdev)
} }
if (gpio_get_value(host->board.det_pin)) { 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; res = -ENXIO;
goto err_no_card; goto err_no_card;
} }
} }
if (host->board.on_flash_bbt || on_flash_bbt) { 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; nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
} }

View File

@ -418,10 +418,8 @@ static int au1550nd_probe(struct platform_device *pdev)
} }
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) { if (!ctx)
dev_err(&pdev->dev, "no memory for NAND context\n");
return -ENOMEM; return -ENOMEM;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) { if (!r) {
@ -480,6 +478,8 @@ static int au1550nd_probe(struct platform_device *pdev)
mtd_device_register(&ctx->info, pd->parts, pd->num_parts); mtd_device_register(&ctx->info, pd->parts, pd->num_parts);
platform_set_drvdata(pdev, ctx);
return 0; return 0;
out3: out3:

View File

@ -745,7 +745,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) { if (info == NULL) {
dev_err(&pdev->dev, "no memory for flash info\n");
err = -ENOMEM; err = -ENOMEM;
goto out_err_kzalloc; goto out_err_kzalloc;
} }

View File

@ -640,10 +640,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
pci_set_master(pdev); pci_set_master(pdev);
mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL); mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL);
if (!mtd) { if (!mtd)
dev_warn(&pdev->dev, "failed to alloc mtd_info\n");
return -ENOMEM; return -ENOMEM;
}
cafe = (void *)(&mtd[1]); cafe = (void *)(&mtd[1]);
mtd->dev.parent = &pdev->dev; mtd->dev.parent = &pdev->dev;

View File

@ -164,7 +164,6 @@ static int __init cmx270_init(void)
sizeof(struct nand_chip), sizeof(struct nand_chip),
GFP_KERNEL); GFP_KERNEL);
if (!cmx270_nand_mtd) { if (!cmx270_nand_mtd) {
pr_debug("Unable to allocate CM-X270 NAND MTD device structure.\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err_kzalloc; goto err_kzalloc;
} }

View File

@ -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 */ /* Allocate memory for MTD device structure and private data */
new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!new_mtd) { if (!new_mtd) {
printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n");
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }

View File

@ -35,6 +35,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_mtd.h>
#include <linux/platform_data/mtd-davinci.h> #include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.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 * ten ECC bytes plus the manufacturer's bad block marker byte, and
* and not overlapping the default BBT markers. * and not overlapping the default BBT markers.
*/ */
static struct nand_ecclayout hwecc4_small __initconst = { static struct nand_ecclayout hwecc4_small = {
.eccbytes = 10, .eccbytes = 10,
.eccpos = { 0, 1, 2, 3, 4, .eccpos = { 0, 1, 2, 3, 4,
/* offset 5 holds the badblock marker */ /* 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, * storing ten ECC bytes plus the manufacturer's bad block marker byte,
* and not overlapping the default BBT markers. * and not overlapping the default BBT markers.
*/ */
static struct nand_ecclayout hwecc4_2048 __initconst = { static struct nand_ecclayout hwecc4_2048 = {
.eccbytes = 40, .eccbytes = 40,
.eccpos = { .eccpos = {
/* at the end of spare sector */ /* at the end of spare sector */
@ -534,17 +535,19 @@ static struct davinci_nand_pdata
struct davinci_nand_pdata *pdata; struct davinci_nand_pdata *pdata;
const char *mode; const char *mode;
u32 prop; u32 prop;
int len;
pdata = devm_kzalloc(&pdev->dev, pdata = devm_kzalloc(&pdev->dev,
sizeof(struct davinci_nand_pdata), sizeof(struct davinci_nand_pdata),
GFP_KERNEL); GFP_KERNEL);
pdev->dev.platform_data = pdata; pdev->dev.platform_data = pdata;
if (!pdata) if (!pdata)
return NULL; return ERR_PTR(-ENOMEM);
if (!of_property_read_u32(pdev->dev.of_node, if (!of_property_read_u32(pdev->dev.of_node,
"ti,davinci-chipselect", &prop)) "ti,davinci-chipselect", &prop))
pdev->id = prop; pdev->id = prop;
else
return ERR_PTR(-EINVAL);
if (!of_property_read_u32(pdev->dev.of_node, if (!of_property_read_u32(pdev->dev.of_node,
"ti,davinci-mask-ale", &prop)) "ti,davinci-mask-ale", &prop))
pdata->mask_ale = prop; pdata->mask_ale = prop;
@ -555,6 +558,8 @@ static struct davinci_nand_pdata
"ti,davinci-mask-chipsel", &prop)) "ti,davinci-mask-chipsel", &prop))
pdata->mask_chipsel = prop; pdata->mask_chipsel = prop;
if (!of_property_read_string(pdev->dev.of_node, 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)) { "ti,davinci-ecc-mode", &mode)) {
if (!strncmp("none", mode, 4)) if (!strncmp("none", mode, 4))
pdata->ecc_mode = NAND_ECC_NONE; pdata->ecc_mode = NAND_ECC_NONE;
@ -566,12 +571,16 @@ static struct davinci_nand_pdata
if (!of_property_read_u32(pdev->dev.of_node, if (!of_property_read_u32(pdev->dev.of_node,
"ti,davinci-ecc-bits", &prop)) "ti,davinci-ecc-bits", &prop))
pdata->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)) "ti,davinci-nand-buswidth", &prop))
if (prop == 16) if (prop == 16)
pdata->options |= NAND_BUSWIDTH_16; pdata->options |= NAND_BUSWIDTH_16;
if (of_find_property(pdev->dev.of_node, if (of_property_read_bool(pdev->dev.of_node,
"ti,davinci-nand-use-bbt", &len)) "nand-on-flash-bbt") ||
of_property_read_bool(pdev->dev.of_node,
"ti,davinci-nand-use-bbt"))
pdata->bbt_options = NAND_BBT_USE_FLASH; pdata->bbt_options = NAND_BBT_USE_FLASH;
} }
@ -585,7 +594,7 @@ static struct davinci_nand_pdata
} }
#endif #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_pdata *pdata;
struct davinci_nand_info *info; 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; nand_ecc_modes_t ecc_mode;
pdata = nand_davinci_get_pdata(pdev); pdata = nand_davinci_get_pdata(pdev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
/* insist on board-specific configuration */ /* insist on board-specific configuration */
if (!pdata) if (!pdata)
return -ENODEV; return -ENODEV;
@ -607,11 +619,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info) { if (!info)
dev_err(&pdev->dev, "unable to allocate memory\n"); return -ENOMEM;
ret = -ENOMEM;
goto err_nomem;
}
platform_set_drvdata(pdev, info); 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); res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res1 || !res2) { if (!res1 || !res2) {
dev_err(&pdev->dev, "resource missing\n"); dev_err(&pdev->dev, "resource missing\n");
ret = -EINVAL; return -EINVAL;
goto err_nomem;
} }
vaddr = devm_ioremap_resource(&pdev->dev, res1); vaddr = devm_ioremap_resource(&pdev->dev, res1);
if (IS_ERR(vaddr)) { if (IS_ERR(vaddr))
ret = PTR_ERR(vaddr); return PTR_ERR(vaddr);
goto err_ioremap;
} /*
base = devm_ioremap_resource(&pdev->dev, res2); * This registers range is used to setup NAND settings. In case with
if (IS_ERR(base)) { * TI AEMIF driver, the same memory address range is requested already
ret = PTR_ERR(base); * by AEMIF, so we cannot request it twice, just ioremap.
goto err_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; info->dev = &pdev->dev;
@ -699,7 +712,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
spin_unlock_irq(&davinci_nand_lock); spin_unlock_irq(&davinci_nand_lock);
if (ret == -EBUSY) if (ret == -EBUSY)
goto err_ecc; return ret;
info->chip.ecc.calculate = nand_davinci_calculate_4bit; info->chip.ecc.calculate = nand_davinci_calculate_4bit;
info->chip.ecc.correct = nand_davinci_correct_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; info->chip.ecc.strength = pdata->ecc_bits;
break; break;
default: default:
ret = -EINVAL; return -EINVAL;
goto err_ecc;
} }
info->chip.ecc.mode = ecc_mode; 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)) { if (IS_ERR(info->clk)) {
ret = PTR_ERR(info->clk); ret = PTR_ERR(info->clk);
dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret); dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
goto err_clk; return ret;
} }
ret = clk_prepare_enable(info->clk); ret = clk_prepare_enable(info->clk);
@ -753,7 +765,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
info->core_chipsel); info->core_chipsel);
if (ret < 0) { if (ret < 0) {
dev_dbg(&pdev->dev, "NAND timing values setup fail\n"); dev_dbg(&pdev->dev, "NAND timing values setup fail\n");
goto err_timing; goto err;
} }
spin_lock_irq(&davinci_nand_lock); 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); ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL);
if (ret < 0) { if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n"); 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 /* 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) { if (!chunks || info->mtd.oobsize < 16) {
dev_dbg(&pdev->dev, "too small\n"); dev_dbg(&pdev->dev, "too small\n");
ret = -EINVAL; ret = -EINVAL;
goto err_scan; goto err;
} }
/* For small page chips, preserve the manufacturer's /* 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 " dev_warn(&pdev->dev, "no 4-bit ECC support yet "
"for 4KiB-page NAND\n"); "for 4KiB-page NAND\n");
ret = -EIO; ret = -EIO;
goto err_scan; goto err;
syndrome_done: syndrome_done:
info->chip.ecc.layout = &info->ecclayout; info->chip.ecc.layout = &info->ecclayout;
@ -822,7 +834,7 @@ syndrome_done:
ret = nand_scan_tail(&info->mtd); ret = nand_scan_tail(&info->mtd);
if (ret < 0) if (ret < 0)
goto err_scan; goto err;
if (pdata->parts) if (pdata->parts)
ret = mtd_device_parse_register(&info->mtd, NULL, NULL, ret = mtd_device_parse_register(&info->mtd, NULL, NULL,
@ -835,7 +847,7 @@ syndrome_done:
NULL, 0); NULL, 0);
} }
if (ret < 0) if (ret < 0)
goto err_scan; goto err;
val = davinci_nand_readl(info, NRCSR_OFFSET); val = davinci_nand_readl(info, NRCSR_OFFSET);
dev_info(&pdev->dev, "controller rev. %d.%d\n", dev_info(&pdev->dev, "controller rev. %d.%d\n",
@ -843,8 +855,7 @@ syndrome_done:
return 0; return 0;
err_scan: err:
err_timing:
clk_disable_unprepare(info->clk); clk_disable_unprepare(info->clk);
err_clk_enable: err_clk_enable:
@ -852,15 +863,10 @@ err_clk_enable:
if (ecc_mode == NAND_ECC_HW_SYNDROME) if (ecc_mode == NAND_ECC_HW_SYNDROME)
ecc4_busy = false; ecc4_busy = false;
spin_unlock_irq(&davinci_nand_lock); spin_unlock_irq(&davinci_nand_lock);
err_ecc:
err_clk:
err_ioremap:
err_nomem:
return ret; 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); 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 = { static struct platform_driver nand_davinci_driver = {
.remove = __exit_p(nand_davinci_remove), .probe = nand_davinci_probe,
.remove = nand_davinci_remove,
.driver = { .driver = {
.name = "davinci_nand", .name = "davinci_nand",
.owner = THIS_MODULE, .owner = THIS_MODULE,
@ -886,7 +893,7 @@ static struct platform_driver nand_davinci_driver = {
}; };
MODULE_ALIAS("platform:davinci_nand"); 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_LICENSE("GPL");
MODULE_AUTHOR("Texas Instruments"); MODULE_AUTHOR("Texas Instruments");

View File

@ -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) 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; 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 /* this function examines buffers to see if they contain data that
* indicate that the buffer is part of an erased region of flash. * 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; int i = 0;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
@ -1429,20 +1428,12 @@ int denali_init(struct denali_nand_info *denali)
} }
} }
/* Is 32-bit DMA supported? */ /* allocate a temporary buffer for nand_scan_ident() */
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32)); denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE,
if (ret) { GFP_DMA | GFP_KERNEL);
pr_err("Spectra: no usable DMA configuration\n"); if (!denali->buf.buf)
return ret; return -ENOMEM;
}
denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
DENALI_BUF_SIZE,
DMA_BIDIRECTIONAL);
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->mtd.dev.parent = denali->dev;
denali_hw_init(denali); denali_hw_init(denali);
denali_drv_init(denali); denali_drv_init(denali);
@ -1475,12 +1466,29 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq; goto failed_req_irq;
} }
/* MTD supported page sizes vary by kernel. We validate our /* allocate the right size buffer now */
* kernel supports the device here. devm_kfree(denali->dev, denali->buf.buf);
*/ denali->buf.buf = devm_kzalloc(denali->dev,
if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) { denali->mtd.writesize + denali->mtd.oobsize,
ret = -ENODEV; GFP_KERNEL);
pr_err("Spectra: device size not supported by this version of MTD."); 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; goto failed_req_irq;
} }
@ -1602,7 +1610,8 @@ EXPORT_SYMBOL(denali_init);
void denali_remove(struct denali_nand_info *denali) void denali_remove(struct denali_nand_info *denali)
{ {
denali_irq_cleanup(denali->irq, 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); DMA_BIDIRECTIONAL);
} }
EXPORT_SYMBOL(denali_remove); EXPORT_SYMBOL(denali_remove);

View File

@ -455,12 +455,10 @@
#define ECC_SECTOR_SIZE 512 #define ECC_SECTOR_SIZE 512
#define DENALI_BUF_SIZE (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE)
struct nand_buf { struct nand_buf {
int head; int head;
int tail; int tail;
uint8_t buf[DENALI_BUF_SIZE]; uint8_t *buf;
dma_addr_t dma_buf; dma_addr_t dma_buf;
}; };

View File

@ -108,7 +108,7 @@ static int denali_dt_probe(struct platform_device *ofdev)
denali->dev->dma_mask = NULL; 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)) { if (IS_ERR(dt->clk)) {
dev_err(&ofdev->dev, "no clk available\n"); dev_err(&ofdev->dev, "no clk available\n");
return PTR_ERR(dt->clk); return PTR_ERR(dt->clk);
@ -124,7 +124,6 @@ static int denali_dt_probe(struct platform_device *ofdev)
out_disable_clk: out_disable_clk:
clk_disable_unprepare(dt->clk); clk_disable_unprepare(dt->clk);
clk_put(dt->clk);
return ret; return ret;
} }
@ -135,7 +134,6 @@ static int denali_dt_remove(struct platform_device *ofdev)
denali_remove(&dt->denali); denali_remove(&dt->denali);
clk_disable(dt->clk); clk_disable(dt->clk);
clk_put(dt->clk);
return 0; return 0;
} }

View File

@ -21,7 +21,7 @@
#define DENALI_NAND_NAME "denali-nand-pci" #define DENALI_NAND_NAME "denali-nand-pci"
/* List of platforms this NAND controller has be integrated into */ /* 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, 0x0701), INTEL_CE4100 },
{ PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
{ /* end: all zeroes */ } { /* end: all zeroes */ }
@ -131,7 +131,6 @@ static struct pci_driver denali_pci_driver = {
static int denali_init_pci(void) 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); return pci_register_driver(&denali_pci_driver);
} }
module_init(denali_init_pci); module_init(denali_init_pci);

View File

@ -1058,7 +1058,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
buf = kmalloc(mtd->writesize, GFP_KERNEL); buf = kmalloc(mtd->writesize, GFP_KERNEL);
if (!buf) { if (!buf) {
printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
return 0; return 0;
} }
if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1))) 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); buf = kmalloc(mtd->writesize, GFP_KERNEL);
if (!buf) { if (!buf) {
printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
return 0; return 0;
} }
@ -1440,10 +1438,13 @@ static int __init doc_probe(unsigned long physadr)
int reg, len, numchips; int reg, len, numchips;
int ret = 0; int ret = 0;
if (!request_mem_region(physadr, DOC_IOREMAP_LEN, NULL))
return -EBUSY;
virtadr = ioremap(physadr, DOC_IOREMAP_LEN); virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
if (!virtadr) { if (!virtadr) {
printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr); 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 /* 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)); sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));
mtd = kzalloc(len, GFP_KERNEL); mtd = kzalloc(len, GFP_KERNEL);
if (!mtd) { if (!mtd) {
printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
} }
@ -1629,6 +1629,10 @@ static int __init doc_probe(unsigned long physadr)
WriteDOC(save_control, virtadr, DOCControl); WriteDOC(save_control, virtadr, DOCControl);
fail: fail:
iounmap(virtadr); iounmap(virtadr);
error_ioremap:
release_mem_region(physadr, DOC_IOREMAP_LEN);
return ret; return ret;
} }
@ -1645,6 +1649,7 @@ static void release_nanddoc(void)
nextmtd = doc->nextdoc; nextmtd = doc->nextdoc;
nand_release(mtd); nand_release(mtd);
iounmap(doc->virtadr); iounmap(doc->virtadr);
release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
kfree(mtd); kfree(mtd);
} }
} }

View File

@ -847,7 +847,6 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
if (!fsl_lbc_ctrl_dev->nand) { if (!fsl_lbc_ctrl_dev->nand) {
elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
if (!elbc_fcm_ctrl) { if (!elbc_fcm_ctrl) {
dev_err(dev, "failed to allocate memory\n");
mutex_unlock(&fsl_elbc_nand_mutex); mutex_unlock(&fsl_elbc_nand_mutex);
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
@ -875,7 +874,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
goto err; 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) { if (!priv->mtd.name) {
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;

View File

@ -1060,7 +1060,6 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
if (!fsl_ifc_ctrl_dev->nand) { if (!fsl_ifc_ctrl_dev->nand) {
ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL); ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
if (!ifc_nand_ctrl) { if (!ifc_nand_ctrl) {
dev_err(&dev->dev, "failed to allocate memory\n");
mutex_unlock(&fsl_ifc_nand_mutex); mutex_unlock(&fsl_ifc_nand_mutex);
return -ENOMEM; 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_FTOERIR_EN |
IFC_NAND_EVTER_INTR_WPERIR_EN, IFC_NAND_EVTER_INTR_WPERIR_EN,
&ifc->ifc_nand.nand_evter_intr_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) { if (!priv->mtd.name) {
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;

View File

@ -889,10 +889,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
pdata->nand_timings = devm_kzalloc(&pdev->dev, pdata->nand_timings = devm_kzalloc(&pdev->dev,
sizeof(*pdata->nand_timings), GFP_KERNEL); sizeof(*pdata->nand_timings), GFP_KERNEL);
if (!pdata->nand_timings) { if (!pdata->nand_timings)
dev_err(&pdev->dev, "no memory for nand_timing\n");
return -ENOMEM; return -ENOMEM;
}
of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings, of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
sizeof(*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) */ /* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host) { if (!host)
dev_err(&pdev->dev, "failed to allocate device structure\n");
return -ENOMEM; return -ENOMEM;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
host->data_va = devm_ioremap_resource(&pdev->dev, res); 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; host->ecc_place = &fsmc_ecc4_lp_place;
break; break;
default: default:
printk(KERN_WARNING "No oob scheme defined for " dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
"oobsize %d\n", mtd->oobsize); mtd->oobsize);
BUG(); BUG();
} }
} else { } else {
@ -1124,8 +1120,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
nand->ecc.layout = &fsmc_ecc1_128_layout; nand->ecc.layout = &fsmc_ecc1_128_layout;
break; break;
default: default:
printk(KERN_WARNING "No oob scheme defined for " dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
"oobsize %d\n", mtd->oobsize); mtd->oobsize);
BUG(); BUG();
} }
} }

View File

@ -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) 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; 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)) "gpio-control-nand,io-sync-reg", &addr))
return NULL; return NULL;
r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
if (!r)
return NULL;
r->start = addr; r->start = addr;
r->end = r->start + 0x3; r->end = r->start + 0x3;
r->flags = IORESOURCE_MEM; r->flags = IORESOURCE_MEM;
@ -211,10 +215,8 @@ static int gpio_nand_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL); gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
if (!gpiomtd) { if (!gpiomtd)
dev_err(&pdev->dev, "failed to create NAND MTD\n");
return -ENOMEM; return -ENOMEM;
}
chip = &gpiomtd->nand_chip; chip = &gpiomtd->nand_chip;

View File

@ -20,6 +20,7 @@
*/ */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/slab.h>
#include "gpmi-nand.h" #include "gpmi-nand.h"
#include "gpmi-regs.h" #include "gpmi-regs.h"
@ -207,30 +208,41 @@ void gpmi_dump_info(struct gpmi_nand_data *this)
u32 reg; u32 reg;
int i; 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++) { for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
reg = readl(r->gpmi_regs + i * 0x10); 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 */ /* 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++) { for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
reg = readl(r->bch_regs + i * 0x10); 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"); dev_err(this->dev, "BCH Geometry :\n"
pr_err("GF length : %u\n", geo->gf_len); "GF length : %u\n"
pr_err("ECC Strength : %u\n", geo->ecc_strength); "ECC Strength : %u\n"
pr_err("Page Size in Bytes : %u\n", geo->page_size); "Page Size in Bytes : %u\n"
pr_err("Metadata Size in Bytes : %u\n", geo->metadata_size); "Metadata Size in Bytes : %u\n"
pr_err("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size); "ECC Chunk Size in Bytes: %u\n"
pr_err("ECC Chunk Count : %u\n", geo->ecc_chunk_count); "ECC Chunk Count : %u\n"
pr_err("Payload Size in Bytes : %u\n", geo->payload_size); "Payload Size in Bytes : %u\n"
pr_err("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size); "Auxiliary Size in Bytes: %u\n"
pr_err("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset); "Auxiliary Status Offset: %u\n"
pr_err("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset); "Block Mark Byte Offset : %u\n"
pr_err("Block Mark Bit Offset : %u\n", geo->block_mark_bit_offset); "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. */ /* 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. * 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 * On the other hand, the MX28 needs the reset, because one case has been
* seen where the BCH produced ECC errors constantly after 10000 * seen where the BCH produced ECC errors constantly after 10000
* consecutive reboots. The latter case has not been seen on the MX23 yet, * consecutive reboots. The latter case has not been seen on the MX23
* still we don't know if it could happen there as well. * yet, still we don't know if it could happen there as well.
*/ */
ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this)); ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
if (ret) if (ret)
@ -353,7 +365,7 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
improved_timing_is_available = improved_timing_is_available =
(target.tREA_in_ns >= 0) && (target.tREA_in_ns >= 0) &&
(target.tRLOH_in_ns >= 0) && (target.tRLOH_in_ns >= 0) &&
(target.tRHOH_in_ns >= 0) ; (target.tRHOH_in_ns >= 0);
/* Inspect the clock. */ /* Inspect the clock. */
nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]); 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 resources *r = &this->resources;
struct nand_chip *nand = &this->nand; struct nand_chip *nand = &this->nand;
struct mtd_info *mtd = &this->mtd; struct mtd_info *mtd = &this->mtd;
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; uint8_t *feature;
unsigned long rate; unsigned long rate;
int ret; int ret;
feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL);
if (!feature)
return -ENOMEM;
nand->select_chip(mtd, 0); nand->select_chip(mtd, 0);
/* [1] send SET FEATURE commond to NAND */ /* [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->flags |= GPMI_ASYNC_EDO_ENABLED;
this->timing_mode = mode; this->timing_mode = mode;
kfree(feature);
dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode); dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode);
return 0; return 0;
err_out: err_out:
nand->select_chip(mtd, -1); nand->select_chip(mtd, -1);
kfree(feature);
dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode); dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode);
return -EINVAL; return -EINVAL;
} }
@ -986,7 +1004,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
/* Enable the clock. */ /* Enable the clock. */
ret = gpmi_enable_clk(this); ret = gpmi_enable_clk(this);
if (ret) { 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; goto err_out;
} }
@ -1003,7 +1021,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
/* [1] Set HW_GPMI_TIMING0 */ /* [1] Set HW_GPMI_TIMING0 */
reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | 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_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); 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); mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
reg = readl(r->gpmi_regs + HW_GPMI_STAT); reg = readl(r->gpmi_regs + HW_GPMI_STAT);
} else } else
pr_err("unknow arch.\n"); dev_err(this->dev, "unknow arch.\n");
return reg & mask; return reg & mask;
} }
@ -1121,10 +1139,8 @@ int gpmi_send_command(struct gpmi_nand_data *this)
desc = dmaengine_prep_slave_sg(channel, desc = dmaengine_prep_slave_sg(channel,
(struct scatterlist *)pio, (struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
if (!desc) { if (!desc)
pr_err("step 1 error\n"); return -EINVAL;
return -1;
}
/* [2] send out the COMMAND + ADDRESS string stored in @buffer */ /* [2] send out the COMMAND + ADDRESS string stored in @buffer */
sgl = &this->cmd_sgl; sgl = &this->cmd_sgl;
@ -1134,11 +1150,8 @@ int gpmi_send_command(struct gpmi_nand_data *this)
desc = dmaengine_prep_slave_sg(channel, desc = dmaengine_prep_slave_sg(channel,
sgl, 1, DMA_MEM_TO_DEV, sgl, 1, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
if (!desc) { return -EINVAL;
pr_err("step 2 error\n");
return -1;
}
/* [3] submit the DMA */ /* [3] submit the DMA */
set_dma_type(this, DMA_FOR_COMMAND); set_dma_type(this, DMA_FOR_COMMAND);
@ -1167,20 +1180,17 @@ int gpmi_send_data(struct gpmi_nand_data *this)
pio[1] = 0; pio[1] = 0;
desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
if (!desc) { if (!desc)
pr_err("step 1 error\n"); return -EINVAL;
return -1;
}
/* [2] send DMA request */ /* [2] send DMA request */
prepare_data_dma(this, DMA_TO_DEVICE); prepare_data_dma(this, DMA_TO_DEVICE);
desc = dmaengine_prep_slave_sg(channel, &this->data_sgl, desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
1, DMA_MEM_TO_DEV, 1, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) { if (!desc)
pr_err("step 2 error\n"); return -EINVAL;
return -1;
}
/* [3] submit the DMA */ /* [3] submit the DMA */
set_dma_type(this, DMA_FOR_WRITE_DATA); set_dma_type(this, DMA_FOR_WRITE_DATA);
return start_dma_without_bch_irq(this, desc); 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, desc = dmaengine_prep_slave_sg(channel,
(struct scatterlist *)pio, (struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
if (!desc) { if (!desc)
pr_err("step 1 error\n"); return -EINVAL;
return -1;
}
/* [2] : send DMA request */ /* [2] : send DMA request */
prepare_data_dma(this, DMA_FROM_DEVICE); prepare_data_dma(this, DMA_FROM_DEVICE);
desc = dmaengine_prep_slave_sg(channel, &this->data_sgl, desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
1, DMA_DEV_TO_MEM, 1, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) { if (!desc)
pr_err("step 2 error\n"); return -EINVAL;
return -1;
}
/* [3] : submit the DMA */ /* [3] : submit the DMA */
set_dma_type(this, DMA_FOR_READ_DATA); set_dma_type(this, DMA_FOR_READ_DATA);
@ -1262,10 +1268,9 @@ int gpmi_send_page(struct gpmi_nand_data *this,
(struct scatterlist *)pio, (struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, ARRAY_SIZE(pio), DMA_TRANS_NONE,
DMA_CTRL_ACK); DMA_CTRL_ACK);
if (!desc) { if (!desc)
pr_err("step 2 error\n"); return -EINVAL;
return -1;
}
set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE); set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE);
return start_dma_with_bch_irq(this, desc); 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, desc = dmaengine_prep_slave_sg(channel,
(struct scatterlist *)pio, 2, (struct scatterlist *)pio, 2,
DMA_TRANS_NONE, 0); DMA_TRANS_NONE, 0);
if (!desc) { if (!desc)
pr_err("step 1 error\n"); return -EINVAL;
return -1;
}
/* [2] Enable the BCH block and read. */ /* [2] Enable the BCH block and read. */
command_mode = BV_GPMI_CTRL0_COMMAND_MODE__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, (struct scatterlist *)pio,
ARRAY_SIZE(pio), DMA_TRANS_NONE, ARRAY_SIZE(pio), DMA_TRANS_NONE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) { if (!desc)
pr_err("step 2 error\n"); return -EINVAL;
return -1;
}
/* [3] Disable the BCH block */ /* [3] Disable the BCH block */
command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; 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, (struct scatterlist *)pio, 3,
DMA_TRANS_NONE, DMA_TRANS_NONE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) { if (!desc)
pr_err("step 3 error\n"); return -EINVAL;
return -1;
}
/* [4] submit the DMA */ /* [4] submit the DMA */
set_dma_type(this, DMA_FOR_READ_ECC_PAGE); set_dma_type(this, DMA_FOR_READ_ECC_PAGE);

View File

@ -18,9 +18,6 @@
* with this program; if not, write to the Free Software Foundation, Inc., * with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.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) 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); 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; struct scatterlist *sgl = &this->data_sgl;
int ret; int ret;
this->direct_dma_map_ok = true;
/* first try to map the upper buffer directly */ /* first try to map the upper buffer directly */
sg_init_one(sgl, this->upper_buf, this->upper_len); if (virt_addr_valid(this->upper_buf) &&
ret = dma_map_sg(this->dev, sgl, 1, dr); !object_is_on_stack(this->upper_buf)) {
if (ret == 0) { sg_init_one(sgl, this->upper_buf, this->upper_len);
/* 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);
ret = dma_map_sg(this->dev, sgl, 1, dr); ret = dma_map_sg(this->dev, sgl, 1, dr);
if (ret == 0) 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. */ /* This will be called after the DMA operation is finished. */
@ -416,7 +419,7 @@ static void dma_irq_callback(void *param)
break; break;
default: default:
pr_err("in wrong DMA operation.\n"); dev_err(this->dev, "in wrong DMA operation.\n");
} }
complete(dma_c); 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. */ /* Wait for the interrupt from the DMA block. */
err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
if (!err) { 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); gpmi_dump_info(this);
return -ETIMEDOUT; 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. */ /* Wait for the interrupt from the BCH block. */
err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
if (!err) { 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); gpmi_dump_info(this);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
@ -483,70 +488,38 @@ static int acquire_register_block(struct gpmi_nand_data *this,
void __iomem *p; void __iomem *p;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
if (!r) { p = devm_ioremap_resource(&pdev->dev, r);
pr_err("Can't get resource for %s\n", res_name); if (IS_ERR(p))
return -ENODEV; return PTR_ERR(p);
}
p = ioremap(r->start, resource_size(r));
if (!p) {
pr_err("Can't remap %s\n", res_name);
return -ENOMEM;
}
if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME)) if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME))
res->gpmi_regs = p; res->gpmi_regs = p;
else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME)) else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME))
res->bch_regs = p; res->bch_regs = p;
else else
pr_err("unknown resource name : %s\n", res_name); dev_err(this->dev, "unknown resource name : %s\n", res_name);
return 0; 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) static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
{ {
struct platform_device *pdev = this->pdev; struct platform_device *pdev = this->pdev;
struct resources *res = &this->resources;
const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME; const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME;
struct resource *r; struct resource *r;
int err; int err;
r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
if (!r) { 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; return -ENODEV;
} }
err = request_irq(r->start, irq_h, 0, res_name, this); err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this);
if (err) { if (err)
pr_err("Can't own %s\n", res_name); dev_err(this->dev, "error requesting BCH IRQ\n");
return err;
}
res->bch_low_interrupt = r->start; return err;
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);
} }
static void release_dma_channels(struct gpmi_nand_data *this) 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 */ /* request dma channel */
dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx"); dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx");
if (!dma_chan) { if (!dma_chan) {
pr_err("Failed to request DMA channel.\n"); dev_err(this->dev, "Failed to request DMA channel.\n");
goto acquire_err; goto acquire_err;
} }
@ -579,21 +552,6 @@ acquire_err:
return -EINVAL; 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] = { static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
"gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", "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; int err, i;
/* The main clock is stored in the first. */ /* 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])) { if (IS_ERR(r->clock[0])) {
err = PTR_ERR(r->clock[0]); err = PTR_ERR(r->clock[0]);
goto err_clock; goto err_clock;
@ -622,7 +580,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
if (extra_clks[i - 1] == NULL) if (extra_clks[i - 1] == NULL)
break; break;
clk = clk_get(this->dev, extra_clks[i - 1]); clk = devm_clk_get(this->dev, extra_clks[i - 1]);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
err = PTR_ERR(clk); err = PTR_ERR(clk);
goto err_clock; goto err_clock;
@ -644,7 +602,6 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
err_clock: err_clock:
dev_dbg(this->dev, "failed in finding the clocks.\n"); dev_dbg(this->dev, "failed in finding the clocks.\n");
gpmi_put_clks(this);
return err; return err;
} }
@ -666,7 +623,7 @@ static int acquire_resources(struct gpmi_nand_data *this)
ret = acquire_dma_channels(this); ret = acquire_dma_channels(this);
if (ret) if (ret)
goto exit_dma_channels; goto exit_regs;
ret = gpmi_get_clks(this); ret = gpmi_get_clks(this);
if (ret) if (ret)
@ -675,18 +632,12 @@ static int acquire_resources(struct gpmi_nand_data *this)
exit_clock: exit_clock:
release_dma_channels(this); release_dma_channels(this);
exit_dma_channels:
release_bch_irq(this);
exit_regs: exit_regs:
release_register_block(this);
return ret; return ret;
} }
static void release_resources(struct gpmi_nand_data *this) 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); release_dma_channels(this);
} }
@ -732,8 +683,7 @@ static int read_page_prepare(struct gpmi_nand_data *this,
length, DMA_FROM_DEVICE); length, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, dest_phys)) { if (dma_mapping_error(dev, dest_phys)) {
if (alt_size < length) { if (alt_size < length) {
pr_err("%s, Alternate buffer is too small\n", dev_err(dev, "Alternate buffer is too small\n");
__func__);
return -ENOMEM; return -ENOMEM;
} }
goto map_failed; goto map_failed;
@ -783,8 +733,7 @@ static int send_page_prepare(struct gpmi_nand_data *this,
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (dma_mapping_error(dev, source_phys)) { if (dma_mapping_error(dev, source_phys)) {
if (alt_size < length) { if (alt_size < length) {
pr_err("%s, Alternate buffer is too small\n", dev_err(dev, "Alternate buffer is too small\n");
__func__);
return -ENOMEM; return -ENOMEM;
} }
goto map_failed; 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 bch_geometry *geo = &this->bch_geometry;
struct device *dev = this->dev; struct device *dev = this->dev;
struct mtd_info *mtd = &this->mtd;
/* [1] Allocate a command buffer. PAGE_SIZE is enough. */ /* [1] Allocate a command buffer. PAGE_SIZE is enough. */
this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL); this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
if (this->cmd_buffer == NULL) if (this->cmd_buffer == NULL)
goto error_alloc; 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) if (this->data_buffer_dma == NULL)
goto error_alloc; goto error_alloc;
@ -872,7 +830,6 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
error_alloc: error_alloc:
gpmi_free_dma_buffer(this); gpmi_free_dma_buffer(this);
pr_err("Error allocating DMA buffers!\n");
return -ENOMEM; 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); ret = gpmi_send_command(this);
if (ret) 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; 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 nand_chip *chip = mtd->priv;
struct gpmi_nand_data *this = chip->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_buf = buf;
this->upper_len = len; 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 nand_chip *chip = mtd->priv;
struct gpmi_nand_data *this = chip->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_buf = (uint8_t *)buf;
this->upper_len = len; 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; unsigned int max_bitflips = 0;
int ret; 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, ret = read_page_prepare(this, buf, mtd->writesize,
this->payload_virt, this->payload_phys, this->payload_virt, this->payload_phys,
nfc_geo->payload_size, nfc_geo->payload_size,
&payload_virt, &payload_phys); &payload_virt, &payload_phys);
if (ret) { if (ret) {
pr_err("Inadequate DMA buffer\n"); dev_err(this->dev, "Inadequate DMA buffer\n");
ret = -ENOMEM; ret = -ENOMEM;
return ret; return ret;
} }
@ -1046,7 +1004,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
nfc_geo->payload_size, nfc_geo->payload_size,
payload_virt, payload_phys); payload_virt, payload_phys);
if (ret) { 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; 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; dma_addr_t auxiliary_phys;
int ret; int ret;
pr_debug("ecc write page.\n"); dev_dbg(this->dev, "ecc write page.\n");
if (this->swap_block_mark) { if (this->swap_block_mark) {
/* /*
* If control arrives here, we're doing block mark swapping. * 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, nfc_geo->payload_size,
&payload_virt, &payload_phys); &payload_virt, &payload_phys);
if (ret) { if (ret) {
pr_err("Inadequate payload DMA buffer\n"); dev_err(this->dev, "Inadequate payload DMA buffer\n");
return 0; return 0;
} }
@ -1142,7 +1100,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
nfc_geo->auxiliary_size, nfc_geo->auxiliary_size,
&auxiliary_virt, &auxiliary_phys); &auxiliary_virt, &auxiliary_phys);
if (ret) { if (ret) {
pr_err("Inadequate auxiliary DMA buffer\n"); dev_err(this->dev, "Inadequate auxiliary DMA buffer\n");
goto exit_auxiliary; goto exit_auxiliary;
} }
} }
@ -1150,7 +1108,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
/* Ask the NFC. */ /* Ask the NFC. */
ret = gpmi_send_page(this, payload_phys, auxiliary_phys); ret = gpmi_send_page(this, payload_phys, auxiliary_phys);
if (ret) 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) { if (!this->swap_block_mark) {
send_page_end(this, chip->oob_poi, mtd->oobsize, 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; 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 */ /* clear the OOB buffer */
memset(chip->oob_poi, ~0, mtd->oobsize); 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. */ /* Write the NCB fingerprint into the page buffer. */
memset(buffer, ~0, mtd->writesize); memset(buffer, ~0, mtd->writesize);
memset(chip->oob_poi, ~0, mtd->oobsize);
memcpy(buffer + 12, fingerprint, strlen(fingerprint)); memcpy(buffer + 12, fingerprint, strlen(fingerprint));
/* Loop through the first search area, writing NCB fingerprints. */ /* 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. */ /* Set up the NFC geometry which is used by BCH. */
ret = bch_set_geometry(this); ret = bch_set_geometry(this);
if (ret) { if (ret) {
pr_err("Error setting BCH geometry : %d\n", ret); dev_err(this->dev, "Error setting BCH geometry : %d\n", ret);
return ret; return ret;
} }
@ -1576,20 +1533,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
return gpmi_alloc_dma_buffer(this); return gpmi_alloc_dma_buffer(this);
} }
static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) static void gpmi_nand_exit(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)
{ {
nand_release(&this->mtd); nand_release(&this->mtd);
gpmi_free_dma_buffer(this); 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; struct bch_geometry *bch_geo = &this->bch_geometry;
int ret; int ret;
/* Prepare for the BBT scan. */ /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
ret = gpmi_pre_bbt_scan(this); this->swap_block_mark = !GPMI_IS_MX23(this);
/* Set up the medium geometry */
ret = gpmi_set_geometry(this);
if (ret) if (ret)
return ret; return ret;
@ -1629,7 +1576,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
return 0; 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 mtd_info *mtd = &this->mtd;
struct nand_chip *chip = &this->nand; struct nand_chip *chip = &this->nand;
@ -1693,7 +1640,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
return 0; return 0;
err_out: err_out:
gpmi_nfc_exit(this); gpmi_nand_exit(this);
return ret; return ret;
} }
@ -1728,15 +1675,13 @@ static int gpmi_nand_probe(struct platform_device *pdev)
if (of_id) { if (of_id) {
pdev->id_entry = of_id->data; pdev->id_entry = of_id->data;
} else { } 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; return -ENODEV;
} }
this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL); this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
if (!this) { if (!this)
pr_err("Failed to allocate per-device memory\n");
return -ENOMEM; return -ENOMEM;
}
platform_set_drvdata(pdev, this); platform_set_drvdata(pdev, this);
this->pdev = pdev; this->pdev = pdev;
@ -1750,7 +1695,7 @@ static int gpmi_nand_probe(struct platform_device *pdev)
if (ret) if (ret)
goto exit_nfc_init; goto exit_nfc_init;
ret = gpmi_nfc_init(this); ret = gpmi_nand_init(this);
if (ret) if (ret)
goto exit_nfc_init; 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); struct gpmi_nand_data *this = platform_get_drvdata(pdev);
gpmi_nfc_exit(this); gpmi_nand_exit(this);
release_resources(this); release_resources(this);
return 0; return 0;
} }

View File

@ -26,8 +26,6 @@
struct resources { struct resources {
void __iomem *gpmi_regs; void __iomem *gpmi_regs;
void __iomem *bch_regs; void __iomem *bch_regs;
unsigned int bch_low_interrupt;
unsigned int bch_high_interrupt;
unsigned int dma_low_channel; unsigned int dma_low_channel;
unsigned int dma_high_channel; unsigned int dma_high_channel;
struct clk *clock[GPMI_CLK_MAX]; struct clk *clock[GPMI_CLK_MAX];

View File

@ -416,10 +416,8 @@ static int jz_nand_probe(struct platform_device *pdev)
uint8_t nand_maf_id = 0, nand_dev_id = 0; uint8_t nand_maf_id = 0, nand_dev_id = 0;
nand = kzalloc(sizeof(*nand), GFP_KERNEL); nand = kzalloc(sizeof(*nand), GFP_KERNEL);
if (!nand) { if (!nand)
dev_err(&pdev->dev, "Failed to allocate device structure.\n");
return -ENOMEM; return -ENOMEM;
}
ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
if (ret) if (ret)

View File

@ -539,20 +539,6 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
return 0; 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, static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) 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; struct device_node *np = dev->of_node;
ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL); ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
if (!ncfg) { if (!ncfg)
dev_err(dev, "could not allocate memory for platform data\n");
return NULL; return NULL;
}
of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay); of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay);
of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_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) */ /* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host) { if (!host)
dev_err(&pdev->dev, "failed to allocate device structure.\n");
return -ENOMEM; return -ENOMEM;
}
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, rc); 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.write_oob = lpc32xx_write_oob;
nand_chip->ecc.read_oob = lpc32xx_read_oob; nand_chip->ecc.read_oob = lpc32xx_read_oob;
nand_chip->ecc.strength = 4; nand_chip->ecc.strength = 4;
nand_chip->write_page = lpc32xx_write_page;
nand_chip->waitfunc = lpc32xx_waitfunc; 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_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
nand_chip->bbt_td = &lpc32xx_nand_bbt; nand_chip->bbt_td = &lpc32xx_nand_bbt;
nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror; 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); host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
if (!host->dma_buf) { if (!host->dma_buf) {
dev_err(&pdev->dev, "Error allocating dma_buf memory\n");
res = -ENOMEM; res = -ENOMEM;
goto err_exit3; goto err_exit3;
} }
host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
if (!host->dummy_buf) { if (!host->dummy_buf) {
dev_err(&pdev->dev, "Error allocating dummy_buf memory\n");
res = -ENOMEM; res = -ENOMEM;
goto err_exit3; goto err_exit3;
} }

View File

@ -725,10 +725,8 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL); ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
if (!ncfg) { if (!ncfg)
dev_err(dev, "could not allocate memory for NAND config\n");
return NULL; return NULL;
}
of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks); of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks);
of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth); 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) */ /* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host) { if (!host)
dev_err(&pdev->dev, "failed to allocate device structure\n");
return -ENOMEM; return -ENOMEM;
}
host->io_base_dma = rc->start; host->io_base_dma = rc->start;
host->io_base = devm_ioremap_resource(&pdev->dev, rc); 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) if (host->ncfg->wp_gpio == -EPROBE_DEFER)
return -EPROBE_DEFER; return -EPROBE_DEFER;
if (gpio_is_valid(host->ncfg->wp_gpio) && if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev,
gpio_request(host->ncfg->wp_gpio, "NAND WP")) { host->ncfg->wp_gpio, "NAND WP")) {
dev_err(&pdev->dev, "GPIO not available\n"); dev_err(&pdev->dev, "GPIO not available\n");
return -EBUSY; return -EBUSY;
} }
@ -808,7 +804,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev; mtd->dev.parent = &pdev->dev;
/* Get NAND clock */ /* Get NAND clock */
host->clk = clk_get(&pdev->dev, NULL); host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk)) { if (IS_ERR(host->clk)) {
dev_err(&pdev->dev, "Clock failure\n"); dev_err(&pdev->dev, "Clock failure\n");
res = -ENOENT; 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, host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
GFP_KERNEL); GFP_KERNEL);
if (host->data_buf == NULL) { if (host->data_buf == NULL) {
dev_err(&pdev->dev, "Error allocating memory\n");
res = -ENOMEM; res = -ENOMEM;
goto err_exit2; goto err_exit2;
} }
@ -927,10 +922,8 @@ err_exit3:
dma_release_channel(host->dma_chan); dma_release_channel(host->dma_chan);
err_exit2: err_exit2:
clk_disable(host->clk); clk_disable(host->clk);
clk_put(host->clk);
err_exit1: err_exit1:
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
gpio_free(host->ncfg->wp_gpio);
return res; return res;
} }
@ -953,9 +946,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
writel(tmp, SLC_CTRL(host->io_base)); writel(tmp, SLC_CTRL(host->io_base));
clk_disable(host->clk); clk_disable(host->clk);
clk_put(host->clk);
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
gpio_free(host->ncfg->wp_gpio);
return 0; return 0;
} }

View File

@ -653,10 +653,8 @@ static int mpc5121_nfc_probe(struct platform_device *op)
} }
prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL); prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
if (!prv) { if (!prv)
dev_err(dev, "Memory exhausted!\n");
return -ENOMEM; return -ENOMEM;
}
mtd = &prv->mtd; mtd = &prv->mtd;
chip = &prv->chip; chip = &prv->chip;
@ -786,7 +784,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
/* Detect NAND chips */ /* Detect NAND chips */
if (nand_scan(mtd, be32_to_cpup(chips_no))) { if (nand_scan(mtd, be32_to_cpup(chips_no))) {
dev_err(dev, "NAND Flash not found !\n"); dev_err(dev, "NAND Flash not found !\n");
devm_free_irq(dev, prv->irq, mtd);
retval = -ENXIO; retval = -ENXIO;
goto error; goto error;
} }
@ -811,7 +808,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
default: default:
dev_err(dev, "Unsupported NAND flash!\n"); dev_err(dev, "Unsupported NAND flash!\n");
devm_free_irq(dev, prv->irq, mtd);
retval = -ENXIO; retval = -ENXIO;
goto error; 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); retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
if (retval) { if (retval) {
dev_err(dev, "Error adding MTD device!\n"); dev_err(dev, "Error adding MTD device!\n");
devm_free_irq(dev, prv->irq, mtd);
goto error; goto error;
} }
@ -836,11 +831,8 @@ static int mpc5121_nfc_remove(struct platform_device *op)
{ {
struct device *dev = &op->dev; struct device *dev = &op->dev;
struct mtd_info *mtd = dev_get_drvdata(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); nand_release(mtd);
devm_free_irq(dev, prv->irq, mtd);
mpc5121_nfc_free(dev, mtd); mpc5121_nfc_free(dev, mtd);
return 0; return 0;

View File

@ -677,7 +677,6 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
ecc_stat >>= 4; ecc_stat >>= 4;
} while (--no_subpages); } while (--no_subpages);
mtd->ecc_stats.corrected += ret;
pr_debug("%d Symbol Correctable RS-ECC Error\n", ret); pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
return ret; return ret;
@ -1400,12 +1399,15 @@ static int mxcnd_probe(struct platform_device *pdev)
int err = 0; int err = 0;
/* Allocate memory for MTD device structure and private data */ /* Allocate memory for MTD device structure and private data */
host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) + host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL); GFP_KERNEL);
if (!host) if (!host)
return -ENOMEM; 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; host->dev = &pdev->dev;
/* structures must be linked */ /* structures must be linked */
@ -1512,7 +1514,9 @@ static int mxcnd_probe(struct platform_device *pdev)
if (err) if (err)
return err; return err;
clk_prepare_enable(host->clk); err = clk_prepare_enable(host->clk);
if (err)
return err;
host->clk_act = 1; host->clk_act = 1;
/* /*
@ -1531,6 +1535,15 @@ static int mxcnd_probe(struct platform_device *pdev)
goto escan; 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 */ /* Call preset again, with correct writesize this time */
host->devtype_data->preset(mtd); 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); struct mxc_nand_host *host = platform_get_drvdata(pdev);
nand_release(&host->mtd); nand_release(&host->mtd);
if (host->clk_act)
clk_disable_unprepare(host->clk);
return 0; return 0;
} }

View File

@ -29,6 +29,8 @@
* *
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/errno.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 * nand_write_buf - [DEFAULT] write buffer to chip
* @mtd: MTD device structure * @mtd: MTD device structure
@ -1407,6 +1454,30 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
return NULL; 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 * nand_do_read_ops - [INTERN] Read data with ECC
* @mtd: MTD device structure * @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; int chipnr, page, realpage, col, bytes, aligned, oob_required;
struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd->priv;
struct mtd_ecc_stats stats;
int ret = 0; int ret = 0;
uint32_t readlen = ops->len; uint32_t readlen = ops->len;
uint32_t oobreadlen = ops->ooblen; 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; uint8_t *bufpoi, *oob, *buf;
unsigned int max_bitflips = 0; unsigned int max_bitflips = 0;
int retry_mode = 0;
stats = mtd->ecc_stats; bool ecc_fail = false;
chipnr = (int)(from >> chip->chip_shift); chipnr = (int)(from >> chip->chip_shift);
chip->select_chip(mtd, chipnr); 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; oob_required = oob ? 1 : 0;
while (1) { while (1) {
unsigned int ecc_failures = mtd->ecc_stats.failed;
bytes = min(mtd->writesize - col, readlen); bytes = min(mtd->writesize - col, readlen);
aligned = (bytes == mtd->writesize); 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) { if (realpage != chip->pagebuf || oob) {
bufpoi = aligned ? buf : chip->buffers->databuf; bufpoi = aligned ? buf : chip->buffers->databuf;
read_retry:
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); 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 */ /* Transfer not aligned data */
if (!aligned) { if (!aligned) {
if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
!(mtd->ecc_stats.failed - stats.failed) && !(mtd->ecc_stats.failed - ecc_failures) &&
(ops->mode != MTD_OPS_RAW)) { (ops->mode != MTD_OPS_RAW)) {
chip->pagebuf = realpage; chip->pagebuf = realpage;
chip->pagebuf_bitflips = ret; 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); memcpy(buf, chip->buffers->databuf + col, bytes);
} }
buf += bytes;
if (unlikely(oob)) { if (unlikely(oob)) {
int toread = min(oobreadlen, max_oobsize); int toread = min(oobreadlen, max_oobsize);
@ -1511,6 +1582,25 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
else else
nand_wait_ready(mtd); 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 { } else {
memcpy(buf, chip->buffers->databuf + col, bytes); memcpy(buf, chip->buffers->databuf + col, bytes);
buf += bytes; buf += bytes;
@ -1520,6 +1610,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
readlen -= bytes; 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) if (!readlen)
break; break;
@ -1545,7 +1643,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (mtd->ecc_stats.failed - stats.failed) if (ecc_fail)
return -EBADMSG; return -EBADMSG;
return max_bitflips; 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 addr, uint8_t *subfeature_param)
{ {
int status; int status;
int i;
if (!chip->onfi_version || if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd) !(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; return -EINVAL;
chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); 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); status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL) if (status & NAND_STATUS_FAIL)
return -EIO; 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, static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
int addr, uint8_t *subfeature_param) int addr, uint8_t *subfeature_param)
{ {
int i;
if (!chip->onfi_version || if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd) !(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES)) & 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); memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); 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; return 0;
} }
@ -2812,6 +2916,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
chip->block_markbad = nand_default_block_markbad; chip->block_markbad = nand_default_block_markbad;
if (!chip->write_buf || chip->write_buf == nand_write_buf) if (!chip->write_buf || chip->write_buf == nand_write_buf)
chip->write_buf = busw ? nand_write_buf16 : 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) if (!chip->read_buf || chip->read_buf == nand_read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->scan_bbt) if (!chip->scan_bbt)
@ -2926,6 +3032,30 @@ ext_out:
return ret; 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. * 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; chip->onfi_version = 10;
if (!chip->onfi_version) { if (!chip->onfi_version) {
pr_info("%s: unsupported ONFI version: %d\n", __func__, val); pr_info("unsupported ONFI version: %d\n", val);
return 0; 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"); pr_warn("Could not retrieve ONFI ECC requirements\n");
} }
if (p->jedec_id == NAND_MFR_MICRON)
nand_onfi_detect_micron(chip, p);
return 1; return 1;
} }
@ -3152,9 +3285,12 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
mtd->oobsize = 512; mtd->oobsize = 512;
break; break;
case 6: case 6:
default: /* Other cases are "reserved" (unknown) */
mtd->oobsize = 640; mtd->oobsize = 640;
break; break;
case 7:
default: /* Other cases are "reserved" (unknown) */
mtd->oobsize = 1024;
break;
} }
extid >>= 2; extid >>= 2;
/* Calc blocksize */ /* 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; *busw = type->options & NAND_BUSWIDTH_16;
if (!mtd->name)
mtd->name = type->name;
return true; return true;
} }
return false; 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); id_data[i] = chip->read_byte(mtd);
if (id_data[0] != *maf_id || id_data[1] != *dev_id) { if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
pr_info("%s: second ID read did not match " pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
"%02x,%02x against %02x,%02x\n", __func__,
*maf_id, *dev_id, id_data[0], id_data[1]); *maf_id, *dev_id, id_data[0], id_data[1]);
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
@ -3440,10 +3578,10 @@ ident_done:
* Check, if buswidth is correct. Hardware drivers should set * Check, if buswidth is correct. Hardware drivers should set
* chip correct! * chip correct!
*/ */
pr_info("NAND device: Manufacturer ID:" pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *maf_id, *dev_id);
*dev_id, nand_manuf_ids[maf_idx].name, mtd->name); pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
pr_warn("NAND bus width %d instead %d bit\n", pr_warn("bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8, (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8); busw ? 16 : 8);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
@ -3472,14 +3610,13 @@ ident_done:
if (mtd->writesize > 512 && chip->cmdfunc == nand_command) if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp; chip->cmdfunc = nand_command_lp;
pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)\n", pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
*maf_id, *dev_id, nand_manuf_ids[maf_idx].name, *maf_id, *dev_id);
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
chip->onfi_version ? chip->onfi_params.model : type->name); chip->onfi_version ? chip->onfi_params.model : type->name);
pr_info("%dMiB, %s, page size: %d, OOB size: %d\n",
pr_info("NAND device: %dMiB, %s, page size: %d, OOB size: %d\n",
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
mtd->writesize, mtd->oobsize); mtd->writesize, mtd->oobsize);
return type; return type;
} }
@ -3535,7 +3672,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
chip->select_chip(mtd, -1); chip->select_chip(mtd, -1);
} }
if (i > 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 */ /* Store the number of chips and calc total size for mtd */
chip->numchips = i; chip->numchips = i;

View File

@ -169,6 +169,8 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_AMD, "AMD/Spansion"}, {NAND_MFR_AMD, "AMD/Spansion"},
{NAND_MFR_MACRONIX, "Macronix"}, {NAND_MFR_MACRONIX, "Macronix"},
{NAND_MFR_EON, "Eon"}, {NAND_MFR_EON, "Eon"},
{NAND_MFR_SANDISK, "SanDisk"},
{NAND_MFR_INTEL, "Intel"},
{0x0, "Unknown"} {0x0, "Unknown"}
}; };

View File

@ -241,12 +241,10 @@ static int nuc900_nand_probe(struct platform_device *pdev)
{ {
struct nuc900_nand *nuc900_nand; struct nuc900_nand *nuc900_nand;
struct nand_chip *chip; struct nand_chip *chip;
int retval;
struct resource *res; struct resource *res;
retval = 0; nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
GFP_KERNEL);
nuc900_nand = kzalloc(sizeof(struct nuc900_nand), GFP_KERNEL);
if (!nuc900_nand) if (!nuc900_nand)
return -ENOMEM; return -ENOMEM;
chip = &(nuc900_nand->chip); chip = &(nuc900_nand->chip);
@ -255,11 +253,9 @@ static int nuc900_nand_probe(struct platform_device *pdev)
nuc900_nand->mtd.owner = THIS_MODULE; nuc900_nand->mtd.owner = THIS_MODULE;
spin_lock_init(&nuc900_nand->lock); spin_lock_init(&nuc900_nand->lock);
nuc900_nand->clk = clk_get(&pdev->dev, NULL); nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(nuc900_nand->clk)) { if (IS_ERR(nuc900_nand->clk))
retval = -ENOENT; return -ENOENT;
goto fail1;
}
clk_enable(nuc900_nand->clk); clk_enable(nuc900_nand->clk);
chip->cmdfunc = nuc900_nand_command_lp; 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; chip->ecc.mode = NAND_ECC_SOFT;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);
retval = -ENXIO; if (IS_ERR(nuc900_nand->reg))
goto fail1; return PTR_ERR(nuc900_nand->reg);
}
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_enable(nuc900_nand); nuc900_nand_enable(nuc900_nand);
if (nand_scan(&(nuc900_nand->mtd), 1)) { if (nand_scan(&(nuc900_nand->mtd), 1))
retval = -ENXIO; return -ENXIO;
goto fail3;
}
mtd_device_register(&(nuc900_nand->mtd), partitions, mtd_device_register(&(nuc900_nand->mtd), partitions,
ARRAY_SIZE(partitions)); ARRAY_SIZE(partitions));
platform_set_drvdata(pdev, nuc900_nand); platform_set_drvdata(pdev, nuc900_nand);
return retval; return 0;
fail3: iounmap(nuc900_nand->reg);
fail2: release_mem_region(res->start, resource_size(res));
fail1: kfree(nuc900_nand);
return retval;
} }
static int nuc900_nand_remove(struct platform_device *pdev) static int nuc900_nand_remove(struct platform_device *pdev)
{ {
struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
struct resource *res;
nand_release(&nuc900_nand->mtd); 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_disable(nuc900_nand->clk);
clk_put(nuc900_nand->clk);
kfree(nuc900_nand);
return 0; return 0;
} }

View File

@ -1730,13 +1730,7 @@ static int omap_nand_probe(struct platform_device *pdev)
break; break;
case NAND_OMAP_POLLED: case NAND_OMAP_POLLED:
if (nand_chip->options & NAND_BUSWIDTH_16) { /* Use nand_base defaults for {read,write}_buf */
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;
}
break; break;
case NAND_OMAP_PREFETCH_DMA: case NAND_OMAP_PREFETCH_DMA:

View File

@ -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); nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
if (!nc) { if (!nc) {
printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");
ret = -ENOMEM; ret = -ENOMEM;
goto no_res; 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)); io_base = ioremap(res->start, resource_size(res));
if (!io_base) { if (!io_base) {
printk(KERN_ERR "orion_nand: ioremap failed\n"); dev_err(&pdev->dev, "ioremap failed\n");
ret = -EIO; ret = -EIO;
goto no_res; 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), board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
GFP_KERNEL); GFP_KERNEL);
if (!board) { if (!board) {
printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
ret = -ENOMEM; ret = -ENOMEM;
goto no_res; goto no_res;
} }

View File

@ -223,7 +223,7 @@ MODULE_DEVICE_TABLE(of, pasemi_nand_match);
static struct platform_driver pasemi_nand_driver = static struct platform_driver pasemi_nand_driver =
{ {
.driver = { .driver = {
.name = (char*)driver_name, .name = driver_name,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = pasemi_nand_match, .of_match_table = pasemi_nand_match,
}, },

View File

@ -9,6 +9,7 @@
* *
*/ */
#include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
@ -47,30 +48,16 @@ static int plat_nand_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENXIO;
/* Allocate memory for the device structure (and zero it) */ /* Allocate memory for the device structure (and zero it) */
data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL); data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data),
if (!data) { GFP_KERNEL);
dev_err(&pdev->dev, "failed to allocate device structure.\n"); if (!data)
return -ENOMEM; return -ENOMEM;
}
if (!request_mem_region(res->start, resource_size(res), res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev_name(&pdev->dev))) { data->io_base = devm_ioremap_resource(&pdev->dev, res);
dev_err(&pdev->dev, "request_mem_region failed\n"); if (IS_ERR(data->io_base))
err = -EBUSY; return PTR_ERR(data->io_base);
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;
}
data->chip.priv = &data; data->chip.priv = &data;
data->mtd.priv = &data->chip; data->mtd.priv = &data->chip;
@ -122,11 +109,6 @@ static int plat_nand_probe(struct platform_device *pdev)
out: out:
if (pdata->ctrl.remove) if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev); 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; 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 plat_nand_data *data = platform_get_drvdata(pdev);
struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev); 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); nand_release(&data->mtd);
if (pdata->ctrl.remove) if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev); pdata->ctrl.remove(pdev);
iounmap(data->io_base);
release_mem_region(res->start, resource_size(res));
kfree(data);
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@ -46,9 +46,43 @@
#include <linux/mtd/nand_ecc.h> #include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <plat/regs-nand.h>
#include <linux/platform_data/mtd-nand-s3c2410.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 /* 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); info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) { if (info == NULL) {
dev_err(&pdev->dev, "no memory for flash info\n");
err = -ENOMEM; err = -ENOMEM;
goto exit_error; goto exit_error;
} }
@ -974,7 +1007,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
size = nr_sets * sizeof(*info->mtds); size = nr_sets * sizeof(*info->mtds);
info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (info->mtds == NULL) { if (info->mtds == NULL) {
dev_err(&pdev->dev, "failed to allocate mtd storage\n");
err = -ENOMEM; err = -ENOMEM;
goto exit_error; goto exit_error;
} }

View File

@ -151,7 +151,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter, 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__, dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
flctl->chan_fifo0_tx); flctl->chan_fifo0_tx);
@ -168,7 +168,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
goto err; goto err;
flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter, 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__, dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
flctl->chan_fifo0_rx); flctl->chan_fifo0_rx);
@ -1021,7 +1021,6 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#ifdef CONFIG_OF
struct flctl_soc_config { struct flctl_soc_config {
unsigned long flcmncr_val; unsigned long flcmncr_val;
unsigned has_hwecc:1; 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), pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
GFP_KERNEL); GFP_KERNEL);
if (!pdata) { if (!pdata)
dev_err(dev, "%s: failed to allocate config data\n", __func__);
return NULL; return NULL;
}
/* set SoC specific options */ /* set SoC specific options */
pdata->flcmncr_val = config->flcmncr_val; pdata->flcmncr_val = config->flcmncr_val;
@ -1080,12 +1077,6 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
return pdata; 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) 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 mtd_info *flctl_mtd;
struct nand_chip *nand; struct nand_chip *nand;
struct sh_flctl_platform_data *pdata; struct sh_flctl_platform_data *pdata;
int ret = -ENXIO; int ret;
int irq; int irq;
struct mtd_part_parser_data ppdata = {}; struct mtd_part_parser_data ppdata = {};
flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL);
if (!flctl) { if (!flctl)
dev_err(&pdev->dev, "failed to allocate driver data\n");
return -ENOMEM; return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { flctl->reg = devm_ioremap_resource(&pdev->dev, res);
dev_err(&pdev->dev, "failed to get I/O memory\n"); if (IS_ERR(flctl->reg))
goto err_iomap; return PTR_ERR(flctl->reg);
}
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;
}
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(&pdev->dev, "failed to get flste irq data\n"); 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) { if (ret) {
dev_err(&pdev->dev, "request interrupt failed.\n"); dev_err(&pdev->dev, "request interrupt failed.\n");
goto err_flste; return ret;
} }
if (pdev->dev.of_node) if (pdev->dev.of_node)
@ -1135,8 +1118,7 @@ static int flctl_probe(struct platform_device *pdev)
if (!pdata) { if (!pdata) {
dev_err(&pdev->dev, "no setup data defined\n"); dev_err(&pdev->dev, "no setup data defined\n");
ret = -EINVAL; return -EINVAL;
goto err_pdata;
} }
platform_set_drvdata(pdev, flctl); platform_set_drvdata(pdev, flctl);
@ -1190,12 +1172,6 @@ static int flctl_probe(struct platform_device *pdev)
err_chip: err_chip:
flctl_release_dma(flctl); flctl_release_dma(flctl);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
err_pdata:
free_irq(irq, flctl);
err_flste:
iounmap(flctl->reg);
err_iomap:
kfree(flctl);
return ret; return ret;
} }
@ -1206,9 +1182,6 @@ static int flctl_remove(struct platform_device *pdev)
flctl_release_dma(flctl); flctl_release_dma(flctl);
nand_release(&flctl->mtd); nand_release(&flctl->mtd);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
free_irq(platform_get_irq(pdev, 0), flctl);
iounmap(flctl->reg);
kfree(flctl);
return 0; return 0;
} }

View File

@ -121,10 +121,8 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
/* Allocate memory for MTD device structure and private data */ /* Allocate memory for MTD device structure and private data */
sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL); sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
if (!sharpsl) { if (!sharpsl)
printk("Unable to allocate SharpSL NAND MTD device structure.\n");
return -ENOMEM; return -ENOMEM;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) { if (!r) {
@ -136,7 +134,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
/* map physical address */ /* map physical address */
sharpsl->io = ioremap(r->start, resource_size(r)); sharpsl->io = ioremap(r->start, resource_size(r));
if (!sharpsl->io) { 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; err = -EIO;
goto err_ioremap; goto err_ioremap;
} }

View File

@ -371,11 +371,9 @@ static int tmio_probe(struct platform_device *dev)
if (data == NULL) if (data == NULL)
dev_warn(&dev->dev, "NULL platform data!\n"); dev_warn(&dev->dev, "NULL platform data!\n");
tmio = kzalloc(sizeof *tmio, GFP_KERNEL); tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL);
if (!tmio) { if (!tmio)
retval = -ENOMEM; return -ENOMEM;
goto err_kzalloc;
}
tmio->dev = dev; tmio->dev = dev;
@ -385,22 +383,18 @@ static int tmio_probe(struct platform_device *dev)
mtd->priv = nand_chip; mtd->priv = nand_chip;
mtd->name = "tmio-nand"; mtd->name = "tmio-nand";
tmio->ccr = ioremap(ccr->start, resource_size(ccr)); tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr));
if (!tmio->ccr) { if (!tmio->ccr)
retval = -EIO; return -EIO;
goto err_iomap_ccr;
}
tmio->fcr_base = fcr->start & 0xfffff; tmio->fcr_base = fcr->start & 0xfffff;
tmio->fcr = ioremap(fcr->start, resource_size(fcr)); tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr));
if (!tmio->fcr) { if (!tmio->fcr)
retval = -EIO; return -EIO;
goto err_iomap_fcr;
}
retval = tmio_hw_init(dev, tmio); retval = tmio_hw_init(dev, tmio);
if (retval) if (retval)
goto err_hwinit; return retval;
/* Set address of NAND IO lines */ /* Set address of NAND IO lines */
nand_chip->IO_ADDR_R = tmio->fcr; nand_chip->IO_ADDR_R = tmio->fcr;
@ -428,7 +422,8 @@ static int tmio_probe(struct platform_device *dev)
/* 15 us command delay time */ /* 15 us command delay time */
nand_chip->chip_delay = 15; 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) { if (retval) {
dev_err(&dev->dev, "request_irq error %d\n", retval); dev_err(&dev->dev, "request_irq error %d\n", retval);
goto err_irq; goto err_irq;
@ -440,7 +435,7 @@ static int tmio_probe(struct platform_device *dev)
/* Scan to find existence of the device */ /* Scan to find existence of the device */
if (nand_scan(mtd, 1)) { if (nand_scan(mtd, 1)) {
retval = -ENODEV; retval = -ENODEV;
goto err_scan; goto err_irq;
} }
/* Register the partitions */ /* Register the partitions */
retval = mtd_device_parse_register(mtd, NULL, NULL, retval = mtd_device_parse_register(mtd, NULL, NULL,
@ -451,18 +446,8 @@ static int tmio_probe(struct platform_device *dev)
nand_release(mtd); nand_release(mtd);
err_scan:
if (tmio->irq)
free_irq(tmio->irq, tmio);
err_irq: err_irq:
tmio_hw_stop(dev, tmio); 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; return retval;
} }
@ -471,12 +456,7 @@ static int tmio_remove(struct platform_device *dev)
struct tmio_nand *tmio = platform_get_drvdata(dev); struct tmio_nand *tmio = platform_get_drvdata(dev);
nand_release(&tmio->mtd); nand_release(&tmio->mtd);
if (tmio->irq)
free_irq(tmio->irq, tmio);
tmio_hw_stop(dev, tmio); tmio_hw_stop(dev, tmio);
iounmap(tmio->fcr);
iounmap(tmio->ccr);
kfree(tmio);
return 0; return 0;
} }

View File

@ -319,11 +319,8 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
continue; continue;
txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv), txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv),
GFP_KERNEL); GFP_KERNEL);
if (!txx9_priv) { if (!txx9_priv)
dev_err(&dev->dev, "Unable to allocate "
"TXx9 NDFMC MTD device structure.\n");
continue; continue;
}
chip = &txx9_priv->chip; chip = &txx9_priv->chip;
mtd = &txx9_priv->mtd; mtd = &txx9_priv->mtd;
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;

View File

@ -81,7 +81,7 @@ static int parse_ofpart_partitions(struct mtd_info *master,
partname = of_get_property(pp, "label", &len); partname = of_get_property(pp, "label", &len);
if (!partname) if (!partname)
partname = of_get_property(pp, "name", &len); partname = of_get_property(pp, "name", &len);
(*pparts)[i].name = (char *)partname; (*pparts)[i].name = partname;
if (of_get_property(pp, "read-only", &len)) if (of_get_property(pp, "read-only", &len))
(*pparts)[i].mask_flags |= MTD_WRITEABLE; (*pparts)[i].mask_flags |= MTD_WRITEABLE;
@ -152,7 +152,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master,
if (names && (plen > 0)) { if (names && (plen > 0)) {
int len = strlen(names) + 1; int len = strlen(names) + 1;
(*pparts)[i].name = (char *)names; (*pparts)[i].name = names;
plen -= len; plen -= len;
names += len; names += len;
} else { } else {
@ -173,18 +173,9 @@ static struct mtd_part_parser ofoldpart_parser = {
static int __init ofpart_parser_init(void) static int __init ofpart_parser_init(void)
{ {
int rc; register_mtd_parser(&ofpart_parser);
rc = register_mtd_parser(&ofpart_parser); register_mtd_parser(&ofoldpart_parser);
if (rc) return 0;
goto out;
rc = register_mtd_parser(&ofoldpart_parser);
if (!rc)
return 0;
deregister_mtd_parser(&ofoldpart_parser);
out:
return rc;
} }
static void __exit ofpart_parser_exit(void) static void __exit ofpart_parser_exit(void)

View File

@ -58,7 +58,7 @@ static int generic_onenand_probe(struct platform_device *pdev)
goto out_release_mem_region; 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->onenand.irq = platform_get_irq(pdev, 0);
info->mtd.name = dev_name(&pdev->dev); info->mtd.name = dev_name(&pdev->dev);

View File

@ -300,7 +300,8 @@ MODULE_ALIAS("RedBoot");
static int __init redboot_parser_init(void) 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) static void __exit redboot_parser_exit(void)

View File

@ -19,7 +19,7 @@
* or detected. * or detected.
*/ */
#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE) #if IS_ENABLED(CONFIG_MTD_NAND)
struct nand_ecc_test { struct nand_ecc_test {
const char *name; const char *name;

View File

@ -288,6 +288,8 @@ struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void)
struct jffs2_xattr_datum *xd; struct jffs2_xattr_datum *xd;
xd = kmem_cache_zalloc(xattr_datum_cache, GFP_KERNEL); xd = kmem_cache_zalloc(xattr_datum_cache, GFP_KERNEL);
dbg_memalloc("%p\n", xd); dbg_memalloc("%p\n", xd);
if (!xd)
return NULL;
xd->class = RAWNODE_CLASS_XATTR_DATUM; xd->class = RAWNODE_CLASS_XATTR_DATUM;
xd->node = (void *)xd; xd->node = (void *)xd;
@ -306,6 +308,8 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void)
struct jffs2_xattr_ref *ref; struct jffs2_xattr_ref *ref;
ref = kmem_cache_zalloc(xattr_ref_cache, GFP_KERNEL); ref = kmem_cache_zalloc(xattr_ref_cache, GFP_KERNEL);
dbg_memalloc("%p\n", ref); dbg_memalloc("%p\n", ref);
if (!ref)
return NULL;
ref->class = RAWNODE_CLASS_XATTR_REF; ref->class = RAWNODE_CLASS_XATTR_REF;
ref->node = (void *)ref; ref->node = (void *)ref;

View File

@ -3,6 +3,6 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 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__ */ #endif /* __MTD_MTDRAM_H__ */

View File

@ -219,6 +219,9 @@ struct nand_chip;
/* ONFI feature address */ /* ONFI feature address */
#define ONFI_FEATURE_ADDR_TIMING_MODE 0x1 #define ONFI_FEATURE_ADDR_TIMING_MODE 0x1
/* Vendor-specific feature address (Micron) */
#define ONFI_FEATURE_ADDR_READ_RETRY 0x89
/* ONFI subfeature parameters length */ /* ONFI subfeature parameters length */
#define ONFI_SUBFEATURE_PARAM_LEN 4 #define ONFI_SUBFEATURE_PARAM_LEN 4
@ -279,16 +282,17 @@ struct nand_onfi_params {
__le16 io_pin_capacitance_typ; __le16 io_pin_capacitance_typ;
__le16 input_pin_capacitance_typ; __le16 input_pin_capacitance_typ;
u8 input_pin_capacitance_max; u8 input_pin_capacitance_max;
u8 driver_strenght_support; u8 driver_strength_support;
__le16 t_int_r; __le16 t_int_r;
__le16 t_ald; __le16 t_ald;
u8 reserved4[7]; u8 reserved4[7];
/* vendor */ /* vendor */
u8 reserved5[90]; __le16 vendor_revision;
u8 vendor[88];
__le16 crc; __le16 crc;
} __attribute__((packed)); } __packed;
#define ONFI_CRC_BASE 0x4F4E #define ONFI_CRC_BASE 0x4F4E
@ -326,6 +330,26 @@ struct onfi_ext_param_page {
*/ */
} __packed; } __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 * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
* @lock: protection lock * @lock: protection lock
@ -432,6 +456,8 @@ struct nand_buffers {
* flash device. * flash device.
* @read_byte: [REPLACEABLE] read one byte from the chip * @read_byte: [REPLACEABLE] read one byte from the chip
* @read_word: [REPLACEABLE] read one word 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 * @write_buf: [REPLACEABLE] write data from the buffer to the chip
* @read_buf: [REPLACEABLE] read data from the chip into the buffer * @read_buf: [REPLACEABLE] read data from the chip into the buffer
* @select_chip: [REPLACEABLE] select chip nr * @select_chip: [REPLACEABLE] select chip nr
@ -451,6 +477,8 @@ struct nand_buffers {
* commands to the chip. * commands to the chip.
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on
* ready. * 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 * @ecc: [BOARDSPECIFIC] ECC control structure
* @buffers: buffer structure for read/write * @buffers: buffer structure for read/write
* @hwcontrol: platform-specific hardware control structure * @hwcontrol: platform-specific hardware control structure
@ -497,6 +525,7 @@ struct nand_buffers {
* non 0 if ONFI supported. * non 0 if ONFI supported.
* @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is
* supported, 0 otherwise. * supported, 0 otherwise.
* @read_retries: [INTERN] the number of read retry modes supported
* @onfi_set_features: [REPLACEABLE] set the features for ONFI nand * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
* @onfi_get_features: [REPLACEABLE] get the features for ONFI nand * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
* @bbt: [INTERN] bad block table pointer * @bbt: [INTERN] bad block table pointer
@ -521,6 +550,7 @@ struct nand_chip {
uint8_t (*read_byte)(struct mtd_info *mtd); uint8_t (*read_byte)(struct mtd_info *mtd);
u16 (*read_word)(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 (*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 (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
void (*select_chip)(struct mtd_info *mtd, int chip); void (*select_chip)(struct mtd_info *mtd, int chip);
@ -544,6 +574,7 @@ struct nand_chip {
int feature_addr, uint8_t *subfeature_para); int feature_addr, uint8_t *subfeature_para);
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para); int feature_addr, uint8_t *subfeature_para);
int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
int chip_delay; int chip_delay;
unsigned int options; unsigned int options;
@ -568,6 +599,8 @@ struct nand_chip {
int onfi_version; int onfi_version;
struct nand_onfi_params onfi_params; struct nand_onfi_params onfi_params;
int read_retries;
flstate_t state; flstate_t state;
uint8_t *oob_poi; uint8_t *oob_poi;
@ -600,6 +633,8 @@ struct nand_chip {
#define NAND_MFR_AMD 0x01 #define NAND_MFR_AMD 0x01
#define NAND_MFR_MACRONIX 0xc2 #define NAND_MFR_MACRONIX 0xc2
#define NAND_MFR_EON 0x92 #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 */ /* The maximum expected count of bytes in the NAND ID sequence */
#define NAND_MAX_ID_LEN 8 #define NAND_MAX_ID_LEN 8

View File

@ -37,7 +37,7 @@
*/ */
struct mtd_partition { struct mtd_partition {
char *name; /* identifier string */ const char *name; /* identifier string */
uint64_t size; /* partition size */ uint64_t size; /* partition size */
uint64_t offset; /* offset within the master MTD space */ uint64_t offset; /* offset within the master MTD space */
uint32_t mask_flags; /* master MTD flags to mask out for this partition */ 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 *); struct mtd_part_parser_data *);
}; };
extern int register_mtd_parser(struct mtd_part_parser *parser); extern void register_mtd_parser(struct mtd_part_parser *parser);
extern int deregister_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_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); long long offset, long long length);
int mtd_del_partition(struct mtd_info *master, int partno); int mtd_del_partition(struct mtd_info *master, int partno);
uint64_t mtd_get_device_size(const struct mtd_info *mtd); uint64_t mtd_get_device_size(const struct mtd_info *mtd);

View File

@ -7,7 +7,7 @@
*/ */
#ifndef __LINUX_OF_MTD_H #ifndef __LINUX_OF_MTD_H
#define __LINUX_OF_NET_H #define __LINUX_OF_MTD_H
#ifdef CONFIG_OF_MTD #ifdef CONFIG_OF_MTD

View File

@ -1,6 +1,4 @@
/* /*
* arch/arm/plat-omap/include/mach/nand.h
*
* Copyright (C) 2006 Micron Technology Inc. * Copyright (C) 2006 Micron Technology Inc.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View File

@ -55,6 +55,9 @@ struct pxa3xx_nand_platform_data {
/* indicate how many chip selects will be used */ /* indicate how many chip selects will be used */
int num_cs; int num_cs;
/* use an flash-based bad block table */
bool flash_bbt;
const struct mtd_partition *parts[NUM_CHIP_SELECT]; const struct mtd_partition *parts[NUM_CHIP_SELECT];
unsigned int nr_parts[NUM_CHIP_SELECT]; unsigned int nr_parts[NUM_CHIP_SELECT];

View File

@ -1,6 +1,4 @@
/* /*
* arch/arm/plat-omap/include/mach/onenand.h
*
* Copyright (C) 2006 Nokia Corporation * Copyright (C) 2006 Nokia Corporation
* Author: Juha Yrjola * Author: Juha Yrjola
* *

View File

@ -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 * This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any * License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied. * warranty of any kind, whether express or implied.
*/ */
#ifndef __PLAT_ORION_NAND_H #ifndef __MTD_ORION_NAND_H
#define __PLAT_ORION_NAND_H #define __MTD_ORION_NAND_H
/* /*
* Device bus NAND private data * Device bus NAND private data