JFFS2 changes:

- Support 64-bit timestamps
 
 MTD changes:
   Core changes:
   - Support sub-partitions
   - Clarify mtd_oob_ops documentation
   - Make Kconfig formatting consistent
   - Fix potential overflows in mtdchar_{write,read}()
   - Fallback to ->_{read,write}() when ->_{read,write}_oob() is missing
     and no OOB data were requested
   - Remove VLA usage in the bch lib
 
   Driver changes:
   - Use mtd_device_register() instead of mtd_device_parse_register()
     where applicable
   - Use proper printk format to print physical addresses in the
     solutionengine driver
   - Add missing mtd_set_of_node() call in the powernv driver
   - Remove unneeded variables in a few drivers
   - Plug the TRX part parser to the DT partition parsers logic
   - Check ioremap_cache() return code in the gpio-addr-flash driver
   - Stop using VMLINUX_SYMBOL_STR() in gen_probe.c
 
 SPI NOR changes:
   Core changes:
   - Apply reset hacks only when reset is explicitly marked as broken in
     the DT
 
    Driver changes:
    - Minor cleanup/fixes in the m25p80 driver
    - Release flash_np in the nxp-spifi driver
    - Add suspend/resume hooks to the atmel-quadspi driver
    - Include gpio/consumer.h instead of gpio.h in the atmel-quadspi
      driver
    - Use %pK instead of %p in the stm32-quadspi driver
    - Improve timeout handling in the cadence-quadspi driver
    - Use mtd_device_register() instead of mtd_device_parse_register()
      in the intel-spi driver
 
 NAND changes:
   Core changes:
   - Add the SPI-NAND framework.
   - Create a helper to find the best ECC configuration.
   - Create NAND controller operations.
   - Allocate dynamically ONFI parameters structure.
   - Add defines for ONFI version bits.
   - Add manufacturer fixup for ONFI parameter page.
   - Add an option to specify NAND chip as a boot device.
   - Add Reed-Solomon error correction algorithm.
   - Better name for the controller structure.
   - Remove unused caller_is_module() definition.
   - Make subop helpers return unsigned values.
   - Expose _notsupp() helpers for raw page accessors.
   - Add default values for dynamic timings.
   - Kill the chip->scan_bbt() hook.
   - Rename nand_default_bbt() into nand_create_bbt().
   - Start to clean the nand_chip structure.
   - Remove stale prototype from rawnand.h.
 
   Raw NAND controllers drivers changes:
   - Qcom: structuring cleanup.
   - Denali: use core helper to find the best ECC configuration.
   - Possible build of almost all drivers by adding a dependency on
     COMPILE_TEST for almost all of them in Kconfig, implies various
     fixes, Kconfig cleanup, GPIO headers inclusion cleanup, and even
     changes in sparc64 and ia64 architectures.
   - Clean the ->probe() functions error path of a lot of drivers.
   - Migrate all drivers to use nand_scan() instead of
     nand_scan_ident()/nand_scan_tail() pair.
   - Use mtd_device_register() where applicable to simplify the code.
   - Marvell:
     * Handle on-die ECC.
     * Better clocks handling.
     * Remove bogus comment.
     * Add suspend and resume support.
   - Tegra: add NAND controller driver.
   - Atmel:
     * Add module param to avoid using dma.
     * Drop Wenyou Yang from MAINTAINERS.
   - Denali: optimize timings handling.
   - FSMC: Stop using chip->read_buf().
   - FSL:
     * Switch to SPDX license tag identifiers.
     * Fix qualifiers in MXC init functions.
 
   Raw NAND chip drivers changes:
   - Micron:
     * Add fixup for ONFI revision.
     * Update ecc_stats.corrected.
     * Make ECC activation stateful.
     * Avoid enabling/disabling ECC when it can't be disabled.
     * Get the actual number of bitflips.
     * Allow forced on-die ECC.
     * Support 8/512 on-die ECC.
     * Fix on-die ECC detection logic.
   - Hynix:
     * Fix decoding the OOB size on H27UCG8T2BTR.
     * Use ->exec_op() in hynix_nand_reg_write_op().
 -----BEGIN PGP SIGNATURE-----
 
 iQI5BAABCAAjBQJbcSYdHBxib3Jpcy5icmV6aWxsb25AYm9vdGxpbi5jb20ACgkQ
 Ze02AX4ItwA85Q//ViUNiWoluaj7q3Kpv44NZZClPjVfirDtIHEfyzob7HbkrqjT
 ivjNUu5cjKU2aqptR24UzIV2lwmaSGicIzvyANN5bNedHy8tb4BWXo1iTEflXc1P
 lYihrRz7AeHQqdrOYAiHxq0fcqgIm2NjCDxfdtkP1HJsMQH+LgvoosOkd8RyLF8E
 jV5IyreTfg10AiVS44yvnqdsYo7GDVZRgnx1dBRbdJ+WwZS05m6LSeNu0ivgfLMM
 NmISrn7pzlMYnuDkzckXwVka7STFhV9befoSCmAHedqNEHtzaGDaNMLEilaC4WzV
 1yvsdRGI3hDkdO4s44nP/Vs2XlVmCevuTpOOQ1dEK94Bbek+us7NEPjxOIAf22jE
 5MVZR6vpNN7JXJ+nvEZjjL8X9zysqZgk2r6os35Wi2zJK7iHIrFpjlMYwTJfVPzv
 JKabOQZuOUqRACbL0isTTdG0+Tzr1BxaQqFiFUteQ9QpG4nSifoHUmI+9XUCJmil
 iGTOy6rEkaMd6qu3xapPtZbxGbUbvcLiJvNrZ02ZfsELDAELowz66O0PX6rSwTV9
 NIWeVNXK9Bsp0oxbb8P8oJIB5K4F6vqncPBls34J7E/xrLO9nLk1VvFQrGqzuwwP
 HmEdgcRwKeXrvJITZz2u0u6lrKpgdDA3FTqfGCNec51PCgb1FwxcpKF/Xz0=
 =yIkF
 -----END PGP SIGNATURE-----

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

Pull mtd updates from Boris Brezillon:
 "JFFS2 changes:
   - Support 64-bit timestamps

  MTD core changes:
   - Support sub-partitions
   - Clarify mtd_oob_ops documentation
   - Make Kconfig formatting consistent
   - Fix potential overflows in mtdchar_{write,read}()
   - Fallback to ->_{read,write}() when ->_{read,write}_oob() is missing
     and no OOB data were requested
   - Remove VLA usage in the bch lib

  MTD driver changes:
   - Use mtd_device_register() instead of mtd_device_parse_register()
     where applicable
   - Use proper printk format to print physical addresses in the
     solutionengine driver
   - Add missing mtd_set_of_node() call in the powernv driver
   - Remove unneeded variables in a few drivers
   - Plug the TRX part parser to the DT partition parsers logic
   - Check ioremap_cache() return code in the gpio-addr-flash driver
   - Stop using VMLINUX_SYMBOL_STR() in gen_probe.c

  SPI NOR core changes:
   - Apply reset hacks only when reset is explicitly marked as broken in
     the DT

   SPI NOR driver changes:
   - Minor cleanup/fixes in the m25p80 driver
   - Release flash_np in the nxp-spifi driver
   - Add suspend/resume hooks to the atmel-quadspi driver
   - Include gpio/consumer.h instead of gpio.h in the atmel-quadspi
     driver
   - Use %pK instead of %p in the stm32-quadspi driver
   - Improve timeout handling in the cadence-quadspi driver
   - Use mtd_device_register() instead of mtd_device_parse_register() in
     the intel-spi driver

  NAND core changes:
   - Add the SPI-NAND framework.
   - Create a helper to find the best ECC configuration.
   - Create NAND controller operations.
   - Allocate dynamically ONFI parameters structure.
   - Add defines for ONFI version bits.
   - Add manufacturer fixup for ONFI parameter page.
   - Add an option to specify NAND chip as a boot device.
   - Add Reed-Solomon error correction algorithm.
   - Better name for the controller structure.
   - Remove unused caller_is_module() definition.
   - Make subop helpers return unsigned values.
   - Expose _notsupp() helpers for raw page accessors.
   - Add default values for dynamic timings.
   - Kill the chip->scan_bbt() hook.
   - Rename nand_default_bbt() into nand_create_bbt().
   - Start to clean the nand_chip structure.
   - Remove stale prototype from rawnand.h.

  Raw NAND controllers drivers changes:
   - Qcom: structuring cleanup.
   - Denali: use core helper to find the best ECC configuration.
   - Possible build of almost all drivers by adding a dependency on
     COMPILE_TEST for almost all of them in Kconfig, implies various
     fixes, Kconfig cleanup, GPIO headers inclusion cleanup, and even
     changes in sparc64 and ia64 architectures.
   - Clean the ->probe() functions error path of a lot of drivers.
   - Migrate all drivers to use nand_scan() instead of
     nand_scan_ident()/nand_scan_tail() pair.
   - Use mtd_device_register() where applicable to simplify the code.
   - Marvell:
      * Handle on-die ECC.
      * Better clocks handling.
      * Remove bogus comment.
      * Add suspend and resume support.
   - Tegra: add NAND controller driver.
   - Atmel:
      * Add module param to avoid using dma.
      * Drop Wenyou Yang from MAINTAINERS.
   - Denali: optimize timings handling.
   - FSMC: Stop using chip->read_buf().
   - FSL:
      * Switch to SPDX license tag identifiers.
      * Fix qualifiers in MXC init functions.

  Raw NAND chip drivers changes:
   - Micron:
      * Add fixup for ONFI revision.
      * Update ecc_stats.corrected.
      * Make ECC activation stateful.
      * Avoid enabling/disabling ECC when it can't be disabled.
      * Get the actual number of bitflips.
      * Allow forced on-die ECC.
      * Support 8/512 on-die ECC.
      * Fix on-die ECC detection logic.
   - Hynix:
      * Fix decoding the OOB size on H27UCG8T2BTR.
      * Use ->exec_op() in hynix_nand_reg_write_op()"

* tag 'mtd/for-4.19' of git://git.infradead.org/linux-mtd: (188 commits)
  mtd: rawnand: atmel: Select GENERIC_ALLOCATOR
  MAINTAINERS: drop Wenyou Yang from Atmel NAND driver support
  mtd: rawnand: allocate dynamically ONFI parameters during detection
  mtd: spi-nor: only apply reset hacks to broken hardware
  mtd: spi-nor: cadence-quadspi: fix timeout handling
  mtd: spi-nor: atmel-quadspi: Include gpio/consumer.h instead of gpio.h
  mtd: spi-nor: intel-spi: use mtd_device_register()
  mtd: spi-nor: stm32-quadspi: replace "%p" with "%pK"
  mtd: spi-nor: atmel-quadspi: add suspend/resume hooks
  mtd: rawnand: allocate model parameter dynamically
  mtd: rawnand: do not export nand_scan_[ident|tail]() anymore
  mtd: rawnand: txx9ndfmc: convert driver to nand_scan()
  mtd: rawnand: txx9ndfmc: clarify ECC parameters assignation
  mtd: rawnand: tegra: convert driver to nand_scan()
  mtd: rawnand: jz4740: convert driver to nand_scan()
  mtd: rawnand: jz4740: group nand_scan_{ident, tail} calls
  mtd: rawnand: jz4740: fix probe function error path
  mtd: rawnand: docg4: convert driver to nand_scan()
  mtd: rawnand: do not execute nand_scan_ident() if maxchips is zero
  mtd: rawnand: atmel: convert driver to nand_scan()
  ...
This commit is contained in:
Linus Torvalds 2018-08-14 10:57:44 -07:00
commit c2fc71c9b7
121 changed files with 6537 additions and 2264 deletions

View file

@ -8,6 +8,9 @@ Required properties:
- 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.
- clocks: should contain phandle of the controller core clock, the bus
interface clock, and the ECC circuit clock.
- clock-names: should contain "nand", "nand_x", "ecc"
Optional properties:
- nand-ecc-step-size: see nand.txt for details. If present, the value must be
@ -31,5 +34,7 @@ nand: nand@ff900000 {
compatible = "altr,socfpga-denali-nand";
reg = <0xff900000 0x20>, <0xffb80000 0x1000>;
reg-names = "nand_data", "denali_reg";
clocks = <&nand_clk>, <&nand_x_clk>, <&nand_ecc_clk>;
clock-names = "nand", "nand_x", "ecc";
interrupts = <0 144 4>;
};

View file

@ -69,6 +69,15 @@ Optional properties:
all chips and support for it can not be detected at runtime.
Refer to your chips' datasheet to check if this is supported
by your chip.
- broken-flash-reset : Some flash devices utilize stateful addressing modes
(e.g., for 32-bit addressing) which need to be managed
carefully by a system. Because these sorts of flash don't
have a standardized software reset command, and because some
systems don't toggle the flash RESET# pin upon system reset
(if the pin even exists at all), there are systems which
cannot reboot properly if the flash is left in the "wrong"
state. This boolean flag can be used on such systems, to
denote the absence of a reliable reset mechanism.
Example:

View file

@ -25,7 +25,7 @@ Optional NAND chip properties:
Deprecated values:
"soft_bch": use "soft" and nand-ecc-algo instead
- nand-ecc-algo: string, algorithm of NAND ECC.
Supported values are: "hamming", "bch".
Valid values are: "hamming", "bch", "rs".
- nand-bus-width : 8 or 16 bus width if not present 8
- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
@ -43,6 +43,10 @@ Optional NAND chip properties:
This is particularly useful when only the in-band area is
used by the upper layers, and you want to make your NAND
as reliable as possible.
- nand-is-boot-medium: Whether the NAND chip is a boot medium. Drivers might use
this information to select ECC algorithms supported by
the boot ROM or similar restrictions.
- nand-rb: shall contain the native Ready/Busy ids.
The ECC strength and ECC step size properties define the correction capability

View file

@ -0,0 +1,64 @@
NVIDIA Tegra NAND Flash controller
Required properties:
- compatible: Must be one of:
- "nvidia,tegra20-nand"
- reg: MMIO address range
- interrupts: interrupt output of the NFC controller
- clocks: Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names: Must include the following entries:
- nand
- resets: Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details.
- reset-names: Must include the following entries:
- nand
Optional children nodes:
Individual NAND chips are children of the NAND controller node. Currently
only one NAND chip supported.
Required children node properties:
- reg: An integer ranging from 1 to 6 representing the CS line to use.
Optional children node properties:
- nand-ecc-mode: String, operation mode of the NAND ecc mode. Currently only
"hw" is supported.
- nand-ecc-algo: string, algorithm of NAND ECC.
Supported values with "hw" ECC mode are: "rs", "bch".
- nand-bus-width : See nand.txt
- nand-on-flash-bbt: See nand.txt
- nand-ecc-strength: integer representing the number of bits to correct
per ECC step (always 512). Supported strength using HW ECC
modes are:
- RS: 4, 6, 8
- BCH: 4, 8, 14, 16
- nand-ecc-maximize: See nand.txt
- nand-is-boot-medium: Makes sure only ECC strengths supported by the boot ROM
are chosen.
- wp-gpios: GPIO specifier for the write protect pin.
Optional child node of NAND chip nodes:
Partitions: see partition.txt
Example:
nand-controller@70008000 {
compatible = "nvidia,tegra20-nand";
reg = <0x70008000 0x100>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA20_CLK_NDFLASH>;
clock-names = "nand";
resets = <&tegra_car 13>;
reset-names = "nand";
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-bus-width = <8>;
nand-on-flash-bbt;
nand-ecc-algo = "bch";
nand-ecc-strength = <8>;
wp-gpios = <&gpio TEGRA_GPIO(S, 0) GPIO_ACTIVE_LOW>;
};
};

View file

@ -14,6 +14,13 @@ method is used for a given flash device. To describe the method there should be
a subnode of the flash device that is named 'partitions'. It must have a
'compatible' property, which is used to identify the method to use.
When a single partition is represented with a DT node (it depends on a used
format) it may also be described using above rules ('compatible' and optionally
some extra properties / subnodes). It allows describing more complex,
hierarchical (multi-level) layouts and should be used if there is some
significant relation between partitions or some partition internally uses
another partitioning method.
Available bindings are listed in the "partitions" subdirectory.
@ -109,3 +116,42 @@ flash@2 {
};
};
};
flash@3 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "bootloader";
reg = <0x000000 0x100000>;
read-only;
};
firmware@100000 {
label = "firmware";
reg = <0x100000 0xe00000>;
compatible = "brcm,trx";
};
calibration@f00000 {
label = "calibration";
reg = <0xf00000 0x100000>;
compatible = "fixed-partitions";
ranges = <0 0xf00000 0x100000>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "wifi0";
reg = <0x000000 0x080000>;
};
partition@80000 {
label = "wifi1";
reg = <0x080000 0x080000>;
};
};
};
};

View file

@ -0,0 +1,37 @@
Broadcom TRX Container Partition
================================
TRX is Broadcom's official firmware format for the BCM947xx boards. It's used by
most of the vendors building devices based on Broadcom's BCM47xx SoCs and is
supported by the CFE bootloader.
Design of the TRX format is very minimalistic. Its header contains
identification fields, CRC32 checksum and the locations of embedded partitions.
Its purpose is to store a few partitions in a format that can be distributed as
a standalone file and written in a flash memory.
Container can hold up to 4 partitions. The first partition has to contain a
device executable binary (e.g. a kernel) as it's what the CFE bootloader starts
executing. Other partitions can be used for operating system purposes. This is
useful for systems that keep kernel and rootfs separated.
TRX doesn't enforce any strict partition boundaries or size limits. All
partitions have to be less than the 4GiB max size limit.
There are two existing/known TRX variants:
1) v1 which contains 3 partitions
2) v2 which contains 4 partitions
There aren't separated compatible bindings for them as version can be trivialy
detected by a software parsing TRX header.
Required properties:
- compatible : (required) must be "brcm,trx"
Example:
flash@0 {
partitions {
compatible = "brcm,trx";
};
};

View file

@ -45,11 +45,12 @@ Required properties:
number (e.g., 0, 1, 2, etc.)
- #address-cells: see partition.txt
- #size-cells: see partition.txt
- nand-ecc-strength: see nand.txt
- nand-ecc-step-size: must be 512. see nand.txt for more details.
Optional properties:
- nand-bus-width: see nand.txt
- nand-ecc-strength: see nand.txt. If not specified, then ECC strength will
be used according to chip requirement and available
OOB size.
Each nandcs device node may optionally contain a 'partitions' sub-node, which
further contains sub-nodes describing the flash partition mapping. See
@ -77,7 +78,6 @@ nand-controller@1ac00000 {
reg = <0>;
nand-ecc-strength = <4>;
nand-ecc-step-size = <512>;
nand-bus-width = <8>;
partitions {
@ -117,7 +117,6 @@ nand-controller@79b0000 {
nand@0 {
reg = <0>;
nand-ecc-strength = <4>;
nand-ecc-step-size = <512>;
nand-bus-width = <8>;
partitions {

View file

@ -0,0 +1,5 @@
SPI NAND flash
Required properties:
- compatible: should be "spi-nand"
- reg: should encode the chip-select line used to access the NAND chip

View file

@ -9353,7 +9353,6 @@ F: drivers/media/platform/atmel/atmel-isc-regs.h
F: devicetree/bindings/media/atmel-isc.txt
MICROCHIP / ATMEL NAND DRIVER
M: Wenyou Yang <wenyou.yang@microchip.com>
M: Josh Wu <rainyfeeling@outlook.com>
L: linux-mtd@lists.infradead.org
S: Supported
@ -14063,6 +14062,13 @@ M: Laxman Dewangan <ldewangan@nvidia.com>
S: Supported
F: drivers/input/keyboard/tegra-kbc.c
TEGRA NAND DRIVER
M: Stefan Agner <stefan@agner.ch>
M: Lucas Stach <dev@lynxeye.de>
S: Maintained
F: Documentation/devicetree/bindings/mtd/nvidia-tegra20-nand.txt
F: drivers/mtd/nand/raw/tegra_nand.c
TEGRA PWM DRIVER
M: Thierry Reding <thierry.reding@gmail.com>
S: Supported

View file

@ -688,7 +688,6 @@ struct platform_nand_data balloon3_nand_pdata = {
.chip_delay = 50,
},
.ctrl = {
.hwcontrol = 0,
.dev_ready = balloon3_nand_dev_ready,
.select_chip = balloon3_nand_select_chip,
.cmd_ctrl = balloon3_nand_cmd_ctl,

View file

@ -346,7 +346,6 @@ struct platform_nand_data em_x270_nand_platdata = {
.chip_delay = 20,
},
.ctrl = {
.hwcontrol = 0,
.dev_ready = em_x270_nand_device_ready,
.select_chip = 0,
.cmd_ctrl = em_x270_nand_cmd_ctl,

View file

@ -83,12 +83,14 @@ virt_to_phys (volatile void *address)
{
return (unsigned long) address - PAGE_OFFSET;
}
#define virt_to_phys virt_to_phys
static inline void*
phys_to_virt (unsigned long address)
{
return (void *) (address + PAGE_OFFSET);
}
#define phys_to_virt phys_to_virt
#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
extern u64 kern_mem_attribute (unsigned long phys_addr, unsigned long size);
@ -433,9 +435,11 @@ static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned lo
{
return ioremap(phys_addr, size);
}
#define ioremap ioremap
#define ioremap_nocache ioremap_nocache
#define ioremap_cache ioremap_cache
#define ioremap_uc ioremap_nocache
#define iounmap iounmap
/*
* String version of IO memory access ops:
@ -444,6 +448,13 @@ extern void memcpy_fromio(void *dst, const volatile void __iomem *src, long n);
extern void memcpy_toio(volatile void __iomem *dst, const void *src, long n);
extern void memset_io(volatile void __iomem *s, int c, long n);
#define memcpy_fromio memcpy_fromio
#define memcpy_toio memcpy_toio
#define memset_io memset_io
#define xlate_dev_kmem_ptr xlate_dev_kmem_ptr
#define xlate_dev_mem_ptr xlate_dev_mem_ptr
#include <asm-generic/io.h>
# endif /* __KERNEL__ */
#endif /* _ASM_IA64_IO_H */

View file

@ -29,10 +29,11 @@
#include <linux/power/gpio-charger.h>
#include <linux/pwm.h>
#include <linux/platform_data/jz4740/jz4740_nand.h>
#include <asm/mach-jz4740/gpio.h>
#include <asm/mach-jz4740/jz4740_fb.h>
#include <asm/mach-jz4740/jz4740_mmc.h>
#include <asm/mach-jz4740/jz4740_nand.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>

View file

@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/platform_data/txx9/ndfmc.h>
#include <linux/serial_core.h>
#include <linux/mtd/physmap.h>
#include <linux/leds.h>
@ -36,7 +37,6 @@
#include <asm/txx9/generic.h>
#include <asm/txx9/pci.h>
#include <asm/txx9tmr.h>
#include <asm/txx9/ndfmc.h>
#include <asm/txx9/dmac.h>
#ifdef CONFIG_CPU_TX49XX
#include <asm/txx9/tx4938.h>

View file

@ -17,13 +17,13 @@
#include <linux/ptrace.h>
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/platform_data/txx9/ndfmc.h>
#include <asm/reboot.h>
#include <asm/traps.h>
#include <asm/txx9irq.h>
#include <asm/txx9tmr.h>
#include <asm/txx9pio.h>
#include <asm/txx9/generic.h>
#include <asm/txx9/ndfmc.h>
#include <asm/txx9/dmac.h>
#include <asm/txx9/tx4938.h>

View file

@ -21,13 +21,13 @@
#include <linux/ptrace.h>
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/platform_data/txx9/ndfmc.h>
#include <asm/bootinfo.h>
#include <asm/reboot.h>
#include <asm/traps.h>
#include <asm/txx9irq.h>
#include <asm/txx9tmr.h>
#include <asm/txx9/generic.h>
#include <asm/txx9/ndfmc.h>
#include <asm/txx9/dmac.h>
#include <asm/txx9/tx4939.h>

View file

@ -243,35 +243,42 @@ void insb(unsigned long, void *, unsigned long);
void insw(unsigned long, void *, unsigned long);
void insl(unsigned long, void *, unsigned long);
static inline void ioread8_rep(void __iomem *port, void *buf, unsigned long count)
static inline void readsb(void __iomem *port, void *buf, unsigned long count)
{
insb((unsigned long __force)port, buf, count);
}
static inline void ioread16_rep(void __iomem *port, void *buf, unsigned long count)
static inline void readsw(void __iomem *port, void *buf, unsigned long count)
{
insw((unsigned long __force)port, buf, count);
}
static inline void ioread32_rep(void __iomem *port, void *buf, unsigned long count)
static inline void readsl(void __iomem *port, void *buf, unsigned long count)
{
insl((unsigned long __force)port, buf, count);
}
static inline void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count)
static inline void writesb(void __iomem *port, const void *buf, unsigned long count)
{
outsb((unsigned long __force)port, buf, count);
}
static inline void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count)
static inline void writesw(void __iomem *port, const void *buf, unsigned long count)
{
outsw((unsigned long __force)port, buf, count);
}
static inline void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count)
static inline void writesl(void __iomem *port, const void *buf, unsigned long count)
{
outsl((unsigned long __force)port, buf, count);
}
#define ioread8_rep(p,d,l) readsb(p,d,l)
#define ioread16_rep(p,d,l) readsw(p,d,l)
#define ioread32_rep(p,d,l) readsl(p,d,l)
#define iowrite8_rep(p,d,l) writesb(p,d,l)
#define iowrite16_rep(p,d,l) writesw(p,d,l)
#define iowrite32_rep(p,d,l) writesl(p,d,l)
/* Valid I/O Space regions are anywhere, because each PCI bus supported
* can live in an arbitrary area of the physical address range.
*/

View file

@ -30,6 +30,7 @@ config BCMA_HOST_PCI
config BCMA_HOST_SOC
bool "Support for BCMA in a SoC"
depends on HAS_IOMEM
help
Host interface for a Broadcom AIX bus directly mapped into
the memory. This only works with the Broadcom SoCs from the
@ -61,7 +62,7 @@ config BCMA_DRIVER_PCI_HOSTMODE
config BCMA_DRIVER_MIPS
bool "BCMA Broadcom MIPS core driver"
depends on MIPS
depends on MIPS || COMPILE_TEST
help
Driver for the Broadcom MIPS core attached to Broadcom specific
Advanced Microcontroller Bus.

View file

@ -116,12 +116,14 @@ config FSL_CORENET_CF
config FSL_IFC
bool
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST
depends on HAS_IOMEM
config JZ4780_NEMC
bool "Ingenic JZ4780 SoC NEMC driver"
default y
depends on MACH_JZ4780
depends on MACH_JZ4780 || COMPILE_TEST
depends on HAS_IOMEM && OF
help
This driver is for the NAND/External Memory Controller (NEMC) in
the Ingenic JZ4780. This controller is used to handle external

View file

@ -24,7 +24,7 @@ config MTD_TESTS
config MTD_REDBOOT_PARTS
tristate "RedBoot partition table parsing"
---help---
help
RedBoot is a ROM monitor and bootloader which deals with multiple
'images' in flash devices by putting a table one of the erase
blocks on the device, similar to a partition table, which gives
@ -45,7 +45,7 @@ if MTD_REDBOOT_PARTS
config MTD_REDBOOT_DIRECTORY_BLOCK
int "Location of RedBoot partition table"
default "-1"
---help---
help
This option is the Linux counterpart to the
CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK RedBoot compile time
option.
@ -75,7 +75,7 @@ endif # MTD_REDBOOT_PARTS
config MTD_CMDLINE_PARTS
tristate "Command line partition table parsing"
depends on MTD
---help---
help
Allow generic configuration of the MTD partition tables via the kernel
command line. Multiple flash resources are supported for hardware where
different kinds of flash memory are available.
@ -112,7 +112,7 @@ config MTD_CMDLINE_PARTS
config MTD_AFS_PARTS
tristate "ARM Firmware Suite partition parsing"
depends on (ARM || ARM64)
---help---
help
The ARM Firmware Suite allows the user to divide flash devices into
multiple 'images'. Each such image has a header containing its name
and offset/size etc.
@ -136,7 +136,7 @@ config MTD_OF_PARTS
config MTD_AR7_PARTS
tristate "TI AR7 partitioning support"
---help---
help
TI AR7 partitioning support
config MTD_BCM63XX_PARTS
@ -170,7 +170,7 @@ config MTD_BLOCK
tristate "Caching block device access to MTD devices"
depends on BLOCK
select MTD_BLKDEVS
---help---
help
Although most flash chips have an erase size too large to be useful
as block devices, it is possible to use MTD devices which are based
on RAM chips in this manner. This block device is a user of MTD
@ -205,7 +205,7 @@ config FTL
tristate "FTL (Flash Translation Layer) support"
depends on BLOCK
select MTD_BLKDEVS
---help---
help
This provides support for the original Flash Translation Layer which
is part of the PCMCIA specification. It uses a kind of pseudo-
file system on a flash device to emulate a block device with
@ -222,7 +222,7 @@ config NFTL
tristate "NFTL (NAND Flash Translation Layer) support"
depends on BLOCK
select MTD_BLKDEVS
---help---
help
This provides support for the NAND Flash Translation Layer which is
used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
file system on a flash device to emulate a block device with
@ -246,7 +246,7 @@ config INFTL
tristate "INFTL (Inverse NAND Flash Translation Layer) support"
depends on BLOCK
select MTD_BLKDEVS
---help---
help
This provides support for the Inverse NAND Flash Translation
Layer which is used on M-Systems' newer DiskOnChip devices. It
uses a kind of pseudo-file system on a flash device to emulate
@ -261,10 +261,10 @@ config INFTL
not use it.
config RFD_FTL
tristate "Resident Flash Disk (Flash Translation Layer) support"
tristate "Resident Flash Disk (Flash Translation Layer) support"
depends on BLOCK
select MTD_BLKDEVS
---help---
help
This provides support for the flash translation layer known
as the Resident Flash Disk (RFD), as used by the Embedded BIOS
of General Software. There is a blurb at:
@ -308,7 +308,7 @@ config MTD_SWAP
select MTD_BLKDEVS
help
Provides volatile block device driver on top of mtd partition
suitable for swapping. The mapping of written blocks is not saved.
suitable for swapping. The mapping of written blocks is not saved.
The driver provides wear leveling by storing erase counter into the
OOB.

View file

@ -44,7 +44,7 @@ choice
prompt "Flash cmd/query data swapping"
depends on MTD_CFI_ADV_OPTIONS
default MTD_CFI_NOSWAP
---help---
help
This option defines the way in which the CPU attempts to arrange
data bits when writing the 'magic' commands to the chips. Saying
'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't

View file

@ -1216,7 +1216,6 @@ static inline int do_read_secsi_onechip(struct map_info *map,
size_t grouplen)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long timeo = jiffies + HZ;
retry:
mutex_lock(&chip->mutex);
@ -1229,7 +1228,6 @@ static inline int do_read_secsi_onechip(struct map_info *map,
schedule();
remove_wait_queue(&chip->wq, &wait);
timeo = jiffies + HZ;
goto retry;
}

View file

@ -202,16 +202,19 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
struct cfi_private *cfi = map->fldrv_priv;
__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
#ifdef CONFIG_MODULES
char probename[sizeof(VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X))];
cfi_cmdset_fn_t *probe_function;
char *probename;
sprintf(probename, VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X), type);
probename = kasprintf(GFP_KERNEL, "cfi_cmdset_%4.4X", type);
if (!probename)
return NULL;
probe_function = __symbol_get(probename);
if (!probe_function) {
request_module("cfi_cmdset_%4.4X", type);
probe_function = __symbol_get(probename);
}
kfree(probename);
if (probe_function) {
struct mtd_info *mtd;

View file

@ -5,7 +5,7 @@ menu "Self-contained MTD device drivers"
config MTD_PMC551
tristate "Ramix PMC551 PCI Mezzanine RAM card support"
depends on PCI
---help---
help
This provides a MTD device driver for the Ramix PMC551 RAM PCI card
from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
These devices come in memory configurations from 32M - 1G. If you
@ -209,7 +209,7 @@ config MTD_DOCG3
select BCH
select BCH_CONST_PARAMS
select BITREVERSE
---help---
help
This provides an MTD device driver for the M-Systems DiskOnChip
G3 devices.

View file

@ -28,11 +28,9 @@
#include <linux/spi/flash.h>
#include <linux/mtd/spi-nor.h>
#define MAX_CMD_SIZE 6
struct m25p {
struct spi_mem *spimem;
struct spi_nor spi_nor;
u8 command[MAX_CMD_SIZE];
};
static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
@ -70,7 +68,7 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
struct spi_mem_op op =
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
SPI_MEM_OP_DUMMY(0, 1),
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_OUT(len, buf, 1));
size_t remaining = len;
int ret;
@ -78,7 +76,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
/* get transfer protocols. */
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
op.dummy.buswidth = op.addr.buswidth;
op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)

View file

@ -223,6 +223,7 @@ static int powernv_flash_set_driver_info(struct device *dev,
mtd->_read = powernv_flash_read;
mtd->_write = powernv_flash_write;
mtd->dev.parent = dev;
mtd_set_of_node(mtd, dev->of_node);
return 0;
}

View file

@ -394,9 +394,8 @@ static int sst25l_probe(struct spi_device *spi)
flash->mtd.numeraseregions);
ret = mtd_device_parse_register(&flash->mtd, NULL, NULL,
data ? data->parts : NULL,
data ? data->nr_parts : 0);
ret = mtd_device_register(&flash->mtd, data ? data->parts : NULL,
data ? data->nr_parts : 0);
if (ret)
return -ENODEV;

