MTD core changes:

* Spelling
 * http to https updates
 
 NAND core changes:
 * Drop useless 'depends on' in Kconfig
 * Add an extra level in the Kconfig hierarchy
 * Trivial spellings
 * Dynamic allocation of the interface configurations
 * Dropping the default ONFI timing mode
 * Various cleanup (types, structures, naming, comments)
 * Hide the chip->data_interface indirection
 * Add the generic rb-gpios property
 * Add the ->choose_interface_config() hook
 * Introduce nand_choose_best_sdr_timings()
 * Use default values for tPROG_max and tBERS_max
 * Avoid redefining tR_max and tCCS_min
 * Add a helper to find the closest ONFI mode
 * bcm63xx MTD parsers: simplify CFE detection
 
 Raw NAND controller drivers changes:
 * fsl-upm: Deprecation of specific DT properties
 * fsl_upm: Driver rework and cleanup in favor of ->exec_op()
 * Ingenic: Cleanup ARRAY_SIZE() vs sizeof() use
 * brcmnand: ECC error handling on EDU transfers
 * brcmnand: Don't default to EDU transfers
 * qcom: Set BAM mode only if not set already
 * qcom: Avoid write to unavailable register
 * gpio: Driver rework in favor of ->exec_op()
 * tango: ->exec_op() conversion
 * mtk: ->exec_op() conversion
 
 Raw NAND chip drivers changes:
 * toshiba: Implement ->choose_interface_config() for TH58NVG2S3HBAI4
 * toshiba: Implement ->choose_interface_config() for TC58NVG0S3E
 * toshiba: Implement ->choose_interface_config() for TC58TEG5DCLTA00
 * hynix: Implement ->choose_interface_config() for H27UCG8T2ATR-BC
 
 SPI NOR core changes:
 * Disable Quad Mode in spi_nor_restore().
 * Don't abort BFPT parsing when QER reserved value is used.
 * Add support/update capabilities for few flashes.
 * Drop s70fl01gs flash: it does not support RDSR(05h) which
   is critical for erase/write.
 * Merge the SPIMEM DTR bits in spi-nor/next to avoid conflicts
   during the release cycle.
 
 SPI NOR controller drivers changes:
 * Move the cadence-quadspi driver to spi-mem. The series was
   taken through the SPI tree. Merge it also in spi-nor/next
   to avoid conflicts during the release cycle.
 * intel-spi:
    - Add new PCI IDs.
    - Ignore the Write Disable command, the controller doesn't
      support it.
    - Fix performance regression.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAl8vJtMACgkQJWrqGEe9
 VoRdGAf/Y5m5BwmLilkEYpffyxi7dVR6XOKPLU5EJXkS3dPvH9398zchbHOdedCZ
 OzJIfh6Iv+qbkgS2g0lAAT+SAfOfG9plubvSdkjrHXl4eZXRnR/49RF5LAEju7sz
 Uw1HdRcawyEi5uI9yYS0tCeVMIUJq+5x7VibH+82yOIdSPc60c7FDc5ih/nVKj/a
 Pn9LOzGzkdndcE1b3FcF2Uk/T1YOJx3Yt5ngALlPpJxaDZmQSHtYPuuz8DfUbamf
 uj3CkpqYRyT18CzuFvtuba6LyF+donXNJgvl6ivW7dlRSPzSMnDQu7J5bpNhUfcd
 p/ZdzX1Jxle4theDm0J9ALsSSM5g2w==
 =RiY8
 -----END PGP SIGNATURE-----

Merge tag 'mtd/for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux

Pull mtd updates from Miquel Raynal:
 "MTD core changes:
   - Spelling
   - http to https updates

  NAND core changes:
   - Drop useless 'depends on' in Kconfig
   - Add an extra level in the Kconfig hierarchy
   - Trivial spellings
   - Dynamic allocation of the interface configurations
   - Dropping the default ONFI timing mode
   - Various cleanup (types, structures, naming, comments)
   - Hide the chip->data_interface indirection
   - Add the generic rb-gpios property
   - Add the ->choose_interface_config() hook
   - Introduce nand_choose_best_sdr_timings()
   - Use default values for tPROG_max and tBERS_max
   - Avoid redefining tR_max and tCCS_min
   - Add a helper to find the closest ONFI mode
   - bcm63xx MTD parsers: simplify CFE detection

  Raw NAND controller drivers changes:
   - fsl-upm: Deprecation of specific DT properties
   - fsl_upm: Driver rework and cleanup in favor of ->exec_op()
   - Ingenic: Cleanup ARRAY_SIZE() vs sizeof() use
   - brcmnand: ECC error handling on EDU transfers
   - brcmnand: Don't default to EDU transfers
   - qcom: Set BAM mode only if not set already
   - qcom: Avoid write to unavailable register
   - gpio: Driver rework in favor of ->exec_op()
   - tango: ->exec_op() conversion
   - mtk: ->exec_op() conversion

  Raw NAND chip drivers changes:
   - toshiba: Implement ->choose_interface_config() for TH58NVG2S3HBAI4,
     TC58NVG0S3E, and TC58TEG5DCLTA00
   - hynix: Implement ->choose_interface_config() for H27UCG8T2ATR-BC

  SPI NOR core changes:
   - Disable Quad Mode in spi_nor_restore().
   - Don't abort BFPT parsing when QER reserved value is used.
   - Add support/update capabilities for few flashes.
   - Drop s70fl01gs flash: it does not support RDSR(05h) which is
     critical for erase/write.
   - Merge the SPIMEM DTR bits in spi-nor/next to avoid conflicts during
     the release cycle.

  SPI NOR controller drivers changes:
   - Move the cadence-quadspi driver to spi-mem. The series was taken
     through the SPI tree. Merge it also in spi-nor/next to avoid
     conflicts during the release cycle.
   - intel-spi:
      - Add new PCI IDs.
      - Ignore the Write Disable command, the controller doesn't support
        it.
      - Fix performance regression"

* tag 'mtd/for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (79 commits)
  MTD: pfow.h: drop a duplicated word
  MTD: mtd-abi.h: drop a duplicated word
  mtd: rawnand: omap_elm: Replace HTTP links with HTTPS ones
  mtd: Replace HTTP links with HTTPS ones
  mtd: hyperbus: Replace HTTP links with HTTPS ones
  mtd: revert "spi-nor: intel: provide a range for poll_timout"
  mtd: spi-nor: update read capabilities for w25q64 and s25fl064k
  mtd: spi-nor: micron: Add SPI_NOR_DUAL_READ flag on mt25qu02g
  mtd: spi-nor: macronix: Add support for mx66u2g45g
  mtd: spi-nor: intel-spi: Simulate WRDI command
  mtd: spi-nor: Disable the flash quad mode in spi_nor_restore()
  mtd: spi-nor: Add capability to disable flash quad mode
  mtd: spi-nor: spansion: Remove s70fl01gs from flash_info
  mtd: spi-nor: sfdp: do not make invalid quad enable fatal
  dt-bindings: mtd: fsl-upm-nand: Deprecate chip-delay and fsl, upm-wait-flags
  mtd: rawnand: stm32_fmc2: get resources from parent node
  mtd: rawnand: stm32_fmc2: use regmap APIs
  memory: stm32-fmc2-ebi: add STM32 FMC2 EBI controller driver
  dt-bindings: memory-controller: add STM32 FMC2 EBI controller documentation
  dt-bindings: mtd: update STM32 FMC2 NAND controller documentation
  ...
This commit is contained in:
Linus Torvalds 2020-08-09 12:38:51 -07:00
commit dec1fbbc1d
65 changed files with 2807 additions and 985 deletions

View File

@ -0,0 +1,252 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/st,stm32-fmc2-ebi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectronics Flexible Memory Controller 2 (FMC2) Bindings
description: |
The FMC2 functional block makes the interface with: synchronous and
asynchronous static devices (such as PSNOR, PSRAM or other memory-mapped
peripherals) and NAND flash memories.
Its main purposes are:
- to translate AXI transactions into the appropriate external device
protocol
- to meet the access time requirements of the external devices
All external devices share the addresses, data and control signals with the
controller. Each external device is accessed by means of a unique Chip
Select. The FMC2 performs only one access at a time to an external device.
maintainers:
- Christophe Kerello <christophe.kerello@st.com>
properties:
compatible:
const: st,stm32mp1-fmc2-ebi
reg:
maxItems: 1
clocks:
maxItems: 1
resets:
maxItems: 1
"#address-cells":
const: 2
"#size-cells":
const: 1
ranges:
description: |
Reflects the memory layout with four integer values per bank. Format:
<bank-number> 0 <address of the bank> <size>
patternProperties:
"^.*@[0-4],[a-f0-9]+$":
type: object
properties:
reg:
description: Bank number, base address and size of the device.
st,fmc2-ebi-cs-transaction-type:
description: |
Select one of the transactions type supported
0: Asynchronous mode 1 SRAM/FRAM.
1: Asynchronous mode 1 PSRAM.
2: Asynchronous mode A SRAM/FRAM.
3: Asynchronous mode A PSRAM.
4: Asynchronous mode 2 NOR.
5: Asynchronous mode B NOR.
6: Asynchronous mode C NOR.
7: Asynchronous mode D NOR.
8: Synchronous read synchronous write PSRAM.
9: Synchronous read asynchronous write PSRAM.
10: Synchronous read synchronous write NOR.
11: Synchronous read asynchronous write NOR.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 11
st,fmc2-ebi-cs-cclk-enable:
description: Continuous clock enable (first bank must be configured
in synchronous mode). The FMC_CLK is generated continuously
during asynchronous and synchronous access. By default, the
FMC_CLK is only generated during synchronous access.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-mux-enable:
description: Address/Data multiplexed on databus (valid only with
NOR and PSRAM transactions type). By default, Address/Data
are not multiplexed.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-buswidth:
description: Data bus width
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 8, 16 ]
default: 16
st,fmc2-ebi-cs-waitpol-high:
description: Wait signal polarity (NWAIT signal active high).
By default, NWAIT is active low.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-waitcfg-enable:
description: The NWAIT signal indicates wheither the data from the
device are valid or if a wait state must be inserted when accessing
the device in synchronous mode. By default, the NWAIT signal is
active one data cycle before wait state.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-wait-enable:
description: The NWAIT signal is enabled (its level is taken into
account after the programmed latency period to insert wait states
if asserted). By default, the NWAIT signal is disabled.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-asyncwait-enable:
description: The NWAIT signal is taken into account during asynchronous
transactions. By default, the NWAIT signal is not taken into account
during asynchronous transactions.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-cpsize:
description: CRAM page size. The controller splits the burst access
when the memory page is reached. By default, no burst split when
crossing page boundary.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 128, 256, 512, 1024 ]
default: 0
st,fmc2-ebi-cs-byte-lane-setup-ns:
description: This property configures the byte lane setup timing
defined in nanoseconds from NBLx low to Chip Select NEx low.
st,fmc2-ebi-cs-address-setup-ns:
description: This property defines the duration of the address setup
phase in nanoseconds used for asynchronous read/write transactions.
st,fmc2-ebi-cs-address-hold-ns:
description: This property defines the duration of the address hold
phase in nanoseconds used for asynchronous multiplexed read/write
transactions.
st,fmc2-ebi-cs-data-setup-ns:
description: This property defines the duration of the data setup phase
in nanoseconds used for asynchronous read/write transactions.
st,fmc2-ebi-cs-bus-turnaround-ns:
description: This property defines the delay in nanoseconds between the
end of current read/write transaction and the next transaction.
st,fmc2-ebi-cs-data-hold-ns:
description: This property defines the duration of the data hold phase
in nanoseconds used for asynchronous read/write transactions.
st,fmc2-ebi-cs-clk-period-ns:
description: This property defines the FMC_CLK output signal period in
nanoseconds.
st,fmc2-ebi-cs-data-latency-ns:
description: This property defines the data latency before reading or
writing the first data in nanoseconds.
st,fmc2_ebi-cs-write-address-setup-ns:
description: This property defines the duration of the address setup
phase in nanoseconds used for asynchronous write transactions.
st,fmc2-ebi-cs-write-address-hold-ns:
description: This property defines the duration of the address hold
phase in nanoseconds used for asynchronous multiplexed write
transactions.
st,fmc2-ebi-cs-write-data-setup-ns:
description: This property defines the duration of the data setup
phase in nanoseconds used for asynchronous write transactions.
st,fmc2-ebi-cs-write-bus-turnaround-ns:
description: This property defines the delay between the end of current
write transaction and the next transaction in nanoseconds.
st,fmc2-ebi-cs-write-data-hold-ns:
description: This property defines the duration of the data hold phase
in nanoseconds used for asynchronous write transactions.
st,fmc2-ebi-cs-max-low-pulse-ns:
description: This property defines the maximum chip select low pulse
duration in nanoseconds for synchronous transactions. When this timing
reaches 0, the controller splits the current access, toggles NE to
allow device refresh and restarts a new access.
required:
- reg
required:
- "#address-cells"
- "#size-cells"
- compatible
- reg
- clocks
- ranges
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <dt-bindings/reset/stm32mp1-resets.h>
memory-controller@58002000 {
#address-cells = <2>;
#size-cells = <1>;
compatible = "st,stm32mp1-fmc2-ebi";
reg = <0x58002000 0x1000>;
clocks = <&rcc FMC_K>;
resets = <&rcc FMC_R>;
ranges = <0 0 0x60000000 0x04000000>, /* EBI CS 1 */
<1 0 0x64000000 0x04000000>, /* EBI CS 2 */
<2 0 0x68000000 0x04000000>, /* EBI CS 3 */
<3 0 0x6c000000 0x04000000>, /* EBI CS 4 */
<4 0 0x80000000 0x10000000>; /* NAND */
psram@0,0 {
compatible = "mtd-ram";
reg = <0 0x00000000 0x100000>;
bank-width = <2>;
st,fmc2-ebi-cs-transaction-type = <1>;
st,fmc2-ebi-cs-address-setup-ns = <60>;
st,fmc2-ebi-cs-data-setup-ns = <30>;
st,fmc2-ebi-cs-bus-turnaround-ns = <5>;
};
nand-controller@4,0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "st,stm32mp1-fmc2-nfc";
reg = <4 0x00000000 0x1000>,
<4 0x08010000 0x1000>,
<4 0x08020000 0x1000>,
<4 0x01000000 0x1000>,
<4 0x09010000 0x1000>,
<4 0x09020000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>,
<&mdma1 20 0x2 0x12000a08 0x0 0x0>,
<&mdma1 21 0x2 0x12000a0a 0x0 0x0>;
dma-names = "tx", "rx", "ecc";
nand@0 {
reg = <0>;
nand-on-flash-bbt;
#address-cells = <1>;
#size-cells = <1>;
};
};
};
...

View File

@ -4,8 +4,8 @@ This file provides information, what the device node for the davinci/keystone
NAND interface contains.
Documentation:
Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf
Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf
Davinci DM646x - https://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf
Kestone - https://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf
Required properties:

View File

