MTD updates for 4.12-rc1:

NAND, from Boris:
 """
  - some minor fixes/improvements on existing drivers (fsmc, gpio, ifc,
    davinci, brcmnand, omap)
  - a huge cleanup/rework of the denali driver accompanied with core
    fixes/improvements to simplify the driver code
  - a complete rewrite of the atmel driver to support new DT bindings
    make future evolution easier
  - the addition of per-vendor detection/initialization steps to avoid
    extending the nand_ids table with more extended-id entries
 """
 
 SPI NOR, from Cyrille:
 """
 - fixes in the hisi SPI controller driver.
 - fixes in the intel SPI controller driver.
 - fixes in the Mediatek SPI controller driver.
 - fixes to some SPI flash memories not supported the Chip Erase command.
 - add support to some new memory parts (Winbond, Macronix, Micron, ESMT).
 - add new driver for the STM32 QSPI controller.
 """
 
 And a few fixes for Gemini and Versatile platforms on physmap-of
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJZE86yAAoJEFySrpd9RFgtlOoP/1o1s8dlKdd4TazdoxBTL2wy
 C4wPkqPWyfREcD5ZUYJgr6ENI2OnEwcAxAt2CXnqegx+ZIPToBW4/WK9gj/TNLRx
 AfSOz+EPPzo5uZwJPnfocgIFYuhsspymvmISwv66kPbjfkrSjo1l/K9nem3gh7an
 IkQdVVq8brvxNeDZOAzbsT2Y5DZNfs00g1jLXkcQrpfM0sWKcbHIUa0BTWy4WKGV
 ElTr+xh7QHh/Pd9/A5znd3xX54w5+YR/xe38jSBfTb0vEgw/RIfhIcnvxQ8G/7Se
 jE0+8GR5ZJGKwA9Xk5nFzS2G3uECMFNS75KfxkZ0LlEE6ivUvpDbokCbIU4bDOCt
 /8bWQf9AGA3gLHGgNUQTSt5HrkBXTGp917jtAZbI/y2MzTkLw3aAZ/m/j37vv9ON
 ezeGRO6VWK3bcimLFrt6KO5emYstmm4Tp4rRe3jakH7eyTlINDsecKtuMo2xVzyZ
 kK3tnDMdEntECAiKh3ndRdAUL3fs+/IdzWTAxnF9VQFQs1YxiZ1K8kY/zcN+rzbn
 CVkEhdm+tdDBx8XgOdfnOTGRAJ07dGOoDhLPR4/egC/ta6GIRkHQjFSwsW7bD9p9
 phHH6nQX9Bpza1JV/xvljezoHjvZkny4UhRpLgYMowb41DXv7os7ZV+g7kf5sd0i
 mGzCH46j0DmWQ1u5/Q6j
 =dxj5
 -----END PGP SIGNATURE-----

Merge tag 'for-linus-20170510' of git://git.infradead.org/linux-mtd

Pull MTD updates from Brian Norris:
 "NAND, from Boris:
   - some minor fixes/improvements on existing drivers (fsmc, gpio, ifc,
     davinci, brcmnand, omap)
   - a huge cleanup/rework of the denali driver accompanied with core
     fixes/improvements to simplify the driver code
   - a complete rewrite of the atmel driver to support new DT bindings
     make future evolution easier
   - the addition of per-vendor detection/initialization steps to avoid
     extending the nand_ids table with more extended-id entries

  SPI NOR, from Cyrille:
   - fixes in the hisi, intel and Mediatek SPI controller drivers
   - fixes to some SPI flash memories not supporting the Chip Erase
     command.
   - add support to some new memory parts (Winbond, Macronix, Micron,
     ESMT).
   - add new driver for the STM32 QSPI controller

  And a few fixes for Gemini and Versatile platforms on physmap-of"

* tag 'for-linus-20170510' of git://git.infradead.org/linux-mtd: (100 commits)
  MAINTAINERS: Update NAND subsystem git repositories
  mtd: nand: gpio: update binding
  mtd: nand: add ooblayout for old hamming layout
  mtd: oxnas_nand: Allocating more than necessary in probe()
  dt-bindings: mtd: Document the STM32 QSPI bindings
  mtd: mtk-nor: set controller's address width according to nor flash
  mtd: spi-nor: add driver for STM32 quad spi flash controller
  mtd: nand: brcmnand: Check flash #WP pin status before nand erase/program
  mtd: nand: davinci: add comment on NAND subpage write status on keystone
  mtd: nand: omap2: Fix partition creation via cmdline mtdparts
  mtd: nand: NULL terminate a of_device_id table
  mtd: nand: Fix a couple error codes
  mtd: nand: allow drivers to request minimum alignment for passed buffer
  mtd: nand: allocate aligned buffers if NAND_OWN_BUFFERS is unset
  mtd: nand: denali: allow to override revision number
  mtd: nand: denali_dt: use pdev instead of ofdev for platform_device
  mtd: nand: denali_dt: remove dma-mask DT property
  mtd: nand: denali: support 64bit capable DMA engine
  mtd: nand: denali_dt: enable HW_ECC_FIXUP for Altera SOCFPGA variant
  mtd: nand: denali: support HW_ECC_FIXUP capability
  ...
This commit is contained in:
Linus Torvalds 2017-05-11 10:44:22 -07:00
commit 9786e34e0a
53 changed files with 6170 additions and 3831 deletions

View File

@ -1,4 +1,109 @@
Atmel NAND flash
Atmel NAND flash controller bindings
The NAND flash controller node should be defined under the EBI bus (see
Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt).
One or several NAND devices can be defined under this NAND controller.
The NAND controller might be connected to an ECC engine.
* NAND controller bindings:
Required properties:
- compatible: should be one of the following
"atmel,at91rm9200-nand-controller"
"atmel,at91sam9260-nand-controller"
"atmel,at91sam9261-nand-controller"
"atmel,at91sam9g45-nand-controller"
"atmel,sama5d3-nand-controller"
- ranges: empty ranges property to forward EBI ranges definitions.
- #address-cells: should be set to 2.
- #size-cells: should be set to 1.
- atmel,nfc-io: phandle to the NFC IO block. Only required for sama5d3
controllers.
- atmel,nfc-sram: phandle to the NFC SRAM block. Only required for sama5d3
controllers.
Optional properties:
- ecc-engine: phandle to the PMECC block. Only meaningful if the SoC embeds
a PMECC engine.
* NAND device/chip bindings:
Required properties:
- reg: describes the CS lines assigned to the NAND device. If the NAND device
exposes multiple CS lines (multi-dies chips), your reg property will
contain X tuples of 3 entries.
1st entry: the CS line this NAND chip is connected to
2nd entry: the base offset of the memory region assigned to this
device (always 0)
3rd entry: the memory region size (always 0x800000)
Optional properties:
- rb-gpios: the GPIO(s) used to check the Ready/Busy status of the NAND.
- cs-gpios: the GPIO(s) used to control the CS line.
- det-gpios: the GPIO used to detect if a Smartmedia Card is present.
- atmel,rb: an integer identifying the native Ready/Busy pin. Only meaningful
on sama5 SoCs.
All generic properties described in
Documentation/devicetree/bindings/mtd/{common,nand}.txt also apply to the NAND
device node, and NAND partitions should be defined under the NAND node as
described in Documentation/devicetree/bindings/mtd/partition.txt.
* ECC engine (PMECC) bindings:
Required properties:
- compatible: should be one of the following
"atmel,at91sam9g45-pmecc"
"atmel,sama5d4-pmecc"
"atmel,sama5d2-pmecc"
- reg: should contain 2 register ranges. The first one is pointing to the PMECC
block, and the second one to the PMECC_ERRLOC block.
Example:
pmecc: ecc-engine@ffffc070 {
compatible = "atmel,at91sam9g45-pmecc";
reg = <0xffffc070 0x490>,
<0xffffc500 0x100>;
};
ebi: ebi@10000000 {
compatible = "atmel,sama5d3-ebi";
#address-cells = <2>;
#size-cells = <1>;
atmel,smc = <&hsmc>;
reg = <0x10000000 0x10000000
0x40000000 0x30000000>;
ranges = <0x0 0x0 0x10000000 0x10000000
0x1 0x0 0x40000000 0x10000000
0x2 0x0 0x50000000 0x10000000
0x3 0x0 0x60000000 0x10000000>;
clocks = <&mck>;
nand_controller: nand-controller {
compatible = "atmel,sama5d3-nand-controller";
atmel,nfc-sram = <&nfc_sram>;
atmel,nfc-io = <&nfc_io>;
ecc-engine = <&pmecc>;
#address-cells = <2>;
#size-cells = <1>;
ranges;
nand@3 {
reg = <0x3 0x0 0x800000>;
atmel,rb = <0>;
/*
* Put generic NAND/MTD properties and
* subnodes here.
*/
};
};
};
-----------------------------------------------------------------------
Deprecated bindings (should not be used in new device trees):
Required properties:
- compatible: The possible values are:

View File

@ -1,11 +1,11 @@
* Denali NAND controller
Required properties:
- compatible : should be "denali,denali-nand-dt"
- compatible : should be one of the following:
"altr,socfpga-denali-nand" - for Altera SOCFPGA
- reg : should contain registers location and length for data and reg.
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
- dm-mask : DMA bit mask
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
@ -15,9 +15,8 @@ Examples:
nand: nand@ff900000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "denali,denali-nand-dt";
compatible = "altr,socfpga-denali-nand";
reg = <0xff900000 0x100000>, <0xffb80000 0x10000>;
reg-names = "nand_data", "denali_reg";
interrupts = <0 144 4>;
dma-mask = <0xffffffff>;
};

View File

@ -12,7 +12,7 @@ Required properties:
- #address-cells, #size-cells : Must be present if the device has sub-nodes
representing partitions.
- gpios : Specifies the GPIO pins to control the NAND device. The order of
GPIO references is: RDY, nCE, ALE, CLE, and an optional nWP.
GPIO references is: RDY, nCE, ALE, CLE, and nWP. nCE and nWP are optional.
Optional properties:
- bank-width : Width (in bytes) of the device. If not present, the width
@ -36,7 +36,7 @@ gpio-nand@1,0 {
#address-cells = <1>;
#size-cells = <1>;
gpios = <&banka 1 0>, /* RDY */
<&banka 2 0>, /* nCE */
<0>, /* nCE */
<&banka 3 0>, /* ALE */
<&banka 4 0>, /* CLE */
<0>; /* nWP */

View File

@ -0,0 +1,43 @@
* STMicroelectronics Quad Serial Peripheral Interface(QuadSPI)
Required properties:
- compatible: should be "st,stm32f469-qspi"
- reg: the first contains the register location and length.
the second contains the memory mapping address and length
- reg-names: should contain the reg names "qspi" "qspi_mm"
- interrupts: should contain the interrupt for the device
- clocks: the phandle of the clock needed by the QSPI controller
- A pinctrl must be defined to set pins in mode of operation for QSPI transfer
Optional properties:
- resets: must contain the phandle to the reset controller.
A spi flash must be a child of the nor_flash node and could have some
properties. Also see jedec,spi-nor.txt.
Required properties:
- reg: chip-Select number (QSPI controller may connect 2 nor flashes)
- spi-max-frequency: max frequency of spi bus
Optional property:
- spi-rx-bus-width: see ../spi/spi-bus.txt for the description
Example:
qspi: spi@a0001000 {
compatible = "st,stm32f469-qspi";
reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>;
reg-names = "qspi", "qspi_mm";
interrupts = <91>;
resets = <&rcc STM32F4_AHB3_RESET(QSPI)>;
clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_qspi0>;
flash@0 {
reg = <0>;
spi-rx-bus-width = <4>;
spi-max-frequency = <108000000>;
...
};
};

View File

@ -2274,7 +2274,7 @@ M: Wenyou Yang <wenyou.yang@atmel.com>
M: Josh Wu <rainyfeeling@outlook.com>
L: linux-mtd@lists.infradead.org
S: Supported
F: drivers/mtd/nand/atmel_nand*
F: drivers/mtd/nand/atmel/*
ATMEL SDMMC DRIVER
M: Ludovic Desroches <ludovic.desroches@microchip.com>
@ -8376,12 +8376,12 @@ M: Brian Norris <computersforpeace@gmail.com>
M: Boris Brezillon <boris.brezillon@free-electrons.com>
M: Marek Vasut <marek.vasut@gmail.com>
M: Richard Weinberger <richard@nod.at>
M: Cyrille Pitchen <cyrille.pitchen@atmel.com>
M: Cyrille Pitchen <cyrille.pitchen@wedev4u.fr>
L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
T: git git://git.infradead.org/linux-mtd.git
T: git git://git.infradead.org/l2-mtd.git
T: git git://git.infradead.org/linux-mtd.git master
T: git git://git.infradead.org/l2-mtd.git master
S: Maintained
F: Documentation/devicetree/bindings/mtd/
F: drivers/mtd/
@ -8756,7 +8756,8 @@ R: Richard Weinberger <richard@nod.at>
L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
T: git git://github.com/linux-nand/linux.git
T: git git://git.infradead.org/linux-mtd.git nand/fixes
T: git git://git.infradead.org/l2-mtd.git nand/next
S: Maintained
F: drivers/mtd/nand/
F: include/linux/mtd/nand*.h
@ -12113,7 +12114,7 @@ S: Maintained
F: drivers/clk/spear/
SPI NOR SUBSYSTEM
M: Cyrille Pitchen <cyrille.pitchen@atmel.com>
M: Cyrille Pitchen <cyrille.pitchen@wedev4u.fr>
M: Marek Vasut <marek.vasut@gmail.com>
L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/

View File

@ -136,7 +136,6 @@ config ETRAX_NANDFLASH
bool "NAND flash support"
depends on ETRAX_ARCH_V32
select MTD_NAND
select MTD_NAND_IDS
help
This option enables MTD mapping of NAND flash devices. Needed to use
NAND flash memories. If unsure, say Y.

View File

@ -116,7 +116,7 @@ config FSL_CORENET_CF
config FSL_IFC
bool
depends on FSL_SOC || ARCH_LAYERSCAPE
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
config JZ4780_NEMC
bool "Ingenic JZ4780 SoC NEMC driver"

View File

@ -323,7 +323,8 @@ static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd)
* it should report a size of 8KBytes (0x0020*256).
*/
cfi->cfiq->EraseRegionInfo[0] = 0x002003ff;
pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name);
pr_warn("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n",
mtd->name);
}
static void fixup_s29gl064n_sectors(struct mtd_info *mtd)
@ -333,7 +334,8 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd)
if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) {
cfi->cfiq->EraseRegionInfo[0] |= 0x0040;
pr_warning("%s: Bad S29GL064N CFI data; adjust from 64 to 128 sectors\n", mtd->name);
pr_warn("%s: Bad S29GL064N CFI data; adjust from 64 to 128 sectors\n",
mtd->name);
}
}
@ -344,7 +346,8 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd)
if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) {
cfi->cfiq->EraseRegionInfo[1] &= ~0x0040;
pr_warning("%s: Bad S29GL032N CFI data; adjust from 127 to 63 sectors\n", mtd->name);
pr_warn("%s: Bad S29GL032N CFI data; adjust from 127 to 63 sectors\n",
mtd->name);
}
}
@ -358,7 +361,8 @@ static void fixup_s29ns512p_sectors(struct mtd_info *mtd)
* which is not permitted by CFI.
*/
cfi->cfiq->EraseRegionInfo[0] = 0x020001ff;
pr_warning("%s: Bad S29NS512P CFI data; adjust to 512 sectors\n", mtd->name);
pr_warn("%s: Bad S29NS512P CFI data; adjust to 512 sectors\n",
mtd->name);
}
/* Used to fix CFI-Tables of chips without Extended Query Tables */

View File

@ -17,12 +17,10 @@ obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
ifdef CONFIG_MTD_PHYSMAP_OF_VERSATILE
physmap_of-objs += physmap_of_versatile.o
endif
ifdef CONFIG_MTD_PHYSMAP_OF_GEMINI
physmap_of-objs += physmap_of_gemini.o
endif
physmap_of-objs-y += physmap_of_core.o
physmap_of-objs-$(CONFIG_MTD_PHYSMAP_OF_VERSATILE) += physmap_of_versatile.o
physmap_of-objs-$(CONFIG_MTD_PHYSMAP_OF_GEMINI) += physmap_of_gemini.o
physmap_of-objs := $(physmap_of-objs-y)
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
obj-$(CONFIG_MTD_PISMO) += pismo.o
obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o

View File

@ -116,32 +116,22 @@ static const char * const part_probe_types_def[] = {
static const char * const *of_get_probes(struct device_node *dp)
{
const char *cp;
int cplen;
unsigned int l;
unsigned int count;
const char **res;
int count;
cp = of_get_property(dp, "linux,part-probe", &cplen);
if (cp == NULL)
count = of_property_count_strings(dp, "linux,part-probe");
if (count < 0)
return part_probe_types_def;
count = 0;
for (l = 0; l != cplen; l++)
if (cp[l] == 0)
count++;
res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL);
if (!res)
return NULL;
count = 0;
while (cplen > 0) {
res[count] = cp;
l = strlen(cp) + 1;
cp += l;
cplen -= l;
count++;
}
count = of_property_read_string_array(dp, "linux,part-probe", res,
count);
if (count < 0)
return NULL;
return res;
}

View File

@ -1235,10 +1235,8 @@ static int mtdswap_show(struct seq_file *s, void *data)
if (root->rb_node) {
count[i] = d->trees[i].count;
min[i] = rb_entry(rb_first(root), struct swap_eb,
rb)->erase_count;
max[i] = rb_entry(rb_last(root), struct swap_eb,
rb)->erase_count;
min[i] = MTDSWAP_ECNT_MIN(root);
max[i] = MTDSWAP_ECNT_MAX(root);
} else
count[i] = 0;
}

View File

@ -13,7 +13,6 @@ config MTD_NAND_ECC_SMC
menuconfig MTD_NAND
tristate "NAND Device Support"
depends on MTD
select MTD_NAND_IDS
select MTD_NAND_ECC
help
This enables support for accessing all type of NAND flash
@ -60,17 +59,6 @@ config MTD_NAND_DENALI_DT
Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device.
config MTD_NAND_DENALI_SCRATCH_REG_ADDR
hex "Denali NAND size scratch register address"
default "0xFF108018"
depends on MTD_NAND_DENALI_PCI
help
Some platforms place the NAND chip size in a scratch register
because (some versions of) the driver aren't able to automatically
determine the size of certain chips. Set the address of the
scratch register here to enable this feature. On Intel Moorestown
boards, the scratch register is at 0xFF108018.
config MTD_NAND_GPIO
tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB || COMPILE_TEST
@ -109,9 +97,6 @@ config MTD_NAND_OMAP_BCH
config MTD_NAND_OMAP_BCH_BUILD
def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
config MTD_NAND_IDS
tristate
config MTD_NAND_RICOH
tristate "Ricoh xD card reader"
default n
@ -321,11 +306,11 @@ config MTD_NAND_CS553X
If you say "m", the module will be called cs553x_nand.
config MTD_NAND_ATMEL
tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32"
depends on ARCH_AT91 || AVR32
tristate "Support for NAND Flash / SmartMedia on AT91"
depends on ARCH_AT91
help
Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 and AVR32 processors.
on Atmel AT91 processors.
config MTD_NAND_PXA3xx
tristate "NAND support on PXA3xx and Armada 370/XP"
@ -443,7 +428,7 @@ config MTD_NAND_FSL_ELBC
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on FSL_SOC || ARCH_LAYERSCAPE
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
select FSL_IFC
select MEMORY
help

View File

@ -5,7 +5,6 @@
obj-$(CONFIG_MTD_NAND) += nand.o
obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
@ -25,7 +24,7 @@ obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel/
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
omap2_nand-objs := omap2.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o
@ -61,4 +60,10 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_nand.o mtk_ecc.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_amd.o
nand-objs += nand_hynix.o
nand-objs += nand_macronix.o
nand-objs += nand_micron.o
nand-objs += nand_samsung.o
nand-objs += nand_toshiba.o

View File