View file

@ -13,10 +13,10 @@ config MTD_QINFO_PROBE
depends on MTD_LPDDR
tristate "Detect flash chips by QINFO probe"
help
Device Information for LPDDR chips is offered through the Overlay
Window QINFO interface, permits software to be used for entire
families of devices. This serves similar purpose of CFI on legacy
Flash products
Device Information for LPDDR chips is offered through the Overlay
Window QINFO interface, permits software to be used for entire
families of devices. This serves similar purpose of CFI on legacy
Flash products
config MTD_LPDDR2_NVM
# ARM dependency is only for writel_relaxed()

View file

@ -476,7 +476,7 @@ static int lpddr2_nvm_probe(struct platform_device *pdev)
return -EINVAL;
}
/* Parse partitions and register the MTD device */
return mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
return mtd_device_register(mtd, NULL, 0);
}
/*

View file

@ -207,13 +207,13 @@ config MTD_ICHXROM
BE VERY CAREFUL.
config MTD_ESB2ROM
tristate "BIOS flash chip on Intel ESB Controller Hub 2"
depends on X86 && MTD_JEDECPROBE && PCI
help
Support for treating the BIOS flash chip on ESB2 motherboards
as an MTD device - with this you can reprogram your BIOS.
tristate "BIOS flash chip on Intel ESB Controller Hub 2"
depends on X86 && MTD_JEDECPROBE && PCI
help
Support for treating the BIOS flash chip on ESB2 motherboards
as an MTD device - with this you can reprogram your BIOS.
BE VERY CAREFUL.
BE VERY CAREFUL.
config MTD_CK804XROM
tristate "BIOS flash chip on Nvidia CK804"
@ -401,12 +401,12 @@ config MTD_PISMO
When built as a module, it will be called pismo.ko
config MTD_LATCH_ADDR
tristate "Latch-assisted Flash Chip Support"
depends on MTD_COMPLEX_MAPPINGS
help
Map driver which allows flashes to be partially physically addressed
and have the upper address lines set by a board specific code.
tristate "Latch-assisted Flash Chip Support"
depends on MTD_COMPLEX_MAPPINGS
help
Map driver which allows flashes to be partially physically addressed
and have the upper address lines set by a board specific code.
If compiled as a module, it will be called latch-addr-flash.
If compiled as a module, it will be called latch-addr-flash.
endmenu

View file

@ -239,6 +239,9 @@ static int gpio_flash_probe(struct platform_device *pdev)
state->map.bankwidth = pdata->width;
state->map.size = state->win_size * (1 << state->gpio_count);
state->map.virt = ioremap_nocache(memory->start, state->map.size);
if (!state->map.virt)
return -ENOMEM;
state->map.phys = NO_XIP;
state->map.map_priv_1 = (unsigned long)state;

View file

@ -88,9 +88,8 @@ static int __init init_impa7(void)
if (impa7_mtd[i]) {
impa7_mtd[i]->owner = THIS_MODULE;
devicesfound++;
mtd_device_parse_register(impa7_mtd[i], NULL, NULL,
partitions,
ARRAY_SIZE(partitions));
mtd_device_register(impa7_mtd[i], partitions,
ARRAY_SIZE(partitions));
} else {
iounmap((void __iomem *)impa7_map[i].virt);
}

View file

@ -71,7 +71,7 @@ static int vr_nor_init_partitions(struct vr_nor_mtd *p)
{
/* register the flash bank */
/* partition the flash bank */
return mtd_device_parse_register(p->info, NULL, NULL, NULL, 0);
return mtd_device_register(p->info, NULL, 0);
}
static void vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)

View file

@ -197,9 +197,8 @@ static int latch_addr_flash_probe(struct platform_device *dev)
}
info->mtd->dev.parent = &dev->dev;
mtd_device_parse_register(info->mtd, NULL, NULL,
latch_addr_data->parts,
latch_addr_data->nr_parts);
mtd_device_register(info->mtd, latch_addr_data->parts,
latch_addr_data->nr_parts);
return 0;
iounmap:

View file

@ -97,8 +97,7 @@ static int rbtx4939_flash_probe(struct platform_device *dev)
goto err_out;
}
info->mtd->dev.parent = &dev->dev;
err = mtd_device_parse_register(info->mtd, NULL, NULL, pdata->parts,
pdata->nr_parts);
err = mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts);
if (err)
goto err_out;

View file

@ -59,9 +59,9 @@ static int __init init_soleng_maps(void)
return -ENXIO;
}
}
printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n",
soleng_flash_map.phys & 0x1fffffff,
soleng_eprom_map.phys & 0x1fffffff);
printk(KERN_NOTICE "Solution Engine: Flash at 0x%pap, EPROM at 0x%pap\n",
&soleng_flash_map.phys,
&soleng_eprom_map.phys);
flash_mtd->owner = THIS_MODULE;
eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map);

View file

@ -160,8 +160,12 @@ static ssize_t mtdchar_read(struct file *file, char __user *buf, size_t count,
pr_debug("MTD_read\n");
if (*ppos + count > mtd->size)
count = mtd->size - *ppos;
if (*ppos + count > mtd->size) {
if (*ppos < mtd->size)
count = mtd->size - *ppos;
else
count = 0;
}
if (!count)
return 0;
@ -246,7 +250,7 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c
pr_debug("MTD_write\n");
if (*ppos == mtd->size)
if (*ppos >= mtd->size)
return -ENOSPC;
if (*ppos + count > mtd->size)

View file

@ -1155,21 +1155,29 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
{
int ret_code;
ops->retlen = ops->oobretlen = 0;
if (!mtd->_read_oob)
return -EOPNOTSUPP;
ret_code = mtd_check_oob_ops(mtd, from, ops);
if (ret_code)
return ret_code;
ledtrig_mtd_activity();
/* Check the validity of a potential fallback on mtd->_read */
if (!mtd->_read_oob && (!mtd->_read || ops->oobbuf))
return -EOPNOTSUPP;
if (mtd->_read_oob)
ret_code = mtd->_read_oob(mtd, from, ops);
else
ret_code = mtd->_read(mtd, from, ops->len, &ops->retlen,
ops->datbuf);
/*
* In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
* similar to mtd->_read(), returning a non-negative integer
* representing max bitflips. In other cases, mtd->_read_oob() may
* return -EUCLEAN. In all cases, perform similar logic to mtd_read().
*/
ret_code = mtd->_read_oob(mtd, from, ops);
if (unlikely(ret_code < 0))
return ret_code;
if (mtd->ecc_strength == 0)
@ -1184,8 +1192,7 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
int ret;
ops->retlen = ops->oobretlen = 0;
if (!mtd->_write_oob)
return -EOPNOTSUPP;
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
@ -1194,7 +1201,16 @@ int mtd_write_oob(struct mtd_info *mtd, loff_t to,
return ret;
ledtrig_mtd_activity();
return mtd->_write_oob(mtd, to, ops);
/* Check the validity of a potential fallback on mtd->_write */
if (!mtd->_write_oob && (!mtd->_write || ops->oobbuf))
return -EOPNOTSUPP;
if (mtd->_write_oob)
return mtd->_write_oob(mtd, to, ops);
else
return mtd->_write(mtd, to, ops->len, &ops->retlen,
ops->datbuf);
}
EXPORT_SYMBOL_GPL(mtd_write_oob);

View file

@ -322,22 +322,6 @@ static inline void free_partition(struct mtd_part *p)
kfree(p);
}
/**
* mtd_parse_part - parse MTD partition looking for subpartitions
*
* @slave: part that is supposed to be a container and should be parsed
* @types: NULL-terminated array with names of partition parsers to try
*
* Some partitions are kind of containers with extra subpartitions (volumes).
* There can be various formats of such containers. This function tries to use
* specified parsers to analyze given partition and registers found
* subpartitions on success.
*/
static int mtd_parse_part(struct mtd_part *slave, const char *const *types)
{
return parse_mtd_partitions(&slave->mtd, types, NULL);
}
static struct mtd_part *allocate_partition(struct mtd_info *parent,
const struct mtd_partition *part, int partno,
uint64_t cur_offset)
@ -735,8 +719,8 @@ int add_mtd_partitions(struct mtd_info *master,
add_mtd_device(&slave->mtd);
mtd_add_partition_attrs(slave);
if (parts[i].types)
mtd_parse_part(slave, parts[i].types);
/* Look for subpartitions */
parse_mtd_partitions(&slave->mtd, parts[i].types, NULL);
cur_offset = slave->offset + slave->mtd.size;
}
@ -812,6 +796,12 @@ static const char * const default_mtd_part_types[] = {
NULL
};
/* Check DT only when looking for subpartitions. */
static const char * const default_subpartition_types[] = {
"ofpart",
NULL
};
static int mtd_part_do_parse(struct mtd_part_parser *parser,
struct mtd_info *master,
struct mtd_partitions *pparts,
@ -882,7 +872,9 @@ static int mtd_part_of_parse(struct mtd_info *master,
const char *fixed = "fixed-partitions";
int ret, err = 0;
np = of_get_child_by_name(mtd_get_of_node(master), "partitions");
np = mtd_get_of_node(master);
if (!mtd_is_partition(master))
np = of_get_child_by_name(np, "partitions");
of_property_for_each_string(np, "compatible", prop, compat) {
parser = mtd_part_get_compatible_parser(compat);
if (!parser)
@ -945,7 +937,8 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
int ret, err = 0;
if (!types)
types = default_mtd_part_types;
types = mtd_is_partition(master) ? default_subpartition_types :
default_mtd_part_types;
for ( ; *types; types++) {
/*

View file

@ -4,3 +4,4 @@ config MTD_NAND_CORE
source "drivers/mtd/nand/onenand/Kconfig"
source "drivers/mtd/nand/raw/Kconfig"
source "drivers/mtd/nand/spi/Kconfig"

View file

@ -5,3 +5,4 @@ obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
obj-y += onenand/
obj-y += raw/
obj-y += spi/

View file

@ -66,9 +66,8 @@ static int generic_onenand_probe(struct platform_device *pdev)
goto out_iounmap;
}
err = mtd_device_parse_register(&info->mtd, NULL, NULL,
pdata ? pdata->parts : NULL,
pdata ? pdata->nr_parts : 0);
err = mtd_device_register(&info->mtd, pdata ? pdata->parts : NULL,
pdata ? pdata->nr_parts : 0);
platform_set_drvdata(pdev, info);

View file

@ -933,9 +933,8 @@ static int s3c_onenand_probe(struct platform_device *pdev)
if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ)
dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n");
err = mtd_device_parse_register(mtd, NULL, NULL,
pdata ? pdata->parts : NULL,
pdata ? pdata->nr_parts : 0);
err = mtd_device_register(mtd, pdata ? pdata->parts : NULL,
pdata ? pdata->nr_parts : 0);
if (err) {
dev_err(&pdev->dev, "failed to parse partitions and register the MTD device\n");
onenand_release(mtd);

View file

@ -44,12 +44,12 @@ config MTD_NAND_DENALI
tristate
config MTD_NAND_DENALI_PCI
tristate "Support Denali NAND controller on Intel Moorestown"
tristate "Support Denali NAND controller on Intel Moorestown"
select MTD_NAND_DENALI
depends on PCI
help
Enable the driver for NAND flash on Intel Moorestown, using the
Denali NAND controller core.
help
Enable the driver for NAND flash on Intel Moorestown, using the
Denali NAND controller core.
config MTD_NAND_DENALI_DT
tristate "Support Denali NAND controller as a DT device"
@ -77,9 +77,10 @@ config MTD_NAND_AMS_DELTA
config MTD_NAND_OMAP2
tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST
depends on HAS_IOMEM
help
Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
and Keystone platforms.
config MTD_NAND_OMAP_BCH
@ -137,7 +138,7 @@ config MTD_NAND_NDFC
depends on 4xx
select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
config MTD_NAND_S3C2410_CLKSTOP
bool "Samsung S3C NAND IDLE clock stop"
@ -152,6 +153,7 @@ config MTD_NAND_S3C2410_CLKSTOP
config MTD_NAND_TANGO
tristate "NAND Flash support for Tango chips"
depends on ARCH_TANGO || COMPILE_TEST
depends on HAS_IOMEM
help
Enables the NAND Flash controller on Tango chips.
@ -168,40 +170,40 @@ config MTD_NAND_DISKONCHIP
these devices.
config MTD_NAND_DISKONCHIP_PROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
depends on MTD_NAND_DISKONCHIP
help
This option allows you to specify nonstandard address at which to
probe for a DiskOnChip, or to change the detection options. You
are unlikely to need any of this unless you are using LinuxBIOS.
Say 'N'.
bool "Advanced detection options for DiskOnChip"
depends on MTD_NAND_DISKONCHIP
help
This option allows you to specify nonstandard address at which to
probe for a DiskOnChip, or to change the detection options. You
are unlikely to need any of this unless you are using LinuxBIOS.
Say 'N'.
config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
depends on MTD_NAND_DISKONCHIP
default "0"
---help---
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option allows you to specify a single address at which to probe
for the device, which is useful if you have other devices in that
range which get upset when they are probed.
hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
depends on MTD_NAND_DISKONCHIP
default "0"
help
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option allows you to specify a single address at which to probe
for the device, which is useful if you have other devices in that
range which get upset when they are probed.
(Note that on PowerPC, the normal probe will only check at
0xE4000000.)
(Note that on PowerPC, the normal probe will only check at
0xE4000000.)
Normally, you should leave this set to zero, to allow the probe at
the normal addresses.
Normally, you should leave this set to zero, to allow the probe at
the normal addresses.
config MTD_NAND_DISKONCHIP_PROBE_HIGH
bool "Probe high addresses"
depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
help
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option changes to make it probe between 0xFFFC8000 and
0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be
useful to you. Say 'N'.
bool "Probe high addresses"
depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
help
By default, the probe for DiskOnChip devices will look for a
DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
This option changes to make it probe between 0xFFFC8000 and
0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be
useful to you. Say 'N'.
config MTD_NAND_DISKONCHIP_BBTWRITE
bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
@ -247,7 +249,8 @@ config MTD_NAND_DOCG4
config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on ARCH_PXA
depends on ARCH_PXA || COMPILE_TEST
depends on HAS_IOMEM
config MTD_NAND_CAFE
tristate "NAND support for OLPC CAFÉ chip"
@ -274,7 +277,9 @@ config MTD_NAND_CS553X
config MTD_NAND_ATMEL
tristate "Support for NAND Flash / SmartMedia on AT91"
depends on ARCH_AT91
depends on ARCH_AT91 || COMPILE_TEST
depends on HAS_IOMEM
select GENERIC_ALLOCATOR
select MFD_ATMEL_SMC
help
Enables support for NAND Flash / Smart Media Card interface
@ -294,7 +299,8 @@ config MTD_NAND_MARVELL
config MTD_NAND_SLC_LPC32XX
tristate "NXP LPC32xx SLC Controller"
depends on ARCH_LPC32XX
depends on ARCH_LPC32XX || COMPILE_TEST
depends on HAS_IOMEM
help
Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
chips) NAND controller. This is the default for the PHYTEC 3250
@ -305,7 +311,8 @@ config MTD_NAND_SLC_LPC32XX
config MTD_NAND_MLC_LPC32XX
tristate "NXP LPC32xx MLC Controller"
depends on ARCH_LPC32XX
depends on ARCH_LPC32XX || COMPILE_TEST
depends on HAS_IOMEM
help
Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
controller. This is the default for the WORK92105 controller
@ -339,17 +346,18 @@ config MTD_NAND_NANDSIM
MTD nand layer.
config MTD_NAND_GPMI_NAND
tristate "GPMI NAND Flash Controller driver"
depends on MTD_NAND && MXS_DMA
help
Enables NAND Flash support for IMX23, IMX28 or IMX6.
The GPMI controller is very powerful, with the help of BCH
module, it can do the hardware ECC. The GPMI supports several
NAND flashs at the same time.
tristate "GPMI NAND Flash Controller driver"
depends on MXS_DMA
help
Enables NAND Flash support for IMX23, IMX28 or IMX6.
The GPMI controller is very powerful, with the help of BCH
module, it can do the hardware ECC. The GPMI supports several
NAND flashs at the same time.
config MTD_NAND_BRCMNAND
tristate "Broadcom STB NAND controller"
depends on ARM || ARM64 || MIPS
depends on ARM || ARM64 || MIPS || COMPILE_TEST
depends on HAS_IOMEM
help
Enables the Broadcom NAND controller driver. The controller was
originally designed for Set-Top Box but is used on various BCM7xxx,
@ -358,6 +366,7 @@ config MTD_NAND_BRCMNAND
config MTD_NAND_BCM47XXNFLASH
tristate "Support for NAND flash on BCM4706 BCMA bus"
depends on BCMA_NFLASH
depends on BCMA
help
BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for
@ -399,7 +408,8 @@ config MTD_NAND_FSL_ELBC
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST
depends on HAS_IOMEM
select FSL_IFC
select MEMORY
help
@ -437,7 +447,8 @@ config MTD_NAND_VF610_NFC
config MTD_NAND_MXC
tristate "MXC NAND support"
depends on ARCH_MXC
depends on ARCH_MXC || COMPILE_TEST
depends on HAS_IOMEM
help
This enables the driver for the NAND flash controller on the
MXC processors.
@ -451,15 +462,17 @@ config MTD_NAND_SH_FLCTL
for NAND Flash using FLCTL.
config MTD_NAND_DAVINCI
tristate "Support NAND on DaVinci/Keystone SoC"
depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
help
tristate "Support NAND on DaVinci/Keystone SoC"
depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) || COMPILE_TEST
depends on HAS_IOMEM
help
Enable the driver for NAND flash chips on Texas Instruments
DaVinci/Keystone processors.
config MTD_NAND_TXX9NDFMC
tristate "NAND Flash support for TXx9 SoC"
depends on SOC_TX4938 || SOC_TX4939
depends on SOC_TX4938 || SOC_TX4939 || COMPILE_TEST
depends on HAS_IOMEM
help
This enables the NAND flash controller on the TXx9 SoCs.
@ -471,28 +484,31 @@ config MTD_NAND_SOCRATES
config MTD_NAND_NUC900
tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards."
depends on ARCH_W90X900
depends on ARCH_W90X900 || COMPILE_TEST
depends on HAS_IOMEM
help
This enables the driver for the NAND Flash on evaluation board based
on w90p910 / NUC9xx.
config MTD_NAND_JZ4740
tristate "Support for JZ4740 SoC NAND controller"
depends on MACH_JZ4740
depends on MACH_JZ4740 || COMPILE_TEST
depends on HAS_IOMEM
help
Enables support for NAND Flash on JZ4740 SoC based boards.
Enables support for NAND Flash on JZ4740 SoC based boards.
config MTD_NAND_JZ4780
tristate "Support for NAND on JZ4780 SoC"
depends on MACH_JZ4780 && JZ4780_NEMC
depends on JZ4780_NEMC
help
Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
based boards, using the BCH controller for hardware error correction.
config MTD_NAND_FSMC
tristate "Support for NAND on ST Micros FSMC"
depends on OF
depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
depends on OF && HAS_IOMEM
depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300 || \
COMPILE_TEST
help
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
@ -506,19 +522,22 @@ config MTD_NAND_XWAY
config MTD_NAND_SUNXI
tristate "Support for NAND on Allwinner SoCs"
depends on ARCH_SUNXI
depends on ARCH_SUNXI || COMPILE_TEST
depends on HAS_IOMEM
help
Enables support for NAND Flash chips on Allwinner SoCs.
config MTD_NAND_HISI504
tristate "Support for NAND controller on Hisilicon SoC Hip04"
depends on ARCH_HISI || COMPILE_TEST
depends on HAS_IOMEM
help
Enables support for NAND controller on Hisilicon SoC Hip04.
config MTD_NAND_QCOM
tristate "Support for NAND on QCOM SoCs"
depends on ARCH_QCOM
depends on ARCH_QCOM || COMPILE_TEST
depends on HAS_IOMEM
help
Enables support for NAND flash chips on SoCs containing the EBI2 NAND
controller. This controller is found on IPQ806x SoC.
@ -526,8 +545,20 @@ config MTD_NAND_QCOM
config MTD_NAND_MTK
tristate "Support for NAND controller on MTK SoCs"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_IOMEM
help
Enables support for NAND controller on MTK SoCs.
This controller is found on mt27xx, mt81xx, mt65xx SoCs.
config MTD_NAND_TEGRA
tristate "Support for NAND controller on NVIDIA Tegra"
depends on ARCH_TEGRA || COMPILE_TEST
depends on HAS_IOMEM
help
Enables support for NAND flash controller on NVIDIA Tegra SoC.
The driver has been developed and tested on a Tegra 2 SoC. DMA
support, raw read/write page as well as HW ECC read/write page
is supported. Extra OOB bytes when using HW ECC are currently
not supported.
endif # MTD_NAND

View file

@ -56,6 +56,7 @@ obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_amd.o

View file

@ -52,7 +52,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/genalloc.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
@ -129,6 +128,11 @@
#define DEFAULT_TIMEOUT_MS 1000
#define MIN_DMA_LEN 128
static bool atmel_nand_avoid_dma __read_mostly;
MODULE_PARM_DESC(avoiddma, "Avoid using DMA");
module_param_named(avoiddma, atmel_nand_avoid_dma, bool, 0400);
enum atmel_nand_rb_type {
ATMEL_NAND_NO_RB,
ATMEL_NAND_NATIVE_RB,
@ -197,7 +201,7 @@ struct atmel_nand_controller_ops {
int (*remove)(struct atmel_nand_controller *nc);
void (*nand_init)(struct atmel_nand_controller *nc,
struct atmel_nand *nand);
int (*ecc_init)(struct atmel_nand *nand);
int (*ecc_init)(struct nand_chip *chip);
int (*setup_data_interface)(struct atmel_nand *nand, int csline,
const struct nand_data_interface *conf);
};
@ -211,7 +215,7 @@ struct atmel_nand_controller_caps {
};
struct atmel_nand_controller {
struct nand_hw_control base;
struct nand_controller base;
const struct atmel_nand_controller_caps *caps;
struct device *dev;
struct regmap *smc;
@ -222,7 +226,7 @@ struct atmel_nand_controller {
};
static inline struct atmel_nand_controller *
to_nand_controller(struct nand_hw_control *ctl)
to_nand_controller(struct nand_controller *ctl)
{
return container_of(ctl, struct atmel_nand_controller, base);
}
@ -234,7 +238,7 @@ struct atmel_smc_nand_controller {
};
static inline struct atmel_smc_nand_controller *
to_smc_nand_controller(struct nand_hw_control *ctl)
to_smc_nand_controller(struct nand_controller *ctl)
{
return container_of(to_nand_controller(ctl),
struct atmel_smc_nand_controller, base);
@ -258,7 +262,7 @@ struct atmel_hsmc_nand_controller {
};
static inline struct atmel_hsmc_nand_controller *
to_hsmc_nand_controller(struct nand_hw_control *ctl)
to_hsmc_nand_controller(struct nand_controller *ctl)
{
return container_of(to_nand_controller(ctl),
struct atmel_hsmc_nand_controller, base);
@ -1128,9 +1132,8 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
return 0;
}
static int atmel_nand_ecc_init(struct atmel_nand *nand)
static int atmel_nand_ecc_init(struct nand_chip *chip)
{
struct nand_chip *chip = &nand->base;
struct atmel_nand_controller *nc;
int ret;
@ -1165,12 +1168,11 @@ static int atmel_nand_ecc_init(struct atmel_nand *nand)
return 0;
}
static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip)
{
struct nand_chip *chip = &nand->base;
int ret;
ret = atmel_nand_ecc_init(nand);
ret = atmel_nand_ecc_init(chip);
if (ret)
return ret;
@ -1553,23 +1555,7 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
chip->select_chip = atmel_hsmc_nand_select_chip;
}
static int atmel_nand_detect(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand_controller *nc;
int ret;
nc = to_nand_controller(chip->controller);
ret = nand_scan_ident(mtd, nand->numcs, NULL);
if (ret)
dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
return ret;
}
static int atmel_nand_unregister(struct atmel_nand *nand)
static int atmel_nand_controller_remove_nand(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
@ -1585,60 +1571,6 @@ static int atmel_nand_unregister(struct atmel_nand *nand)
return 0;
}
static int atmel_nand_register(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand_controller *nc;
int ret;
nc = to_nand_controller(chip->controller);
if (nc->caps->legacy_of_bindings || !nc->dev->of_node) {
/*
* We keep the MTD name unchanged to avoid breaking platforms
* where the MTD cmdline parser is used and the bootloader
* has not been updated to use the new naming scheme.
*/
mtd->name = "atmel_nand";
} else if (!mtd->name) {
/*
* If the new bindings are used and the bootloader has not been
* updated to pass a new mtdparts parameter on the cmdline, you
* should define the following property in your nand node:
*
* label = "atmel_nand";
*
* This way, mtd->name will be set by the core when
* nand_set_flash_node() is called.
*/
mtd->name = devm_kasprintf(nc->dev, GFP_KERNEL,
"%s:nand.%d", dev_name(nc->dev),
nand->cs[0].id);
if (!mtd->name) {
dev_err(nc->dev, "Failed to allocate mtd->name\n");
return -ENOMEM;
}
}
ret = nand_scan_tail(mtd);
if (ret) {
dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
return ret;
}
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
nand_cleanup(chip);
return ret;
}
list_add_tail(&nand->node, &nc->chips);
return 0;
}
static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
struct device_node *np,
int reg_cells)
@ -1750,6 +1682,8 @@ static int
atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
/* No card inserted, skip this NAND. */
@ -1760,15 +1694,22 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
nc->caps->ops->nand_init(nc, nand);
ret = atmel_nand_detect(nand);
if (ret)
ret = nand_scan(mtd, nand->numcs);
if (ret) {
dev_err(nc->dev, "NAND scan failed: %d\n", ret);
return ret;
}
ret = nc->caps->ops->ecc_init(nand);
if (ret)
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
nand_cleanup(chip);
return ret;
}
return atmel_nand_register(nand);
list_add_tail(&nand->node, &nc->chips);
return 0;
}
static int
@ -1778,7 +1719,7 @@ atmel_nand_controller_remove_nands(struct atmel_nand_controller *nc)
int ret;
list_for_each_entry_safe(nand, tmp, &nc->chips, node) {
ret = atmel_nand_unregister(nand);
ret = atmel_nand_controller_remove_nand(nand);
if (ret)
return ret;
}
@ -1953,6 +1894,51 @@ static const struct of_device_id atmel_matrix_of_ids[] = {
{ /* sentinel */ },
};
static int atmel_nand_attach_chip(struct nand_chip *chip)
{
struct atmel_nand_controller *nc = to_nand_controller(chip->controller);
struct atmel_nand *nand = to_atmel_nand(chip);
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = nc->caps->ops->ecc_init(chip);
if (ret)
return ret;
if (nc->caps->legacy_of_bindings || !nc->dev->of_node) {
/*
* We keep the MTD name unchanged to avoid breaking platforms
* where the MTD cmdline parser is used and the bootloader
* has not been updated to use the new naming scheme.
*/
mtd->name = "atmel_nand";
} else if (!mtd->name) {
/*
* If the new bindings are used and the bootloader has not been
* updated to pass a new mtdparts parameter on the cmdline, you
* should define the following property in your nand node:
*
* label = "atmel_nand";
*
* This way, mtd->name will be set by the core when
* nand_set_flash_node() is called.
*/
mtd->name = devm_kasprintf(nc->dev, GFP_KERNEL,
"%s:nand.%d", dev_name(nc->dev),
nand->cs[0].id);
if (!mtd->name) {
dev_err(nc->dev, "Failed to allocate mtd->name\n");
return -ENOMEM;
}
}
return 0;
}
static const struct nand_controller_ops atmel_nand_controller_ops = {
.attach_chip = atmel_nand_attach_chip,
};
static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
struct platform_device *pdev,
const struct atmel_nand_controller_caps *caps)
@ -1961,7 +1947,8 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
struct device_node *np = dev->of_node;
int ret;
nand_hw_control_init(&nc->base);
nand_controller_init(&nc->base);
nc->base.ops = &atmel_nand_controller_ops;
INIT_LIST_HEAD(&nc->chips);
nc->dev = dev;
nc->caps = caps;
@ -1977,7 +1964,7 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
return ret;
}
if (nc->caps->has_dma) {
if (nc->caps->has_dma && !atmel_nand_avoid_dma) {
dma_cap_mask_t mask;
dma_cap_zero(mask);
@ -2045,7 +2032,7 @@ atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc)
return ret;
}
nc->ebi_csa_offs = (unsigned int)match->data;
nc->ebi_csa_offs = (uintptr_t)match->data;
/*
* The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1
@ -2214,9 +2201,9 @@ atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc)
return -ENOMEM;
}
nc->sram.virt = gen_pool_dma_alloc(nc->sram.pool,
ATMEL_NFC_SRAM_SIZE,
&nc->sram.dma);
nc->sram.virt = (void __iomem *)gen_pool_dma_alloc(nc->sram.pool,
ATMEL_NFC_SRAM_SIZE,
&nc->sram.dma);
if (!nc->sram.virt) {
dev_err(nc->base.dev,
"Could not allocate memory from the NFC SRAM pool\n");

View file

@ -8,7 +8,6 @@
*/
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/mtd/mtd.h>

View file