@ -7,14 +7,16 @@ Required properties:
- fsl,upm-cmd-offset : UPM pattern offset for the command latch.
Optional properties:
- fsl,upm-wait-flags : add chip-dependent short delays after running the
UPM pattern (0x1), after writing a data byte (0x2) or after
writing out a buffer (0x4).
- fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support.
The corresponding address lines are used to select the chip.
- gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins
(R/B#). For multi-chip devices, "n" GPIO definitions are required
according to the number of chips.
Deprecated properties:
- fsl,upm-wait-flags : add chip-dependent short delays after running the
UPM pattern (0x1), after writing a data byte (0x2) or after
writing out a buffer (0x4).
- chip-delay : chip dependent delay for transferring data from array to
read registers (tR). Required if property "gpios" is not used
(R/B# pins not connected).
@ -52,8 +54,6 @@ upm@3,0 {
fsl,upm-cmd-offset = <0x08>;
/* Multi-chip NAND device */
fsl,upm-addr-line-cs-offsets = <0x0 0x200>;
fsl,upm-wait-flags = <0x5>;
chip-delay = <25>; // in micro-seconds
nand@0 {
#address-cells = <1>;

View File

@ -114,6 +114,13 @@ patternProperties:
description:
Contains the native Ready/Busy IDs.
rb-gpios:
description:
Contains one or more GPIO descriptor (the numper of descriptor
depends on the number of R/B pins exposed by the flash) for the
Ready/Busy pins. Active state refers to the NAND ready state and
should be set to GPIOD_ACTIVE_HIGH unless the signal is inverted.
required:
- reg

View File

@ -9,32 +9,19 @@ title: STMicroelectronics Flexible Memory Controller 2 (FMC2) Bindings
maintainers:
- Christophe Kerello <christophe.kerello@st.com>
allOf:
- $ref: "nand-controller.yaml#"
properties:
compatible:
const: st,stm32mp15-fmc2
enum:
- st,stm32mp15-fmc2
- st,stm32mp1-fmc2-nfc
reg:
items:
- description: Registers
- description: Chip select 0 data
- description: Chip select 0 command
- description: Chip select 0 address space
- description: Chip select 1 data
- description: Chip select 1 command
- description: Chip select 1 address space
minItems: 6
maxItems: 7
interrupts:
maxItems: 1
clocks:
maxItems: 1
resets:
maxItems: 1
dmas:
items:
- description: tx DMA channel
@ -57,11 +44,55 @@ patternProperties:
nand-ecc-strength:
enum: [1, 4 ,8 ]
allOf:
- $ref: "nand-controller.yaml#"
- if:
properties:
compatible:
contains:
const: st,stm32mp15-fmc2
then:
properties:
reg:
items:
- description: Registers
- description: Chip select 0 data
- description: Chip select 0 command
- description: Chip select 0 address space
- description: Chip select 1 data
- description: Chip select 1 command
- description: Chip select 1 address space
clocks:
maxItems: 1
resets:
maxItems: 1
required:
- clocks
- if:
properties:
compatible:
contains:
const: st,stm32mp1-fmc2-nfc
then:
properties:
reg:
items:
- description: Chip select 0 data
- description: Chip select 0 command
- description: Chip select 0 address space
- description: Chip select 1 data
- description: Chip select 1 command
- description: Chip select 1 address space
required:
- compatible
- reg
- interrupts
- clocks
examples:
- |
@ -77,13 +108,13 @@ examples:
<0x81000000 0x1000>,
<0x89010000 0x1000>,
<0x89020000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&mdma1 20 0x10 0x12000a02 0x0 0x0>,
<&mdma1 20 0x10 0x12000a08 0x0 0x0>,
<&mdma1 21 0x10 0x12000a0a 0x0 0x0>;
dma-names = "tx", "rx", "ecc";
clocks = <&rcc FMC_K>;
resets = <&rcc FMC_R>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>,
<&mdma1 20 0x2 0x12000a08 0x0 0x0>,
<&mdma1 21 0x2 0x12000a0a 0x0 0x0>;
dma-names = "tx", "rx", "ecc";
clocks = <&rcc FMC_K>;
resets = <&rcc FMC_R>;
#address-cells = <1>;
#size-cells = <0>;

View File

@ -188,6 +188,16 @@ config RENESAS_RPCIF
host or HyperFlash. You'll have to select individual components
under the corresponding menu.
config STM32_FMC2_EBI
tristate "Support for FMC2 External Bus Interface on STM32MP SoCs"
depends on MACH_STM32MP157 || COMPILE_TEST
select MFD_SYSCON
help
Select this option to enable the STM32 FMC2 External Bus Interface
controller. This driver configures the transactions with external
devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on
SOCs containing the FMC2 External Bus Interface.
source "drivers/memory/samsung/Kconfig"
source "drivers/memory/tegra/Kconfig"

View File

@ -23,6 +23,7 @@ obj-$(CONFIG_MTK_SMI) += mtk-smi.o
obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o
obj-$(CONFIG_PL353_SMC) += pl353-smc.o
obj-$(CONFIG_RENESAS_RPCIF) += renesas-rpc-if.o
obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o
obj-$(CONFIG_SAMSUNG_MC) += samsung/
obj-$(CONFIG_TEGRA_MC) += tegra/

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ config MTD_CFI
AMD and other flash manufactures that provides a universal method
for probing the capabilities of flash devices. If you wish to
support any device that is CFI-compliant, you need to enable this
option. Visit <http://www.amd.com/products/nvd/overview/cfi.html>
option. Visit <https://www.amd.com/products/nvd/overview/cfi.html>
for more information on CFI.
config MTD_JEDECPROBE

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
// Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
// Author: Vignesh Raghavendra <vigneshr@ti.com>
#include <linux/err.h>

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
// Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
// Author: Vignesh Raghavendra <vigneshr@ti.com>
#include <linux/err.h>

View File

@ -310,7 +310,7 @@ config MTD_DC21285
help
This provides a driver for the flash accessed using Intel's
21285 bridge used with Intel's StrongARM processors. More info at
<http://www.intel.com/design/bridge/docs/21285_documentation.htm>.
<https://www.intel.com/design/bridge/docs/21285_documentation.htm>.
config MTD_IXP4XX
tristate "CFI Flash device mapped on Intel IXP4xx based systems"

View File

@ -6,7 +6,7 @@
* The SC520CDP is an evaluation board for the Elan SC520 processor available
* from AMD. It has two banks of 32-bit Flash ROM, each 8 Megabytes in size,
* and up to 512 KiB of 8-bit DIL Flash ROM.
* For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html
* For details see https://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html
*/
#include <linux/module.h>

View File

@ -1,7 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "NAND"
config MTD_NAND_CORE
tristate
source "drivers/mtd/nand/onenand/Kconfig"
source "drivers/mtd/nand/raw/Kconfig"
source "drivers/mtd/nand/spi/Kconfig"
endmenu

View File

@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig MTD_ONENAND
tristate "OneNAND Device Support"
depends on MTD
depends on HAS_IOMEM
help
This enables support for accessing all type of OneNAND flash

View File

@ -12,7 +12,6 @@ config MTD_NAND_ECC_SW_HAMMING_SMC
menuconfig MTD_RAW_NAND
tristate "Raw/Parallel NAND Device Support"
depends on MTD
select MTD_NAND_CORE
select MTD_NAND_ECC_SW_HAMMING
help
@ -415,6 +414,7 @@ config MTD_NAND_TEGRA
config MTD_NAND_STM32_FMC2
tristate "Support for NAND controller on STM32MP SoCs"
depends on MACH_STM32MP157 || COMPILE_TEST
select MFD_SYSCON
help
Enables support for NAND Flash chips on SoCs containing the FMC2
NAND controller. This controller is found on STM32MP SoCs.

View File

@ -191,8 +191,8 @@ static int gpio_nand_exec_op(struct nand_chip *this,
return ret;
}
static int gpio_nand_setup_data_interface(struct nand_chip *this, int csline,
const struct nand_data_interface *cf)
static int gpio_nand_setup_interface(struct nand_chip *this, int csline,
const struct nand_interface_config *cf)
{
struct gpio_nand *priv = nand_get_controller_data(this);
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(cf);
@ -217,7 +217,7 @@ static int gpio_nand_setup_data_interface(struct nand_chip *this, int csline,
static const struct nand_controller_ops gpio_nand_ops = {
.exec_op = gpio_nand_exec_op,
.setup_data_interface = gpio_nand_setup_data_interface,
.setup_interface = gpio_nand_setup_interface,
};
/*

View File

@ -854,8 +854,8 @@ static int anfc_exec_op(struct nand_chip *chip,
return nand_op_parser_exec_op(chip, &anfc_op_parser, op, check_only);
}
static int anfc_setup_data_interface(struct nand_chip *chip, int target,
const struct nand_data_interface *conf)
static int anfc_setup_interface(struct nand_chip *chip, int target,
const struct nand_interface_config *conf)
{
struct anand *anand = to_anand(chip);
struct arasan_nfc *nfc = to_anfc(chip->controller);
@ -1083,7 +1083,7 @@ static void anfc_detach_chip(struct nand_chip *chip)
static const struct nand_controller_ops anfc_ops = {
.exec_op = anfc_exec_op,
.setup_data_interface = anfc_setup_data_interface,
.setup_interface = anfc_setup_interface,
.attach_chip = anfc_attach_chip,
.detach_chip = anfc_detach_chip,
};

View File

@ -200,8 +200,8 @@ struct atmel_nand_controller_ops {
void (*nand_init)(struct atmel_nand_controller *nc,
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);
int (*setup_interface)(struct atmel_nand *nand, int csline,
const struct nand_interface_config *conf);
};
struct atmel_nand_controller_caps {
@ -1168,7 +1168,7 @@ static int atmel_hsmc_nand_ecc_init(struct nand_chip *chip)
}
static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
const struct nand_data_interface *conf,
const struct nand_interface_config *conf,
struct atmel_smc_cs_conf *smcconf)
{
u32 ncycles, totalcycles, timeps, mckperiodps;
@ -1397,9 +1397,9 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
return 0;
}
static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand,
static int atmel_smc_nand_setup_interface(struct atmel_nand *nand,
int csline,
const struct nand_data_interface *conf)
const struct nand_interface_config *conf)
{
struct atmel_nand_controller *nc;
struct atmel_smc_cs_conf smcconf;
@ -1422,9 +1422,9 @@ static int atmel_smc_nand_setup_data_interface(struct atmel_nand *nand,
return 0;
}
static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
static int atmel_hsmc_nand_setup_interface(struct atmel_nand *nand,
int csline,
const struct nand_data_interface *conf)
const struct nand_interface_config *conf)
{
struct atmel_hsmc_nand_controller *nc;
struct atmel_smc_cs_conf smcconf;
@ -1452,8 +1452,8 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
return 0;
}
static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
static int atmel_nand_setup_interface(struct nand_chip *chip, int csline,
const struct nand_interface_config *conf)
{
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@ -1464,7 +1464,7 @@ static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline,
(csline < 0 && csline != NAND_DATA_IFACE_CHECK_ONLY))
return -EINVAL;
return nc->caps->ops->setup_data_interface(nand, csline, conf);
return nc->caps->ops->setup_interface(nand, csline, conf);
}
static void atmel_nand_init(struct atmel_nand_controller *nc,
@ -1483,7 +1483,7 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
chip->legacy.write_buf = atmel_nand_write_buf;
chip->legacy.select_chip = atmel_nand_select_chip;
if (!nc->mck || !nc->caps->ops->setup_data_interface)
if (!nc->mck || !nc->caps->ops->setup_interface)
chip->options |= NAND_KEEP_TIMINGS;
/* Some NANDs require a longer delay than the default one (20us). */
@ -1956,7 +1956,7 @@ static int atmel_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops atmel_nand_controller_ops = {
.attach_chip = atmel_nand_attach_chip,
.setup_data_interface = atmel_nand_setup_data_interface,
.setup_interface = atmel_nand_setup_interface,
};
static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
@ -2318,7 +2318,7 @@ static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
.remove = atmel_hsmc_nand_controller_remove,
.ecc_init = atmel_hsmc_nand_ecc_init,
.nand_init = atmel_hsmc_nand_init,
.setup_data_interface = atmel_hsmc_nand_setup_data_interface,
.setup_interface = atmel_hsmc_nand_setup_interface,
};
static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
@ -2375,10 +2375,10 @@ atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
/*
* The SMC reg layout of at91rm9200 is completely different which prevents us
* from re-using atmel_smc_nand_setup_data_interface() for the
* ->setup_data_interface() hook.
* from re-using atmel_smc_nand_setup_interface() for the
* ->setup_interface() hook.
* At this point, there's no support for the at91rm9200 SMC IP, so we leave
* ->setup_data_interface() unassigned.
* ->setup_interface() unassigned.
*/
static const struct atmel_nand_controller_ops at91rm9200_nc_ops = {
.probe = atmel_smc_nand_controller_probe,
@ -2399,7 +2399,7 @@ static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
.remove = atmel_smc_nand_controller_remove,
.ecc_init = atmel_nand_ecc_init,
.nand_init = atmel_smc_nand_init,
.setup_data_interface = atmel_smc_nand_setup_data_interface,
.setup_interface = atmel_smc_nand_setup_interface,
};
static const struct atmel_nand_controller_caps atmel_sam9260_nc_caps = {

View File

@ -1918,6 +1918,22 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
edu_writel(ctrl, EDU_STOP, 0); /* force stop */
edu_readl(ctrl, EDU_STOP);
if (!ret && edu_cmd == EDU_CMD_READ) {
u64 err_addr = 0;
/*
* check for ECC errors here, subpage ECC errors are
* retained in ECC error address register
*/
err_addr = brcmnand_get_uncorrecc_addr(ctrl);
if (!err_addr) {
err_addr = brcmnand_get_correcc_addr(ctrl);
if (err_addr)
ret = -EUCLEAN;
} else
ret = -EBADMSG;
}
return ret;
}
@ -2124,6 +2140,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
u64 err_addr = 0;
int err;
bool retry = true;
bool edu_err = false;
dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
@ -2141,6 +2158,10 @@ try_dmaread:
else
return -EIO;
}
if (has_edu(ctrl) && err_addr)
edu_err = true;
} else {
if (oob)
memset(oob, 0x99, mtd->oobsize);
@ -2188,6 +2209,11 @@ try_dmaread:
if (mtd_is_bitflip(err)) {
unsigned int corrected = brcmnand_count_corrected(ctrl);
/* in case of EDU correctable error we read again using PIO */
if (edu_err)
err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
oob, &err_addr);
dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
(unsigned long long)err_addr);
mtd->ecc_stats.corrected += corrected;
@ -3023,8 +3049,9 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
if (ret < 0)
goto err;
/* set edu transfer function to call */
ctrl->dma_trans = brcmnand_edu_trans;
if (has_edu(ctrl))
/* set edu transfer function to call */
ctrl->dma_trans = brcmnand_edu_trans;
}
/* Disable automatic device ID config, direct addressing */

View File

@ -2304,8 +2304,8 @@ static inline u32 calc_tdvw(u32 trp_cnt, u32 clk_period, u32 trhoh_min,
}
static int
cadence_nand_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
cadence_nand_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_interface_config *conf)
{
const struct nand_sdr_timings *sdr;
struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller);
@ -2691,7 +2691,7 @@ static int cadence_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops cadence_nand_controller_ops = {
.attach_chip = cadence_nand_attach_chip,
.exec_op = cadence_nand_exec_op,
.setup_data_interface = cadence_nand_setup_data_interface,
.setup_interface = cadence_nand_setup_interface,
};
static int cadence_nand_chip_init(struct cdns_nand_ctrl *cdns_ctrl,

View File

@ -761,8 +761,8 @@ static int denali_write_page(struct nand_chip *chip, const u8 *buf,
return denali_page_xfer(chip, (void *)buf, mtd->writesize, page, true);
}
static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
static int denali_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_interface_config *conf)
{
static const unsigned int data_setup_on_host = 10000;
struct denali_controller *denali = to_denali_controller(chip);
@ -1173,7 +1173,7 @@ static int denali_exec_op(struct nand_chip *chip,
static const struct nand_controller_ops denali_controller_ops = {
.attach_chip = denali_attach_chip,
.exec_op = denali_exec_op,
.setup_data_interface = denali_setup_data_interface,
.setup_interface = denali_setup_interface,
};
int denali_chip_init(struct denali_controller *denali,
@ -1230,7 +1230,7 @@ int denali_chip_init(struct denali_controller *denali,
chip->buf_align = 16;
}
/* clk rate info is needed for setup_data_interface */
/* clk rate info is needed for setup_interface */
if (!denali->clk_rate || !denali->clk_x_rate)
chip->options |= NAND_KEEP_TIMINGS;

View File

@ -14,32 +14,23 @@
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/mtd.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <asm/fsl_lbc.h>
#define FSL_UPM_WAIT_RUN_PATTERN 0x1
#define FSL_UPM_WAIT_WRITE_BYTE 0x2
#define FSL_UPM_WAIT_WRITE_BUFFER 0x4
struct fsl_upm_nand {
struct nand_controller base;
struct device *dev;
struct nand_chip chip;
int last_ctrl;
struct mtd_partition *parts;
struct fsl_upm upm;
uint8_t upm_addr_offset;
uint8_t upm_cmd_offset;
void __iomem *io_base;
int rnb_gpio[NAND_MAX_CHIPS];
struct gpio_desc *rnb_gpio[NAND_MAX_CHIPS];
uint32_t mchip_offsets[NAND_MAX_CHIPS];
uint32_t mchip_count;
uint32_t mchip_number;
int chip_delay;
uint32_t wait_flags;
};
static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
@ -48,106 +39,6 @@ static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
chip);
}
static int fun_chip_ready(struct nand_chip *chip)
{
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
return 1;
dev_vdbg(fun->dev, "busy\n");
return 0;
}
static void fun_wait_rnb(struct fsl_upm_nand *fun)
{
if (fun->rnb_gpio[fun->mchip_number] >= 0) {
struct mtd_info *mtd = nand_to_mtd(&fun->chip);
int cnt = 1000000;
while (--cnt && !fun_chip_ready(&fun->chip))
cpu_relax();
if (!cnt)
dev_err(fun->dev, "tired waiting for RNB\n");
} else {
ndelay(100);
}
}
static void fun_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
{
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
u32 mar;
if (!(ctrl & fun->last_ctrl)) {
fsl_upm_end_pattern(&fun->upm);
if (cmd == NAND_CMD_NONE)
return;
fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE);
}
if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_ALE)
fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
else if (ctrl & NAND_CLE)
fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
}
mar = (cmd << (32 - fun->upm.width)) |
fun->mchip_offsets[fun->mchip_number];
fsl_upm_run_pattern(&fun->upm, chip->legacy.IO_ADDR_R, mar);
if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN)
fun_wait_rnb(fun);
}
static void fun_select_chip(struct nand_chip *chip, int mchip_nr)
{
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
if (mchip_nr == -1) {
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
} else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
fun->mchip_number = mchip_nr;
chip->legacy.IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
} else {
BUG();
}
}
static uint8_t fun_read_byte(struct nand_chip *chip)
{
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
return in_8(fun->chip.legacy.IO_ADDR_R);
}
static void fun_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
int i;
for (i = 0; i < len; i++)
buf[i] = in_8(fun->chip.legacy.IO_ADDR_R);
}
static void fun_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
int i;
for (i = 0; i < len; i++) {
out_8(fun->chip.legacy.IO_ADDR_W, buf[i]);
if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE)
fun_wait_rnb(fun);
}
if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER)
fun_wait_rnb(fun);
}
static int fun_chip_init(struct fsl_upm_nand *fun,
const struct device_node *upm_np,
const struct resource *io_res)
@ -156,21 +47,9 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
int ret;
struct device_node *flash_np;
fun->chip.legacy.IO_ADDR_R = fun->io_base;
fun->chip.legacy.IO_ADDR_W = fun->io_base;
fun->chip.legacy.cmd_ctrl = fun_cmd_ctrl;
fun->chip.legacy.chip_delay = fun->chip_delay;
fun->chip.legacy.read_byte = fun_read_byte;
fun->chip.legacy.read_buf = fun_read_buf;
fun->chip.legacy.write_buf = fun_write_buf;
fun->chip.ecc.mode = NAND_ECC_SOFT;
fun->chip.ecc.algo = NAND_ECC_HAMMING;
if (fun->mchip_count > 1)
fun->chip.legacy.select_chip = fun_select_chip;
if (fun->rnb_gpio[0] >= 0)
fun->chip.legacy.dev_ready = fun_chip_ready;
fun->chip.controller = &fun->base;
mtd->dev.parent = fun->dev;
flash_np = of_get_next_child(upm_np, NULL);
@ -178,8 +57,9 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
return -ENODEV;
nand_set_flash_node(&fun->chip, flash_np);
mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%pOFn", (u64)io_res->start,
flash_np);
mtd->name = devm_kasprintf(fun->dev, GFP_KERNEL, "0x%llx.%pOFn",
(u64)io_res->start,
flash_np);
if (!mtd->name) {
ret = -ENOMEM;
goto err;
@ -192,51 +72,130 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
ret = mtd_device_register(mtd, NULL, 0);
err:
of_node_put(flash_np);
if (ret)
kfree(mtd->name);
return ret;
}
static int func_exec_instr(struct nand_chip *chip,
const struct nand_op_instr *instr)
{
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
u32 mar, reg_offs = fun->mchip_offsets[fun->mchip_number];
unsigned int i;
const u8 *out;
u8 *in;
switch (instr->type) {
case NAND_OP_CMD_INSTR:
fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
mar = (instr->ctx.cmd.opcode << (32 - fun->upm.width)) |
reg_offs;
fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar);
fsl_upm_end_pattern(&fun->upm);
return 0;
case NAND_OP_ADDR_INSTR:
fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
for (i = 0; i < instr->ctx.addr.naddrs; i++) {
mar = (instr->ctx.addr.addrs[i] << (32 - fun->upm.width)) |
reg_offs;
fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar);
}
fsl_upm_end_pattern(&fun->upm);
return 0;
case NAND_OP_DATA_IN_INSTR:
in = instr->ctx.data.buf.in;
for (i = 0; i < instr->ctx.data.len; i++)
in[i] = in_8(fun->io_base + reg_offs);
return 0;
case NAND_OP_DATA_OUT_INSTR:
out = instr->ctx.data.buf.out;
for (i = 0; i < instr->ctx.data.len; i++)
out_8(fun->io_base + reg_offs, out[i]);
return 0;
case NAND_OP_WAITRDY_INSTR:
if (!fun->rnb_gpio[fun->mchip_number])
return nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms);
return nand_gpio_waitrdy(chip, fun->rnb_gpio[fun->mchip_number],
instr->ctx.waitrdy.timeout_ms);
default:
return -EINVAL;
}
return 0;
}
static int fun_exec_op(struct nand_chip *chip, const struct nand_operation *op,
bool check_only)
{
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
unsigned int i;
int ret;
if (op->cs > NAND_MAX_CHIPS)
return -EINVAL;
if (check_only)
return 0;
fun->mchip_number = op->cs;
for (i = 0; i < op->ninstrs; i++) {
ret = func_exec_instr(chip, &op->instrs[i]);
if (ret)
return ret;
if (op->instrs[i].delay_ns)
ndelay(op->instrs[i].delay_ns);
}
return 0;
}
static const struct nand_controller_ops fun_ops = {
.exec_op = fun_exec_op,
};
static int fun_probe(struct platform_device *ofdev)
{
struct fsl_upm_nand *fun;
struct resource io_res;
struct resource *io_res;
const __be32 *prop;
int rnb_gpio;
int ret;
int size;
int i;
fun = kzalloc(sizeof(*fun), GFP_KERNEL);
fun = devm_kzalloc(&ofdev->dev, sizeof(*fun), GFP_KERNEL);
if (!fun)
return -ENOMEM;
ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res);
if (ret) {
dev_err(&ofdev->dev, "can't get IO base\n");
goto err1;
}
io_res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
fun->io_base = devm_ioremap_resource(&ofdev->dev, io_res);
if (IS_ERR(fun->io_base))
return PTR_ERR(fun->io_base);
ret = fsl_upm_find(io_res.start, &fun->upm);
ret = fsl_upm_find(io_res->start, &fun->upm);
if (ret) {
dev_err(&ofdev->dev, "can't find UPM\n");
goto err1;
return ret;
}
prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset",
&size);
if (!prop || size != sizeof(uint32_t)) {
dev_err(&ofdev->dev, "can't get UPM address offset\n");
ret = -EINVAL;
goto err1;
return -EINVAL;
}
fun->upm_addr_offset = *prop;
prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size);
if (!prop || size != sizeof(uint32_t)) {
dev_err(&ofdev->dev, "can't get UPM command offset\n");
ret = -EINVAL;
goto err1;
return -EINVAL;
}
fun->upm_cmd_offset = *prop;
@ -246,7 +205,7 @@ static int fun_probe(struct platform_device *ofdev)
fun->mchip_count = size / sizeof(uint32_t);
if (fun->mchip_count >= NAND_MAX_CHIPS) {
dev_err(&ofdev->dev, "too much multiple chips\n");
goto err1;
return -EINVAL;
}
for (i = 0; i < fun->mchip_count; i++)
fun->mchip_offsets[i] = be32_to_cpu(prop[i]);
@ -255,63 +214,26 @@ static int fun_probe(struct platform_device *ofdev)
}
for (i = 0; i < fun->mchip_count; i++) {
fun->rnb_gpio[i] = -1;
rnb_gpio = of_get_gpio(ofdev->dev.of_node, i);
if (rnb_gpio >= 0) {
ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev));
if (ret) {
dev_err(&ofdev->dev,
"can't request RNB gpio #%d\n", i);
goto err2;
}
gpio_direction_input(rnb_gpio);
fun->rnb_gpio[i] = rnb_gpio;
} else if (rnb_gpio == -EINVAL) {
fun->rnb_gpio[i] = devm_gpiod_get_index_optional(&ofdev->dev,
NULL, i,
GPIOD_IN);
if (IS_ERR(fun->rnb_gpio[i])) {
dev_err(&ofdev->dev, "RNB gpio #%d is invalid\n", i);
goto err2;
return PTR_ERR(fun->rnb_gpio[i]);
}
}
prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL);
if (prop)
fun->chip_delay = be32_to_cpup(prop);
else
fun->chip_delay = 50;
prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size);
if (prop && size == sizeof(uint32_t))
fun->wait_flags = be32_to_cpup(prop);
else
fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN |
FSL_UPM_WAIT_WRITE_BYTE;
fun->io_base = devm_ioremap(&ofdev->dev, io_res.start,
resource_size(&io_res));
if (!fun->io_base) {
ret = -ENOMEM;
goto err2;
}
nand_controller_init(&fun->base);
fun->base.ops = &fun_ops;
fun->dev = &ofdev->dev;
fun->last_ctrl = NAND_CLE;
ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res);
ret = fun_chip_init(fun, ofdev->dev.of_node, io_res);
if (ret)
goto err2;
return ret;
dev_set_drvdata(&ofdev->dev, fun);
return 0;
err2:
for (i = 0; i < fun->mchip_count; i++) {
if (fun->rnb_gpio[i] < 0)
break;
gpio_free(fun->rnb_gpio[i]);
}
err1:
kfree(fun);
return ret;
}
static int fun_remove(struct platform_device *ofdev)
@ -319,20 +241,11 @@ static int fun_remove(struct platform_device *ofdev)
struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
struct nand_chip *chip = &fun->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
int ret, i;
int ret;
ret = mtd_device_unregister(mtd);
WARN_ON(ret);
nand_cleanup(chip);
kfree(mtd->name);
for (i = 0; i < fun->mchip_count; i++) {
if (fun->rnb_gpio[i] < 0)
break;
gpio_free(fun->rnb_gpio[i]);
}
kfree(fun);
return 0;
}