@ -0,0 +1,4 @@
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel-nand-controller.o atmel-pmecc.o
atmel-nand-controller-objs := nand-controller.o
atmel-pmecc-objs := pmecc.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
/*
* © Copyright 2016 ATMEL
* © Copyright 2016 Free Electrons
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* Derived from the atmel_nand.c driver which contained the following
* copyrights:
*
* Copyright © 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
* Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
* Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
*
*
* Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
* Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007
*
* Derived from Das U-Boot source code
* (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
* © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
*
* Add Programmable Multibit ECC support for various AT91 SoC
* © Copyright 2012 ATMEL, Hong Xu
*
* Add Nand Flash Controller support for SAMA5 SoC
* © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
*
* 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.
*
*/
#ifndef ATMEL_PMECC_H
#define ATMEL_PMECC_H
#define ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH 0
#define ATMEL_PMECC_SECTOR_SIZE_AUTO 0
#define ATMEL_PMECC_OOBOFFSET_AUTO -1
struct atmel_pmecc_user_req {
int pagesize;
int oobsize;
struct {
int strength;
int bytes;
int sectorsize;
int nsectors;
int ooboffset;
} ecc;
};
struct atmel_pmecc *devm_atmel_pmecc_get(struct device *dev);
struct atmel_pmecc_user *
atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
struct atmel_pmecc_user_req *req);
void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user);
int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op);
void atmel_pmecc_disable(struct atmel_pmecc_user *user);
int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user);
int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
void *data, void *ecc);
bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user);
void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
int sector, void *ecc);
#endif /* ATMEL_PMECC_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,163 +0,0 @@
/*
* Error Corrected Code Controller (ECC) - System peripherals regsters.
* Based on AT91SAM9260 datasheet revision B.
*
* Copyright (C) 2007 Andrew Victor
* Copyright (C) 2007 - 2012 Atmel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef ATMEL_NAND_ECC_H
#define ATMEL_NAND_ECC_H
#define ATMEL_ECC_CR 0x00 /* Control register */
#define ATMEL_ECC_RST (1 << 0) /* Reset parity */
#define ATMEL_ECC_MR 0x04 /* Mode register */
#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */
#define ATMEL_ECC_PAGESIZE_528 (0)
#define ATMEL_ECC_PAGESIZE_1056 (1)
#define ATMEL_ECC_PAGESIZE_2112 (2)
#define ATMEL_ECC_PAGESIZE_4224 (3)
#define ATMEL_ECC_SR 0x08 /* Status register */
#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */
#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */
#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */
#define ATMEL_ECC_PR 0x0c /* Parity register */
#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */
#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */
#define ATMEL_ECC_NPR 0x10 /* NParity register */
#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */
/* PMECC Register Definitions */
#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */
#define PMECC_CFG_BCH_ERR2 (0 << 0)
#define PMECC_CFG_BCH_ERR4 (1 << 0)
#define PMECC_CFG_BCH_ERR8 (2 << 0)
#define PMECC_CFG_BCH_ERR12 (3 << 0)
#define PMECC_CFG_BCH_ERR24 (4 << 0)
#define PMECC_CFG_BCH_ERR32 (5 << 0)
#define PMECC_CFG_SECTOR512 (0 << 4)
#define PMECC_CFG_SECTOR1024 (1 << 4)
#define PMECC_CFG_PAGE_1SECTOR (0 << 8)
#define PMECC_CFG_PAGE_2SECTORS (1 << 8)
#define PMECC_CFG_PAGE_4SECTORS (2 << 8)
#define PMECC_CFG_PAGE_8SECTORS (3 << 8)
#define PMECC_CFG_READ_OP (0 << 12)
#define PMECC_CFG_WRITE_OP (1 << 12)
#define PMECC_CFG_SPARE_ENABLE (1 << 16)
#define PMECC_CFG_SPARE_DISABLE (0 << 16)
#define PMECC_CFG_AUTO_ENABLE (1 << 20)
#define PMECC_CFG_AUTO_DISABLE (0 << 20)
#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */
#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */
#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */
#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */
#define PMECC_CLK_133MHZ (2 << 0)
#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */
#define PMECC_CTRL_RST (1 << 0)
#define PMECC_CTRL_DATA (1 << 1)
#define PMECC_CTRL_USER (1 << 2)
#define PMECC_CTRL_ENABLE (1 << 4)
#define PMECC_CTRL_DISABLE (1 << 5)
#define ATMEL_PMECC_SR 0x018 /* PMECC status register */
#define PMECC_SR_BUSY (1 << 0)
#define PMECC_SR_ENABLE (1 << 4)
#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */
#define PMECC_IER_ENABLE (1 << 0)
#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */
#define PMECC_IER_DISABLE (1 << 0)
#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */
#define PMECC_IER_MASK (1 << 0)
#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */
#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */
#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */
/* PMERRLOC Register Definitions */
#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */
#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */
#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */
#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */
#define PMERRLOC_DISABLE (1 << 0)
#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */
#define PMERRLOC_ELSR_BUSY (1 << 0)
#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */
#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */
#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */
#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */
#define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
#define PMERRLOC_CALC_DONE (1 << 0)
#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */
/*
* The ATMEL_PMERRLOC_ELx register location depends from the number of
* bits corrected by the PMECC controller. Do not use it.
*/
/* Register access macros for PMECC */
#define pmecc_readl_relaxed(addr, reg) \
readl_relaxed((addr) + ATMEL_PMECC_##reg)
#define pmecc_writel(addr, reg, value) \
writel((value), (addr) + ATMEL_PMECC_##reg)
#define pmecc_readb_ecc_relaxed(addr, sector, n) \
readb_relaxed((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
#define pmecc_readl_rem_relaxed(addr, sector, n) \
readl_relaxed((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4))
#define pmerrloc_readl_relaxed(addr, reg) \
readl_relaxed((addr) + ATMEL_PMERRLOC_##reg)
#define pmerrloc_writel(addr, reg, value) \
writel((value), (addr) + ATMEL_PMERRLOC_##reg)
#define pmerrloc_writel_sigma_relaxed(addr, n, value) \
writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
#define pmerrloc_readl_sigma_relaxed(addr, n) \
readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
#define pmerrloc_readl_el_relaxed(addr, n) \
readl_relaxed((addr) + ((n) * 4))
/* Galois field dimension */
#define PMECC_GF_DIMENSION_13 13
#define PMECC_GF_DIMENSION_14 14
/* Primitive Polynomial used by PMECC */
#define PMECC_GF_13_PRIMITIVE_POLY 0x201b
#define PMECC_GF_14_PRIMITIVE_POLY 0x4443
#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
/* Time out value for reading PMECC status register */
#define PMECC_MAX_TIMEOUT_MS 100
/* Reserved bytes in oob area */
#define PMECC_OOB_RESERVED_BYTES 2
#endif

View File

@ -1,103 +0,0 @@
/*
* Atmel Nand Flash Controller (NFC) - System peripherals regsters.
* Based on SAMA5D3 datasheet.
*
* © Copyright 2013 Atmel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef ATMEL_NAND_NFC_H
#define ATMEL_NAND_NFC_H
/*
* HSMC NFC registers
*/
#define ATMEL_HSMC_NFC_CFG 0x00 /* NFC Configuration Register */
#define NFC_CFG_PAGESIZE (7 << 0)
#define NFC_CFG_PAGESIZE_512 (0 << 0)
#define NFC_CFG_PAGESIZE_1024 (1 << 0)
#define NFC_CFG_PAGESIZE_2048 (2 << 0)
#define NFC_CFG_PAGESIZE_4096 (3 << 0)
#define NFC_CFG_PAGESIZE_8192 (4 << 0)
#define NFC_CFG_WSPARE (1 << 8)
#define NFC_CFG_RSPARE (1 << 9)
#define NFC_CFG_NFC_DTOCYC (0xf << 16)
#define NFC_CFG_NFC_DTOMUL (0x7 << 20)
#define NFC_CFG_NFC_SPARESIZE (0x7f << 24)
#define NFC_CFG_NFC_SPARESIZE_BIT_POS 24
#define ATMEL_HSMC_NFC_CTRL 0x04 /* NFC Control Register */
#define NFC_CTRL_ENABLE (1 << 0)
#define NFC_CTRL_DISABLE (1 << 1)
#define ATMEL_HSMC_NFC_SR 0x08 /* NFC Status Register */
#define NFC_SR_BUSY (1 << 8)
#define NFC_SR_XFR_DONE (1 << 16)
#define NFC_SR_CMD_DONE (1 << 17)
#define NFC_SR_DTOE (1 << 20)
#define NFC_SR_UNDEF (1 << 21)
#define NFC_SR_AWB (1 << 22)
#define NFC_SR_ASE (1 << 23)
#define NFC_SR_RB_EDGE (1 << 24)
#define ATMEL_HSMC_NFC_IER 0x0c
#define ATMEL_HSMC_NFC_IDR 0x10
#define ATMEL_HSMC_NFC_IMR 0x14
#define ATMEL_HSMC_NFC_CYCLE0 0x18 /* NFC Address Cycle Zero */
#define ATMEL_HSMC_NFC_ADDR_CYCLE0 (0xff)
#define ATMEL_HSMC_NFC_BANK 0x1c /* NFC Bank Register */
#define ATMEL_HSMC_NFC_BANK0 (0 << 0)
#define ATMEL_HSMC_NFC_BANK1 (1 << 0)
#define nfc_writel(addr, reg, value) \
writel((value), (addr) + ATMEL_HSMC_NFC_##reg)
#define nfc_readl(addr, reg) \
readl_relaxed((addr) + ATMEL_HSMC_NFC_##reg)
/*
* NFC Address Command definitions
*/
#define NFCADDR_CMD_CMD1 (0xff << 2) /* Command for Cycle 1 */
#define NFCADDR_CMD_CMD1_BIT_POS 2
#define NFCADDR_CMD_CMD2 (0xff << 10) /* Command for Cycle 2 */
#define NFCADDR_CMD_CMD2_BIT_POS 10
#define NFCADDR_CMD_VCMD2 (0x1 << 18) /* Valid Cycle 2 Command */
#define NFCADDR_CMD_ACYCLE (0x7 << 19) /* Number of Address required */
#define NFCADDR_CMD_ACYCLE_NONE (0x0 << 19)
#define NFCADDR_CMD_ACYCLE_1 (0x1 << 19)
#define NFCADDR_CMD_ACYCLE_2 (0x2 << 19)
#define NFCADDR_CMD_ACYCLE_3 (0x3 << 19)
#define NFCADDR_CMD_ACYCLE_4 (0x4 << 19)
#define NFCADDR_CMD_ACYCLE_5 (0x5 << 19)
#define NFCADDR_CMD_ACYCLE_BIT_POS 19
#define NFCADDR_CMD_CSID (0x7 << 22) /* Chip Select Identifier */
#define NFCADDR_CMD_CSID_0 (0x0 << 22)
#define NFCADDR_CMD_CSID_1 (0x1 << 22)
#define NFCADDR_CMD_CSID_2 (0x2 << 22)
#define NFCADDR_CMD_CSID_3 (0x3 << 22)
#define NFCADDR_CMD_CSID_4 (0x4 << 22)
#define NFCADDR_CMD_CSID_5 (0x5 << 22)
#define NFCADDR_CMD_CSID_6 (0x6 << 22)
#define NFCADDR_CMD_CSID_7 (0x7 << 22)
#define NFCADDR_CMD_DATAEN (0x1 << 25) /* Data Transfer Enable */
#define NFCADDR_CMD_DATADIS (0x0 << 25) /* Data Transfer Disable */
#define NFCADDR_CMD_NFCRD (0x0 << 26) /* NFC Read Enable */
#define NFCADDR_CMD_NFCWR (0x1 << 26) /* NFC Write Enable */
#define NFCADDR_CMD_NFCBUSY (0x1 << 27) /* NFC Busy */
#define nfc_cmd_addr1234_writel(cmd, addr1234, nfc_base) \
writel((addr1234), (cmd) + nfc_base)
#define nfc_cmd_readl(bitstatus, nfc_base) \
readl_relaxed((bitstatus) + nfc_base)
#define NFC_TIME_OUT_MS 100
#define NFC_SRAM_BANK1_OFFSET 0x1200
#endif

View File

@ -101,6 +101,9 @@ struct brcm_nand_dma_desc {
#define BRCMNAND_MIN_BLOCKSIZE (8 * 1024)
#define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024)
#define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY)
#define NAND_POLL_STATUS_TIMEOUT_MS 100
/* Controller feature flags */
enum {
BRCMNAND_HAS_1K_SECTORS = BIT(0),
@ -765,6 +768,31 @@ enum {
CS_SELECT_AUTO_DEVICE_ID_CFG = BIT(30),
};
static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
u32 mask, u32 expected_val,
unsigned long timeout_ms)
{
unsigned long limit;
u32 val;
if (!timeout_ms)
timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
limit = jiffies + msecs_to_jiffies(timeout_ms);
do {
val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
if ((val & mask) == expected_val)
return 0;
cpu_relax();
} while (time_after(limit, jiffies));
dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
expected_val, val & mask);
return -ETIMEDOUT;
}
static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
{
u32 val = en ? CS_SELECT_NAND_WP : 0;
@ -1024,12 +1052,39 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)
if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
static int old_wp = -1;
int ret;
if (old_wp != wp) {
dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
old_wp = wp;
}
/*
* make sure ctrl/flash ready before and after
* changing state of #WP pin
*/
ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY |
NAND_STATUS_READY,
NAND_CTRL_RDY |
NAND_STATUS_READY, 0);
if (ret)
return;
brcmnand_set_wp(ctrl, wp);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
ret = bcmnand_ctrl_poll_status(ctrl,
NAND_CTRL_RDY |
NAND_STATUS_READY |
NAND_STATUS_WP,
NAND_CTRL_RDY |
NAND_STATUS_READY |
(wp ? 0 : NAND_STATUS_WP), 0);
if (ret)
dev_err_ratelimited(&host->pdev->dev,
"nand #WP expected %s\n",
wp ? "on" : "off");
}
}
@ -1157,15 +1212,15 @@ static irqreturn_t brcmnand_dma_irq(int irq, void *data)
static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
{
struct brcmnand_controller *ctrl = host->ctrl;
u32 intfc;
int ret;
dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
BUG_ON(ctrl->cmd_pending != 0);
ctrl->cmd_pending = cmd;
intfc = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
WARN_ON(!(intfc & INTFC_CTLR_READY));
ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
WARN_ON(ret);
mb(); /* flush previous writes */
brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,

View File

@ -145,7 +145,7 @@ static int __init cmx270_init(void)
ret = gpio_request(GPIO_NAND_CS, "NAND CS");
if (ret) {
pr_warning("CM-X270: failed to request NAND CS gpio\n");
pr_warn("CM-X270: failed to request NAND CS gpio\n");
return ret;
}
@ -153,7 +153,7 @@ static int __init cmx270_init(void)
ret = gpio_request(GPIO_NAND_RB, "NAND R/B");
if (ret) {
pr_warning("CM-X270: failed to request NAND R/B gpio\n");
pr_warn("CM-X270: failed to request NAND R/B gpio\n");
goto err_gpio_request;
}

View File

@ -581,6 +581,17 @@ static struct davinci_nand_pdata
"ti,davinci-nand-use-bbt"))
pdata->bbt_options = NAND_BBT_USE_FLASH;
/*
* Since kernel v4.8, this driver has been fixed to enable
* use of 4-bit hardware ECC with subpages and verified on
* TI's keystone EVMs (K2L, K2HK and K2E).
* However, in the interest of not breaking systems using
* existing UBI partitions, sub-page writes are not being
* (re)enabled. If you want to use subpage writes on Keystone
* platforms (i.e. do not have any existing UBI partitions),
* then use "ti,davinci-nand" as the compatible in your
* device-tree file.
*/
if (of_device_is_compatible(pdev->dev.of_node,
"ti,keystone-nand")) {
pdata->options |= NAND_NO_SUBPAGE_WRITE;

View File

@ -45,16 +45,16 @@ MODULE_PARM_DESC(onfi_timing_mode,
* We define a macro here that combines all interrupts this driver uses into
* a single constant value, for convenience.
*/
#define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \
INTR_STATUS__ECC_TRANSACTION_DONE | \
INTR_STATUS__ECC_ERR | \
INTR_STATUS__PROGRAM_FAIL | \
INTR_STATUS__LOAD_COMP | \
INTR_STATUS__PROGRAM_COMP | \
INTR_STATUS__TIME_OUT | \
INTR_STATUS__ERASE_FAIL | \
INTR_STATUS__RST_COMP | \
INTR_STATUS__ERASE_COMP)
#define DENALI_IRQ_ALL (INTR__DMA_CMD_COMP | \
INTR__ECC_TRANSACTION_DONE | \
INTR__ECC_ERR | \
INTR__PROGRAM_FAIL | \
INTR__LOAD_COMP | \
INTR__PROGRAM_COMP | \
INTR__TIME_OUT | \
INTR__ERASE_FAIL | \
INTR__RST_COMP | \
INTR__ERASE_COMP)
/*
* indicates whether or not the internal value for the flash bank is
@ -62,8 +62,6 @@ MODULE_PARM_DESC(onfi_timing_mode,
*/
#define CHIP_SELECT_INVALID -1
#define SUPPORT_8BITECC 1
/*
* This macro divides two integers and rounds fractional values up
* to the nearest integer value.
@ -86,16 +84,10 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
#define SPARE_ACCESS 0x41
#define MAIN_ACCESS 0x42
#define MAIN_SPARE_ACCESS 0x43
#define PIPELINE_ACCESS 0x2000
#define DENALI_READ 0
#define DENALI_WRITE 0x100
/* types of device accesses. We can issue commands and get status */
#define COMMAND_CYCLE 0
#define ADDR_CYCLE 1
#define STATUS_CYCLE 2
/*
* this is a helper macro that allows us to
* format the bank into the proper bits for the controller
@ -164,7 +156,7 @@ static void read_status(struct denali_nand_info *denali)
static void reset_bank(struct denali_nand_info *denali)
{
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT;
uint32_t irq_mask = INTR__RST_COMP | INTR__TIME_OUT;
clear_interrupts(denali);
@ -172,7 +164,7 @@ static void reset_bank(struct denali_nand_info *denali)
irq_status = wait_for_irq(denali, irq_mask);
if (irq_status & INTR_STATUS__TIME_OUT)
if (irq_status & INTR__TIME_OUT)
dev_err(denali->dev, "reset bank failed.\n");
}
@ -182,22 +174,22 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali)
int i;
for (i = 0; i < denali->max_banks; i++)
iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
iowrite32(INTR__RST_COMP | INTR__TIME_OUT,
denali->flash_reg + INTR_STATUS(i));
for (i = 0; i < denali->max_banks; i++) {
iowrite32(1 << i, denali->flash_reg + DEVICE_RESET);
while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) &
(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT)))
(INTR__RST_COMP | INTR__TIME_OUT)))
cpu_relax();
if (ioread32(denali->flash_reg + INTR_STATUS(i)) &
INTR_STATUS__TIME_OUT)
INTR__TIME_OUT)
dev_dbg(denali->dev,
"NAND Reset operation timed out on bank %d\n", i);
}
for (i = 0; i < denali->max_banks; i++)
iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
iowrite32(INTR__RST_COMP | INTR__TIME_OUT,
denali->flash_reg + INTR_STATUS(i));
return PASS;
@ -347,52 +339,25 @@ static void get_samsung_nand_para(struct denali_nand_info *denali,
static void get_toshiba_nand_para(struct denali_nand_info *denali)
{
uint32_t tmp;
/*
* Workaround to fix a controller bug which reports a wrong
* spare area size for some kind of Toshiba NAND device
*/
if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
(ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) {
(ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64))
iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
tmp = ioread32(denali->flash_reg + DEVICES_CONNECTED) *
ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
iowrite32(tmp,
denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
#if SUPPORT_15BITECC
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
#elif SUPPORT_8BITECC
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
#endif
}
}
static void get_hynix_nand_para(struct denali_nand_info *denali,
uint8_t device_id)
{
uint32_t main_size, spare_size;
switch (device_id) {
case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */
iowrite32(128, denali->flash_reg + PAGES_PER_BLOCK);
iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
main_size = 4096 *
ioread32(denali->flash_reg + DEVICES_CONNECTED);
spare_size = 224 *
ioread32(denali->flash_reg + DEVICES_CONNECTED);
iowrite32(main_size,
denali->flash_reg + LOGICAL_PAGE_DATA_SIZE);
iowrite32(spare_size,
denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
iowrite32(0, denali->flash_reg + DEVICE_WIDTH);
#if SUPPORT_15BITECC
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
#elif SUPPORT_8BITECC
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
#endif
break;
default:
dev_warn(denali->dev,
@ -454,17 +419,12 @@ static void find_valid_banks(struct denali_nand_info *denali)
static void detect_max_banks(struct denali_nand_info *denali)
{
uint32_t features = ioread32(denali->flash_reg + FEATURES);
/*
* Read the revision register, so we can calculate the max_banks
* properly: the encoding changed from rev 5.0 to 5.1
*/
u32 revision = MAKE_COMPARABLE_REVISION(
ioread32(denali->flash_reg + REVISION));
if (revision < REVISION_5_1)
denali->max_banks = 2 << (features & FEATURES__N_BANKS);
else
denali->max_banks = 1 << (features & FEATURES__N_BANKS);
denali->max_banks = 1 << (features & FEATURES__N_BANKS);
/* the encoding changed from rev 5.0 to 5.1 */
if (denali->revision < 0x0501)
denali->max_banks <<= 1;
}
static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
@ -653,7 +613,6 @@ static irqreturn_t denali_isr(int irq, void *dev_id)
spin_unlock(&denali->irq_lock);
return result;
}
#define BANK(x) ((x) << 24)
static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
{
@ -718,15 +677,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
int access_type, int op)
{
int status = PASS;
uint32_t page_count = 1;
uint32_t addr, cmd, irq_status, irq_mask;
if (op == DENALI_READ)
irq_mask = INTR_STATUS__LOAD_COMP;
else if (op == DENALI_WRITE)
irq_mask = 0;
else
BUG();
uint32_t addr, cmd;
setup_ecc_for_xfer(denali, ecc_en, transfer_spare);
@ -749,35 +700,8 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
cmd = MODE_10 | addr;
index_addr(denali, cmd, access_type);
/*
* page 33 of the NAND controller spec indicates we should not
* use the pipeline commands in Spare area only mode.
* So we don't.
*/
if (access_type == SPARE_ACCESS) {
cmd = MODE_01 | addr;
iowrite32(cmd, denali->flash_mem);
} else {
index_addr(denali, cmd,
PIPELINE_ACCESS | op | page_count);
/*
* wait for command to be accepted
* can always use status0 bit as the
* mask is identical for each bank.
*/
irq_status = wait_for_irq(denali, irq_mask);
if (irq_status == 0) {
dev_err(denali->dev,
"cmd, page, addr on timeout (0x%x, 0x%x, 0x%x)\n",
cmd, denali->page, addr);
status = FAIL;
} else {
cmd = MODE_01 | addr;
iowrite32(cmd, denali->flash_mem);
}
}
cmd = MODE_01 | addr;
iowrite32(cmd, denali->flash_mem);
}
return status;
}
@ -829,8 +753,7 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP |
INTR_STATUS__PROGRAM_FAIL;
uint32_t irq_mask = INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL;
int status = 0;
denali->page = page;
@ -857,7 +780,7 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
uint32_t irq_mask = INTR_STATUS__LOAD_COMP;
uint32_t irq_mask = INTR__LOAD_COMP;
uint32_t irq_status, addr, cmd;
denali->page = page;
@ -890,98 +813,158 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
}
}
/*
* this function examines buffers to see if they contain data that
* indicate that the buffer is part of an erased region of flash.
*/
static bool is_erased(uint8_t *buf, int len)
static int denali_check_erased_page(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf,
unsigned long uncor_ecc_flags,
unsigned int max_bitflips)
{
int i;
uint8_t *ecc_code = chip->buffers->ecccode;
int ecc_steps = chip->ecc.steps;
int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes;
int i, ret, stat;
for (i = 0; i < len; i++)
if (buf[i] != 0xFF)
return false;
return true;
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total);
if (ret)
return ret;
for (i = 0; i < ecc_steps; i++) {
if (!(uncor_ecc_flags & BIT(i)))
continue;
stat = nand_check_erased_ecc_chunk(buf, ecc_size,
ecc_code, ecc_bytes,
NULL, 0,
chip->ecc.strength);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
buf += ecc_size;
ecc_code += ecc_bytes;
}
return max_bitflips;
}
static int denali_hw_ecc_fixup(struct mtd_info *mtd,
struct denali_nand_info *denali,
unsigned long *uncor_ecc_flags)
{
struct nand_chip *chip = mtd_to_nand(mtd);
int bank = denali->flash_bank;
uint32_t ecc_cor;
unsigned int max_bitflips;
ecc_cor = ioread32(denali->flash_reg + ECC_COR_INFO(bank));
ecc_cor >>= ECC_COR_INFO__SHIFT(bank);
if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
/*
* This flag is set when uncorrectable error occurs at least in
* one ECC sector. We can not know "how many sectors", or
* "which sector(s)". We need erase-page check for all sectors.
*/
*uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0);
return 0;
}
max_bitflips = ecc_cor & ECC_COR_INFO__MAX_ERRORS;
/*
* The register holds the maximum of per-sector corrected bitflips.
* This is suitable for the return value of the ->read_page() callback.
* Unfortunately, we can not know the total number of corrected bits in
* the page. Increase the stats by max_bitflips. (compromised solution)
*/
mtd->ecc_stats.corrected += max_bitflips;
return max_bitflips;
}
#define ECC_SECTOR_SIZE 512
#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
#define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET))
#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK)
#define ECC_ERROR_CORRECTABLE(x) (!((x) & ERR_CORRECTION_INFO__ERROR_TYPE))
#define ECC_ERROR_UNCORRECTABLE(x) ((x) & ERR_CORRECTION_INFO__ERROR_TYPE)
#define ECC_ERR_DEVICE(x) (((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8)
#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)
static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
uint32_t irq_status, unsigned int *max_bitflips)
static int denali_sw_ecc_fixup(struct mtd_info *mtd,
struct denali_nand_info *denali,
unsigned long *uncor_ecc_flags, uint8_t *buf)
{
bool check_erased_page = false;
unsigned int bitflips = 0;
unsigned int max_bitflips = 0;
uint32_t err_addr, err_cor_info;
unsigned int err_byte, err_sector, err_device;
uint8_t err_cor_value;
unsigned int prev_sector = 0;
if (irq_status & INTR_STATUS__ECC_ERR) {
/* read the ECC errors. we'll ignore them for now */
uint32_t err_address, err_correction_info, err_byte,
err_sector, err_device, err_correction_value;
denali_set_intr_modes(denali, false);
/* read the ECC errors. we'll ignore them for now */
denali_set_intr_modes(denali, false);
do {
err_address = ioread32(denali->flash_reg +
ECC_ERROR_ADDRESS);
err_sector = ECC_SECTOR(err_address);
err_byte = ECC_BYTE(err_address);
do {
err_addr = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS);
err_sector = ECC_SECTOR(err_addr);
err_byte = ECC_BYTE(err_addr);
err_correction_info = ioread32(denali->flash_reg +
ERR_CORRECTION_INFO);
err_correction_value =
ECC_CORRECTION_VALUE(err_correction_info);
err_device = ECC_ERR_DEVICE(err_correction_info);
err_cor_info = ioread32(denali->flash_reg + ERR_CORRECTION_INFO);
err_cor_value = ECC_CORRECTION_VALUE(err_cor_info);
err_device = ECC_ERR_DEVICE(err_cor_info);
if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
/*
* If err_byte is larger than ECC_SECTOR_SIZE,
* means error happened in OOB, so we ignore
* it. It's no need for us to correct it
* err_device is represented the NAND error
* bits are happened in if there are more
* than one NAND connected.
*/
if (err_byte < ECC_SECTOR_SIZE) {
struct mtd_info *mtd =
nand_to_mtd(&denali->nand);
int offset;
/* reset the bitflip counter when crossing ECC sector */
if (err_sector != prev_sector)
bitflips = 0;
offset = (err_sector *
ECC_SECTOR_SIZE +
err_byte) *
denali->devnum +
err_device;
/* correct the ECC error */
buf[offset] ^= err_correction_value;
mtd->ecc_stats.corrected++;
bitflips++;
}
} else {
/*
* if the error is not correctable, need to
* look at the page to see if it is an erased
* page. if so, then it's not a real ECC error
*/
check_erased_page = true;
}
} while (!ECC_LAST_ERR(err_correction_info));
/*
* Once handle all ecc errors, controller will triger
* a ECC_TRANSACTION_DONE interrupt, so here just wait
* for a while for this interrupt
*/
while (!(read_interrupt_status(denali) &
INTR_STATUS__ECC_TRANSACTION_DONE))
cpu_relax();
clear_interrupts(denali);
denali_set_intr_modes(denali, true);
}
*max_bitflips = bitflips;
return check_erased_page;
if (ECC_ERROR_UNCORRECTABLE(err_cor_info)) {
/*
* Check later if this is a real ECC error, or
* an erased sector.
*/
*uncor_ecc_flags |= BIT(err_sector);
} else if (err_byte < ECC_SECTOR_SIZE) {
/*
* If err_byte is larger than ECC_SECTOR_SIZE, means error
* happened in OOB, so we ignore it. It's no need for
* us to correct it err_device is represented the NAND
* error bits are happened in if there are more than
* one NAND connected.
*/
int offset;
unsigned int flips_in_byte;
offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
denali->devnum + err_device;
/* correct the ECC error */
flips_in_byte = hweight8(buf[offset] ^ err_cor_value);
buf[offset] ^= err_cor_value;
mtd->ecc_stats.corrected += flips_in_byte;
bitflips += flips_in_byte;
max_bitflips = max(max_bitflips, bitflips);
}
prev_sector = err_sector;
} while (!ECC_LAST_ERR(err_cor_info));
/*
* Once handle all ecc errors, controller will trigger a
* ECC_TRANSACTION_DONE interrupt, so here just wait for
* a while for this interrupt
*/
while (!(read_interrupt_status(denali) & INTR__ECC_TRANSACTION_DONE))
cpu_relax();
clear_interrupts(denali);
denali_set_intr_modes(denali, true);
return max_bitflips;
}
/* programs the controller to either enable/disable DMA transfers */
@ -991,8 +974,30 @@ static void denali_enable_dma(struct denali_nand_info *denali, bool en)
ioread32(denali->flash_reg + DMA_ENABLE);
}
/* setups the HW to perform the data DMA */
static void denali_setup_dma(struct denali_nand_info *denali, int op)
static void denali_setup_dma64(struct denali_nand_info *denali, int op)
{
uint32_t mode;
const int page_count = 1;
uint64_t addr = denali->buf.dma_buf;
mode = MODE_10 | BANK(denali->flash_bank) | denali->page;
/* DMA is a three step process */
/*
* 1. setup transfer type, interrupt when complete,
* burst len = 64 bytes, the number of pages
*/
index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count);
/* 2. set memory low address */
index_addr(denali, mode, addr);
/* 3. set memory high address */
index_addr(denali, mode, addr >> 32);
}
static void denali_setup_dma32(struct denali_nand_info *denali, int op)
{
uint32_t mode;
const int page_count = 1;
@ -1015,6 +1020,14 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
index_addr(denali, mode | 0x14000, 0x2400);
}
static void denali_setup_dma(struct denali_nand_info *denali, int op)
{
if (denali->caps & DENALI_CAP_DMA_64BIT)
denali_setup_dma64(denali, op);
else
denali_setup_dma32(denali, op);
}
/*
* writes a page. user specifies type, and this function handles the
* configuration details.
@ -1026,8 +1039,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP |
INTR_STATUS__PROGRAM_FAIL;
uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL;
/*
* if it is a raw xfer, we want to disable ecc and send the spare area.
@ -1118,16 +1130,15 @@ static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
unsigned int max_bitflips;
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE |
INTR_STATUS__ECC_ERR;
bool check_erased_page = false;
uint32_t irq_mask = denali->caps & DENALI_CAP_HW_ECC_FIXUP ?
INTR__DMA_CMD_COMP | INTR__ECC_UNCOR_ERR :
INTR__ECC_TRANSACTION_DONE | INTR__ECC_ERR;
unsigned long uncor_ecc_flags = 0;
int stat = 0;
if (page != denali->page) {
dev_err(denali->dev,
@ -1151,21 +1162,23 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
memcpy(buf, denali->buf.buf, mtd->writesize);
check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips);
if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags);
else if (irq_status & INTR__ECC_ERR)
stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf);
denali_enable_dma(denali, false);
if (check_erased_page) {
if (stat < 0)
return stat;
if (uncor_ecc_flags) {
read_oob_data(mtd, chip->oob_poi, denali->page);
/* check ECC failures that may have occurred on erased pages */
if (check_erased_page) {
if (!is_erased(buf, mtd->writesize))
mtd->ecc_stats.failed++;
if (!is_erased(buf, mtd->oobsize))
mtd->ecc_stats.failed++;
}
stat = denali_check_erased_page(mtd, chip, buf,
uncor_ecc_flags, stat);
}
return max_bitflips;
return stat;
}
static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
@ -1174,7 +1187,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP;
uint32_t irq_mask = INTR__DMA_CMD_COMP;
if (page != denali->page) {
dev_err(denali->dev,
@ -1247,10 +1260,9 @@ static int denali_erase(struct mtd_info *mtd, int page)
index_addr(denali, cmd, 0x1);
/* wait for erase to complete or failure to occur */
irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP |
INTR_STATUS__ERASE_FAIL);
irq_status = wait_for_irq(denali, INTR__ERASE_COMP | INTR__ERASE_FAIL);
return irq_status & INTR_STATUS__ERASE_FAIL ? NAND_STATUS_FAIL : PASS;
return irq_status & INTR__ERASE_FAIL ? NAND_STATUS_FAIL : PASS;
}
static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
@ -1302,6 +1314,14 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
/* Initialization code to bring the device up to a known good state */
static void denali_hw_init(struct denali_nand_info *denali)
{
/*
* The REVISION register may not be reliable. Platforms are allowed to
* override it.
*/
if (!denali->revision)
denali->revision =
swab16(ioread32(denali->flash_reg + REVISION));
/*
* tell driver how many bit controller will skip before
* writing ECC code in OOB, this register may be already
@ -1413,9 +1433,61 @@ static void denali_drv_init(struct denali_nand_info *denali)
denali->irq_status = 0;
}
static int denali_multidev_fixup(struct denali_nand_info *denali)
{
struct nand_chip *chip = &denali->nand;
struct mtd_info *mtd = nand_to_mtd(chip);
/*
* Support for multi device:
* When the IP configuration is x16 capable and two x8 chips are
* connected in parallel, DEVICES_CONNECTED should be set to 2.
* In this case, the core framework knows nothing about this fact,
* so we should tell it the _logical_ pagesize and anything necessary.
*/
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
/*
* On some SoCs, DEVICES_CONNECTED is not auto-detected.
* For those, DEVICES_CONNECTED is left to 0. Set 1 if it is the case.
*/
if (denali->devnum == 0) {
denali->devnum = 1;
iowrite32(1, denali->flash_reg + DEVICES_CONNECTED);
}
if (denali->devnum == 1)
return 0;
if (denali->devnum != 2) {
dev_err(denali->dev, "unsupported number of devices %d\n",
denali->devnum);
return -EINVAL;
}
/* 2 chips in parallel */
mtd->size <<= 1;
mtd->erasesize <<= 1;
mtd->writesize <<= 1;
mtd->oobsize <<= 1;
chip->chipsize <<= 1;
chip->page_shift += 1;
chip->phys_erase_shift += 1;
chip->bbt_erase_shift += 1;
chip->chip_shift += 1;
chip->pagemask <<= 1;
chip->ecc.size <<= 1;
chip->ecc.bytes <<= 1;
chip->ecc.strength <<= 1;
denali->bbtskipbytes <<= 1;
return 0;
}
int denali_init(struct denali_nand_info *denali)
{
struct mtd_info *mtd = nand_to_mtd(&denali->nand);
struct nand_chip *chip = &denali->nand;
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
if (denali->platform == INTEL_CE4100) {
@ -1449,13 +1521,16 @@ int denali_init(struct denali_nand_info *denali)
/* now that our ISR is registered, we can enable interrupts */
denali_set_intr_modes(denali, true);
mtd->name = "denali-nand";
nand_set_flash_node(chip, denali->dev->of_node);
/* Fallback to the default name if DT did not give "label" property */
if (!mtd->name)
mtd->name = "denali-nand";
/* register the driver with the NAND core subsystem */
denali->nand.select_chip = denali_select_chip;
denali->nand.cmdfunc = denali_cmdfunc;
denali->nand.read_byte = denali_read_byte;
denali->nand.waitfunc = denali_waitfunc;
chip->select_chip = denali_select_chip;
chip->cmdfunc = denali_cmdfunc;
chip->read_byte = denali_read_byte;
chip->waitfunc = denali_waitfunc;
/*
* scan for NAND devices attached to the controller
@ -1476,8 +1551,9 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
}
/* Is 32-bit DMA supported? */
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
ret = dma_set_mask(denali->dev,
DMA_BIT_MASK(denali->caps & DENALI_CAP_DMA_64BIT ?
64 : 32));
if (ret) {
dev_err(denali->dev, "No usable DMA configuration\n");
goto failed_req_irq;
@ -1492,25 +1568,6 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
}
/*
* support for multi nand
* MTD known nothing about multi nand, so we should tell it
* the real pagesize and anything necessery
*/
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
denali->nand.chipsize <<= denali->devnum - 1;
denali->nand.page_shift += denali->devnum - 1;
denali->nand.pagemask = (denali->nand.chipsize >>
denali->nand.page_shift) - 1;
denali->nand.bbt_erase_shift += denali->devnum - 1;
denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift;
denali->nand.chip_shift += denali->devnum - 1;
mtd->writesize <<= denali->devnum - 1;
mtd->oobsize <<= denali->devnum - 1;
mtd->erasesize <<= denali->devnum - 1;
mtd->size = denali->nand.numchips * denali->nand.chipsize;
denali->bbtskipbytes *= denali->devnum;
/*
* second stage of the NAND scan
* this stage requires information regarding ECC and
@ -1518,29 +1575,29 @@ int denali_init(struct denali_nand_info *denali)
*/
/* Bad block management */
denali->nand.bbt_td = &bbt_main_descr;
denali->nand.bbt_md = &bbt_mirror_descr;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
/* skip the scan for now until we have OOB read and write support */
denali->nand.bbt_options |= NAND_BBT_USE_FLASH;
denali->nand.options |= NAND_SKIP_BBTSCAN;
denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
chip->bbt_options |= NAND_BBT_USE_FLASH;
chip->options |= NAND_SKIP_BBTSCAN;
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
/* no subpage writes on denali */
denali->nand.options |= NAND_NO_SUBPAGE_WRITE;
chip->options |= NAND_NO_SUBPAGE_WRITE;
/*
* Denali Controller only support 15bit and 8bit ECC in MRST,
* so just let controller do 15bit ECC for MLC and 8bit ECC for
* SLC if possible.
* */
if (!nand_is_slc(&denali->nand) &&
if (!nand_is_slc(chip) &&
(mtd->oobsize > (denali->bbtskipbytes +
ECC_15BITS * (mtd->writesize /
ECC_SECTOR_SIZE)))) {
/* if MLC OOB size is large enough, use 15bit ECC*/
denali->nand.ecc.strength = 15;
denali->nand.ecc.bytes = ECC_15BITS;
chip->ecc.strength = 15;
chip->ecc.bytes = ECC_15BITS;
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
} else if (mtd->oobsize < (denali->bbtskipbytes +
ECC_8BITS * (mtd->writesize /
@ -1548,24 +1605,26 @@ int denali_init(struct denali_nand_info *denali)
pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
goto failed_req_irq;
} else {
denali->nand.ecc.strength = 8;
denali->nand.ecc.bytes = ECC_8BITS;
chip->ecc.strength = 8;
chip->ecc.bytes = ECC_8BITS;
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
}
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
denali->nand.ecc.bytes *= denali->devnum;
denali->nand.ecc.strength *= denali->devnum;
/* override the default read operations */
denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
denali->nand.ecc.read_page = denali_read_page;
denali->nand.ecc.read_page_raw = denali_read_page_raw;
denali->nand.ecc.write_page = denali_write_page;
denali->nand.ecc.write_page_raw = denali_write_page_raw;
denali->nand.ecc.read_oob = denali_read_oob;
denali->nand.ecc.write_oob = denali_write_oob;
denali->nand.erase = denali_erase;
chip->ecc.size = ECC_SECTOR_SIZE;
chip->ecc.read_page = denali_read_page;
chip->ecc.read_page_raw = denali_read_page_raw;
chip->ecc.write_page = denali_write_page;
chip->ecc.write_page_raw = denali_write_page_raw;
chip->ecc.read_oob = denali_read_oob;
chip->ecc.write_oob = denali_write_oob;
chip->erase = denali_erase;
ret = denali_multidev_fixup(denali);
if (ret)
goto failed_req_irq;
ret = nand_scan_tail(mtd);
if (ret)

View File

@ -20,6 +20,7 @@
#ifndef __DENALI_H__
#define __DENALI_H__
#include <linux/bitops.h>
#include <linux/mtd/nand.h>
#define DEVICE_RESET 0x0
@ -178,8 +179,6 @@
#define REVISION 0x370
#define REVISION__VALUE 0xffff
#define MAKE_COMPARABLE_REVISION(x) swab16((x) & REVISION__VALUE)
#define REVISION_5_1 0x00000501
#define ONFI_DEVICE_FEATURES 0x380
#define ONFI_DEVICE_FEATURES__VALUE 0x003f
@ -218,65 +217,29 @@
#define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50))
#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50))
#define INTR_STATUS__ECC_TRANSACTION_DONE 0x0001
#define INTR_STATUS__ECC_ERR 0x0002
#define INTR_STATUS__DMA_CMD_COMP 0x0004
#define INTR_STATUS__TIME_OUT 0x0008
#define INTR_STATUS__PROGRAM_FAIL 0x0010
#define INTR_STATUS__ERASE_FAIL 0x0020
#define INTR_STATUS__LOAD_COMP 0x0040
#define INTR_STATUS__PROGRAM_COMP 0x0080
#define INTR_STATUS__ERASE_COMP 0x0100
#define INTR_STATUS__PIPE_CPYBCK_CMD_COMP 0x0200
#define INTR_STATUS__LOCKED_BLK 0x0400
#define INTR_STATUS__UNSUP_CMD 0x0800
#define INTR_STATUS__INT_ACT 0x1000
#define INTR_STATUS__RST_COMP 0x2000
#define INTR_STATUS__PIPE_CMD_ERR 0x4000
#define INTR_STATUS__PAGE_XFER_INC 0x8000
#define INTR_EN__ECC_TRANSACTION_DONE 0x0001
#define INTR_EN__ECC_ERR 0x0002
#define INTR_EN__DMA_CMD_COMP 0x0004
#define INTR_EN__TIME_OUT 0x0008
#define INTR_EN__PROGRAM_FAIL 0x0010
#define INTR_EN__ERASE_FAIL 0x0020
#define INTR_EN__LOAD_COMP 0x0040
#define INTR_EN__PROGRAM_COMP 0x0080
#define INTR_EN__ERASE_COMP 0x0100
#define INTR_EN__PIPE_CPYBCK_CMD_COMP 0x0200
#define INTR_EN__LOCKED_BLK 0x0400
#define INTR_EN__UNSUP_CMD 0x0800
#define INTR_EN__INT_ACT 0x1000
#define INTR_EN__RST_COMP 0x2000
#define INTR_EN__PIPE_CMD_ERR 0x4000
#define INTR_EN__PAGE_XFER_INC 0x8000
/* bit[1:0] is used differently depending on IP version */
#define INTR__ECC_UNCOR_ERR 0x0001 /* new IP */
#define INTR__ECC_TRANSACTION_DONE 0x0001 /* old IP */
#define INTR__ECC_ERR 0x0002 /* old IP */
#define INTR__DMA_CMD_COMP 0x0004
#define INTR__TIME_OUT 0x0008
#define INTR__PROGRAM_FAIL 0x0010
#define INTR__ERASE_FAIL 0x0020
#define INTR__LOAD_COMP 0x0040
#define INTR__PROGRAM_COMP 0x0080
#define INTR__ERASE_COMP 0x0100
#define INTR__PIPE_CPYBCK_CMD_COMP 0x0200
#define INTR__LOCKED_BLK 0x0400
#define INTR__UNSUP_CMD 0x0800
#define INTR__INT_ACT 0x1000
#define INTR__RST_COMP 0x2000
#define INTR__PIPE_CMD_ERR 0x4000
#define INTR__PAGE_XFER_INC 0x8000
#define PAGE_CNT(__bank) (0x430 + ((__bank) * 0x50))
#define ERR_PAGE_ADDR(__bank) (0x440 + ((__bank) * 0x50))
#define ERR_BLOCK_ADDR(__bank) (0x450 + ((__bank) * 0x50))
#define DATA_INTR 0x550
#define DATA_INTR__WRITE_SPACE_AV 0x0001
#define DATA_INTR__READ_DATA_AV 0x0002
#define DATA_INTR_EN 0x560
#define DATA_INTR_EN__WRITE_SPACE_AV 0x0001
#define DATA_INTR_EN__READ_DATA_AV 0x0002
#define GPREG_0 0x570
#define GPREG_0__VALUE 0xffff
#define GPREG_1 0x580
#define GPREG_1__VALUE 0xffff
#define GPREG_2 0x590
#define GPREG_2__VALUE 0xffff
#define GPREG_3 0x5a0
#define GPREG_3__VALUE 0xffff
#define ECC_THRESHOLD 0x600
#define ECC_THRESHOLD__VALUE 0x03ff
@ -297,6 +260,11 @@
#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000
#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000
#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10)
#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8)
#define ECC_COR_INFO__MAX_ERRORS 0x007f
#define ECC_COR_INFO__UNCOR_ERR 0x0080
#define DMA_ENABLE 0x700
#define DMA_ENABLE__FLAG 0x0001
@ -304,20 +272,13 @@
#define IGNORE_ECC_DONE__FLAG 0x0001
#define DMA_INTR 0x720
#define DMA_INTR_EN 0x730
#define DMA_INTR__TARGET_ERROR 0x0001
#define DMA_INTR__DESC_COMP_CHANNEL0 0x0002
#define DMA_INTR__DESC_COMP_CHANNEL1 0x0004
#define DMA_INTR__DESC_COMP_CHANNEL2 0x0008
#define DMA_INTR__DESC_COMP_CHANNEL3 0x0010
#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020
#define DMA_INTR_EN 0x730
#define DMA_INTR_EN__TARGET_ERROR 0x0001
#define DMA_INTR_EN__DESC_COMP_CHANNEL0 0x0002
#define DMA_INTR_EN__DESC_COMP_CHANNEL1 0x0004
#define DMA_INTR_EN__DESC_COMP_CHANNEL2 0x0008
#define DMA_INTR_EN__DESC_COMP_CHANNEL3 0x0010
#define DMA_INTR_EN__MEMCOPY_DESC_COMP 0x0020
#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020
#define TARGET_ERR_ADDR_LO 0x740
#define TARGET_ERR_ADDR_LO__VALUE 0xffff
@ -331,69 +292,12 @@
#define CHNL_ACTIVE__CHANNEL2 0x0004
#define CHNL_ACTIVE__CHANNEL3 0x0008
#define ACTIVE_SRC_ID 0x800
#define ACTIVE_SRC_ID__VALUE 0x00ff
#define PTN_INTR 0x810
#define PTN_INTR__CONFIG_ERROR 0x0001
#define PTN_INTR__ACCESS_ERROR_BANK0 0x0002
#define PTN_INTR__ACCESS_ERROR_BANK1 0x0004
#define PTN_INTR__ACCESS_ERROR_BANK2 0x0008
#define PTN_INTR__ACCESS_ERROR_BANK3 0x0010
#define PTN_INTR__REG_ACCESS_ERROR 0x0020
#define PTN_INTR_EN 0x820
#define PTN_INTR_EN__CONFIG_ERROR 0x0001
#define PTN_INTR_EN__ACCESS_ERROR_BANK0 0x0002
#define PTN_INTR_EN__ACCESS_ERROR_BANK1 0x0004
#define PTN_INTR_EN__ACCESS_ERROR_BANK2 0x0008
#define PTN_INTR_EN__ACCESS_ERROR_BANK3 0x0010
#define PTN_INTR_EN__REG_ACCESS_ERROR 0x0020
#define PERM_SRC_ID(__bank) (0x830 + ((__bank) * 0x40))
#define PERM_SRC_ID__SRCID 0x00ff
#define PERM_SRC_ID__DIRECT_ACCESS_ACTIVE 0x0800
#define PERM_SRC_ID__WRITE_ACTIVE 0x2000
#define PERM_SRC_ID__READ_ACTIVE 0x4000
#define PERM_SRC_ID__PARTITION_VALID 0x8000
#define MIN_BLK_ADDR(__bank) (0x840 + ((__bank) * 0x40))
#define MIN_BLK_ADDR__VALUE 0xffff
#define MAX_BLK_ADDR(__bank) (0x850 + ((__bank) * 0x40))
#define MAX_BLK_ADDR__VALUE 0xffff
#define MIN_MAX_BANK(__bank) (0x860 + ((__bank) * 0x40))
#define MIN_MAX_BANK__MIN_VALUE 0x0003
#define MIN_MAX_BANK__MAX_VALUE 0x000c
/* ffsdefs.h */
#define CLEAR 0 /*use this to clear a field instead of "fail"*/
#define SET 1 /*use this to set a field instead of "pass"*/
#define FAIL 1 /*failed flag*/
#define PASS 0 /*success flag*/
#define ERR -1 /*error flag*/
/* lld.h */
#define GOOD_BLOCK 0
#define DEFECTIVE_BLOCK 1
#define READ_ERROR 2
#define CLK_X 5
#define CLK_MULTI 4
/* KBV - Updated to LNW scratch register address */
#define SCRATCH_REG_ADDR CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR
#define SCRATCH_REG_SIZE 64
#define GLOB_HWCTL_DEFAULT_BLKS 2048
#define SUPPORT_15BITECC 1
#define SUPPORT_8BITECC 1
#define CUSTOM_CONF_PARAMS 0
#define ONFI_BLOOM_TIME 1
#define MODE5_WORKAROUND 0
@ -403,31 +307,6 @@
#define MODE_10 0x08000000
#define MODE_11 0x0C000000
#define DATA_TRANSFER_MODE 0
#define PROTECTION_PER_BLOCK 1
#define LOAD_WAIT_COUNT 2
#define PROGRAM_WAIT_COUNT 3
#define ERASE_WAIT_COUNT 4
#define INT_MONITOR_CYCLE_COUNT 5
#define READ_BUSY_PIN_ENABLED 6
#define MULTIPLANE_OPERATION_SUPPORT 7
#define PRE_FETCH_MODE 8
#define CE_DONT_CARE_SUPPORT 9
#define COPYBACK_SUPPORT 10
#define CACHE_WRITE_SUPPORT 11
#define CACHE_READ_SUPPORT 12
#define NUM_PAGES_IN_BLOCK 13
#define ECC_ENABLE_SELECT 14
#define WRITE_ENABLE_2_READ_ENABLE 15
#define ADDRESS_2_DATA 16
#define READ_ENABLE_2_WRITE_ENABLE 17
#define TWO_ROW_ADDRESS_CYCLES 18
#define MULTIPLANE_ADDRESS_RESTRICT 19
#define ACC_CLOCKS 20
#define READ_WRITE_ENABLE_LOW_COUNT 21
#define READ_WRITE_ENABLE_HIGH_COUNT 22
#define ECC_SECTOR_SIZE 512
struct nand_buf {
@ -449,23 +328,26 @@ struct denali_nand_info {
struct nand_buf buf;
struct device *dev;
int total_used_banks;
uint32_t block; /* stored for future use */
uint16_t page;
void __iomem *flash_reg; /* Mapped io reg base address */
void __iomem *flash_mem; /* Mapped io reg base address */
int page;
void __iomem *flash_reg; /* Register Interface */
void __iomem *flash_mem; /* Host Data/Command Interface */
/* elements used by ISR */
struct completion complete;
spinlock_t irq_lock;
uint32_t irq_status;
int irq_debug_array[32];
int irq;
uint32_t devnum; /* represent how many nands connected */
uint32_t bbtskipbytes;
uint32_t max_banks;
int devnum; /* represent how many nands connected */
int bbtskipbytes;
int max_banks;
unsigned int revision;
unsigned int caps;
};
#define DENALI_CAP_HW_ECC_FIXUP BIT(0)
#define DENALI_CAP_DMA_64BIT BIT(1)
extern int denali_init(struct denali_nand_info *denali);
extern void denali_remove(struct denali_nand_info *denali);

View File

@ -29,64 +29,66 @@ struct denali_dt {
struct clk *clk;
};
static const struct of_device_id denali_nand_dt_ids[] = {
{ .compatible = "denali,denali-nand-dt" },
{ /* sentinel */ }
};
struct denali_dt_data {
unsigned int revision;
unsigned int caps;
};
static const struct denali_dt_data denali_socfpga_data = {
.caps = DENALI_CAP_HW_ECC_FIXUP,
};
static const struct of_device_id denali_nand_dt_ids[] = {
{
.compatible = "altr,socfpga-denali-nand",
.data = &denali_socfpga_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
static u64 denali_dma_mask;
static int denali_dt_probe(struct platform_device *ofdev)
static int denali_dt_probe(struct platform_device *pdev)
{
struct resource *denali_reg, *nand_data;
struct denali_dt *dt;
const struct denali_dt_data *data;
struct denali_nand_info *denali;
int ret;
const struct of_device_id *of_id;
of_id = of_match_device(denali_nand_dt_ids, &ofdev->dev);
if (of_id) {
ofdev->id_entry = of_id->data;
} else {
pr_err("Failed to find the right device id.\n");
return -ENOMEM;
}
dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL);
dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
if (!dt)
return -ENOMEM;
denali = &dt->denali;
data = of_device_get_match_data(&pdev->dev);
if (data) {
denali->revision = data->revision;
denali->caps = data->caps;
}
denali->platform = DT;
denali->dev = &ofdev->dev;
denali->irq = platform_get_irq(ofdev, 0);
denali->dev = &pdev->dev;
denali->irq = platform_get_irq(pdev, 0);
if (denali->irq < 0) {
dev_err(&ofdev->dev, "no irq defined\n");
dev_err(&pdev->dev, "no irq defined\n");
return denali->irq;
}
denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg");
denali->flash_reg = devm_ioremap_resource(&ofdev->dev, denali_reg);
denali_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"denali_reg");
denali->flash_reg = devm_ioremap_resource(&pdev->dev, denali_reg);
if (IS_ERR(denali->flash_reg))
return PTR_ERR(denali->flash_reg);
nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data");
denali->flash_mem = devm_ioremap_resource(&ofdev->dev, nand_data);
nand_data = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"nand_data");
denali->flash_mem = devm_ioremap_resource(&pdev->dev, nand_data);
if (IS_ERR(denali->flash_mem))
return PTR_ERR(denali->flash_mem);
if (!of_property_read_u32(ofdev->dev.of_node,
"dma-mask", (u32 *)&denali_dma_mask)) {
denali->dev->dma_mask = &denali_dma_mask;
} else {
denali->dev->dma_mask = NULL;
}
dt->clk = devm_clk_get(&ofdev->dev, NULL);
dt->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dt->clk)) {
dev_err(&ofdev->dev, "no clk available\n");
dev_err(&pdev->dev, "no clk available\n");
return PTR_ERR(dt->clk);
}
clk_prepare_enable(dt->clk);
@ -95,7 +97,7 @@ static int denali_dt_probe(struct platform_device *ofdev)
if (ret)
goto out_disable_clk;
platform_set_drvdata(ofdev, dt);
platform_set_drvdata(pdev, dt);
return 0;
out_disable_clk:
@ -104,9 +106,9 @@ out_disable_clk:
return ret;
}
static int denali_dt_remove(struct platform_device *ofdev)
static int denali_dt_remove(struct platform_device *pdev)
{
struct denali_dt *dt = platform_get_drvdata(ofdev);
struct denali_dt *dt = platform_get_drvdata(pdev);
denali_remove(&dt->denali);
clk_disable_unprepare(dt->clk);

View File

@ -38,15 +38,6 @@
#include <linux/amba/bus.h>
#include <mtd/mtd-abi.h>
#define FSMC_NAND_BW8 1
#define FSMC_NAND_BW16 2
#define FSMC_MAX_NOR_BANKS 4
#define FSMC_MAX_NAND_BANKS 4
#define FSMC_FLASH_WIDTH8 1
#define FSMC_FLASH_WIDTH16 2
/* fsmc controller registers for NOR flash */
#define CTRL 0x0
/* ctrl register definitions */
@ -133,33 +124,48 @@ enum access_mode {
};
/**
* fsmc_nand_platform_data - platform specific NAND controller config
* @nand_timings: timing setup for the physical NAND interface
* @partitions: partition table for the platform, use a default fallback
* if this is NULL
* @nr_partitions: the number of partitions in the previous entry
* @options: different options for the driver
* @width: bus width
* @bank: default bank
* @select_bank: callback to select a certain bank, this is
* platform-specific. If the controller only supports one bank
* this may be set to NULL
* struct fsmc_nand_data - structure for FSMC NAND device state
*
* @pid: Part ID on the AMBA PrimeCell format
* @mtd: MTD info for a NAND flash.
* @nand: Chip related info for a NAND flash.
* @partitions: Partition info for a NAND Flash.
* @nr_partitions: Total number of partition of a NAND flash.
*
* @bank: Bank number for probed device.
* @clk: Clock structure for FSMC.
*
* @read_dma_chan: DMA channel for read access
* @write_dma_chan: DMA channel for write access to NAND
* @dma_access_complete: Completion structure
*
* @data_pa: NAND Physical port for Data.
* @data_va: NAND port for Data.
* @cmd_va: NAND port for Command.
* @addr_va: NAND port for Address.
* @regs_va: FSMC regs base address.
*/
struct fsmc_nand_platform_data {
struct fsmc_nand_timings *nand_timings;
struct mtd_partition *partitions;
unsigned int nr_partitions;
unsigned int options;
unsigned int width;
struct fsmc_nand_data {
u32 pid;
struct nand_chip nand;
unsigned int bank;
struct device *dev;
enum access_mode mode;
struct clk *clk;
void (*select_bank)(uint32_t bank, uint32_t busw);
/* DMA related objects */
struct dma_chan *read_dma_chan;
struct dma_chan *write_dma_chan;
struct completion dma_access_complete;
/* priv structures for dma accesses */
void *read_dma_priv;
void *write_dma_priv;
struct fsmc_nand_timings *dev_timings;
dma_addr_t data_pa;
void __iomem *data_va;
void __iomem *cmd_va;
void __iomem *addr_va;
void __iomem *regs_va;
};
static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
@ -246,86 +252,11 @@ static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
.free = fsmc_ecc4_ooblayout_free,
};
/**
* struct fsmc_nand_data - structure for FSMC NAND device state
*
* @pid: Part ID on the AMBA PrimeCell format
* @mtd: MTD info for a NAND flash.
* @nand: Chip related info for a NAND flash.
* @partitions: Partition info for a NAND Flash.
* @nr_partitions: Total number of partition of a NAND flash.
*
* @bank: Bank number for probed device.
* @clk: Clock structure for FSMC.
*
* @read_dma_chan: DMA channel for read access
* @write_dma_chan: DMA channel for write access to NAND
* @dma_access_complete: Completion structure
*
* @data_pa: NAND Physical port for Data.
* @data_va: NAND port for Data.
* @cmd_va: NAND port for Command.
* @addr_va: NAND port for Address.
* @regs_va: FSMC regs base address.
*/
struct fsmc_nand_data {
u32 pid;
struct nand_chip nand;
struct mtd_partition *partitions;
unsigned int nr_partitions;
unsigned int bank;
struct device *dev;
enum access_mode mode;
struct clk *clk;
/* DMA related objects */
struct dma_chan *read_dma_chan;
struct dma_chan *write_dma_chan;
struct completion dma_access_complete;
struct fsmc_nand_timings *dev_timings;
dma_addr_t data_pa;
void __iomem *data_va;
void __iomem *cmd_va;
void __iomem *addr_va;
void __iomem *regs_va;
void (*select_chip)(uint32_t bank, uint32_t busw);
};
static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd)
{
return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand);
}
/* Assert CS signal based on chipnr */
static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct fsmc_nand_data *host;
host = mtd_to_fsmc(mtd);
switch (chipnr) {
case -1:
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
break;
case 0:
case 1:
case 2:
case 3:
if (host->select_chip)
host->select_chip(chipnr,
chip->options & NAND_BUSWIDTH_16);
break;
default:
dev_err(host->dev, "unsupported chip-select %d\n", chipnr);
}
}
/*
* fsmc_cmd_ctrl - For facilitaing Hardware access
* This routine allows hardware specific access to control-lines(ALE,CLE)
@ -838,44 +769,46 @@ static bool filter(struct dma_chan *chan, void *slave)
}
static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
struct fsmc_nand_data *host,
struct nand_chip *nand)
{
struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
u32 val;
int ret;
/* Set default NAND width to 8 bits */
pdata->width = 8;
nand->options = 0;
if (!of_property_read_u32(np, "bank-width", &val)) {
if (val == 2) {
pdata->width = 16;
nand->options |= NAND_BUSWIDTH_16;
} else if (val != 1) {
dev_err(&pdev->dev, "invalid bank-width %u\n", val);
return -EINVAL;
}
}
if (of_get_property(np, "nand-skip-bbtscan", NULL))
pdata->options = NAND_SKIP_BBTSCAN;
pdata->nand_timings = devm_kzalloc(&pdev->dev,
sizeof(*pdata->nand_timings), GFP_KERNEL);
if (!pdata->nand_timings)
if (of_get_property(np, "nand-skip-bbtscan", NULL))
nand->options |= NAND_SKIP_BBTSCAN;
host->dev_timings = devm_kzalloc(&pdev->dev,
sizeof(*host->dev_timings), GFP_KERNEL);
if (!host->dev_timings)
return -ENOMEM;
ret = of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
sizeof(*pdata->nand_timings));
ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
sizeof(*host->dev_timings));
if (ret) {
dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n");
pdata->nand_timings = NULL;
host->dev_timings = NULL;
}
/* Set default NAND bank to 0 */
pdata->bank = 0;
host->bank = 0;
if (!of_property_read_u32(np, "bank", &val)) {
if (val > 3) {
dev_err(&pdev->dev, "invalid bank %u\n", val);
return -EINVAL;
}
pdata->bank = val;
host->bank = val;
}
return 0;
}
@ -886,8 +819,6 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
*/
static int __init fsmc_nand_probe(struct platform_device *pdev)
{
struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node __maybe_unused *np = pdev->dev.of_node;
struct fsmc_nand_data *host;
struct mtd_info *mtd;
struct nand_chip *nand;
@ -897,22 +828,17 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
u32 pid;
int i;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdev->dev.platform_data = pdata;
ret = fsmc_nand_probe_config_dt(pdev, np);
if (ret) {
dev_err(&pdev->dev, "no platform data\n");
return -ENODEV;
}
/* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host)
return -ENOMEM;
nand = &host->nand;
ret = fsmc_nand_probe_config_dt(pdev, host, nand);
if (ret)
return ret;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
host->data_va = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->data_va))
@ -935,7 +861,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (IS_ERR(host->regs_va))
return PTR_ERR(host->regs_va);
host->clk = clk_get(&pdev->dev, NULL);
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk)) {
dev_err(&pdev->dev, "failed to fetch block clock\n");
return PTR_ERR(host->clk);
@ -943,7 +869,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
ret = clk_prepare_enable(host->clk);
if (ret)
goto err_clk_prepare_enable;
return ret;
/*
* This device ID is actually a common AMBA ID as used on the
@ -957,22 +883,15 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid),
AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid));
host->bank = pdata->bank;
host->select_chip = pdata->select_bank;
host->partitions = pdata->partitions;
host->nr_partitions = pdata->nr_partitions;
host->dev = &pdev->dev;
host->dev_timings = pdata->nand_timings;
host->mode = pdata->mode;
if (host->mode == USE_DMA_ACCESS)
init_completion(&host->dma_access_complete);
/* Link all private pointers */
mtd = nand_to_mtd(&host->nand);
nand = &host->nand;
nand_set_controller_data(nand, host);
nand_set_flash_node(nand, np);
nand_set_flash_node(nand, pdev->dev.of_node);
mtd->dev.parent = &pdev->dev;
nand->IO_ADDR_R = host->data_va;
@ -987,26 +906,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.hwctl = fsmc_enable_hwecc;
nand->ecc.size = 512;
nand->options = pdata->options;
nand->select_chip = fsmc_select_chip;
nand->badblockbits = 7;
nand_set_flash_node(nand, np);
if (pdata->width == FSMC_NAND_BW16)
nand->options |= NAND_BUSWIDTH_16;
switch (host->mode) {
case USE_DMA_ACCESS:
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
host->read_dma_chan = dma_request_channel(mask, filter,
pdata->read_dma_priv);
host->read_dma_chan = dma_request_channel(mask, filter, NULL);
if (!host->read_dma_chan) {
dev_err(&pdev->dev, "Unable to get read dma channel\n");
goto err_req_read_chnl;
}
host->write_dma_chan = dma_request_channel(mask, filter,
pdata->write_dma_priv);
host->write_dma_chan = dma_request_channel(mask, filter, NULL);
if (!host->write_dma_chan) {
dev_err(&pdev->dev, "Unable to get write dma channel\n");
goto err_req_write_chnl;
@ -1107,18 +1018,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (ret)
goto err_probe;
/*
* The partition information can is accessed by (in the same precedence)
*
* command line through Bootloader,
* platform data,
* default partition information present in driver.
*/
/*
* Check for partition info passed
*/
mtd->name = "nand";
ret = mtd_device_register(mtd, host->partitions, host->nr_partitions);
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
goto err_probe;
@ -1135,8 +1036,6 @@ err_req_write_chnl:
dma_release_channel(host->read_dma_chan);
err_req_read_chnl:
clk_disable_unprepare(host->clk);
err_clk_prepare_enable:
clk_put(host->clk);
return ret;
}
@ -1155,7 +1054,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
dma_release_channel(host->read_dma_chan);
}
clk_disable_unprepare(host->clk);
clk_put(host->clk);
}
return 0;
@ -1185,20 +1083,18 @@ static int fsmc_nand_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
#ifdef CONFIG_OF
static const struct of_device_id fsmc_nand_id_table[] = {
{ .compatible = "st,spear600-fsmc-nand" },
{ .compatible = "stericsson,fsmc-nand" },
{}
};
MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
#endif
static struct platform_driver fsmc_nand_driver = {
.remove = fsmc_nand_remove,
.driver = {
.name = "fsmc-nand",
.of_match_table = of_match_ptr(fsmc_nand_id_table),
.of_match_table = fsmc_nand_id_table,
.pm = &fsmc_nand_pm_ops,
},
};