@ -114,7 +114,7 @@ enum {
struct brcmnand_controller {
struct device *dev;
struct nand_hw_control controller;
struct nand_controller controller;
void __iomem *nand_base;
void __iomem *nand_fc; /* flash cache */
void __iomem *flash_dma_base;
@ -2208,6 +2208,40 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
return 0;
}
static int brcmnand_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
int ret;
chip->options |= NAND_NO_SUBPAGE_WRITE;
/*
* Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
* to/from, and have nand_base pass us a bounce buffer instead, as
* needed.
*/
chip->options |= NAND_USE_BOUNCE_BUFFER;
if (chip->bbt_options & NAND_BBT_USE_FLASH)
chip->bbt_options |= NAND_BBT_NO_OOB;
if (brcmnand_setup_dev(host))
return -ENXIO;
chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
/* only use our internal HW threshold */
mtd->bitflip_threshold = 1;
ret = brcmstb_choose_ecc_layout(host);
return ret;
}
static const struct nand_controller_ops brcmnand_controller_ops = {
.attach_chip = brcmnand_attach_chip,
};
static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
{
struct brcmnand_controller *ctrl = host->ctrl;
@ -2267,33 +2301,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
nand_writereg(ctrl, cfg_offs,
nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
return ret;
chip->options |= NAND_NO_SUBPAGE_WRITE;
/*
* Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
* to/from, and have nand_base pass us a bounce buffer instead, as
* needed.
*/
chip->options |= NAND_USE_BOUNCE_BUFFER;
if (chip->bbt_options & NAND_BBT_USE_FLASH)
chip->bbt_options |= NAND_BBT_NO_OOB;
if (brcmnand_setup_dev(host))
return -ENXIO;
chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
/* only use our internal HW threshold */
mtd->bitflip_threshold = 1;
ret = brcmstb_choose_ecc_layout(host);
if (ret)
return ret;
ret = nand_scan_tail(mtd);
ret = nand_scan(mtd, 1);
if (ret)
return ret;
@ -2433,7 +2441,8 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
init_completion(&ctrl->done);
init_completion(&ctrl->dma_done);
nand_hw_control_init(&ctrl->controller);
nand_controller_init(&ctrl->controller);
ctrl->controller.ops = &brcmnand_controller_ops;
INIT_LIST_HEAD(&ctrl->host_list);
/* NAND register range */

View file

@ -67,6 +67,7 @@ struct cafe_priv {
int nr_data;
int data_pos;
int page_addr;
bool usedma;
dma_addr_t dmaaddr;
unsigned char *dmabuf;
};
@ -121,7 +122,7 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
if (usedma)
if (cafe->usedma)
memcpy(cafe->dmabuf + cafe->datalen, buf, len);
else
memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
@ -137,7 +138,7 @@ static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
if (usedma)
if (cafe->usedma)
memcpy(buf, cafe->dmabuf + cafe->datalen, len);
else
memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len);
@ -253,7 +254,7 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
/* NB: The datasheet lies -- we really should be subtracting 1 here */
cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN);
cafe_writel(cafe, 0x90000000, NAND_IRQ);
if (usedma && (ctl1 & (3<<25))) {
if (cafe->usedma && (ctl1 & (3<<25))) {
uint32_t dmactl = 0xc0000000 + cafe->datalen;
/* If WR or RD bits set, set up DMA */
if (ctl1 & (1<<26)) {
@ -345,11 +346,6 @@ static irqreturn_t cafe_nand_interrupt(int irq, void *id)
return IRQ_HANDLED;
}
static void cafe_nand_bug(struct mtd_info *mtd)
{
BUG();
}
static int cafe_nand_write_oob(struct mtd_info *mtd,
struct nand_chip *chip, int page)
{
@ -598,6 +594,76 @@ static int cafe_mul(int x)
return gf4096_mul(x, 0xe01);
}
static int cafe_nand_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct cafe_priv *cafe = nand_get_controller_data(chip);
int err = 0;
cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
&cafe->dmaaddr, GFP_KERNEL);
if (!cafe->dmabuf)
return -ENOMEM;
/* Set up DMA address */
cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
/* Restore the DMA flag */
cafe->usedma = usedma;
cafe->ctl2 = BIT(27); /* Reed-Solomon ECC */
if (mtd->writesize == 2048)
cafe->ctl2 |= BIT(29); /* 2KiB page size */
/* Set up ECC according to the type of chip we found */
mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
if (mtd->writesize == 2048) {
cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
} else if (mtd->writesize == 512) {
cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
} else {
dev_warn(&cafe->pdev->dev,
"Unexpected NAND flash writesize %d. Aborting\n",
mtd->writesize);
err = -ENOTSUPP;
goto out_free_dma;
}
cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
cafe->nand.ecc.size = mtd->writesize;
cafe->nand.ecc.bytes = 14;
cafe->nand.ecc.strength = 4;
cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
cafe->nand.ecc.write_oob = cafe_nand_write_oob;
cafe->nand.ecc.read_page = cafe_nand_read_page;
cafe->nand.ecc.read_oob = cafe_nand_read_oob;
return 0;
out_free_dma:
dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
return err;
}
static void cafe_nand_detach_chip(struct nand_chip *chip)
{
struct cafe_priv *cafe = nand_get_controller_data(chip);
dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
}
static const struct nand_controller_ops cafe_nand_controller_ops = {
.attach_chip = cafe_nand_attach_chip,
.detach_chip = cafe_nand_detach_chip,
};
static int cafe_nand_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@ -605,7 +671,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
struct cafe_priv *cafe;
uint32_t ctrl;
int err = 0;
int old_dma;
/* Very old versions shared the same PCI ident for all three
functions on the chip. Verify the class too... */
@ -713,65 +778,15 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe_readl(cafe, GLOBAL_CTRL),
cafe_readl(cafe, GLOBAL_IRQ_MASK));
/* Do not use the DMA for the nand_scan_ident() */
old_dma = usedma;
usedma = 0;
/* Do not use the DMA during the NAND identification */
cafe->usedma = 0;
/* Scan to find existence of the device */
err = nand_scan_ident(mtd, 2, NULL);
cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops;
err = nand_scan(mtd, 2);
if (err)
goto out_irq;
cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
&cafe->dmaaddr, GFP_KERNEL);
if (!cafe->dmabuf) {
err = -ENOMEM;
goto out_irq;
}
/* Set up DMA address */
cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
/* Restore the DMA flag */
usedma = old_dma;
cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
if (mtd->writesize == 2048)
cafe->ctl2 |= 1<<29; /* 2KiB page size */
/* Set up ECC according to the type of chip we found */
mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
if (mtd->writesize == 2048) {
cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
} else if (mtd->writesize == 512) {
cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
} else {
pr_warn("Unexpected NAND flash writesize %d. Aborting\n",
mtd->writesize);
goto out_free_dma;
}
cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
cafe->nand.ecc.size = mtd->writesize;
cafe->nand.ecc.bytes = 14;
cafe->nand.ecc.strength = 4;
cafe->nand.ecc.hwctl = (void *)cafe_nand_bug;
cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
cafe->nand.ecc.correct = (void *)cafe_nand_bug;
cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
cafe->nand.ecc.write_oob = cafe_nand_write_oob;
cafe->nand.ecc.read_page = cafe_nand_read_page;
cafe->nand.ecc.read_oob = cafe_nand_read_oob;
err = nand_scan_tail(mtd);
if (err)
goto out_free_dma;
pci_set_drvdata(pdev, mtd);
mtd->name = "cafe_nand";
@ -783,8 +798,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
out_cleanup_nand:
nand_cleanup(&cafe->nand);
out_free_dma:
dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
out_irq:
/* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);

View file

@ -200,8 +200,8 @@ static int __init cmx270_init(void)
}
/* Register the partitions */
ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL,
partition_info, NUM_PARTITIONS);
ret = mtd_device_register(cmx270_nand_mtd, partition_info,
NUM_PARTITIONS);
if (ret)
goto err_scan;

View file

@ -310,8 +310,7 @@ static int __init cs553x_init(void)
for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
if (cs553x_mtd[i]) {
/* If any devices registered, return success. Else the last error. */
mtd_device_parse_register(cs553x_mtd[i], NULL, NULL,
NULL, 0);
mtd_device_register(cs553x_mtd[i], NULL, 0);
err = 0;
}
}

View file

@ -53,15 +53,14 @@
struct davinci_nand_info {
struct nand_chip chip;
struct device *dev;
struct platform_device *pdev;
bool is_readmode;
void __iomem *base;
void __iomem *vaddr;
uint32_t ioaddr;
uint32_t current_cs;
void __iomem *current_cs;
uint32_t mask_chipsel;
uint32_t mask_ale;
@ -102,17 +101,17 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct davinci_nand_info *info = to_davinci_nand(mtd);
uint32_t addr = info->current_cs;
void __iomem *addr = info->current_cs;
struct nand_chip *nand = mtd_to_nand(mtd);
/* Did the control lines change? */
if (ctrl & NAND_CTRL_CHANGE) {
if ((ctrl & NAND_CTRL_CLE) == NAND_CTRL_CLE)
addr |= info->mask_cle;
addr += info->mask_cle;
else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
addr |= info->mask_ale;
addr += info->mask_ale;
nand->IO_ADDR_W = (void __iomem __force *)addr;
nand->IO_ADDR_W = addr;
}
if (cmd != NAND_CMD_NONE)
@ -122,14 +121,14 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
{
struct davinci_nand_info *info = to_davinci_nand(mtd);
uint32_t addr = info->ioaddr;
info->current_cs = info->vaddr;
/* maybe kick in a second chipselect */
if (chip > 0)
addr |= info->mask_chipsel;
info->current_cs = addr;
info->current_cs += info->mask_chipsel;
info->chip.IO_ADDR_W = (void __iomem __force *)addr;
info->chip.IO_ADDR_W = info->current_cs;
info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
}
@ -319,7 +318,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
/* Unpack ten bytes into eight 10 bit values. We know we're
* little-endian, and use type punning for less shifting/masking.
*/
if (WARN_ON(0x01 & (unsigned) ecc_code))
if (WARN_ON(0x01 & (uintptr_t)ecc_code))
return -EINVAL;
ecc16 = (unsigned short *)ecc_code;
@ -441,9 +440,9 @@ static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
else
ioread8_rep(chip->IO_ADDR_R, buf, len);
@ -454,9 +453,9 @@ static void nand_davinci_write_buf(struct mtd_info *mtd,
{
struct nand_chip *chip = mtd_to_nand(mtd);
if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
else
iowrite8_rep(chip->IO_ADDR_R, buf, len);
@ -606,6 +605,104 @@ static struct davinci_nand_pdata
}
#endif
static int davinci_nand_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct davinci_nand_info *info = to_davinci_nand(mtd);
struct davinci_nand_pdata *pdata = nand_davinci_get_pdata(info->pdev);
int ret = 0;
if (IS_ERR(pdata))
return PTR_ERR(pdata);
switch (info->chip.ecc.mode) {
case NAND_ECC_NONE:
pdata->ecc_bits = 0;
break;
case NAND_ECC_SOFT:
pdata->ecc_bits = 0;
/*
* This driver expects Hamming based ECC when ecc_mode is set
* to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
* avoid adding an extra ->ecc_algo field to
* davinci_nand_pdata.
*/
info->chip.ecc.algo = NAND_ECC_HAMMING;
break;
case NAND_ECC_HW:
if (pdata->ecc_bits == 4) {
/*
* No sanity checks: CPUs must support this,
* and the chips may not use NAND_BUSWIDTH_16.
*/
/* No sharing 4-bit hardware between chipselects yet */
spin_lock_irq(&davinci_nand_lock);
if (ecc4_busy)
ret = -EBUSY;
else
ecc4_busy = true;
spin_unlock_irq(&davinci_nand_lock);
if (ret == -EBUSY)
return ret;
info->chip.ecc.calculate = nand_davinci_calculate_4bit;
info->chip.ecc.correct = nand_davinci_correct_4bit;
info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
info->chip.ecc.bytes = 10;
info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
info->chip.ecc.algo = NAND_ECC_BCH;
} else {
/* 1bit ecc hamming */
info->chip.ecc.calculate = nand_davinci_calculate_1bit;
info->chip.ecc.correct = nand_davinci_correct_1bit;
info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
info->chip.ecc.bytes = 3;
info->chip.ecc.algo = NAND_ECC_HAMMING;
}
info->chip.ecc.size = 512;
info->chip.ecc.strength = pdata->ecc_bits;
break;
default:
return -EINVAL;
}
/*
* Update ECC layout if needed ... for 1-bit HW ECC, the default
* is OK, but it allocates 6 bytes when only 3 are needed (for
* each 512 bytes). For the 4-bit HW ECC, that default is not
* usable: 10 bytes are needed, not 6.
*/
if (pdata->ecc_bits == 4) {
int chunks = mtd->writesize / 512;
if (!chunks || mtd->oobsize < 16) {
dev_dbg(&info->pdev->dev, "too small\n");
return -EINVAL;
}
/* For small page chips, preserve the manufacturer's
* badblock marking data ... and make sure a flash BBT
* table marker fits in the free bytes.
*/
if (chunks == 1) {
mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
} else if (chunks == 4 || chunks == 8) {
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
} else {
return -EIO;
}
}
return ret;
}
static const struct nand_controller_ops davinci_nand_controller_ops = {
.attach_chip = davinci_nand_attach_chip,
};
static int nand_davinci_probe(struct platform_device *pdev)
{
struct davinci_nand_pdata *pdata;
@ -659,7 +756,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
return -EADDRNOTAVAIL;
}
info->dev = &pdev->dev;
info->pdev = pdev;
info->base = base;
info->vaddr = vaddr;
@ -680,9 +777,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->chip.bbt_md = pdata->bbt_md;
info->timing = pdata->timing;
info->ioaddr = (uint32_t __force) vaddr;
info->current_cs = info->ioaddr;
info->current_cs = info->vaddr;
info->core_chipsel = pdata->core_chipsel;
info->mask_chipsel = pdata->mask_chipsel;
@ -711,100 +806,15 @@ static int nand_davinci_probe(struct platform_device *pdev)
spin_unlock_irq(&davinci_nand_lock);
/* Scan to find existence of the device(s) */
ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1);
if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
return ret;
}
switch (info->chip.ecc.mode) {
case NAND_ECC_NONE:
pdata->ecc_bits = 0;
break;
case NAND_ECC_SOFT:
pdata->ecc_bits = 0;
/*
* This driver expects Hamming based ECC when ecc_mode is set
* to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
* avoid adding an extra ->ecc_algo field to
* davinci_nand_pdata.
*/
info->chip.ecc.algo = NAND_ECC_HAMMING;
break;
case NAND_ECC_HW:
if (pdata->ecc_bits == 4) {
/* No sanity checks: CPUs must support this,
* and the chips may not use NAND_BUSWIDTH_16.
*/
/* No sharing 4-bit hardware between chipselects yet */
spin_lock_irq(&davinci_nand_lock);
if (ecc4_busy)
ret = -EBUSY;
else
ecc4_busy = true;
spin_unlock_irq(&davinci_nand_lock);
if (ret == -EBUSY)
return ret;
info->chip.ecc.calculate = nand_davinci_calculate_4bit;
info->chip.ecc.correct = nand_davinci_correct_4bit;
info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;
info->chip.ecc.bytes = 10;
info->chip.ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
info->chip.ecc.algo = NAND_ECC_BCH;
} else {
/* 1bit ecc hamming */
info->chip.ecc.calculate = nand_davinci_calculate_1bit;
info->chip.ecc.correct = nand_davinci_correct_1bit;
info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;
info->chip.ecc.bytes = 3;
info->chip.ecc.algo = NAND_ECC_HAMMING;
}
info->chip.ecc.size = 512;
info->chip.ecc.strength = pdata->ecc_bits;
break;
default:
return -EINVAL;
}
/* Update ECC layout if needed ... for 1-bit HW ECC, the default
* is OK, but it allocates 6 bytes when only 3 are needed (for
* each 512 bytes). For the 4-bit HW ECC, that default is not
* usable: 10 bytes are needed, not 6.
*/
if (pdata->ecc_bits == 4) {
int chunks = mtd->writesize / 512;
if (!chunks || mtd->oobsize < 16) {
dev_dbg(&pdev->dev, "too small\n");
ret = -EINVAL;
goto err;
}
/* For small page chips, preserve the manufacturer's
* badblock marking data ... and make sure a flash BBT
* table marker fits in the free bytes.
*/
if (chunks == 1) {
mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
} else if (chunks == 4 || chunks == 8) {
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
} else {
ret = -EIO;
goto err;
}
}
ret = nand_scan_tail(mtd);
if (ret < 0)
goto err;
if (pdata->parts)
ret = mtd_device_parse_register(mtd, NULL, NULL,
pdata->parts, pdata->nr_parts);
ret = mtd_device_register(mtd, pdata->parts, pdata->nr_parts);
else
ret = mtd_device_register(mtd, NULL, 0);
if (ret < 0)
@ -819,11 +829,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
err_cleanup_nand:
nand_cleanup(&info->chip);
err:
spin_lock_irq(&davinci_nand_lock);
if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
ecc4_busy = false;
spin_unlock_irq(&davinci_nand_lock);
return ret;
}

View file

@ -51,14 +51,6 @@ MODULE_LICENSE("GPL");
#define DENALI_INVALID_BANK -1
#define DENALI_NR_BANKS 4
/*
* The bus interface clock, clk_x, is phase aligned with the core clock. The
* clk_x is an integral multiple N of the core clk. The value N is configured
* at IP delivery time, and its available value is 4, 5, or 6. We need to align
* to the largest value to make it work with any possible configuration.
*/
#define DENALI_CLK_X_MULT 6
static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
{
return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
@ -954,7 +946,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
const struct nand_sdr_timings *timings;
unsigned long t_clk;
unsigned long t_x, mult_x;
int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
int addr_2_data_mask;
@ -965,15 +957,24 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
return PTR_ERR(timings);
/* clk_x period in picoseconds */
t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
if (!t_clk)
t_x = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
if (!t_x)
return -EINVAL;
/*
* The bus interface clock, clk_x, is phase aligned with the core clock.
* The clk_x is an integral multiple N of the core clk. The value N is
* configured at IP delivery time, and its available value is 4, 5, 6.
*/
mult_x = DIV_ROUND_CLOSEST_ULL(denali->clk_x_rate, denali->clk_rate);
if (mult_x < 4 || mult_x > 6)
return -EINVAL;
if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
/* tREA -> ACC_CLKS */
acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
acc_clks = DIV_ROUND_UP(timings->tREA_max, t_x);
acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
tmp = ioread32(denali->reg + ACC_CLKS);
@ -982,7 +983,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
iowrite32(tmp, denali->reg + ACC_CLKS);
/* tRWH -> RE_2_WE */
re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_x);
re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
tmp = ioread32(denali->reg + RE_2_WE);
@ -991,7 +992,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
iowrite32(tmp, denali->reg + RE_2_WE);
/* tRHZ -> RE_2_RE */
re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_x);
re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
tmp = ioread32(denali->reg + RE_2_RE);
@ -1005,8 +1006,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
* With WE_2_RE properly set, the Denali controller automatically takes
* care of the delay; the driver need not set NAND_WAIT_TCCS.
*/
we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min),
t_clk);
we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min), t_x);
we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
@ -1021,7 +1021,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
if (denali->revision < 0x0501)
addr_2_data_mask >>= 1;
addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_x);
addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
@ -1031,7 +1031,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
/* tREH, tWH -> RDWR_EN_HI_CNT */
rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
t_clk);
t_x);
rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
@ -1040,11 +1040,10 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
/* tRP, tWP -> RDWR_EN_LO_CNT */
rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
t_clk);
rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), t_x);
rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
t_clk);
rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
t_x);
rdwr_en_lo_hi = max_t(int, rdwr_en_lo_hi, mult_x);
rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
@ -1054,8 +1053,8 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
/* tCS, tCEA -> CS_SETUP_CNT */
cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
(int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_x) - rdwr_en_lo,
(int)DIV_ROUND_UP(timings->tCEA_max, t_x) - acc_clks,
0);
cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
@ -1120,33 +1119,6 @@ int denali_calc_ecc_bytes(int step_size, int strength)
}
EXPORT_SYMBOL(denali_calc_ecc_bytes);
static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
struct denali_nand_info *denali)
{
int oobavail = mtd->oobsize - denali->oob_skip_bytes;
int ret;
/*
* If .size and .strength are already set (usually by DT),
* check if they are supported by this controller.
*/
if (chip->ecc.size && chip->ecc.strength)
return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
/*
* We want .size and .strength closest to the chip's requirement
* unless NAND_ECC_MAXIMIZE is requested.
*/
if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
if (!ret)
return 0;
}
/* Max ECC strength is the last thing we can do */
return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
}
static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
@ -1233,6 +1205,115 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
return 0;
}
static int denali_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
int ret;
if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
denali->dma_avail = 1;
if (denali->dma_avail) {
int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32;
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit));
if (ret) {
dev_info(denali->dev,
"Failed to set DMA mask. Disabling DMA.\n");
denali->dma_avail = 0;
}
}
if (denali->dma_avail) {
chip->options |= NAND_USE_BOUNCE_BUFFER;
chip->buf_align = 16;
if (denali->caps & DENALI_CAP_DMA_64BIT)
denali->setup_dma = denali_setup_dma64;
else
denali->setup_dma = denali_setup_dma32;
}
chip->bbt_options |= NAND_BBT_USE_FLASH;
chip->bbt_options |= NAND_BBT_NO_OOB;
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
chip->options |= NAND_NO_SUBPAGE_WRITE;
ret = nand_ecc_choose_conf(chip, denali->ecc_caps,
mtd->oobsize - denali->oob_skip_bytes);
if (ret) {
dev_err(denali->dev, "Failed to setup ECC settings.\n");
return ret;
}
dev_dbg(denali->dev,
"chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) |
FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength),
denali->reg + ECC_CORRECTION);
iowrite32(mtd->erasesize / mtd->writesize,
denali->reg + PAGES_PER_BLOCK);
iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
denali->reg + DEVICE_WIDTH);
iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG,
denali->reg + TWO_ROW_ADDR_CYCLES);
iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
/* chip->ecc.steps is set by nand_scan_tail(); not available here */
iowrite32(mtd->writesize / chip->ecc.size,
denali->reg + CFG_NUM_DATA_BLOCKS);
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
if (chip->options & NAND_BUSWIDTH_16) {
chip->read_buf = denali_read_buf16;
chip->write_buf = denali_write_buf16;
} else {
chip->read_buf = denali_read_buf;
chip->write_buf = denali_write_buf;
}
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)
return ret;
/*
* This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not
* use devm_kmalloc() because the memory allocated by devm_ does not
* guarantee DMA-safe alignment.
*/
denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
if (!denali->buf)
return -ENOMEM;
return 0;
}
static void denali_detach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
kfree(denali->buf);
}
static const struct nand_controller_ops denali_controller_ops = {
.attach_chip = denali_attach_chip,
.detach_chip = denali_detach_chip,
};
int denali_init(struct denali_nand_info *denali)
{
struct nand_chip *chip = &denali->nand;
@ -1282,116 +1363,24 @@ int denali_init(struct denali_nand_info *denali)
}
/* clk rate info is needed for setup_data_interface */
if (denali->clk_x_rate)
if (denali->clk_rate && denali->clk_x_rate)
chip->setup_data_interface = denali_setup_data_interface;
ret = nand_scan_ident(mtd, denali->max_banks, NULL);
chip->dummy_controller.ops = &denali_controller_ops;
ret = nand_scan(mtd, denali->max_banks);
if (ret)
goto disable_irq;
if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
denali->dma_avail = 1;
if (denali->dma_avail) {
int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32;
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit));
if (ret) {
dev_info(denali->dev,
"Failed to set DMA mask. Disabling DMA.\n");
denali->dma_avail = 0;
}
}
if (denali->dma_avail) {
chip->options |= NAND_USE_BOUNCE_BUFFER;
chip->buf_align = 16;
if (denali->caps & DENALI_CAP_DMA_64BIT)
denali->setup_dma = denali_setup_dma64;
else
denali->setup_dma = denali_setup_dma32;
}
chip->bbt_options |= NAND_BBT_USE_FLASH;
chip->bbt_options |= NAND_BBT_NO_OOB;
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
chip->options |= NAND_NO_SUBPAGE_WRITE;
ret = denali_ecc_setup(mtd, chip, denali);
if (ret) {
dev_err(denali->dev, "Failed to setup ECC settings.\n");
goto disable_irq;
}
dev_dbg(denali->dev,
"chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) |
FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength),
denali->reg + ECC_CORRECTION);
iowrite32(mtd->erasesize / mtd->writesize,
denali->reg + PAGES_PER_BLOCK);
iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
denali->reg + DEVICE_WIDTH);
iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG,
denali->reg + TWO_ROW_ADDR_CYCLES);
iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
/* chip->ecc.steps is set by nand_scan_tail(); not available here */
iowrite32(mtd->writesize / chip->ecc.size,
denali->reg + CFG_NUM_DATA_BLOCKS);
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
if (chip->options & NAND_BUSWIDTH_16) {
chip->read_buf = denali_read_buf16;
chip->write_buf = denali_write_buf16;
} else {
chip->read_buf = denali_read_buf;
chip->write_buf = denali_write_buf;
}
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 disable_irq;
/*
* This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not
* use devm_kmalloc() because the memory allocated by devm_ does not
* guarantee DMA-safe alignment.
*/
denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
if (!denali->buf) {
ret = -ENOMEM;
goto disable_irq;
}
ret = nand_scan_tail(mtd);
if (ret)
goto free_buf;
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
goto cleanup_nand;
}
return 0;
cleanup_nand:
nand_cleanup(chip);
free_buf:
kfree(denali->buf);
disable_irq:
denali_disable_irq(denali);
@ -1404,7 +1393,6 @@ void denali_remove(struct denali_nand_info *denali)
struct mtd_info *mtd = nand_to_mtd(&denali->nand);
nand_release(mtd);
kfree(denali->buf);
denali_disable_irq(denali);
}
EXPORT_SYMBOL(denali_remove);

View file

@ -300,6 +300,7 @@
struct denali_nand_info {
struct nand_chip nand;
unsigned long clk_rate; /* core clock rate */
unsigned long clk_x_rate; /* bus interface clock rate */
int active_bank; /* currently selected bank */
struct device *dev;

View file

@ -27,7 +27,9 @@
struct denali_dt {
struct denali_nand_info denali;
struct clk *clk;
struct clk *clk; /* core clock */
struct clk *clk_x; /* bus interface clock */
struct clk *clk_ecc; /* ECC circuit clock */
};
struct denali_dt_data {
@ -79,63 +81,99 @@ MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
static int denali_dt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct denali_dt *dt;
const struct denali_dt_data *data;
struct denali_nand_info *denali;
int ret;
dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL);
if (!dt)
return -ENOMEM;
denali = &dt->denali;
data = of_device_get_match_data(&pdev->dev);
data = of_device_get_match_data(dev);
if (data) {
denali->revision = data->revision;
denali->caps = data->caps;
denali->ecc_caps = data->ecc_caps;
}
denali->dev = &pdev->dev;
denali->dev = dev;
denali->irq = platform_get_irq(pdev, 0);
if (denali->irq < 0) {
dev_err(&pdev->dev, "no irq defined\n");
dev_err(dev, "no irq defined\n");
return denali->irq;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
denali->reg = devm_ioremap_resource(&pdev->dev, res);
denali->reg = devm_ioremap_resource(dev, res);
if (IS_ERR(denali->reg))
return PTR_ERR(denali->reg);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
denali->host = devm_ioremap_resource(&pdev->dev, res);
denali->host = devm_ioremap_resource(dev, res);
if (IS_ERR(denali->host))
return PTR_ERR(denali->host);
dt->clk = devm_clk_get(&pdev->dev, NULL);
/*
* A single anonymous clock is supported for the backward compatibility.
* New platforms should support all the named clocks.
*/
dt->clk = devm_clk_get(dev, "nand");
if (IS_ERR(dt->clk))
dt->clk = devm_clk_get(dev, NULL);
if (IS_ERR(dt->clk)) {
dev_err(&pdev->dev, "no clk available\n");
dev_err(dev, "no clk available\n");
return PTR_ERR(dt->clk);
}
dt->clk_x = devm_clk_get(dev, "nand_x");
if (IS_ERR(dt->clk_x))
dt->clk_x = NULL;
dt->clk_ecc = devm_clk_get(dev, "ecc");
if (IS_ERR(dt->clk_ecc))
dt->clk_ecc = NULL;
ret = clk_prepare_enable(dt->clk);
if (ret)
return ret;
/*
* Hardcode the clock rate for the backward compatibility.
* This works for both SOCFPGA and UniPhier.
*/
denali->clk_x_rate = 200000000;
ret = clk_prepare_enable(dt->clk_x);
if (ret)
goto out_disable_clk;
ret = clk_prepare_enable(dt->clk_ecc);
if (ret)
goto out_disable_clk_x;
if (dt->clk_x) {
denali->clk_rate = clk_get_rate(dt->clk);
denali->clk_x_rate = clk_get_rate(dt->clk_x);
} else {
/*
* Hardcode the clock rates for the backward compatibility.
* This works for both SOCFPGA and UniPhier.
*/
dev_notice(dev,
"necessary clock is missing. default clock rates are used.\n");
denali->clk_rate = 50000000;
denali->clk_x_rate = 200000000;
}
ret = denali_init(denali);
if (ret)
goto out_disable_clk;
goto out_disable_clk_ecc;
platform_set_drvdata(pdev, dt);
return 0;
out_disable_clk_ecc:
clk_disable_unprepare(dt->clk_ecc);
out_disable_clk_x:
clk_disable_unprepare(dt->clk_x);
out_disable_clk:
clk_disable_unprepare(dt->clk);
@ -147,6 +185,8 @@ static int denali_dt_remove(struct platform_device *pdev)
struct denali_dt *dt = platform_get_drvdata(pdev);
denali_remove(&dt->denali);
clk_disable_unprepare(dt->clk_ecc);
clk_disable_unprepare(dt->clk_x);
clk_disable_unprepare(dt->clk);
return 0;

View file

@ -73,6 +73,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
denali->irq = dev->irq;
denali->ecc_caps = &denali_pci_ecc_caps;
denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
denali->clk_rate = 50000000; /* 50 MHz */
denali->clk_x_rate = 200000000; /* 200 MHz */
ret = pci_request_regions(dev, DENALI_NAND_NAME);

View file

@ -1291,7 +1291,7 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
this->bbt_md = NULL;
}
ret = this->scan_bbt(mtd);
ret = nand_create_bbt(this);
if (ret)
return ret;
@ -1338,7 +1338,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
this->bbt_md->pattern = "TBB_SYSM";
}
ret = this->scan_bbt(mtd);
ret = nand_create_bbt(this);
if (ret)
return ret;

View file