View File

@ -327,8 +327,8 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
return 0;
}
static int fsmc_setup_data_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf)
static int fsmc_setup_interface(struct nand_chip *nand, int csline,
const struct nand_interface_config *conf)
{
struct fsmc_nand_data *host = nand_to_fsmc(nand);
struct fsmc_nand_timings tims;
@ -951,7 +951,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
static const struct nand_controller_ops fsmc_nand_controller_ops = {
.attach_chip = fsmc_nand_attach_chip,
.exec_op = fsmc_exec_op,
.setup_data_interface = fsmc_setup_data_interface,
.setup_interface = fsmc_setup_interface,
};
/**

View File

@ -25,8 +25,11 @@
#include <linux/mtd/nand-gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/delay.h>
struct gpiomtd {
struct nand_controller base;
void __iomem *io;
void __iomem *io_sync;
struct nand_chip nand_chip;
struct gpio_nand_platdata plat;
@ -69,34 +72,99 @@ static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
#endif
static void gpio_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
static int gpio_nand_exec_instr(struct nand_chip *chip,
const struct nand_op_instr *instr)
{
struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
unsigned int i;
gpio_nand_dosync(gpiomtd);
if (ctrl & NAND_CTRL_CHANGE) {
if (gpiomtd->nce)
gpiod_set_value(gpiomtd->nce, !(ctrl & NAND_NCE));
gpiod_set_value(gpiomtd->cle, !!(ctrl & NAND_CLE));
gpiod_set_value(gpiomtd->ale, !!(ctrl & NAND_ALE));
switch (instr->type) {
case NAND_OP_CMD_INSTR:
gpio_nand_dosync(gpiomtd);
}
if (cmd == NAND_CMD_NONE)
return;
gpiod_set_value(gpiomtd->cle, 1);
gpio_nand_dosync(gpiomtd);
writeb(instr->ctx.cmd.opcode, gpiomtd->io);
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->cle, 0);
return 0;
writeb(cmd, gpiomtd->nand_chip.legacy.IO_ADDR_W);
gpio_nand_dosync(gpiomtd);
case NAND_OP_ADDR_INSTR:
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->ale, 1);
gpio_nand_dosync(gpiomtd);
for (i = 0; i < instr->ctx.addr.naddrs; i++)
writeb(instr->ctx.addr.addrs[i], gpiomtd->io);
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->ale, 0);
return 0;
case NAND_OP_DATA_IN_INSTR:
gpio_nand_dosync(gpiomtd);
if ((chip->options & NAND_BUSWIDTH_16) &&
!instr->ctx.data.force_8bit)
ioread16_rep(gpiomtd->io, instr->ctx.data.buf.in,
instr->ctx.data.len / 2);
else
ioread8_rep(gpiomtd->io, instr->ctx.data.buf.in,
instr->ctx.data.len);
return 0;
case NAND_OP_DATA_OUT_INSTR:
gpio_nand_dosync(gpiomtd);
if ((chip->options & NAND_BUSWIDTH_16) &&
!instr->ctx.data.force_8bit)
iowrite16_rep(gpiomtd->io, instr->ctx.data.buf.out,
instr->ctx.data.len / 2);
else
iowrite8_rep(gpiomtd->io, instr->ctx.data.buf.out,
instr->ctx.data.len);
return 0;
case NAND_OP_WAITRDY_INSTR:
if (!gpiomtd->rdy)
return nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms);
return nand_gpio_waitrdy(chip, gpiomtd->rdy,
instr->ctx.waitrdy.timeout_ms);
default:
return -EINVAL;
}
return 0;
}
static int gpio_nand_devready(struct nand_chip *chip)
static int gpio_nand_exec_op(struct nand_chip *chip,
const struct nand_operation *op,
bool check_only)
{
struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
unsigned int i;
int ret = 0;
return gpiod_get_value(gpiomtd->rdy);
if (check_only)
return 0;
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->nce, 0);
for (i = 0; i < op->ninstrs; i++) {
ret = gpio_nand_exec_instr(chip, &op->instrs[i]);
if (ret)
break;
if (op->instrs[i].delay_ns)
ndelay(op->instrs[i].delay_ns);
}
gpio_nand_dosync(gpiomtd);
gpiod_set_value(gpiomtd->nce, 1);
return ret;
}
static const struct nand_controller_ops gpio_nand_ops = {
.exec_op = gpio_nand_exec_op,
};
#ifdef CONFIG_OF
static const struct of_device_id gpio_nand_id_table[] = {
{ .compatible = "gpio-control-nand" },
@ -225,9 +293,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
chip = &gpiomtd->nand_chip;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
chip->legacy.IO_ADDR_R = devm_ioremap_resource(dev, res);
if (IS_ERR(chip->legacy.IO_ADDR_R))
return PTR_ERR(chip->legacy.IO_ADDR_R);
gpiomtd->io = devm_ioremap_resource(dev, res);
if (IS_ERR(gpiomtd->io))
return PTR_ERR(gpiomtd->io);
res = gpio_nand_get_io_sync(pdev);
if (res) {
@ -269,17 +337,15 @@ static int gpio_nand_probe(struct platform_device *pdev)
ret = PTR_ERR(gpiomtd->rdy);
goto out_ce;
}
/* Using RDY pin */
if (gpiomtd->rdy)
chip->legacy.dev_ready = gpio_nand_devready;
nand_controller_init(&gpiomtd->base);
gpiomtd->base.ops = &gpio_nand_ops;
nand_set_flash_node(chip, pdev->dev.of_node);
chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
chip->options = gpiomtd->plat.options;
chip->legacy.chip_delay = gpiomtd->plat.chip_delay;
chip->legacy.cmd_ctrl = gpio_nand_cmd_ctrl;
chip->controller = &gpiomtd->base;
mtd = nand_to_mtd(chip);
mtd->dev.parent = dev;

View File

@ -736,8 +736,8 @@ static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
udelay(dll_wait_time_us);
}
static int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
static int gpmi_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_interface_config *conf)
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
const struct nand_sdr_timings *sdr;
@ -2400,7 +2400,7 @@ unmap:
static const struct nand_controller_ops gpmi_nand_controller_ops = {
.attach_chip = gpmi_nand_attach_chip,
.setup_data_interface = gpmi_setup_data_interface,
.setup_interface = gpmi_setup_interface,
.exec_op = gpmi_nfc_exec_op,
};

View File

@ -90,8 +90,8 @@ static int jz4740_ecc_calculate(struct ingenic_ecc *ecc,
* If the written data is completely 0xff, we also want to write 0xff as
* ECC, otherwise we will get in trouble when doing subpage writes.
*/
if (memcmp(ecc_code, empty_block_ecc, ARRAY_SIZE(empty_block_ecc)) == 0)
memset(ecc_code, 0xff, ARRAY_SIZE(empty_block_ecc));
if (memcmp(ecc_code, empty_block_ecc, sizeof(empty_block_ecc)) == 0)
memset(ecc_code, 0xff, sizeof(empty_block_ecc));
return 0;
}

View File

@ -53,12 +53,12 @@ struct nand_manufacturer_ops {
};
/**
* struct nand_manufacturer - NAND Flash Manufacturer structure
* struct nand_manufacturer_desc - NAND Flash Manufacturer descriptor
* @name: Manufacturer name
* @id: manufacturer ID code of device.
* @ops: manufacturer operations
*/
struct nand_manufacturer {
struct nand_manufacturer_desc {
int id;
char *name;
const struct nand_manufacturer_ops *ops;
@ -79,14 +79,21 @@ extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
extern const struct mtd_pairing_scheme dist3_pairing_scheme;
/* Core functions */
const struct nand_manufacturer *nand_get_manufacturer(u8 id);
const struct nand_manufacturer_desc *nand_get_manufacturer_desc(u8 id);
int nand_bbm_get_next_page(struct nand_chip *chip, int page);
int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs);
int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
int allowbbt);
int onfi_fill_data_interface(struct nand_chip *chip,
enum nand_data_interface_type type,
int timing_mode);
void onfi_fill_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface,
enum nand_interface_type type,
unsigned int timing_mode);
unsigned int
onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings);
int nand_choose_best_sdr_timings(struct nand_chip *chip,
struct nand_interface_config *iface,
struct nand_sdr_timings *spec_timings);
const struct nand_interface_config *nand_get_reset_interface_config(void);
int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
@ -130,10 +137,10 @@ static inline int nand_exec_op(struct nand_chip *chip,
return chip->controller->ops->exec_op(chip, op, false);
}
static inline bool nand_has_setup_data_iface(struct nand_chip *chip)
static inline bool nand_controller_can_setup_interface(struct nand_chip *chip)
{
if (!chip->controller || !chip->controller->ops ||
!chip->controller->ops->setup_data_interface)
!chip->controller->ops->setup_interface)
return false;
if (chip->options & NAND_KEEP_TIMINGS)

View File