View File

@ -78,7 +78,9 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
gpio_nand_dosync(gpiomtd);
if (ctrl & NAND_CTRL_CHANGE) {
gpio_set_value(gpiomtd->plat.gpio_nce, !(ctrl & NAND_NCE));
if (gpio_is_valid(gpiomtd->plat.gpio_nce))
gpio_set_value(gpiomtd->plat.gpio_nce,
!(ctrl & NAND_NCE));
gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE));
gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE));
gpio_nand_dosync(gpiomtd);
@ -201,7 +203,8 @@ static int gpio_nand_remove(struct platform_device *pdev)
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
gpio_set_value(gpiomtd->plat.gpio_nce, 1);
if (gpio_is_valid(gpiomtd->plat.gpio_nce))
gpio_set_value(gpiomtd->plat.gpio_nce, 1);
return 0;
}
@ -239,10 +242,13 @@ static int gpio_nand_probe(struct platform_device *pdev)
if (ret)
return ret;
ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce, "NAND NCE");
if (ret)
return ret;
gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
if (gpio_is_valid(gpiomtd->plat.gpio_nce)) {
ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce,
"NAND NCE");
if (ret)
return ret;
gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
}
if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp,

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/mtd/nand.h>
static void amd_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
nand_decode_ext_id(chip);
/*
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
* some Spansion chips have erasesize that conflicts with size
* listed in nand_ids table.
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
*/
if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 &&
chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 &&
mtd->writesize == 512) {
mtd->erasesize = 128 * 1024;
mtd->erasesize <<= ((chip->id.data[3] & 0x03) << 1);
}
}
static int amd_nand_init(struct nand_chip *chip)
{
if (nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops amd_nand_manuf_ops = {
.detect = amd_nand_decode_id,
.init = amd_nand_init,
};

View File

@ -139,6 +139,74 @@ const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
};
EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
/*
* Support the old "large page" layout used for 1-bit Hamming ECC where ECC
* are placed at a fixed offset.
*/
static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
if (section)
return -ERANGE;
switch (mtd->oobsize) {
case 64:
oobregion->offset = 40;
break;
case 128:
oobregion->offset = 80;
break;
default:
return -EINVAL;
}
oobregion->length = ecc->total;
if (oobregion->offset + oobregion->length > mtd->oobsize)
return -ERANGE;
return 0;
}
static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ecc_offset = 0;
if (section < 0 || section > 1)
return -ERANGE;
switch (mtd->oobsize) {
case 64:
ecc_offset = 40;
break;
case 128:
ecc_offset = 80;
break;
default:
return -EINVAL;
}
if (section == 0) {
oobregion->offset = 2;
oobregion->length = ecc_offset - 2;
} else {
oobregion->offset = ecc_offset + ecc->total;
oobregion->length = mtd->oobsize - oobregion->offset;
}
return 0;
}
const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = {
.ecc = nand_ooblayout_ecc_lp_hamming,
.free = nand_ooblayout_free_lp_hamming,
};
static int check_offs_len(struct mtd_info *mtd,
loff_t ofs, uint64_t len)
{
@ -354,40 +422,32 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
*/
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
{
int page, res = 0, i = 0;
int page, page_end, res;
struct nand_chip *chip = mtd_to_nand(mtd);
u16 bad;
u8 bad;
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
ofs += mtd->erasesize - mtd->writesize;
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
do {
if (chip->options & NAND_BUSWIDTH_16) {
chip->cmdfunc(mtd, NAND_CMD_READOOB,
chip->badblockpos & 0xFE, page);
bad = cpu_to_le16(chip->read_word(mtd));
if (chip->badblockpos & 0x1)
bad >>= 8;
else
bad &= 0xFF;
} else {
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
page);
bad = chip->read_byte(mtd);
}
for (; page < page_end; page++) {
res = chip->ecc.read_oob(mtd, chip, page);
if (res)
return res;
bad = chip->oob_poi[chip->badblockpos];
if (likely(chip->badblockbits == 8))
res = bad != 0xFF;
else
res = hweight8(bad) < chip->badblockbits;
ofs += mtd->writesize;
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
i++;
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
if (res)
return res;
}
return res;
return 0;
}
/**
@ -676,6 +736,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_STATUS:
case NAND_CMD_READID:
case NAND_CMD_SET_FEATURES:
return;
case NAND_CMD_RESET:
@ -794,6 +856,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_STATUS:
case NAND_CMD_READID:
case NAND_CMD_SET_FEATURES:
return;
case NAND_CMD_RNDIN:
@ -1958,7 +2022,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if (!aligned)
use_bufpoi = 1;
else if (chip->options & NAND_USE_BOUNCE_BUFFER)
use_bufpoi = !virt_addr_valid(buf);
use_bufpoi = !virt_addr_valid(buf) ||
!IS_ALIGNED((unsigned long)buf,
chip->buf_align);
else
use_bufpoi = 0;
@ -1997,8 +2063,6 @@ read_retry:
break;
}
max_bitflips = max_t(unsigned int, max_bitflips, ret);
/* Transfer not aligned data */
if (use_bufpoi) {
if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
@ -2049,6 +2113,7 @@ read_retry:
}
buf += bytes;
max_bitflips = max_t(unsigned int, max_bitflips, ret);
} else {
memcpy(buf, chip->buffers->databuf + col, bytes);
buf += bytes;
@ -2637,7 +2702,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
}
/**
* nand_write_page - [REPLACEABLE] write one page
* nand_write_page - write one page
* @mtd: MTD device structure
* @chip: NAND chip descriptor
* @offset: address offset within the page
@ -2815,7 +2880,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
if (part_pagewr)
use_bufpoi = 1;
else if (chip->options & NAND_USE_BOUNCE_BUFFER)
use_bufpoi = !virt_addr_valid(buf);
use_bufpoi = !virt_addr_valid(buf) ||
!IS_ALIGNED((unsigned long)buf,
chip->buf_align);
else
use_bufpoi = 0;
@ -2840,9 +2907,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
/* We still need to erase leftover OOB data */
memset(chip->oob_poi, 0xff, mtd->oobsize);
}
ret = chip->write_page(mtd, chip, column, bytes, wbuf,
oob_required, page, cached,
(ops->mode == MTD_OPS_RAW));
ret = nand_write_page(mtd, chip, column, bytes, wbuf,
oob_required, page, cached,
(ops->mode == MTD_OPS_RAW));
if (ret)
break;
@ -3385,8 +3453,10 @@ static void nand_shutdown(struct mtd_info *mtd)
}
/* Set default functions */
static void nand_set_defaults(struct nand_chip *chip, int busw)
static void nand_set_defaults(struct nand_chip *chip)
{
unsigned int busw = chip->options & NAND_BUSWIDTH_16;
/* check for proper chip_delay setup, set 20us if not */
if (!chip->chip_delay)
chip->chip_delay = 20;
@ -3431,6 +3501,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
nand_hw_control_init(chip->controller);
}
if (!chip->buf_align)
chip->buf_align = 1;
}
/* Sanitize ONFI strings so we can safely print them */
@ -3464,9 +3536,10 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
}
/* Parse the Extended Parameter Page. */
static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
struct nand_chip *chip, struct nand_onfi_params *p)
static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
struct nand_onfi_params *p)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct onfi_ext_param_page *ep;
struct onfi_ext_section *s;
struct onfi_ext_ecc_info *ecc;
@ -3534,36 +3607,12 @@ ext_out:
return ret;
}
static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
{
struct nand_chip *chip = mtd_to_nand(mtd);
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.
*/
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
int *busw)
static int nand_flash_detect_onfi(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_onfi_params *p = &chip->onfi_params;
int i, j;
int val;
@ -3633,9 +3682,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
*busw = NAND_BUSWIDTH_16;
else
*busw = 0;
chip->options |= NAND_BUSWIDTH_16;
if (p->ecc_bits != 0xff) {
chip->ecc_strength_ds = p->ecc_bits;
@ -3653,24 +3700,21 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip->cmdfunc = nand_command_lp;
/* The Extended Parameter Page is supported since ONFI 2.1. */
if (nand_flash_detect_ext_param_page(mtd, chip, p))
if (nand_flash_detect_ext_param_page(chip, p))
pr_warn("Failed to detect ONFI extended param page\n");
} else {
pr_warn("Could not retrieve ONFI ECC requirements\n");
}
if (p->jedec_id == NAND_MFR_MICRON)
nand_onfi_detect_micron(chip, p);
return 1;
}
/*
* Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
*/
static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
int *busw)
static int nand_flash_detect_jedec(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_jedec_params *p = &chip->jedec_params;
struct jedec_ecc_info *ecc;
int val;
@ -3729,9 +3773,7 @@ static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
chip->bits_per_cell = p->bits_per_cell;
if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
*busw = NAND_BUSWIDTH_16;
else
*busw = 0;
chip->options |= NAND_BUSWIDTH_16;
/* ECC info */
ecc = &p->ecc_info[0];
@ -3820,165 +3862,46 @@ static int nand_get_bits_per_cell(u8 cellinfo)
* chip. The rest of the parameters must be decoded according to generic or
* manufacturer-specific "extended ID" decoding patterns.
*/
static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
u8 id_data[8], int *busw)
void nand_decode_ext_id(struct nand_chip *chip)
{
int extid, id_len;
struct mtd_info *mtd = nand_to_mtd(chip);
int extid;
u8 *id_data = chip->id.data;
/* The 3rd id byte holds MLC / multichip data */
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
/* The 4th id byte is the important one */
extid = id_data[3];
id_len = nand_id_len(id_data, 8);
/*
* Field definitions are in the following datasheets:
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
* Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
*
* Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
* ID to decide what to do.
*/
if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
!nand_is_slc(chip) && id_data[5] != 0x00) {
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
case 1:
mtd->oobsize = 128;
break;
case 2:
mtd->oobsize = 218;
break;
case 3:
mtd->oobsize = 400;
break;
case 4:
mtd->oobsize = 436;
break;
case 5:
mtd->oobsize = 512;
break;
case 6:
mtd->oobsize = 640;
break;
case 7:
default: /* Other cases are "reserved" (unknown) */
mtd->oobsize = 1024;
break;
}
extid >>= 2;
/* Calc blocksize */
mtd->erasesize = (128 * 1024) <<
(((extid >> 1) & 0x04) | (extid & 0x03));
*busw = 0;
} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
!nand_is_slc(chip)) {
unsigned int tmp;
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
case 0:
mtd->oobsize = 128;
break;
case 1:
mtd->oobsize = 224;
break;
case 2:
mtd->oobsize = 448;
break;
case 3:
mtd->oobsize = 64;
break;
case 4:
mtd->oobsize = 32;
break;
case 5:
mtd->oobsize = 16;
break;
default:
mtd->oobsize = 640;
break;
}
extid >>= 2;
/* Calc blocksize */
tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
if (tmp < 0x03)
mtd->erasesize = (128 * 1024) << tmp;
else if (tmp == 0x03)
mtd->erasesize = 768 * 1024;
else
mtd->erasesize = (64 * 1024) << tmp;
*busw = 0;
} else {
/* Calc pagesize */
mtd->writesize = 1024 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
mtd->oobsize = (8 << (extid & 0x01)) *
(mtd->writesize >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB */
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information */
*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
/*
* Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
* 512B page. For Toshiba SLC, we decode the 5th/6th byte as
* follows:
* - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
* 110b -> 24nm
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
*/
if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
nand_is_slc(chip) &&
(id_data[5] & 0x7) == 0x6 /* 24nm */ &&
!(id_data[4] & 0x80) /* !BENAND */) {
mtd->oobsize = 32 * mtd->writesize >> 9;
}
}
/* Calc pagesize */
mtd->writesize = 1024 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB */
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information */
if (extid & 0x1)
chip->options |= NAND_BUSWIDTH_16;
}
EXPORT_SYMBOL_GPL(nand_decode_ext_id);
/*
* Old devices have chip data hardcoded in the device ID table. nand_decode_id
* decodes a matching ID table entry and assigns the MTD size parameters for
* the chip.
*/
static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_flash_dev *type, u8 id_data[8],
int *busw)
static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
{
int maf_id = id_data[0];
struct mtd_info *mtd = nand_to_mtd(chip);
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
*busw = type->options & NAND_BUSWIDTH_16;
/* All legacy ID NAND are small-page, SLC */
chip->bits_per_cell = 1;
/*
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
* some Spansion chips have erasesize that conflicts with size
* listed in nand_ids table.
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
*/
if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00
&& id_data[6] == 0x00 && id_data[7] == 0x00
&& mtd->writesize == 512) {
mtd->erasesize = 128 * 1024;
mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
}
}
/*
@ -3986,36 +3909,15 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
* heuristic patterns using various detected parameters (e.g., manufacturer,
* page size, cell-type information).
*/
static void nand_decode_bbm_options(struct mtd_info *mtd,
struct nand_chip *chip, u8 id_data[8])
static void nand_decode_bbm_options(struct nand_chip *chip)
{
int maf_id = id_data[0];
struct mtd_info *mtd = nand_to_mtd(chip);
/* Set the bad block position */
if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
else
chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
/*
* Bad block marker is stored in the last page of each block on Samsung
* and Hynix MLC devices; stored in first two pages of each block on
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
* AMD/Spansion, and Macronix. All others scan only the first page.
*/
if (!nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
else if ((nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX ||
maf_id == NAND_MFR_TOSHIBA ||
maf_id == NAND_MFR_AMD ||
maf_id == NAND_MFR_MACRONIX)) ||
(mtd->writesize == 2048 &&
maf_id == NAND_MFR_MICRON))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
}
static inline bool is_full_id_nand(struct nand_flash_dev *type)
@ -4023,9 +3925,12 @@ static inline bool is_full_id_nand(struct nand_flash_dev *type)
return type->id_len;
}
static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_flash_dev *type, u8 *id_data, int *busw)
static bool find_full_id_nand(struct nand_chip *chip,
struct nand_flash_dev *type)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 *id_data = chip->id.data;
if (!strncmp(type->id, id_data, type->id_len)) {
mtd->writesize = type->pagesize;
mtd->erasesize = type->erasesize;
@ -4039,8 +3944,6 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;
*busw = type->options & NAND_BUSWIDTH_16;
if (!mtd->name)
mtd->name = type->name;
@ -4049,16 +3952,64 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
return false;
}
/*
* Manufacturer detection. Only used when the NAND is not ONFI or JEDEC
* compliant and does not have a full-id or legacy-id entry in the nand_ids
* table.
*/
static void nand_manufacturer_detect(struct nand_chip *chip)
{
/*
* Try manufacturer detection if available and use
* nand_decode_ext_id() otherwise.
*/
if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
chip->manufacturer.desc->ops->detect)
chip->manufacturer.desc->ops->detect(chip);
else
nand_decode_ext_id(chip);
}
/*
* Manufacturer initialization. This function is called for all NANDs including
* ONFI and JEDEC compliant ones.
* Manufacturer drivers should put all their specific initialization code in
* their ->init() hook.
*/
static int nand_manufacturer_init(struct nand_chip *chip)
{
if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops ||
!chip->manufacturer.desc->ops->init)
return 0;
return chip->manufacturer.desc->ops->init(chip);
}
/*
* Manufacturer cleanup. This function is called for all NANDs including
* ONFI and JEDEC compliant ones.
* Manufacturer drivers should put all their specific cleanup code in their
* ->cleanup() hook.
*/
static void nand_manufacturer_cleanup(struct nand_chip *chip)
{
/* Release manufacturer private data */
if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
chip->manufacturer.desc->ops->cleanup)
chip->manufacturer.desc->ops->cleanup(chip);
}
/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
int *maf_id, int *dev_id,
struct nand_flash_dev *type)
static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
{
const struct nand_manufacturer *manufacturer;
struct mtd_info *mtd = nand_to_mtd(chip);
int busw;
int i, maf_idx;
u8 id_data[8];
int i, ret;
u8 *id_data = chip->id.data;
u8 maf_id, dev_id;
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
@ -4073,8 +4024,8 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
*maf_id = chip->read_byte(mtd);
*dev_id = chip->read_byte(mtd);
maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
/*
* Try again to make sure, as some systems the bus-hold or other
@ -4089,20 +4040,41 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < 8; i++)
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("second ID read did not match %02x,%02x against %02x,%02x\n",
*maf_id, *dev_id, id_data[0], id_data[1]);
maf_id, dev_id, id_data[0], id_data[1]);
return -ENODEV;
}
chip->id.len = nand_id_len(id_data, 8);
/* Try to identify manufacturer */
manufacturer = nand_get_manufacturer(maf_id);
chip->manufacturer.desc = manufacturer;
if (!type)
type = nand_flash_ids;
/*
* Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
* override it.
* This is required to make sure initial NAND bus width set by the
* NAND controller driver is coherent with the real NAND bus width
* (extracted by auto-detection code).
*/
busw = chip->options & NAND_BUSWIDTH_16;
/*
* The flag is only set (never cleared), reset it to its default value
* before starting auto-detection.
*/
chip->options &= ~NAND_BUSWIDTH_16;
for (; type->name != NULL; type++) {
if (is_full_id_nand(type)) {
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
if (find_full_id_nand(chip, type))
goto ident_done;
} else if (*dev_id == type->dev_id) {
} else if (dev_id == type->dev_id) {
break;
}
}
@ -4110,11 +4082,11 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
chip->onfi_version = 0;
if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
if (nand_flash_detect_onfi(mtd, chip, &busw))
if (nand_flash_detect_onfi(chip))
goto ident_done;
/* Check if the chip is JEDEC compliant */
if (nand_flash_detect_jedec(mtd, chip, &busw))
if (nand_flash_detect_jedec(chip))
goto ident_done;
}
@ -4126,48 +4098,34 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
chip->chipsize = (uint64_t)type->chipsize << 20;
if (!type->pagesize) {
/* Decode parameters from extended ID */
nand_decode_ext_id(mtd, chip, id_data, &busw);
} else {
nand_decode_id(mtd, chip, type, id_data, &busw);
}
if (!type->pagesize)
nand_manufacturer_detect(chip);
else
nand_decode_id(chip, type);
/* Get chip options */
chip->options |= type->options;
/*
* Check if chip is not a Samsung device. Do not clear the
* options for chips which do not have an extended id.
*/
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
ident_done:
/* Try to identify manufacturer */
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
if (nand_manuf_ids[maf_idx].id == *maf_id)
break;
}
if (chip->options & NAND_BUSWIDTH_AUTO) {
WARN_ON(chip->options & NAND_BUSWIDTH_16);
chip->options |= busw;
nand_set_defaults(chip, busw);
WARN_ON(busw & NAND_BUSWIDTH_16);
nand_set_defaults(chip);
} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
/*
* Check, if buswidth is correct. Hardware drivers should set
* chip correct!
*/
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
*maf_id, *dev_id);
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
pr_warn("bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
maf_id, dev_id);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
mtd->name);
pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
return -EINVAL;
}
nand_decode_bbm_options(mtd, chip, id_data);
nand_decode_bbm_options(chip);
/* Calculate the address shift from the page size */
chip->page_shift = ffs(mtd->writesize) - 1;
@ -4190,18 +4148,22 @@ ident_done:
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
ret = nand_manufacturer_init(chip);
if (ret)
return ret;
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
*maf_id, *dev_id);
maf_id, dev_id);
if (chip->onfi_version)
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
chip->onfi_params.model);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
chip->onfi_params.model);
else if (chip->jedec_version)
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
chip->jedec_params.model);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
chip->jedec_params.model);
else
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
type->name);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
type->name);
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
@ -4333,12 +4295,6 @@ static int nand_dt_init(struct nand_chip *chip)
ecc_strength = of_get_nand_ecc_strength(dn);
ecc_step = of_get_nand_ecc_step_size(dn);
if ((ecc_step >= 0 && !(ecc_strength >= 0)) ||
(!(ecc_step >= 0) && ecc_strength >= 0)) {
pr_err("must set both strength and step size in DT\n");
return -EINVAL;
}
if (ecc_mode >= 0)
chip->ecc.mode = ecc_mode;
@ -4391,10 +4347,10 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return -EINVAL;
}
/* Set the default functions */
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
nand_set_defaults(chip);
/* Read the flash type */
ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table);
ret = nand_detect(chip, table);
if (ret) {
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
pr_warn("No NAND device found\n");
@ -4419,6 +4375,9 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
if (ret)
return ret;
nand_maf_id = chip->id.data[0];
nand_dev_id = chip->id.data[1];
chip->select_chip(mtd, -1);
/* Check for a chip array */
@ -4610,7 +4569,7 @@ int nand_scan_tail(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct nand_buffers *nbuf;
struct nand_buffers *nbuf = NULL;
int ret;
/* New bad blocks should be marked in OOB, flash-based BBT, or both */
@ -4624,13 +4583,28 @@ int nand_scan_tail(struct mtd_info *mtd)
}
if (!(chip->options & NAND_OWN_BUFFERS)) {
nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
+ mtd->oobsize * 3, GFP_KERNEL);
nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL);
if (!nbuf)
return -ENOMEM;
nbuf->ecccalc = (uint8_t *)(nbuf + 1);
nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
nbuf->databuf = nbuf->ecccode + mtd->oobsize;
nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL);
if (!nbuf->ecccalc) {
ret = -ENOMEM;
goto err_free;
}
nbuf->ecccode = kmalloc(mtd->oobsize, GFP_KERNEL);
if (!nbuf->ecccode) {
ret = -ENOMEM;
goto err_free;
}
nbuf->databuf = kmalloc(mtd->writesize + mtd->oobsize,
GFP_KERNEL);
if (!nbuf->databuf) {
ret = -ENOMEM;
goto err_free;
}
chip->buffers = nbuf;
} else {
@ -4653,7 +4627,7 @@ int nand_scan_tail(struct mtd_info *mtd)
break;
case 64:
case 128:
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops);
break;
default:
WARN(1, "No oob scheme defined for oobsize %d\n",
@ -4663,9 +4637,6 @@ int nand_scan_tail(struct mtd_info *mtd)
}
}
if (!chip->write_page)
chip->write_page = nand_write_page;
/*
* Check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
@ -4873,8 +4844,12 @@ int nand_scan_tail(struct mtd_info *mtd)
/* Build bad block table */
return chip->scan_bbt(mtd);
err_free:
if (!(chip->options & NAND_OWN_BUFFERS))
kfree(chip->buffers);
if (nbuf) {
kfree(nbuf->databuf);
kfree(nbuf->ecccode);
kfree(nbuf->ecccalc);
kfree(nbuf);
}
return ret;
}
EXPORT_SYMBOL(nand_scan_tail);
@ -4925,13 +4900,20 @@ void nand_cleanup(struct nand_chip *chip)
/* Free bad block table memory */
kfree(chip->bbt);
if (!(chip->options & NAND_OWN_BUFFERS))
if (!(chip->options & NAND_OWN_BUFFERS) && chip->buffers) {
kfree(chip->buffers->databuf);
kfree(chip->buffers->ecccode);
kfree(chip->buffers->ecccalc);
kfree(chip->buffers);
}
/* Free bad block descriptor memory */
if (chip->badblock_pattern && chip->badblock_pattern->options
& NAND_BBT_DYNAMICSTRUCT)
kfree(chip->badblock_pattern);
/* Free manufacturer priv data. */
nand_manufacturer_cleanup(chip);
}
EXPORT_SYMBOL_GPL(nand_cleanup);