@ -1227,10 +1227,9 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
* required within a nand driver because they are performed by the nand
* infrastructure code as part of nand_scan(). In this case they need
* to be initialized here because we skip call to nand_scan_ident() (the
* first half of nand_scan()). The call to nand_scan_ident() is skipped
* because for this device the chip id is not read in the manner of a
* standard nand device. Unfortunately, nand_scan_ident() does other
* things as well, such as call nand_set_defaults().
* first half of nand_scan()). The call to nand_scan_ident() could be
* skipped because for this device the chip id is not read in the manner
* of a standard nand device.
*/
struct nand_chip *nand = mtd_to_nand(mtd);
@ -1257,8 +1256,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->ecc.strength = DOCG4_T;
nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
nand->controller = &nand->hwcontrol;
nand_hw_control_init(nand->controller);
nand->controller = &nand->dummy_controller;
nand_controller_init(nand->controller);
/* methods */
nand->cmdfunc = docg4_command;
@ -1315,6 +1314,40 @@ static int __init read_id_reg(struct mtd_info *mtd)
static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
static int docg4_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
int ret;
init_mtd_structs(mtd);
/* Initialize kernel BCH algorithm */
doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
if (!doc->bch)
return -EINVAL;
reset(mtd);
ret = read_id_reg(mtd);
if (ret)
free_bch(doc->bch);
return ret;
}
static void docg4_detach_chip(struct nand_chip *chip)
{
struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
free_bch(doc->bch);
}
static const struct nand_controller_ops docg4_controller_ops = {
.attach_chip = docg4_attach_chip,
.detach_chip = docg4_detach_chip,
};
static int __init probe_docg4(struct platform_device *pdev)
{
struct mtd_info *mtd;
@ -1341,7 +1374,7 @@ static int __init probe_docg4(struct platform_device *pdev)
nand = kzalloc(len, GFP_KERNEL);
if (nand == NULL) {
retval = -ENOMEM;
goto fail_unmap;
goto unmap;
}
mtd = nand_to_mtd(nand);
@ -1350,46 +1383,35 @@ static int __init probe_docg4(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
doc->virtadr = virtadr;
doc->dev = dev;
init_mtd_structs(mtd);
/* initialize kernel bch algorithm */
doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
if (doc->bch == NULL) {
retval = -EINVAL;
goto fail;
}
platform_set_drvdata(pdev, doc);
reset(mtd);
retval = read_id_reg(mtd);
if (retval == -ENODEV) {
dev_warn(dev, "No diskonchip G4 device found.\n");
goto fail;
}
retval = nand_scan_tail(mtd);
/*
* Running nand_scan() with maxchips == 0 will skip nand_scan_ident(),
* which is a specific operation with this driver and done in the
* ->attach_chip callback.
*/
nand->dummy_controller.ops = &docg4_controller_ops;
retval = nand_scan(mtd, 0);
if (retval)
goto fail;
goto free_nand;
retval = read_factory_bbt(mtd);
if (retval)
goto fail;
goto cleanup_nand;
retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
if (retval)
goto fail;
goto cleanup_nand;
doc->mtd = mtd;
return 0;
fail:
nand_release(mtd); /* deletes partitions and mtd devices */
free_bch(doc->bch);
cleanup_nand:
nand_cleanup(nand);
free_nand:
kfree(nand);
fail_unmap:
unmap:
iounmap(virtadr);
return retval;
@ -1399,7 +1421,6 @@ static int __exit cleanup_docg4(struct platform_device *pdev)
{
struct docg4_priv *doc = platform_get_drvdata(pdev);
nand_release(doc->mtd);
free_bch(doc->bch);
kfree(mtd_to_nand(doc->mtd));
iounmap(doc->virtadr);
return 0;

View file

@ -61,7 +61,7 @@ struct fsl_elbc_mtd {
/* Freescale eLBC FCM controller information */
struct fsl_elbc_fcm_ctrl {
struct nand_hw_control controller;
struct nand_controller controller;
struct fsl_elbc_mtd *chips[MAX_BANKS];
u8 __iomem *addr; /* Address of assigned FCM buffer */
@ -637,9 +637,9 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
}
static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
static int fsl_elbc_attach_chip(struct nand_chip *chip)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@ -700,12 +700,16 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
dev_err(priv->dev,
"fsl_elbc_init: page size %d is not supported\n",
mtd->writesize);
return -1;
return -ENOTSUPP;
}
return 0;
}
static const struct nand_controller_ops fsl_elbc_controller_ops = {
.attach_chip = fsl_elbc_attach_chip,
};
static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
@ -879,7 +883,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
}
elbc_fcm_ctrl->counter++;
nand_hw_control_init(&elbc_fcm_ctrl->controller);
nand_controller_init(&elbc_fcm_ctrl->controller);
fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
} else {
elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
@ -910,15 +914,8 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
if (ret)
goto err;
ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
goto err;
ret = fsl_elbc_chip_init_tail(mtd);
if (ret)
goto err;
ret = nand_scan_tail(mtd);
priv->chip.controller->ops = &fsl_elbc_controller_ops;
ret = nand_scan(mtd, 1);
if (ret)
goto err;

View file

@ -51,7 +51,7 @@ struct fsl_ifc_mtd {
/* overview of the fsl ifc controller */
struct fsl_ifc_nand_ctrl {
struct nand_hw_control controller;
struct nand_controller controller;
struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
void __iomem *addr; /* Address of assigned IFC buffer */
@ -225,7 +225,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
int bufnum = nctrl->page & priv->bufnum_mask;
int sector_start = bufnum * chip->ecc.steps;
int sector_end = sector_start + chip->ecc.steps - 1;
__be32 *eccstat_regs;
__be32 __iomem *eccstat_regs;
eccstat_regs = ifc->ifc_nand.nand_eccstat;
eccstat = ifc_in32(&eccstat_regs[sector_start / 4]);
@ -714,9 +714,9 @@ static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
static int fsl_ifc_attach_chip(struct nand_chip *chip)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
@ -757,6 +757,10 @@ static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
return 0;
}
static const struct nand_controller_ops fsl_ifc_controller_ops = {
.attach_chip = fsl_ifc_attach_chip,
};
static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
{
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
@ -1004,7 +1008,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
ifc_nand_ctrl->addr = NULL;
fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
nand_hw_control_init(&ifc_nand_ctrl->controller);
nand_controller_init(&ifc_nand_ctrl->controller);
} else {
ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
}
@ -1046,15 +1050,8 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
if (ret)
goto err;
ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
goto err;
ret = fsl_ifc_chip_init_tail(mtd);
if (ret)
goto err;
ret = nand_scan_tail(mtd);
priv->chip.controller->ops = &fsl_ifc_controller_ops;
ret = nand_scan(mtd, 1);
if (ret)
goto err;

View file

@ -62,7 +62,7 @@
reg)
/* fsmc controller registers for NAND flash */
#define PC 0x00
#define FSMC_PC 0x00
/* pc register definitions */
#define FSMC_RESET (1 << 0)
#define FSMC_WAITON (1 << 1)
@ -273,12 +273,13 @@ static void fsmc_nand_setup(struct fsmc_nand_data *host,
tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
if (host->nand.options & NAND_BUSWIDTH_16)
writel_relaxed(value | FSMC_DEVWID_16, host->regs_va + PC);
writel_relaxed(value | FSMC_DEVWID_16,
host->regs_va + FSMC_PC);
else
writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + PC);
writel_relaxed(value | FSMC_DEVWID_8, host->regs_va + FSMC_PC);
writel_relaxed(readl(host->regs_va + PC) | tclr | tar,
host->regs_va + PC);
writel_relaxed(readl(host->regs_va + FSMC_PC) | tclr | tar,
host->regs_va + FSMC_PC);
writel_relaxed(thiz | thold | twait | tset, host->regs_va + COMM);
writel_relaxed(thiz | thold | twait | tset, host->regs_va + ATTRIB);
}
@ -371,12 +372,12 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCPLEN_256,
host->regs_va + PC);
writel_relaxed(readl(host->regs_va + PC) & ~FSMC_ECCEN,
host->regs_va + PC);
writel_relaxed(readl(host->regs_va + PC) | FSMC_ECCEN,
host->regs_va + PC);
writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCPLEN_256,
host->regs_va + FSMC_PC);
writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCEN,
host->regs_va + FSMC_PC);
writel_relaxed(readl(host->regs_va + FSMC_PC) | FSMC_ECCEN,
host->regs_va + FSMC_PC);
}
/*
@ -546,7 +547,7 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
int i;
if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
if (IS_ALIGNED((uintptr_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
@ -569,7 +570,7 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
int i;
if (IS_ALIGNED((uint32_t)buf, sizeof(uint32_t)) &&
if (IS_ALIGNED((uintptr_t)buf, sizeof(uint32_t)) &&
IS_ALIGNED(len, sizeof(uint32_t))) {
uint32_t *p = (uint32_t *)buf;
len = len >> 2;
@ -618,11 +619,11 @@ static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
if (chipnr > 0)
return;
pc = readl(host->regs_va + PC);
pc = readl(host->regs_va + FSMC_PC);
if (chipnr < 0)
writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + PC);
writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + FSMC_PC);
else
writel_relaxed(pc | FSMC_ENABLE, host->regs_va + PC);
writel_relaxed(pc | FSMC_ENABLE, host->regs_va + FSMC_PC);
/* nCE line must be asserted before starting any operation */
mb();
@ -740,7 +741,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
nand_read_page_op(chip, page, s * eccsize, NULL, 0);
chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize);
nand_read_data_op(chip, p, eccsize, false);
for (j = 0; j < eccbytes;) {
struct mtd_oob_region oobregion;
@ -918,6 +919,82 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
return 0;
}
static int fsmc_nand_attach_chip(struct nand_chip *nand)
{
struct mtd_info *mtd = nand_to_mtd(nand);
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
if (AMBA_REV_BITS(host->pid) >= 8) {
switch (mtd->oobsize) {
case 16:
case 64:
case 128:
case 224:
case 256:
break;
default:
dev_warn(host->dev,
"No oob scheme defined for oobsize %d\n",
mtd->oobsize);
return -EINVAL;
}
mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
return 0;
}
switch (nand->ecc.mode) {
case NAND_ECC_HW:
dev_info(host->dev, "Using 1-bit HW ECC scheme\n");
nand->ecc.calculate = fsmc_read_hwecc_ecc1;
nand->ecc.correct = nand_correct_data;
nand->ecc.bytes = 3;
nand->ecc.strength = 1;
break;
case NAND_ECC_SOFT:
if (nand->ecc.algo == NAND_ECC_BCH) {
dev_info(host->dev,
"Using 4-bit SW BCH ECC scheme\n");
break;
}
case NAND_ECC_ON_DIE:
break;
default:
dev_err(host->dev, "Unsupported ECC mode!\n");
return -ENOTSUPP;
}
/*
* Don't set layout for BCH4 SW ECC. This will be
* generated later in nand_bch_init() later.
*/
if (nand->ecc.mode == NAND_ECC_HW) {
switch (mtd->oobsize) {
case 16:
case 64:
case 128:
mtd_set_ooblayout(mtd,
&fsmc_ecc1_ooblayout_ops);
break;
default:
dev_warn(host->dev,
"No oob scheme defined for oobsize %d\n",
mtd->oobsize);
return -EINVAL;
}
}
return 0;
}
static const struct nand_controller_ops fsmc_nand_controller_ops = {
.attach_chip = fsmc_nand_attach_chip,
};
/*
* fsmc_nand_probe - Probe function
* @pdev: platform device structure
@ -1047,76 +1124,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
/*
* Scan to find existence of the device
*/
ret = nand_scan_ident(mtd, 1, NULL);
if (ret) {
dev_err(&pdev->dev, "No NAND Device found!\n");
goto release_dma_write_chan;
}
if (AMBA_REV_BITS(host->pid) >= 8) {
switch (mtd->oobsize) {
case 16:
case 64:
case 128:
case 224:
case 256:
break;
default:
dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
mtd->oobsize);
ret = -EINVAL;
goto release_dma_write_chan;
}
mtd_set_ooblayout(mtd, &fsmc_ecc4_ooblayout_ops);
} else {
switch (nand->ecc.mode) {
case NAND_ECC_HW:
dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n");
nand->ecc.calculate = fsmc_read_hwecc_ecc1;
nand->ecc.correct = nand_correct_data;
nand->ecc.bytes = 3;
nand->ecc.strength = 1;
break;
case NAND_ECC_SOFT:
if (nand->ecc.algo == NAND_ECC_BCH) {
dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n");
break;
}
case NAND_ECC_ON_DIE:
break;
default:
dev_err(&pdev->dev, "Unsupported ECC mode!\n");
goto release_dma_write_chan;
}
/*
* Don't set layout for BCH4 SW ECC. This will be
* generated later in nand_bch_init() later.
*/
if (nand->ecc.mode == NAND_ECC_HW) {
switch (mtd->oobsize) {
case 16:
case 64:
case 128:
mtd_set_ooblayout(mtd,
&fsmc_ecc1_ooblayout_ops);
break;
default:
dev_warn(&pdev->dev,
"No oob scheme defined for oobsize %d\n",
mtd->oobsize);
ret = -EINVAL;
goto release_dma_write_chan;
}
}
}
/* Second stage of scan to fill MTD data-structures */
ret = nand_scan_tail(mtd);
nand->dummy_controller.ops = &fsmc_nand_controller_ops;
ret = nand_scan(mtd, 1);
if (ret)
goto release_dma_write_chan;

View file

@ -1,22 +1,9 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale GPMI NAND Flash Driver
*
* Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
* Copyright (C) 2008 Embedded Alley Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/delay.h>
#include <linux/clk.h>

View file

@ -1,22 +1,9 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale GPMI NAND Flash Driver
*
* Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
* Copyright (C) 2008 Embedded Alley Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/clk.h>
#include <linux/slab.h>
@ -757,9 +744,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
* [2] Allocate a read/write data buffer.
* The gpmi_alloc_dma_buffer can be called twice.
* We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
* is called before the nand_scan_ident; and we allocate a buffer
* of the real NAND page size when the gpmi_alloc_dma_buffer is
* called after the nand_scan_ident.
* is called before the NAND identification; and we allocate a
* buffer of the real NAND page size when the gpmi_alloc_dma_buffer
* is called after.
*/
this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
GFP_DMA | GFP_KERNEL);
@ -957,7 +944,6 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
struct mtd_info *mtd = nand_to_mtd(chip);
void *payload_virt;
dma_addr_t payload_phys;
unsigned int i;
unsigned char *status;
@ -967,7 +953,6 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
dev_dbg(this->dev, "page number is : %d\n", page);
payload_virt = this->payload_virt;
payload_phys = this->payload_phys;
if (virt_addr_valid(buf)) {
@ -976,7 +961,6 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
dest_phys = dma_map_single(this->dev, buf, nfc_geo->payload_size,
DMA_FROM_DEVICE);
if (!dma_mapping_error(this->dev, dest_phys)) {
payload_virt = buf;
payload_phys = dest_phys;
direct = true;
}
@ -1881,6 +1865,34 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
return 0;
}
static int gpmi_nand_attach_chip(struct nand_chip *chip)
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret;
if (chip->bbt_options & NAND_BBT_USE_FLASH) {
chip->bbt_options |= NAND_BBT_NO_OOB;
if (of_property_read_bool(this->dev->of_node,
"fsl,no-blockmark-swap"))
this->swap_block_mark = false;
}
dev_dbg(this->dev, "Blockmark swapping %sabled\n",
this->swap_block_mark ? "en" : "dis");
ret = gpmi_init_last(this);
if (ret)
return ret;
chip->options |= NAND_SKIP_BBTSCAN;
return 0;
}
static const struct nand_controller_ops gpmi_nand_controller_ops = {
.attach_chip = gpmi_nand_attach_chip,
};
static int gpmi_nand_init(struct gpmi_nand_data *this)
{
struct nand_chip *chip = &this->nand;
@ -1921,33 +1933,15 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
if (ret)
goto err_out;
if (chip->bbt_options & NAND_BBT_USE_FLASH) {
chip->bbt_options |= NAND_BBT_NO_OOB;
if (of_property_read_bool(this->dev->of_node,
"fsl,no-blockmark-swap"))
this->swap_block_mark = false;
}
dev_dbg(this->dev, "Blockmark swapping %sabled\n",
this->swap_block_mark ? "en" : "dis");
ret = gpmi_init_last(this);
if (ret)
goto err_out;
chip->options |= NAND_SKIP_BBTSCAN;
ret = nand_scan_tail(mtd);
chip->dummy_controller.ops = &gpmi_nand_controller_ops;
ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1);
if (ret)
goto err_out;
ret = nand_boot_init(this);
if (ret)
goto err_nand_cleanup;
ret = chip->scan_bbt(mtd);
ret = nand_create_bbt(chip);
if (ret)
goto err_nand_cleanup;

View file

@ -1,18 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Freescale GPMI NAND Flash Driver
*
* Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
* Copyright (C) 2008 Embedded Alley Solutions, Inc.
*
* 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.
*/
#ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H
#define __DRIVERS_MTD_NAND_GPMI_NAND_H

View file

@ -709,9 +709,50 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
return 0;
}
static int hisi_nfc_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct hinfc_host *host = nand_get_controller_data(chip);
int flag;
host->buffer = dmam_alloc_coherent(host->dev,
mtd->writesize + mtd->oobsize,
&host->dma_buffer, GFP_KERNEL);
if (!host->buffer)
return -ENOMEM;
host->dma_oob = host->dma_buffer + mtd->writesize;
memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
flag = hinfc_read(host, HINFC504_CON);
flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
switch (mtd->writesize) {
case 2048:
flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT);
break;
/*
* TODO: add more pagesize support,
* default pagesize has been set in hisi_nfc_host_init
*/
default:
dev_err(host->dev, "NON-2KB page size nand flash\n");
return -EINVAL;
}
hinfc_write(host, flag, HINFC504_CON);
if (chip->ecc.mode == NAND_ECC_HW)
hisi_nfc_ecc_probe(host);
return 0;
}
static const struct nand_controller_ops hisi_nfc_controller_ops = {
.attach_chip = hisi_nfc_attach_chip,
};
static int hisi_nfc_probe(struct platform_device *pdev)
{
int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
int ret = 0, irq, max_chips = HINFC504_MAX_CHIP;
struct device *dev = &pdev->dev;
struct hinfc_host *host;
struct nand_chip *chip;
@ -769,42 +810,11 @@ static int hisi_nfc_probe(struct platform_device *pdev)
return ret;
}
ret = nand_scan_ident(mtd, max_chips, NULL);
chip->dummy_controller.ops = &hisi_nfc_controller_ops;
ret = nand_scan(mtd, max_chips);
if (ret)
return ret;
host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
&host->dma_buffer, GFP_KERNEL);
if (!host->buffer)
return -ENOMEM;
host->dma_oob = host->dma_buffer + mtd->writesize;
memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
flag = hinfc_read(host, HINFC504_CON);
flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
switch (mtd->writesize) {
case 2048:
flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
/*
* TODO: add more pagesize support,
* default pagesize has been set in hisi_nfc_host_init
*/
default:
dev_err(dev, "NON-2KB page size nand flash\n");
return -EINVAL;
}
hinfc_write(host, flag, HINFC504_CON);
if (chip->ecc.mode == NAND_ECC_HW)
hisi_nfc_ecc_probe(host);
ret = nand_scan_tail(mtd);
if (ret) {
dev_err(dev, "nand_scan_tail failed: %d\n", ret);
return ret;
}
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "Err MTD partition=%d\n", ret);

View file

@ -13,6 +13,7 @@
*
*/
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
@ -23,9 +24,9 @@
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <asm/mach-jz4740/jz4740_nand.h>
#include <linux/platform_data/jz4740/jz4740_nand.h>
#define JZ_REG_NAND_CTRL 0x50
#define JZ_REG_NAND_ECC_CTRL 0x100
@ -330,7 +331,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
if (chipnr == 0) {
/* Detect first chip. */
ret = nand_scan_ident(mtd, 1, NULL);
ret = nand_scan(mtd, 1);
if (ret)
goto notfound_id;
@ -355,7 +356,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
mtd->size += chip->chipsize;
}
dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank);
dev_info(&pdev->dev, "Found chip %zu on bank %i\n", chipnr, bank);
return 0;
notfound_id:
@ -367,6 +368,24 @@ notfound_id:
return ret;
}
static int jz_nand_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct device *dev = mtd->dev.parent;
struct jz_nand_platform_data *pdata = dev_get_platdata(dev);
struct platform_device *pdev = to_platform_device(dev);
if (pdata && pdata->ident_callback)
pdata->ident_callback(pdev, mtd, &pdata->partitions,
&pdata->num_partitions);
return 0;
}
static const struct nand_controller_ops jz_nand_controller_ops = {
.attach_chip = jz_nand_attach_chip,
};
static int jz_nand_probe(struct platform_device *pdev)
{
int ret;
@ -410,6 +429,7 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->chip_delay = 50;
chip->cmd_ctrl = jz_nand_cmd_ctrl;
chip->select_chip = jz_nand_select_chip;
chip->dummy_controller.ops = &jz_nand_controller_ops;
if (nand->busy_gpio)
chip->dev_ready = jz_nand_dev_ready;
@ -455,33 +475,20 @@ static int jz_nand_probe(struct platform_device *pdev)
goto err_iounmap_mmio;
}
if (pdata && pdata->ident_callback) {
pdata->ident_callback(pdev, mtd, &pdata->partitions,
&pdata->num_partitions);
}
ret = nand_scan_tail(mtd);
if (ret) {
dev_err(&pdev->dev, "Failed to scan NAND\n");
goto err_unclaim_banks;
}
ret = mtd_device_parse_register(mtd, NULL, NULL,
pdata ? pdata->partitions : NULL,
pdata ? pdata->num_partitions : 0);
ret = mtd_device_register(mtd, pdata ? pdata->partitions : NULL,
pdata ? pdata->num_partitions : 0);
if (ret) {
dev_err(&pdev->dev, "Failed to add mtd device\n");
goto err_nand_release;
goto err_cleanup_nand;
}
dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
return 0;
err_nand_release:
nand_release(mtd);
err_unclaim_banks:
err_cleanup_nand:
nand_cleanup(chip);
while (chipnr--) {
unsigned char bank = nand->banks[chipnr];
jz_nand_iounmap_resource(nand->bank_mem[bank - 1],

View file

@ -44,7 +44,7 @@ struct jz4780_nand_cs {
struct jz4780_nand_controller {
struct device *dev;
struct jz4780_bch *bch;
struct nand_hw_control controller;
struct nand_controller controller;
unsigned int num_banks;
struct list_head chips;
int selected;
@ -65,7 +65,8 @@ static inline struct jz4780_nand_chip *to_jz4780_nand_chip(struct mtd_info *mtd)
return container_of(mtd_to_nand(mtd), struct jz4780_nand_chip, chip);
}
static inline struct jz4780_nand_controller *to_jz4780_nand_controller(struct nand_hw_control *ctrl)
static inline struct jz4780_nand_controller
*to_jz4780_nand_controller(struct nand_controller *ctrl)
{
return container_of(ctrl, struct jz4780_nand_controller, controller);
}
@ -157,9 +158,8 @@ static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
return jz4780_bch_correct(nfc->bch, &params, dat, read_ecc);
}
static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *dev)
static int jz4780_nand_attach_chip(struct nand_chip *chip)
{
struct nand_chip *chip = &nand->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
int eccbytes;
@ -170,7 +170,8 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
switch (chip->ecc.mode) {
case NAND_ECC_HW:
if (!nfc->bch) {
dev_err(dev, "HW BCH selected, but BCH controller not found\n");
dev_err(nfc->dev,
"HW BCH selected, but BCH controller not found\n");
return -ENODEV;
}
@ -179,15 +180,16 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
chip->ecc.correct = jz4780_nand_ecc_correct;
/* fall through */
case NAND_ECC_SOFT:
dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
(nfc->bch) ? "hardware BCH" : "software ECC",
chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n",
(nfc->bch) ? "hardware BCH" : "software ECC",
chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
break;
case NAND_ECC_NONE:
dev_info(dev, "not using ECC\n");
dev_info(nfc->dev, "not using ECC\n");
break;
default:
dev_err(dev, "ECC mode %d not supported\n", chip->ecc.mode);
dev_err(nfc->dev, "ECC mode %d not supported\n",
chip->ecc.mode);
return -EINVAL;
}
@ -199,7 +201,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
if (eccbytes > mtd->oobsize - 2) {
dev_err(dev,
dev_err(nfc->dev,
"invalid ECC config: required %d ECC bytes, but only %d are available",
eccbytes, mtd->oobsize - 2);
return -EINVAL;
@ -210,6 +212,10 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
return 0;
}
static const struct nand_controller_ops jz4780_nand_controller_ops = {
.attach_chip = jz4780_nand_attach_chip,
};
static int jz4780_nand_init_chip(struct platform_device *pdev,
struct jz4780_nand_controller *nfc,
struct device_node *np,
@ -279,15 +285,8 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
chip->controller = &nfc->controller;
nand_set_flash_node(chip, np);
ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
return ret;
ret = jz4780_nand_init_ecc(nand, dev);
if (ret)
return ret;
ret = nand_scan_tail(mtd);
chip->controller->ops = &jz4780_nand_controller_ops;
ret = nand_scan(mtd, 1);
if (ret)
return ret;
@ -368,7 +367,7 @@ static int jz4780_nand_probe(struct platform_device *pdev)
nfc->dev = dev;
nfc->num_banks = num_banks;
nand_hw_control_init(&nfc->controller);
nand_controller_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
ret = jz4780_nand_init_chips(nfc, pdev);

View file

@ -184,6 +184,7 @@ static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
};
struct lpc32xx_nand_host {
struct platform_device *pdev;
struct nand_chip nand_chip;
struct lpc32xx_mlc_platform_data *pdata;
struct clk *clk;
@ -653,6 +654,32 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
return ncfg;
}
static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
struct device *dev = &host->pdev->dev;
host->dma_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
if (!host->dma_buf)
return -ENOMEM;
host->dummy_buf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
if (!host->dummy_buf)
return -ENOMEM;
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 512;
mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
host->mlcsubpages = mtd->writesize / 512;
return 0;
}
static const struct nand_controller_ops lpc32xx_nand_controller_ops = {
.attach_chip = lpc32xx_nand_attach_chip,
};
/*
* Probe for NAND controller
*/
@ -669,6 +696,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
if (!host)
return -ENOMEM;
host->pdev = pdev;
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, rc);
if (IS_ERR(host->io_base))
@ -748,31 +777,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
}
/*
* Scan to find existance of the device and
* Get the type of NAND device SMALL block or LARGE block
*/
res = nand_scan_ident(mtd, 1, NULL);
if (res)
goto release_dma_chan;
host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
if (!host->dma_buf) {
res = -ENOMEM;
goto release_dma_chan;
}
host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
if (!host->dummy_buf) {
res = -ENOMEM;
goto release_dma_chan;
}
nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512;
mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
host->mlcsubpages = mtd->writesize / 512;
/* initially clear interrupt status */
readb(MLC_IRQ_SR(host->io_base));
@ -794,10 +798,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
/*
* Fills out all the uninitialized function pointers with the defaults
* And scans for a bad block table if appropriate.
* Scan to find existence of the device and get the type of NAND device:
* SMALL block or LARGE block.
*/
res = nand_scan_tail(mtd);
nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
res = nand_scan(mtd, 1);
if (res)
goto free_irq;

View file

@ -779,6 +779,46 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
return ncfg;
}
static int lpc32xx_nand_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* OOB and ECC CPU and DMA work areas */
host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
/*
* Small page FLASH has a unique OOB layout, but large and huge
* page FLASH use the standard layout. Small page FLASH uses a
* custom BBT marker layout.
*/
if (mtd->writesize <= 512)
mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
/* These sizes remain the same regardless of page size */
chip->ecc.size = 256;
chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
chip->ecc.prepad = 0;
chip->ecc.postpad = 0;
/*
* Use a custom BBT marker setup for small page FLASH that
* won't interfere with the ECC layout. Large and huge page
* FLASH use the standard layout.
*/
if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
mtd->writesize <= 512) {
chip->bbt_td = &bbt_smallpage_main_descr;
chip->bbt_md = &bbt_smallpage_mirror_descr;
}
return 0;
}
static const struct nand_controller_ops lpc32xx_nand_controller_ops = {
.attach_chip = lpc32xx_nand_attach_chip,
};
/*
* Probe for NAND controller
*/
@ -884,41 +924,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
/* Find NAND device */
res = nand_scan_ident(mtd, 1, NULL);
if (res)
goto release_dma;
/* OOB and ECC CPU and DMA work areas */
host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
/*
* Small page FLASH has a unique OOB layout, but large and huge
* page FLASH use the standard layout. Small page FLASH uses a
* custom BBT marker layout.
*/
if (mtd->writesize <= 512)
mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
/* These sizes remain the same regardless of page size */
chip->ecc.size = 256;
chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
chip->ecc.prepad = chip->ecc.postpad = 0;
/*
* Use a custom BBT marker setup for small page FLASH that
* won't interfere with the ECC layout. Large and huge page
* FLASH use the standard layout.
*/
if ((chip->bbt_options & NAND_BBT_USE_FLASH) &&
mtd->writesize <= 512) {
chip->bbt_td = &bbt_smallpage_main_descr;
chip->bbt_md = &bbt_smallpage_mirror_descr;
}
/*
* Fills out all the uninitialized function pointers with the defaults
*/
res = nand_scan_tail(mtd);
chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
res = nand_scan(mtd, 1);
if (res)
goto release_dma;

View file