@ -1096,6 +1096,8 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
const u8 *oob_buf, bool raw,
int page)
{
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
@ -1141,7 +1143,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
return ret;
ret = marvell_nfc_wait_op(chip,
PSEC_TO_MSEC(chip->data_interface.timings.sdr.tPROG_max));
PSEC_TO_MSEC(sdr->tPROG_max));
return ret;
}
@ -1562,6 +1564,8 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
const u8 *data = buf;
@ -1598,8 +1602,7 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
marvell_nfc_wait_ndrun(chip);
}
ret = marvell_nfc_wait_op(chip,
PSEC_TO_MSEC(chip->data_interface.timings.sdr.tPROG_max));
ret = marvell_nfc_wait_op(chip, PSEC_TO_MSEC(sdr->tPROG_max));
marvell_nfc_disable_hw_ecc(chip);
@ -2305,9 +2308,8 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.pattern = bbt_mirror_pattern
};
static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface
*conf)
static int marvell_nfc_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_interface_config *conf)
{
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
@ -2508,7 +2510,7 @@ static int marvell_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops marvell_nand_controller_ops = {
.attach_chip = marvell_nand_attach_chip,
.exec_op = marvell_nfc_exec_op,
.setup_data_interface = marvell_nfc_setup_data_interface,
.setup_interface = marvell_nfc_setup_interface,
};
static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
@ -2644,7 +2646,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
/*
* Save a reference value for timing registers before
* ->setup_data_interface() is called.
* ->setup_interface() is called.
*/
marvell_nand->ndtr0 = readl_relaxed(nfc->regs + NDTR0);
marvell_nand->ndtr1 = readl_relaxed(nfc->regs + NDTR1);

View File

@ -573,10 +573,10 @@ static int meson_nfc_write_buf(struct nand_chip *nand, u8 *buf, int len)
static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
int page, bool in)
{
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(nand));
struct mtd_info *mtd = nand_to_mtd(nand);
struct meson_nfc *nfc = nand_get_controller_data(nand);
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&nand->data_interface);
u32 *addrs = nfc->cmdfifo.rw.addrs;
u32 cs = nfc->param.chip_select;
u32 cmd0, cmd_num, row_start;
@ -626,9 +626,9 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
static int meson_nfc_write_page_sub(struct nand_chip *nand,
int page, int raw)
{
struct mtd_info *mtd = nand_to_mtd(nand);
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&nand->data_interface);
nand_get_sdr_timings(nand_get_interface_config(nand));
struct mtd_info *mtd = nand_to_mtd(nand);
struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
struct meson_nfc *nfc = nand_get_controller_data(nand);
int data_len, info_len;
@ -1097,8 +1097,8 @@ static int meson_chip_buffer_init(struct nand_chip *nand)
}
static
int meson_nfc_setup_data_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf)
int meson_nfc_setup_interface(struct nand_chip *nand, int csline,
const struct nand_interface_config *conf)
{
struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
const struct nand_sdr_timings *timings;
@ -1222,7 +1222,7 @@ static int meson_nand_attach_chip(struct nand_chip *nand)
static const struct nand_controller_ops meson_nand_controller_ops = {
.attach_chip = meson_nand_attach_chip,
.detach_chip = meson_nand_detach_chip,
.setup_data_interface = meson_nfc_setup_data_interface,
.setup_interface = meson_nfc_setup_interface,
.exec_op = meson_nfc_exec_op,
};

View File

@ -387,44 +387,6 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
return 0;
}
static void mtk_nfc_select_chip(struct nand_chip *nand, int chip)
{
struct mtk_nfc *nfc = nand_get_controller_data(nand);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
if (chip < 0)
return;
mtk_nfc_hw_runtime_config(nand_to_mtd(nand));
nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
}
static int mtk_nfc_dev_ready(struct nand_chip *nand)
{
struct mtk_nfc *nfc = nand_get_controller_data(nand);
if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
return 0;
return 1;
}
static void mtk_nfc_cmd_ctrl(struct nand_chip *chip, int dat,
unsigned int ctrl)
{
struct mtk_nfc *nfc = nand_get_controller_data(chip);
if (ctrl & NAND_ALE) {
mtk_nfc_send_address(nfc, dat);
} else if (ctrl & NAND_CLE) {
mtk_nfc_hw_reset(nfc);
nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
mtk_nfc_send_command(nfc, dat);
}
}
static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
{
int rc;
@ -501,8 +463,76 @@ static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
mtk_nfc_write_byte(chip, buf[i]);
}
static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
static int mtk_nfc_exec_instr(struct nand_chip *chip,
const struct nand_op_instr *instr)
{
struct mtk_nfc *nfc = nand_get_controller_data(chip);
unsigned int i;
u32 status;
switch (instr->type) {
case NAND_OP_CMD_INSTR:
mtk_nfc_send_command(nfc, instr->ctx.cmd.opcode);
return 0;
case NAND_OP_ADDR_INSTR:
for (i = 0; i < instr->ctx.addr.naddrs; i++)
mtk_nfc_send_address(nfc, instr->ctx.addr.addrs[i]);
return 0;
case NAND_OP_DATA_IN_INSTR:
mtk_nfc_read_buf(chip, instr->ctx.data.buf.in,
instr->ctx.data.len);
return 0;
case NAND_OP_DATA_OUT_INSTR:
mtk_nfc_write_buf(chip, instr->ctx.data.buf.out,
instr->ctx.data.len);
return 0;
case NAND_OP_WAITRDY_INSTR:
return readl_poll_timeout(nfc->regs + NFI_STA, status,
status & STA_BUSY, 20,
instr->ctx.waitrdy.timeout_ms);
default:
break;
}
return -EINVAL;
}
static void mtk_nfc_select_target(struct nand_chip *nand, unsigned int cs)
{
struct mtk_nfc *nfc = nand_get_controller_data(nand);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
mtk_nfc_hw_runtime_config(nand_to_mtd(nand));
nfi_writel(nfc, mtk_nand->sels[cs], NFI_CSEL);
}
static int mtk_nfc_exec_op(struct nand_chip *chip,
const struct nand_operation *op,
bool check_only)
{
struct mtk_nfc *nfc = nand_get_controller_data(chip);
unsigned int i;
int ret = 0;
if (check_only)
return 0;
mtk_nfc_hw_reset(nfc);
nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
mtk_nfc_select_target(chip, op->cs);
for (i = 0; i < op->ninstrs; i++) {
ret = mtk_nfc_exec_instr(chip, &op->instrs[i]);
if (ret)
break;
}
return ret;
}
static int mtk_nfc_setup_interface(struct nand_chip *chip, int csline,
const struct nand_interface_config *conf)
{
struct mtk_nfc *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *timings;
@ -803,6 +833,7 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
u32 reg;
int ret;
mtk_nfc_select_target(chip, chip->cur_cs);
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
if (!raw) {
@ -920,6 +951,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
u8 *buf;
int rc;
mtk_nfc_select_target(chip, chip->cur_cs);
start = data_offs / chip->ecc.size;
end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
@ -1325,7 +1357,8 @@ static int mtk_nfc_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops mtk_nfc_controller_ops = {
.attach_chip = mtk_nfc_attach_chip,
.setup_data_interface = mtk_nfc_setup_data_interface,
.setup_interface = mtk_nfc_setup_interface,
.exec_op = mtk_nfc_exec_op,
};
static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
@ -1381,13 +1414,6 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
nand_set_controller_data(nand, nfc);
nand->options |= NAND_USES_DMA | NAND_SUBPAGE_READ;
nand->legacy.dev_ready = mtk_nfc_dev_ready;
nand->legacy.select_chip = mtk_nfc_select_chip;
nand->legacy.write_byte = mtk_nfc_write_byte;
nand->legacy.write_buf = mtk_nfc_write_buf;
nand->legacy.read_byte = mtk_nfc_read_byte;
nand->legacy.read_buf = mtk_nfc_read_buf;
nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl;
/* set default mode in case dt entry is missing */
nand->ecc.mode = NAND_ECC_HW;

View File

@ -137,8 +137,8 @@ struct mxc_nand_devtype_data {
u32 (*get_ecc_status)(struct mxc_nand_host *);
const struct mtd_ooblayout_ops *ooblayout;
void (*select_chip)(struct nand_chip *chip, int cs);
int (*setup_data_interface)(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf);
int (*setup_interface)(struct nand_chip *chip, int csline,
const struct nand_interface_config *conf);
void (*enable_hwecc)(struct nand_chip *chip, bool enable);
/*
@ -1139,8 +1139,8 @@ static void preset_v1(struct mtd_info *mtd)
writew(0x4, NFC_V1_V2_WRPROT);
}
static int mxc_nand_v2_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
static int mxc_nand_v2_setup_interface(struct nand_chip *chip, int csline,
const struct nand_interface_config *conf)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
int tRC_min_ns, tRC_ps, ret;
@ -1432,7 +1432,7 @@ static int mxc_nand_get_features(struct nand_chip *chip, int addr,
}
/*
* The generic flash bbt decriptors overlap with our ecc
* The generic flash bbt descriptors overlap with our ecc
* hardware, so define some i.MX specific ones.
*/
static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
@ -1521,7 +1521,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.get_ecc_status = get_ecc_status_v2,
.ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v2,
.setup_data_interface = mxc_nand_v2_setup_data_interface,
.setup_interface = mxc_nand_v2_setup_interface,
.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
.irqpending_quirk = 0,
.needs_ip = 0,
@ -1738,17 +1738,17 @@ static int mxcnd_attach_chip(struct nand_chip *chip)
return 0;
}
static int mxcnd_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
static int mxcnd_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_interface_config *conf)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
return host->devtype_data->setup_data_interface(chip, chipnr, conf);
return host->devtype_data->setup_interface(chip, chipnr, conf);
}
static const struct nand_controller_ops mxcnd_controller_ops = {
.attach_chip = mxcnd_attach_chip,
.setup_data_interface = mxcnd_setup_data_interface,
.setup_interface = mxcnd_setup_interface,
};
static int mxcnd_probe(struct platform_device *pdev)
@ -1809,7 +1809,7 @@ static int mxcnd_probe(struct platform_device *pdev)
if (err < 0)
return err;
if (!host->devtype_data->setup_data_interface)
if (!host->devtype_data->setup_interface)
this->options |= NAND_KEEP_TIMINGS;
if (host->devtype_data->needs_ip) {

View File

@ -451,8 +451,8 @@ static int mxic_nfc_exec_op(struct nand_chip *chip,
return ret;
}
static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
static int mxic_nfc_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_interface_config *conf)
{
struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *sdr;
@ -480,7 +480,7 @@ static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
static const struct nand_controller_ops mxic_nand_controller_ops = {
.exec_op = mxic_nfc_exec_op,
.setup_data_interface = mxic_nfc_setup_data_interface,
.setup_interface = mxic_nfc_setup_interface,
};
static int mxic_nfc_probe(struct platform_device *pdev)

View File

@ -773,7 +773,7 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
return -ENOTSUPP;
/* Wait tWB before polling the STATUS reg. */
timings = nand_get_sdr_timings(&chip->data_interface);
timings = nand_get_sdr_timings(nand_get_interface_config(chip));
ndelay(PSEC_TO_NSEC(timings->tWB_max));
ret = nand_status_op(chip, NULL);
@ -898,7 +898,7 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr)
}
/**
* nand_reset_data_interface - Reset data interface and timings
* nand_reset_interface - Reset data interface and timings
* @chip: The NAND chip
* @chipnr: Internal die id
*
@ -906,11 +906,12 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr)
*
* Returns 0 for success or negative error code otherwise.
*/
static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
static int nand_reset_interface(struct nand_chip *chip, int chipnr)
{
const struct nand_controller_ops *ops = chip->controller->ops;
int ret;
if (!nand_has_setup_data_iface(chip))
if (!nand_controller_can_setup_interface(chip))
return 0;
/*
@ -927,9 +928,9 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
* timings to timing mode 0.
*/
onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
ret = chip->controller->ops->setup_data_interface(chip, chipnr,
&chip->data_interface);
chip->current_interface_config = nand_get_reset_interface_config();
ret = ops->setup_interface(chip, chipnr,
chip->current_interface_config);
if (ret)
pr_err("Failed to configure data interface to SDR timing mode 0\n");
@ -937,28 +938,36 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
}
/**
* nand_setup_data_interface - Setup the best data interface and timings
* nand_setup_interface - Setup the best data interface and timings
* @chip: The NAND chip
* @chipnr: Internal die id
*
* Find and configure the best data interface and NAND timings supported by
* the chip and the driver.
* First tries to retrieve supported timing modes from ONFI information,
* and if the NAND chip does not support ONFI, relies on the
* ->onfi_timing_mode_default specified in the nand_ids table.
* Configure what has been reported to be the best data interface and NAND
* timings supported by the chip and the driver.
*
* Returns 0 for success or negative error code otherwise.
*/
static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
static int nand_setup_interface(struct nand_chip *chip, int chipnr)
{
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
const struct nand_controller_ops *ops = chip->controller->ops;
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { };
int ret;
if (!nand_has_setup_data_iface(chip))
if (!nand_controller_can_setup_interface(chip))
return 0;
/*
* A nand_reset_interface() put both the NAND chip and the NAND
* controller in timings mode 0. If the default mode for this chip is
* also 0, no need to proceed to the change again. Plus, at probe time,
* nand_setup_interface() uses ->set/get_features() which would
* fail anyway as the parameter page is not available yet.
*/
if (!chip->best_interface_config)
return 0;
tmode_param[0] = chip->best_interface_config->timings.mode;
/* Change the mode on the chip side (if supported by the NAND chip) */
if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
nand_select_target(chip, chipnr);
@ -970,14 +979,13 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
}
/* Change the mode on the controller side */
ret = chip->controller->ops->setup_data_interface(chip, chipnr,
&chip->data_interface);
ret = ops->setup_interface(chip, chipnr, chip->best_interface_config);
if (ret)
return ret;
/* Check the mode has been accepted by the chip, if supported */
if (!nand_supports_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE))
return 0;
goto update_interface_config;
memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
nand_select_target(chip, chipnr);
@ -987,12 +995,15 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
if (ret)
goto err_reset_chip;
if (tmode_param[0] != chip->onfi_timing_mode_default) {
if (tmode_param[0] != chip->best_interface_config->timings.mode) {
pr_warn("timing mode %d not acknowledged by the NAND chip\n",
chip->onfi_timing_mode_default);
chip->best_interface_config->timings.mode);
goto err_reset_chip;
}
update_interface_config:
chip->current_interface_config = chip->best_interface_config;
return 0;
err_reset_chip:
@ -1000,7 +1011,7 @@ err_reset_chip:
* Fallback to mode 0 if the chip explicitly did not ack the chosen
* timing mode.
*/
nand_reset_data_interface(chip, chipnr);
nand_reset_interface(chip, chipnr);
nand_select_target(chip, chipnr);
nand_reset_op(chip);
nand_deselect_target(chip);
@ -1009,59 +1020,90 @@ err_reset_chip:
}
/**
* nand_init_data_interface - find the best data interface and timings
* nand_choose_best_sdr_timings - Pick up the best SDR timings that both the
* NAND controller and the NAND chip support
* @chip: the NAND chip
* @iface: the interface configuration (can eventually be updated)
* @spec_timings: specific timings, when not fitting the ONFI specification
*
* If specific timings are provided, use them. Otherwise, retrieve supported
* timing modes from ONFI information.
*/
int nand_choose_best_sdr_timings(struct nand_chip *chip,
struct nand_interface_config *iface,
struct nand_sdr_timings *spec_timings)
{
const struct nand_controller_ops *ops = chip->controller->ops;
int best_mode = 0, mode, ret;
iface->type = NAND_SDR_IFACE;
if (spec_timings) {
iface->timings.sdr = *spec_timings;
iface->timings.mode = onfi_find_closest_sdr_mode(spec_timings);
/* Verify the controller supports the requested interface */
ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
iface);
if (!ret) {
chip->best_interface_config = iface;
return ret;
}
/* Fallback to slower modes */
best_mode = iface->timings.mode;
} else if (chip->parameters.onfi) {
best_mode = fls(chip->parameters.onfi->async_timing_mode) - 1;
}
for (mode = best_mode; mode >= 0; mode--) {
onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, mode);
ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
iface);
if (!ret)
break;
}
chip->best_interface_config = iface;
return 0;
}
/**
* nand_choose_interface_config - find the best data interface and timings
* @chip: The NAND chip
*
* Find the best data interface and NAND timings supported by the chip
* and the driver.
* First tries to retrieve supported timing modes from ONFI information,
* and if the NAND chip does not support ONFI, relies on the
* ->onfi_timing_mode_default specified in the nand_ids table. After this
* function nand_chip->data_interface is initialized with the best timing mode
* available.
* and the driver. Eventually let the NAND manufacturer driver propose his own
* set of timings.
*
* After this function nand_chip->interface_config is initialized with the best
* timing mode available.
*
* Returns 0 for success or negative error code otherwise.
*/
static int nand_init_data_interface(struct nand_chip *chip)
static int nand_choose_interface_config(struct nand_chip *chip)
{
int modes, mode, ret;
struct nand_interface_config *iface;
int ret;
if (!nand_has_setup_data_iface(chip))
if (!nand_controller_can_setup_interface(chip))
return 0;
/*
* First try to identify the best timings from ONFI parameters and
* if the NAND does not support ONFI, fallback to the default ONFI
* timing mode.
*/
if (chip->parameters.onfi) {
modes = chip->parameters.onfi->async_timing_mode;
} else {
if (!chip->onfi_timing_mode_default)
return 0;
iface = kzalloc(sizeof(*iface), GFP_KERNEL);
if (!iface)
return -ENOMEM;
modes = GENMASK(chip->onfi_timing_mode_default, 0);
}
if (chip->ops.choose_interface_config)
ret = chip->ops.choose_interface_config(chip, iface);
else
ret = nand_choose_best_sdr_timings(chip, iface, NULL);
for (mode = fls(modes) - 1; mode >= 0; mode--) {
ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode);
if (ret)
continue;
if (ret)
kfree(iface);
/*
* Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the
* controller supports the requested timings.
*/
ret = chip->controller->ops->setup_data_interface(chip,
NAND_DATA_IFACE_CHECK_ONLY,
&chip->data_interface);
if (!ret) {
chip->onfi_timing_mode_default = mode;
break;
}
}
return 0;
return ret;
}
/**
@ -1122,9 +1164,9 @@ static int nand_sp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf,
unsigned int len)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct mtd_info *mtd = nand_to_mtd(chip);
u8 addrs[4];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
@ -1166,7 +1208,7 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int len)
{
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
u8 addrs[5];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
@ -1263,7 +1305,7 @@ int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_PARAM, 0),
NAND_OP_ADDR(1, &page, PSEC_TO_NSEC(sdr->tWB_max)),
@ -1318,7 +1360,7 @@ int nand_change_read_column_op(struct nand_chip *chip,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
u8 addrs[2] = {};
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RNDOUT, 0),
@ -1392,9 +1434,9 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, const void *buf,
unsigned int len, bool prog)
{
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct mtd_info *mtd = nand_to_mtd(chip);
u8 addrs[5] = {};
struct nand_op_instr instrs[] = {
/*
@ -1517,7 +1559,7 @@ int nand_prog_page_end_op(struct nand_chip *chip)
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_PAGEPROG,
PSEC_TO_NSEC(sdr->tWB_max)),
@ -1624,7 +1666,7 @@ int nand_change_write_column_op(struct nand_chip *chip,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
u8 addrs[2];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RNDIN, 0),
@ -1679,7 +1721,7 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READID, 0),
NAND_OP_ADDR(1, &addr, PSEC_TO_NSEC(sdr->tADL_min)),
@ -1718,7 +1760,7 @@ int nand_status_op(struct nand_chip *chip, u8 *status)
{
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_STATUS,
PSEC_TO_NSEC(sdr->tADL_min)),
@ -1787,7 +1829,7 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
u8 addrs[3] = { page, page >> 8, page >> 16 };
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_ERASE1, 0),
@ -1846,7 +1888,7 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_SET_FEATURES, 0),
NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tADL_min)),
@ -1893,7 +1935,7 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_GET_FEATURES, 0),
NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tWB_max)),
@ -1950,7 +1992,7 @@ int nand_reset_op(struct nand_chip *chip)
{
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RESET, PSEC_TO_NSEC(sdr->tWB_max)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tRST_max), 0),
@ -2480,17 +2522,16 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len);
* @chipnr: Internal die id
*
* Save the timings data structure, then apply SDR timings mode 0 (see
* nand_reset_data_interface for details), do the reset operation, and
* apply back the previous timings.
* nand_reset_interface for details), do the reset operation, and apply
* back the previous timings.
*
* Returns 0 on success, a negative error code otherwise.
*/
int nand_reset(struct nand_chip *chip, int chipnr)
{
struct nand_data_interface saved_data_intf = chip->data_interface;
int ret;
ret = nand_reset_data_interface(chip, chipnr);
ret = nand_reset_interface(chip, chipnr);
if (ret)
return ret;
@ -2505,18 +2546,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
if (ret)
return ret;
/*
* A nand_reset_data_interface() put both the NAND chip and the NAND
* controller in timings mode 0. If the default mode for this chip is
* also 0, no need to proceed to the change again. Plus, at probe time,
* nand_setup_data_interface() uses ->set/get_features() which would
* fail anyway as the parameter page is not available yet.
*/
if (!chip->onfi_timing_mode_default)
return 0;
chip->data_interface = saved_data_intf;
ret = nand_setup_data_interface(chip, chipnr);
ret = nand_setup_interface(chip, chipnr);
if (ret)
return ret;
@ -3215,10 +3245,10 @@ static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
if (retry_mode >= chip->read_retries)
return -EINVAL;
if (!chip->setup_read_retry)
if (!chip->ops.setup_read_retry)
return -EOPNOTSUPP;
return chip->setup_read_retry(chip, retry_mode);
return chip->ops.setup_read_retry(chip, retry_mode);
}
static void nand_wait_readrdy(struct nand_chip *chip)
@ -3228,7 +3258,7 @@ static void nand_wait_readrdy(struct nand_chip *chip)
if (!(chip->options & NAND_NEED_READRDY))
return;
sdr = nand_get_sdr_timings(&chip->data_interface);
sdr = nand_get_sdr_timings(nand_get_interface_config(chip));
WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0));
}
@ -4462,8 +4492,8 @@ static int nand_suspend(struct mtd_info *mtd)
int ret = 0;
mutex_lock(&chip->lock);
if (chip->suspend)
ret = chip->suspend(chip);
if (chip->ops.suspend)
ret = chip->ops.suspend(chip);
if (!ret)
chip->suspended = 1;
mutex_unlock(&chip->lock);
@ -4481,8 +4511,8 @@ static void nand_resume(struct mtd_info *mtd)
mutex_lock(&chip->lock);
if (chip->suspended) {
if (chip->resume)
chip->resume(chip);
if (chip->ops.resume)
chip->ops.resume(chip);
chip->suspended = 0;
} else {
pr_err("%s called for a chip which is not in suspended state\n",
@ -4511,10 +4541,10 @@ static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if (!chip->lock_area)
if (!chip->ops.lock_area)
return -ENOTSUPP;
return chip->lock_area(chip, ofs, len);
return chip->ops.lock_area(chip, ofs, len);
}
/**
@ -4527,10 +4557,10 @@ static int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if (!chip->unlock_area)
if (!chip->ops.unlock_area)
return -ENOTSUPP;
return chip->unlock_area(chip, ofs, len);
return chip->ops.unlock_area(chip, ofs, len);
}
/* Set default functions */
@ -4743,8 +4773,6 @@ static bool find_full_id_nand(struct nand_chip *chip,
chip->options |= type->options;
chip->base.eccreq.strength = NAND_ECC_STRENGTH(type);
chip->base.eccreq.step_size = NAND_ECC_STEP(type);
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;
chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
if (!chip->parameters.model)
@ -4810,9 +4838,9 @@ static void nand_manufacturer_cleanup(struct nand_chip *chip)
}
static const char *
nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc)
{
return manufacturer ? manufacturer->name : "Unknown";
return manufacturer_desc ? manufacturer_desc->name : "Unknown";
}
/*
@ -4820,7 +4848,7 @@ nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
*/
static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
{
const struct nand_manufacturer *manufacturer;
const struct nand_manufacturer_desc *manufacturer_desc;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
int busw, ret;
@ -4877,8 +4905,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data));
/* Try to identify manufacturer */
manufacturer = nand_get_manufacturer(maf_id);
chip->manufacturer.desc = manufacturer;
manufacturer_desc = nand_get_manufacturer_desc(maf_id);
chip->manufacturer.desc = manufacturer_desc;
if (!type)
type = nand_flash_ids;
@ -4957,7 +4985,7 @@ ident_done:
*/
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
maf_id, dev_id);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
pr_info("%s %s\n", nand_manufacturer_name(manufacturer_desc),
mtd->name);
pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
@ -4992,7 +5020,7 @@ ident_done:
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
maf_id, dev_id);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
pr_info("%s %s\n", nand_manufacturer_name(manufacturer_desc),
chip->parameters.model);
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
(int)(targetsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
@ -5185,7 +5213,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
mutex_init(&chip->lock);
/* Enforce the right timings for reset/detection */
onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
chip->current_interface_config = nand_get_reset_interface_config();
ret = nand_dt_init(chip);
if (ret)
@ -5972,16 +6000,16 @@ static int nand_scan_tail(struct nand_chip *chip)
if (!mtd->bitflip_threshold)
mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
/* Initialize the ->data_interface field. */
ret = nand_init_data_interface(chip);
/* Find the fastest data interface for this chip */
ret = nand_choose_interface_config(chip);
if (ret)
goto err_nanddev_cleanup;
/* Enter fastest possible mode on all dies. */
for (i = 0; i < nanddev_ntargets(&chip->base); i++) {
ret = nand_setup_data_interface(chip, i);
ret = nand_setup_interface(chip, i);
if (ret)
goto err_nanddev_cleanup;
goto err_free_interface_config;
}
/* Check, if we should skip the bad block table scan */
@ -5991,10 +6019,12 @@ static int nand_scan_tail(struct nand_chip *chip)
/* Build bad block table */
ret = nand_create_bbt(chip);
if (ret)
goto err_nanddev_cleanup;
goto err_free_interface_config;
return 0;
err_free_interface_config:
kfree(chip->best_interface_config);
err_nanddev_cleanup:
nanddev_cleanup(&chip->base);
@ -6088,6 +6118,9 @@ void nand_cleanup(struct nand_chip *chip)
& NAND_BBT_DYNAMICSTRUCT)
kfree(chip->badblock_pattern);
/* Free the data interface */
kfree(chip->best_interface_config);
/* Free manufacturer priv data. */
nand_manufacturer_cleanup(chip);