View File

@ -0,0 +1,631 @@
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/mtd/nand.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#define NAND_HYNIX_CMD_SET_PARAMS 0x36
#define NAND_HYNIX_CMD_APPLY_PARAMS 0x16
#define NAND_HYNIX_1XNM_RR_REPEAT 8
/**
* struct hynix_read_retry - read-retry data
* @nregs: number of register to set when applying a new read-retry mode
* @regs: register offsets (NAND chip dependent)
* @values: array of values to set in registers. The array size is equal to
* (nregs * nmodes)
*/
struct hynix_read_retry {
int nregs;
const u8 *regs;
u8 values[0];
};
/**
* struct hynix_nand - private Hynix NAND struct
* @nand_technology: manufacturing process expressed in picometer
* @read_retry: read-retry information
*/
struct hynix_nand {
const struct hynix_read_retry *read_retry;
};
/**
* struct hynix_read_retry_otp - structure describing how the read-retry OTP
* area
* @nregs: number of hynix private registers to set before reading the reading
* the OTP area
* @regs: registers that should be configured
* @values: values that should be set in regs
* @page: the address to pass to the READ_PAGE command. Depends on the NAND
* chip
* @size: size of the read-retry OTP section
*/
struct hynix_read_retry_otp {
int nregs;
const u8 *regs;
const u8 *values;
int page;
int size;
};
static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 jedecid[6] = { };
int i = 0;
chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
for (i = 0; i < 5; i++)
jedecid[i] = chip->read_byte(mtd);
return !strcmp("JEDEC", jedecid);
}
static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
const u8 *values;
int status;
int i;
values = hynix->read_retry->values +
(retry_mode * hynix->read_retry->nregs);
/* Enter 'Set Hynix Parameters' mode */
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1);
/*
* Configure the NAND in the requested read-retry mode.
* This is done by setting pre-defined values in internal NAND
* registers.
*
* The set of registers is NAND specific, and the values are either
* predefined or extracted from an OTP area on the NAND (values are
* probably tweaked at production in this case).
*/
for (i = 0; i < hynix->read_retry->nregs; i++) {
int column = hynix->read_retry->regs[i];
column |= column << 8;
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
chip->write_byte(mtd, values[i]);
}
/* Apply the new settings. */
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
/**
* hynix_get_majority - get the value that is occurring the most in a given
* set of values
* @in: the array of values to test
* @repeat: the size of the in array
* @out: pointer used to store the output value
*
* This function implements the 'majority check' logic that is supposed to
* overcome the unreliability of MLC NANDs when reading the OTP area storing
* the read-retry parameters.
*
* It's based on a pretty simple assumption: if we repeat the same value
* several times and then take the one that is occurring the most, we should
* find the correct value.
* Let's hope this dummy algorithm prevents us from losing the read-retry
* parameters.
*/
static int hynix_get_majority(const u8 *in, int repeat, u8 *out)
{
int i, j, half = repeat / 2;
/*
* We only test the first half of the in array because we must ensure
* that the value is at least occurring repeat / 2 times.
*
* This loop is suboptimal since we may count the occurrences of the
* same value several time, but we are doing that on small sets, which
* makes it acceptable.
*/
for (i = 0; i < half; i++) {
int cnt = 0;
u8 val = in[i];
/* Count all values that are matching the one at index i. */
for (j = i + 1; j < repeat; j++) {
if (in[j] == val)
cnt++;
}
/* We found a value occurring more than repeat / 2. */
if (cnt > half) {
*out = val;
return 0;
}
}
return -EIO;
}
static int hynix_read_rr_otp(struct nand_chip *chip,
const struct hynix_read_retry_otp *info,
void *buf)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int i;
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1);
for (i = 0; i < info->nregs; i++) {
int column = info->regs[i];
column |= column << 8;
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
chip->write_byte(mtd, info->values[i]);
}
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
/* Sequence to enter OTP mode? */
chip->cmdfunc(mtd, 0x17, -1, -1);
chip->cmdfunc(mtd, 0x04, -1, -1);
chip->cmdfunc(mtd, 0x19, -1, -1);
/* Now read the page */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, info->page);
chip->read_buf(mtd, buf, info->size);
/* Put everything back to normal */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, 0x38, -1);
chip->write_byte(mtd, 0x0);
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, -1);
return 0;
}
#define NAND_HYNIX_1XNM_RR_COUNT_OFFS 0
#define NAND_HYNIX_1XNM_RR_REG_COUNT_OFFS 8
#define NAND_HYNIX_1XNM_RR_SET_OFFS(x, setsize, inv) \
(16 + ((((x) * 2) + ((inv) ? 1 : 0)) * (setsize)))
static int hynix_mlc_1xnm_rr_value(const u8 *buf, int nmodes, int nregs,
int mode, int reg, bool inv, u8 *val)
{
u8 tmp[NAND_HYNIX_1XNM_RR_REPEAT];
int val_offs = (mode * nregs) + reg;
int set_size = nmodes * nregs;
int i, ret;
for (i = 0; i < NAND_HYNIX_1XNM_RR_REPEAT; i++) {
int set_offs = NAND_HYNIX_1XNM_RR_SET_OFFS(i, set_size, inv);
tmp[i] = buf[val_offs + set_offs];
}
ret = hynix_get_majority(tmp, NAND_HYNIX_1XNM_RR_REPEAT, val);
if (ret)
return ret;
if (inv)
*val = ~*val;
return 0;
}
static u8 hynix_1xnm_mlc_read_retry_regs[] = {
0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
};
static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip,
const struct hynix_read_retry_otp *info)
{
struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
struct hynix_read_retry *rr = NULL;
int ret, i, j;
u8 nregs, nmodes;
u8 *buf;
buf = kmalloc(info->size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = hynix_read_rr_otp(chip, info, buf);
if (ret)
goto out;
ret = hynix_get_majority(buf, NAND_HYNIX_1XNM_RR_REPEAT,
&nmodes);
if (ret)
goto out;
ret = hynix_get_majority(buf + NAND_HYNIX_1XNM_RR_REPEAT,
NAND_HYNIX_1XNM_RR_REPEAT,
&nregs);
if (ret)
goto out;
rr = kzalloc(sizeof(*rr) + (nregs * nmodes), GFP_KERNEL);
if (!rr) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < nmodes; i++) {
for (j = 0; j < nregs; j++) {
u8 *val = rr->values + (i * nregs);
ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
false, val);
if (!ret)
continue;
ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
true, val);
if (ret)
goto out;
}
}
rr->nregs = nregs;
rr->regs = hynix_1xnm_mlc_read_retry_regs;
hynix->read_retry = rr;
chip->setup_read_retry = hynix_nand_setup_read_retry;
chip->read_retries = nmodes;
out:
kfree(buf);
if (ret)
kfree(rr);
return ret;
}
static const u8 hynix_mlc_1xnm_rr_otp_regs[] = { 0x38 };
static const u8 hynix_mlc_1xnm_rr_otp_values[] = { 0x52 };
static const struct hynix_read_retry_otp hynix_mlc_1xnm_rr_otps[] = {
{
.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
.regs = hynix_mlc_1xnm_rr_otp_regs,
.values = hynix_mlc_1xnm_rr_otp_values,
.page = 0x21f,
.size = 784
},
{
.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
.regs = hynix_mlc_1xnm_rr_otp_regs,
.values = hynix_mlc_1xnm_rr_otp_values,
.page = 0x200,
.size = 528,
},
};
static int hynix_nand_rr_init(struct nand_chip *chip)
{
int i, ret = 0;
bool valid_jedecid;
valid_jedecid = hynix_nand_has_valid_jedecid(chip);
/*
* We only support read-retry for 1xnm NANDs, and those NANDs all
* expose a valid JEDEC ID.
*/
if (valid_jedecid) {
u8 nand_tech = chip->id.data[5] >> 4;
/* 1xnm technology */
if (nand_tech == 4) {
for (i = 0; i < ARRAY_SIZE(hynix_mlc_1xnm_rr_otps);
i++) {
/*
* FIXME: Hynix recommend to copy the
* read-retry OTP area into a normal page.
*/
ret = hynix_mlc_1xnm_rr_init(chip,
hynix_mlc_1xnm_rr_otps);
if (!ret)
break;
}
}
}
if (ret)
pr_warn("failed to initialize read-retry infrastructure");
return 0;
}
static void hynix_nand_extract_oobsize(struct nand_chip *chip,
bool valid_jedecid)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 oobsize;
oobsize = ((chip->id.data[3] >> 2) & 0x3) |
((chip->id.data[3] >> 4) & 0x4);
if (valid_jedecid) {
switch (oobsize) {
case 0:
mtd->oobsize = 2048;
break;
case 1:
mtd->oobsize = 1664;
break;
case 2:
mtd->oobsize = 1024;
break;
case 3:
mtd->oobsize = 640;
break;
default:
/*
* We should never reach this case, but if that
* happens, this probably means Hynix decided to use
* a different extended ID format, and we should find
* a way to support it.
*/
WARN(1, "Invalid OOB size");
break;
}
} else {
switch (oobsize) {
case 0:
mtd->oobsize = 128;
break;
case 1:
mtd->oobsize = 224;
break;
case 2:
mtd->oobsize = 448;
break;
case 3:
mtd->oobsize = 64;
break;
case 4:
mtd->oobsize = 32;
break;
case 5:
mtd->oobsize = 16;
break;
case 6:
mtd->oobsize = 640;
break;
default:
/*
* We should never reach this case, but if that
* happens, this probably means Hynix decided to use
* a different extended ID format, and we should find
* a way to support it.
*/
WARN(1, "Invalid OOB size");
break;
}
}
}
static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
bool valid_jedecid)
{
u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
if (valid_jedecid) {
/* Reference: H27UCG8T2E datasheet */
chip->ecc_step_ds = 1024;
switch (ecc_level) {
case 0:
chip->ecc_step_ds = 0;
chip->ecc_strength_ds = 0;
break;
case 1:
chip->ecc_strength_ds = 4;
break;
case 2:
chip->ecc_strength_ds = 24;
break;
case 3:
chip->ecc_strength_ds = 32;
break;
case 4:
chip->ecc_strength_ds = 40;
break;
case 5:
chip->ecc_strength_ds = 50;
break;
case 6:
chip->ecc_strength_ds = 60;
break;
default:
/*
* We should never reach this case, but if that
* happens, this probably means Hynix decided to use
* a different extended ID format, and we should find
* a way to support it.
*/
WARN(1, "Invalid ECC requirements");
}
} else {
/*
* The ECC requirements field meaning depends on the
* NAND technology.
*/
u8 nand_tech = chip->id.data[5] & 0x3;
if (nand_tech < 3) {
/* > 26nm, reference: H27UBG8T2A datasheet */
if (ecc_level < 5) {
chip->ecc_step_ds = 512;
chip->ecc_strength_ds = 1 << ecc_level;
} else if (ecc_level < 7) {
if (ecc_level == 5)
chip->ecc_step_ds = 2048;
else
chip->ecc_step_ds = 1024;
chip->ecc_strength_ds = 24;
} else {
/*
* We should never reach this case, but if that
* happens, this probably means Hynix decided
* to use a different extended ID format, and
* we should find a way to support it.
*/
WARN(1, "Invalid ECC requirements");
}
} else {
/* <= 26nm, reference: H27UBG8T2B datasheet */
if (!ecc_level) {
chip->ecc_step_ds = 0;
chip->ecc_strength_ds = 0;
} else if (ecc_level < 5) {
chip->ecc_step_ds = 512;
chip->ecc_strength_ds = 1 << (ecc_level - 1);
} else {
chip->ecc_step_ds = 1024;
chip->ecc_strength_ds = 24 +
(8 * (ecc_level - 5));
}
}
}
}
static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
bool valid_jedecid)
{
u8 nand_tech;
/* We need scrambling on all TLC NANDs*/
if (chip->bits_per_cell > 2)
chip->options |= NAND_NEED_SCRAMBLING;
/* And on MLC NANDs with sub-3xnm process */
if (valid_jedecid) {
nand_tech = chip->id.data[5] >> 4;
/* < 3xnm */
if (nand_tech > 0)
chip->options |= NAND_NEED_SCRAMBLING;
} else {
nand_tech = chip->id.data[5] & 0x3;
/* < 32nm */
if (nand_tech > 2)
chip->options |= NAND_NEED_SCRAMBLING;
}
}
static void hynix_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
bool valid_jedecid;
u8 tmp;
/*
* Exclude all SLC NANDs from this advanced detection scheme.
* According to the ranges defined in several datasheets, it might
* appear that even SLC NANDs could fall in this extended ID scheme.
* If that the case rework the test to let SLC NANDs go through the
* detection process.
*/
if (chip->id.len < 6 || nand_is_slc(chip)) {
nand_decode_ext_id(chip);
return;
}
/* Extract pagesize */
mtd->writesize = 2048 << (chip->id.data[3] & 0x03);
tmp = (chip->id.data[3] >> 4) & 0x3;
/*
* When bit7 is set that means we start counting at 1MiB, otherwise
* we start counting at 128KiB and shift this value the content of
* ID[3][4:5].
* The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in
* this case the erasesize is set to 768KiB.
*/
if (chip->id.data[3] & 0x80)
mtd->erasesize = SZ_1M << tmp;
else if (tmp == 3)
mtd->erasesize = SZ_512K + SZ_256K;
else
mtd->erasesize = SZ_128K << tmp;
/*
* Modern Toggle DDR NANDs have a valid JEDECID even though they are
* not exposing a valid JEDEC parameter table.
* These NANDs use a different NAND ID scheme.
*/
valid_jedecid = hynix_nand_has_valid_jedecid(chip);
hynix_nand_extract_oobsize(chip, valid_jedecid);
hynix_nand_extract_ecc_requirements(chip, valid_jedecid);
hynix_nand_extract_scrambling_requirements(chip, valid_jedecid);
}
static void hynix_nand_cleanup(struct nand_chip *chip)
{
struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
if (!hynix)
return;
kfree(hynix->read_retry);
kfree(hynix);
nand_set_manufacturer_data(chip, NULL);
}
static int hynix_nand_init(struct nand_chip *chip)
{
struct hynix_nand *hynix;
int ret;
if (!nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
else
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
if (!hynix)
return -ENOMEM;
nand_set_manufacturer_data(chip, hynix);
ret = hynix_nand_rr_init(chip);
if (ret)
hynix_nand_cleanup(chip);
return ret;
}
const struct nand_manufacturer_ops hynix_nand_manuf_ops = {
.detect = hynix_nand_decode_id,
.init = hynix_nand_init,
.cleanup = hynix_nand_cleanup,
};

View File

@ -10,7 +10,7 @@
#include <linux/mtd/nand.h>
#include <linux/sizes.h>
#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
#define LP_OPTIONS 0
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
#define SP_OPTIONS NAND_NEED_READRDY
@ -169,29 +169,40 @@ struct nand_flash_dev nand_flash_ids[] = {
};
/* Manufacturer IDs */
struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_TOSHIBA, "Toshiba"},
static const struct nand_manufacturer nand_manufacturers[] = {
{NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
{NAND_MFR_ESMT, "ESMT"},
{NAND_MFR_SAMSUNG, "Samsung"},
{NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
{NAND_MFR_FUJITSU, "Fujitsu"},
{NAND_MFR_NATIONAL, "National"},
{NAND_MFR_RENESAS, "Renesas"},
{NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix"},
{NAND_MFR_MICRON, "Micron"},
{NAND_MFR_AMD, "AMD/Spansion"},
{NAND_MFR_MACRONIX, "Macronix"},
{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
{NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
{NAND_MFR_MACRONIX, "Macronix", &macronix_nand_manuf_ops},
{NAND_MFR_EON, "Eon"},
{NAND_MFR_SANDISK, "SanDisk"},
{NAND_MFR_INTEL, "Intel"},
{NAND_MFR_ATO, "ATO"},
{NAND_MFR_WINBOND, "Winbond"},
{0x0, "Unknown"}
};
EXPORT_SYMBOL(nand_manuf_ids);
EXPORT_SYMBOL(nand_flash_ids);
/**
* nand_get_manufacturer - Get manufacturer information from the manufacturer
* ID
* @id: manufacturer ID
*
* Returns a pointer a nand_manufacturer object if the manufacturer is defined
* in the NAND manufacturers database, NULL otherwise.
*/
const struct nand_manufacturer *nand_get_manufacturer(u8 id)
{
int i;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
MODULE_DESCRIPTION("Nand device & manufacturer IDs");
for (i = 0; i < ARRAY_SIZE(nand_manufacturers); i++)
if (nand_manufacturers[i].id == id)
return &nand_manufacturers[i];
return NULL;
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/mtd/nand.h>
static int macronix_nand_init(struct nand_chip *chip)
{
if (nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops macronix_nand_manuf_ops = {
.init = macronix_nand_init,
};

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/mtd/nand.h>
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;
static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
{
struct nand_chip *chip = mtd_to_nand(mtd);
u8 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 int micron_nand_onfi_init(struct nand_chip *chip)
{
struct nand_onfi_params *p = &chip->onfi_params;
struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
if (!chip->onfi_version)
return 0;
if (le16_to_cpu(p->vendor_revision) < 1)
return 0;
chip->read_retries = micron->read_retry_options;
chip->setup_read_retry = micron_nand_setup_read_retry;
return 0;
}
static int micron_nand_init(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = micron_nand_onfi_init(chip);
if (ret)
return ret;
if (mtd->writesize == 2048)
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops micron_nand_manuf_ops = {
.init = micron_nand_init,
};

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/mtd/nand.h>
static void samsung_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
/* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
if (chip->id.len == 6 && !nand_is_slc(chip) &&
chip->id.data[5] != 0x00) {
u8 extid = chip->id.data[3];
/* Get pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
/* Get oobsize */
switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
case 1:
mtd->oobsize = 128;
break;
case 2:
mtd->oobsize = 218;
break;
case 3:
mtd->oobsize = 400;
break;
case 4:
mtd->oobsize = 436;
break;
case 5:
mtd->oobsize = 512;
break;
case 6:
mtd->oobsize = 640;
break;
default:
/*
* We should never reach this case, but if that
* happens, this probably means Samsung decided to use
* a different extended ID format, and we should find
* a way to support it.
*/
WARN(1, "Invalid OOB size value");
break;
}
/* Get blocksize */
extid >>= 2;
mtd->erasesize = (128 * 1024) <<
(((extid >> 1) & 0x04) | (extid & 0x03));
/* Extract ECC requirements from 5th id byte*/
extid = (chip->id.data[4] >> 4) & 0x07;
if (extid < 5) {
chip->ecc_step_ds = 512;
chip->ecc_strength_ds = 1 << extid;
} else {
chip->ecc_step_ds = 1024;
switch (extid) {
case 5:
chip->ecc_strength_ds = 24;
break;
case 6:
chip->ecc_strength_ds = 40;
break;
case 7:
chip->ecc_strength_ds = 60;
break;
}
}
} else {
nand_decode_ext_id(chip);
}
}
static int samsung_nand_init(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (mtd->writesize > 512)
chip->options |= NAND_SAMSUNG_LP_OPTIONS;
if (!nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
else
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
.detect = samsung_nand_decode_id,
.init = samsung_nand_init,
};

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/mtd/nand.h>
static void toshiba_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
nand_decode_ext_id(chip);
/*
* Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
* 512B page. For Toshiba SLC, we decode the 5th/6th byte as
* follows:
* - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
* 110b -> 24nm
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
*/
if (chip->id.len >= 6 && nand_is_slc(chip) &&
(chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
!(chip->id.data[4] & 0x80) /* !BENAND */)
mtd->oobsize = 32 * mtd->writesize >> 9;
}
static int toshiba_nand_init(struct nand_chip *chip)
{
if (nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops toshiba_nand_manuf_ops = {
.detect = toshiba_nand_decode_id,
.init = toshiba_nand_init,
};

View File

@ -902,7 +902,7 @@ static int parse_weakpages(void)
zero_ok = (*w == '0' ? 1 : 0);
page_no = simple_strtoul(w, &w, 0);
if (!zero_ok && !page_no) {
NS_ERR("invalid weakpagess.\n");
NS_ERR("invalid weakpages.\n");
return -EINVAL;
}
max_writes = 3;

View File

@ -1856,6 +1856,15 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.priv = NULL;
nand_set_flash_node(nand_chip, dev->of_node);
if (!mtd->name) {
mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"omap2-nand.%d", info->gpmc_cs);
if (!mtd->name) {
dev_err(&pdev->dev, "Failed to set MTD name\n");
return -ENOMEM;
}
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nand_chip->IO_ADDR_R))

View File

@ -23,6 +23,11 @@
#include <asm/sizes.h>
#include <linux/platform_data/mtd-orion_nand.h>
struct orion_nand_info {
struct nand_chip chip;
struct clk *clk;
};
static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *nc = mtd_to_nand(mtd);
@ -75,20 +80,21 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static int __init orion_nand_probe(struct platform_device *pdev)
{
struct orion_nand_info *info;
struct mtd_info *mtd;
struct nand_chip *nc;
struct orion_nand_data *board;
struct resource *res;
struct clk *clk;
void __iomem *io_base;
int ret = 0;
u32 val = 0;
nc = devm_kzalloc(&pdev->dev,
sizeof(struct nand_chip),
info = devm_kzalloc(&pdev->dev,
sizeof(struct orion_nand_info),
GFP_KERNEL);
if (!nc)
if (!info)
return -ENOMEM;
nc = &info->chip;
mtd = nand_to_mtd(nc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -145,16 +151,23 @@ static int __init orion_nand_probe(struct platform_device *pdev)
if (board->dev_ready)
nc->dev_ready = board->dev_ready;
platform_set_drvdata(pdev, mtd);
platform_set_drvdata(pdev, info);
/* Not all platforms can gate the clock, so it is not
an error if the clock does not exists. */
clk = clk_get(&pdev->dev, NULL);
if (!IS_ERR(clk)) {
clk_prepare_enable(clk);
clk_put(clk);
info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
ret = PTR_ERR(info->clk);
if (ret == -ENOENT) {
info->clk = NULL;
} else {
dev_err(&pdev->dev, "failed to get clock!\n");
return ret;
}
}
clk_prepare_enable(info->clk);
ret = nand_scan(mtd, 1);
if (ret)
goto no_dev;
@ -169,26 +182,19 @@ static int __init orion_nand_probe(struct platform_device *pdev)
return 0;
no_dev:
if (!IS_ERR(clk)) {
clk_disable_unprepare(clk);
clk_put(clk);
}
clk_disable_unprepare(info->clk);
return ret;
}
static int orion_nand_remove(struct platform_device *pdev)
{
struct mtd_info *mtd = platform_get_drvdata(pdev);
struct clk *clk;
struct orion_nand_info *info = platform_get_drvdata(pdev);
struct nand_chip *chip = &info->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
nand_release(mtd);
clk = clk_get(&pdev->dev, NULL);
if (!IS_ERR(clk)) {
clk_disable_unprepare(clk);
clk_put(clk);
}
clk_disable_unprepare(info->clk);
return 0;
}

View File

@ -91,7 +91,7 @@ static int oxnas_nand_probe(struct platform_device *pdev)
int err = 0;
/* Allocate memory for the device structure (and zero it) */
oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
oxnas = devm_kzalloc(&pdev->dev, sizeof(*oxnas),
GFP_KERNEL);
if (!oxnas)
return -ENOMEM;

View File

@ -2212,17 +2212,17 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
goto out_ahb_clk_unprepare;
nfc->reset = devm_reset_control_get_optional(dev, "ahb");
if (!IS_ERR(nfc->reset)) {
ret = reset_control_deassert(nfc->reset);
if (ret) {
dev_err(dev, "reset err %d\n", ret);
goto out_mod_clk_unprepare;
}
} else if (PTR_ERR(nfc->reset) != -ENOENT) {
if (IS_ERR(nfc->reset)) {
ret = PTR_ERR(nfc->reset);
goto out_mod_clk_unprepare;
}
ret = reset_control_deassert(nfc->reset);
if (ret) {
dev_err(dev, "reset err %d\n", ret);
goto out_mod_clk_unprepare;
}
ret = sunxi_nfc_rst(nfc);
if (ret)
goto out_ahb_reset_reassert;
@ -2262,8 +2262,7 @@ out_release_dmac:
if (nfc->dmac)
dma_release_channel(nfc->dmac);
out_ahb_reset_reassert:
if (!IS_ERR(nfc->reset))
reset_control_assert(nfc->reset);
reset_control_assert(nfc->reset);
out_mod_clk_unprepare:
clk_disable_unprepare(nfc->mod_clk);
out_ahb_clk_unprepare:
@ -2278,8 +2277,7 @@ static int sunxi_nfc_remove(struct platform_device *pdev)
sunxi_nand_chips_cleanup(nfc);
if (!IS_ERR(nfc->reset))
reset_control_assert(nfc->reset);
reset_control_assert(nfc->reset);
if (nfc->dmac)
dma_release_channel(nfc->dmac);

View File

@ -223,12 +223,13 @@ static void tango_dma_callback(void *arg)
complete(arg);
}
static int do_dma(struct tango_nfc *nfc, int dir, int cmd, const void *buf,
int len, int page)
static int do_dma(struct tango_nfc *nfc, enum dma_data_direction dir, int cmd,
const void *buf, int len, int page)
{
void __iomem *addr = nfc->reg_base + NFC_STATUS;
struct dma_chan *chan = nfc->chan;
struct dma_async_tx_descriptor *desc;
enum dma_transfer_direction tdir;
struct scatterlist sg;
struct completion tx_done;
int err = -EIO;
@ -238,7 +239,8 @@ static int do_dma(struct tango_nfc *nfc, int dir, int cmd, const void *buf,
if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
return -EIO;
desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
tdir = dir == DMA_TO_DEVICE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
desc = dmaengine_prep_slave_sg(chan, &sg, 1, tdir, DMA_PREP_INTERRUPT);
if (!desc)
goto dma_unmap;

View File

@ -166,8 +166,8 @@ static int parse_ofoldpart_partitions(struct mtd_info *master,
if (!part)
return 0; /* No partitions found */
pr_warning("Device tree uses obsolete partition map binding: %s\n",
dp->full_name);
pr_warn("Device tree uses obsolete partition map binding: %s\n",
dp->full_name);
nr_parts = plen / sizeof(part[0]);

View File

@ -106,4 +106,11 @@ config SPI_INTEL_SPI_PLATFORM
To compile this driver as a module, choose M here: the module
will be called intel-spi-platform.
config SPI_STM32_QUADSPI
tristate "STM32 Quad SPI controller"
depends on ARCH_STM32
help
This enables support for the STM32 Quad SPI controller.
We only connect the NOR to this controller.
endif # MTD_SPI_NOR

View File

@ -8,3 +8,4 @@ obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o
obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o
obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o
obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o

View File

@ -448,8 +448,11 @@ static int hisi_spi_nor_probe(struct platform_device *pdev)
if (!host->buffer)
return -ENOMEM;
ret = clk_prepare_enable(host->clk);
if (ret)
return ret;
mutex_init(&host->lock);
clk_prepare_enable(host->clk);
hisi_spi_nor_init(host);
ret = hisi_spi_nor_register_all(host);
if (ret)

View File

@ -704,7 +704,7 @@ static void intel_spi_fill_partition(struct intel_spi *ispi,
* whole partition read-only to be on the safe side.
*/
if (intel_spi_is_protected(ispi, base, limit))
ispi->writeable = 0;
ispi->writeable = false;
end = (limit << 12) + 4096;
if (end > part->size)
@ -728,7 +728,7 @@ struct intel_spi *intel_spi_probe(struct device *dev,
ispi->base = devm_ioremap_resource(dev, mem);
if (IS_ERR(ispi->base))
return ispi->base;
return ERR_CAST(ispi->base);
ispi->dev = dev;
ispi->info = info;

View File

@ -104,6 +104,8 @@
#define MTK_NOR_MAX_RX_TX_SHIFT 6
/* can shift up to 56 bits (7 bytes) transfer by MTK_NOR_PRG_CMD */
#define MTK_NOR_MAX_SHIFT 7
/* nor controller 4-byte address mode enable bit */
#define MTK_NOR_4B_ADDR_EN BIT(4)
/* Helpers for accessing the program data / shift data registers */
#define MTK_NOR_PRG_REG(n) (MTK_NOR_PRGDATA0_REG + 4 * (n))
@ -230,10 +232,35 @@ static int mt8173_nor_write_buffer_disable(struct mt8173_nor *mt8173_nor)
10000);
}
static void mt8173_nor_set_addr_width(struct mt8173_nor *mt8173_nor)
{
u8 val;
struct spi_nor *nor = &mt8173_nor->nor;
val = readb(mt8173_nor->base + MTK_NOR_DUAL_REG);
switch (nor->addr_width) {
case 3:
val &= ~MTK_NOR_4B_ADDR_EN;
break;
case 4:
val |= MTK_NOR_4B_ADDR_EN;
break;
default:
dev_warn(mt8173_nor->dev, "Unexpected address width %u.\n",
nor->addr_width);
break;
}
writeb(val, mt8173_nor->base + MTK_NOR_DUAL_REG);
}
static void mt8173_nor_set_addr(struct mt8173_nor *mt8173_nor, u32 addr)
{
int i;
mt8173_nor_set_addr_width(mt8173_nor);
for (i = 0; i < 3; i++) {
writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR0_REG + i * 4);
addr >>= 8;

View File

@ -85,6 +85,7 @@ struct flash_info {
* Use dedicated 4byte address op codes
* to support memory size above 128Mib.
*/
#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */
};
#define JEDEC_MFR(info) ((info)->id[0])
@ -960,6 +961,8 @@ static const struct flash_info spi_nor_ids[] = {
/* ESMT */
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) },
{ "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) },
{ "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_LOCK) },
/* Everspin */
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
@ -1013,11 +1016,14 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) },
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) },
{ "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) },
{ "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16, SECT_4K) },
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) },
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
@ -1031,10 +1037,11 @@ static const struct flash_info spi_nor_ids[] = {
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
/* PMC */
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
@ -1128,6 +1135,9 @@ static const struct flash_info spi_nor_ids[] = {
{ "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) },
{ "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) },
{ "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) },
{ "w25q20ew", INFO(0xef6012, 0, 64 * 1024, 4, SECT_4K) },
{ "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) },
{
"w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64,
@ -1629,6 +1639,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
nor->flags |= SNOR_F_USE_FSR;
if (info->flags & SPI_NOR_HAS_TB)
nor->flags |= SNOR_F_HAS_SR_TB;
if (info->flags & NO_CHIP_ERASE)
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
/* prefer "small sector" erase if possible */

View File

@ -0,0 +1,693 @@
/*
* stm32_quadspi.c
*
* Copyright (C) 2017, Ludovic Barre
*
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/spi-nor.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#define QUADSPI_CR 0x00
#define CR_EN BIT(0)
#define CR_ABORT BIT(1)
#define CR_DMAEN BIT(2)
#define CR_TCEN BIT(3)
#define CR_SSHIFT BIT(4)
#define CR_DFM BIT(6)
#define CR_FSEL BIT(7)
#define CR_FTHRES_SHIFT 8
#define CR_FTHRES_MASK GENMASK(12, 8)
#define CR_FTHRES(n) (((n) << CR_FTHRES_SHIFT) & CR_FTHRES_MASK)
#define CR_TEIE BIT(16)
#define CR_TCIE BIT(17)
#define CR_FTIE BIT(18)
#define CR_SMIE BIT(19)
#define CR_TOIE BIT(20)
#define CR_PRESC_SHIFT 24
#define CR_PRESC_MASK GENMASK(31, 24)
#define CR_PRESC(n) (((n) << CR_PRESC_SHIFT) & CR_PRESC_MASK)
#define QUADSPI_DCR 0x04
#define DCR_CSHT_SHIFT 8
#define DCR_CSHT_MASK GENMASK(10, 8)
#define DCR_CSHT(n) (((n) << DCR_CSHT_SHIFT) & DCR_CSHT_MASK)
#define DCR_FSIZE_SHIFT 16
#define DCR_FSIZE_MASK GENMASK(20, 16)
#define DCR_FSIZE(n) (((n) << DCR_FSIZE_SHIFT) & DCR_FSIZE_MASK)
#define QUADSPI_SR 0x08
#define SR_TEF BIT(0)
#define SR_TCF BIT(1)
#define SR_FTF BIT(2)
#define SR_SMF BIT(3)
#define SR_TOF BIT(4)
#define SR_BUSY BIT(5)
#define SR_FLEVEL_SHIFT 8
#define SR_FLEVEL_MASK GENMASK(13, 8)
#define QUADSPI_FCR 0x0c
#define FCR_CTCF BIT(1)
#define QUADSPI_DLR 0x10
#define QUADSPI_CCR 0x14
#define CCR_INST_SHIFT 0
#define CCR_INST_MASK GENMASK(7, 0)
#define CCR_INST(n) (((n) << CCR_INST_SHIFT) & CCR_INST_MASK)
#define CCR_IMODE_NONE (0U << 8)
#define CCR_IMODE_1 (1U << 8)
#define CCR_IMODE_2 (2U << 8)
#define CCR_IMODE_4 (3U << 8)
#define CCR_ADMODE_NONE (0U << 10)
#define CCR_ADMODE_1 (1U << 10)
#define CCR_ADMODE_2 (2U << 10)
#define CCR_ADMODE_4 (3U << 10)
#define CCR_ADSIZE_SHIFT 12
#define CCR_ADSIZE_MASK GENMASK(13, 12)
#define CCR_ADSIZE(n) (((n) << CCR_ADSIZE_SHIFT) & CCR_ADSIZE_MASK)
#define CCR_ABMODE_NONE (0U << 14)
#define CCR_ABMODE_1 (1U << 14)
#define CCR_ABMODE_2 (2U << 14)
#define CCR_ABMODE_4 (3U << 14)
#define CCR_ABSIZE_8 (0U << 16)
#define CCR_ABSIZE_16 (1U << 16)
#define CCR_ABSIZE_24 (2U << 16)
#define CCR_ABSIZE_32 (3U << 16)
#define CCR_DCYC_SHIFT 18
#define CCR_DCYC_MASK GENMASK(22, 18)
#define CCR_DCYC(n) (((n) << CCR_DCYC_SHIFT) & CCR_DCYC_MASK)
#define CCR_DMODE_NONE (0U << 24)
#define CCR_DMODE_1 (1U << 24)
#define CCR_DMODE_2 (2U << 24)
#define CCR_DMODE_4 (3U << 24)
#define CCR_FMODE_INDW (0U << 26)
#define CCR_FMODE_INDR (1U << 26)
#define CCR_FMODE_APM (2U << 26)
#define CCR_FMODE_MM (3U << 26)
#define QUADSPI_AR 0x18
#define QUADSPI_ABR 0x1c
#define QUADSPI_DR 0x20
#define QUADSPI_PSMKR 0x24
#define QUADSPI_PSMAR 0x28
#define QUADSPI_PIR 0x2c
#define QUADSPI_LPTR 0x30
#define LPTR_DFT_TIMEOUT 0x10
#define FSIZE_VAL(size) (__fls(size) - 1)
#define STM32_MAX_MMAP_SZ SZ_256M
#define STM32_MAX_NORCHIP 2
#define STM32_QSPI_FIFO_TIMEOUT_US 30000
#define STM32_QSPI_BUSY_TIMEOUT_US 100000
struct stm32_qspi_flash {
struct spi_nor nor;
struct stm32_qspi *qspi;
u32 cs;
u32 fsize;
u32 presc;
u32 read_mode;
bool registered;
};
struct stm32_qspi {
struct device *dev;
void __iomem *io_base;
void __iomem *mm_base;
resource_size_t mm_size;
u32 nor_num;
struct clk *clk;
u32 clk_rate;
struct stm32_qspi_flash flash[STM32_MAX_NORCHIP];
struct completion cmd_completion;
/*
* to protect device configuration, could be different between
* 2 flash access (bk1, bk2)
*/
struct mutex lock;
};
struct stm32_qspi_cmd {
u8 addr_width;
u8 dummy;
bool tx_data;
u8 opcode;
u32 framemode;
u32 qspimode;
u32 addr;
size_t len;
void *buf;
};
static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi)
{
u32 cr;
int err = 0;
if (readl_relaxed(qspi->io_base + QUADSPI_SR) & SR_TCF)
return 0;
reinit_completion(&qspi->cmd_completion);
cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
writel_relaxed(cr | CR_TCIE, qspi->io_base + QUADSPI_CR);
if (!wait_for_completion_interruptible_timeout(&qspi->cmd_completion,
msecs_to_jiffies(1000)))
err = -ETIMEDOUT;
writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
return err;
}
static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
{
u32 sr;
return readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, sr,
!(sr & SR_BUSY), 10,
STM32_QSPI_BUSY_TIMEOUT_US);
}
static void stm32_qspi_set_framemode(struct spi_nor *nor,
struct stm32_qspi_cmd *cmd, bool read)
{
u32 dmode = CCR_DMODE_1;
cmd->framemode = CCR_IMODE_1;
if (read) {
switch (nor->flash_read) {
case SPI_NOR_NORMAL:
case SPI_NOR_FAST:
dmode = CCR_DMODE_1;
break;
case SPI_NOR_DUAL:
dmode = CCR_DMODE_2;
break;
case SPI_NOR_QUAD:
dmode = CCR_DMODE_4;
break;
}
}
cmd->framemode |= cmd->tx_data ? dmode : 0;
cmd->framemode |= cmd->addr_width ? CCR_ADMODE_1 : 0;
}
static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
{
*val = readb_relaxed(addr);
}
static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
{
writeb_relaxed(*val, addr);
}
static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
const struct stm32_qspi_cmd *cmd)
{
void (*tx_fifo)(u8 *, void __iomem *);
u32 len = cmd->len, sr;
u8 *buf = cmd->buf;
int ret;
if (cmd->qspimode == CCR_FMODE_INDW)
tx_fifo = stm32_qspi_write_fifo;
else
tx_fifo = stm32_qspi_read_fifo;
while (len--) {
ret = readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR,
sr, (sr & SR_FTF), 10,
STM32_QSPI_FIFO_TIMEOUT_US);
if (ret) {
dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr);
break;
}
tx_fifo(buf++, qspi->io_base + QUADSPI_DR);
}
return ret;
}
static int stm32_qspi_tx_mm(struct stm32_qspi *qspi,
const struct stm32_qspi_cmd *cmd)
{
memcpy_fromio(cmd->buf, qspi->mm_base + cmd->addr, cmd->len);
return 0;
}
static int stm32_qspi_tx(struct stm32_qspi *qspi,
const struct stm32_qspi_cmd *cmd)
{
if (!cmd->tx_data)
return 0;
if (cmd->qspimode == CCR_FMODE_MM)
return stm32_qspi_tx_mm(qspi, cmd);
return stm32_qspi_tx_poll(qspi, cmd);
}
static int stm32_qspi_send(struct stm32_qspi_flash *flash,
const struct stm32_qspi_cmd *cmd)
{
struct stm32_qspi *qspi = flash->qspi;
u32 ccr, dcr, cr;
int err;
err = stm32_qspi_wait_nobusy(qspi);
if (err)
goto abort;
dcr = readl_relaxed(qspi->io_base + QUADSPI_DCR) & ~DCR_FSIZE_MASK;
dcr |= DCR_FSIZE(flash->fsize);
writel_relaxed(dcr, qspi->io_base + QUADSPI_DCR);
cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
cr &= ~CR_PRESC_MASK & ~CR_FSEL;
cr |= CR_PRESC(flash->presc);
cr |= flash->cs ? CR_FSEL : 0;
writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
if (cmd->tx_data)
writel_relaxed(cmd->len - 1, qspi->io_base + QUADSPI_DLR);
ccr = cmd->framemode | cmd->qspimode;
if (cmd->dummy)
ccr |= CCR_DCYC(cmd->dummy);
if (cmd->addr_width)
ccr |= CCR_ADSIZE(cmd->addr_width - 1);
ccr |= CCR_INST(cmd->opcode);
writel_relaxed(ccr, qspi->io_base + QUADSPI_CCR);
if (cmd->addr_width && cmd->qspimode != CCR_FMODE_MM)
writel_relaxed(cmd->addr, qspi->io_base + QUADSPI_AR);
err = stm32_qspi_tx(qspi, cmd);
if (err)
goto abort;
if (cmd->qspimode != CCR_FMODE_MM) {
err = stm32_qspi_wait_cmd(qspi);
if (err)
goto abort;
writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR);
}
return err;
abort:
cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT;
writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
dev_err(qspi->dev, "%s abort err:%d\n", __func__, err);
return err;
}
static int stm32_qspi_read_reg(struct spi_nor *nor,
u8 opcode, u8 *buf, int len)
{
struct stm32_qspi_flash *flash = nor->priv;
struct device *dev = flash->qspi->dev;
struct stm32_qspi_cmd cmd;
dev_dbg(dev, "read_reg: cmd:%#.2x buf:%p len:%#x\n", opcode, buf, len);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = opcode;
cmd.tx_data = true;
cmd.len = len;
cmd.buf = buf;
cmd.qspimode = CCR_FMODE_INDR;
stm32_qspi_set_framemode(nor, &cmd, false);
return stm32_qspi_send(flash, &cmd);
}
static int stm32_qspi_write_reg(struct spi_nor *nor, u8 opcode,
u8 *buf, int len)
{
struct stm32_qspi_flash *flash = nor->priv;
struct device *dev = flash->qspi->dev;
struct stm32_qspi_cmd cmd;
dev_dbg(dev, "write_reg: cmd:%#.2x buf:%p len:%#x\n", opcode, buf, len);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = opcode;
cmd.tx_data = !!(buf && len > 0);
cmd.len = len;
cmd.buf = buf;
cmd.qspimode = CCR_FMODE_INDW;
stm32_qspi_set_framemode(nor, &cmd, false);
return stm32_qspi_send(flash, &cmd);
}
static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
u_char *buf)
{
struct stm32_qspi_flash *flash = nor->priv;
struct stm32_qspi *qspi = flash->qspi;
struct stm32_qspi_cmd cmd;
int err;
dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#x\n",
nor->read_opcode, buf, (u32)from, len);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = nor->read_opcode;
cmd.addr_width = nor->addr_width;
cmd.addr = (u32)from;
cmd.tx_data = true;
cmd.dummy = nor->read_dummy;
cmd.len = len;
cmd.buf = buf;
cmd.qspimode = flash->read_mode;
stm32_qspi_set_framemode(nor, &cmd, true);
err = stm32_qspi_send(flash, &cmd);
return err ? err : len;
}
static ssize_t stm32_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
const u_char *buf)
{
struct stm32_qspi_flash *flash = nor->priv;
struct device *dev = flash->qspi->dev;
struct stm32_qspi_cmd cmd;
int err;
dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#x\n",
nor->program_opcode, buf, (u32)to, len);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = nor->program_opcode;
cmd.addr_width = nor->addr_width;
cmd.addr = (u32)to;
cmd.tx_data = true;
cmd.len = len;
cmd.buf = (void *)buf;
cmd.qspimode = CCR_FMODE_INDW;
stm32_qspi_set_framemode(nor, &cmd, false);
err = stm32_qspi_send(flash, &cmd);
return err ? err : len;
}
static int stm32_qspi_erase(struct spi_nor *nor, loff_t offs)
{
struct stm32_qspi_flash *flash = nor->priv;
struct device *dev = flash->qspi->dev;
struct stm32_qspi_cmd cmd;
dev_dbg(dev, "erase(%#.2x):offs:%#x\n", nor->erase_opcode, (u32)offs);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = nor->erase_opcode;
cmd.addr_width = nor->addr_width;
cmd.addr = (u32)offs;
cmd.qspimode = CCR_FMODE_INDW;
stm32_qspi_set_framemode(nor, &cmd, false);
return stm32_qspi_send(flash, &cmd);
}
static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
{
struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
u32 cr, sr, fcr = 0;
cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
sr = readl_relaxed(qspi->io_base + QUADSPI_SR);
if ((cr & CR_TCIE) && (sr & SR_TCF)) {
/* tx complete */
fcr |= FCR_CTCF;
complete(&qspi->cmd_completion);
} else {
dev_info_ratelimited(qspi->dev, "spurious interrupt\n");
}
writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR);
return IRQ_HANDLED;
}
static int stm32_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
{
struct stm32_qspi_flash *flash = nor->priv;
struct stm32_qspi *qspi = flash->qspi;
mutex_lock(&qspi->lock);
return 0;
}
static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
{
struct stm32_qspi_flash *flash = nor->priv;
struct stm32_qspi *qspi = flash->qspi;
mutex_unlock(&qspi->lock);
}
static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
struct device_node *np)
{
u32 width, flash_read, presc, cs_num, max_rate = 0;
struct stm32_qspi_flash *flash;
struct mtd_info *mtd;
int ret;
of_property_read_u32(np, "reg", &cs_num);
if (cs_num >= STM32_MAX_NORCHIP)
return -EINVAL;
of_property_read_u32(np, "spi-max-frequency", &max_rate);
if (!max_rate)
return -EINVAL;
presc = DIV_ROUND_UP(qspi->clk_rate, max_rate) - 1;
if (of_property_read_u32(np, "spi-rx-bus-width", &width))
width = 1;
if (width == 4)
flash_read = SPI_NOR_QUAD;
else if (width == 2)
flash_read = SPI_NOR_DUAL;
else if (width == 1)
flash_read = SPI_NOR_NORMAL;
else
return -EINVAL;
flash = &qspi->flash[cs_num];
flash->qspi = qspi;
flash->cs = cs_num;
flash->presc = presc;
flash->nor.dev = qspi->dev;
spi_nor_set_flash_node(&flash->nor, np);
flash->nor.priv = flash;
mtd = &flash->nor.mtd;
flash->nor.read = stm32_qspi_read;
flash->nor.write = stm32_qspi_write;
flash->nor.erase = stm32_qspi_erase;
flash->nor.read_reg = stm32_qspi_read_reg;
flash->nor.write_reg = stm32_qspi_write_reg;
flash->nor.prepare = stm32_qspi_prep;
flash->nor.unprepare = stm32_qspi_unprep;
writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR);
writel_relaxed(CR_PRESC(presc) | CR_FTHRES(3) | CR_TCEN | CR_SSHIFT
| CR_EN, qspi->io_base + QUADSPI_CR);
/*
* in stm32 qspi controller, QUADSPI_DCR register has a fsize field
* which define the size of nor flash.
* if fsize is NULL, the controller can't sent spi-nor command.
* set a temporary value just to discover the nor flash with
* "spi_nor_scan". After, the right value (mtd->size) can be set.
*/
flash->fsize = FSIZE_VAL(SZ_1K);
ret = spi_nor_scan(&flash->nor, NULL, flash_read);
if (ret) {
dev_err(qspi->dev, "device scan failed\n");
return ret;
}
flash->fsize = FSIZE_VAL(mtd->size);
flash->read_mode = CCR_FMODE_MM;
if (mtd->size > qspi->mm_size)
flash->read_mode = CCR_FMODE_INDR;
writel_relaxed(DCR_CSHT(1), qspi->io_base + QUADSPI_DCR);
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(qspi->dev, "mtd device parse failed\n");
return ret;
}
flash->registered = true;
dev_dbg(qspi->dev, "read mm:%s cs:%d bus:%d\n",
flash->read_mode == CCR_FMODE_MM ? "yes" : "no", cs_num, width);
return 0;
}
static void stm32_qspi_mtd_free(struct stm32_qspi *qspi)
{
int i;
for (i = 0; i < STM32_MAX_NORCHIP; i++)
if (qspi->flash[i].registered)
mtd_device_unregister(&qspi->flash[i].nor.mtd);
}
static int stm32_qspi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *flash_np;
struct reset_control *rstc;
struct stm32_qspi *qspi;
struct resource *res;
int ret, irq;
qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
if (!qspi)
return -ENOMEM;
qspi->nor_num = of_get_child_count(dev->of_node);
if (!qspi->nor_num || qspi->nor_num > STM32_MAX_NORCHIP)
return -ENODEV;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
qspi->io_base = devm_ioremap_resource(dev, res);
if (IS_ERR(qspi->io_base))
return PTR_ERR(qspi->io_base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
qspi->mm_base = devm_ioremap_resource(dev, res);
if (IS_ERR(qspi->mm_base))
return PTR_ERR(qspi->mm_base);
qspi->mm_size = resource_size(res);
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
dev_name(dev), qspi);
if (ret) {
dev_err(dev, "failed to request irq\n");
return ret;
}
init_completion(&qspi->cmd_completion);
qspi->clk = devm_clk_get(dev, NULL);
if (IS_ERR(qspi->clk))
return PTR_ERR(qspi->clk);
qspi->clk_rate = clk_get_rate(qspi->clk);
if (!qspi->clk_rate)
return -EINVAL;
ret = clk_prepare_enable(qspi->clk);
if (ret) {
dev_err(dev, "can not enable the clock\n");
return ret;
}
rstc = devm_reset_control_get(dev, NULL);
if (!IS_ERR(rstc)) {
reset_control_assert(rstc);
udelay(2);
reset_control_deassert(rstc);
}
qspi->dev = dev;
platform_set_drvdata(pdev, qspi);
mutex_init(&qspi->lock);
for_each_available_child_of_node(dev->of_node, flash_np) {
ret = stm32_qspi_flash_setup(qspi, flash_np);
if (ret) {
dev_err(dev, "unable to setup flash chip\n");
goto err_flash;
}
}
return 0;
err_flash:
mutex_destroy(&qspi->lock);
stm32_qspi_mtd_free(qspi);
clk_disable_unprepare(qspi->clk);
return ret;
}
static int stm32_qspi_remove(struct platform_device *pdev)
{
struct stm32_qspi *qspi = platform_get_drvdata(pdev);
/* disable qspi */
writel_relaxed(0, qspi->io_base + QUADSPI_CR);
stm32_qspi_mtd_free(qspi);
mutex_destroy(&qspi->lock);
clk_disable_unprepare(qspi->clk);
return 0;
}
static const struct of_device_id stm32_qspi_match[] = {
{.compatible = "st,stm32f469-qspi"},
{}
};
MODULE_DEVICE_TABLE(of, stm32_qspi_match);
static struct platform_driver stm32_qspi_driver = {
.probe = stm32_qspi_probe,
.remove = stm32_qspi_remove,
.driver = {
.name = "stm32-quadspi",
.of_match_table = stm32_qspi_match,
},
};
module_platform_driver(stm32_qspi_driver);
MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver");
MODULE_LICENSE("GPL v2");

View File

@ -1366,7 +1366,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
jffs2_add_ino_cache(c, f->inocache);
}
if (!f->inocache) {
JFFS2_ERROR("requestied to read an nonexistent ino %u\n", ino);
JFFS2_ERROR("requested to read a nonexistent ino %u\n", ino);
return -ENOENT;
}

View File

@ -388,7 +388,7 @@ static inline void mtd_set_of_node(struct mtd_info *mtd,
static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
{
return mtd->dev.of_node;
return dev_of_node(&mtd->dev);
}
static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)

View File

@ -366,26 +366,6 @@ struct onfi_ext_param_page {
*/
} __packed;
struct nand_onfi_vendor_micron {
u8 two_plane_read;
u8 read_cache;
u8 read_unique_id;
u8 dq_imped;
u8 dq_imped_num_settings;
u8 dq_imped_feat_addr;
u8 rb_pulldown_strength;
u8 rb_pulldown_strength_feat_addr;
u8 rb_pulldown_strength_num_settings;
u8 otp_mode;
u8 otp_page_start;
u8 otp_data_prot_addr;
u8 otp_num_pages;
u8 otp_feat_addr;
u8 read_retry_options;
u8 reserved[72];
u8 param_revision;
} __packed;
struct jedec_ecc_info {
u8 ecc_bits;
u8 codeword_size;
@ -464,6 +444,17 @@ struct nand_jedec_params {
__le16 crc;
} __packed;
/**
* struct nand_id - NAND id structure
* @data: buffer containing the id bytes. Currently 8 bytes large, but can
* be extended if required.
* @len: ID length.
*/
struct nand_id {
u8 data[8];
int len;
};
/**
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
* @lock: protection lock
@ -525,7 +516,7 @@ static inline void nand_hw_control_init(struct nand_hw_control *nfc)
* out-of-band data).
* @read_page: function to read a page according to the ECC generator
* requirements; returns maximum number of bitflips corrected in
* any single ECC step, 0 if bitflips uncorrectable, -EIO hw error
* any single ECC step, -EIO hw error
* @read_subpage: function to read parts of the page covered by ECC;
* returns same as read_page()
* @write_subpage: function to write parts of the page covered by ECC.
@ -720,6 +711,20 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
return &conf->timings.sdr;
}
/**
* struct nand_manufacturer_ops - NAND Manufacturer operations
* @detect: detect the NAND memory organization and capabilities
* @init: initialize all vendor specific fields (like the ->read_retry()
* implementation) if any.
* @cleanup: the ->init() function may have allocated resources, ->cleanup()
* is here to let vendor specific code release those resources.
*/
struct nand_manufacturer_ops {
void (*detect)(struct nand_chip *chip);
int (*init)(struct nand_chip *chip);
void (*cleanup)(struct nand_chip *chip);
};
/**
* struct nand_chip - NAND Private Flash Chip Data
* @mtd: MTD device registered to the MTD framework
@ -750,6 +755,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
* setting the read-retry mode. Mostly needed for MLC NAND.
* @ecc: [BOARDSPECIFIC] ECC control structure
* @buffers: buffer structure for read/write
* @buf_align: minimum buffer alignment required by a platform
* @hwcontrol: platform-specific hardware control structure
* @erase: [REPLACEABLE] erase function
* @scan_bbt: [REPLACEABLE] function to scan bad block table
@ -793,6 +799,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
* @pagebuf_bitflips: [INTERN] holds the bitflip count for the page which is
* currently in data_buf.
* @subpagesize: [INTERN] holds the subpagesize
* @id: [INTERN] holds NAND ID
* @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded),
* non 0 if ONFI supported.
* @jedec_version: [INTERN] holds the chip JEDEC version (BCD encoded),
@ -822,7 +829,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
* @errstat: [OPTIONAL] hardware specific function to perform
* additional error status checks (determine if errors are
* correctable).
* @write_page: [REPLACEABLE] High-level page write function
* @manufacturer: [INTERN] Contains manufacturer information
*/
struct nand_chip {
@ -847,9 +854,6 @@ struct nand_chip {
int (*scan_bbt)(struct mtd_info *mtd);
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
int status, int page);
int (*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 (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para);
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
@ -881,6 +885,7 @@ struct nand_chip {
int badblockpos;
int badblockbits;
struct nand_id id;
int onfi_version;
int jedec_version;
union {
@ -901,6 +906,7 @@ struct nand_chip {
struct nand_ecc_ctrl ecc;
struct nand_buffers *buffers;
unsigned long buf_align;
struct nand_hw_control hwcontrol;
uint8_t *bbt;
@ -910,6 +916,11 @@ struct nand_chip {
struct nand_bbt_descr *badblock_pattern;
void *priv;
struct {
const struct nand_manufacturer *desc;
void *priv;
} manufacturer;
};
extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
@ -946,6 +957,17 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv)
chip->priv = priv;
}
static inline void nand_set_manufacturer_data(struct nand_chip *chip,
void *priv)
{
chip->manufacturer.priv = priv;
}
static inline void *nand_get_manufacturer_data(struct nand_chip *chip)
{
return chip->manufacturer.priv;
}
/*
* NAND Flash Manufacturer ID Codes
*/
@ -1049,17 +1071,33 @@ struct nand_flash_dev {
};
/**
* struct nand_manufacturers - NAND Flash Manufacturer ID Structure
* struct nand_manufacturer - NAND Flash Manufacturer structure
* @name: Manufacturer name
* @id: manufacturer ID code of device.
* @ops: manufacturer operations
*/
struct nand_manufacturers {
struct nand_manufacturer {
int id;
char *name;
const struct nand_manufacturer_ops *ops;
};
const struct nand_manufacturer *nand_get_manufacturer(u8 id);
static inline const char *
nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
{
return manufacturer ? manufacturer->name : "Unknown";
}
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];
extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
extern const struct nand_manufacturer_ops hynix_nand_manuf_ops;
extern const struct nand_manufacturer_ops micron_nand_manuf_ops;
extern const struct nand_manufacturer_ops amd_nand_manuf_ops;
extern const struct nand_manufacturer_ops macronix_nand_manuf_ops;
int nand_default_bbt(struct mtd_info *mtd);
int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
@ -1226,4 +1264,6 @@ int nand_reset(struct nand_chip *chip, int chipnr);
/* Free resources held by the NAND device */
void nand_cleanup(struct nand_chip *chip);
/* Default extended ID decoding function */
void nand_decode_ext_id(struct nand_chip *chip);
#endif /* __LINUX_MTD_NAND_H */