@ -318,7 +318,7 @@ struct marvell_nfc_caps {
* @dma_buf: 32-bit aligned buffer for DMA transfers (NFCv1 only)
*/
struct marvell_nfc {
struct nand_hw_control controller;
struct nand_controller controller;
struct device *dev;
void __iomem *regs;
struct clk *core_clk;
@ -335,7 +335,7 @@ struct marvell_nfc {
u8 *dma_buf;
};
static inline struct marvell_nfc *to_marvell_nfc(struct nand_hw_control *ctrl)
static inline struct marvell_nfc *to_marvell_nfc(struct nand_controller *ctrl)
{
return container_of(ctrl, struct marvell_nfc, controller);
}
@ -650,11 +650,6 @@ static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
return;
}
/*
* Do not change the timing registers when using the DT property
* marvell,nand-keep-config; in that case ->ndtr0 and ->ndtr1 from the
* marvell_nand structure are supposedly empty.
*/
writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0);
writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1);
@ -2157,6 +2152,7 @@ static int marvell_nand_ecc_init(struct mtd_info *mtd,
break;
case NAND_ECC_NONE:
case NAND_ECC_SOFT:
case NAND_ECC_ON_DIE:
if (!nfc->caps->is_nfcv2 && mtd->writesize != SZ_512 &&
mtd->writesize != SZ_2K) {
dev_err(nfc->dev, "NFCv1 cannot write %d bytes pages\n",
@ -2294,6 +2290,111 @@ static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
return 0;
}
static int marvell_nand_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(nfc->dev);
int ret;
if (pdata && pdata->flash_bbt)
chip->bbt_options |= NAND_BBT_USE_FLASH;
if (chip->bbt_options & NAND_BBT_USE_FLASH) {
/*
* We'll use a bad block table stored in-flash and don't
* allow writing the bad block marker to the flash.
*/
chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
}
/* Save the chip-specific fields of NDCR */
marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
if (chip->options & NAND_BUSWIDTH_16)
marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
/*
* On small page NANDs, only one cycle is needed to pass the
* column address.
*/
if (mtd->writesize <= 512) {
marvell_nand->addr_cyc = 1;
} else {
marvell_nand->addr_cyc = 2;
marvell_nand->ndcr |= NDCR_RA_START;
}
/*
* Now add the number of cycles needed to pass the row
* address.
*
* Addressing a chip using CS 2 or 3 should also need the third row
* cycle but due to inconsistance in the documentation and lack of
* hardware to test this situation, this case is not supported.
*/
if (chip->options & NAND_ROW_ADDR_3)
marvell_nand->addr_cyc += 3;
else
marvell_nand->addr_cyc += 2;
if (pdata) {
chip->ecc.size = pdata->ecc_step_size;
chip->ecc.strength = pdata->ecc_strength;
}
ret = marvell_nand_ecc_init(mtd, &chip->ecc);
if (ret) {
dev_err(nfc->dev, "ECC init failed: %d\n", ret);
return ret;
}
if (chip->ecc.mode == NAND_ECC_HW) {
/*
* Subpage write not available with hardware ECC, prohibit also
* subpage read as in userspace subpage access would still be
* allowed and subpage write, if used, would lead to numerous
* uncorrectable ECC errors.
*/
chip->options |= NAND_NO_SUBPAGE_WRITE;
}
if (pdata || nfc->caps->legacy_of_bindings) {
/*
* We keep the MTD name unchanged to avoid breaking platforms
* where the MTD cmdline parser is used and the bootloader
* has not been updated to use the new naming scheme.
*/
mtd->name = "pxa3xx_nand-0";
} else if (!mtd->name) {
/*
* If the new bindings are used and the bootloader has not been
* updated to pass a new mtdparts parameter on the cmdline, you
* should define the following property in your NAND node, ie:
*
* label = "main-storage";
*
* This way, mtd->name will be set by the core when
* nand_set_flash_node() is called.
*/
mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
"%s:nand.%d", dev_name(nfc->dev),
marvell_nand->sels[0].cs);
if (!mtd->name) {
dev_err(nfc->dev, "Failed to allocate mtd->name\n");
return -ENOMEM;
}
}
return 0;
}
static const struct nand_controller_ops marvell_nand_controller_ops = {
.attach_chip = marvell_nand_attach_chip,
};
static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
struct device_node *np)
{
@ -2436,105 +2537,10 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1);
chip->options |= NAND_BUSWIDTH_AUTO;
ret = nand_scan_ident(mtd, marvell_nand->nsels, NULL);
ret = nand_scan(mtd, marvell_nand->nsels);
if (ret) {
dev_err(dev, "could not identify the nand chip\n");
return ret;
}
if (pdata && pdata->flash_bbt)
chip->bbt_options |= NAND_BBT_USE_FLASH;
if (chip->bbt_options & NAND_BBT_USE_FLASH) {
/*
* We'll use a bad block table stored in-flash and don't
* allow writing the bad block marker to the flash.
*/
chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
}
/* Save the chip-specific fields of NDCR */
marvell_nand->ndcr = NDCR_PAGE_SZ(mtd->writesize);
if (chip->options & NAND_BUSWIDTH_16)
marvell_nand->ndcr |= NDCR_DWIDTH_M | NDCR_DWIDTH_C;
/*
* On small page NANDs, only one cycle is needed to pass the
* column address.
*/
if (mtd->writesize <= 512) {
marvell_nand->addr_cyc = 1;
} else {
marvell_nand->addr_cyc = 2;
marvell_nand->ndcr |= NDCR_RA_START;
}
/*
* Now add the number of cycles needed to pass the row
* address.
*
* Addressing a chip using CS 2 or 3 should also need the third row
* cycle but due to inconsistance in the documentation and lack of
* hardware to test this situation, this case is not supported.
*/
if (chip->options & NAND_ROW_ADDR_3)
marvell_nand->addr_cyc += 3;
else
marvell_nand->addr_cyc += 2;
if (pdata) {
chip->ecc.size = pdata->ecc_step_size;
chip->ecc.strength = pdata->ecc_strength;
}
ret = marvell_nand_ecc_init(mtd, &chip->ecc);
if (ret) {
dev_err(dev, "ECC init failed: %d\n", ret);
return ret;
}
if (chip->ecc.mode == NAND_ECC_HW) {
/*
* Subpage write not available with hardware ECC, prohibit also
* subpage read as in userspace subpage access would still be
* allowed and subpage write, if used, would lead to numerous
* uncorrectable ECC errors.
*/
chip->options |= NAND_NO_SUBPAGE_WRITE;
}
if (pdata || nfc->caps->legacy_of_bindings) {
/*
* We keep the MTD name unchanged to avoid breaking platforms
* where the MTD cmdline parser is used and the bootloader
* has not been updated to use the new naming scheme.
*/
mtd->name = "pxa3xx_nand-0";
} else if (!mtd->name) {
/*
* If the new bindings are used and the bootloader has not been
* updated to pass a new mtdparts parameter on the cmdline, you
* should define the following property in your NAND node, ie:
*
* label = "main-storage";
*
* This way, mtd->name will be set by the core when
* nand_set_flash_node() is called.
*/
mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
"%s:nand.%d", dev_name(nfc->dev),
marvell_nand->sels[0].cs);
if (!mtd->name) {
dev_err(nfc->dev, "Failed to allocate mtd->name\n");
return -ENOMEM;
}
}
ret = nand_scan_tail(mtd);
if (ret) {
dev_err(dev, "nand_scan_tail failed: %d\n", ret);
dev_err(dev, "could not scan the nand chip\n");
return ret;
}
@ -2677,6 +2683,21 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc)
return 0;
}
static void marvell_nfc_reset(struct marvell_nfc *nfc)
{
/*
* ECC operations and interruptions are only enabled when specifically
* needed. ECC shall not be activated in the early stages (fails probe).
* Arbiter flag, even if marked as "reserved", must be set (empirical).
* SPARE_EN bit must always be set or ECC bytes will not be at the same
* offset in the read page and this will fail the protection.
*/
writel_relaxed(NDCR_ALL_INT | NDCR_ND_ARB_EN | NDCR_SPARE_EN |
NDCR_RD_ID_CNT(NFCV1_READID_LEN), nfc->regs + NDCR);
writel_relaxed(0xFFFFFFFF, nfc->regs + NDSR);
writel_relaxed(0, nfc->regs + NDECCCTRL);
}
static int marvell_nfc_init(struct marvell_nfc *nfc)
{
struct device_node *np = nfc->dev->of_node;
@ -2715,17 +2736,7 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
if (!nfc->caps->is_nfcv2)
marvell_nfc_init_dma(nfc);
/*
* ECC operations and interruptions are only enabled when specifically
* needed. ECC shall not be activated in the early stages (fails probe).
* Arbiter flag, even if marked as "reserved", must be set (empirical).
* SPARE_EN bit must always be set or ECC bytes will not be at the same
* offset in the read page and this will fail the protection.
*/
writel_relaxed(NDCR_ALL_INT | NDCR_ND_ARB_EN | NDCR_SPARE_EN |
NDCR_RD_ID_CNT(NFCV1_READID_LEN), nfc->regs + NDCR);
writel_relaxed(0xFFFFFFFF, nfc->regs + NDSR);
writel_relaxed(0, nfc->regs + NDECCCTRL);
marvell_nfc_reset(nfc);
return 0;
}
@ -2744,7 +2755,8 @@ static int marvell_nfc_probe(struct platform_device *pdev)
return -ENOMEM;
nfc->dev = dev;
nand_hw_control_init(&nfc->controller);
nand_controller_init(&nfc->controller);
nfc->controller.ops = &marvell_nand_controller_ops;
INIT_LIST_HEAD(&nfc->chips);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -2772,17 +2784,19 @@ static int marvell_nfc_probe(struct platform_device *pdev)
return ret;
nfc->reg_clk = devm_clk_get(&pdev->dev, "reg");
if (PTR_ERR(nfc->reg_clk) != -ENOENT) {
if (!IS_ERR(nfc->reg_clk)) {
ret = clk_prepare_enable(nfc->reg_clk);
if (ret)
goto unprepare_core_clk;
} else {
if (IS_ERR(nfc->reg_clk)) {
if (PTR_ERR(nfc->reg_clk) != -ENOENT) {
ret = PTR_ERR(nfc->reg_clk);
goto unprepare_core_clk;
}
nfc->reg_clk = NULL;
}
ret = clk_prepare_enable(nfc->reg_clk);
if (ret)
goto unprepare_core_clk;
marvell_nfc_disable_int(nfc, NDCR_ALL_INT);
marvell_nfc_clear_int(nfc, NDCR_ALL_INT);
ret = devm_request_irq(dev, irq, marvell_nfc_isr,
@ -2840,6 +2854,49 @@ static int marvell_nfc_remove(struct platform_device *pdev)
return 0;
}
static int __maybe_unused marvell_nfc_suspend(struct device *dev)
{
struct marvell_nfc *nfc = dev_get_drvdata(dev);
struct marvell_nand_chip *chip;
list_for_each_entry(chip, &nfc->chips, node)
marvell_nfc_wait_ndrun(&chip->chip);
clk_disable_unprepare(nfc->reg_clk);
clk_disable_unprepare(nfc->core_clk);
return 0;
}
static int __maybe_unused marvell_nfc_resume(struct device *dev)
{
struct marvell_nfc *nfc = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(nfc->core_clk);
if (ret < 0)
return ret;
ret = clk_prepare_enable(nfc->reg_clk);
if (ret < 0)
return ret;
/*
* Reset nfc->selected_chip so the next command will cause the timing
* registers to be restored in marvell_nfc_select_chip().
*/
nfc->selected_chip = NULL;
/* Reset registers that have lost their contents */
marvell_nfc_reset(nfc);
return 0;
}
static const struct dev_pm_ops marvell_nfc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(marvell_nfc_suspend, marvell_nfc_resume)
};
static const struct marvell_nfc_caps marvell_armada_8k_nfc_caps = {
.max_cs_nb = 4,
.max_rb_nb = 2,
@ -2924,6 +2981,7 @@ static struct platform_driver marvell_nfc_driver = {
.driver = {
.name = "marvell-nfc",
.of_match_table = marvell_nfc_of_ids,
.pm = &marvell_nfc_pm_ops,
},
.id_table = marvell_nfc_platform_ids,
.probe = marvell_nfc_probe,

View file

@ -145,7 +145,7 @@ struct mtk_nfc_clk {
};
struct mtk_nfc {
struct nand_hw_control controller;
struct nand_controller controller;
struct mtk_ecc_config ecc_cfg;
struct mtk_nfc_clk clk;
struct mtk_ecc *ecc;
@ -1250,13 +1250,54 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
return 0;
}
static int mtk_nfc_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct device *dev = mtd->dev.parent;
struct mtk_nfc *nfc = nand_get_controller_data(chip);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
int len;
int ret;
if (chip->options & NAND_BUSWIDTH_16) {
dev_err(dev, "16bits buswidth not supported");
return -EINVAL;
}
/* store bbt magic in page, cause OOB is not protected */
if (chip->bbt_options & NAND_BBT_USE_FLASH)
chip->bbt_options |= NAND_BBT_NO_OOB;
ret = mtk_nfc_ecc_init(dev, mtd);
if (ret)
return ret;
ret = mtk_nfc_set_spare_per_sector(&mtk_nand->spare_per_sector, mtd);
if (ret)
return ret;
mtk_nfc_set_fdm(&mtk_nand->fdm, mtd);
mtk_nfc_set_bad_mark_ctl(&mtk_nand->bad_mark, mtd);
len = mtd->writesize + mtd->oobsize;
nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
if (!nfc->buffer)
return -ENOMEM;
return 0;
}
static const struct nand_controller_ops mtk_nfc_controller_ops = {
.attach_chip = mtk_nfc_attach_chip,
};
static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
struct device_node *np)
{
struct mtk_nfc_nand_chip *chip;
struct nand_chip *nand;
struct mtd_info *mtd;
int nsels, len;
int nsels;
u32 tmp;
int ret;
int i;
@ -1324,40 +1365,11 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
mtk_nfc_hw_init(nfc);
ret = nand_scan_ident(mtd, nsels, NULL);
ret = nand_scan(mtd, nsels);
if (ret)
return ret;
/* store bbt magic in page, cause OOB is not protected */
if (nand->bbt_options & NAND_BBT_USE_FLASH)
nand->bbt_options |= NAND_BBT_NO_OOB;
ret = mtk_nfc_ecc_init(dev, mtd);
if (ret)
return -EINVAL;
if (nand->options & NAND_BUSWIDTH_16) {
dev_err(dev, "16bits buswidth not supported");
return -EINVAL;
}
ret = mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
if (ret)
return ret;
mtk_nfc_set_fdm(&chip->fdm, mtd);
mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
len = mtd->writesize + mtd->oobsize;
nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
if (!nfc->buffer)
return -ENOMEM;
ret = nand_scan_tail(mtd);
if (ret)
return ret;
ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "mtd parse partition error\n");
nand_release(mtd);
@ -1443,6 +1455,7 @@ static int mtk_nfc_probe(struct platform_device *pdev)
spin_lock_init(&nfc->controller.lock);
init_waitqueue_head(&nfc->controller.wq);
INIT_LIST_HEAD(&nfc->chips);
nfc->controller.ops = &mtk_nfc_controller_ops;
/* probe defer if not ready */
nfc->ecc = of_mtk_ecc_get(np);

View file

@ -1,20 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Sascha Hauer, kernel@pengutronix.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <linux/delay.h>
@ -34,8 +21,6 @@
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <asm/mach/flash.h>
#include <linux/platform_data/mtd-mxc_nand.h>
#define DRIVER_NAME "mxc_nand"
@ -1686,7 +1671,7 @@ static const struct of_device_id mxcnd_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
static int mxcnd_probe_dt(struct mxc_nand_host *host)
{
struct device_node *np = host->dev->of_node;
const struct of_device_id *of_id =
@ -1700,12 +1685,80 @@ static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
return 0;
}
#else
static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
static int mxcnd_probe_dt(struct mxc_nand_host *host)
{
return 1;
}
#endif
static int mxcnd_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct mxc_nand_host *host = nand_get_controller_data(chip);
struct device *dev = mtd->dev.parent;
switch (chip->ecc.mode) {
case NAND_ECC_HW:
chip->ecc.read_page = mxc_nand_read_page;
chip->ecc.read_page_raw = mxc_nand_read_page_raw;
chip->ecc.read_oob = mxc_nand_read_oob;
chip->ecc.write_page = mxc_nand_write_page_ecc;
chip->ecc.write_page_raw = mxc_nand_write_page_raw;
chip->ecc.write_oob = mxc_nand_write_oob;
break;
case NAND_ECC_SOFT:
break;
default:
return -EINVAL;
}
if (chip->bbt_options & NAND_BBT_USE_FLASH) {
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
}
/* Allocate the right size buffer now */
devm_kfree(dev, (void *)host->data_buf);
host->data_buf = devm_kzalloc(dev, mtd->writesize + mtd->oobsize,
GFP_KERNEL);
if (!host->data_buf)
return -ENOMEM;
/* Call preset again, with correct writesize chip time */
host->devtype_data->preset(mtd);
if (!chip->ecc.bytes) {
if (host->eccsize == 8)
chip->ecc.bytes = 18;
else if (host->eccsize == 4)
chip->ecc.bytes = 9;
}
/*
* Experimentation shows that i.MX NFC can only handle up to 218 oob
* bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
* into copying invalid data to/from the spare IO buffer, as this
* might cause ECC data corruption when doing sub-page write to a
* partially written page.
*/
host->used_oobsize = min(mtd->oobsize, 218U);
if (chip->ecc.mode == NAND_ECC_HW) {
if (is_imx21_nfc(host) || is_imx27_nfc(host))
chip->ecc.strength = 1;
else
chip->ecc.strength = (host->eccsize == 4) ? 4 : 8;
}
return 0;
}
static const struct nand_controller_ops mxcnd_controller_ops = {
.attach_chip = mxcnd_attach_chip,
};
static int mxcnd_probe(struct platform_device *pdev)
{
struct nand_chip *this;
@ -1845,71 +1898,9 @@ static int mxcnd_probe(struct platform_device *pdev)
host->devtype_data->irq_control(host, 1);
}
/* first scan to find the device and get the page size */
err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL);
if (err)
goto escan;
switch (this->ecc.mode) {
case NAND_ECC_HW:
this->ecc.read_page = mxc_nand_read_page;
this->ecc.read_page_raw = mxc_nand_read_page_raw;
this->ecc.read_oob = mxc_nand_read_oob;
this->ecc.write_page = mxc_nand_write_page_ecc;
this->ecc.write_page_raw = mxc_nand_write_page_raw;
this->ecc.write_oob = mxc_nand_write_oob;
break;
case NAND_ECC_SOFT:
break;
default:
err = -EINVAL;
goto escan;
}
if (this->bbt_options & NAND_BBT_USE_FLASH) {
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
}
/* allocate the right size buffer now */
devm_kfree(&pdev->dev, (void *)host->data_buf);
host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
GFP_KERNEL);
if (!host->data_buf) {
err = -ENOMEM;
goto escan;
}
/* Call preset again, with correct writesize this time */
host->devtype_data->preset(mtd);
if (!this->ecc.bytes) {
if (host->eccsize == 8)
this->ecc.bytes = 18;
else if (host->eccsize == 4)
this->ecc.bytes = 9;
}
/*
* Experimentation shows that i.MX NFC can only handle up to 218 oob
* bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
* into copying invalid data to/from the spare IO buffer, as this
* might cause ECC data corruption when doing sub-page write to a
* partially written page.
*/
host->used_oobsize = min(mtd->oobsize, 218U);
if (this->ecc.mode == NAND_ECC_HW) {
if (is_imx21_nfc(host) || is_imx27_nfc(host))
this->ecc.strength = 1;
else
this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
}
/* second phase scan */
err = nand_scan_tail(mtd);
/* Scan the NAND device */
this->dummy_controller.ops = &mxcnd_controller_ops;
err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1);
if (err)
goto escan;

View file