View File

@ -1226,7 +1226,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
return -ENOMEM;
/*
* If no primary table decriptor is given, scan the device to build a
* If no primary table descriptor is given, scan the device to build a
* memory based bad block table.
*/
if (!td) {

View File

@ -337,7 +337,7 @@ static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip,
rr->nregs = nregs;
rr->regs = hynix_1xnm_mlc_read_retry_regs;
hynix->read_retry = rr;
chip->setup_read_retry = hynix_nand_setup_read_retry;
chip->ops.setup_read_retry = hynix_nand_setup_read_retry;
chip->read_retries = nmodes;
out:
@ -673,6 +673,15 @@ static void hynix_nand_cleanup(struct nand_chip *chip)
nand_set_manufacturer_data(chip, NULL);
}
static int
h27ucg8t2atrbc_choose_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface)
{
onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4);
return nand_choose_best_sdr_timings(chip, iface, NULL);
}
static int hynix_nand_init(struct nand_chip *chip)
{
struct hynix_nand *hynix;
@ -689,6 +698,11 @@ static int hynix_nand_init(struct nand_chip *chip)
nand_set_manufacturer_data(chip, hynix);
if (!strncmp("H27UCG8T2ATR-BC", chip->parameters.model,
sizeof("H27UCG8T2ATR-BC") - 1))
chip->ops.choose_interface_config =
h27ucg8t2atrbc_choose_interface_config;
ret = hynix_nand_rr_init(chip);
if (ret)
hynix_nand_cleanup(chip);

View File

@ -28,8 +28,7 @@ struct nand_flash_dev nand_flash_ids[] = {
*/
{"TC58NVG0S3E 1G 3.3V 8-bit",
{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512),
2 },
SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), },
{"TC58NVG2S0F 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
@ -51,7 +50,10 @@ struct nand_flash_dev nand_flash_ids[] = {
{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
NAND_ECC_INFO(40, SZ_1K), 4 },
NAND_ECC_INFO(40, SZ_1K) },
{"TH58NVG2S3HBAI4 4G 3.3V 8-bit",
{ .id = {0x98, 0xdc, 0x91, 0x15, 0x76} },
SZ_2K, SZ_512, SZ_128K, 0, 5, 128, NAND_ECC_INFO(8, SZ_512) },
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
@ -166,7 +168,7 @@ struct nand_flash_dev nand_flash_ids[] = {
};
/* Manufacturer IDs */
static const struct nand_manufacturer nand_manufacturers[] = {
static const struct nand_manufacturer_desc nand_manufacturer_descs[] = {
{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
{NAND_MFR_ATO, "ATO"},
{NAND_MFR_EON, "Eon"},
@ -186,20 +188,20 @@ static const struct nand_manufacturer nand_manufacturers[] = {
};
/**
* nand_get_manufacturer - Get manufacturer information from the manufacturer
* ID
* nand_get_manufacturer_desc - Get manufacturer information from the
* manufacturer ID
* @id: manufacturer ID
*
* Returns a pointer a nand_manufacturer object if the manufacturer is defined
* Returns a nand_manufacturer_desc object if the manufacturer is defined
* in the NAND manufacturers database, NULL otherwise.
*/
const struct nand_manufacturer *nand_get_manufacturer(u8 id)
const struct nand_manufacturer_desc *nand_get_manufacturer_desc(u8 id)
{
int i;
for (i = 0; i < ARRAY_SIZE(nand_manufacturers); i++)
if (nand_manufacturers[i].id == id)
return &nand_manufacturers[i];
for (i = 0; i < ARRAY_SIZE(nand_manufacturer_descs); i++)
if (nand_manufacturer_descs[i].id == id)
return &nand_manufacturer_descs[i];
return NULL;
}

View File

@ -354,6 +354,9 @@ static void nand_command(struct nand_chip *chip, unsigned int command,
static void nand_ccs_delay(struct nand_chip *chip)
{
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
/*
* The controller already takes care of waiting for tCCS when the RNDIN
* or RNDOUT command is sent, return directly.
@ -365,8 +368,8 @@ static void nand_ccs_delay(struct nand_chip *chip)
* Wait tCCS_min if it is correctly defined, otherwise wait 500ns
* (which should be safe for all NANDs).
*/
if (nand_has_setup_data_iface(chip))
ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
if (nand_controller_can_setup_interface(chip))
ndelay(sdr->tCCS_min / 1000);
else
ndelay(500);
}

View File

@ -130,7 +130,7 @@ static void macronix_nand_onfi_init(struct nand_chip *chip)
return;
chip->read_retries = MACRONIX_NUM_READ_RETRY_MODES;
chip->setup_read_retry = macronix_nand_setup_read_retry;
chip->ops.setup_read_retry = macronix_nand_setup_read_retry;
if (p->supports_set_get_features) {
bitmap_set(p->set_feature_list,
@ -242,8 +242,8 @@ static void macronix_nand_block_protection_support(struct nand_chip *chip)
bitmap_set(chip->parameters.set_feature_list,
ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1);
chip->lock_area = mxic_nand_lock;
chip->unlock_area = mxic_nand_unlock;
chip->ops.lock_area = mxic_nand_lock;
chip->ops.unlock_area = mxic_nand_unlock;
}
static int nand_power_down_op(struct nand_chip *chip)
@ -312,8 +312,8 @@ static void macronix_nand_deep_power_down_support(struct nand_chip *chip)
if (i < 0)
return;
chip->suspend = mxic_nand_suspend;
chip->resume = mxic_nand_resume;
chip->ops.suspend = mxic_nand_suspend;
chip->ops.resume = mxic_nand_resume;
}
static int macronix_nand_init(struct nand_chip *chip)

View File

@ -84,7 +84,7 @@ static int micron_nand_onfi_init(struct nand_chip *chip)
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;
chip->ops.setup_read_retry = micron_nand_setup_read_retry;
}
if (p->supports_set_get_features) {

View File

@ -12,7 +12,14 @@
#define ONFI_DYN_TIMING_MAX U16_MAX
static const struct nand_data_interface onfi_sdr_timings[] = {
/*
* 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.
*
* These four values are tweaked to be more accurate in the case of ONFI chips.
*/
static const struct nand_interface_config onfi_sdr_timings[] = {
/* Mode 0 */
{
.type = NAND_SDR_IFACE,
@ -20,6 +27,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000,
.tALH_min = 20000,
.tALS_min = 50000,
@ -63,6 +72,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000,
.tALH_min = 10000,
.tALS_min = 25000,
@ -106,6 +117,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000,
.tALH_min = 10000,
.tALS_min = 15000,
@ -149,6 +162,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
@ -192,6 +207,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
@ -235,6 +252,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
.timings.sdr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tADL_min = 400000,
.tALH_min = 5000,
.tALS_min = 10000,
@ -273,23 +292,79 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
},
};
/**
* onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
* given ONFI mode
* @mode: The ONFI timing mode
*/
int onfi_fill_data_interface(struct nand_chip *chip,
enum nand_data_interface_type type,
int timing_mode)
/* All NAND chips share the same reset data interface: SDR mode 0 */
const struct nand_interface_config *nand_get_reset_interface_config(void)
{
return &onfi_sdr_timings[0];
}
/**
* onfi_find_closest_sdr_mode - Derive the closest ONFI SDR timing mode given a
* set of timings
* @spec_timings: the timings to challenge
*/
unsigned int
onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings)
{
const struct nand_sdr_timings *onfi_timings;
int mode;
for (mode = ARRAY_SIZE(onfi_sdr_timings) - 1; mode > 0; mode--) {
onfi_timings = &onfi_sdr_timings[mode].timings.sdr;
if (spec_timings->tCCS_min <= onfi_timings->tCCS_min &&
spec_timings->tADL_min <= onfi_timings->tADL_min &&
spec_timings->tALH_min <= onfi_timings->tALH_min &&
spec_timings->tALS_min <= onfi_timings->tALS_min &&
spec_timings->tAR_min <= onfi_timings->tAR_min &&
spec_timings->tCEH_min <= onfi_timings->tCEH_min &&
spec_timings->tCH_min <= onfi_timings->tCH_min &&
spec_timings->tCLH_min <= onfi_timings->tCLH_min &&
spec_timings->tCLR_min <= onfi_timings->tCLR_min &&
spec_timings->tCLS_min <= onfi_timings->tCLS_min &&
spec_timings->tCOH_min <= onfi_timings->tCOH_min &&
spec_timings->tCS_min <= onfi_timings->tCS_min &&
spec_timings->tDH_min <= onfi_timings->tDH_min &&
spec_timings->tDS_min <= onfi_timings->tDS_min &&
spec_timings->tIR_min <= onfi_timings->tIR_min &&
spec_timings->tRC_min <= onfi_timings->tRC_min &&
spec_timings->tREH_min <= onfi_timings->tREH_min &&
spec_timings->tRHOH_min <= onfi_timings->tRHOH_min &&
spec_timings->tRHW_min <= onfi_timings->tRHW_min &&
spec_timings->tRLOH_min <= onfi_timings->tRLOH_min &&
spec_timings->tRP_min <= onfi_timings->tRP_min &&
spec_timings->tRR_min <= onfi_timings->tRR_min &&
spec_timings->tWC_min <= onfi_timings->tWC_min &&
spec_timings->tWH_min <= onfi_timings->tWH_min &&
spec_timings->tWHR_min <= onfi_timings->tWHR_min &&
spec_timings->tWP_min <= onfi_timings->tWP_min &&
spec_timings->tWW_min <= onfi_timings->tWW_min)
return mode;
}
return 0;
}
/**
* onfi_fill_interface_config - Initialize an interface config from a given
* ONFI mode
* @chip: The NAND chip
* @iface: The interface configuration to fill
* @type: The interface type
* @timing_mode: The ONFI timing mode
*/
void onfi_fill_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface,
enum nand_interface_type type,
unsigned 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;
if (WARN_ON(type != NAND_SDR_IFACE))
return;
if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
return -EINVAL;
if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_sdr_timings)))
return;
*iface = onfi_sdr_timings[timing_mode];
@ -308,22 +383,5 @@ int onfi_fill_data_interface(struct nand_chip *chip,
/* nanoseconds -> picoseconds */
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 = 200000000;
timings->tCCS_min = 500000;
}
return 0;
}

View File

@ -33,7 +33,7 @@ static int toshiba_nand_benand_read_eccstatus_op(struct nand_chip *chip,
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
nand_get_sdr_timings(nand_get_interface_config(chip));
struct nand_op_instr instrs[] = {
NAND_OP_CMD(TOSHIBA_NAND_CMD_ECC_STATUS_READ,
PSEC_TO_NSEC(sdr->tADL_min)),
@ -194,17 +194,79 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
}
}
static int
tc58teg5dclta00_choose_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface)
{
onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 5);
return nand_choose_best_sdr_timings(chip, iface, NULL);
}
static int
tc58nvg0s3e_choose_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface)
{
onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 2);
return nand_choose_best_sdr_timings(chip, iface, NULL);
}
static int
th58nvg2s3hbai4_choose_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface)
{
struct nand_sdr_timings *sdr = &iface->timings.sdr;
/* Start with timings from the closest timing mode, mode 4. */
onfi_fill_interface_config(chip, iface, NAND_SDR_IFACE, 4);
/* Patch timings that differ from mode 4. */
sdr->tALS_min = 12000;
sdr->tCHZ_max = 20000;
sdr->tCLS_min = 12000;
sdr->tCOH_min = 0;
sdr->tDS_min = 12000;
sdr->tRHOH_min = 25000;
sdr->tRHW_min = 30000;
sdr->tRHZ_max = 60000;
sdr->tWHR_min = 60000;
/* Patch timings not part of onfi timing mode. */
sdr->tPROG_max = 700000000;
sdr->tBERS_max = 5000000000;
return nand_choose_best_sdr_timings(chip, iface, sdr);
}
static int tc58teg5dclta00_init(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
chip->onfi_timing_mode_default = 5;
chip->ops.choose_interface_config =
&tc58teg5dclta00_choose_interface_config;
chip->options |= NAND_NEED_SCRAMBLING;
mtd_set_pairing_scheme(mtd, &dist3_pairing_scheme);
return 0;
}
static int tc58nvg0s3e_init(struct nand_chip *chip)
{
chip->ops.choose_interface_config =
&tc58nvg0s3e_choose_interface_config;
return 0;
}
static int th58nvg2s3hbai4_init(struct nand_chip *chip)
{
chip->ops.choose_interface_config =
&th58nvg2s3hbai4_choose_interface_config;
return 0;
}
static int toshiba_nand_init(struct nand_chip *chip)
{
if (nand_is_slc(chip))
@ -217,6 +279,12 @@ static int toshiba_nand_init(struct nand_chip *chip)
if (!strcmp("TC58TEG5DCLTA00", chip->parameters.model))
tc58teg5dclta00_init(chip);
if (!strncmp("TC58NVG0S3E", chip->parameters.model,
sizeof("TC58NVG0S3E") - 1))
tc58nvg0s3e_init(chip);
if (!strncmp("TH58NVG2S3HBAI4", chip->parameters.model,
sizeof("TH58NVG2S3HBAI4") - 1))
th58nvg2s3hbai4_init(chip);
return 0;
}

View File

@ -2,7 +2,7 @@
/*
* Error Location Module
*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
* Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/
*/
#define DRIVER_NAME "omap-elm"

View File