@ -2668,8 +2668,8 @@ static bool nand_subop_instr_is_valid(const struct nand_subop *subop,
return subop && instr_idx < subop->ninstrs;
}
static int nand_subop_get_start_off(const struct nand_subop *subop,
unsigned int instr_idx)
static unsigned int nand_subop_get_start_off(const struct nand_subop *subop,
unsigned int instr_idx)
{
if (instr_idx)
return 0;
@ -2688,12 +2688,12 @@ static int nand_subop_get_start_off(const struct nand_subop *subop,
*
* Given an address instruction, returns the offset of the first cycle to issue.
*/
int nand_subop_get_addr_start_off(const struct nand_subop *subop,
unsigned int instr_idx)
unsigned int nand_subop_get_addr_start_off(const struct nand_subop *subop,
unsigned int instr_idx)
{
if (!nand_subop_instr_is_valid(subop, instr_idx) ||
subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
return -EINVAL;
if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) ||
subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR))
return 0;
return nand_subop_get_start_off(subop, instr_idx);
}
@ -2710,14 +2710,14 @@ EXPORT_SYMBOL_GPL(nand_subop_get_addr_start_off);
*
* Given an address instruction, returns the number of address cycle to issue.
*/
int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
unsigned int instr_idx)
unsigned int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
unsigned int instr_idx)
{
int start_off, end_off;
if (!nand_subop_instr_is_valid(subop, instr_idx) ||
subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
return -EINVAL;
if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) ||
subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR))
return 0;
start_off = nand_subop_get_addr_start_off(subop, instr_idx);
@ -2742,12 +2742,12 @@ EXPORT_SYMBOL_GPL(nand_subop_get_num_addr_cyc);
*
* Given a data instruction, returns the offset to start from.
*/
int nand_subop_get_data_start_off(const struct nand_subop *subop,
unsigned int instr_idx)
unsigned int nand_subop_get_data_start_off(const struct nand_subop *subop,
unsigned int instr_idx)
{
if (!nand_subop_instr_is_valid(subop, instr_idx) ||
!nand_instr_is_data(&subop->instrs[instr_idx]))
return -EINVAL;
if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) ||
!nand_instr_is_data(&subop->instrs[instr_idx])))
return 0;
return nand_subop_get_start_off(subop, instr_idx);
}
@ -2764,14 +2764,14 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_start_off);
*
* Returns the length of the chunk of data to send/receive.
*/
int nand_subop_get_data_len(const struct nand_subop *subop,
unsigned int instr_idx)
unsigned int nand_subop_get_data_len(const struct nand_subop *subop,
unsigned int instr_idx)
{
int start_off = 0, end_off;
if (!nand_subop_instr_is_valid(subop, instr_idx) ||
!nand_instr_is_data(&subop->instrs[instr_idx]))
return -EINVAL;
if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) ||
!nand_instr_is_data(&subop->instrs[instr_idx])))
return 0;
start_off = nand_subop_get_data_start_off(subop, instr_idx);
@ -2966,6 +2966,23 @@ int nand_check_erased_ecc_chunk(void *data, int datalen,
}
EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
/**
* nand_read_page_raw_notsupp - dummy read raw page function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Returns -ENOTSUPP unconditionally.
*/
int nand_read_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
u8 *buf, int oob_required, int page)
{
return -ENOTSUPP;
}
EXPORT_SYMBOL(nand_read_page_raw_notsupp);
/**
* nand_read_page_raw - [INTERN] read raw page data without ecc
* @mtd: mtd info structure
@ -3960,6 +3977,22 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
return ret;
}
/**
* nand_write_page_raw_notsupp - dummy raw page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
*
* Returns -ENOTSUPP unconditionally.
*/
int nand_write_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
const u8 *buf, int oob_required, int page)
{
return -ENOTSUPP;
}
EXPORT_SYMBOL(nand_write_page_raw_notsupp);
/**
* nand_write_page_raw - [INTERN] raw page write function
@ -4965,12 +4998,10 @@ static void nand_set_defaults(struct nand_chip *chip)
chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
if (!chip->read_buf || chip->read_buf == nand_read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
nand_hw_control_init(chip->controller);
chip->controller = &chip->dummy_controller;
nand_controller_init(chip->controller);
}
if (!chip->buf_align)
@ -5120,6 +5151,8 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_onfi_params *p;
struct onfi_params *onfi;
int onfi_version = 0;
char id[4];
int i, ret, val;
@ -5168,30 +5201,35 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
}
}
if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
chip->manufacturer.desc->ops->fixup_onfi_param_page)
chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);
/* Check version */
val = le16_to_cpu(p->revision);
if (val & (1 << 5))
chip->parameters.onfi.version = 23;
else if (val & (1 << 4))
chip->parameters.onfi.version = 22;
else if (val & (1 << 3))
chip->parameters.onfi.version = 21;
else if (val & (1 << 2))
chip->parameters.onfi.version = 20;
else if (val & (1 << 1))
chip->parameters.onfi.version = 10;
if (val & ONFI_VERSION_2_3)
onfi_version = 23;
else if (val & ONFI_VERSION_2_2)
onfi_version = 22;
else if (val & ONFI_VERSION_2_1)
onfi_version = 21;
else if (val & ONFI_VERSION_2_0)
onfi_version = 20;
else if (val & ONFI_VERSION_1_0)
onfi_version = 10;
if (!chip->parameters.onfi.version) {
if (!onfi_version) {
pr_info("unsupported ONFI version: %d\n", val);
goto free_onfi_param_page;
} else {
ret = 1;
}
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
strncpy(chip->parameters.model, p->model,
sizeof(chip->parameters.model) - 1);
chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
if (!chip->parameters.model) {
ret = -ENOMEM;
goto free_onfi_param_page;
}
mtd->writesize = le32_to_cpu(p->byte_per_page);
@ -5219,7 +5257,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
if (p->ecc_bits != 0xff) {
chip->ecc_strength_ds = p->ecc_bits;
chip->ecc_step_ds = 512;
} else if (chip->parameters.onfi.version >= 21 &&
} else if (onfi_version >= 21 &&
(le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
/*
@ -5246,19 +5284,33 @@ static int nand_flash_detect_onfi(struct nand_chip *chip)
bitmap_set(chip->parameters.set_feature_list,
ONFI_FEATURE_ADDR_TIMING_MODE, 1);
}
chip->parameters.onfi.tPROG = le16_to_cpu(p->t_prog);
chip->parameters.onfi.tBERS = le16_to_cpu(p->t_bers);
chip->parameters.onfi.tR = le16_to_cpu(p->t_r);
chip->parameters.onfi.tCCS = le16_to_cpu(p->t_ccs);
chip->parameters.onfi.async_timing_mode =
le16_to_cpu(p->async_timing_mode);
chip->parameters.onfi.vendor_revision =
le16_to_cpu(p->vendor_revision);
memcpy(chip->parameters.onfi.vendor, p->vendor,
sizeof(p->vendor));
onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
if (!onfi) {
ret = -ENOMEM;
goto free_model;
}
onfi->version = onfi_version;
onfi->tPROG = le16_to_cpu(p->t_prog);
onfi->tBERS = le16_to_cpu(p->t_bers);
onfi->tR = le16_to_cpu(p->t_r);
onfi->tCCS = le16_to_cpu(p->t_ccs);
onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
chip->parameters.onfi = onfi;
/* Identification done, free the full ONFI parameter page and exit */
kfree(p);
return 1;
free_model:
kfree(chip->parameters.model);
free_onfi_param_page:
kfree(p);
return ret;
}
@ -5321,8 +5373,11 @@ static int nand_flash_detect_jedec(struct nand_chip *chip)
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
strncpy(chip->parameters.model, p->model,
sizeof(chip->parameters.model) - 1);
chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
if (!chip->parameters.model) {
ret = -ENOMEM;
goto free_jedec_param_page;
}
mtd->writesize = le32_to_cpu(p->byte_per_page);
@ -5511,8 +5566,9 @@ static bool find_full_id_nand(struct nand_chip *chip,
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;
strncpy(chip->parameters.model, type->name,
sizeof(chip->parameters.model) - 1);
chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
if (!chip->parameters.model)
return false;
return true;
}
@ -5651,7 +5707,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
}
}
chip->parameters.onfi.version = 0;
if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
ret = nand_flash_detect_onfi(chip);
@ -5671,8 +5726,9 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
if (!type->name)
return -ENODEV;
strncpy(chip->parameters.model, type->name,
sizeof(chip->parameters.model) - 1);
chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
if (!chip->parameters.model)
return -ENOMEM;
chip->chipsize = (uint64_t)type->chipsize << 20;
@ -5702,7 +5758,9 @@ ident_done:
mtd->name);
pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
return -EINVAL;
ret = -EINVAL;
goto free_detect_allocation;
}
nand_decode_bbm_options(chip);
@ -5739,6 +5797,11 @@ ident_done:
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
return 0;
free_detect_allocation:
kfree(chip->parameters.model);
return ret;
}
static const char * const nand_ecc_modes[] = {
@ -5777,6 +5840,7 @@ static int of_get_nand_ecc_mode(struct device_node *np)
static const char * const nand_ecc_algos[] = {
[NAND_ECC_HAMMING] = "hamming",
[NAND_ECC_BCH] = "bch",
[NAND_ECC_RS] = "rs",
};
static int of_get_nand_ecc_algo(struct device_node *np)
@ -5858,6 +5922,9 @@ static int nand_dt_init(struct nand_chip *chip)
if (of_get_nand_bus_width(dn) == 16)
chip->options |= NAND_BUSWIDTH_16;
if (of_property_read_bool(dn, "nand-is-boot-medium"))
chip->options |= NAND_IS_BOOT_MEDIUM;
if (of_get_nand_on_flash_bbt(dn))
chip->bbt_options |= NAND_BBT_USE_FLASH;
@ -5885,7 +5952,7 @@ static int nand_dt_init(struct nand_chip *chip)
}
/**
* nand_scan_ident - [NAND Interface] Scan for the NAND device
* nand_scan_ident - Scan for the NAND device
* @mtd: MTD device structure
* @maxchips: number of chips to scan for
* @table: alternative NAND ID table
@ -5893,9 +5960,13 @@ static int nand_dt_init(struct nand_chip *chip)
* This is the first phase of the normal nand_scan() function. It reads the
* flash ID and sets up MTD fields accordingly.
*
* This helper used to be called directly from controller drivers that needed
* to tweak some ECC-related parameters before nand_scan_tail(). This separation
* prevented dynamic allocations during this phase which was unconvenient and
* as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks.
*/
int nand_scan_ident(struct mtd_info *mtd, int maxchips,
struct nand_flash_dev *table)
static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
struct nand_flash_dev *table)
{
int i, nand_maf_id, nand_dev_id;
struct nand_chip *chip = mtd_to_nand(mtd);
@ -5969,7 +6040,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return 0;
}
EXPORT_SYMBOL(nand_scan_ident);
static void nand_scan_ident_cleanup(struct nand_chip *chip)
{
kfree(chip->parameters.model);
kfree(chip->parameters.onfi);
}
static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
{
@ -6077,24 +6153,17 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
* by the controller and the calculated ECC bytes fit within the chip's OOB.
* On success, the calculated ECC bytes is set.
*/
int nand_check_ecc_caps(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
static int
nand_check_ecc_caps(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
int preset_step = chip->ecc.size;
int preset_strength = chip->ecc.strength;
int nsteps, ecc_bytes;
int ecc_bytes, nsteps = mtd->writesize / preset_step;
int i, j;
if (WARN_ON(oobavail < 0))
return -EINVAL;
if (!preset_step || !preset_strength)
return -ENODATA;
nsteps = mtd->writesize / preset_step;
for (i = 0; i < caps->nstepinfos; i++) {
stepinfo = &caps->stepinfos[i];
@ -6127,7 +6196,6 @@ int nand_check_ecc_caps(struct nand_chip *chip,
return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
/**
* nand_match_ecc_req - meet the chip's requirement with least ECC bytes
@ -6139,8 +6207,9 @@ EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
* number of ECC bytes (i.e. with the largest number of OOB-free bytes).
* On success, the chosen ECC settings are set.
*/
int nand_match_ecc_req(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
static int
nand_match_ecc_req(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
@ -6151,9 +6220,6 @@ int nand_match_ecc_req(struct nand_chip *chip,
int best_ecc_bytes_total = INT_MAX;
int i, j;
if (WARN_ON(oobavail < 0))
return -EINVAL;
/* No information provided by the NAND chip */
if (!req_step || !req_strength)
return -ENOTSUPP;
@ -6212,7 +6278,6 @@ int nand_match_ecc_req(struct nand_chip *chip,
return 0;
}
EXPORT_SYMBOL_GPL(nand_match_ecc_req);
/**
* nand_maximize_ecc - choose the max ECC strength available
@ -6223,8 +6288,9 @@ EXPORT_SYMBOL_GPL(nand_match_ecc_req);
* Choose the max ECC strength that is supported on the controller, and can fit
* within the chip's OOB. On success, the chosen ECC settings are set.
*/
int nand_maximize_ecc(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
static int
nand_maximize_ecc(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_ecc_step_info *stepinfo;
@ -6234,9 +6300,6 @@ int nand_maximize_ecc(struct nand_chip *chip,
int best_strength, best_ecc_bytes;
int i, j;
if (WARN_ON(oobavail < 0))
return -EINVAL;
for (i = 0; i < caps->nstepinfos; i++) {
stepinfo = &caps->stepinfos[i];
step_size = stepinfo->stepsize;
@ -6285,7 +6348,44 @@ int nand_maximize_ecc(struct nand_chip *chip,
return 0;
}
EXPORT_SYMBOL_GPL(nand_maximize_ecc);
/**
* nand_ecc_choose_conf - Set the ECC strength and ECC step size
* @chip: nand chip info structure
* @caps: ECC engine caps info structure
* @oobavail: OOB size that the ECC engine can use
*
* Choose the ECC configuration according to following logic
*
* 1. If both ECC step size and ECC strength are already set (usually by DT)
* then check if it is supported by this controller.
* 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
* 3. Otherwise, try to match the ECC step size and ECC strength closest
* to the chip's requirement. If available OOB size can't fit the chip
* requirement then fallback to the maximum ECC step size and ECC strength.
*
* On success, the chosen ECC settings are set.
*/
int nand_ecc_choose_conf(struct nand_chip *chip,
const struct nand_ecc_caps *caps, int oobavail)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize))
return -EINVAL;
if (chip->ecc.size && chip->ecc.strength)
return nand_check_ecc_caps(chip, caps, oobavail);
if (chip->ecc.options & NAND_ECC_MAXIMIZE)
return nand_maximize_ecc(chip, caps, oobavail);
if (!nand_match_ecc_req(chip, caps, oobavail))
return 0;
return nand_maximize_ecc(chip, caps, oobavail);
}
EXPORT_SYMBOL_GPL(nand_ecc_choose_conf);
/*
* Check if the chip configuration meet the datasheet requirements.
@ -6322,14 +6422,14 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
}
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
* nand_scan_tail - Scan for the NAND device
* @mtd: MTD device structure
*
* This is the second phase of the normal nand_scan() function. It fills out
* all the uninitialized function pointers with the defaults and scans for a
* bad block table if appropriate.
*/
int nand_scan_tail(struct mtd_info *mtd)
static int nand_scan_tail(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@ -6636,7 +6736,7 @@ int nand_scan_tail(struct mtd_info *mtd)
return 0;
/* Build bad block table */
ret = chip->scan_bbt(mtd);
ret = nand_create_bbt(chip);
if (ret)
goto err_nand_manuf_cleanup;
@ -6653,24 +6753,27 @@ err_free_buf:
return ret;
}
EXPORT_SYMBOL(nand_scan_tail);
/*
* is_module_text_address() isn't exported, and it's mostly a pointless
* test if this is a module _anyway_ -- they'd have to try _really_ hard
* to call us from in-kernel code if the core NAND support is modular.
*/
#ifdef MODULE
#define caller_is_module() (1)
#else
#define caller_is_module() \
is_module_text_address((unsigned long)__builtin_return_address(0))
#endif
static int nand_attach(struct nand_chip *chip)
{
if (chip->controller->ops && chip->controller->ops->attach_chip)
return chip->controller->ops->attach_chip(chip);
return 0;
}
static void nand_detach(struct nand_chip *chip)
{
if (chip->controller->ops && chip->controller->ops->detach_chip)
chip->controller->ops->detach_chip(chip);
}
/**
* nand_scan_with_ids - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
* @maxchips: number of chips to scan for
* @maxchips: number of chips to scan for. @nand_scan_ident() will not be run if
* this parameter is zero (useful for specific drivers that must
* handle this part of the process themselves, e.g docg4).
* @ids: optional flash IDs table
*
* This fills out all the uninitialized function pointers with the defaults.
@ -6680,11 +6783,30 @@ EXPORT_SYMBOL(nand_scan_tail);
int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
struct nand_flash_dev *ids)
{
struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
ret = nand_scan_ident(mtd, maxchips, ids);
if (!ret)
ret = nand_scan_tail(mtd);
if (maxchips) {
ret = nand_scan_ident(mtd, maxchips, ids);
if (ret)
return ret;
}
ret = nand_attach(chip);
if (ret)
goto cleanup_ident;
ret = nand_scan_tail(mtd);
if (ret)
goto detach_chip;
return 0;
detach_chip:
nand_detach(chip);
cleanup_ident:
nand_scan_ident_cleanup(chip);
return ret;
}
EXPORT_SYMBOL(nand_scan_with_ids);
@ -6712,7 +6834,14 @@ void nand_cleanup(struct nand_chip *chip)
/* Free manufacturer priv data. */
nand_manufacturer_cleanup(chip);
/* Free controller specific allocations after chip identification */
nand_detach(chip);
/* Free identification phase allocations */
nand_scan_ident_cleanup(chip);
}
EXPORT_SYMBOL_GPL(nand_cleanup);
/**

View file

@ -1349,15 +1349,14 @@ static int nand_create_badblock_pattern(struct nand_chip *this)
}
/**
* nand_default_bbt - [NAND Interface] Select a default bad block table for the device
* @mtd: MTD device structure
* nand_create_bbt - [NAND Interface] Select a default bad block table for the device
* @this: NAND chip object
*
* This function selects the default bad block table support for the device and
* calls the nand_scan_bbt function.
*/
int nand_default_bbt(struct mtd_info *mtd)
int nand_create_bbt(struct nand_chip *this)
{
struct nand_chip *this = mtd_to_nand(mtd);
int ret;
/* Is a flash based bad block table requested? */
@ -1383,8 +1382,9 @@ int nand_default_bbt(struct mtd_info *mtd)
return ret;
}
return nand_scan_bbt(mtd, this->badblock_pattern);
return nand_scan_bbt(nand_to_mtd(this), this->badblock_pattern);
}
EXPORT_SYMBOL(nand_create_bbt);
/**
* nand_isreserved_bbt - [NAND Interface] Check if a block is reserved

View file

@ -100,6 +100,16 @@ static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
struct mtd_info *mtd = nand_to_mtd(chip);
u16 column = ((u16)addr << 8) | addr;
if (chip->exec_op) {
struct nand_op_instr instrs[] = {
NAND_OP_ADDR(1, &addr, 0),
NAND_OP_8BIT_DATA_OUT(1, &val, 0),
};
struct nand_operation op = NAND_OPERATION(instrs);
return nand_exec_op(chip, &op);
}
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
chip->write_byte(mtd, val);
@ -473,6 +483,19 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
WARN(1, "Invalid OOB size");
break;
}
/*
* The datasheet of H27UCG8T2BTR mentions that the "Redundant
* Area Size" is encoded "per 8KB" (page size). This chip uses
* a page size of 16KiB. The datasheet mentions an OOB size of
* 1.280 bytes, but the OOB size encoded in the ID bytes (using
* the existing logic above) is 640 bytes.
* Update the OOB size for this chip by taking the value
* determined above and scaling it to the actual page size (so
* the actual OOB size for this chip is: 640 * 16k / 8k).
*/
if (chip->id.data[1] == 0xde)
mtd->oobsize *= mtd->writesize / SZ_8K;
}
}

View file

@ -16,12 +16,33 @@
*/
#include <linux/mtd/rawnand.h>
#include <linux/slab.h>
/*
* Special Micron status bit that indicates when the block has been
* corrected by on-die ECC and should be rewritten
* Special Micron status bit 3 indicates that the block has been
* corrected by on-die ECC and should be rewritten.
*/
#define NAND_STATUS_WRITE_RECOMMENDED BIT(3)
#define NAND_ECC_STATUS_WRITE_RECOMMENDED BIT(3)
/*
* On chips with 8-bit ECC and additional bit can be used to distinguish
* cases where a errors were corrected without needing a rewrite
*
* Bit 4 Bit 3 Bit 0 Description
* ----- ----- ----- -----------
* 0 0 0 No Errors
* 0 0 1 Multiple uncorrected errors
* 0 1 0 4 - 6 errors corrected, recommend rewrite
* 0 1 1 Reserved
* 1 0 0 1 - 3 errors corrected
* 1 0 1 Reserved
* 1 1 0 7 - 8 errors corrected, recommend rewrite
*/
#define NAND_ECC_STATUS_MASK (BIT(4) | BIT(3) | BIT(0))
#define NAND_ECC_STATUS_UNCORRECTABLE BIT(0)
#define NAND_ECC_STATUS_4_6_CORRECTED BIT(3)
#define NAND_ECC_STATUS_1_3_CORRECTED BIT(4)
#define NAND_ECC_STATUS_7_8_CORRECTED (BIT(4) | BIT(3))
struct nand_onfi_vendor_micron {
u8 two_plane_read;
@ -43,6 +64,16 @@ struct nand_onfi_vendor_micron {
u8 param_revision;
} __packed;
struct micron_on_die_ecc {
bool forced;
bool enabled;
void *rawbuf;
};
struct micron_nand {
struct micron_on_die_ecc ecc;
};
static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
{
struct nand_chip *chip = mtd_to_nand(mtd);
@ -57,9 +88,10 @@ static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
static int micron_nand_onfi_init(struct nand_chip *chip)
{
struct nand_parameters *p = &chip->parameters;
struct nand_onfi_vendor_micron *micron = (void *)p->onfi.vendor;
if (chip->parameters.onfi.version && p->onfi.vendor_revision) {
if (p->onfi) {
struct nand_onfi_vendor_micron *micron = (void *)p->onfi->vendor;
chip->read_retries = micron->read_retry_options;
chip->setup_read_retry = micron_nand_setup_read_retry;
}
@ -74,8 +106,9 @@ static int micron_nand_onfi_init(struct nand_chip *chip)
return 0;
}
static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
static int micron_nand_on_die_4_ooblayout_ecc(struct mtd_info *mtd,
int section,
struct mtd_oob_region *oobregion)
{
if (section >= 4)
return -ERANGE;
@ -86,8 +119,9 @@ static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section,
return 0;
}
static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
static int micron_nand_on_die_4_ooblayout_free(struct mtd_info *mtd,
int section,
struct mtd_oob_region *oobregion)
{
if (section >= 4)
return -ERANGE;
@ -98,19 +132,161 @@ static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section,
return 0;
}
static const struct mtd_ooblayout_ops micron_nand_on_die_ooblayout_ops = {
.ecc = micron_nand_on_die_ooblayout_ecc,
.free = micron_nand_on_die_ooblayout_free,
static const struct mtd_ooblayout_ops micron_nand_on_die_4_ooblayout_ops = {
.ecc = micron_nand_on_die_4_ooblayout_ecc,
.free = micron_nand_on_die_4_ooblayout_free,
};
static int micron_nand_on_die_8_ooblayout_ecc(struct mtd_info *mtd,
int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if (section)
return -ERANGE;
oobregion->offset = mtd->oobsize - chip->ecc.total;
oobregion->length = chip->ecc.total;
return 0;
}
static int micron_nand_on_die_8_ooblayout_free(struct mtd_info *mtd,
int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if (section)
return -ERANGE;
oobregion->offset = 2;
oobregion->length = mtd->oobsize - chip->ecc.total - 2;
return 0;
}
static const struct mtd_ooblayout_ops micron_nand_on_die_8_ooblayout_ops = {
.ecc = micron_nand_on_die_8_ooblayout_ecc,
.free = micron_nand_on_die_8_ooblayout_free,
};
static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
{
struct micron_nand *micron = nand_get_manufacturer_data(chip);
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
int ret;
if (micron->ecc.forced)
return 0;
if (micron->ecc.enabled == enable)
return 0;
if (enable)
feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
return nand_set_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
ret = nand_set_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
if (!ret)
micron->ecc.enabled = enable;
return ret;
}
static int micron_nand_on_die_ecc_status_4(struct nand_chip *chip, u8 status,
void *buf, int page,
int oob_required)
{
struct micron_nand *micron = nand_get_manufacturer_data(chip);
struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int step, max_bitflips = 0;
int ret;
if (!(status & NAND_ECC_STATUS_WRITE_RECOMMENDED)) {
if (status & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++;
return 0;
}
/*
* The internal ECC doesn't tell us the number of bitflips that have
* been corrected, but tells us if it recommends to rewrite the block.
* If it's the case, we need to read the page in raw mode and compare
* its content to the corrected version to extract the actual number of
* bitflips.
* But before we do that, we must make sure we have all OOB bytes read
* in non-raw mode, even if the user did not request those bytes.
*/
if (!oob_required) {
ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
false);
if (ret)
return ret;
}
micron_nand_on_die_ecc_setup(chip, false);
ret = nand_read_page_op(chip, page, 0, micron->ecc.rawbuf,
mtd->writesize + mtd->oobsize);
if (ret)
return ret;
for (step = 0; step < chip->ecc.steps; step++) {
unsigned int offs, i, nbitflips = 0;
u8 *rawbuf, *corrbuf;
offs = step * chip->ecc.size;
rawbuf = micron->ecc.rawbuf + offs;
corrbuf = buf + offs;
for (i = 0; i < chip->ecc.size; i++)
nbitflips += hweight8(corrbuf[i] ^ rawbuf[i]);
offs = (step * 16) + 4;
rawbuf = micron->ecc.rawbuf + mtd->writesize + offs;
corrbuf = chip->oob_poi + offs;
for (i = 0; i < chip->ecc.bytes + 4; i++)
nbitflips += hweight8(corrbuf[i] ^ rawbuf[i]);
if (WARN_ON(nbitflips > chip->ecc.strength))
return -EINVAL;
max_bitflips = max(nbitflips, max_bitflips);
mtd->ecc_stats.corrected += nbitflips;
}
return max_bitflips;
}
static int micron_nand_on_die_ecc_status_8(struct nand_chip *chip, u8 status)
{
struct mtd_info *mtd = nand_to_mtd(chip);
/*
* With 8/512 we have more information but still don't know precisely
* how many bit-flips were seen.
*/
switch (status & NAND_ECC_STATUS_MASK) {
case NAND_ECC_STATUS_UNCORRECTABLE:
mtd->ecc_stats.failed++;
return 0;
case NAND_ECC_STATUS_1_3_CORRECTED:
mtd->ecc_stats.corrected += 3;
return 3;
case NAND_ECC_STATUS_4_6_CORRECTED:
mtd->ecc_stats.corrected += 6;
/* rewrite recommended */
return 6;
case NAND_ECC_STATUS_7_8_CORRECTED:
mtd->ecc_stats.corrected += 8;
/* rewrite recommended */
return 8;
default:
return 0;
}
}
static int
@ -137,24 +313,18 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
if (ret)
goto out;
if (status & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++;
/*
* The internal ECC doesn't tell us the number of bitflips
* that have been corrected, but tells us if it recommends to
* rewrite the block. If it's the case, then we pretend we had
* a number of bitflips equal to the ECC strength, which will
* hint the NAND core to rewrite the block.
*/
else if (status & NAND_STATUS_WRITE_RECOMMENDED)
max_bitflips = chip->ecc.strength;
ret = nand_read_data_op(chip, buf, mtd->writesize, false);
if (!ret && oob_required)
ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
false);
if (chip->ecc.strength == 4)
max_bitflips = micron_nand_on_die_ecc_status_4(chip, status,
buf, page,
oob_required);
else
max_bitflips = micron_nand_on_die_ecc_status_8(chip, status);
out:
micron_nand_on_die_ecc_setup(chip, false);
@ -195,6 +365,9 @@ enum {
MICRON_ON_DIE_MANDATORY,
};
#define MICRON_ID_INTERNAL_ECC_MASK GENMASK(1, 0)
#define MICRON_ID_ECC_ENABLED BIT(7)
/*
* Try to detect if the NAND support on-die ECC. To do this, we enable
* the feature, and read back if it has been enabled as expected. We
@ -207,42 +380,52 @@ enum {
*/
static int micron_supports_on_die_ecc(struct nand_chip *chip)
{
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
u8 id[5];
int ret;
if (!chip->parameters.onfi.version)
if (!chip->parameters.onfi)
return MICRON_ON_DIE_UNSUPPORTED;
if (chip->bits_per_cell != 1)
return MICRON_ON_DIE_UNSUPPORTED;
/*
* We only support on-die ECC of 4/512 or 8/512
*/
if (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8)
return MICRON_ON_DIE_UNSUPPORTED;
/* 0x2 means on-die ECC is available. */
if (chip->id.len != 5 ||
(chip->id.data[4] & MICRON_ID_INTERNAL_ECC_MASK) != 0x2)
return MICRON_ON_DIE_UNSUPPORTED;
ret = micron_nand_on_die_ecc_setup(chip, true);
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
if (ret < 0)
return ret;
ret = nand_readid_op(chip, 0, id, sizeof(id));
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0)
if (!(id[4] & MICRON_ID_ECC_ENABLED))
return MICRON_ON_DIE_UNSUPPORTED;
ret = micron_nand_on_die_ecc_setup(chip, false);
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
ret = nand_get_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
if (ret < 0)
return ret;
ret = nand_readid_op(chip, 0, id, sizeof(id));
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN)
if (id[4] & MICRON_ID_ECC_ENABLED)
return MICRON_ON_DIE_MANDATORY;
/*
* Some Micron NANDs have an on-die ECC of 4/512, some other
* 8/512. We only support the former.
* We only support on-die ECC of 4/512 or 8/512
*/
if (chip->ecc_strength_ds != 4)
if (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8)
return MICRON_ON_DIE_UNSUPPORTED;
return MICRON_ON_DIE_SUPPORTED;
@ -251,44 +434,116 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
static int micron_nand_init(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct micron_nand *micron;
int ondie;
int ret;
micron = kzalloc(sizeof(*micron), GFP_KERNEL);
if (!micron)
return -ENOMEM;
nand_set_manufacturer_data(chip, micron);
ret = micron_nand_onfi_init(chip);
if (ret)
return ret;
goto err_free_manuf_data;
if (mtd->writesize == 2048)
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
ondie = micron_supports_on_die_ecc(chip);
if (ondie == MICRON_ON_DIE_MANDATORY) {
if (ondie == MICRON_ON_DIE_MANDATORY &&
chip->ecc.mode != NAND_ECC_ON_DIE) {
pr_err("On-die ECC forcefully enabled, not supported\n");
return -EINVAL;
ret = -EINVAL;
goto err_free_manuf_data;
}
if (chip->ecc.mode == NAND_ECC_ON_DIE) {
if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
pr_err("On-die ECC selected but not supported\n");
return -EINVAL;
ret = -EINVAL;
goto err_free_manuf_data;
}
chip->ecc.bytes = 8;
if (ondie == MICRON_ON_DIE_MANDATORY) {
micron->ecc.forced = true;
micron->ecc.enabled = true;
}
/*
* In case of 4bit on-die ECC, we need a buffer to store a
* page dumped in raw mode so that we can compare its content
* to the same page after ECC correction happened and extract
* the real number of bitflips from this comparison.
* That's not needed for 8-bit ECC, because the status expose
* a better approximation of the number of bitflips in a page.
*/
if (chip->ecc_strength_ds == 4) {
micron->ecc.rawbuf = kmalloc(mtd->writesize +
mtd->oobsize,
GFP_KERNEL);
if (!micron->ecc.rawbuf) {
ret = -ENOMEM;
goto err_free_manuf_data;
}
}
if (chip->ecc_strength_ds == 4)
mtd_set_ooblayout(mtd,
&micron_nand_on_die_4_ooblayout_ops);
else
mtd_set_ooblayout(mtd,
&micron_nand_on_die_8_ooblayout_ops);
chip->ecc.bytes = chip->ecc_strength_ds * 2;
chip->ecc.size = 512;
chip->ecc.strength = 4;
chip->ecc.strength = chip->ecc_strength_ds;
chip->ecc.algo = NAND_ECC_BCH;
chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
chip->ecc.read_page_raw = nand_read_page_raw;
chip->ecc.write_page_raw = nand_write_page_raw;
mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops);
if (ondie == MICRON_ON_DIE_MANDATORY) {
chip->ecc.read_page_raw = nand_read_page_raw_notsupp;
chip->ecc.write_page_raw = nand_write_page_raw_notsupp;
} else {
chip->ecc.read_page_raw = nand_read_page_raw;
chip->ecc.write_page_raw = nand_write_page_raw;
}
}
return 0;
err_free_manuf_data:
kfree(micron->ecc.rawbuf);
kfree(micron);
return ret;
}
static void micron_nand_cleanup(struct nand_chip *chip)
{
struct micron_nand *micron = nand_get_manufacturer_data(chip);
kfree(micron->ecc.rawbuf);
kfree(micron);
}
static void micron_fixup_onfi_param_page(struct nand_chip *chip,
struct nand_onfi_params *p)
{
/*
* MT29F1G08ABAFAWP-ITE:F and possibly others report 00 00 for the
* revision number field of the ONFI parameter page. Assume ONFI
* version 1.0 if the revision number is 00 00.
*/
if (le16_to_cpu(p->revision) == 0)
p->revision = cpu_to_le16(ONFI_VERSION_1_0);
}
const struct nand_manufacturer_ops micron_nand_manuf_ops = {
.init = micron_nand_init,
.cleanup = micron_nand_cleanup,
.fixup_onfi_param_page = micron_fixup_onfi_param_page,
};

View file

@ -13,6 +13,8 @@
#include <linux/export.h>
#include <linux/mtd/rawnand.h>
#define ONFI_DYN_TIMING_MAX U16_MAX
static const struct nand_data_interface onfi_sdr_timings[] = {
/* Mode 0 */
{
@ -292,6 +294,7 @@ int onfi_fill_data_interface(struct nand_chip *chip,
int timing_mode)
{
struct nand_data_interface *iface = &chip->data_interface;
struct onfi_params *onfi = chip->parameters.onfi;
if (type != NAND_SDR_IFACE)
return -EINVAL;
@ -303,20 +306,35 @@ int onfi_fill_data_interface(struct nand_chip *chip,
/*
* Initialize timings that cannot be deduced from timing mode:
* tR, tPROG, tCCS, ...
* tPROG, tBERS, tR and tCCS.
* These information are part of the ONFI parameter page.
*/
if (chip->parameters.onfi.version) {
struct nand_parameters *params = &chip->parameters;
if (onfi) {
struct nand_sdr_timings *timings = &iface->timings.sdr;
/* microseconds -> picoseconds */
timings->tPROG_max = 1000000ULL * params->onfi.tPROG;
timings->tBERS_max = 1000000ULL * params->onfi.tBERS;
timings->tR_max = 1000000ULL * params->onfi.tR;
timings->tPROG_max = 1000000ULL * onfi->tPROG;
timings->tBERS_max = 1000000ULL * onfi->tBERS;
timings->tR_max = 1000000ULL * onfi->tR;
/* nanoseconds -> picoseconds */
timings->tCCS_min = 1000UL * params->onfi.tCCS;
timings->tCCS_min = 1000UL * onfi->tCCS;
} else {
struct nand_sdr_timings *timings = &iface->timings.sdr;
/*
* For non-ONFI chips we use the highest possible value for
* tPROG and tBERS. tR and tCCS will take the default values
* precised in the ONFI specification for timing mode 0,
* respectively 200us and 500ns.
*/
/* microseconds -> picoseconds */
timings->tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX;
timings->tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX;
timings->tR_max = 1000000ULL * 200000000ULL;
/* nanoseconds -> picoseconds */
timings->tCCS_min = 1000UL * 500000;
}
return 0;

View file

@ -2192,6 +2192,48 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
return;
}
static int ns_attach_chip(struct nand_chip *chip)
{
unsigned int eccsteps, eccbytes;
if (!bch)
return 0;
if (!mtd_nand_has_bch()) {
NS_ERR("BCH ECC support is disabled\n");
return -EINVAL;
}
/* Use 512-byte ecc blocks */
eccsteps = nsmtd->writesize / 512;
eccbytes = ((bch * 13) + 7) / 8;
/* Do not bother supporting small page devices */
if (nsmtd->oobsize < 64 || !eccsteps) {
NS_ERR("BCH not available on small page devices\n");
return -EINVAL;
}
if (((eccbytes * eccsteps) + 2) > nsmtd->oobsize) {
NS_ERR("Invalid BCH value %u\n", bch);
return -EINVAL;
}
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_BCH;
chip->ecc.size = 512;
chip->ecc.strength = bch;
chip->ecc.bytes = eccbytes;
NS_INFO("Using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
return 0;
}
static const struct nand_controller_ops ns_controller_ops = {
.attach_chip = ns_attach_chip,
};
/*
* Module initialization function
*/
@ -2276,44 +2318,10 @@ static int __init ns_init_module(void)
if ((retval = parse_gravepages()) != 0)
goto error;
retval = nand_scan_ident(nsmtd, 1, NULL);
chip->dummy_controller.ops = &ns_controller_ops;
retval = nand_scan(nsmtd, 1);
if (retval) {
NS_ERR("cannot scan NAND Simulator device\n");
goto error;
}
if (bch) {
unsigned int eccsteps, eccbytes;
if (!mtd_nand_has_bch()) {
NS_ERR("BCH ECC support is disabled\n");
retval = -EINVAL;
goto error;
}
/* use 512-byte ecc blocks */
eccsteps = nsmtd->writesize/512;
eccbytes = (bch*13+7)/8;
/* do not bother supporting small page devices */
if ((nsmtd->oobsize < 64) || !eccsteps) {
NS_ERR("bch not available on small page devices\n");
retval = -EINVAL;
goto error;
}
if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
NS_ERR("invalid bch value %u\n", bch);
retval = -EINVAL;
goto error;
}
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_BCH;
chip->ecc.size = 512;
chip->ecc.strength = bch;
chip->ecc.bytes = eccbytes;
NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
}
retval = nand_scan_tail(nsmtd);
if (retval) {
NS_ERR("can't register NAND Simulator\n");
NS_ERR("Could not scan NAND Simulator device\n");
goto error;
}
@ -2337,7 +2345,7 @@ static int __init ns_init_module(void)
if ((retval = init_nandsim(nsmtd)) != 0)
goto err_exit;
if ((retval = chip->scan_bbt(nsmtd)) != 0)
if ((retval = nand_create_bbt(chip)) != 0)
goto err_exit;
if ((retval = parse_badblocks(nand, nsmtd)) != 0)

View file

@ -39,7 +39,7 @@ struct ndfc_controller {
void __iomem *ndfcbase;
struct nand_chip chip;
int chip_select;
struct nand_hw_control ndfc_control;
struct nand_controller ndfc_control;
};
static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
@ -218,7 +218,7 @@ static int ndfc_probe(struct platform_device *ofdev)
ndfc = &ndfc_ctrl[cs];
ndfc->chip_select = cs;
nand_hw_control_init(&ndfc->ndfc_control);
nand_controller_init(&ndfc->ndfc_control);
ndfc->ofdev = ofdev;
dev_set_drvdata(&ofdev->dev, ndfc);

View file

@ -144,12 +144,6 @@ static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
0xac, 0x6b, 0xff, 0x99, 0x7b};
static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
/* Shared among all NAND instances to synchronize access to the ECC Engine */
static struct nand_hw_control omap_gpmc_controller = {
.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
};
struct omap_nand_info {
struct nand_chip nand;
struct platform_device *pdev;
@ -1915,17 +1909,278 @@ static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
.free = omap_sw_ooblayout_free,
};
static int omap_nand_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
struct device *dev = &info->pdev->dev;
int min_oobbytes = BADBLOCK_MARKER_LENGTH;
int oobbytes_per_step;
dma_cap_mask_t mask;
int err;
if (chip->bbt_options & NAND_BBT_USE_FLASH)
chip->bbt_options |= NAND_BBT_NO_OOB;
else
chip->options |= NAND_SKIP_BBTSCAN;
/* Re-populate low-level callbacks based on xfer modes */
switch (info->xfer_type) {
case NAND_OMAP_PREFETCH_POLLED:
chip->read_buf = omap_read_buf_pref;
chip->write_buf = omap_write_buf_pref;
break;
case NAND_OMAP_POLLED:
/* Use nand_base defaults for {read,write}_buf */
break;
case NAND_OMAP_PREFETCH_DMA:
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
info->dma = dma_request_chan(dev, "rxtx");
if (IS_ERR(info->dma)) {
dev_err(dev, "DMA engine request failed\n");
return PTR_ERR(info->dma);
} else {
struct dma_slave_config cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.src_addr = info->phys_base;
cfg.dst_addr = info->phys_base;
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.src_maxburst = 16;
cfg.dst_maxburst = 16;
err = dmaengine_slave_config(info->dma, &cfg);
if (err) {
dev_err(dev,
"DMA engine slave config failed: %d\n",
err);
return err;
}
chip->read_buf = omap_read_buf_dma_pref;
chip->write_buf = omap_write_buf_dma_pref;
}
break;
case NAND_OMAP_PREFETCH_IRQ:
info->gpmc_irq_fifo = platform_get_irq(info->pdev, 0);
if (info->gpmc_irq_fifo <= 0) {
dev_err(dev, "Error getting fifo IRQ\n");
return -ENODEV;
}
err = devm_request_irq(dev, info->gpmc_irq_fifo,
omap_nand_irq, IRQF_SHARED,
"gpmc-nand-fifo", info);
if (err) {
dev_err(dev, "Requesting IRQ %d, error %d\n",
info->gpmc_irq_fifo, err);
info->gpmc_irq_fifo = 0;
return err;
}
info->gpmc_irq_count = platform_get_irq(info->pdev, 1);
if (info->gpmc_irq_count <= 0) {
dev_err(dev, "Error getting IRQ count\n");
return -ENODEV;
}
err = devm_request_irq(dev, info->gpmc_irq_count,
omap_nand_irq, IRQF_SHARED,
"gpmc-nand-count", info);
if (err) {
dev_err(dev, "Requesting IRQ %d, error %d\n",
info->gpmc_irq_count, err);
info->gpmc_irq_count = 0;
return err;
}
chip->read_buf = omap_read_buf_irq_pref;
chip->write_buf = omap_write_buf_irq_pref;
break;
default:
dev_err(dev, "xfer_type %d not supported!\n", info->xfer_type);
return -EINVAL;
}
if (!omap2_nand_ecc_check(info))
return -EINVAL;
/*
* Bail out earlier to let NAND_ECC_SOFT code create its own
* ooblayout instead of using ours.
*/
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
return 0;
}
/* Populate MTD interface based on ECC scheme */
switch (info->ecc_opt) {
case OMAP_ECC_HAM1_CODE_HW:
dev_info(dev, "nand: using OMAP_ECC_HAM1_CODE_HW\n");
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.bytes = 3;
chip->ecc.size = 512;
chip->ecc.strength = 1;
chip->ecc.calculate = omap_calculate_ecc;
chip->ecc.hwctl = omap_enable_hwecc;
chip->ecc.correct = omap_correct_data;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
if (!(chip->options & NAND_BUSWIDTH_16))
min_oobbytes = 1;
break;
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 512;
chip->ecc.bytes = 7;
chip->ecc.strength = 4;
chip->ecc.hwctl = omap_enable_hwecc_bch;
chip->ecc.correct = nand_bch_correct_data;
chip->ecc.calculate = omap_calculate_ecc_bch_sw;
mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
/* Reserve one byte for the OMAP marker */
oobbytes_per_step = chip->ecc.bytes + 1;
/* Software BCH library is used for locating errors */
chip->ecc.priv = nand_bch_init(mtd);
if (!chip->ecc.priv) {
dev_err(dev, "Unable to use BCH library\n");
return -EINVAL;
}
break;
case OMAP_ECC_BCH4_CODE_HW:
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 512;
/* 14th bit is kept reserved for ROM-code compatibility */
chip->ecc.bytes = 7 + 1;
chip->ecc.strength = 4;
chip->ecc.hwctl = omap_enable_hwecc_bch;
chip->ecc.correct = omap_elm_correct_data;
chip->ecc.read_page = omap_read_page_bch;
chip->ecc.write_page = omap_write_page_bch;
chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
err = elm_config(info->elm_dev, BCH4_ECC,
mtd->writesize / chip->ecc.size,
chip->ecc.size, chip->ecc.bytes);
if (err < 0)
return err;
break;
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 512;
chip->ecc.bytes = 13;
chip->ecc.strength = 8;
chip->ecc.hwctl = omap_enable_hwecc_bch;
chip->ecc.correct = nand_bch_correct_data;
chip->ecc.calculate = omap_calculate_ecc_bch_sw;
mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
/* Reserve one byte for the OMAP marker */
oobbytes_per_step = chip->ecc.bytes + 1;
/* Software BCH library is used for locating errors */
chip->ecc.priv = nand_bch_init(mtd);
if (!chip->ecc.priv) {
dev_err(dev, "unable to use BCH library\n");
return -EINVAL;
}
break;
case OMAP_ECC_BCH8_CODE_HW:
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 512;
/* 14th bit is kept reserved for ROM-code compatibility */
chip->ecc.bytes = 13 + 1;
chip->ecc.strength = 8;
chip->ecc.hwctl = omap_enable_hwecc_bch;
chip->ecc.correct = omap_elm_correct_data;
chip->ecc.read_page = omap_read_page_bch;
chip->ecc.write_page = omap_write_page_bch;
chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
err = elm_config(info->elm_dev, BCH8_ECC,
mtd->writesize / chip->ecc.size,
chip->ecc.size, chip->ecc.bytes);
if (err < 0)
return err;
break;
case OMAP_ECC_BCH16_CODE_HW:
pr_info("Using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 512;
chip->ecc.bytes = 26;
chip->ecc.strength = 16;
chip->ecc.hwctl = omap_enable_hwecc_bch;
chip->ecc.correct = omap_elm_correct_data;
chip->ecc.read_page = omap_read_page_bch;
chip->ecc.write_page = omap_write_page_bch;
chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
err = elm_config(info->elm_dev, BCH16_ECC,
mtd->writesize / chip->ecc.size,
chip->ecc.size, chip->ecc.bytes);
if (err < 0)
return err;
break;
default:
dev_err(dev, "Invalid or unsupported ECC scheme\n");
return -EINVAL;
}
/* Check if NAND device's OOB is enough to store ECC signatures */
min_oobbytes += (oobbytes_per_step *
(mtd->writesize / chip->ecc.size));
if (mtd->oobsize < min_oobbytes) {
dev_err(dev,
"Not enough OOB bytes: required = %d, available=%d\n",
min_oobbytes, mtd->oobsize);
return -EINVAL;
}
return 0;
}
static const struct nand_controller_ops omap_nand_controller_ops = {
.attach_chip = omap_nand_attach_chip,
};
/* Shared among all NAND instances to synchronize access to the ECC Engine */
static struct nand_controller omap_gpmc_controller = {
.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
.ops = &omap_nand_controller_ops,
};
static int omap_nand_probe(struct platform_device *pdev)
{
struct omap_nand_info *info;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
int err;
dma_cap_mask_t mask;
struct resource *res;
struct device *dev = &pdev->dev;
int min_oobbytes = BADBLOCK_MARKER_LENGTH;
int oobbytes_per_step;
info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
GFP_KERNEL);
@ -1998,266 +2253,8 @@ static int omap_nand_probe(struct platform_device *pdev)
/* scan NAND device connected to chip controller */
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
err = nand_scan_ident(mtd, 1, NULL);
if (err) {
dev_err(&info->pdev->dev,
"scan failed, may be bus-width mismatch\n");
goto return_error;
}
if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
nand_chip->bbt_options |= NAND_BBT_NO_OOB;
else
nand_chip->options |= NAND_SKIP_BBTSCAN;
/* re-populate low-level callbacks based on xfer modes */
switch (info->xfer_type) {
case NAND_OMAP_PREFETCH_POLLED:
nand_chip->read_buf = omap_read_buf_pref;
nand_chip->write_buf = omap_write_buf_pref;
break;
case NAND_OMAP_POLLED:
/* Use nand_base defaults for {read,write}_buf */
break;
case NAND_OMAP_PREFETCH_DMA:
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
if (IS_ERR(info->dma)) {
dev_err(&pdev->dev, "DMA engine request failed\n");
err = PTR_ERR(info->dma);
goto return_error;
} else {
struct dma_slave_config cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.src_addr = info->phys_base;
cfg.dst_addr = info->phys_base;
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.src_maxburst = 16;
cfg.dst_maxburst = 16;
err = dmaengine_slave_config(info->dma, &cfg);
if (err) {
dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
err);
goto return_error;
}
nand_chip->read_buf = omap_read_buf_dma_pref;
nand_chip->write_buf = omap_write_buf_dma_pref;
}
break;
case NAND_OMAP_PREFETCH_IRQ:
info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
if (info->gpmc_irq_fifo <= 0) {
dev_err(&pdev->dev, "error getting fifo irq\n");
err = -ENODEV;
goto return_error;
}
err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
omap_nand_irq, IRQF_SHARED,
"gpmc-nand-fifo", info);
if (err) {
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
info->gpmc_irq_fifo, err);
info->gpmc_irq_fifo = 0;
goto return_error;
}
info->gpmc_irq_count = platform_get_irq(pdev, 1);
if (info->gpmc_irq_count <= 0) {
dev_err(&pdev->dev, "error getting count irq\n");
err = -ENODEV;
goto return_error;
}
err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
omap_nand_irq, IRQF_SHARED,
"gpmc-nand-count", info);
if (err) {
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
info->gpmc_irq_count, err);
info->gpmc_irq_count = 0;
goto return_error;
}
nand_chip->read_buf = omap_read_buf_irq_pref;
nand_chip->write_buf = omap_write_buf_irq_pref;
break;
default:
dev_err(&pdev->dev,
"xfer_type(%d) not supported!\n", info->xfer_type);
err = -EINVAL;
goto return_error;
}
if (!omap2_nand_ecc_check(info)) {
err = -EINVAL;
goto return_error;
}
/*
* Bail out earlier to let NAND_ECC_SOFT code create its own
* ooblayout instead of using ours.
*/
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
nand_chip->ecc.mode = NAND_ECC_SOFT;
nand_chip->ecc.algo = NAND_ECC_HAMMING;
goto scan_tail;
}
/* populate MTD interface based on ECC scheme */
switch (info->ecc_opt) {
case OMAP_ECC_HAM1_CODE_HW:
pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.bytes = 3;
nand_chip->ecc.size = 512;
nand_chip->ecc.strength = 1;
nand_chip->ecc.calculate = omap_calculate_ecc;
nand_chip->ecc.hwctl = omap_enable_hwecc;
nand_chip->ecc.correct = omap_correct_data;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = nand_chip->ecc.bytes;
if (!(nand_chip->options & NAND_BUSWIDTH_16))
min_oobbytes = 1;
break;
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512;
nand_chip->ecc.bytes = 7;
nand_chip->ecc.strength = 4;
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
nand_chip->ecc.correct = nand_bch_correct_data;
nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw;
mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
/* Reserve one byte for the OMAP marker */
oobbytes_per_step = nand_chip->ecc.bytes + 1;
/* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd);
if (!nand_chip->ecc.priv) {
dev_err(&info->pdev->dev, "unable to use BCH library\n");
err = -EINVAL;
goto return_error;
}
break;
case OMAP_ECC_BCH4_CODE_HW:
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512;
/* 14th bit is kept reserved for ROM-code compatibility */
nand_chip->ecc.bytes = 7 + 1;
nand_chip->ecc.strength = 4;
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
nand_chip->ecc.correct = omap_elm_correct_data;
nand_chip->ecc.read_page = omap_read_page_bch;
nand_chip->ecc.write_page = omap_write_page_bch;
nand_chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = nand_chip->ecc.bytes;
err = elm_config(info->elm_dev, BCH4_ECC,
mtd->writesize / nand_chip->ecc.size,
nand_chip->ecc.size, nand_chip->ecc.bytes);
if (err < 0)
goto return_error;
break;
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512;
nand_chip->ecc.bytes = 13;
nand_chip->ecc.strength = 8;
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
nand_chip->ecc.correct = nand_bch_correct_data;
nand_chip->ecc.calculate = omap_calculate_ecc_bch_sw;
mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
/* Reserve one byte for the OMAP marker */
oobbytes_per_step = nand_chip->ecc.bytes + 1;
/* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd);
if (!nand_chip->ecc.priv) {
dev_err(&info->pdev->dev, "unable to use BCH library\n");
err = -EINVAL;
goto return_error;
}
break;
case OMAP_ECC_BCH8_CODE_HW:
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512;
/* 14th bit is kept reserved for ROM-code compatibility */
nand_chip->ecc.bytes = 13 + 1;
nand_chip->ecc.strength = 8;
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
nand_chip->ecc.correct = omap_elm_correct_data;
nand_chip->ecc.read_page = omap_read_page_bch;
nand_chip->ecc.write_page = omap_write_page_bch;
nand_chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = nand_chip->ecc.bytes;
err = elm_config(info->elm_dev, BCH8_ECC,
mtd->writesize / nand_chip->ecc.size,
nand_chip->ecc.size, nand_chip->ecc.bytes);
if (err < 0)
goto return_error;
break;
case OMAP_ECC_BCH16_CODE_HW:
pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n");
nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512;
nand_chip->ecc.bytes = 26;
nand_chip->ecc.strength = 16;
nand_chip->ecc.hwctl = omap_enable_hwecc_bch;
nand_chip->ecc.correct = omap_elm_correct_data;
nand_chip->ecc.read_page = omap_read_page_bch;
nand_chip->ecc.write_page = omap_write_page_bch;
nand_chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = nand_chip->ecc.bytes;
err = elm_config(info->elm_dev, BCH16_ECC,
mtd->writesize / nand_chip->ecc.size,
nand_chip->ecc.size, nand_chip->ecc.bytes);
if (err < 0)
goto return_error;
break;
default:
dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
err = -EINVAL;
goto return_error;
}
/* check if NAND device's OOB is enough to store ECC signatures */
min_oobbytes += (oobbytes_per_step *
(mtd->writesize / nand_chip->ecc.size));
if (mtd->oobsize < min_oobbytes) {
dev_err(&info->pdev->dev,
"not enough OOB bytes required = %d, available=%d\n",
min_oobbytes, mtd->oobsize);
err = -EINVAL;
goto return_error;
}
scan_tail:
/* second phase scan */
err = nand_scan_tail(mtd);
err = nand_scan(mtd, 1);
if (err)
goto return_error;

View file

@ -18,7 +18,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <asm/sizes.h>
#include <linux/sizes.h>
#include <linux/platform_data/mtd-orion_nand.h>
struct orion_nand_info {
@ -52,7 +52,7 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
void __iomem *io_base = chip->IO_ADDR_R;
#if __LINUX_ARM_ARCH__ >= 5
#if defined(__LINUX_ARM_ARCH__) && __LINUX_ARM_ARCH__ >= 5
uint64_t *buf64;
#endif
int i = 0;
@ -61,7 +61,7 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
*buf++ = readb(io_base);
len--;
}
#if __LINUX_ARM_ARCH__ >= 5
#if defined(__LINUX_ARM_ARCH__) && __LINUX_ARM_ARCH__ >= 5
buf64 = (uint64_t *)buf;
while (i < len/8) {
/*
@ -153,9 +153,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
if (board->width == 16)
nc->options |= NAND_BUSWIDTH_16;
if (board->dev_ready)
nc->dev_ready = board->dev_ready;
platform_set_drvdata(pdev, info);
/* Not all platforms can gate the clock, so it is not

View file

@ -32,7 +32,7 @@
#define OXNAS_NAND_MAX_CHIPS 1
struct oxnas_nand_ctrl {
struct nand_hw_control base;
struct nand_controller base;
void __iomem *io_base;
struct clk *clk;
struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
@ -96,7 +96,7 @@ static int oxnas_nand_probe(struct platform_device *pdev)
if (!oxnas)
return -ENOMEM;
nand_hw_control_init(&oxnas->base);
nand_controller_init(&oxnas->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);

View file

@ -67,12 +67,10 @@ static int plat_nand_probe(struct platform_device *pdev)
data->chip.select_chip = pdata->ctrl.select_chip;
data->chip.write_buf = pdata->ctrl.write_buf;
data->chip.read_buf = pdata->ctrl.read_buf;
data->chip.read_byte = pdata->ctrl.read_byte;
data->chip.chip_delay = pdata->chip.chip_delay;
data->chip.options |= pdata->chip.options;
data->chip.bbt_options |= pdata->chip.bbt_options;
data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
data->chip.ecc.mode = NAND_ECC_SOFT;
data->chip.ecc.algo = NAND_ECC_HAMMING;

View file

@ -213,6 +213,8 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \
#define QPIC_PER_CW_CMD_SGL 32
#define QPIC_PER_CW_DATA_SGL 8
#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
/*
* Flags used in DMA descriptor preparation helper functions
* (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma)
@ -245,6 +247,11 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \
* @tx_sgl_start - start index in data sgl for tx.
* @rx_sgl_pos - current index in data sgl for rx.
* @rx_sgl_start - start index in data sgl for rx.
* @wait_second_completion - wait for second DMA desc completion before making
* the NAND transfer completion.
* @txn_done - completion for NAND transfer.
* @last_data_desc - last DMA desc in data channel (tx/rx).
* @last_cmd_desc - last DMA desc in command channel.
*/
struct bam_transaction {
struct bam_cmd_element *bam_ce;
@ -258,6 +265,10 @@ struct bam_transaction {
u32 tx_sgl_start;
u32 rx_sgl_pos;
u32 rx_sgl_start;
bool wait_second_completion;
struct completion txn_done;
struct dma_async_tx_descriptor *last_data_desc;
struct dma_async_tx_descriptor *last_cmd_desc;
};
/*
@ -354,7 +365,7 @@ struct nandc_regs {
* from all connected NAND devices pagesize
*/
struct qcom_nand_controller {
struct nand_hw_control controller;
struct nand_controller controller;
struct list_head host_list;
struct device *dev;
@ -504,6 +515,8 @@ alloc_bam_transaction(struct qcom_nand_controller *nandc)
bam_txn->data_sgl = bam_txn_buf;
init_completion(&bam_txn->txn_done);
return bam_txn;
}
@ -523,11 +536,33 @@ static void clear_bam_transaction(struct qcom_nand_controller *nandc)
bam_txn->tx_sgl_start = 0;
bam_txn->rx_sgl_pos = 0;
bam_txn->rx_sgl_start = 0;
bam_txn->last_data_desc = NULL;
bam_txn->wait_second_completion = false;
sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage *
QPIC_PER_CW_CMD_SGL);
sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage *
QPIC_PER_CW_DATA_SGL);
reinit_completion(&bam_txn->txn_done);
}
/* Callback for DMA descriptor completion */
static void qpic_bam_dma_done(void *data)
{
struct bam_transaction *bam_txn = data;
/*
* In case of data transfer with NAND, 2 callbacks will be generated.
* One for command channel and another one for data channel.
* If current transaction has data descriptors
* (i.e. wait_second_completion is true), then set this to false
* and wait for second DMA descriptor completion.
*/
if (bam_txn->wait_second_completion)
bam_txn->wait_second_completion = false;
else
complete(&bam_txn->txn_done);
}
static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
@ -756,6 +791,12 @@ static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
desc->dma_desc = dma_desc;
/* update last data/command descriptor */
if (chan == nandc->cmd_chan)
bam_txn->last_cmd_desc = dma_desc;
else
bam_txn->last_data_desc = dma_desc;
list_add_tail(&desc->node, &nandc->desc_list);
return 0;
@ -1055,7 +1096,8 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc)
* Helper to prepare DMA descriptors for configuring registers
* before reading each codeword in NAND page.
*/
static void config_nand_cw_read(struct qcom_nand_controller *nandc)
static void
config_nand_cw_read(struct qcom_nand_controller *nandc, bool use_ecc)
{
if (nandc->props->is_bam)
write_reg_dma(nandc, NAND_READ_LOCATION_0, 4,
@ -1064,19 +1106,25 @@ static void config_nand_cw_read(struct qcom_nand_controller *nandc)
write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
NAND_BAM_NEXT_SGL);
if (use_ecc) {
read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0);
read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1,
NAND_BAM_NEXT_SGL);
} else {
read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
}
}
/*
* Helper to prepare dma descriptors to configure registers needed for reading a
* single codeword in page
*/
static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc)
static void
config_nand_single_cw_page_read(struct qcom_nand_controller *nandc,
bool use_ecc)
{
config_nand_page_read(nandc);
config_nand_cw_read(nandc);
config_nand_cw_read(nandc, use_ecc);
}
/*
@ -1157,7 +1205,7 @@ static int nandc_param(struct qcom_nand_host *host)
nandc->buf_count = 512;
memset(nandc->data_buffer, 0xff, nandc->buf_count);
config_nand_single_cw_page_read(nandc);
config_nand_single_cw_page_read(nandc, false);
read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
nandc->buf_count, 0);
@ -1273,10 +1321,20 @@ static int submit_descs(struct qcom_nand_controller *nandc)
cookie = dmaengine_submit(desc->dma_desc);
if (nandc->props->is_bam) {
bam_txn->last_cmd_desc->callback = qpic_bam_dma_done;
bam_txn->last_cmd_desc->callback_param = bam_txn;
if (bam_txn->last_data_desc) {
bam_txn->last_data_desc->callback = qpic_bam_dma_done;
bam_txn->last_data_desc->callback_param = bam_txn;
bam_txn->wait_second_completion = true;
}
dma_async_issue_pending(nandc->tx_chan);
dma_async_issue_pending(nandc->rx_chan);
dma_async_issue_pending(nandc->cmd_chan);
if (dma_sync_wait(nandc->cmd_chan, cookie) != DMA_COMPLETE)
if (!wait_for_completion_timeout(&bam_txn->txn_done,
QPIC_NAND_COMPLETION_TIMEOUT))
return -ETIMEDOUT;
} else {
if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE)
@ -1512,20 +1570,180 @@ struct read_stats {
__le32 erased_cw;
};
/* reads back FLASH_STATUS register set by the controller */
static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt)
{
struct nand_chip *chip = &host->chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
int i;
for (i = 0; i < cw_cnt; i++) {
u32 flash = le32_to_cpu(nandc->reg_read_buf[i]);
if (flash & (FS_OP_ERR | FS_MPU_ERR))
return -EIO;
}
return 0;
}
/* performs raw read for one codeword */
static int
qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip,
u8 *data_buf, u8 *oob_buf, int page, int cw)
{
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int data_size1, data_size2, oob_size1, oob_size2;
int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
nand_read_page_op(chip, page, 0, NULL, 0);
host->use_ecc = false;
clear_bam_transaction(nandc);
set_address(host, host->cw_size * cw, page);
update_rw_regs(host, 1, true);
config_nand_page_read(nandc);
data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
oob_size1 = host->bbm_size;
if (cw == (ecc->steps - 1)) {
data_size2 = ecc->size - data_size1 -
((ecc->steps - 1) * 4);
oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw +
host->spare_bytes;
} else {
data_size2 = host->cw_data - data_size1;
oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
}
if (nandc->props->is_bam) {
nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0);
read_loc += data_size1;
nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0);
read_loc += oob_size1;
nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0);
read_loc += data_size2;
nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
}
config_nand_cw_read(nandc, false);
read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
reg_off += data_size1;
read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
reg_off += oob_size1;
read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0);
reg_off += data_size2;
read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
ret = submit_descs(nandc);
free_descs(nandc);
if (ret) {
dev_err(nandc->dev, "failure to read raw cw %d\n", cw);
return ret;
}
return check_flash_errors(host, 1);
}
/*
* Bitflips can happen in erased codewords also so this function counts the
* number of 0 in each CW for which ECC engine returns the uncorrectable
* error. The page will be assumed as erased if this count is less than or
* equal to the ecc->strength for each CW.
*
* 1. Both DATA and OOB need to be checked for number of 0. The
* top-level API can be called with only data buf or OOB buf so use
* chip->data_buf if data buf is null and chip->oob_poi if oob buf
* is null for copying the raw bytes.
* 2. Perform raw read for all the CW which has uncorrectable errors.
* 3. For each CW, check the number of 0 in cw_data and usable OOB bytes.
* The BBM and spare bytes bit flip wont affect the ECC so dont check
* the number of bitflips in this area.
*/
static int
check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf,
u8 *oob_buf, unsigned long uncorrectable_cws,
int page, unsigned int max_bitflips)
{
struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
u8 *cw_data_buf, *cw_oob_buf;
int cw, data_size, oob_size, ret = 0;
if (!data_buf) {
data_buf = chip->data_buf;
chip->pagebuf = -1;
}
if (!oob_buf) {
oob_buf = chip->oob_poi;
chip->pagebuf = -1;
}
for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) {
if (cw == (ecc->steps - 1)) {
data_size = ecc->size - ((ecc->steps - 1) * 4);
oob_size = (ecc->steps * 4) + host->ecc_bytes_hw;
} else {
data_size = host->cw_data;
oob_size = host->ecc_bytes_hw;
}
/* determine starting buffer address for current CW */
cw_data_buf = data_buf + (cw * host->cw_data);
cw_oob_buf = oob_buf + (cw * ecc->bytes);
ret = qcom_nandc_read_cw_raw(mtd, chip, cw_data_buf,
cw_oob_buf, page, cw);
if (ret)
return ret;
/*
* make sure it isn't an erased page reported
* as not-erased by HW because of a few bitflips
*/
ret = nand_check_erased_ecc_chunk(cw_data_buf, data_size,
cw_oob_buf + host->bbm_size,
oob_size, NULL,
0, ecc->strength);
if (ret < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += ret;
max_bitflips = max_t(unsigned int, max_bitflips, ret);
}
}
return max_bitflips;
}
/*
* reads back status registers set by the controller to notify page read
* errors. this is equivalent to what 'ecc->correct()' would do.
*/
static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
u8 *oob_buf)
u8 *oob_buf, int page)
{
struct nand_chip *chip = &host->chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
unsigned int max_bitflips = 0;
unsigned int max_bitflips = 0, uncorrectable_cws = 0;
struct read_stats *buf;
bool flash_op_err = false, erased;
int i;
u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
buf = (struct read_stats *)nandc->reg_read_buf;
nandc_read_buffer_sync(nandc, true);
@ -1546,48 +1764,49 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
buffer = le32_to_cpu(buf->buffer);
erased_cw = le32_to_cpu(buf->erased_cw);
if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
bool erased;
/* ignore erased codeword errors */
/*
* Check ECC failure for each codeword. ECC failure can
* happen in either of the following conditions
* 1. If number of bitflips are greater than ECC engine
* capability.
* 2. If this codeword contains all 0xff for which erased
* codeword detection check will be done.
*/
if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
/*
* For BCH ECC, ignore erased codeword errors, if
* ERASED_CW bits are set.
*/
if (host->bch_enabled) {
erased = (erased_cw & ERASED_CW) == ERASED_CW ?
true : false;
} else {
/*
* For RS ECC, HW reports the erased CW by placing
* special characters at certain offsets in the buffer.
* These special characters will be valid only if
* complete page is read i.e. data_buf is not NULL.
*/
} else if (data_buf) {
erased = erased_chunk_check_and_fixup(data_buf,
data_len);
} else {
erased = false;
}
if (erased) {
data_buf += data_len;
if (oob_buf)
oob_buf += oob_len + ecc->bytes;
continue;
}
if (buffer & BS_UNCORRECTABLE_BIT) {
int ret, ecclen, extraooblen;
void *eccbuf;
eccbuf = oob_buf ? oob_buf + oob_len : NULL;
ecclen = oob_buf ? host->ecc_bytes_hw : 0;
extraooblen = oob_buf ? oob_len : 0;
/*
* make sure it isn't an erased page reported
* as not-erased by HW because of a few bitflips
*/
ret = nand_check_erased_ecc_chunk(data_buf,
data_len, eccbuf, ecclen, oob_buf,
extraooblen, ecc->strength);
if (ret < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += ret;
max_bitflips =
max_t(unsigned int, max_bitflips, ret);
}
}
if (!erased)
uncorrectable_cws |= BIT(i);
/*
* Check if MPU or any other operational error (timeout,
* device failure, etc.) happened for this codeword and
* make flash_op_err true. If flash_op_err is set, then
* EIO will be returned for page read.
*/
} else if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
flash_op_err = true;
/*
* No ECC or operational errors happened. Check the number of
* bits corrected and update the ecc_stats.corrected.
*/
} else {
unsigned int stat;
@ -1596,12 +1815,21 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
max_bitflips = max(max_bitflips, stat);
}
data_buf += data_len;
if (data_buf)
data_buf += data_len;
if (oob_buf)
oob_buf += oob_len + ecc->bytes;
}
return max_bitflips;
if (flash_op_err)
return -EIO;
if (!uncorrectable_cws)
return max_bitflips;
return check_for_erased_page(host, data_buf_start, oob_buf_start,
uncorrectable_cws, page,
max_bitflips);
}
/*
@ -1609,11 +1837,12 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
* ecc->read_oob()
*/
static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
u8 *oob_buf)
u8 *oob_buf, int page)
{
struct nand_chip *chip = &host->chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
int i, ret;
config_nand_page_read(nandc);
@ -1644,7 +1873,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
}
}
config_nand_cw_read(nandc);
config_nand_cw_read(nandc, true);
if (data_buf)
read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
@ -1674,12 +1903,14 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
}
ret = submit_descs(nandc);
if (ret)
dev_err(nandc->dev, "failure to read page/oob\n");
free_descs(nandc);
return ret;
if (ret) {
dev_err(nandc->dev, "failure to read page/oob\n");
return ret;
}
return parse_read_errors(host, data_buf_start, oob_buf_start, page);
}
/*
@ -1704,7 +1935,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int page)
set_address(host, host->cw_size * (ecc->steps - 1), page);
update_rw_regs(host, 1, true);
config_nand_single_cw_page_read(nandc);
config_nand_single_cw_page_read(nandc, host->use_ecc);
read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
@ -1724,20 +1955,14 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
u8 *data_buf, *oob_buf = NULL;
int ret;
nand_read_page_op(chip, page, 0, NULL, 0);
data_buf = buf;
oob_buf = oob_required ? chip->oob_poi : NULL;
clear_bam_transaction(nandc);
ret = read_page_ecc(host, data_buf, oob_buf);
if (ret) {
dev_err(nandc->dev, "failure to read page\n");
return ret;
}
return parse_read_errors(host, data_buf, oob_buf);
return read_page_ecc(host, data_buf, oob_buf, page);
}
/* implements ecc->read_page_raw() */
@ -1746,77 +1971,20 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
int oob_required, int page)
{
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
u8 *data_buf, *oob_buf;
struct nand_ecc_ctrl *ecc = &chip->ecc;
int i, ret;
int read_loc;
int cw, ret;
u8 *data_buf = buf, *oob_buf = chip->oob_poi;
nand_read_page_op(chip, page, 0, NULL, 0);
data_buf = buf;
oob_buf = chip->oob_poi;
for (cw = 0; cw < ecc->steps; cw++) {
ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf,
page, cw);
if (ret)
return ret;
host->use_ecc = false;
clear_bam_transaction(nandc);
update_rw_regs(host, ecc->steps, true);
config_nand_page_read(nandc);
for (i = 0; i < ecc->steps; i++) {
int data_size1, data_size2, oob_size1, oob_size2;
int reg_off = FLASH_BUF_ACC;
data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
oob_size1 = host->bbm_size;
if (i == (ecc->steps - 1)) {
data_size2 = ecc->size - data_size1 -
((ecc->steps - 1) << 2);
oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
host->spare_bytes;
} else {
data_size2 = host->cw_data - data_size1;
oob_size2 = host->ecc_bytes_hw + host->spare_bytes;
}
if (nandc->props->is_bam) {
read_loc = 0;
nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0);
read_loc += data_size1;
nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0);
read_loc += oob_size1;
nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0);
read_loc += data_size2;
nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1);
}
config_nand_cw_read(nandc);
read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
reg_off += data_size1;
data_buf += data_size1;
read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0);
reg_off += oob_size1;
oob_buf += oob_size1;
read_data_dma(nandc, reg_off, data_buf, data_size2, 0);
reg_off += data_size2;
data_buf += data_size2;
read_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
oob_buf += oob_size2;
data_buf += host->cw_data;
oob_buf += ecc->bytes;
}
ret = submit_descs(nandc);
if (ret)
dev_err(nandc->dev, "failure to read raw page\n");
free_descs(nandc);
return 0;
}
@ -1827,7 +1995,6 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret;
clear_read_regs(nandc);
clear_bam_transaction(nandc);
@ -1836,11 +2003,7 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
set_address(host, 0, page);
update_rw_regs(host, ecc->steps, true);
ret = read_page_ecc(host, NULL, chip->oob_poi);
if (ret)
dev_err(nandc->dev, "failure to read oob\n");
return ret;
return read_page_ecc(host, NULL, chip->oob_poi, page);
}
/* implements ecc->write_page() */
@ -1988,11 +2151,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
/*
* implements ecc->write_oob()
*
* the NAND controller cannot write only data or only oob within a codeword,
* since ecc is calculated for the combined codeword. we first copy the
* entire contents for the last codeword(data + oob), replace the old oob
* with the new one in chip->oob_poi, and then write the entire codeword.
* this read-copy-write operation results in a slight performance loss.
* the NAND controller cannot write only data or only OOB within a codeword
* since ECC is calculated for the combined codeword. So update the OOB from
* chip->oob_poi, and pad the data area with OxFF before writing.
*/
static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
@ -2005,19 +2166,13 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int ret;
host->use_ecc = true;
clear_bam_transaction(nandc);
ret = copy_last_cw(host, page);
if (ret)
return ret;
clear_read_regs(nandc);
clear_bam_transaction(nandc);
/* calculate the data and oob size for the last codeword/step */
data_size = ecc->size - ((ecc->steps - 1) << 2);
oob_size = mtd->oobavail;
memset(nandc->data_buffer, 0xff, host->cw_data);
/* override new oob content to last codeword */
mtd_ooblayout_get_databytes(mtd, nandc->data_buffer + data_size, oob,
0, mtd->oobavail);
@ -2049,7 +2204,6 @@ static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int page, ret, bbpos, bad = 0;
u32 flash_status;
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
@ -2066,9 +2220,7 @@ static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
if (ret)
goto err;
flash_status = le32_to_cpu(nandc->reg_read_buf[0]);
if (flash_status & (FS_OP_ERR | FS_MPU_ERR)) {
if (check_flash_errors(host, 1)) {
dev_warn(nandc->dev, "error when trying to read BBM\n");
goto err;
}
@ -2315,26 +2467,39 @@ static const struct mtd_ooblayout_ops qcom_nand_ooblayout_ops = {
.free = qcom_nand_ooblayout_free,
};
static int qcom_nand_host_setup(struct qcom_nand_host *host)
static int
qcom_nandc_calc_ecc_bytes(int step_size, int strength)
{
return strength == 4 ? 12 : 16;
}
NAND_ECC_CAPS_SINGLE(qcom_nandc_ecc_caps, qcom_nandc_calc_ecc_bytes,
NANDC_STEP_SIZE, 4, 8);
static int qcom_nand_attach_chip(struct nand_chip *chip)
{
struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
int cwperpage, bad_block_byte;
int cwperpage, bad_block_byte, ret;
bool wide_bus;
int ecc_mode = 1;
/*
* the controller requires each step consists of 512 bytes of data.
* bail out if DT has populated a wrong step size.
*/
if (ecc->size != NANDC_STEP_SIZE) {
dev_err(nandc->dev, "invalid ecc size\n");
return -EINVAL;
}
/* controller only supports 512 bytes data steps */
ecc->size = NANDC_STEP_SIZE;
wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
cwperpage = mtd->writesize / NANDC_STEP_SIZE;
/*
* Each CW has 4 available OOB bytes which will be protected with ECC
* so remaining bytes can be used for ECC.
*/
ret = nand_ecc_choose_conf(chip, &qcom_nandc_ecc_caps,
mtd->oobsize - (cwperpage * 4));
if (ret) {
dev_err(nandc->dev, "No valid ECC settings possible\n");
return ret;
}
if (ecc->strength >= 8) {
/* 8 bit ECC defaults to BCH ECC on all platforms */
@ -2403,7 +2568,6 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host)
mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
cwperpage = mtd->writesize / ecc->size;
nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
cwperpage);
@ -2419,12 +2583,6 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host)
* for 8 bit ECC
*/
host->cw_size = host->cw_data + ecc->bytes;
if (ecc->bytes * (mtd->writesize / ecc->size) > mtd->oobsize) {
dev_err(nandc->dev, "ecc data doesn't fit in OOB area\n");
return -EINVAL;
}
bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1;
host->cfg0 = (cwperpage - 1) << CW_PER_PAGE
@ -2482,6 +2640,10 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host)
return 0;
}
static const struct nand_controller_ops qcom_nandc_ops = {
.attach_chip = qcom_nand_attach_chip,
};
static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
{
int ret;
@ -2570,7 +2732,8 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
INIT_LIST_HEAD(&nandc->desc_list);
INIT_LIST_HEAD(&nandc->host_list);
nand_hw_control_init(&nandc->controller);
nand_controller_init(&nandc->controller);
nandc->controller.ops = &qcom_nandc_ops;
return 0;
}
@ -2623,9 +2786,9 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
return 0;
}
static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
struct qcom_nand_host *host,
struct device_node *dn)
static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
struct qcom_nand_host *host,
struct device_node *dn)
{
struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
@ -2672,30 +2835,13 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
/* set up initial status value */
host->status = NAND_STATUS_READY | NAND_STATUS_WP;
ret = nand_scan_ident(mtd, 1, NULL);
if (ret)
return ret;
ret = qcom_nand_host_setup(host);
return ret;
}
static int qcom_nand_mtd_register(struct qcom_nand_controller *nandc,
struct qcom_nand_host *host,
struct device_node *dn)
{
struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = nand_scan_tail(mtd);
ret = nand_scan(mtd, 1);
if (ret)
return ret;
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
nand_cleanup(mtd_to_nand(mtd));
nand_cleanup(chip);
return ret;
}
@ -2704,28 +2850,9 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
{
struct device *dev = nandc->dev;
struct device_node *dn = dev->of_node, *child;
struct qcom_nand_host *host, *tmp;
struct qcom_nand_host *host;
int ret;
for_each_available_child_of_node(dn, child) {
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host) {
of_node_put(child);
return -ENOMEM;
}
ret = qcom_nand_host_init(nandc, host, child);
if (ret) {
devm_kfree(dev, host);
continue;
}
list_add_tail(&host->node, &nandc->host_list);
}
if (list_empty(&nandc->host_list))
return -ENODEV;
if (nandc->props->is_bam) {
free_bam_transaction(nandc);
nandc->bam_txn = alloc_bam_transaction(nandc);
@ -2736,12 +2863,20 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
}
}
list_for_each_entry_safe(host, tmp, &nandc->host_list, node) {
ret = qcom_nand_mtd_register(nandc, host, child);
if (ret) {
list_del(&host->node);
devm_kfree(dev, host);
for_each_available_child_of_node(dn, child) {
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host) {
of_node_put(child);
return -ENOMEM;
}
ret = qcom_nand_host_init_and_register(nandc, host, child);
if (ret) {
devm_kfree(dev, host);
continue;
}
list_add_tail(&host->node, &nandc->host_list);
}
if (list_empty(&nandc->host_list))
@ -2799,14 +2934,6 @@ static int qcom_nandc_probe(struct platform_device *pdev)
nandc->props = dev_data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nandc->base = devm_ioremap_resource(dev, res);
if (IS_ERR(nandc->base))
return PTR_ERR(nandc->base);
nandc->base_phys = res->start;
nandc->base_dma = phys_to_dma(dev, (phys_addr_t)res->start);
nandc->core_clk = devm_clk_get(dev, "core");
if (IS_ERR(nandc->core_clk))
return PTR_ERR(nandc->core_clk);
@ -2819,9 +2946,21 @@ static int qcom_nandc_probe(struct platform_device *pdev)
if (ret)
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nandc->base = devm_ioremap_resource(dev, res);
if (IS_ERR(nandc->base))
return PTR_ERR(nandc->base);
nandc->base_phys = res->start;
nandc->base_dma = dma_map_resource(dev, res->start,
resource_size(res),
DMA_BIDIRECTIONAL, 0);
if (!nandc->base_dma)
return -ENXIO;
ret = qcom_nandc_alloc(nandc);
if (ret)
goto err_core_clk;
goto err_nandc_alloc;
ret = clk_prepare_enable(nandc->core_clk);
if (ret)
@ -2847,6 +2986,9 @@ err_aon_clk:
clk_disable_unprepare(nandc->core_clk);
err_core_clk:
qcom_nandc_unalloc(nandc);
err_nandc_alloc:
dma_unmap_resource(dev, res->start, resource_size(res),
DMA_BIDIRECTIONAL, 0);
return ret;
}
@ -2854,16 +2996,21 @@ err_core_clk:
static int qcom_nandc_remove(struct platform_device *pdev)
{
struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct qcom_nand_host *host;
list_for_each_entry(host, &nandc->host_list, node)
nand_release(nand_to_mtd(&host->chip));
qcom_nandc_unalloc(nandc);
clk_disable_unprepare(nandc->aon_clk);
clk_disable_unprepare(nandc->core_clk);
dma_unmap_resource(&pdev->dev, nandc->base_dma, resource_size(res),
DMA_BIDIRECTIONAL, 0);
return 0;
}

View file

@ -162,7 +162,7 @@ enum s3c_nand_clk_state {
*/
struct s3c2410_nand_info {
/* mtd info */
struct nand_hw_control controller;
struct nand_controller controller;
struct s3c2410_nand_mtd *mtds;
struct s3c2410_platform_nand *platform;
@ -802,8 +802,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
mtdinfo->name = set->name;
return mtd_device_parse_register(mtdinfo, NULL, NULL,
set->partitions, set->nr_partitions);
return mtd_device_register(mtdinfo, set->partitions,
set->nr_partitions);
}
return -ENODEV;
@ -915,20 +915,19 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
}
/**
* s3c2410_nand_update_chip - post probe update
* @info: The controller instance.
* @nmtd: The driver version of the MTD instance.
* s3c2410_nand_attach_chip - Init the ECC engine after NAND scan
* @chip: The NAND chip
*
* This routine is called after the chip probe has successfully completed
* and the relevant per-chip information updated. This call ensure that
* This hook is called by the core after the identification of the NAND chip,
* once the relevant per-chip information is up to date.. This call ensure that
* we update the internal state accordingly.
*
* The internal state is currently limited to the ECC state information.
*/
static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
struct s3c2410_nand_mtd *nmtd)
static int s3c2410_nand_attach_chip(struct nand_chip *chip)
{
struct nand_chip *chip = &nmtd->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
switch (chip->ecc.mode) {
@ -998,6 +997,10 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info,
return 0;
}
static const struct nand_controller_ops s3c24xx_nand_controller_ops = {
.attach_chip = s3c2410_nand_attach_chip,
};
static const struct of_device_id s3c24xx_nand_dt_ids[] = {
{
.compatible = "samsung,s3c2410-nand",
@ -1094,7 +1097,8 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
nand_hw_control_init(&info->controller);
nand_controller_init(&info->controller);
info->controller.ops = &s3c24xx_nand_controller_ops;
/* get the clock source and enable it */
@ -1134,8 +1138,13 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
sets = (plat != NULL) ? plat->sets : NULL;
nr_sets = (plat != NULL) ? plat->nr_sets : 1;
if (!plat->sets || plat->nr_sets < 1) {
err = -EINVAL;
goto exit_error;
}
sets = plat->sets;
nr_sets = plat->nr_sets;
info->mtd_count = nr_sets;
@ -1152,7 +1161,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
nmtd = info->mtds;
for (setno = 0; setno < nr_sets; setno++, nmtd++) {
for (setno = 0; setno < nr_sets; setno++, nmtd++, sets++) {
struct mtd_info *mtd = nand_to_mtd(&nmtd->chip);
pr_debug("initialising set %d (%p, info %p)\n",
@ -1161,22 +1170,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
s3c2410_nand_init_chip(info, nmtd, sets);
err = nand_scan_ident(mtd, (sets) ? sets->nr_chips : 1, NULL);
if (err)
goto exit_error;
err = s3c2410_nand_update_chip(info, nmtd);
if (err < 0)
goto exit_error;
err = nand_scan_tail(mtd);
err = nand_scan(mtd, sets ? sets->nr_chips : 1);
if (err)
goto exit_error;
s3c2410_nand_add_partition(info, nmtd, sets);
if (sets != NULL)
sets++;
}
/* initialise the hardware */

View file

@ -1002,10 +1002,17 @@ static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
flctl->index += len;
}
static int flctl_chip_init_tail(struct mtd_info *mtd)
static int flctl_chip_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct sh_flctl *flctl = mtd_to_flctl(mtd);
struct nand_chip *chip = &flctl->chip;
/*
* NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
* Add the SEL_16BIT flag in flctl->flcmncr_base.
*/
if (chip->options & NAND_BUSWIDTH_16)
flctl->flcmncr_base |= SEL_16BIT;
if (mtd->writesize == 512) {
flctl->page_size = 0;
@ -1063,6 +1070,10 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
return 0;
}
static const struct nand_controller_ops flctl_nand_controller_ops = {
.attach_chip = flctl_chip_attach_chip,
};
static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
{
struct sh_flctl *flctl = dev_id;
@ -1191,25 +1202,8 @@ static int flctl_probe(struct platform_device *pdev)
flctl_setup_dma(flctl);
ret = nand_scan_ident(flctl_mtd, 1, NULL);
if (ret)
goto err_chip;
if (nand->options & NAND_BUSWIDTH_16) {
/*
* NAND_BUSWIDTH_16 may have been set by nand_scan_ident().
* Add the SEL_16BIT flag in pdata->flcmncr_val and re-assign
* flctl->flcmncr_base to pdata->flcmncr_val.
*/
pdata->flcmncr_val |= SEL_16BIT;
flctl->flcmncr_base = pdata->flcmncr_val;
}
ret = flctl_chip_init_tail(flctl_mtd);
if (ret)
goto err_chip;
ret = nand_scan_tail(flctl_mtd);
nand->dummy_controller.ops = &flctl_nand_controller_ops;
ret = nand_scan(flctl_mtd, 1);
if (ret)
goto err_chip;

View file

@ -21,10 +21,7 @@
#include <linux/mtd/sharpsl.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <linux/io.h>
struct sharpsl_nand {
struct nand_chip chip;

View file

@ -160,19 +160,9 @@ static struct nand_flash_dev nand_xd_flash_ids[] = {
{NULL}
};
int sm_register_device(struct mtd_info *mtd, int smartmedia)
static int sm_attach_chip(struct nand_chip *chip)
{
struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
chip->options |= NAND_SKIP_BBTSCAN;
/* Scan for card properties */
ret = nand_scan_ident(mtd, 1, smartmedia ?
nand_smartmedia_flash_ids : nand_xd_flash_ids);
if (ret)
return ret;
struct mtd_info *mtd = nand_to_mtd(chip);
/* Bad block marker position */
chip->badblockpos = 0x05;
@ -187,12 +177,33 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
else
return -ENODEV;
ret = nand_scan_tail(mtd);
return 0;
}
static const struct nand_controller_ops sm_controller_ops = {
.attach_chip = sm_attach_chip,
};
int sm_register_device(struct mtd_info *mtd, int smartmedia)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_flash_dev *flash_ids;
int ret;
chip->options |= NAND_SKIP_BBTSCAN;
/* Scan for card properties */
chip->dummy_controller.ops = &sm_controller_ops;
flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
ret = nand_scan_with_ids(mtd, 1, flash_ids);
if (ret)
return ret;
return mtd_device_register(mtd, NULL, 0);
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
nand_cleanup(chip);
return ret;
}
EXPORT_SYMBOL_GPL(sm_register_device);

View file

@ -29,14 +29,12 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/reset.h>
@ -127,7 +125,7 @@
#define NFC_CMD_TYPE_MSK GENMASK(31, 30)
#define NFC_NORMAL_OP (0 << 30)
#define NFC_ECC_OP (1 << 30)
#define NFC_PAGE_OP (2 << 30)
#define NFC_PAGE_OP (2U << 30)
/* define bit use in NFC_RCMD_SET */
#define NFC_READ_CMD_MSK GENMASK(7, 0)
@ -234,7 +232,7 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
* controller events
*/
struct sunxi_nfc {
struct nand_hw_control controller;
struct nand_controller controller;
struct device *dev;
void __iomem *regs;
struct clk *ahb_clk;
@ -247,7 +245,7 @@ struct sunxi_nfc {
struct dma_chan *dmac;
};
static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_controller *ctrl)
{
return container_of(ctrl, struct sunxi_nfc, controller);
}
@ -544,7 +542,7 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
{
uint8_t ret;
uint8_t ret = 0;
sunxi_nfc_read_buf(mtd, &ret, 1);
@ -1816,12 +1814,21 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
}
}
static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
struct device_node *np)
static int sunxi_nand_attach_chip(struct nand_chip *nand)
{
struct nand_chip *nand = mtd_to_nand(mtd);
struct mtd_info *mtd = nand_to_mtd(nand);
struct nand_ecc_ctrl *ecc = &nand->ecc;
struct device_node *np = nand_get_flash_node(nand);
int ret;
if (nand->bbt_options & NAND_BBT_USE_FLASH)
nand->bbt_options |= NAND_BBT_NO_OOB;
if (nand->options & NAND_NEED_SCRAMBLING)
nand->options |= NAND_NO_SUBPAGE_WRITE;
nand->options |= NAND_SUBPAGE_READ;
if (!ecc->size) {
ecc->size = nand->ecc_step_ds;
ecc->strength = nand->ecc_strength_ds;
@ -1846,6 +1853,10 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
return 0;
}
static const struct nand_controller_ops sunxi_nand_controller_ops = {
.attach_chip = sunxi_nand_attach_chip,
};
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np)
{
@ -1911,6 +1922,8 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
nand->chip_delay = 200;
nand->controller = &nfc->controller;
nand->controller->ops = &sunxi_nand_controller_ops;
/*
* Set the ECC mode to the default value in case nothing is specified
* in the DT.
@ -1927,30 +1940,10 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
mtd = nand_to_mtd(nand);
mtd->dev.parent = dev;
ret = nand_scan_ident(mtd, nsels, NULL);
ret = nand_scan(mtd, nsels);
if (ret)
return ret;
if (nand->bbt_options & NAND_BBT_USE_FLASH)
nand->bbt_options |= NAND_BBT_NO_OOB;
if (nand->options & NAND_NEED_SCRAMBLING)
nand->options |= NAND_NO_SUBPAGE_WRITE;
nand->options |= NAND_SUBPAGE_READ;
ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
if (ret) {
dev_err(dev, "ECC init failed: %d\n", ret);
return ret;
}
ret = nand_scan_tail(mtd);
if (ret) {
dev_err(dev, "nand_scan_tail failed: %d\n", ret);
return ret;
}
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
@ -2012,7 +2005,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
return -ENOMEM;
nfc->dev = dev;
nand_hw_control_init(&nfc->controller);
nand_controller_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);

View file

@ -83,7 +83,7 @@
#define MAX_CS 4
struct tango_nfc {
struct nand_hw_control hw;
struct nand_controller hw;
void __iomem *reg_base;
void __iomem *mem_base;
void __iomem *pbus_base;
@ -517,6 +517,28 @@ static int tango_set_timings(struct mtd_info *mtd, int csline,
return 0;
}
static int tango_attach_chip(struct nand_chip *chip)
{
struct nand_ecc_ctrl *ecc = &chip->ecc;
ecc->mode = NAND_ECC_HW;
ecc->algo = NAND_ECC_BCH;
ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
ecc->read_page_raw = tango_read_page_raw;
ecc->write_page_raw = tango_write_page_raw;
ecc->read_page = tango_read_page;
ecc->write_page = tango_write_page;
ecc->read_oob = tango_read_oob;
ecc->write_oob = tango_write_oob;
return 0;
}
static const struct nand_controller_ops tango_controller_ops = {
.attach_chip = tango_attach_chip,
};
static int chip_init(struct device *dev, struct device_node *np)
{
u32 cs;
@ -566,22 +588,7 @@ static int chip_init(struct device *dev, struct device_node *np)
mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
mtd->dev.parent = dev;
err = nand_scan_ident(mtd, 1, NULL);
if (err)
return err;
ecc->mode = NAND_ECC_HW;
ecc->algo = NAND_ECC_BCH;
ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE);
ecc->read_page_raw = tango_read_page_raw;
ecc->write_page_raw = tango_write_page_raw;
ecc->read_page = tango_read_page;
ecc->write_page = tango_write_page;
ecc->read_oob = tango_read_oob;
ecc->write_oob = tango_write_oob;
err = nand_scan_tail(mtd);
err = nand_scan(mtd, 1);
if (err)
return err;
@ -654,7 +661,8 @@ static int tango_nand_probe(struct platform_device *pdev)
return PTR_ERR(nfc->chan);
platform_set_drvdata(pdev, nfc);
nand_hw_control_init(&nfc->hw);
nand_controller_init(&nfc->hw);
nfc->hw.ops = &tango_controller_ops;
nfc->freq_kHz = clk_get_rate(clk) / 1000;
for_each_child_of_node(pdev->dev.of_node, np) {

File diff suppressed because it is too large Load diff

View file

@ -20,7 +20,7 @@
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
#include <asm/txx9/ndfmc.h>
#include <linux/platform_data/txx9/ndfmc.h>
/* TXX9 NDFMC Registers */
#define TXX9_NDFDTR 0x00
@ -73,7 +73,7 @@ struct txx9ndfmc_drvdata {
void __iomem *base;
unsigned char hold; /* in gbusclock */
unsigned char spw; /* in gbusclock */
struct nand_hw_control hw_control;
struct nand_controller controller;
};
static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
@ -254,23 +254,25 @@ static void txx9ndfmc_initialize(struct platform_device *dev)
#define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \
DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000)
static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
static int txx9ndfmc_attach_chip(struct nand_chip *chip)
{
struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
struct mtd_info *mtd = nand_to_mtd(chip);
ret = nand_scan_ident(mtd, 1, NULL);
if (!ret) {
if (mtd->writesize >= 512) {
/* Hardware ECC 6 byte ECC per 512 Byte data */
chip->ecc.size = 512;
chip->ecc.bytes = 6;
}
ret = nand_scan_tail(mtd);
if (mtd->writesize >= 512) {
chip->ecc.size = 512;
chip->ecc.bytes = 6;
} else {
chip->ecc.size = 256;
chip->ecc.bytes = 3;
}
return ret;
return 0;
}
static const struct nand_controller_ops txx9ndfmc_controller_ops = {
.attach_chip = txx9ndfmc_attach_chip,
};
static int __init txx9ndfmc_probe(struct platform_device *dev)
{
struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
@ -303,7 +305,8 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
(gbusclk + 500000) / 1000000, hold, spw);
nand_hw_control_init(&drvdata->hw_control);
nand_controller_init(&drvdata->controller);
drvdata->controller.ops = &txx9ndfmc_controller_ops;
platform_set_drvdata(dev, drvdata);
txx9ndfmc_initialize(dev);
@ -332,12 +335,9 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
chip->ecc.correct = txx9ndfmc_correct_data;
chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
chip->ecc.mode = NAND_ECC_HW;
/* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */
chip->ecc.size = 256;
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
chip->chip_delay = 100;
chip->controller = &drvdata->hw_control;
chip->controller = &drvdata->controller;
nand_set_controller_data(chip, txx9_priv);
txx9_priv->dev = dev;
@ -359,14 +359,14 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
if (plat->wide_mask & (1 << i))
chip->options |= NAND_BUSWIDTH_16;
if (txx9ndfmc_nand_scan(mtd)) {
if (nand_scan(mtd, 1)) {
kfree(txx9_priv->mtdname);
kfree(txx9_priv);
continue;
}
mtd->name = txx9_priv->mtdname;
mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
mtd_device_register(mtd, NULL, 0);
drvdata->mtds[i] = mtd;
}

View file

@ -747,6 +747,69 @@ static void vf610_nfc_init_controller(struct vf610_nfc *nfc)
}
}
static int vf610_nfc_attach_chip(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
vf610_nfc_init_controller(nfc);
/* Bad block options. */
if (chip->bbt_options & NAND_BBT_USE_FLASH)
chip->bbt_options |= NAND_BBT_NO_OOB;
/* Single buffer only, max 256 OOB minus ECC status */
if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
dev_err(nfc->dev, "Unsupported flash page size\n");
return -ENXIO;
}
if (chip->ecc.mode != NAND_ECC_HW)
return 0;
if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
dev_err(nfc->dev, "Unsupported flash with hwecc\n");
return -ENXIO;
}
if (chip->ecc.size != mtd->writesize) {
dev_err(nfc->dev, "Step size needs to be page size\n");
return -ENXIO;
}
/* Only 64 byte ECC layouts known */
if (mtd->oobsize > 64)
mtd->oobsize = 64;
/* Use default large page ECC layout defined in NAND core */
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
if (chip->ecc.strength == 32) {
nfc->ecc_mode = ECC_60_BYTE;
chip->ecc.bytes = 60;
} else if (chip->ecc.strength == 24) {
nfc->ecc_mode = ECC_45_BYTE;
chip->ecc.bytes = 45;
} else {
dev_err(nfc->dev, "Unsupported ECC strength\n");
return -ENXIO;
}
chip->ecc.read_page = vf610_nfc_read_page;
chip->ecc.write_page = vf610_nfc_write_page;
chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
chip->ecc.read_oob = vf610_nfc_read_oob;
chip->ecc.write_oob = vf610_nfc_write_oob;
chip->ecc.size = PAGE_2K;
return 0;
}
static const struct nand_controller_ops vf610_nfc_controller_ops = {
.attach_chip = vf610_nfc_attach_chip,
};
static int vf610_nfc_probe(struct platform_device *pdev)
{
struct vf610_nfc *nfc;
@ -827,67 +890,9 @@ static int vf610_nfc_probe(struct platform_device *pdev)
vf610_nfc_preinit_controller(nfc);
/* first scan to find the device and get the page size */
err = nand_scan_ident(mtd, 1, NULL);
if (err)
goto err_disable_clk;
vf610_nfc_init_controller(nfc);
/* Bad block options. */
if (chip->bbt_options & NAND_BBT_USE_FLASH)
chip->bbt_options |= NAND_BBT_NO_OOB;
/* Single buffer only, max 256 OOB minus ECC status */
if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
dev_err(nfc->dev, "Unsupported flash page size\n");
err = -ENXIO;
goto err_disable_clk;
}
if (chip->ecc.mode == NAND_ECC_HW) {
if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
dev_err(nfc->dev, "Unsupported flash with hwecc\n");
err = -ENXIO;
goto err_disable_clk;
}
if (chip->ecc.size != mtd->writesize) {
dev_err(nfc->dev, "Step size needs to be page size\n");
err = -ENXIO;
goto err_disable_clk;
}
/* Only 64 byte ECC layouts known */
if (mtd->oobsize > 64)
mtd->oobsize = 64;
/* Use default large page ECC layout defined in NAND core */
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
if (chip->ecc.strength == 32) {
nfc->ecc_mode = ECC_60_BYTE;
chip->ecc.bytes = 60;
} else if (chip->ecc.strength == 24) {
nfc->ecc_mode = ECC_45_BYTE;
chip->ecc.bytes = 45;
} else {
dev_err(nfc->dev, "Unsupported ECC strength\n");
err = -ENXIO;
goto err_disable_clk;
}
chip->ecc.read_page = vf610_nfc_read_page;
chip->ecc.write_page = vf610_nfc_write_page;
chip->ecc.read_page_raw = vf610_nfc_read_page_raw;
chip->ecc.write_page_raw = vf610_nfc_write_page_raw;
chip->ecc.read_oob = vf610_nfc_read_oob;
chip->ecc.write_oob = vf610_nfc_write_oob;
chip->ecc.size = PAGE_2K;
}
/* second phase scan */
err = nand_scan_tail(mtd);
/* Scan the NAND chip */
chip->dummy_controller.ops = &vf610_nfc_controller_ops;
err = nand_scan(mtd, 1);
if (err)
goto err_disable_clk;