@ -459,11 +459,13 @@ struct qcom_nand_host {
* among different NAND controllers.
* @ecc_modes - ecc mode for NAND
* @is_bam - whether NAND controller is using BAM
* @is_qpic - whether NAND CTRL is part of qpic IP
* @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset
*/
struct qcom_nandc_props {
u32 ecc_modes;
bool is_bam;
bool is_qpic;
u32 dev_cmd_reg_start;
};
@ -2774,14 +2776,24 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
u32 nand_ctrl;
/* kill onenand */
nandc_write(nandc, SFLASHC_BURST_CFG, 0);
if (!nandc->props->is_qpic)
nandc_write(nandc, SFLASHC_BURST_CFG, 0);
nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD),
NAND_DEV_CMD_VLD_VAL);
/* enable ADM or BAM DMA */
if (nandc->props->is_bam) {
nand_ctrl = nandc_read(nandc, NAND_CTRL);
nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
/*
*NAND_CTRL is an operational registers, and CPU
* access to operational registers are read only
* in BAM mode. So update the NAND_CTRL register
* only if it is not in BAM mode. In most cases BAM
* mode will be enabled in bootloader
*/
if (!(nand_ctrl & BAM_MODE_EN))
nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN);
} else {
nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
}
@ -3035,12 +3047,14 @@ static const struct qcom_nandc_props ipq806x_nandc_props = {
static const struct qcom_nandc_props ipq4019_nandc_props = {
.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
.is_bam = true,
.is_qpic = true,
.dev_cmd_reg_start = 0x0,
};
static const struct qcom_nandc_props ipq8074_nandc_props = {
.ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
.is_bam = true,
.is_qpic = true,
.dev_cmd_reg_start = 0x7000,
};

View File

@ -808,8 +808,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
return -ENODEV;
}
static int s3c2410_nand_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
static int s3c2410_nand_setup_interface(struct nand_chip *chip, int csline,
const struct nand_interface_config *conf)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
@ -999,7 +999,7 @@ static int s3c2410_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops s3c24xx_nand_controller_ops = {
.attach_chip = s3c2410_nand_attach_chip,
.setup_data_interface = s3c2410_nand_setup_data_interface,
.setup_interface = s3c2410_nand_setup_interface,
};
static const struct of_device_id s3c24xx_nand_dt_ids[] = {

View File

@ -11,10 +11,13 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/mtd/rawnand.h>
#include <linux/of_address.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
/* Bad block marker length */
@ -242,7 +245,8 @@ struct stm32_fmc2_nfc {
struct nand_controller base;
struct stm32_fmc2_nand nand;
struct device *dev;
void __iomem *io_base;
struct device *cdev;
struct regmap *regmap;
void __iomem *data_base[FMC2_MAX_CE];
void __iomem *cmd_base[FMC2_MAX_CE];
void __iomem *addr_base[FMC2_MAX_CE];
@ -277,40 +281,37 @@ static void stm32_fmc2_nfc_timings_init(struct nand_chip *chip)
struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
struct stm32_fmc2_nand *nand = to_fmc2_nand(chip);
struct stm32_fmc2_timings *timings = &nand->timings;
u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR);
u32 pmem, patt;
/* Set tclr/tar timings */
pcr &= ~FMC2_PCR_TCLR;
pcr |= FIELD_PREP(FMC2_PCR_TCLR, timings->tclr);
pcr &= ~FMC2_PCR_TAR;
pcr |= FIELD_PREP(FMC2_PCR_TAR, timings->tar);
regmap_update_bits(nfc->regmap, FMC2_PCR,
FMC2_PCR_TCLR | FMC2_PCR_TAR,
FIELD_PREP(FMC2_PCR_TCLR, timings->tclr) |
FIELD_PREP(FMC2_PCR_TAR, timings->tar));
/* Set tset/twait/thold/thiz timings in common bank */
pmem = FIELD_PREP(FMC2_PMEM_MEMSET, timings->tset_mem);
pmem |= FIELD_PREP(FMC2_PMEM_MEMWAIT, timings->twait);
pmem |= FIELD_PREP(FMC2_PMEM_MEMHOLD, timings->thold_mem);
pmem |= FIELD_PREP(FMC2_PMEM_MEMHIZ, timings->thiz);
regmap_write(nfc->regmap, FMC2_PMEM, pmem);
/* Set tset/twait/thold/thiz timings in attribut bank */
patt = FIELD_PREP(FMC2_PATT_ATTSET, timings->tset_att);
patt |= FIELD_PREP(FMC2_PATT_ATTWAIT, timings->twait);
patt |= FIELD_PREP(FMC2_PATT_ATTHOLD, timings->thold_att);
patt |= FIELD_PREP(FMC2_PATT_ATTHIZ, timings->thiz);
writel_relaxed(pcr, nfc->io_base + FMC2_PCR);
writel_relaxed(pmem, nfc->io_base + FMC2_PMEM);
writel_relaxed(patt, nfc->io_base + FMC2_PATT);
regmap_write(nfc->regmap, FMC2_PATT, patt);
}
static void stm32_fmc2_nfc_setup(struct nand_chip *chip)
{
struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR);
u32 pcr = 0, pcr_mask;
/* Configure ECC algorithm (default configuration is Hamming) */
pcr &= ~FMC2_PCR_ECCALG;
pcr &= ~FMC2_PCR_BCHECC;
pcr_mask = FMC2_PCR_ECCALG;
pcr_mask |= FMC2_PCR_BCHECC;
if (chip->ecc.strength == FMC2_ECC_BCH8) {
pcr |= FMC2_PCR_ECCALG;
pcr |= FMC2_PCR_BCHECC;
@ -319,15 +320,15 @@ static void stm32_fmc2_nfc_setup(struct nand_chip *chip)
}
/* Set buswidth */
pcr &= ~FMC2_PCR_PWID;
pcr_mask |= FMC2_PCR_PWID;
if (chip->options & NAND_BUSWIDTH_16)
pcr |= FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16);
/* Set ECC sector size */
pcr &= ~FMC2_PCR_ECCSS;
pcr_mask |= FMC2_PCR_ECCSS;
pcr |= FIELD_PREP(FMC2_PCR_ECCSS, FMC2_PCR_ECCSS_512);
writel_relaxed(pcr, nfc->io_base + FMC2_PCR);
regmap_update_bits(nfc->regmap, FMC2_PCR, pcr_mask, pcr);
}
static int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr)
@ -393,81 +394,63 @@ static int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr)
static void stm32_fmc2_nfc_set_buswidth_16(struct stm32_fmc2_nfc *nfc, bool set)
{
u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR);
u32 pcr;
pcr &= ~FMC2_PCR_PWID;
if (set)
pcr |= FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16);
writel_relaxed(pcr, nfc->io_base + FMC2_PCR);
pcr = set ? FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16) :
FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_8);
regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_PWID, pcr);
}
static void stm32_fmc2_nfc_set_ecc(struct stm32_fmc2_nfc *nfc, bool enable)
{
u32 pcr = readl(nfc->io_base + FMC2_PCR);
pcr &= ~FMC2_PCR_ECCEN;
if (enable)
pcr |= FMC2_PCR_ECCEN;
writel(pcr, nfc->io_base + FMC2_PCR);
regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_ECCEN,
enable ? FMC2_PCR_ECCEN : 0);
}
static inline void stm32_fmc2_nfc_enable_seq_irq(struct stm32_fmc2_nfc *nfc)
static void stm32_fmc2_nfc_enable_seq_irq(struct stm32_fmc2_nfc *nfc)
{
u32 csqier = readl_relaxed(nfc->io_base + FMC2_CSQIER);
csqier |= FMC2_CSQIER_TCIE;
nfc->irq_state = FMC2_IRQ_SEQ;
writel_relaxed(csqier, nfc->io_base + FMC2_CSQIER);
regmap_update_bits(nfc->regmap, FMC2_CSQIER,
FMC2_CSQIER_TCIE, FMC2_CSQIER_TCIE);
}
static inline void stm32_fmc2_nfc_disable_seq_irq(struct stm32_fmc2_nfc *nfc)
static void stm32_fmc2_nfc_disable_seq_irq(struct stm32_fmc2_nfc *nfc)
{
u32 csqier = readl_relaxed(nfc->io_base + FMC2_CSQIER);
csqier &= ~FMC2_CSQIER_TCIE;
writel_relaxed(csqier, nfc->io_base + FMC2_CSQIER);
regmap_update_bits(nfc->regmap, FMC2_CSQIER, FMC2_CSQIER_TCIE, 0);
nfc->irq_state = FMC2_IRQ_UNKNOWN;
}
static inline void stm32_fmc2_nfc_clear_seq_irq(struct stm32_fmc2_nfc *nfc)
static void stm32_fmc2_nfc_clear_seq_irq(struct stm32_fmc2_nfc *nfc)
{
writel_relaxed(FMC2_CSQICR_CLEAR_IRQ, nfc->io_base + FMC2_CSQICR);
regmap_write(nfc->regmap, FMC2_CSQICR, FMC2_CSQICR_CLEAR_IRQ);
}
static inline void stm32_fmc2_nfc_enable_bch_irq(struct stm32_fmc2_nfc *nfc,
int mode)
static void stm32_fmc2_nfc_enable_bch_irq(struct stm32_fmc2_nfc *nfc, int mode)
{
u32 bchier = readl_relaxed(nfc->io_base + FMC2_BCHIER);
if (mode == NAND_ECC_WRITE)
bchier |= FMC2_BCHIER_EPBRIE;
else
bchier |= FMC2_BCHIER_DERIE;
nfc->irq_state = FMC2_IRQ_BCH;
writel_relaxed(bchier, nfc->io_base + FMC2_BCHIER);
if (mode == NAND_ECC_WRITE)
regmap_update_bits(nfc->regmap, FMC2_BCHIER,
FMC2_BCHIER_EPBRIE, FMC2_BCHIER_EPBRIE);
else
regmap_update_bits(nfc->regmap, FMC2_BCHIER,
FMC2_BCHIER_DERIE, FMC2_BCHIER_DERIE);
}
static inline void stm32_fmc2_nfc_disable_bch_irq(struct stm32_fmc2_nfc *nfc)
static void stm32_fmc2_nfc_disable_bch_irq(struct stm32_fmc2_nfc *nfc)
{
u32 bchier = readl_relaxed(nfc->io_base + FMC2_BCHIER);
bchier &= ~FMC2_BCHIER_DERIE;
bchier &= ~FMC2_BCHIER_EPBRIE;
writel_relaxed(bchier, nfc->io_base + FMC2_BCHIER);
regmap_update_bits(nfc->regmap, FMC2_BCHIER,
FMC2_BCHIER_DERIE | FMC2_BCHIER_EPBRIE, 0);
nfc->irq_state = FMC2_IRQ_UNKNOWN;
}
static inline void stm32_fmc2_nfc_clear_bch_irq(struct stm32_fmc2_nfc *nfc)
static void stm32_fmc2_nfc_clear_bch_irq(struct stm32_fmc2_nfc *nfc)
{
writel_relaxed(FMC2_BCHICR_CLEAR_IRQ, nfc->io_base + FMC2_BCHICR);
regmap_write(nfc->regmap, FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ);
}
/*
@ -481,13 +464,8 @@ static void stm32_fmc2_nfc_hwctl(struct nand_chip *chip, int mode)
stm32_fmc2_nfc_set_ecc(nfc, false);
if (chip->ecc.strength != FMC2_ECC_HAM) {
u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR);
if (mode == NAND_ECC_WRITE)
pcr |= FMC2_PCR_WEN;
else
pcr &= ~FMC2_PCR_WEN;
writel_relaxed(pcr, nfc->io_base + FMC2_PCR);
regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN,
mode == NAND_ECC_WRITE ? FMC2_PCR_WEN : 0);
reinit_completion(&nfc->complete);
stm32_fmc2_nfc_clear_bch_irq(nfc);
@ -502,7 +480,7 @@ static void stm32_fmc2_nfc_hwctl(struct nand_chip *chip, int mode)
* ECC is 3 bytes for 512 bytes of data (supports error correction up to
* max of 1-bit)
*/
static inline void stm32_fmc2_nfc_ham_set_ecc(const u32 ecc_sta, u8 *ecc)
static void stm32_fmc2_nfc_ham_set_ecc(const u32 ecc_sta, u8 *ecc)
{
ecc[0] = ecc_sta;
ecc[1] = ecc_sta >> 8;
@ -516,15 +494,15 @@ static int stm32_fmc2_nfc_ham_calculate(struct nand_chip *chip, const u8 *data,
u32 sr, heccr;
int ret;
ret = readl_relaxed_poll_timeout(nfc->io_base + FMC2_SR,
sr, sr & FMC2_SR_NWRF, 1,
1000 * FMC2_TIMEOUT_MS);
ret = regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr,
sr & FMC2_SR_NWRF, 1,
1000 * FMC2_TIMEOUT_MS);
if (ret) {
dev_err(nfc->dev, "ham timeout\n");
return ret;
}
heccr = readl_relaxed(nfc->io_base + FMC2_HECCR);
regmap_read(nfc->regmap, FMC2_HECCR, &heccr);
stm32_fmc2_nfc_ham_set_ecc(heccr, ecc);
stm32_fmc2_nfc_set_ecc(nfc, false);
@ -603,13 +581,13 @@ static int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data,
}
/* Read parity bits */
bchpbr = readl_relaxed(nfc->io_base + FMC2_BCHPBR1);
regmap_read(nfc->regmap, FMC2_BCHPBR1, &bchpbr);
ecc[0] = bchpbr;
ecc[1] = bchpbr >> 8;
ecc[2] = bchpbr >> 16;
ecc[3] = bchpbr >> 24;
bchpbr = readl_relaxed(nfc->io_base + FMC2_BCHPBR2);
regmap_read(nfc->regmap, FMC2_BCHPBR2, &bchpbr);
ecc[4] = bchpbr;
ecc[5] = bchpbr >> 8;
ecc[6] = bchpbr >> 16;
@ -617,13 +595,13 @@ static int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data,
if (chip->ecc.strength == FMC2_ECC_BCH8) {
ecc[7] = bchpbr >> 24;
bchpbr = readl_relaxed(nfc->io_base + FMC2_BCHPBR3);
regmap_read(nfc->regmap, FMC2_BCHPBR3, &bchpbr);
ecc[8] = bchpbr;
ecc[9] = bchpbr >> 8;
ecc[10] = bchpbr >> 16;
ecc[11] = bchpbr >> 24;
bchpbr = readl_relaxed(nfc->io_base + FMC2_BCHPBR4);
regmap_read(nfc->regmap, FMC2_BCHPBR4, &bchpbr);
ecc[12] = bchpbr;
}
@ -685,11 +663,7 @@ static int stm32_fmc2_nfc_bch_correct(struct nand_chip *chip, u8 *dat,
return -ETIMEDOUT;
}
ecc_sta[0] = readl_relaxed(nfc->io_base + FMC2_BCHDSR0);
ecc_sta[1] = readl_relaxed(nfc->io_base + FMC2_BCHDSR1);
ecc_sta[2] = readl_relaxed(nfc->io_base + FMC2_BCHDSR2);
ecc_sta[3] = readl_relaxed(nfc->io_base + FMC2_BCHDSR3);
ecc_sta[4] = readl_relaxed(nfc->io_base + FMC2_BCHDSR4);
regmap_bulk_read(nfc->regmap, FMC2_BCHDSR0, ecc_sta, 5);
stm32_fmc2_nfc_set_ecc(nfc, false);
@ -764,30 +738,29 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page,
{
struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller);
struct mtd_info *mtd = nand_to_mtd(chip);
u32 csqcfgr1, csqcfgr2, csqcfgr3;
u32 csqar1, csqar2;
u32 ecc_offset = mtd->writesize + FMC2_BBM_LEN;
u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR);
/*
* cfg[0] => csqcfgr1, cfg[1] => csqcfgr2, cfg[2] => csqcfgr3
* cfg[3] => csqar1, cfg[4] => csqar2
*/
u32 cfg[5];
if (write_data)
pcr |= FMC2_PCR_WEN;
else
pcr &= ~FMC2_PCR_WEN;
writel_relaxed(pcr, nfc->io_base + FMC2_PCR);
regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN,
write_data ? FMC2_PCR_WEN : 0);
/*
* - Set Program Page/Page Read command
* - Enable DMA request data
* - Set timings
*/
csqcfgr1 = FMC2_CSQCFGR1_DMADEN | FMC2_CSQCFGR1_CMD1T;
cfg[0] = FMC2_CSQCFGR1_DMADEN | FMC2_CSQCFGR1_CMD1T;
if (write_data)
csqcfgr1 |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_SEQIN);
cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_SEQIN);
else
csqcfgr1 |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_READ0) |
FMC2_CSQCFGR1_CMD2EN |
FIELD_PREP(FMC2_CSQCFGR1_CMD2, NAND_CMD_READSTART) |
FMC2_CSQCFGR1_CMD2T;
cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_READ0) |
FMC2_CSQCFGR1_CMD2EN |
FIELD_PREP(FMC2_CSQCFGR1_CMD2, NAND_CMD_READSTART) |
FMC2_CSQCFGR1_CMD2T;
/*
* - Set Random Data Input/Random Data Read command
@ -796,30 +769,29 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page,
* - Set timings
*/
if (write_data)
csqcfgr2 = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDIN);
cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDIN);
else
csqcfgr2 = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDOUT) |
FMC2_CSQCFGR2_RCMD2EN |
FIELD_PREP(FMC2_CSQCFGR2_RCMD2,
NAND_CMD_RNDOUTSTART) |
FMC2_CSQCFGR2_RCMD1T |
FMC2_CSQCFGR2_RCMD2T;
cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDOUT) |
FMC2_CSQCFGR2_RCMD2EN |
FIELD_PREP(FMC2_CSQCFGR2_RCMD2, NAND_CMD_RNDOUTSTART) |
FMC2_CSQCFGR2_RCMD1T |
FMC2_CSQCFGR2_RCMD2T;
if (!raw) {
csqcfgr2 |= write_data ? 0 : FMC2_CSQCFGR2_DMASEN;
csqcfgr2 |= FMC2_CSQCFGR2_SQSDTEN;
cfg[1] |= write_data ? 0 : FMC2_CSQCFGR2_DMASEN;
cfg[1] |= FMC2_CSQCFGR2_SQSDTEN;
}
/*
* - Set the number of sectors to be written
* - Set timings
*/
csqcfgr3 = FIELD_PREP(FMC2_CSQCFGR3_SNBR, chip->ecc.steps - 1);
cfg[2] = FIELD_PREP(FMC2_CSQCFGR3_SNBR, chip->ecc.steps - 1);
if (write_data) {
csqcfgr3 |= FMC2_CSQCFGR3_RAC2T;
cfg[2] |= FMC2_CSQCFGR3_RAC2T;
if (chip->options & NAND_ROW_ADDR_3)
csqcfgr3 |= FMC2_CSQCFGR3_AC5T;
cfg[2] |= FMC2_CSQCFGR3_AC5T;
else
csqcfgr3 |= FMC2_CSQCFGR3_AC4T;
cfg[2] |= FMC2_CSQCFGR3_AC4T;
}
/*
@ -827,8 +799,8 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page,
* Byte 1 and byte 2 => column, we start at 0x0
* Byte 3 and byte 4 => page
*/
csqar1 = FIELD_PREP(FMC2_CSQCAR1_ADDC3, page);
csqar1 |= FIELD_PREP(FMC2_CSQCAR1_ADDC4, page >> 8);
cfg[3] = FIELD_PREP(FMC2_CSQCAR1_ADDC3, page);
cfg[3] |= FIELD_PREP(FMC2_CSQCAR1_ADDC4, page >> 8);
/*
* - Set chip enable number
@ -836,23 +808,19 @@ static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page,
* - Calculate the number of address cycles to be issued
* - Set byte 5 of address cycle if needed
*/
csqar2 = FIELD_PREP(FMC2_CSQCAR2_NANDCEN, nfc->cs_sel);
cfg[4] = FIELD_PREP(FMC2_CSQCAR2_NANDCEN, nfc->cs_sel);
if (chip->options & NAND_BUSWIDTH_16)
csqar2 |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset >> 1);
cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset >> 1);
else
csqar2 |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset);
cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset);
if (chip->options & NAND_ROW_ADDR_3) {
csqcfgr1 |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 5);
csqar2 |= FIELD_PREP(FMC2_CSQCAR2_ADDC5, page >> 16);
cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 5);
cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_ADDC5, page >> 16);
} else {
csqcfgr1 |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 4);
cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 4);
}
writel_relaxed(csqcfgr1, nfc->io_base + FMC2_CSQCFGR1);
writel_relaxed(csqcfgr2, nfc->io_base + FMC2_CSQCFGR2);
writel_relaxed(csqcfgr3, nfc->io_base + FMC2_CSQCFGR3);
writel_relaxed(csqar1, nfc->io_base + FMC2_CSQAR1);
writel_relaxed(csqar2, nfc->io_base + FMC2_CSQAR2);
regmap_bulk_write(nfc->regmap, FMC2_CSQCFGR1, cfg, 5);
}
static void stm32_fmc2_nfc_dma_callback(void *arg)
@ -870,7 +838,6 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf,
struct dma_chan *dma_ch = nfc->dma_rx_ch;
enum dma_data_direction dma_data_dir = DMA_FROM_DEVICE;
enum dma_transfer_direction dma_transfer_dir = DMA_DEV_TO_MEM;
u32 csqcr = readl_relaxed(nfc->io_base + FMC2_CSQCR);
int eccsteps = chip->ecc.steps;
int eccsize = chip->ecc.size;
unsigned long timeout = msecs_to_jiffies(FMC2_TIMEOUT_MS);
@ -948,8 +915,8 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf,
stm32_fmc2_nfc_enable_seq_irq(nfc);
/* Start the transfer */
csqcr |= FMC2_CSQCR_CSQSTART;
writel_relaxed(csqcr, nfc->io_base + FMC2_CSQCR);
regmap_update_bits(nfc->regmap, FMC2_CSQCR,
FMC2_CSQCR_CSQSTART, FMC2_CSQCR_CSQSTART);
/* Wait end of sequencer transfer */
if (!wait_for_completion_timeout(&nfc->complete, timeout)) {
@ -1042,11 +1009,13 @@ static int stm32_fmc2_nfc_seq_write_page_raw(struct nand_chip *chip,
}
/* Get a status indicating which sectors have errors */
static inline u16 stm32_fmc2_nfc_get_mapping_status(struct stm32_fmc2_nfc *nfc)
static u16 stm32_fmc2_nfc_get_mapping_status(struct stm32_fmc2_nfc *nfc)
{
u32 csqemsr = readl_relaxed(nfc->io_base + FMC2_CSQEMSR);
u32 csqemsr;
return csqemsr & FMC2_CSQEMSR_SEM;
regmap_read(nfc->regmap, FMC2_CSQEMSR, &csqemsr);
return FIELD_GET(FMC2_CSQEMSR_SEM, csqemsr);
}
static int stm32_fmc2_nfc_seq_correct(struct nand_chip *chip, u8 *dat,
@ -1302,22 +1271,22 @@ static int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip,
u32 isr, sr;
/* Check if there is no pending requests to the NAND flash */
if (readl_relaxed_poll_timeout_atomic(nfc->io_base + FMC2_SR, sr,
sr & FMC2_SR_NWRF, 1,
1000 * FMC2_TIMEOUT_MS))
if (regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr,
sr & FMC2_SR_NWRF, 1,
1000 * FMC2_TIMEOUT_MS))
dev_warn(nfc->dev, "Waitrdy timeout\n");
/* Wait tWB before R/B# signal is low */
timings = nand_get_sdr_timings(&chip->data_interface);
timings = nand_get_sdr_timings(nand_get_interface_config(chip));
ndelay(PSEC_TO_NSEC(timings->tWB_max));
/* R/B# signal is low, clear high level flag */
writel_relaxed(FMC2_ICR_CIHLF, nfc->io_base + FMC2_ICR);
regmap_write(nfc->regmap, FMC2_ICR, FMC2_ICR_CIHLF);
/* Wait R/B# signal is high */
return readl_relaxed_poll_timeout_atomic(nfc->io_base + FMC2_ISR,
isr, isr & FMC2_ISR_IHLF,
5, 1000 * timeout_ms);
return regmap_read_poll_timeout(nfc->regmap, FMC2_ISR, isr,
isr & FMC2_ISR_IHLF, 5,
1000 * FMC2_TIMEOUT_MS);
}
static int stm32_fmc2_nfc_exec_op(struct nand_chip *chip,
@ -1375,8 +1344,9 @@ static int stm32_fmc2_nfc_exec_op(struct nand_chip *chip,
static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc)
{
u32 pcr = readl_relaxed(nfc->io_base + FMC2_PCR);
u32 bcr1 = readl_relaxed(nfc->io_base + FMC2_BCR1);
u32 pcr;
regmap_read(nfc->regmap, FMC2_PCR, &pcr);
/* Set CS used to undefined */
nfc->cs_sel = -1;
@ -1407,12 +1377,13 @@ static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc)
pcr |= FIELD_PREP(FMC2_PCR_TAR, FMC2_PCR_TAR_DEFAULT);
/* Enable FMC2 controller */
bcr1 |= FMC2_BCR1_FMC2EN;
if (nfc->dev == nfc->cdev)
regmap_update_bits(nfc->regmap, FMC2_BCR1,
FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN);
writel_relaxed(bcr1, nfc->io_base + FMC2_BCR1);
writel_relaxed(pcr, nfc->io_base + FMC2_PCR);
writel_relaxed(FMC2_PMEM_DEFAULT, nfc->io_base + FMC2_PMEM);
writel_relaxed(FMC2_PATT_DEFAULT, nfc->io_base + FMC2_PATT);
regmap_write(nfc->regmap, FMC2_PCR, pcr);
regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT);
regmap_write(nfc->regmap, FMC2_PATT, FMC2_PATT_DEFAULT);
}
static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip,
@ -1546,7 +1517,7 @@ static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip,
}
static int stm32_fmc2_nfc_setup_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
const struct nand_interface_config *conf)
{
const struct nand_sdr_timings *sdrt;
@ -1570,7 +1541,7 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc)
nfc->dma_tx_ch = dma_request_chan(nfc->dev, "tx");
if (IS_ERR(nfc->dma_tx_ch)) {
ret = PTR_ERR(nfc->dma_tx_ch);
if (ret != -ENODEV)
if (ret != -ENODEV && ret != -EPROBE_DEFER)
dev_err(nfc->dev,
"failed to request tx DMA channel: %d\n", ret);
nfc->dma_tx_ch = NULL;
@ -1580,7 +1551,7 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc)
nfc->dma_rx_ch = dma_request_chan(nfc->dev, "rx");
if (IS_ERR(nfc->dma_rx_ch)) {
ret = PTR_ERR(nfc->dma_rx_ch);
if (ret != -ENODEV)
if (ret != -ENODEV && ret != -EPROBE_DEFER)
dev_err(nfc->dev,
"failed to request rx DMA channel: %d\n", ret);
nfc->dma_rx_ch = NULL;
@ -1590,7 +1561,7 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc)
nfc->dma_ecc_ch = dma_request_chan(nfc->dev, "ecc");
if (IS_ERR(nfc->dma_ecc_ch)) {
ret = PTR_ERR(nfc->dma_ecc_ch);
if (ret != -ENODEV)
if (ret != -ENODEV && ret != -EPROBE_DEFER)
dev_err(nfc->dev,
"failed to request ecc DMA channel: %d\n", ret);
nfc->dma_ecc_ch = NULL;
@ -1764,7 +1735,7 @@ static int stm32_fmc2_nfc_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops stm32_fmc2_nfc_controller_ops = {
.attach_chip = stm32_fmc2_nfc_attach_chip,
.exec_op = stm32_fmc2_nfc_exec_op,
.setup_data_interface = stm32_fmc2_nfc_setup_interface,
.setup_interface = stm32_fmc2_nfc_setup_interface,
};
static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc,
@ -1838,6 +1809,33 @@ static int stm32_fmc2_nfc_parse_dt(struct stm32_fmc2_nfc *nfc)
return ret;
}
static int stm32_fmc2_nfc_set_cdev(struct stm32_fmc2_nfc *nfc)
{
struct device *dev = nfc->dev;
bool ebi_found = false;
if (dev->parent && of_device_is_compatible(dev->parent->of_node,
"st,stm32mp1-fmc2-ebi"))
ebi_found = true;
if (of_device_is_compatible(dev->of_node, "st,stm32mp1-fmc2-nfc")) {
if (ebi_found) {
nfc->cdev = dev->parent;
return 0;
}
return -EINVAL;
}
if (ebi_found)
return -EINVAL;
nfc->cdev = dev;
return 0;
}
static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -1847,7 +1845,9 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
struct resource *res;
struct mtd_info *mtd;
struct nand_chip *chip;
struct resource cres;
int chip_cs, mem_region, ret, irq;
int start_region = 0;
nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
if (!nfc)
@ -1857,18 +1857,28 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
nand_controller_init(&nfc->base);
nfc->base.ops = &stm32_fmc2_nfc_controller_ops;
ret = stm32_fmc2_nfc_set_cdev(nfc);
if (ret)
return ret;
ret = stm32_fmc2_nfc_parse_dt(nfc);
if (ret)
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nfc->io_base = devm_ioremap_resource(dev, res);
if (IS_ERR(nfc->io_base))
return PTR_ERR(nfc->io_base);
ret = of_address_to_resource(nfc->cdev->of_node, 0, &cres);
if (ret)
return ret;
nfc->io_phys_addr = res->start;
nfc->io_phys_addr = cres.start;
for (chip_cs = 0, mem_region = 1; chip_cs < FMC2_MAX_CE;
nfc->regmap = device_node_to_regmap(nfc->cdev->of_node);
if (IS_ERR(nfc->regmap))
return PTR_ERR(nfc->regmap);
if (nfc->dev == nfc->cdev)
start_region = 1;
for (chip_cs = 0, mem_region = start_region; chip_cs < FMC2_MAX_CE;
chip_cs++, mem_region += 3) {
if (!(nfc->cs_assigned & BIT(chip_cs)))
continue;
@ -1906,7 +1916,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
init_completion(&nfc->complete);
nfc->clk = devm_clk_get(dev, NULL);
nfc->clk = devm_clk_get(nfc->cdev, NULL);
if (IS_ERR(nfc->clk))
return PTR_ERR(nfc->clk);
@ -2047,6 +2057,7 @@ static SIMPLE_DEV_PM_OPS(stm32_fmc2_nfc_pm_ops, stm32_fmc2_nfc_suspend,
static const struct of_device_id stm32_fmc2_nfc_match[] = {
{.compatible = "st,stm32mp15-fmc2"},
{.compatible = "st,stm32mp1-fmc2-nfc"},
{}
};
MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match);

View File

@ -1376,8 +1376,8 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
static int sunxi_nfc_setup_data_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf)
static int sunxi_nfc_setup_interface(struct nand_chip *nand, int csline,
const struct nand_interface_config *conf)
{
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
@ -1920,7 +1920,7 @@ static int sunxi_nfc_exec_op(struct nand_chip *nand,
static const struct nand_controller_ops sunxi_nand_controller_ops = {
.attach_chip = sunxi_nand_attach_chip,
.setup_data_interface = sunxi_nfc_setup_data_interface,
.setup_interface = sunxi_nfc_setup_interface,
.exec_op = sunxi_nfc_exec_op,
};

View File

@ -113,53 +113,11 @@ struct tango_chip {
#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
static void tango_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
{
struct tango_chip *tchip = to_tango_chip(chip);
if (ctrl & NAND_CLE)
writeb_relaxed(dat, tchip->base + PBUS_CMD);
if (ctrl & NAND_ALE)
writeb_relaxed(dat, tchip->base + PBUS_ADDR);
}
static int tango_dev_ready(struct nand_chip *chip)
{
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
}
static u8 tango_read_byte(struct nand_chip *chip)
{
struct tango_chip *tchip = to_tango_chip(chip);
return readb_relaxed(tchip->base + PBUS_DATA);
}
static void tango_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
struct tango_chip *tchip = to_tango_chip(chip);
ioread8_rep(tchip->base + PBUS_DATA, buf, len);
}
static void tango_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
struct tango_chip *tchip = to_tango_chip(chip);
iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
}
static void tango_select_chip(struct nand_chip *chip, int idx)
static void tango_select_target(struct nand_chip *chip, unsigned int cs)
{
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip);
if (idx < 0)
return; /* No "chip unselect" function */
writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
@ -168,6 +126,69 @@ static void tango_select_chip(struct nand_chip *chip, int idx)
writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
}
static int tango_waitrdy(struct nand_chip *chip, unsigned int timeout_ms)
{
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
u32 status;
return readl_relaxed_poll_timeout(nfc->pbus_base + PBUS_CS_CTRL,
status, status & PBUS_IORDY, 20,
timeout_ms);
}
static int tango_exec_instr(struct nand_chip *chip,
const struct nand_op_instr *instr)
{
struct tango_chip *tchip = to_tango_chip(chip);
unsigned int i;
switch (instr->type) {
case NAND_OP_CMD_INSTR:
writeb_relaxed(instr->ctx.cmd.opcode, tchip->base + PBUS_CMD);
return 0;
case NAND_OP_ADDR_INSTR:
for (i = 0; i < instr->ctx.addr.naddrs; i++)
writeb_relaxed(instr->ctx.addr.addrs[i],
tchip->base + PBUS_ADDR);
return 0;
case NAND_OP_DATA_IN_INSTR:
ioread8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.in,
instr->ctx.data.len);
return 0;
case NAND_OP_DATA_OUT_INSTR:
iowrite8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.out,
instr->ctx.data.len);
return 0;
case NAND_OP_WAITRDY_INSTR:
return tango_waitrdy(chip,
instr->ctx.waitrdy.timeout_ms);
default:
break;
}
return -EINVAL;
}
static int tango_exec_op(struct nand_chip *chip,
const struct nand_operation *op,
bool check_only)
{
unsigned int i;
int ret = 0;
if (check_only)
return 0;
tango_select_target(chip, op->cs);
for (i = 0; i < op->ninstrs; i++) {
ret = tango_exec_instr(chip, &op->instrs[i]);
if (ret)
break;
}
return ret;
}
/*
* The controller does not check for bitflips in erased pages,
* therefore software must check instead.
@ -279,6 +300,7 @@ static int tango_read_page(struct nand_chip *chip, u8 *buf,
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, res, len = mtd->writesize;
tango_select_target(chip, chip->cur_cs);
if (oob_required)
chip->ecc.read_oob(chip, page);
@ -300,22 +322,30 @@ static int tango_write_page(struct nand_chip *chip, const u8 *buf,
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, status, len = mtd->writesize;
const struct nand_sdr_timings *timings;
int err, len = mtd->writesize;
u8 status;
/* Calling tango_write_oob() would send PAGEPROG twice */
if (oob_required)
return -ENOTSUPP;
tango_select_target(chip, chip->cur_cs);
writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
if (err)
return err;
status = chip->legacy.waitfunc(chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
timings = nand_get_sdr_timings(nand_get_interface_config(chip));
err = tango_waitrdy(chip, PSEC_TO_MSEC(timings->tR_max));
if (err)
return err;
return 0;
err = nand_status_op(chip, &status);
if (err)
return err;
return (status & NAND_STATUS_FAIL) ? -EIO : 0;
}
static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
@ -326,7 +356,9 @@ static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
/* skip over "len" bytes */
nand_change_read_column_op(chip, *pos, NULL, 0, false);
} else {
tango_read_buf(chip, *buf, len);
struct tango_chip *tchip = to_tango_chip(chip);
ioread8_rep(tchip->base + PBUS_DATA, *buf, len);
*buf += len;
}
}
@ -339,7 +371,9 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
/* skip over "len" bytes */
nand_change_write_column_op(chip, *pos, NULL, 0, false);
} else {
tango_write_buf(chip, *buf, len);
struct tango_chip *tchip = to_tango_chip(chip);
iowrite8_rep(tchip->base + PBUS_DATA, *buf, len);
*buf += len;
}
}
@ -420,6 +454,7 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
tango_select_target(chip, chip->cur_cs);
nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, buf, chip->oob_poi);
return 0;
@ -428,6 +463,7 @@ static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
tango_select_target(chip, chip->cur_cs);
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, buf, chip->oob_poi);
return nand_prog_page_end_op(chip);
@ -435,6 +471,7 @@ static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
static int tango_read_oob(struct nand_chip *chip, int page)
{
tango_select_target(chip, chip->cur_cs);
nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, NULL, chip->oob_poi);
return 0;
@ -442,6 +479,7 @@ static int tango_read_oob(struct nand_chip *chip, int page)
static int tango_write_oob(struct nand_chip *chip, int page)
{
tango_select_target(chip, chip->cur_cs);
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, NULL, chip->oob_poi);
return nand_prog_page_end_op(chip);
@ -477,7 +515,7 @@ static u32 to_ticks(int kHz, int ps)
}
static int tango_set_timings(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
const struct nand_interface_config *conf)
{
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
@ -527,7 +565,8 @@ static int tango_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops tango_controller_ops = {
.attach_chip = tango_attach_chip,
.setup_data_interface = tango_set_timings,
.setup_interface = tango_set_timings,
.exec_op = tango_exec_op,
};
static int chip_init(struct device *dev, struct device_node *np)
@ -562,12 +601,6 @@ static int chip_init(struct device *dev, struct device_node *np)
ecc = &chip->ecc;
mtd = nand_to_mtd(chip);
chip->legacy.read_byte = tango_read_byte;
chip->legacy.write_buf = tango_write_buf;
chip->legacy.read_buf = tango_read_buf;
chip->legacy.select_chip = tango_select_chip;
chip->legacy.cmd_ctrl = tango_cmd_ctrl;
chip->legacy.dev_ready = tango_dev_ready;
chip->options = NAND_USES_DMA |
NAND_NO_SUBPAGE_WRITE |
NAND_WAIT_TCCS;

View File

@ -813,8 +813,8 @@ static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl,
writel_relaxed(reg, ctrl->regs + TIMING_2);
}
static int tegra_nand_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
static int tegra_nand_setup_interface(struct nand_chip *chip, int csline,
const struct nand_interface_config *conf)
{
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
const struct nand_sdr_timings *timings;
@ -1053,7 +1053,7 @@ static int tegra_nand_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops tegra_nand_controller_ops = {
.attach_chip = &tegra_nand_attach_chip,
.exec_op = tegra_nand_exec_op,
.setup_data_interface = tegra_nand_setup_data_interface,
.setup_interface = tegra_nand_setup_interface,
};
static int tegra_nand_chips_init(struct device *dev,

View File

@ -22,6 +22,11 @@
#include <linux/mtd/partitions.h>
#include <linux/of.h>
#ifdef CONFIG_MIPS
#include <asm/bootinfo.h>
#include <asm/fw/cfe/cfe_api.h>
#endif /* CONFIG_MIPS */
#define BCM963XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */
#define BCM963XX_CFE_MAGIC_OFFSET 0x4e0
@ -32,28 +37,15 @@
#define STR_NULL_TERMINATE(x) \
do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
static int bcm63xx_detect_cfe(struct mtd_info *master)
static inline int bcm63xx_detect_cfe(void)
{
char buf[9];
int ret;
size_t retlen;
int ret = 0;
ret = mtd_read(master, BCM963XX_CFE_VERSION_OFFSET, 5, &retlen,
(void *)buf);
buf[retlen] = 0;
#ifdef CONFIG_MIPS
ret = (fw_arg3 == CFE_EPTSEAL);
#endif /* CONFIG_MIPS */
if (ret)
return ret;
if (strncmp("cfe-v", buf, 5) == 0)
return 0;
/* very old CFE's do not have the cfe-v string, so check for magic */
ret = mtd_read(master, BCM963XX_CFE_MAGIC_OFFSET, 8, &retlen,
(void *)buf);
buf[retlen] = 0;
return strncmp("CFE1CFE1", buf, 8);
return ret;
}
static int bcm63xx_read_nvram(struct mtd_info *master,
@ -138,7 +130,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
struct bcm963xx_nvram *nvram = NULL;
int ret;
if (bcm63xx_detect_cfe(master))
if (!bcm63xx_detect_cfe())
return -EINVAL;
nvram = vzalloc(sizeof(*nvram));

View File

@ -68,7 +68,9 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },

View File

@ -292,7 +292,7 @@ static int intel_spi_wait_hw_busy(struct intel_spi *ispi)
u32 val;
return readl_poll_timeout(ispi->base + HSFSTS_CTL, val,
!(val & HSFSTS_CTL_SCIP), 40,
!(val & HSFSTS_CTL_SCIP), 0,
INTEL_SPI_TIMEOUT * 1000);
}
@ -301,7 +301,7 @@ static int intel_spi_wait_sw_busy(struct intel_spi *ispi)
u32 val;
return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val,
!(val & SSFSTS_CTL_SCIP), 40,
!(val & SSFSTS_CTL_SCIP), 0,
INTEL_SPI_TIMEOUT * 1000);
}
@ -612,6 +612,15 @@ static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
return 0;
}
/*
* We hope that HW sequencer will do the right thing automatically and
* with the SW sequencer we cannot use preopcode anyway, so just ignore
* the Write Disable operation and pretend it was completed
* successfully.
*/
if (opcode == SPINOR_OP_WRDI)
return 0;
writel(0, ispi->base + FADDR);
/* Write the value beforehand */