View file

@ -0,0 +1,7 @@
menuconfig MTD_SPI_NAND
tristate "SPI NAND device Support"
select MTD_NAND_CORE
depends on SPI_MASTER
select SPI_MEM
help
This is the framework for the SPI NAND device drivers.

View file

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
spinand-objs := core.o macronix.o micron.o winbond.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o

1155
drivers/mtd/nand/spi/core.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,144 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 Macronix
*
* Author: Boris Brezillon <boris.brezillon@bootlin.com>
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_MACRONIX 0xC2
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
return -ERANGE;
}
static int mx35lfxge4ab_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
region->offset = 2;
region->length = mtd->oobsize - 2;
return 0;
}
static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
.ecc = mx35lfxge4ab_ooblayout_ecc,
.free = mx35lfxge4ab_ooblayout_free,
};
static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
{
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_DUMMY(1, 1),
SPI_MEM_OP_DATA_IN(1, eccsr, 1));
return spi_mem_exec_op(spinand->spimem, &op);
}
static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
struct nand_device *nand = spinand_to_nand(spinand);
u8 eccsr;
switch (status & STATUS_ECC_MASK) {
case STATUS_ECC_NO_BITFLIPS:
return 0;
case STATUS_ECC_UNCOR_ERROR:
return -EBADMSG;
case STATUS_ECC_HAS_BITFLIPS:
/*
* Let's try to retrieve the real maximum number of bitflips
* in order to avoid forcing the wear-leveling layer to move
* data around if it's not necessary.
*/
if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
return nand->eccreq.strength;
if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
return nand->eccreq.strength;
return eccsr;
default:
break;
}
return -EINVAL;
}
static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO("MX35LF1GE4AB", 0x12,
NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35LF2GE4AB", 0x22,
NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
};
static int macronix_spinand_detect(struct spinand_device *spinand)
{
u8 *id = spinand->id.data;
int ret;
/*
* Macronix SPI NAND read ID needs a dummy byte, so the first byte in
* raw_id is garbage.
*/
if (id[1] != SPINAND_MFR_MACRONIX)
return 0;
ret = spinand_match_and_init(spinand, macronix_spinand_table,
ARRAY_SIZE(macronix_spinand_table),
id[2]);
if (ret)
return ret;
return 1;
}
static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
.detect = macronix_spinand_detect,
};
const struct spinand_manufacturer macronix_spinand_manufacturer = {
.id = SPINAND_MFR_MACRONIX,
.name = "Macronix",
.ops = &macronix_spinand_manuf_ops,
};

View file

@ -0,0 +1,133 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016-2017 Micron Technology, Inc.
*
* Authors:
* Peter Pan <peterpandong@micron.com>
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_MICRON 0x2c
#define MICRON_STATUS_ECC_MASK GENMASK(7, 4)
#define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4)
#define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
#define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
#define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4)
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
static int mt29f2g01abagd_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
region->offset = 64;
region->length = 64;
return 0;
}
static int mt29f2g01abagd_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
/* Reserve 2 bytes for the BBM. */
region->offset = 2;
region->length = 62;
return 0;
}
static const struct mtd_ooblayout_ops mt29f2g01abagd_ooblayout = {
.ecc = mt29f2g01abagd_ooblayout_ecc,
.free = mt29f2g01abagd_ooblayout_free,
};
static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
switch (status & MICRON_STATUS_ECC_MASK) {
case STATUS_ECC_NO_BITFLIPS:
return 0;
case STATUS_ECC_UNCOR_ERROR:
return -EBADMSG;
case MICRON_STATUS_ECC_1TO3_BITFLIPS:
return 3;
case MICRON_STATUS_ECC_4TO6_BITFLIPS:
return 6;
case MICRON_STATUS_ECC_7TO8_BITFLIPS:
return 8;
default:
break;
}
return -EINVAL;
}
static const struct spinand_info micron_spinand_table[] = {
SPINAND_INFO("MT29F2G01ABAGD", 0x24,
NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&mt29f2g01abagd_ooblayout,
mt29f2g01abagd_ecc_get_status)),
};
static int micron_spinand_detect(struct spinand_device *spinand)
{
u8 *id = spinand->id.data;
int ret;
/*
* Micron SPI NAND read ID need a dummy byte,
* so the first byte in raw_id is dummy.
*/
if (id[1] != SPINAND_MFR_MICRON)
return 0;
ret = spinand_match_and_init(spinand, micron_spinand_table,
ARRAY_SIZE(micron_spinand_table), id[2]);
if (ret)
return ret;
return 1;
}
static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
.detect = micron_spinand_detect,
};
const struct spinand_manufacturer micron_spinand_manufacturer = {
.id = SPINAND_MFR_MICRON,
.name = "Micron",
.ops = &micron_spinand_manuf_ops,
};

View file

@ -0,0 +1,141 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017 exceet electronics GmbH
*
* Authors:
* Frieder Schrempf <frieder.schrempf@exceet.de>
* Boris Brezillon <boris.brezillon@bootlin.com>
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_WINBOND 0xEF
#define WINBOND_CFG_BUF_READ BIT(3)
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section > 3)
return -ERANGE;
region->offset = (16 * section) + 8;
region->length = 8;
return 0;
}
static int w25m02gv_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section > 3)
return -ERANGE;
region->offset = (16 * section) + 2;
region->length = 6;
return 0;
}
static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
.ecc = w25m02gv_ooblayout_ecc,
.free = w25m02gv_ooblayout_free,
};
static int w25m02gv_select_target(struct spinand_device *spinand,
unsigned int target)
{
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_OUT(1,
spinand->scratchbuf,
1));
*spinand->scratchbuf = target;
return spi_mem_exec_op(spinand->spimem, &op);
}
static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO("W25M02GV", 0xAB,
NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
SPINAND_SELECT_TARGET(w25m02gv_select_target)),
};
/**
* winbond_spinand_detect - initialize device related part in spinand_device
* struct if it is a Winbond device.
* @spinand: SPI NAND device structure
*/
static int winbond_spinand_detect(struct spinand_device *spinand)
{
u8 *id = spinand->id.data;
int ret;
/*
* Winbond SPI NAND read ID need a dummy byte,
* so the first byte in raw_id is dummy.
*/
if (id[1] != SPINAND_MFR_WINBOND)
return 0;
ret = spinand_match_and_init(spinand, winbond_spinand_table,
ARRAY_SIZE(winbond_spinand_table), id[2]);
if (ret)
return ret;
return 1;
}
static int winbond_spinand_init(struct spinand_device *spinand)
{
struct nand_device *nand = spinand_to_nand(spinand);
unsigned int i;
/*
* Make sure all dies are in buffer read mode and not continuous read
* mode.
*/
for (i = 0; i < nand->memorg.ntargets; i++) {
spinand_select_target(spinand, i);
spinand_upd_cfg(spinand, WINBOND_CFG_BUF_READ,
WINBOND_CFG_BUF_READ);
}
return 0;
}
static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
.detect = winbond_spinand_detect,
.init = winbond_spinand_init,
};
const struct spinand_manufacturer winbond_spinand_manufacturer = {
.id = SPINAND_MFR_WINBOND,
.name = "Winbond",
.ops = &winbond_spinand_manuf_ops,
};

View file

@ -577,7 +577,7 @@ static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
int NFTL_mount(struct NFTLrecord *s)
{
int i;
unsigned int first_logical_block, logical_block, rep_block, nb_erases, erase_mark;
unsigned int first_logical_block, logical_block, rep_block, erase_mark;
unsigned int block, first_block, is_first_block;
int chain_length, do_format_chain;
struct nftl_uci0 h0;
@ -621,7 +621,6 @@ int NFTL_mount(struct NFTLrecord *s)
logical_block = le16_to_cpu ((h0.VirtUnitNum | h0.SpareVirtUnitNum));
rep_block = le16_to_cpu ((h0.ReplUnitNum | h0.SpareReplUnitNum));
nb_erases = le32_to_cpu (h1.WearInfo);
erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
is_first_block = !(logical_block >> 15);

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