View File

@ -1907,15 +1907,16 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
}
/**
* spi_nor_sr1_bit6_quad_enable() - Set the Quad Enable BIT(6) in the Status
* Register 1.
* spi_nor_sr1_bit6_quad_enable() - Set/Unset the Quad Enable BIT(6) in the
* Status Register 1.
* @nor: pointer to a 'struct spi_nor'
* @enable: true to enable Quad mode, false to disable Quad mode.
*
* Bit 6 of the Status Register 1 is the QE bit for Macronix like QSPI memories.
*
* Return: 0 on success, -errno otherwise.
*/
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor)
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable)
{
int ret;
@ -1923,45 +1924,56 @@ int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor)
if (ret)
return ret;
if (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)
if ((enable && (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)) ||
(!enable && !(nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)))
return 0;
nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6;
if (enable)
nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6;
else
nor->bouncebuf[0] &= ~SR1_QUAD_EN_BIT6;
return spi_nor_write_sr1_and_check(nor, nor->bouncebuf[0]);
}
/**
* spi_nor_sr2_bit1_quad_enable() - set the Quad Enable BIT(1) in the Status
* Register 2.
* spi_nor_sr2_bit1_quad_enable() - set/unset the Quad Enable BIT(1) in the
* Status Register 2.
* @nor: pointer to a 'struct spi_nor'.
* @enable: true to enable Quad mode, false to disable Quad mode.
*
* Bit 1 of the Status Register 2 is the QE bit for Spansion like QSPI memories.
*
* Return: 0 on success, -errno otherwise.
*/
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor)
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable)
{
int ret;
if (nor->flags & SNOR_F_NO_READ_CR)
return spi_nor_write_16bit_cr_and_check(nor, SR2_QUAD_EN_BIT1);
return spi_nor_write_16bit_cr_and_check(nor,
enable ? SR2_QUAD_EN_BIT1 : 0);
ret = spi_nor_read_cr(nor, nor->bouncebuf);
if (ret)
return ret;
if (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)
if ((enable && (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)) ||
(!enable && !(nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)))
return 0;
nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1;
if (enable)
nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1;
else
nor->bouncebuf[0] &= ~SR2_QUAD_EN_BIT1;
return spi_nor_write_16bit_cr_and_check(nor, nor->bouncebuf[0]);
}
/**
* spi_nor_sr2_bit7_quad_enable() - set QE bit in Status Register 2.
* spi_nor_sr2_bit7_quad_enable() - set/unset QE bit in Status Register 2.
* @nor: pointer to a 'struct spi_nor'
* @enable: true to enable Quad mode, false to disable Quad mode.
*
* Set the Quad Enable (QE) bit in the Status Register 2.
*
@ -1971,7 +1983,7 @@ int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor)
*
* Return: 0 on success, -errno otherwise.
*/
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor)
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable)
{
u8 *sr2 = nor->bouncebuf;
int ret;
@ -1981,11 +1993,15 @@ int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor)
ret = spi_nor_read_sr2(nor, sr2);
if (ret)
return ret;
if (*sr2 & SR2_QUAD_EN_BIT7)
if ((enable && (*sr2 & SR2_QUAD_EN_BIT7)) ||
(!enable && !(*sr2 & SR2_QUAD_EN_BIT7)))
return 0;
/* Update the Quad Enable bit. */
*sr2 |= SR2_QUAD_EN_BIT7;
if (enable)
*sr2 |= SR2_QUAD_EN_BIT7;
else
*sr2 &= ~SR2_QUAD_EN_BIT7;
ret = spi_nor_write_sr2(nor, sr2);
if (ret)
@ -2898,12 +2914,13 @@ static int spi_nor_init_params(struct spi_nor *nor)
}
/**
* spi_nor_quad_enable() - enable Quad I/O if needed.
* spi_nor_quad_enable() - enable/disable Quad I/O if needed.
* @nor: pointer to a 'struct spi_nor'
* @enable: true to enable Quad mode. false to disable Quad mode.
*
* Return: 0 on success, -errno otherwise.
*/
static int spi_nor_quad_enable(struct spi_nor *nor)
static int spi_nor_quad_enable(struct spi_nor *nor, bool enable)
{
if (!nor->params->quad_enable)
return 0;
@ -2912,7 +2929,7 @@ static int spi_nor_quad_enable(struct spi_nor *nor)
spi_nor_get_protocol_width(nor->write_proto) == 4))
return 0;
return nor->params->quad_enable(nor);
return nor->params->quad_enable(nor, enable);
}
/**
@ -2936,7 +2953,7 @@ static int spi_nor_init(struct spi_nor *nor)
{
int err;
err = spi_nor_quad_enable(nor);
err = spi_nor_quad_enable(nor, true);
if (err) {
dev_dbg(nor->dev, "quad mode not supported\n");
return err;
@ -2983,6 +3000,8 @@ void spi_nor_restore(struct spi_nor *nor)
if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET)
nor->params->set_4byte_addr_mode(nor, false);
spi_nor_quad_enable(nor, false);
}
EXPORT_SYMBOL_GPL(spi_nor_restore);

View File

@ -198,7 +198,7 @@ struct spi_nor_locking_ops {
* higher index in the array, the higher priority.
* @erase_map: the erase map parsed from the SFDP Sector Map Parameter
* Table.
* @quad_enable: enables SPI NOR quad mode.
* @quad_enable: enables/disables SPI NOR Quad mode.
* @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode.
* @convert_addr: converts an absolute address into something the flash
* will understand. Particularly useful when pagesize is
@ -219,7 +219,7 @@ struct spi_nor_flash_parameter {
struct spi_nor_erase_map erase_map;
int (*quad_enable)(struct spi_nor *nor);
int (*quad_enable)(struct spi_nor *nor, bool enable);
int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps);
@ -406,9 +406,9 @@ int spi_nor_write_ear(struct spi_nor *nor, u8 ear);
int spi_nor_wait_till_ready(struct spi_nor *nor);
int spi_nor_lock_and_prep(struct spi_nor *nor);
void spi_nor_unlock_and_unprep(struct spi_nor *nor);
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor);
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable);
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable);
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable);
int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr);
ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,

View File

@ -52,6 +52,9 @@ static const struct flash_info macronix_parts[] = {
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25r1635f", INFO(0xc22815, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) },
{ "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) },
@ -84,6 +87,9 @@ static const struct flash_info macronix_parts[] = {
SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048,
SPI_NOR_QUAD_READ) },
{ "mx66u2g45g", INFO(0xc2253c, 0, 64 * 1024, 4096,
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
};
static void macronix_default_init(struct spi_nor *nor)

View File

@ -71,8 +71,8 @@ static const struct flash_info st_parts[] = {
SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
NO_CHIP_ERASE) },
{ "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096,
SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
NO_CHIP_ERASE) },
SECT_4K | USE_FSR | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) },
{ "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) },

View File

@ -598,7 +598,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
break;
default:
return -EINVAL;
dev_dbg(nor->dev, "BFPT QER reserved value used\n");
break;
}
/* Stop here if not JESD216 rev C or later. */

View File

@ -64,7 +64,6 @@ static const struct flash_info spansion_parts[] = {
{ "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256,
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR)
.fixups = &s25fs_s_fixups, },
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64,
@ -84,7 +83,8 @@ static const struct flash_info spansion_parts[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) },

View File

@ -64,10 +64,12 @@ static const struct flash_info winbond_parts[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
{ "w25q64jvm", INFO(0xef7017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
* Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
*/
#ifndef __LINUX_MTD_HYPERBUS_H__

View File

@ -12,6 +12,8 @@
#include <linux/mtd/mtd.h>
struct nand_device;
/**
* struct nand_memory_organization - Memory organization structure
* @bits_per_cell: number of bits per NAND cell
@ -114,11 +116,11 @@ struct nand_page_io_req {
};
/**
* struct nand_ecc_req - NAND ECC requirements
* struct nand_ecc_props - NAND ECC properties
* @strength: ECC strength
* @step_size: ECC step/block size
* @step_size: Number of bytes per step
*/
struct nand_ecc_req {
struct nand_ecc_props {
unsigned int strength;
unsigned int step_size;
};
@ -133,8 +135,6 @@ struct nand_bbt {
unsigned long *cache;
};
struct nand_device;
/**
* struct nand_ops - NAND operations
* @erase: erase a specific block. No need to check if the block is bad before
@ -179,7 +179,7 @@ struct nand_ops {
struct nand_device {
struct mtd_info mtd;
struct nand_memory_organization memorg;
struct nand_ecc_req eccreq;
struct nand_ecc_props eccreq;
struct nand_row_converter rowconv;
struct nand_bbt bbt;
const struct nand_ops *ops;

View File

@ -19,7 +19,7 @@
/* Identification info for LPDDR chip */
#define PFOW_MANUFACTURER_ID 0x0020
#define PFOW_DEVICE_ID 0x0022
/* Address in PFOW where prog buffer can can be found */
/* Address in PFOW where prog buffer can be found */
#define PFOW_PROGRAM_BUFFER_OFFSET 0x0040
/* Size of program buffer in words */
#define PFOW_PROGRAM_BUFFER_SIZE 0x0042

View File

@ -492,22 +492,22 @@ struct nand_sdr_timings {
};
/**
* enum nand_data_interface_type - NAND interface timing type
* enum nand_interface_type - NAND interface type
* @NAND_SDR_IFACE: Single Data Rate interface
*/
enum nand_data_interface_type {
enum nand_interface_type {
NAND_SDR_IFACE,
};
/**
* struct nand_data_interface - NAND interface timing
* struct nand_interface_config - NAND interface timing
* @type: type of the timing
* @timings: The timing information
* @timings.mode: Timing mode as defined in the specification
* @timings.sdr: Use it when @type is %NAND_SDR_IFACE.
*/
struct nand_data_interface {
enum nand_data_interface_type type;
struct nand_interface_config {
enum nand_interface_type type;
struct nand_timings {
unsigned int mode;
union {
@ -521,7 +521,7 @@ struct nand_data_interface {
* @conf: The data interface
*/
static inline const struct nand_sdr_timings *
nand_get_sdr_timings(const struct nand_data_interface *conf)
nand_get_sdr_timings(const struct nand_interface_config *conf)
{
if (conf->type != NAND_SDR_IFACE)
return ERR_PTR(-EINVAL);
@ -944,11 +944,10 @@ static inline void nand_op_trace(const char *prefix,
* This method replaces chip->legacy.cmdfunc(),
* chip->legacy.{read,write}_{buf,byte,word}(),
* chip->legacy.dev_ready() and chip->legacy.waifunc().
* @setup_data_interface: setup the data interface and timing. If
* chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this
* means the configuration should not be applied but
* only checked.
* This hook is optional.
* @setup_interface: setup the data interface and timing. If chipnr is set to
* %NAND_DATA_IFACE_CHECK_ONLY this means the configuration
* should not be applied but only checked.
* This hook is optional.
*/
struct nand_controller_ops {
int (*attach_chip)(struct nand_chip *chip);
@ -956,8 +955,8 @@ struct nand_controller_ops {
int (*exec_op)(struct nand_chip *chip,
const struct nand_operation *op,
bool check_only);
int (*setup_data_interface)(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf);
int (*setup_interface)(struct nand_chip *chip, int chipnr,
const struct nand_interface_config *conf);
};
/**
@ -1028,140 +1027,138 @@ struct nand_legacy {
};
/**
* struct nand_chip - NAND Private Flash Chip Data
* @base: Inherit from the generic NAND device
* @legacy: All legacy fields/hooks. If you develop a new driver,
* don't even try to use any of these fields/hooks, and if
* you're modifying an existing driver that is using those
* fields/hooks, you should consider reworking the driver
* avoid using them.
* @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for
* setting the read-retry mode. Mostly needed for MLC NAND.
* @ecc: [BOARDSPECIFIC] ECC control structure
* @buf_align: minimum buffer alignment required by a platform
* @oob_poi: "poison value buffer," used for laying out OOB data
* before writing
* @page_shift: [INTERN] number of address bits in a page (column
* address bits).
* @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
* @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
* @chip_shift: [INTERN] number of address bits in one chip
* @options: [BOARDSPECIFIC] various chip options. They can partly
* be set to inform nand_scan about special functionality.
* See the defines for further explanation.
* @bbt_options: [INTERN] bad block specific options. All options used
* here must come from bbm.h. By default, these options
* will be copied to the appropriate nand_bbt_descr's.
* @badblockpos: [INTERN] position of the bad block marker in the oob
* area.
* @badblockbits: [INTERN] minimum number of set bits in a good block's
* bad block marker position; i.e., BBM == 11110111b is
* not bad when badblockbits == 7
* @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
* set to the actually used ONFI mode if the chip is
* ONFI compliant or deduced from the datasheet if
* the NAND chip is not ONFI compliant.
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
* @data_buf: [INTERN] buffer for data, size is (page size + oobsize).
* @pagecache: Structure containing page cache related fields
* @pagecache.bitflips: Number of bitflips of the cached page
* @pagecache.page: Page number currently in the cache. -1 means no page is
* currently cached
* @subpagesize: [INTERN] holds the subpagesize
* @id: [INTERN] holds NAND ID
* @parameters: [INTERN] holds generic parameters under an easily
* readable form.
* @data_interface: [INTERN] NAND interface timing information
* @cur_cs: currently selected target. -1 means no target selected,
* otherwise we should always have cur_cs >= 0 &&
* cur_cs < nanddev_ntargets(). NAND Controller drivers
* should not modify this value, but they're allowed to
* read it.
* @read_retries: [INTERN] the number of read retry modes supported
* @lock: lock protecting the suspended field. Also used to
* serialize accesses to the NAND device.
* @suspended: set to 1 when the device is suspended, 0 when it's not.
* @suspend: [REPLACEABLE] specific NAND device suspend operation
* @resume: [REPLACEABLE] specific NAND device resume operation
* @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
* lookup.
* @bbt_md: [REPLACEABLE] bad block table mirror descriptor
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial
* bad block scan.
* @controller: [REPLACEABLE] a pointer to a hardware controller
* structure which is shared among multiple independent
* devices.
* @priv: [OPTIONAL] pointer to private chip data
* @manufacturer: [INTERN] Contains manufacturer information
* @manufacturer.desc: [INTERN] Contains manufacturer's description
* @manufacturer.priv: [INTERN] Contains manufacturer private information
* @lock_area: [REPLACEABLE] specific NAND chip lock operation
* @unlock_area: [REPLACEABLE] specific NAND chip unlock operation
* struct nand_chip_ops - NAND chip operations
* @suspend: Suspend operation
* @resume: Resume operation
* @lock_area: Lock operation
* @unlock_area: Unlock operation
* @setup_read_retry: Set the read-retry mode (mostly needed for MLC NANDs)
* @choose_interface_config: Choose the best interface configuration
*/
struct nand_chip_ops {
int (*suspend)(struct nand_chip *chip);
void (*resume)(struct nand_chip *chip);
int (*lock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len);
int (*unlock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len);
int (*setup_read_retry)(struct nand_chip *chip, int retry_mode);
int (*choose_interface_config)(struct nand_chip *chip,
struct nand_interface_config *iface);
};
/**
* struct nand_manufacturer - NAND manufacturer structure
* @desc: The manufacturer description
* @priv: Private information for the manufacturer driver
*/
struct nand_manufacturer {
const struct nand_manufacturer_desc *desc;
void *priv;
};
/**
* struct nand_chip - NAND Private Flash Chip Data
* @base: Inherit from the generic NAND device
* @id: Holds NAND ID
* @parameters: Holds generic parameters under an easily readable form
* @manufacturer: Manufacturer information
* @ops: NAND chip operations
* @legacy: All legacy fields/hooks. If you develop a new driver, don't even try
* to use any of these fields/hooks, and if you're modifying an
* existing driver that is using those fields/hooks, you should
* consider reworking the driver and avoid using them.
* @options: Various chip options. They can partly be set to inform nand_scan
* about special functionality. See the defines for further
* explanation.
* @current_interface_config: The currently used NAND interface configuration
* @best_interface_config: The best NAND interface configuration which fits both
* the NAND chip and NAND controller constraints. If
* unset, the default reset interface configuration must
* be used.
* @bbt_erase_shift: Number of address bits in a bbt entry
* @bbt_options: Bad block table specific options. All options used here must
* come from bbm.h. By default, these options will be copied to
* the appropriate nand_bbt_descr's.
* @badblockpos: Bad block marker position in the oob area
* @badblockbits: Minimum number of set bits in a good block's bad block marker
* position; i.e., BBM = 11110111b is good when badblockbits = 7
* @bbt_td: Bad block table descriptor for flash lookup
* @bbt_md: Bad block table mirror descriptor
* @badblock_pattern: Bad block scan pattern used for initial bad block scan
* @bbt: Bad block table pointer
* @page_shift: Number of address bits in a page (column address bits)
* @phys_erase_shift: Number of address bits in a physical eraseblock
* @chip_shift: Number of address bits in one chip
* @pagemask: Page number mask = number of (pages / chip) - 1
* @subpagesize: Holds the subpagesize
* @data_buf: Buffer for data, size is (page size + oobsize)
* @oob_poi: pointer on the OOB area covered by data_buf
* @pagecache: Structure containing page cache related fields
* @pagecache.bitflips: Number of bitflips of the cached page
* @pagecache.page: Page number currently in the cache. -1 means no page is
* currently cached
* @buf_align: Minimum buffer alignment required by a platform
* @lock: Lock protecting the suspended field. Also used to serialize accesses
* to the NAND device
* @suspended: Set to 1 when the device is suspended, 0 when it's not
* @cur_cs: Currently selected target. -1 means no target selected, otherwise we
* should always have cur_cs >= 0 && cur_cs < nanddev_ntargets().
* NAND Controller drivers should not modify this value, but they're
* allowed to read it.
* @read_retries: The number of read retry modes supported
* @controller: The hardware controller structure which is shared among multiple
* independent devices
* @ecc: The ECC controller structure
* @priv: Chip private data
*/
struct nand_chip {
struct nand_device base;
struct nand_id id;
struct nand_parameters parameters;
struct nand_manufacturer manufacturer;
struct nand_chip_ops ops;
struct nand_legacy legacy;
int (*setup_read_retry)(struct nand_chip *chip, int retry_mode);
unsigned int options;
/* Data interface */
const struct nand_interface_config *current_interface_config;
struct nand_interface_config *best_interface_config;
/* Bad block information */
unsigned int bbt_erase_shift;
unsigned int bbt_options;
unsigned int badblockpos;
unsigned int badblockbits;
struct nand_bbt_descr *bbt_td;
struct nand_bbt_descr *bbt_md;
struct nand_bbt_descr *badblock_pattern;
u8 *bbt;
int page_shift;
int phys_erase_shift;
int bbt_erase_shift;
int chip_shift;
int pagemask;
/* Device internal layout */
unsigned int page_shift;
unsigned int phys_erase_shift;
unsigned int chip_shift;
unsigned int pagemask;
unsigned int subpagesize;
/* Buffers */
u8 *data_buf;
u8 *oob_poi;
struct {
unsigned int bitflips;
int page;
} pagecache;
int subpagesize;
int onfi_timing_mode_default;
unsigned int badblockpos;
int badblockbits;
struct nand_id id;
struct nand_parameters parameters;
struct nand_data_interface data_interface;
int cur_cs;
int read_retries;
struct mutex lock;
unsigned int suspended : 1;
int (*suspend)(struct nand_chip *chip);
void (*resume)(struct nand_chip *chip);
uint8_t *oob_poi;
struct nand_controller *controller;
struct nand_ecc_ctrl ecc;
unsigned long buf_align;
uint8_t *bbt;
struct nand_bbt_descr *bbt_td;
struct nand_bbt_descr *bbt_md;
struct nand_bbt_descr *badblock_pattern;
/* Internals */
struct mutex lock;
unsigned int suspended : 1;
int cur_cs;
int read_retries;
/* Externals */
struct nand_controller *controller;
struct nand_ecc_ctrl ecc;
void *priv;
struct {
const struct nand_manufacturer *desc;
void *priv;
} manufacturer;
int (*lock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len);
int (*unlock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len);
};
extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
@ -1209,6 +1206,17 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
return mtd_get_of_node(nand_to_mtd(chip));
}
/**
* nand_get_interface_config - Retrieve the current interface configuration
* of a NAND chip
* @chip: The NAND chip
*/
static inline const struct nand_interface_config *
nand_get_interface_config(struct nand_chip *chip)
{
return chip->current_interface_config;
}
/*
* A helper for defining older NAND chips where the second ID byte fully
* defined the chip, including the geometry (chip size, eraseblock size, page
@ -1261,10 +1269,6 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
* @ecc_step_ds in nand_chip{}, also from the datasheet.
* For example, the "4bit ECC for each 512Byte" can be set with
* NAND_ECC_INFO(4, 512).
* @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND
* reset. Should be deduced from timings described
* in the datasheet.
*
*/
struct nand_flash_dev {
char *name;
@ -1285,7 +1289,6 @@ struct nand_flash_dev {
uint16_t strength_ds;
uint16_t step_ds;
} ecc;
int onfi_timing_mode_default;
};
int nand_create_bbt(struct nand_chip *chip);

View File

@ -309,7 +309,7 @@ struct spinand_info {
struct spinand_devid devid;
u32 flags;
struct nand_memory_organization memorg;
struct nand_ecc_req eccreq;
struct nand_ecc_props eccreq;
struct spinand_ecc_info eccinfo;
struct {
const struct spinand_op_variants *read_cache;

View File

@ -262,7 +262,7 @@ struct mtd_ecc_stats {
* @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode
* @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled
*
* These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained
* These modes can be set via ioctl(MTDFILEMODE). The mode will be retained
* separately for each open file descriptor.
*
* Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW -