Raw NAND core:

* Allow SDR timings to be nacked
 * Bring support for NV-DDR timings which involved a number of small
   preparation changes to bring new helpers, properly introduce NV-DDR
   structures, fill them, differenciate them and pick the best timing set.
 * Add the necessary infrastructure to parse the new gpio-cs property
   which aims at enlarging the number of available CS when a hardware
   controller is too constrained.
 * Update dead URL
 * Silence static checker warning in nand_setup_interface()
 * BBT:
   - Fix corner case in bad block table handling
 * onfi:
   - Use more recent ONFI specification wording
   - Use the BIT() macro when possible
 
 Raw NAND controller drivers:
 * Atmel:
   - Ensure the data interface is supported.
 * Arasan:
   - Finer grain NV-DDR configuration
   - Rename the data interface register
   - Use the right DMA mask
   - Leverage additional GPIO CS
   - Ensure proper configuration for the asserted target
   - Add support for the NV-DDR interface
   - Fix a macro parameter
 * brcmnand:
   - Convert bindings to json-schema
 * OMAP:
   - Various fixes and style improvements
   - Add larger page NAND chips support
 * PL35X:
   - New driver
 * QCOM:
   - Avoid writing to obsolete register
   - Delete an unneeded bool conversion
   - Allow override of partition parser
 * Marvell:
   - Minor documentation correction
   - Add missing clk_disable_unprepare() on error in marvell_nfc_resume()
 * R852:
   - Use DEVICE_ATTR_RO() helper macro
 * MTK:
   - Remove redundant dev_err call in mtk_ecc_probe()
 * HISI504:
   - Remove redundant dev_err call in probe
 
 SPI-NAND core:
 * Light reorganisation for the introduction of a core resume handler
 * Fix double counting of ECC stats
 
 SPI-NAND manufacturer drivers:
 * Macronix:
   - Add support for serial NAND flash
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAmDS290ACgkQJWrqGEe9
 VoS77wgAgKnqfFwbqzdSecVmXai9roSNHi/aMpVJvvLHSTCV35iCcNNtrz0Jno56
 t/8twVPPZUI6f3vPXk5+NjKRCb8Oif3oU+tNxqG6mwzrBRf5R80pYCMm+HGPWZaK
 +MolqGAbgFO088DTK5fGNtmbnb5fPT174RKRBGEH5NgK5M1q95uF8fIjBXDcjVe2
 hvAyoqqC7i/bp40sxRtglgBpYYz+KUjCX11JvJPa5IuVU+8ezZSKJLSo5/CtgIKJ
 mRQ8p8myiUjZngcnebjTrAA5AwQ13ai9ofKG0pHkdxwOq4lSRNgKou0Hk5+oq+s0
 BFEuXnUrdnJNU7+XV+kAqBoT6WOFzg==
 =I/9X
 -----END PGP SIGNATURE-----

Merge tag 'nand/for-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux into mtd/next

Raw NAND core:
* Allow SDR timings to be nacked
* Bring support for NV-DDR timings which involved a number of small
  preparation changes to bring new helpers, properly introduce NV-DDR
  structures, fill them, differenciate them and pick the best timing set.
* Add the necessary infrastructure to parse the new gpio-cs property
  which aims at enlarging the number of available CS when a hardware
  controller is too constrained.
* Update dead URL
* Silence static checker warning in nand_setup_interface()
* BBT:
  - Fix corner case in bad block table handling
* onfi:
  - Use more recent ONFI specification wording
  - Use the BIT() macro when possible

Raw NAND controller drivers:
* Atmel:
  - Ensure the data interface is supported.
* Arasan:
  - Finer grain NV-DDR configuration
  - Rename the data interface register
  - Use the right DMA mask
  - Leverage additional GPIO CS
  - Ensure proper configuration for the asserted target
  - Add support for the NV-DDR interface
  - Fix a macro parameter
* brcmnand:
  - Convert bindings to json-schema
* OMAP:
  - Various fixes and style improvements
  - Add larger page NAND chips support
* PL35X:
  - New driver
* QCOM:
  - Avoid writing to obsolete register
  - Delete an unneeded bool conversion
  - Allow override of partition parser
* Marvell:
  - Minor documentation correction
  - Add missing clk_disable_unprepare() on error in marvell_nfc_resume()
* R852:
  - Use DEVICE_ATTR_RO() helper macro
* MTK:
  - Remove redundant dev_err call in mtk_ecc_probe()
* HISI504:
  - Remove redundant dev_err call in probe

SPI-NAND core:
* Light reorganisation for the introduction of a core resume handler
* Fix double counting of ECC stats

SPI-NAND manufacturer drivers:
* Macronix:
  - Add support for serial NAND flash
This commit is contained in:
Richard Weinberger 2021-06-29 23:01:39 +02:00
commit 600d050944
33 changed files with 3176 additions and 901 deletions

View File

@ -0,0 +1,131 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/arm,pl353-smc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ARM PL353 Static Memory Controller (SMC) device-tree bindings
maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com>
- Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
description:
The PL353 Static Memory Controller is a bus where you can connect two kinds
of memory interfaces, which are NAND and memory mapped interfaces (such as
SRAM or NOR).
# We need a select here so we don't match all nodes with 'arm,primecell'
select:
properties:
compatible:
contains:
const: arm,pl353-smc-r2p1
required:
- compatible
properties:
$nodename:
pattern: "^memory-controller@[0-9a-f]+$"
compatible:
items:
- const: arm,pl353-smc-r2p1
- const: arm,primecell
"#address-cells":
const: 2
"#size-cells":
const: 1
reg:
items:
- description:
Configuration registers for the host and sub-controllers.
The three chip select regions are defined in 'ranges'.
clocks:
items:
- description: clock for the memory device bus
- description: main clock of the SMC
clock-names:
items:
- const: memclk
- const: apb_pclk
ranges:
minItems: 1
maxItems: 3
description: |
Memory bus areas for interacting with the devices. Reflects
the memory layout with four integer values following:
<cs-number> 0 <offset> <size>
items:
- description: NAND bank 0
- description: NOR/SRAM bank 0
- description: NOR/SRAM bank 1
interrupts: true
patternProperties:
"@[0-3],[a-f0-9]+$":
type: object
description: |
The child device node represents the controller connected to the SMC
bus. The controller can be a NAND controller or a pair of any memory
mapped controllers such as NOR and SRAM controllers.
properties:
compatible:
description:
Compatible of memory controller.
reg:
items:
- items:
- description: |
Chip-select ID, as in the parent range property.
minimum: 0
maximum: 2
- description: |
Offset of the memory region requested by the device.
- description: |
Length of the memory region requested by the device.
required:
- compatible
- reg
required:
- compatible
- reg
- clock-names
- clocks
- "#address-cells"
- "#size-cells"
- ranges
additionalProperties: false
examples:
- |
smcc: memory-controller@e000e000 {
compatible = "arm,pl353-smc-r2p1", "arm,primecell";
reg = <0xe000e000 0x0001000>;
clock-names = "memclk", "apb_pclk";
clocks = <&clkc 11>, <&clkc 44>;
ranges = <0x0 0x0 0xe1000000 0x1000000 /* Nand CS region */
0x1 0x0 0xe2000000 0x2000000 /* SRAM/NOR CS0 region */
0x2 0x0 0xe4000000 0x2000000>; /* SRAM/NOR CS1 region */
#address-cells = <2>;
#size-cells = <1>;
nfc0: nand-controller@0,0 {
compatible = "arm,pl353-nand-r2p1";
reg = <0 0 0x1000000>;
#address-cells = <1>;
#size-cells = <0>;
};
};

View File

@ -1,47 +0,0 @@
Device tree bindings for ARM PL353 static memory controller
PL353 static memory controller supports two kinds of memory
interfaces.i.e NAND and SRAM/NOR interfaces.
The actual devices are instantiated from the child nodes of pl353 smc node.
Required properties:
- compatible : Should be "arm,pl353-smc-r2p1", "arm,primecell".
- reg : Controller registers map and length.
- clock-names : List of input clock names - "memclk", "apb_pclk"
(See clock bindings for details).
- clocks : Clock phandles (see clock bindings for details).
- address-cells : Must be 2.
- size-cells : Must be 1.
Child nodes:
For NAND the "arm,pl353-nand-r2p1" and for NOR the "cfi-flash" drivers are
supported as child nodes.
for NAND partition information please refer the below file
Documentation/devicetree/bindings/mtd/partition.txt
Example:
smcc: memory-controller@e000e000
compatible = "arm,pl353-smc-r2p1", "arm,primecell";
clock-names = "memclk", "apb_pclk";
clocks = <&clkc 11>, <&clkc 44>;
reg = <0xe000e000 0x1000>;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0x0 0x0 0xe1000000 0x1000000 //Nand CS Region
0x1 0x0 0xe2000000 0x2000000 //SRAM/NOR CS Region
0x2 0x0 0xe4000000 0x2000000>; //SRAM/NOR CS Region
nand_0: flash@e1000000 {
compatible = "arm,pl353-nand-r2p1"
reg = <0 0 0x1000000>;
(...)
};
nor0: flash@e2000000 {
compatible = "cfi-flash";
reg = <1 0 0x2000000>;
};
nor1: flash@e4000000 {
compatible = "cfi-flash";
reg = <2 0 0x2000000>;
};
};

View File

@ -0,0 +1,53 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mtd/arm,pl353-nand-r2p1.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: PL353 NAND Controller device tree bindings
allOf:
- $ref: "nand-controller.yaml"
maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com>
- Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
properties:
compatible:
items:
- const: arm,pl353-nand-r2p1
reg:
items:
- items:
- description: CS with regard to the parent ranges property
- description: Offset of the memory region requested by the device
- description: Length of the memory region requested by the device
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
smcc: memory-controller@e000e000 {
compatible = "arm,pl353-smc-r2p1", "arm,primecell";
reg = <0xe000e000 0x0001000>;
clock-names = "memclk", "apb_pclk";
clocks = <&clkc 11>, <&clkc 44>;
ranges = <0x0 0x0 0xe1000000 0x1000000 /* Nand CS region */
0x1 0x0 0xe2000000 0x2000000 /* SRAM/NOR CS0 region */
0x2 0x0 0xe4000000 0x2000000>; /* SRAM/NOR CS1 region */
#address-cells = <2>;
#size-cells = <1>;
nfc0: nand-controller@0,0 {
compatible = "arm,pl353-nand-r2p1";
reg = <0 0 0x1000000>;
#address-cells = <1>;
#size-cells = <0>;
};
};

View File

@ -1,186 +0,0 @@
* Broadcom STB NAND Controller
The Broadcom Set-Top Box NAND controller supports low-level access to raw NAND
flash chips. It has a memory-mapped register interface for both control
registers and for its data input/output buffer. On some SoCs, this controller is
paired with a custom DMA engine (inventively named "Flash DMA") which supports
basic PROGRAM and READ functions, among other features.
This controller was originally designed for STB SoCs (BCM7xxx) but is now
available on a variety of Broadcom SoCs, including some BCM3xxx, BCM63xx, and
iProc/Cygnus. Its history includes several similar (but not fully register
compatible) versions.
Required properties:
- compatible : May contain an SoC-specific compatibility string (see below)
to account for any SoC-specific hardware bits that may be
added on top of the base core controller.
In addition, must contain compatibility information about
the core NAND controller, of the following form:
"brcm,brcmnand" and an appropriate version compatibility
string, like "brcm,brcmnand-v7.0"
Possible values:
brcm,brcmnand-v2.1
brcm,brcmnand-v2.2
brcm,brcmnand-v4.0
brcm,brcmnand-v5.0
brcm,brcmnand-v6.0
brcm,brcmnand-v6.1
brcm,brcmnand-v6.2
brcm,brcmnand-v7.0
brcm,brcmnand-v7.1
brcm,brcmnand-v7.2
brcm,brcmnand-v7.3
brcm,brcmnand
- reg : the register start and length for NAND register region.
(optional) Flash DMA register range (if present)
(optional) NAND flash cache range (if at non-standard offset)
- reg-names : a list of the names corresponding to the previous register
ranges. Should contain "nand" and (optionally)
"flash-dma" or "flash-edu" and/or "nand-cache".
- interrupts : The NAND CTLRDY interrupt, (if Flash DMA is available)
FLASH_DMA_DONE and if EDU is avaialble and used FLASH_EDU_DONE
- interrupt-names : May be "nand_ctlrdy" or "flash_dma_done" or "flash_edu_done",
if broken out as individual interrupts.
May be "nand", if the SoC has the individual NAND
interrupts multiplexed behind another custom piece of
hardware
- #address-cells : <1> - subnodes give the chip-select number
- #size-cells : <0>
Optional properties:
- clock : reference to the clock for the NAND controller
- clock-names : "nand" (required for the above clock)
- brcm,nand-has-wp : Some versions of this IP include a write-protect
(WP) control bit. It is always available on >=
v7.0. Use this property to describe the rare
earlier versions of this core that include WP
-- Additional SoC-specific NAND controller properties --
The NAND controller is integrated differently on the variety of SoCs on which it
is found. Part of this integration involves providing status and enable bits
with which to control the 8 exposed NAND interrupts, as well as hardware for
configuring the endianness of the data bus. On some SoCs, these features are
handled via standard, modular components (e.g., their interrupts look like a
normal IRQ chip), but on others, they are controlled in unique and interesting
ways, sometimes with registers that lump multiple NAND-related functions
together. The former case can be described simply by the standard interrupts
properties in the main controller node. But for the latter exceptional cases,
we define additional 'compatible' properties and associated register resources within the NAND controller node above.
- compatible: Can be one of several SoC-specific strings. Each SoC may have
different requirements for its additional properties, as described below each
bullet point below.
* "brcm,nand-bcm63138"
- reg: (required) the 'NAND_INT_BASE' register range, with separate status
and enable registers
- reg-names: (required) "nand-int-base"
* "brcm,nand-bcm6368"
- compatible: should contain "brcm,nand-bcm<soc>", "brcm,nand-bcm6368"
- reg: (required) the 'NAND_INTR_BASE' register range, with combined status
and enable registers, and boot address registers
- reg-names: (required) "nand-int-base"
* "brcm,nand-iproc"
- reg: (required) the "IDM" register range, for interrupt enable and APB
bus access endianness configuration, and the "EXT" register range,
for interrupt status/ack.
- reg-names: (required) a list of the names corresponding to the previous
register ranges. Should contain "iproc-idm" and "iproc-ext".
* NAND chip-select
Each controller (compatible: "brcm,brcmnand") may contain one or more subnodes
to represent enabled chip-selects which (may) contain NAND flash chips. Their
properties are as follows.
Required properties:
- compatible : should contain "brcm,nandcs"
- reg : a single integer representing the chip-select
number (e.g., 0, 1, 2, etc.)
- #address-cells : see partition.txt
- #size-cells : see partition.txt
Optional properties:
- nand-ecc-strength : see nand-controller.yaml
- nand-ecc-step-size : must be 512 or 1024. See nand-controller.yaml
- nand-on-flash-bbt : boolean, to enable the on-flash BBT for this
chip-select. See nand-controller.yaml
- brcm,nand-oob-sector-size : integer, to denote the spare area sector size
expected for the ECC layout in use. This size, in
addition to the strength and step-size,
determines how the hardware BCH engine will lay
out the parity bytes it stores on the flash.
This property can be automatically determined by
the flash geometry (particularly the NAND page
and OOB size) in many cases, but when booting
from NAND, the boot controller has only a limited
number of available options for its default ECC
layout.
Each nandcs device node may optionally contain sub-nodes describing the flash
partition mapping. See partition.txt for more detail.
Example:
nand@f0442800 {
compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand";
reg = <0xF0442800 0x600>,
<0xF0443000 0x100>;
reg-names = "nand", "flash-dma";
interrupt-parent = <&hif_intr2_intc>;
interrupts = <24>, <4>;
#address-cells = <1>;
#size-cells = <0>;
nandcs@1 {
compatible = "brcm,nandcs";
reg = <1>; // Chip select 1
nand-on-flash-bbt;
nand-ecc-strength = <12>;
nand-ecc-step-size = <512>;
// Partitions
#address-cells = <1>; // <2>, for 64-bit offset
#size-cells = <1>; // <2>, for 64-bit length
flash0.rootfs@0 {
reg = <0 0x10000000>;
};
flash0@0 {
reg = <0 0>; // MTDPART_SIZ_FULL
};
flash0.kernel@10000000 {
reg = <0x10000000 0x400000>;
};
};
};
nand@10000200 {
compatible = "brcm,nand-bcm63168", "brcm,nand-bcm6368",
"brcm,brcmnand-v4.0", "brcm,brcmnand";
reg = <0x10000200 0x180>,
<0x10000600 0x200>,
<0x100000b0 0x10>;
reg-names = "nand", "nand-cache", "nand-int-base";
interrupt-parent = <&periph_intc>;
interrupts = <50>;
clocks = <&periph_clk 20>;
clock-names = "nand";
#address-cells = <1>;
#size-cells = <0>;
nand0: nandcs@0 {
compatible = "brcm,nandcs";
reg = <0>;
nand-on-flash-bbt;
nand-ecc-strength = <1>;
nand-ecc-step-size = <512>;
};
};

View File

@ -0,0 +1,242 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mtd/brcm,brcmnand.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom STB NAND Controller
maintainers:
- Brian Norris <computersforpeace@gmail.com>
- Kamal Dasu <kdasu.kdev@gmail.com>
description: |
The Broadcom Set-Top Box NAND controller supports low-level access to raw NAND
flash chips. It has a memory-mapped register interface for both control
registers and for its data input/output buffer. On some SoCs, this controller
is paired with a custom DMA engine (inventively named "Flash DMA") which
supports basic PROGRAM and READ functions, among other features.
This controller was originally designed for STB SoCs (BCM7xxx) but is now
available on a variety of Broadcom SoCs, including some BCM3xxx, BCM63xx, and
iProc/Cygnus. Its history includes several similar (but not fully register
compatible) versions.
-- Additional SoC-specific NAND controller properties --
The NAND controller is integrated differently on the variety of SoCs on which
it is found. Part of this integration involves providing status and enable
bits with which to control the 8 exposed NAND interrupts, as well as hardware
for configuring the endianness of the data bus. On some SoCs, these features
are handled via standard, modular components (e.g., their interrupts look like
a normal IRQ chip), but on others, they are controlled in unique and
interesting ways, sometimes with registers that lump multiple NAND-related
functions together. The former case can be described simply by the standard
interrupts properties in the main controller node. But for the latter
exceptional cases, we define additional 'compatible' properties and associated
register resources within the NAND controller node above.
properties:
compatible:
oneOf:
- items:
- enum:
- brcm,brcmnand-v2.1
- brcm,brcmnand-v2.2
- brcm,brcmnand-v4.0
- brcm,brcmnand-v5.0
- brcm,brcmnand-v6.0
- brcm,brcmnand-v6.1
- brcm,brcmnand-v6.2
- brcm,brcmnand-v7.0
- brcm,brcmnand-v7.1
- brcm,brcmnand-v7.2
- brcm,brcmnand-v7.3
- const: brcm,brcmnand
- description: BCM63138 SoC-specific NAND controller
items:
- const: brcm,nand-bcm63138
- enum:
- brcm,brcmnand-v7.0
- brcm,brcmnand-v7.1
- const: brcm,brcmnand
- description: iProc SoC-specific NAND controller
items:
- const: brcm,nand-iproc
- const: brcm,brcmnand-v6.1
- const: brcm,brcmnand
- description: BCM63168 SoC-specific NAND controller
items:
- const: brcm,nand-bcm63168
- const: brcm,nand-bcm6368
- const: brcm,brcmnand-v4.0
- const: brcm,brcmnand
reg:
minItems: 1
maxItems: 6
reg-names:
minItems: 1
maxItems: 6
items:
enum: [ nand, flash-dma, flash-edu, nand-cache, nand-int-base, iproc-idm, iproc-ext ]
interrupts:
minItems: 1
maxItems: 3
items:
- description: NAND CTLRDY interrupt
- description: FLASH_DMA_DONE if flash DMA is available
- description: FLASH_EDU_DONE if EDU is available
interrupt-names:
minItems: 1
maxItems: 3
items:
- const: nand_ctlrdy
- const: flash_dma_done
- const: flash_edu_done
clocks:
maxItems: 1
description: reference to the clock for the NAND controller
clock-names:
const: nand
brcm,nand-has-wp:
description: >
Some versions of this IP include a write-protect
(WP) control bit. It is always available on >=
v7.0. Use this property to describe the rare
earlier versions of this core that include WP
type: boolean
patternProperties:
"^nand@[a-f0-9]$":
type: object
properties:
compatible:
const: brcm,nandcs
nand-ecc-step-size:
enum: [ 512, 1024 ]
brcm,nand-oob-sector-size:
description: |
integer, to denote the spare area sector size
expected for the ECC layout in use. This size, in
addition to the strength and step-size,
determines how the hardware BCH engine will lay
out the parity bytes it stores on the flash.
This property can be automatically determined by
the flash geometry (particularly the NAND page
and OOB size) in many cases, but when booting
from NAND, the boot controller has only a limited
number of available options for its default ECC
layout.
$ref: /schemas/types.yaml#/definitions/uint32
allOf:
- $ref: nand-controller.yaml#
- if:
properties:
compatible:
contains:
const: brcm,nand-bcm63138
then:
properties:
reg-names:
minItems: 2
maxItems: 2
items:
- const: nand
- const: nand-int-base
- if:
properties:
compatible:
contains:
const: brcm,nand-bcm6368
then:
properties:
reg-names:
minItems: 3
maxItems: 3
items:
- const: nand
- const: nand-int-base
- const: nand-cache
- if:
properties:
compatible:
contains:
const: brcm,nand-iproc
then:
properties:
reg-names:
minItems: 3
maxItems: 3
items:
- const: nand
- const: iproc-idm
- const: iproc-ext
unevaluatedProperties: false
required:
- reg
- reg-names
- interrupts
examples:
- |
nand-controller@f0442800 {
compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand";
reg = <0xf0442800 0x600>,
<0xf0443000 0x100>;
reg-names = "nand", "flash-dma";
interrupt-parent = <&hif_intr2_intc>;
interrupts = <24>, <4>;
#address-cells = <1>;
#size-cells = <0>;
nand@1 {
compatible = "brcm,nandcs";
reg = <1>; // Chip select 1
nand-on-flash-bbt;
nand-ecc-strength = <12>;
nand-ecc-step-size = <512>;
#address-cells = <1>;
#size-cells = <1>;
};
};
- |
nand-controller@10000200 {
compatible = "brcm,nand-bcm63168", "brcm,nand-bcm6368",
"brcm,brcmnand-v4.0", "brcm,brcmnand";
reg = <0x10000200 0x180>,
<0x100000b0 0x10>,
<0x10000600 0x200>;
reg-names = "nand", "nand-int-base", "nand-cache";
interrupt-parent = <&periph_intc>;
interrupts = <50>;
clocks = <&periph_clk 20>;
clock-names = "nand";
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
compatible = "brcm,nandcs";
reg = <0>;
nand-on-flash-bbt;
nand-ecc-strength = <1>;
nand-ecc-step-size = <512>;
#address-cells = <1>;
#size-cells = <1>;
};
};

View File

@ -38,6 +38,17 @@ properties:
ranges: true
cs-gpios:
minItems: 1
maxItems: 8
description:
Array of chip-select available to the controller. The first
entries are a 1:1 mapping of the available chip-select on the
NAND controller (even if they are not used). As many additional
chip-select as needed may follow and should be phandles of GPIO
lines. 'reg' entries of the NAND chip subnodes become indexes of
this array when this property is present.
patternProperties:
"^nand@[a-f0-9]$":
type: object
@ -164,14 +175,19 @@ examples:
nand-controller {
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <0>, <&gpioA 1>; /* A single native CS is available */
/* controller specific properties */
nand@0 {
reg = <0>;
reg = <0>; /* Native CS */
nand-use-soft-ecc-engine;
nand-ecc-algo = "bch";
/* controller specific properties */
};
nand@1 {
reg = <1>; /* GPIO CS */
};
};

View File

@ -1311,6 +1311,7 @@ W: http://www.aquantia.com
F: drivers/net/ethernet/aquantia/atlantic/aq_ptp*
ARASAN NAND CONTROLLER DRIVER
M: Miquel Raynal <miquel.raynal@bootlin.com>
M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-mtd@lists.infradead.org
S: Maintained
@ -1452,6 +1453,22 @@ S: Odd Fixes
F: drivers/amba/
F: include/linux/amba/bus.h
ARM PRIMECELL PL35X NAND CONTROLLER DRIVER
M: Miquel Raynal <miquel.raynal@bootlin.com@bootlin.com>
M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml
F: drivers/mtd/nand/raw/pl35x-nand-controller.c
ARM PRIMECELL PL35X SMC DRIVER
M: Miquel Raynal <miquel.raynal@bootlin.com@bootlin.com>
M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/mtd/arm,pl353-smc.yaml
F: drivers/memory/pl353-smc.c
ARM PRIMECELL CLCD PL110 DRIVER
M: Russell King <linux@armlinux.org.uk>
S: Odd Fixes

View File

@ -8,263 +8,22 @@
*/
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/pl353-smc.h>
#include <linux/amba/bus.h>
/* Register definitions */
#define PL353_SMC_MEMC_STATUS_OFFS 0 /* Controller status reg, RO */
#define PL353_SMC_CFG_CLR_OFFS 0xC /* Clear config reg, WO */
#define PL353_SMC_DIRECT_CMD_OFFS 0x10 /* Direct command reg, WO */
#define PL353_SMC_SET_CYCLES_OFFS 0x14 /* Set cycles register, WO */
#define PL353_SMC_SET_OPMODE_OFFS 0x18 /* Set opmode register, WO */
#define PL353_SMC_ECC_STATUS_OFFS 0x400 /* ECC status register */
#define PL353_SMC_ECC_MEMCFG_OFFS 0x404 /* ECC mem config reg */
#define PL353_SMC_ECC_MEMCMD1_OFFS 0x408 /* ECC mem cmd1 reg */
#define PL353_SMC_ECC_MEMCMD2_OFFS 0x40C /* ECC mem cmd2 reg */
#define PL353_SMC_ECC_VALUE0_OFFS 0x418 /* ECC value 0 reg */
/* Controller status register specific constants */
#define PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT 6
/* Clear configuration register specific constants */
#define PL353_SMC_CFG_CLR_INT_CLR_1 0x10
#define PL353_SMC_CFG_CLR_ECC_INT_DIS_1 0x40
#define PL353_SMC_CFG_CLR_INT_DIS_1 0x2
#define PL353_SMC_CFG_CLR_DEFAULT_MASK (PL353_SMC_CFG_CLR_INT_CLR_1 | \
PL353_SMC_CFG_CLR_ECC_INT_DIS_1 | \
PL353_SMC_CFG_CLR_INT_DIS_1)
/* Set cycles register specific constants */
#define PL353_SMC_SET_CYCLES_T0_MASK 0xF
#define PL353_SMC_SET_CYCLES_T0_SHIFT 0
#define PL353_SMC_SET_CYCLES_T1_MASK 0xF
#define PL353_SMC_SET_CYCLES_T1_SHIFT 4
#define PL353_SMC_SET_CYCLES_T2_MASK 0x7
#define PL353_SMC_SET_CYCLES_T2_SHIFT 8
#define PL353_SMC_SET_CYCLES_T3_MASK 0x7
#define PL353_SMC_SET_CYCLES_T3_SHIFT 11
#define PL353_SMC_SET_CYCLES_T4_MASK 0x7
#define PL353_SMC_SET_CYCLES_T4_SHIFT 14
#define PL353_SMC_SET_CYCLES_T5_MASK 0x7
#define PL353_SMC_SET_CYCLES_T5_SHIFT 17
#define PL353_SMC_SET_CYCLES_T6_MASK 0xF
#define PL353_SMC_SET_CYCLES_T6_SHIFT 20
/* ECC status register specific constants */
#define PL353_SMC_ECC_STATUS_BUSY BIT(6)
#define PL353_SMC_ECC_REG_SIZE_OFFS 4
/* ECC memory config register specific constants */
#define PL353_SMC_ECC_MEMCFG_MODE_MASK 0xC
#define PL353_SMC_ECC_MEMCFG_MODE_SHIFT 2
#define PL353_SMC_ECC_MEMCFG_PGSIZE_MASK 0x3
#define PL353_SMC_DC_UPT_NAND_REGS ((4 << 23) | /* CS: NAND chip */ \
(2 << 21)) /* UpdateRegs operation */
#define PL353_NAND_ECC_CMD1 ((0x80) | /* Write command */ \
(0 << 8) | /* Read command */ \
(0x30 << 16) | /* Read End command */ \
(1 << 24)) /* Read End command calid */
#define PL353_NAND_ECC_CMD2 ((0x85) | /* Write col change cmd */ \
(5 << 8) | /* Read col change cmd */ \
(0xE0 << 16) | /* Read col change end cmd */ \
(1 << 24)) /* Read col change end cmd valid */
#define PL353_NAND_ECC_BUSY_TIMEOUT (1 * HZ)
/**
* struct pl353_smc_data - Private smc driver structure
* @memclk: Pointer to the peripheral clock
* @aclk: Pointer to the APER clock
* @aclk: Pointer to the AXI peripheral clock
*/
struct pl353_smc_data {
struct clk *memclk;
struct clk *aclk;
};
/* SMC virtual register base */
static void __iomem *pl353_smc_base;
/**
* pl353_smc_set_buswidth - Set memory buswidth
* @bw: Memory buswidth (8 | 16)
* Return: 0 on success or negative errno.
*/
int pl353_smc_set_buswidth(unsigned int bw)
{
if (bw != PL353_SMC_MEM_WIDTH_8 && bw != PL353_SMC_MEM_WIDTH_16)
return -EINVAL;
writel(bw, pl353_smc_base + PL353_SMC_SET_OPMODE_OFFS);
writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base +
PL353_SMC_DIRECT_CMD_OFFS);
return 0;
}
EXPORT_SYMBOL_GPL(pl353_smc_set_buswidth);
/**
* pl353_smc_set_cycles - Set memory timing parameters
* @timings: NAND controller timing parameters
*
* Sets NAND chip specific timing parameters.
*/
void pl353_smc_set_cycles(u32 timings[])
{
/*
* Set write pulse timing. This one is easy to extract:
*
* NWE_PULSE = tWP
*/
timings[0] &= PL353_SMC_SET_CYCLES_T0_MASK;
timings[1] = (timings[1] & PL353_SMC_SET_CYCLES_T1_MASK) <<
PL353_SMC_SET_CYCLES_T1_SHIFT;
timings[2] = (timings[2] & PL353_SMC_SET_CYCLES_T2_MASK) <<
PL353_SMC_SET_CYCLES_T2_SHIFT;
timings[3] = (timings[3] & PL353_SMC_SET_CYCLES_T3_MASK) <<
PL353_SMC_SET_CYCLES_T3_SHIFT;
timings[4] = (timings[4] & PL353_SMC_SET_CYCLES_T4_MASK) <<
PL353_SMC_SET_CYCLES_T4_SHIFT;
timings[5] = (timings[5] & PL353_SMC_SET_CYCLES_T5_MASK) <<
PL353_SMC_SET_CYCLES_T5_SHIFT;
timings[6] = (timings[6] & PL353_SMC_SET_CYCLES_T6_MASK) <<
PL353_SMC_SET_CYCLES_T6_SHIFT;
timings[0] |= timings[1] | timings[2] | timings[3] |
timings[4] | timings[5] | timings[6];
writel(timings[0], pl353_smc_base + PL353_SMC_SET_CYCLES_OFFS);
writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base +
PL353_SMC_DIRECT_CMD_OFFS);
}
EXPORT_SYMBOL_GPL(pl353_smc_set_cycles);
/**
* pl353_smc_ecc_is_busy - Read ecc busy flag
* Return: the ecc_status bit from the ecc_status register. 1 = busy, 0 = idle
*/
bool pl353_smc_ecc_is_busy(void)
{
return ((readl(pl353_smc_base + PL353_SMC_ECC_STATUS_OFFS) &
PL353_SMC_ECC_STATUS_BUSY) == PL353_SMC_ECC_STATUS_BUSY);
}
EXPORT_SYMBOL_GPL(pl353_smc_ecc_is_busy);
/**
* pl353_smc_get_ecc_val - Read ecc_valueN registers
* @ecc_reg: Index of the ecc_value reg (0..3)
* Return: the content of the requested ecc_value register.
*
* There are four valid ecc_value registers. The argument is truncated to stay
* within this valid boundary.
*/
u32 pl353_smc_get_ecc_val(int ecc_reg)
{
u32 addr, reg;
addr = PL353_SMC_ECC_VALUE0_OFFS +
(ecc_reg * PL353_SMC_ECC_REG_SIZE_OFFS);
reg = readl(pl353_smc_base + addr);
return reg;
}
EXPORT_SYMBOL_GPL(pl353_smc_get_ecc_val);
/**
* pl353_smc_get_nand_int_status_raw - Get NAND interrupt status bit
* Return: the raw_int_status1 bit from the memc_status register
*/
int pl353_smc_get_nand_int_status_raw(void)
{
u32 reg;
reg = readl(pl353_smc_base + PL353_SMC_MEMC_STATUS_OFFS);
reg >>= PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT;
reg &= 1;
return reg;
}
EXPORT_SYMBOL_GPL(pl353_smc_get_nand_int_status_raw);
/**
* pl353_smc_clr_nand_int - Clear NAND interrupt
*/
void pl353_smc_clr_nand_int(void)
{
writel(PL353_SMC_CFG_CLR_INT_CLR_1,
pl353_smc_base + PL353_SMC_CFG_CLR_OFFS);
}
EXPORT_SYMBOL_GPL(pl353_smc_clr_nand_int);
/**
* pl353_smc_set_ecc_mode - Set SMC ECC mode
* @mode: ECC mode (BYPASS, APB, MEM)
* Return: 0 on success or negative errno.
*/
int pl353_smc_set_ecc_mode(enum pl353_smc_ecc_mode mode)
{
u32 reg;
int ret = 0;
switch (mode) {
case PL353_SMC_ECCMODE_BYPASS:
case PL353_SMC_ECCMODE_APB:
case PL353_SMC_ECCMODE_MEM:
reg = readl(pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
reg &= ~PL353_SMC_ECC_MEMCFG_MODE_MASK;
reg |= mode << PL353_SMC_ECC_MEMCFG_MODE_SHIFT;
writel(reg, pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
break;
default:
ret = -EINVAL;
}
return ret;
}
EXPORT_SYMBOL_GPL(pl353_smc_set_ecc_mode);
/**
* pl353_smc_set_ecc_pg_size - Set SMC ECC page size
* @pg_sz: ECC page size
* Return: 0 on success or negative errno.
*/
int pl353_smc_set_ecc_pg_size(unsigned int pg_sz)
{
u32 reg, sz;
switch (pg_sz) {
case 0:
sz = 0;
break;
case SZ_512:
sz = 1;
break;
case SZ_1K:
sz = 2;
break;
case SZ_2K:
sz = 3;
break;
default:
return -EINVAL;
}
reg = readl(pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
reg &= ~PL353_SMC_ECC_MEMCFG_PGSIZE_MASK;
reg |= sz;
writel(reg, pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
return 0;
}
EXPORT_SYMBOL_GPL(pl353_smc_set_ecc_pg_size);
static int __maybe_unused pl353_smc_suspend(struct device *dev)
{
struct pl353_smc_data *pl353_smc = dev_get_drvdata(dev);
@ -277,8 +36,8 @@ static int __maybe_unused pl353_smc_suspend(struct device *dev)
static int __maybe_unused pl353_smc_resume(struct device *dev)
{
int ret;
struct pl353_smc_data *pl353_smc = dev_get_drvdata(dev);
int ret;
ret = clk_enable(pl353_smc->aclk);
if (ret) {
@ -296,77 +55,31 @@ static int __maybe_unused pl353_smc_resume(struct device *dev)
return ret;
}
static struct amba_driver pl353_smc_driver;
static SIMPLE_DEV_PM_OPS(pl353_smc_dev_pm_ops, pl353_smc_suspend,
pl353_smc_resume);
/**
* pl353_smc_init_nand_interface - Initialize the NAND interface
* @adev: Pointer to the amba_device struct
* @nand_node: Pointer to the pl353_nand device_node struct
*/
static void pl353_smc_init_nand_interface(struct amba_device *adev,
struct device_node *nand_node)
{
unsigned long timeout;
pl353_smc_set_buswidth(PL353_SMC_MEM_WIDTH_8);
writel(PL353_SMC_CFG_CLR_INT_CLR_1,
pl353_smc_base + PL353_SMC_CFG_CLR_OFFS);
writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base +
PL353_SMC_DIRECT_CMD_OFFS);
timeout = jiffies + PL353_NAND_ECC_BUSY_TIMEOUT;
/* Wait till the ECC operation is complete */
do {
if (pl353_smc_ecc_is_busy())
cpu_relax();
else
break;
} while (!time_after_eq(jiffies, timeout));
if (time_after_eq(jiffies, timeout))
return;
writel(PL353_NAND_ECC_CMD1,
pl353_smc_base + PL353_SMC_ECC_MEMCMD1_OFFS);
writel(PL353_NAND_ECC_CMD2,
pl353_smc_base + PL353_SMC_ECC_MEMCMD2_OFFS);
}
static const struct of_device_id pl353_smc_supported_children[] = {
{
.compatible = "cfi-flash"
},
{
.compatible = "arm,pl353-nand-r2p1",
.data = pl353_smc_init_nand_interface
},
{}
};
static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device_node *of_node = adev->dev.of_node;
const struct of_device_id *match = NULL;
struct pl353_smc_data *pl353_smc;
struct device_node *child;
struct resource *res;
int err;
struct device_node *of_node = adev->dev.of_node;
static void (*init)(struct amba_device *adev,
struct device_node *nand_node);
const struct of_device_id *match = NULL;
pl353_smc = devm_kzalloc(&adev->dev, sizeof(*pl353_smc), GFP_KERNEL);
if (!pl353_smc)
return -ENOMEM;
/* Get the NAND controller virtual address */
res = &adev->res;
pl353_smc_base = devm_ioremap_resource(&adev->dev, res);
if (IS_ERR(pl353_smc_base))
return PTR_ERR(pl353_smc_base);
pl353_smc->aclk = devm_clk_get(&adev->dev, "apb_pclk");
if (IS_ERR(pl353_smc->aclk)) {
dev_err(&adev->dev, "aclk clock not found.\n");
@ -388,15 +101,11 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
err = clk_prepare_enable(pl353_smc->memclk);
if (err) {
dev_err(&adev->dev, "Unable to enable memory clock.\n");
goto out_clk_dis_aper;
goto disable_axi_clk;
}
amba_set_drvdata(adev, pl353_smc);
/* clear interrupts */
writel(PL353_SMC_CFG_CLR_DEFAULT_MASK,
pl353_smc_base + PL353_SMC_CFG_CLR_OFFS);
/* Find compatible children. Only a single child is supported */
for_each_available_child_of_node(of_node, child) {
match = of_match_node(pl353_smc_supported_children, child);
@ -408,19 +117,16 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
}
if (!match) {
dev_err(&adev->dev, "no matching children\n");
goto out_clk_disable;
goto disable_mem_clk;
}
init = match->data;
if (init)
init(adev, child);
of_platform_device_create(child, NULL, &adev->dev);
return 0;
out_clk_disable:
disable_mem_clk:
clk_disable_unprepare(pl353_smc->memclk);
out_clk_dis_aper:
disable_axi_clk:
clk_disable_unprepare(pl353_smc->aclk);
return err;
@ -436,8 +142,8 @@ static void pl353_smc_remove(struct amba_device *adev)
static const struct amba_id pl353_ids[] = {
{
.id = 0x00041353,
.mask = 0x000fffff,
.id = 0x00041353,
.mask = 0x000fffff,
},
{ 0, 0 },
};

View File

@ -123,7 +123,7 @@ int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
pos[1] &= ~GENMASK(rbits - 1, 0);
pos[1] |= val >> rbits;
pos[1] |= val >> (bits_per_block - rbits);
}
return 0;

View File

@ -453,6 +453,14 @@ config MTD_NAND_ROCKCHIP
NFC v800: RK3308, RV1108
NFC v900: PX30, RK3326
config MTD_NAND_PL35X
tristate "ARM PL35X NAND controller"
depends on OF || COMPILE_TEST
depends on PL353_SMC
help
Enables support for PrimeCell SMC PL351 and PL353 NAND
controller found on Zynq7000.
comment "Misc"
config MTD_SM_COMMON

View File

@ -57,6 +57,7 @@ obj-$(CONFIG_MTD_NAND_CADENCE) += cadence-nand-controller.o
obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o
obj-$(CONFIG_MTD_NAND_INTEL_LGM) += intel-nand-controller.o
obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o
obj-$(CONFIG_MTD_NAND_PL35X) += pl35x-nand-controller.o
nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_onfi.o

View File

@ -15,6 +15,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/module.h>
@ -53,6 +54,7 @@
#define PROG_RST BIT(8)
#define PROG_GET_FEATURE BIT(9)
#define PROG_SET_FEATURE BIT(10)
#define PROG_CHG_RD_COL_ENH BIT(14)
#define INTR_STS_EN_REG 0x14
#define INTR_SIG_EN_REG 0x18
@ -70,6 +72,15 @@
#define FLASH_STS_REG 0x28
#define TIMING_REG 0x2C
#define TCCS_TIME_500NS 0
#define TCCS_TIME_300NS 3
#define TCCS_TIME_200NS 2
#define TCCS_TIME_100NS 1
#define FAST_TCAD BIT(2)
#define DQS_BUFF_SEL_IN(x) FIELD_PREP(GENMASK(6, 3), (x))
#define DQS_BUFF_SEL_OUT(x) FIELD_PREP(GENMASK(18, 15), (x))
#define DATA_PORT_REG 0x30
#define ECC_CONF_REG 0x34
@ -91,7 +102,7 @@
#define DATA_INTERFACE_REG 0x6C
#define DIFACE_SDR_MODE(x) FIELD_PREP(GENMASK(2, 0), (x))
#define DIFACE_DDR_MODE(x) FIELD_PREP(GENMASK(5, 3), (X))
#define DIFACE_DDR_MODE(x) FIELD_PREP(GENMASK(5, 3), (x))
#define DIFACE_SDR 0
#define DIFACE_NVDDR BIT(9)
@ -107,6 +118,8 @@
#define ANFC_XLNX_SDR_DFLT_CORE_CLK 100000000
#define ANFC_XLNX_SDR_HS_CORE_CLK 80000000
static struct gpio_desc *anfc_default_cs_array[2] = {NULL, NULL};
/**
* struct anfc_op - Defines how to execute an operation
* @pkt_reg: Packet register
@ -137,11 +150,11 @@ struct anfc_op {
* struct anand - Defines the NAND chip related information
* @node: Used to store NAND chips into a list
* @chip: NAND chip information structure
* @cs: Chip select line
* @rb: Ready-busy line
* @page_sz: Register value of the page_sz field to use
* @clk: Expected clock frequency to use
* @timings: Data interface timing mode to use
* @data_iface: Data interface timing mode to use
* @timings: NV-DDR specific timings to use
* @ecc_conf: Hardware ECC configuration value
* @strength: Register value of the ECC strength
* @raddr_cycles: Row address cycle information
@ -151,14 +164,17 @@ struct anfc_op {
* @errloc: Array of errors located with soft BCH
* @hw_ecc: Buffer to store syndromes computed by hardware
* @bch: BCH structure
* @cs_idx: Array of chip-select for this device, values are indexes
* of the controller structure @gpio_cs array
* @ncs_idx: Size of the @cs_idx array
*/
struct anand {
struct list_head node;
struct nand_chip chip;
unsigned int cs;
unsigned int rb;
unsigned int page_sz;
unsigned long clk;
u32 data_iface;
u32 timings;
u32 ecc_conf;
u32 strength;
@ -169,6 +185,8 @@ struct anand {
unsigned int *errloc;
u8 *hw_ecc;
struct bch_control *bch;
int *cs_idx;
int ncs_idx;
};
/**
@ -179,8 +197,14 @@ struct anand {
* @bus_clk: Pointer to the flash clock
* @controller: Base controller structure
* @chips: List of all NAND chips attached to the controller
* @assigned_cs: Bitmask describing already assigned CS lines
* @cur_clk: Current clock rate
* @cs_array: CS array. Native CS are left empty, the other cells are
* populated with their corresponding GPIO descriptor.
* @ncs: Size of @cs_array
* @cur_cs: Index in @cs_array of the currently in use CS
* @native_cs: Currently selected native CS
* @spare_cs: Native CS that is not wired (may be selected when a GPIO
* CS is in use)
*/
struct arasan_nfc {
struct device *dev;
@ -189,8 +213,12 @@ struct arasan_nfc {
struct clk *bus_clk;
struct nand_controller controller;
struct list_head chips;
unsigned long assigned_cs;
unsigned int cur_clk;
struct gpio_desc **cs_array;
unsigned int ncs;
int cur_cs;
unsigned int native_cs;
unsigned int spare_cs;
};
static struct anand *to_anand(struct nand_chip *nand)
@ -273,6 +301,72 @@ static int anfc_pkt_len_config(unsigned int len, unsigned int *steps,
return 0;
}
static bool anfc_is_gpio_cs(struct arasan_nfc *nfc, int nfc_cs)
{
return nfc_cs >= 0 && nfc->cs_array[nfc_cs];
}
static int anfc_relative_to_absolute_cs(struct anand *anand, int num)
{
return anand->cs_idx[num];
}
static void anfc_assert_cs(struct arasan_nfc *nfc, unsigned int nfc_cs_idx)
{
/* CS did not change: do nothing */
if (nfc->cur_cs == nfc_cs_idx)
return;
/* Deassert the previous CS if it was a GPIO */
if (anfc_is_gpio_cs(nfc, nfc->cur_cs))
gpiod_set_value_cansleep(nfc->cs_array[nfc->cur_cs], 1);
/* Assert the new one */
if (anfc_is_gpio_cs(nfc, nfc_cs_idx)) {
nfc->native_cs = nfc->spare_cs;
gpiod_set_value_cansleep(nfc->cs_array[nfc_cs_idx], 0);
} else {
nfc->native_cs = nfc_cs_idx;
}
nfc->cur_cs = nfc_cs_idx;
}
static int anfc_select_target(struct nand_chip *chip, int target)
{
struct anand *anand = to_anand(chip);
struct arasan_nfc *nfc = to_anfc(chip->controller);
unsigned int nfc_cs_idx = anfc_relative_to_absolute_cs(anand, target);
int ret;
anfc_assert_cs(nfc, nfc_cs_idx);
/* Update the controller timings and the potential ECC configuration */
writel_relaxed(anand->data_iface, nfc->base + DATA_INTERFACE_REG);
writel_relaxed(anand->timings, nfc->base + TIMING_REG);
/* Update clock frequency */
if (nfc->cur_clk != anand->clk) {
clk_disable_unprepare(nfc->controller_clk);
ret = clk_set_rate(nfc->controller_clk, anand->clk);
if (ret) {
dev_err(nfc->dev, "Failed to change clock rate\n");
return ret;
}
ret = clk_prepare_enable(nfc->controller_clk);
if (ret) {
dev_err(nfc->dev,
"Failed to re-enable the controller clock\n");
return ret;
}
nfc->cur_clk = anand->clk;
}
return 0;
}
/*
* When using the embedded hardware ECC engine, the controller is in charge of
* feeding the engine with, first, the ECC residue present in the data array.
@ -315,7 +409,7 @@ static int anfc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
.addr2_reg =
((page >> 16) & 0xFF) |
ADDR2_STRENGTH(anand->strength) |
ADDR2_CS(anand->cs),
ADDR2_CS(nfc->native_cs),
.cmd_reg =
CMD_1(NAND_CMD_READ0) |
CMD_2(NAND_CMD_READSTART) |
@ -401,6 +495,18 @@ static int anfc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
return 0;
}
static int anfc_sel_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
int ret;
ret = anfc_select_target(chip, chip->cur_cs);
if (ret)
return ret;
return anfc_read_page_hw_ecc(chip, buf, oob_required, page);
};
static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
@ -420,7 +526,7 @@ static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
.addr2_reg =
((page >> 16) & 0xFF) |
ADDR2_STRENGTH(anand->strength) |
ADDR2_CS(anand->cs),
ADDR2_CS(nfc->native_cs),
.cmd_reg =
CMD_1(NAND_CMD_SEQIN) |
CMD_2(NAND_CMD_PAGEPROG) |
@ -461,11 +567,24 @@ static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
return ret;
}
static int anfc_sel_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
int ret;
ret = anfc_select_target(chip, chip->cur_cs);
if (ret)
return ret;
return anfc_write_page_hw_ecc(chip, buf, oob_required, page);
};
/* NAND framework ->exec_op() hooks and related helpers */
static int anfc_parse_instructions(struct nand_chip *chip,
const struct nand_subop *subop,
struct anfc_op *nfc_op)
{
struct arasan_nfc *nfc = to_anfc(chip->controller);
struct anand *anand = to_anand(chip);
const struct nand_op_instr *instr = NULL;
bool first_cmd = true;
@ -473,7 +592,7 @@ static int anfc_parse_instructions(struct nand_chip *chip,
int ret, i;
memset(nfc_op, 0, sizeof(*nfc_op));
nfc_op->addr2_reg = ADDR2_CS(anand->cs);
nfc_op->addr2_reg = ADDR2_CS(nfc->native_cs);
nfc_op->cmd_reg = CMD_PAGE_SIZE(anand->page_sz);
for (op_id = 0; op_id < subop->ninstrs; op_id++) {
@ -622,7 +741,23 @@ static int anfc_param_read_type_exec(struct nand_chip *chip,
static int anfc_data_read_type_exec(struct nand_chip *chip,
const struct nand_subop *subop)
{
return anfc_misc_data_type_exec(chip, subop, PROG_PGRD);
u32 prog_reg = PROG_PGRD;
/*
* Experience shows that while in SDR mode sending a CHANGE READ COLUMN
* command through the READ PAGE "type" always works fine, when in
* NV-DDR mode the same command simply fails. However, it was also
* spotted that any CHANGE READ COLUMN command sent through the CHANGE
* READ COLUMN ENHANCED "type" would correctly work in both cases (SDR
* and NV-DDR). So, for simplicity, let's program the controller with
* the CHANGE READ COLUMN ENHANCED "type" whenever we are requested to
* perform a CHANGE READ COLUMN operation.
*/
if (subop->instrs[0].ctx.cmd.opcode == NAND_CMD_RNDOUT &&
subop->instrs[2].ctx.cmd.opcode == NAND_CMD_RNDOUTSTART)
prog_reg = PROG_CHG_RD_COL_ENH;
return anfc_misc_data_type_exec(chip, subop, prog_reg);
}
static int anfc_param_write_type_exec(struct nand_chip *chip,
@ -753,37 +888,6 @@ static const struct nand_op_parser anfc_op_parser = NAND_OP_PARSER(
NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
);
static int anfc_select_target(struct nand_chip *chip, int target)
{
struct anand *anand = to_anand(chip);
struct arasan_nfc *nfc = to_anfc(chip->controller);
int ret;
/* Update the controller timings and the potential ECC configuration */
writel_relaxed(anand->timings, nfc->base + DATA_INTERFACE_REG);
/* Update clock frequency */
if (nfc->cur_clk != anand->clk) {
clk_disable_unprepare(nfc->controller_clk);
ret = clk_set_rate(nfc->controller_clk, anand->clk);
if (ret) {
dev_err(nfc->dev, "Failed to change clock rate\n");
return ret;
}
ret = clk_prepare_enable(nfc->controller_clk);
if (ret) {
dev_err(nfc->dev,
"Failed to re-enable the controller clock\n");
return ret;
}
nfc->cur_clk = anand->clk;
}
return 0;
}
static int anfc_check_op(struct nand_chip *chip,
const struct nand_operation *op)
{
@ -861,21 +965,79 @@ static int anfc_setup_interface(struct nand_chip *chip, int target,
struct anand *anand = to_anand(chip);
struct arasan_nfc *nfc = to_anfc(chip->controller);
struct device_node *np = nfc->dev->of_node;
const struct nand_sdr_timings *sdr;
const struct nand_nvddr_timings *nvddr;
unsigned int tccs_min, dqs_mode, fast_tcad;
if (nand_interface_is_nvddr(conf)) {
nvddr = nand_get_nvddr_timings(conf);
if (IS_ERR(nvddr))
return PTR_ERR(nvddr);
} else {
sdr = nand_get_sdr_timings(conf);
if (IS_ERR(sdr))
return PTR_ERR(sdr);
}
if (target < 0)
return 0;
anand->timings = DIFACE_SDR | DIFACE_SDR_MODE(conf->timings.mode);
if (nand_interface_is_sdr(conf)) {
anand->data_iface = DIFACE_SDR |
DIFACE_SDR_MODE(conf->timings.mode);
anand->timings = 0;
} else {
anand->data_iface = DIFACE_NVDDR |
DIFACE_DDR_MODE(conf->timings.mode);
if (conf->timings.nvddr.tCCS_min <= 100000)
tccs_min = TCCS_TIME_100NS;
else if (conf->timings.nvddr.tCCS_min <= 200000)
tccs_min = TCCS_TIME_200NS;
else if (conf->timings.nvddr.tCCS_min <= 300000)
tccs_min = TCCS_TIME_300NS;
else
tccs_min = TCCS_TIME_500NS;
fast_tcad = 0;
if (conf->timings.nvddr.tCAD_min < 45000)
fast_tcad = FAST_TCAD;
switch (conf->timings.mode) {
case 5:
case 4:
dqs_mode = 2;
break;
case 3:
dqs_mode = 3;
break;
case 2:
dqs_mode = 4;
break;
case 1:
dqs_mode = 5;
break;
case 0:
default:
dqs_mode = 6;
break;
}
anand->timings = tccs_min | fast_tcad |
DQS_BUFF_SEL_IN(dqs_mode) |
DQS_BUFF_SEL_OUT(dqs_mode);
}
anand->clk = ANFC_XLNX_SDR_DFLT_CORE_CLK;
/*
* Due to a hardware bug in the ZynqMP SoC, SDR timing modes 0-1 work
* with f > 90MHz (default clock is 100MHz) but signals are unstable
* with higher modes. Hence we decrease a little bit the clock rate to
* 80MHz when using modes 2-5 with this SoC.
* 80MHz when using SDR modes 2-5 with this SoC.
*/
if (of_device_is_compatible(np, "xlnx,zynqmp-nand-controller") &&
conf->timings.mode >= 2)
nand_interface_is_sdr(conf) && conf->timings.mode >= 2)
anand->clk = ANFC_XLNX_SDR_HS_CORE_CLK;
return 0;
@ -1007,8 +1169,8 @@ static int anfc_init_hw_ecc_controller(struct arasan_nfc *nfc,
if (!anand->bch)
return -EINVAL;
ecc->read_page = anfc_read_page_hw_ecc;
ecc->write_page = anfc_write_page_hw_ecc;
ecc->read_page = anfc_sel_read_page_hw_ecc;
ecc->write_page = anfc_sel_write_page_hw_ecc;
return 0;
}
@ -1094,37 +1256,43 @@ static int anfc_chip_init(struct arasan_nfc *nfc, struct device_node *np)
struct anand *anand;
struct nand_chip *chip;
struct mtd_info *mtd;
int cs, rb, ret;
int rb, ret, i;
anand = devm_kzalloc(nfc->dev, sizeof(*anand), GFP_KERNEL);
if (!anand)
return -ENOMEM;
/* We do not support multiple CS per chip yet */
if (of_property_count_elems_of_size(np, "reg", sizeof(u32)) != 1) {
/* Chip-select init */
anand->ncs_idx = of_property_count_elems_of_size(np, "reg", sizeof(u32));
if (anand->ncs_idx <= 0 || anand->ncs_idx > nfc->ncs) {
dev_err(nfc->dev, "Invalid reg property\n");
return -EINVAL;
}
ret = of_property_read_u32(np, "reg", &cs);
if (ret)
return ret;
anand->cs_idx = devm_kcalloc(nfc->dev, anand->ncs_idx,
sizeof(*anand->cs_idx), GFP_KERNEL);
if (!anand->cs_idx)
return -ENOMEM;
for (i = 0; i < anand->ncs_idx; i++) {
ret = of_property_read_u32_index(np, "reg", i,
&anand->cs_idx[i]);
if (ret) {
dev_err(nfc->dev, "invalid CS property: %d\n", ret);
return ret;
}
}
/* Ready-busy init */
ret = of_property_read_u32(np, "nand-rb", &rb);
if (ret)
return ret;
if (cs >= ANFC_MAX_CS || rb >= ANFC_MAX_CS) {
dev_err(nfc->dev, "Wrong CS %d or RB %d\n", cs, rb);
if (rb >= ANFC_MAX_CS) {
dev_err(nfc->dev, "Wrong RB %d\n", rb);
return -EINVAL;
}
if (test_and_set_bit(cs, &nfc->assigned_cs)) {
dev_err(nfc->dev, "Already assigned CS %d\n", cs);
return -EINVAL;
}
anand->cs = cs;
anand->rb = rb;
chip = &anand->chip;
@ -1140,7 +1308,7 @@ static int anfc_chip_init(struct arasan_nfc *nfc, struct device_node *np)
return -EINVAL;
}
ret = nand_scan(chip, 1);
ret = nand_scan(chip, anand->ncs_idx);
if (ret) {
dev_err(nfc->dev, "Scan operation failed\n");
return ret;
@ -1178,7 +1346,7 @@ static int anfc_chips_init(struct arasan_nfc *nfc)
int nchips = of_get_child_count(np);
int ret;
if (!nchips || nchips > ANFC_MAX_CS) {
if (!nchips) {
dev_err(nfc->dev, "Incorrect number of NAND chips (%d)\n",
nchips);
return -EINVAL;
@ -1203,6 +1371,47 @@ static void anfc_reset(struct arasan_nfc *nfc)
/* Enable interrupt status */
writel_relaxed(EVENT_MASK, nfc->base + INTR_STS_EN_REG);
nfc->cur_cs = -1;
}
static int anfc_parse_cs(struct arasan_nfc *nfc)
{
int ret;
/* Check the gpio-cs property */
ret = rawnand_dt_parse_gpio_cs(nfc->dev, &nfc->cs_array, &nfc->ncs);
if (ret)
return ret;
/*
* The controller native CS cannot be both disabled at the same time.
* Hence, only one native CS can be used if GPIO CS are needed, so that
* the other is selected when a non-native CS must be asserted (not
* wired physically or configured as GPIO instead of NAND CS). In this
* case, the "not" chosen CS is assigned to nfc->spare_cs and selected
* whenever a GPIO CS must be asserted.
*/
if (nfc->cs_array && nfc->ncs > 2) {
if (!nfc->cs_array[0] && !nfc->cs_array[1]) {
dev_err(nfc->dev,
"Assign a single native CS when using GPIOs\n");
return -EINVAL;
}
if (nfc->cs_array[0])
nfc->spare_cs = 0;
else
nfc->spare_cs = 1;
}
if (!nfc->cs_array) {
nfc->cs_array = anfc_default_cs_array;
nfc->ncs = ANFC_MAX_CS;
return 0;
}
return 0;
}
static int anfc_probe(struct platform_device *pdev)
@ -1241,6 +1450,14 @@ static int anfc_probe(struct platform_device *pdev)
if (ret)
goto disable_controller_clk;
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
if (ret)
goto disable_bus_clk;
ret = anfc_parse_cs(nfc);
if (ret)
goto disable_bus_clk;
ret = anfc_chips_init(nfc);
if (ret)
goto disable_bus_clk;

View File

@ -1246,7 +1246,7 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
nc = to_nand_controller(nand->base.controller);
/* DDR interface not supported. */
if (conf->type != NAND_SDR_IFACE)
if (!nand_interface_is_sdr(conf))
return -ENOTSUPP;
/*
@ -1524,8 +1524,13 @@ 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);
const struct nand_sdr_timings *sdr;
struct atmel_nand_controller *nc;
sdr = nand_get_sdr_timings(conf);
if (IS_ERR(sdr))
return PTR_ERR(sdr);
nc = to_nand_controller(nand->base.controller);
if (csline >= nand->numcs ||

View File

@ -2348,9 +2348,9 @@ cadence_nand_setup_interface(struct nand_chip *chip, int chipnr,
* for tRP and tRH timings. If it is NOT possible to sample data
* with optimal tRP/tRH settings, the parameters will be extended.
* If clk_period is 50ns (the lowest value) this condition is met
* for asynchronous timing modes 1, 2, 3, 4 and 5.
* If clk_period is 20ns the condition is met only
* for asynchronous timing mode 5.
* for SDR timing modes 1, 2, 3, 4 and 5.
* If clk_period is 20ns the condition is met only for SDR timing
* mode 5.
*/
if (sdr->tRC_min <= clk_period &&
sdr->tRP_min <= (clk_period / 2) &&

View File

@ -79,7 +79,7 @@ enum gpmi_type {
struct gpmi_devdata {
enum gpmi_type type;
int bch_max_ecc_strength;
int max_chain_delay; /* See the async EDO mode */
int max_chain_delay; /* See the SDR EDO mode */
const char * const *clks;
const int clks_count;
};

View File

@ -761,10 +761,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
host->mmio = devm_ioremap_resource(dev, res);
if (IS_ERR(host->mmio)) {
dev_err(dev, "devm_ioremap_resource[1] fail\n");
if (IS_ERR(host->mmio))
return PTR_ERR(host->mmio);
}
mtd->name = "hisi_nand";
mtd->dev.parent = &pdev->dev;

View File

@ -90,9 +90,14 @@ void onfi_fill_interface_config(struct nand_chip *chip,
unsigned int timing_mode);
unsigned int
onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings);
unsigned int
onfi_find_closest_nvddr_mode(const struct nand_nvddr_timings *spec_timings);
int nand_choose_best_sdr_timings(struct nand_chip *chip,
struct nand_interface_config *iface,
struct nand_sdr_timings *spec_timings);
int nand_choose_best_nvddr_timings(struct nand_chip *chip,
struct nand_interface_config *iface,
struct nand_nvddr_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);

View File

@ -451,7 +451,7 @@ struct marvell_nfc_timings {
};
/**
* Derives a duration in numbers of clock cycles.
* TO_CYCLES() - Derives a duration in numbers of clock cycles.
*
* @ps: Duration in pico-seconds
* @period_ns: Clock period in nano-seconds
@ -3030,8 +3030,10 @@ static int __maybe_unused marvell_nfc_resume(struct device *dev)
return ret;
ret = clk_prepare_enable(nfc->reg_clk);
if (ret < 0)
if (ret < 0) {
clk_disable_unprepare(nfc->core_clk);
return ret;
}
/*
* Reset nfc->selected_chip so the next command will cause the timing

View File

@ -515,10 +515,8 @@ static int mtk_ecc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ecc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(ecc->regs)) {
dev_err(dev, "failed to map regs: %ld\n", PTR_ERR(ecc->regs));
if (IS_ERR(ecc->regs))
return PTR_ERR(ecc->regs);
}
ecc->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ecc->clk)) {

View File

@ -42,6 +42,7 @@
#include <linux/io.h>
#include <linux/mtd/partitions.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include "internals.h"
@ -647,7 +648,7 @@ static int nand_block_checkbad(struct nand_chip *chip, loff_t ofs, int allowbbt)
*/
int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
{
const struct nand_sdr_timings *timings;
const struct nand_interface_config *conf;
u8 status = 0;
int ret;
@ -655,8 +656,8 @@ 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(nand_get_interface_config(chip));
ndelay(PSEC_TO_NSEC(timings->tWB_max));
conf = nand_get_interface_config(chip);
ndelay(NAND_COMMON_TIMING_NS(conf, tWB_max));
ret = nand_status_op(chip, NULL);
if (ret)
@ -832,7 +833,7 @@ static int nand_reset_interface(struct nand_chip *chip, int chipnr)
static int nand_setup_interface(struct nand_chip *chip, int chipnr)
{
const struct nand_controller_ops *ops = chip->controller->ops;
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { };
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { }, request;
int ret;
if (!nand_controller_can_setup_interface(chip))
@ -848,7 +849,12 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr)
if (!chip->best_interface_config)
return 0;
tmode_param[0] = chip->best_interface_config->timings.mode;
request = chip->best_interface_config->timings.mode;
if (nand_interface_is_sdr(chip->best_interface_config))
request |= ONFI_DATA_INTERFACE_SDR;
else
request |= ONFI_DATA_INTERFACE_NVDDR;
tmode_param[0] = request;
/* Change the mode on the chip side (if supported by the NAND chip) */
if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
@ -877,9 +883,13 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr)
if (ret)
goto err_reset_chip;
if (tmode_param[0] != chip->best_interface_config->timings.mode) {
pr_warn("timing mode %d not acknowledged by the NAND chip\n",
if (request != tmode_param[0]) {
pr_warn("%s timing mode %d not acknowledged by the NAND chip\n",
nand_interface_is_nvddr(chip->best_interface_config) ? "NV-DDR" : "SDR",
chip->best_interface_config->timings.mode);
pr_debug("NAND chip would work in %s timing mode %d\n",
tmode_param[0] & ONFI_DATA_INTERFACE_NVDDR ? "NV-DDR" : "SDR",
(unsigned int)ONFI_TIMING_MODE_PARAM(tmode_param[0]));
goto err_reset_chip;
}
@ -935,7 +945,7 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip,
/* Fallback to slower modes */
best_mode = iface->timings.mode;
} else if (chip->parameters.onfi) {
best_mode = fls(chip->parameters.onfi->async_timing_mode) - 1;
best_mode = fls(chip->parameters.onfi->sdr_timing_modes) - 1;
}
for (mode = best_mode; mode >= 0; mode--) {
@ -943,13 +953,87 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip,
ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
iface);
if (!ret)
if (!ret) {
chip->best_interface_config = iface;
break;
}
}
chip->best_interface_config = iface;
return ret;
}
return 0;
/**
* nand_choose_best_nvddr_timings - Pick up the best NVDDR 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_nvddr_timings(struct nand_chip *chip,
struct nand_interface_config *iface,
struct nand_nvddr_timings *spec_timings)
{
const struct nand_controller_ops *ops = chip->controller->ops;
int best_mode = 0, mode, ret;
iface->type = NAND_NVDDR_IFACE;
if (spec_timings) {
iface->timings.nvddr = *spec_timings;
iface->timings.mode = onfi_find_closest_nvddr_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->nvddr_timing_modes) - 1;
}
for (mode = best_mode; mode >= 0; mode--) {
onfi_fill_interface_config(chip, iface, NAND_NVDDR_IFACE, mode);
ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
iface);
if (!ret) {
chip->best_interface_config = iface;
break;
}
}
return ret;
}
/**
* nand_choose_best_timings - Pick up the best NVDDR or SDR timings that both
* NAND controller and the NAND chip support
* @chip: the NAND chip
* @iface: the interface configuration (can eventually be updated)
*
* If specific timings are provided, use them. Otherwise, retrieve supported
* timing modes from ONFI information.
*/
static int nand_choose_best_timings(struct nand_chip *chip,
struct nand_interface_config *iface)
{
int ret;
/* Try the fastest timings: NV-DDR */
ret = nand_choose_best_nvddr_timings(chip, iface, NULL);
if (!ret)
return 0;
/* Fallback to SDR timings otherwise */
return nand_choose_best_sdr_timings(chip, iface, NULL);
}
/**
@ -980,7 +1064,7 @@ static int nand_choose_interface_config(struct nand_chip *chip)
if (chip->ops.choose_interface_config)
ret = chip->ops.choose_interface_config(chip, iface);
else
ret = nand_choose_best_sdr_timings(chip, iface, NULL);
ret = nand_choose_best_timings(chip, iface);
if (ret)
kfree(iface);
@ -1046,15 +1130,15 @@ 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)
{
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
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),
NAND_OP_ADDR(3, addrs, PSEC_TO_NSEC(sdr->tWB_max)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
PSEC_TO_NSEC(sdr->tRR_min)),
NAND_OP_ADDR(3, addrs, NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@ -1089,15 +1173,15 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf,
unsigned int len)
{
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
nand_get_interface_config(chip);
u8 addrs[5];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
NAND_OP_ADDR(4, addrs, 0),
NAND_OP_CMD(NAND_CMD_READSTART, PSEC_TO_NSEC(sdr->tWB_max)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
PSEC_TO_NSEC(sdr->tRR_min)),
NAND_OP_CMD(NAND_CMD_READSTART, NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@ -1186,13 +1270,14 @@ int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
return -EINVAL;
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
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)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
PSEC_TO_NSEC(sdr->tRR_min)),
NAND_OP_ADDR(1, &page,
NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_8BIT_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@ -1241,14 +1326,14 @@ int nand_change_read_column_op(struct nand_chip *chip,
return -ENOTSUPP;
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
nand_get_interface_config(chip);
u8 addrs[2] = {};
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RNDOUT, 0),
NAND_OP_ADDR(2, addrs, 0),
NAND_OP_CMD(NAND_CMD_RNDOUTSTART,
PSEC_TO_NSEC(sdr->tCCS_min)),
NAND_COMMON_TIMING_NS(conf, tCCS_min)),
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@ -1316,8 +1401,8 @@ 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)
{
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
nand_get_interface_config(chip);
struct mtd_info *mtd = nand_to_mtd(chip);
u8 addrs[5] = {};
struct nand_op_instr instrs[] = {
@ -1328,10 +1413,11 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
*/
NAND_OP_CMD(NAND_CMD_READ0, 0),
NAND_OP_CMD(NAND_CMD_SEQIN, 0),
NAND_OP_ADDR(0, addrs, PSEC_TO_NSEC(sdr->tADL_min)),
NAND_OP_ADDR(0, addrs, NAND_COMMON_TIMING_NS(conf, tADL_min)),
NAND_OP_DATA_OUT(len, buf, 0),
NAND_OP_CMD(NAND_CMD_PAGEPROG, PSEC_TO_NSEC(sdr->tWB_max)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
NAND_OP_CMD(NAND_CMD_PAGEPROG,
NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tPROG_max), 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page);
@ -1430,12 +1516,13 @@ int nand_prog_page_end_op(struct nand_chip *chip)
u8 status;
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
nand_get_interface_config(chip);
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_PAGEPROG,
PSEC_TO_NSEC(sdr->tWB_max)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tPROG_max),
0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@ -1548,12 +1635,12 @@ int nand_change_write_column_op(struct nand_chip *chip,
return -ENOTSUPP;
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
nand_get_interface_config(chip);
u8 addrs[2];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RNDIN, 0),
NAND_OP_ADDR(2, addrs, PSEC_TO_NSEC(sdr->tCCS_min)),
NAND_OP_ADDR(2, addrs, NAND_COMMON_TIMING_NS(conf, tCCS_min)),
NAND_OP_DATA_OUT(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@ -1597,26 +1684,46 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
unsigned int len)
{
unsigned int i;
u8 *id = buf;
u8 *id = buf, *ddrbuf = NULL;
if (len && !buf)
return -EINVAL;
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
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)),
NAND_OP_ADDR(1, &addr,
NAND_COMMON_TIMING_NS(conf, tADL_min)),
NAND_OP_8BIT_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
int ret;
/* READ_ID data bytes are received twice in NV-DDR mode */
if (len && nand_interface_is_nvddr(conf)) {
ddrbuf = kzalloc(len * 2, GFP_KERNEL);
if (!ddrbuf)
return -ENOMEM;
instrs[2].ctx.data.len *= 2;
instrs[2].ctx.data.buf.in = ddrbuf;
}
/* Drop the DATA_IN instruction if len is set to 0. */
if (!len)
op.ninstrs--;
return nand_exec_op(chip, &op);
ret = nand_exec_op(chip, &op);
if (!ret && len && nand_interface_is_nvddr(conf)) {
for (i = 0; i < len; i++)
id[i] = ddrbuf[i * 2];
}
kfree(ddrbuf);
return ret;
}
chip->legacy.cmdfunc(chip, NAND_CMD_READID, addr, -1);
@ -1642,19 +1749,31 @@ EXPORT_SYMBOL_GPL(nand_readid_op);
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(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
nand_get_interface_config(chip);
u8 ddrstatus[2];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_STATUS,
PSEC_TO_NSEC(sdr->tADL_min)),
NAND_COMMON_TIMING_NS(conf, tADL_min)),
NAND_OP_8BIT_DATA_IN(1, status, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
int ret;
/* The status data byte will be received twice in NV-DDR mode */
if (status && nand_interface_is_nvddr(conf)) {
instrs[1].ctx.data.len *= 2;
instrs[1].ctx.data.buf.in = ddrstatus;
}
if (!status)
op.ninstrs--;
return nand_exec_op(chip, &op);
ret = nand_exec_op(chip, &op);
if (!ret && status && nand_interface_is_nvddr(conf))
*status = ddrstatus[0];
return ret;
}
chip->legacy.cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
@ -1711,15 +1830,16 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
u8 status;
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
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),
NAND_OP_ADDR(2, addrs, 0),
NAND_OP_CMD(NAND_CMD_ERASE2,
PSEC_TO_MSEC(sdr->tWB_max)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tBERS_max), 0),
NAND_COMMON_TIMING_MS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tBERS_max),
0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@ -1770,14 +1890,17 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
int i, ret;
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
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)),
NAND_OP_ADDR(1, &feature, NAND_COMMON_TIMING_NS(conf,
tADL_min)),
NAND_OP_8BIT_DATA_OUT(ONFI_SUBFEATURE_PARAM_LEN, data,
PSEC_TO_NSEC(sdr->tWB_max)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max), 0),
NAND_COMMON_TIMING_NS(conf,
tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tFEAT_max),
0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@ -1813,23 +1936,37 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
static int nand_get_features_op(struct nand_chip *chip, u8 feature,
void *data)
{
u8 *params = data;
u8 *params = data, ddrbuf[ONFI_SUBFEATURE_PARAM_LEN * 2];
int i;
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
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)),
NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max),
PSEC_TO_NSEC(sdr->tRR_min)),
NAND_OP_ADDR(1, &feature,
NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tFEAT_max),
NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_8BIT_DATA_IN(ONFI_SUBFEATURE_PARAM_LEN,
data, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
int ret;
return nand_exec_op(chip, &op);
/* GET_FEATURE data bytes are received twice in NV-DDR mode */
if (nand_interface_is_nvddr(conf)) {
instrs[3].ctx.data.len *= 2;
instrs[3].ctx.data.buf.in = ddrbuf;
}
ret = nand_exec_op(chip, &op);
if (nand_interface_is_nvddr(conf)) {
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; i++)
params[i] = ddrbuf[i * 2];
}
return ret;
}
chip->legacy.cmdfunc(chip, NAND_CMD_GET_FEATURES, feature, -1);
@ -1874,11 +2011,13 @@ static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms,
int nand_reset_op(struct nand_chip *chip)
{
if (nand_has_exec_op(chip)) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(nand_get_interface_config(chip));
const struct nand_interface_config *conf =
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),
NAND_OP_CMD(NAND_CMD_RESET,
NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tRST_max),
0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@ -1913,17 +2052,50 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
return -EINVAL;
if (nand_has_exec_op(chip)) {
const struct nand_interface_config *conf =
nand_get_interface_config(chip);
struct nand_op_instr instrs[] = {
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
u8 *ddrbuf = NULL;
int ret, i;
instrs[0].ctx.data.force_8bit = force_8bit;
if (check_only)
return nand_check_op(chip, &op);
/*
* Parameter payloads (ID, status, features, etc) do not go
* through the same pipeline as regular data, hence the
* force_8bit flag must be set and this also indicates that in
* case NV-DDR timings are being used the data will be received
* twice.
*/
if (force_8bit && nand_interface_is_nvddr(conf)) {
ddrbuf = kzalloc(len * 2, GFP_KERNEL);
if (!ddrbuf)
return -ENOMEM;
return nand_exec_op(chip, &op);
instrs[0].ctx.data.len *= 2;
instrs[0].ctx.data.buf.in = ddrbuf;
}
if (check_only) {
ret = nand_check_op(chip, &op);
kfree(ddrbuf);
return ret;
}
ret = nand_exec_op(chip, &op);
if (!ret && force_8bit && nand_interface_is_nvddr(conf)) {
u8 *dst = buf;
for (i = 0; i < len; i++)
dst[i] = ddrbuf[i * 2];
}
kfree(ddrbuf);
return ret;
}
if (check_only)
@ -3136,13 +3308,13 @@ static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
static void nand_wait_readrdy(struct nand_chip *chip)
{
const struct nand_sdr_timings *sdr;
const struct nand_interface_config *conf;
if (!(chip->options & NAND_NEED_READRDY))
return;
sdr = nand_get_sdr_timings(nand_get_interface_config(chip));
WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0));
conf = nand_get_interface_config(chip);
WARN_ON(nand_wait_rdy_op(chip, NAND_COMMON_TIMING_MS(conf, tR_max), 0));
}
/**
@ -5078,6 +5250,44 @@ static int of_get_nand_secure_regions(struct nand_chip *chip)
return 0;
}
/**
* rawnand_dt_parse_gpio_cs - Parse the gpio-cs property of a controller
* @dev: Device that will be parsed. Also used for managed allocations.
* @cs_array: Array of GPIO desc pointers allocated on success
* @ncs_array: Number of entries in @cs_array updated on success.
* @return 0 on success, an error otherwise.
*/
int rawnand_dt_parse_gpio_cs(struct device *dev, struct gpio_desc ***cs_array,
unsigned int *ncs_array)
{
struct device_node *np = dev->of_node;
struct gpio_desc **descs;
int ndescs, i;
ndescs = of_gpio_named_count(np, "cs-gpios");
if (ndescs < 0) {
dev_dbg(dev, "No valid cs-gpios property\n");
return 0;
}
descs = devm_kcalloc(dev, ndescs, sizeof(*descs), GFP_KERNEL);
if (!descs)
return -ENOMEM;
for (i = 0; i < ndescs; i++) {
descs[i] = gpiod_get_index_optional(dev, "cs", i,
GPIOD_OUT_HIGH);
if (IS_ERR(descs[i]))
return PTR_ERR(descs[i]);
}
*ncs_array = ndescs;
*cs_array = descs;
return 0;
}
EXPORT_SYMBOL(rawnand_dt_parse_gpio_cs);
static int rawnand_dt_init(struct nand_chip *chip)
{
struct nand_device *nand = mtd_to_nanddev(nand_to_mtd(chip));

View File

@ -369,7 +369,7 @@ 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_controller_can_setup_interface(chip))
if (!IS_ERR(sdr) && nand_controller_can_setup_interface(chip))
ndelay(sdr->tCCS_min / 1000);
else
ndelay(500);

View File

@ -315,7 +315,10 @@ int nand_onfi_detect(struct nand_chip *chip)
onfi->tBERS = le16_to_cpu(p->t_bers);
onfi->tR = le16_to_cpu(p->t_r);
onfi->tCCS = le16_to_cpu(p->t_ccs);
onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
onfi->fast_tCAD = le16_to_cpu(p->nvddr_nvddr2_features) & BIT(0);
onfi->sdr_timing_modes = le16_to_cpu(p->sdr_timing_modes);
if (le16_to_cpu(p->features) & ONFI_FEATURE_NV_DDR)
onfi->nvddr_timing_modes = le16_to_cpu(p->nvddr_timing_modes);
onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
chip->parameters.onfi = onfi;

View File

@ -292,6 +292,261 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
},
};
static const struct nand_interface_config onfi_nvddr_timings[] = {
/* Mode 0 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 0,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 10000,
.tCALH_min = 10000,
.tCALS_min = 10000,
.tCAS_min = 10000,
.tCEH_min = 20000,
.tCH_min = 10000,
.tCK_min = 50000,
.tCS_min = 35000,
.tDH_min = 5000,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 5000,
.tDS_min = 5000,
.tDSC_min = 50000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 6000,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 1 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 1,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 5000,
.tCALH_min = 5000,
.tCALS_min = 5000,
.tCAS_min = 5000,
.tCEH_min = 20000,
.tCH_min = 5000,
.tCK_min = 30000,
.tCS_min = 25000,
.tDH_min = 2500,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 2500,
.tDS_min = 3000,
.tDSC_min = 30000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 3000,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 2 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 2,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 4000,
.tCALH_min = 4000,
.tCALS_min = 4000,
.tCAS_min = 4000,
.tCEH_min = 20000,
.tCH_min = 4000,
.tCK_min = 20000,
.tCS_min = 15000,
.tDH_min = 1700,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 1700,
.tDS_min = 2000,
.tDSC_min = 20000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 2000,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 3 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 3,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 3000,
.tCALH_min = 3000,
.tCALS_min = 3000,
.tCAS_min = 3000,
.tCEH_min = 20000,
.tCH_min = 3000,
.tCK_min = 15000,
.tCS_min = 15000,
.tDH_min = 1300,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 1300,
.tDS_min = 1500,
.tDSC_min = 15000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 1500,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 4 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 4,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 2500,
.tCALH_min = 2500,
.tCALS_min = 2500,
.tCAS_min = 2500,
.tCEH_min = 20000,
.tCH_min = 2500,
.tCK_min = 12000,
.tCS_min = 15000,
.tDH_min = 1100,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 1000,
.tDS_min = 1100,
.tDSC_min = 12000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 1200,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 5 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 5,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 2000,
.tCALH_min = 2000,
.tCALS_min = 2000,
.tCAS_min = 2000,
.tCEH_min = 20000,
.tCH_min = 2000,
.tCK_min = 10000,
.tCS_min = 15000,
.tDH_min = 900,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 850,
.tDS_min = 900,
.tDSC_min = 10000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 1000,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
};
/* All NAND chips share the same reset data interface: SDR mode 0 */
const struct nand_interface_config *nand_get_reset_interface_config(void)
{
@ -346,23 +601,60 @@ onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings)
}
/**
* onfi_fill_interface_config - Initialize an interface config from a given
* ONFI mode
* onfi_find_closest_nvddr_mode - Derive the closest ONFI NVDDR timing mode
* given a set of timings
* @spec_timings: the timings to challenge
*/
unsigned int
onfi_find_closest_nvddr_mode(const struct nand_nvddr_timings *spec_timings)
{
const struct nand_nvddr_timings *onfi_timings;
int mode;
for (mode = ARRAY_SIZE(onfi_nvddr_timings) - 1; mode > 0; mode--) {
onfi_timings = &onfi_nvddr_timings[mode].timings.nvddr;
if (spec_timings->tCCS_min <= onfi_timings->tCCS_min &&
spec_timings->tAC_min <= onfi_timings->tAC_min &&
spec_timings->tADL_min <= onfi_timings->tADL_min &&
spec_timings->tCAD_min <= onfi_timings->tCAD_min &&
spec_timings->tCAH_min <= onfi_timings->tCAH_min &&
spec_timings->tCALH_min <= onfi_timings->tCALH_min &&
spec_timings->tCALS_min <= onfi_timings->tCALS_min &&
spec_timings->tCAS_min <= onfi_timings->tCAS_min &&
spec_timings->tCEH_min <= onfi_timings->tCEH_min &&
spec_timings->tCH_min <= onfi_timings->tCH_min &&
spec_timings->tCK_min <= onfi_timings->tCK_min &&
spec_timings->tCS_min <= onfi_timings->tCS_min &&
spec_timings->tDH_min <= onfi_timings->tDH_min &&
spec_timings->tDQSCK_min <= onfi_timings->tDQSCK_min &&
spec_timings->tDQSD_min <= onfi_timings->tDQSD_min &&
spec_timings->tDS_min <= onfi_timings->tDS_min &&
spec_timings->tDSC_min <= onfi_timings->tDSC_min &&
spec_timings->tRHW_min <= onfi_timings->tRHW_min &&
spec_timings->tRR_min <= onfi_timings->tRR_min &&
spec_timings->tWHR_min <= onfi_timings->tWHR_min &&
spec_timings->tWRCK_min <= onfi_timings->tWRCK_min &&
spec_timings->tWW_min <= onfi_timings->tWW_min)
return mode;
}
return 0;
}
/*
* onfi_fill_sdr_interface_config - Initialize a SDR 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)
static void onfi_fill_sdr_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface,
unsigned int timing_mode)
{
struct onfi_params *onfi = chip->parameters.onfi;
if (WARN_ON(type != NAND_SDR_IFACE))
return;
if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_sdr_timings)))
return;
@ -385,3 +677,61 @@ void onfi_fill_interface_config(struct nand_chip *chip,
timings->tCCS_min = 1000UL * onfi->tCCS;
}
}
/**
* onfi_fill_nvddr_interface_config - Initialize a NVDDR interface config from a
* given ONFI mode
* @chip: The NAND chip
* @iface: The interface configuration to fill
* @timing_mode: The ONFI timing mode
*/
static void onfi_fill_nvddr_interface_config(struct nand_chip *chip,
struct nand_interface_config *iface,
unsigned int timing_mode)
{
struct onfi_params *onfi = chip->parameters.onfi;
if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_nvddr_timings)))
return;
*iface = onfi_nvddr_timings[timing_mode];
/*
* Initialize timings that cannot be deduced from timing mode:
* tPROG, tBERS, tR, tCCS and tCAD.
* These information are part of the ONFI parameter page.
*/
if (onfi) {
struct nand_nvddr_timings *timings = &iface->timings.nvddr;
/* microseconds -> picoseconds */
timings->tPROG_max = 1000000ULL * onfi->tPROG;
timings->tBERS_max = 1000000ULL * onfi->tBERS;
timings->tR_max = 1000000ULL * onfi->tR;
/* nanoseconds -> picoseconds */
timings->tCCS_min = 1000UL * onfi->tCCS;
if (onfi->fast_tCAD)
timings->tCAD_min = 25000;
}
}
/**
* 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)
{
if (type == NAND_SDR_IFACE)
return onfi_fill_sdr_interface_config(chip, iface, timing_mode);
else
return onfi_fill_nvddr_interface_config(chip, iface, timing_mode);
}

View File

@ -131,7 +131,7 @@
#define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */
#define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */
#define BADBLOCK_MARKER_LENGTH 2
#define BBM_LEN 2
static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78,
@ -171,6 +171,10 @@ struct omap_nand_info {
struct device *elm_dev;
/* NAND ready gpio */
struct gpio_desc *ready_gpiod;
unsigned int neccpg;
unsigned int nsteps_per_eccpg;
unsigned int eccpg_size;
unsigned int eccpg_bytes;
};
static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
@ -1355,7 +1359,7 @@ static int omap_elm_correct_data(struct nand_chip *chip, u_char *data,
{
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
struct nand_ecc_ctrl *ecc = &info->nand.ecc;
int eccsteps = info->nand.ecc.steps;
int eccsteps = info->nsteps_per_eccpg;
int i , j, stat = 0;
int eccflag, actual_eccbytes;
struct elm_errorvec err_vec[ERROR_VECTOR_MAX];
@ -1525,25 +1529,38 @@ static int omap_write_page_bch(struct nand_chip *chip, const uint8_t *buf,
int oob_required, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
struct omap_nand_info *info = mtd_to_omap(mtd);
uint8_t *ecc_calc = chip->ecc.calc_buf;
unsigned int eccpg;
int ret;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
/* Enable GPMC ecc engine */
chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* Write data */
chip->legacy.write_buf(chip, buf, mtd->writesize);
/* Update ecc vector from GPMC result registers */
omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
chip->ecc.total);
ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
if (ret)
return ret;
for (eccpg = 0; eccpg < info->neccpg; eccpg++) {
/* Enable GPMC ecc engine */
chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* Write data */
chip->legacy.write_buf(chip, buf + (eccpg * info->eccpg_size),
info->eccpg_size);
/* Update ecc vector from GPMC result registers */
ret = omap_calculate_ecc_bch_multi(mtd,
buf + (eccpg * info->eccpg_size),
ecc_calc);
if (ret)
return ret;
ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc,
chip->oob_poi,
eccpg * info->eccpg_bytes,
info->eccpg_bytes);
if (ret)
return ret;
}
/* Write ecc vector to OOB area */
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
@ -1566,12 +1583,13 @@ static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
int oob_required, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
u8 *ecc_calc = chip->ecc.calc_buf;
int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes;
int ecc_steps = chip->ecc.steps;
u32 start_step = offset / ecc_size;
u32 end_step = (offset + data_len - 1) / ecc_size;
unsigned int eccpg;
int step, ret = 0;
/*
@ -1580,36 +1598,48 @@ static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
* ECC is calculated for all subpages but we choose
* only what we want.
*/
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
/* Enable GPMC ECC engine */
chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* Write data */
chip->legacy.write_buf(chip, buf, mtd->writesize);
for (step = 0; step < ecc_steps; step++) {
/* mask ECC of un-touched subpages by padding 0xFF */
if (step < start_step || step > end_step)
memset(ecc_calc, 0xff, ecc_bytes);
else
ret = _omap_calculate_ecc_bch(mtd, buf, ecc_calc, step);
if (ret)
return ret;
buf += ecc_size;
ecc_calc += ecc_bytes;
}
/* copy calculated ECC for whole page to chip->buffer->oob */
/* this include masked-value(0xFF) for unwritten subpages */
ecc_calc = chip->ecc.calc_buf;
ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
chip->ecc.total);
ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
if (ret)
return ret;
for (eccpg = 0; eccpg < info->neccpg; eccpg++) {
/* Enable GPMC ECC engine */
chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* Write data */
chip->legacy.write_buf(chip, buf + (eccpg * info->eccpg_size),
info->eccpg_size);
for (step = 0; step < info->nsteps_per_eccpg; step++) {
unsigned int base_step = eccpg * info->nsteps_per_eccpg;
const u8 *bufoffs = buf + (eccpg * info->eccpg_size);
/* Mask ECC of un-touched subpages with 0xFFs */
if ((step + base_step) < start_step ||
(step + base_step) > end_step)
memset(ecc_calc + (step * ecc_bytes), 0xff,
ecc_bytes);
else
ret = _omap_calculate_ecc_bch(mtd,
bufoffs + (step * ecc_size),
ecc_calc + (step * ecc_bytes),
step);
if (ret)
return ret;
}
/*
* Copy the calculated ECC for the whole page including the
* masked values (0xFF) corresponding to unwritten subpages.
*/
ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi,
eccpg * info->eccpg_bytes,
info->eccpg_bytes);
if (ret)
return ret;
}
/* write OOB buffer to NAND device */
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
@ -1634,40 +1664,60 @@ static int omap_read_page_bch(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
uint8_t *ecc_calc = chip->ecc.calc_buf;
uint8_t *ecc_code = chip->ecc.code_buf;
unsigned int max_bitflips = 0, eccpg;
int stat, ret;
unsigned int max_bitflips = 0;
nand_read_page_op(chip, page, 0, NULL, 0);
/* Enable GPMC ecc engine */
chip->ecc.hwctl(chip, NAND_ECC_READ);
/* Read data */
chip->legacy.read_buf(chip, buf, mtd->writesize);
/* Read oob bytes */
nand_change_read_column_op(chip,
mtd->writesize + BADBLOCK_MARKER_LENGTH,
chip->oob_poi + BADBLOCK_MARKER_LENGTH,
chip->ecc.total, false);
/* Calculate ecc bytes */
omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total);
ret = nand_read_page_op(chip, page, 0, NULL, 0);
if (ret)
return ret;
stat = chip->ecc.correct(chip, buf, ecc_code, ecc_calc);
for (eccpg = 0; eccpg < info->neccpg; eccpg++) {
/* Enable GPMC ecc engine */
chip->ecc.hwctl(chip, NAND_ECC_READ);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
/* Read data */
ret = nand_change_read_column_op(chip, eccpg * info->eccpg_size,
buf + (eccpg * info->eccpg_size),
info->eccpg_size, false);
if (ret)
return ret;
/* Read oob bytes */
ret = nand_change_read_column_op(chip,
mtd->writesize + BBM_LEN +
(eccpg * info->eccpg_bytes),
chip->oob_poi + BBM_LEN +
(eccpg * info->eccpg_bytes),
info->eccpg_bytes, false);
if (ret)
return ret;
/* Calculate ecc bytes */
ret = omap_calculate_ecc_bch_multi(mtd,
buf + (eccpg * info->eccpg_size),
ecc_calc);
if (ret)
return ret;
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code,
chip->oob_poi,
eccpg * info->eccpg_bytes,
info->eccpg_bytes);
if (ret)
return ret;
stat = chip->ecc.correct(chip,
buf + (eccpg * info->eccpg_size),
ecc_code, ecc_calc);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return max_bitflips;
@ -1820,7 +1870,7 @@ static int omap_ooblayout_ecc(struct mtd_info *mtd, int section,
{
struct omap_nand_info *info = mtd_to_omap(mtd);
struct nand_chip *chip = &info->nand;
int off = BADBLOCK_MARKER_LENGTH;
int off = BBM_LEN;
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
!(chip->options & NAND_BUSWIDTH_16))
@ -1840,7 +1890,7 @@ static int omap_ooblayout_free(struct mtd_info *mtd, int section,
{
struct omap_nand_info *info = mtd_to_omap(mtd);
struct nand_chip *chip = &info->nand;
int off = BADBLOCK_MARKER_LENGTH;
int off = BBM_LEN;
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
!(chip->options & NAND_BUSWIDTH_16))
@ -1870,7 +1920,7 @@ static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
struct nand_device *nand = mtd_to_nanddev(mtd);
unsigned int nsteps = nanddev_get_ecc_nsteps(nand);
unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand);
int off = BADBLOCK_MARKER_LENGTH;
int off = BBM_LEN;
if (section >= nsteps)
return -ERANGE;
@ -1891,7 +1941,7 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
struct nand_device *nand = mtd_to_nanddev(mtd);
unsigned int nsteps = nanddev_get_ecc_nsteps(nand);
unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand);
int off = BADBLOCK_MARKER_LENGTH;
int off = BBM_LEN;
if (section)
return -ERANGE;
@ -1920,7 +1970,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
struct device *dev = &info->pdev->dev;
int min_oobbytes = BADBLOCK_MARKER_LENGTH;
int min_oobbytes = BBM_LEN;
int elm_bch_strength = -1;
int oobbytes_per_step;
dma_cap_mask_t mask;
int err;
@ -2074,12 +2125,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
err = elm_config(info->elm_dev, BCH4_ECC,
mtd->writesize / chip->ecc.size,
chip->ecc.size, chip->ecc.bytes);
if (err < 0)
return err;
elm_bch_strength = BCH4_ECC;
break;
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
@ -2116,13 +2162,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
err = elm_config(info->elm_dev, BCH8_ECC,
mtd->writesize / chip->ecc.size,
chip->ecc.size, chip->ecc.bytes);
if (err < 0)
return err;
elm_bch_strength = BCH8_ECC;
break;
case OMAP_ECC_BCH16_CODE_HW:
@ -2138,19 +2178,32 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
err = elm_config(info->elm_dev, BCH16_ECC,
mtd->writesize / chip->ecc.size,
chip->ecc.size, chip->ecc.bytes);
if (err < 0)
return err;
elm_bch_strength = BCH16_ECC;
break;
default:
dev_err(dev, "Invalid or unsupported ECC scheme\n");
return -EINVAL;
}
if (elm_bch_strength >= 0) {
chip->ecc.steps = mtd->writesize / chip->ecc.size;
info->neccpg = chip->ecc.steps / ERROR_VECTOR_MAX;
if (info->neccpg) {
info->nsteps_per_eccpg = ERROR_VECTOR_MAX;
} else {
info->neccpg = 1;
info->nsteps_per_eccpg = chip->ecc.steps;
}
info->eccpg_size = info->nsteps_per_eccpg * chip->ecc.size;
info->eccpg_bytes = info->nsteps_per_eccpg * chip->ecc.bytes;
err = elm_config(info->elm_dev, elm_bch_strength,
info->nsteps_per_eccpg, chip->ecc.size,
chip->ecc.bytes);
if (err < 0)
return err;
}
/* Check if NAND device's OOB is enough to store ECC signatures */
min_oobbytes += (oobbytes_per_step *
(mtd->writesize / chip->ecc.size));

View File

@ -116,7 +116,7 @@ int elm_config(struct device *dev, enum bch_ecc bch_type,
return -EINVAL;
}
/* ELM support 8 error syndrome process */
if (ecc_steps > ERROR_VECTOR_MAX) {
if (ecc_steps > ERROR_VECTOR_MAX && ecc_steps % ERROR_VECTOR_MAX) {
dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps);
return -EINVAL;
}

File diff suppressed because it is too large Load Diff

View File

@ -734,6 +734,7 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i
{
struct nand_chip *chip = &host->chip;
u32 cmd, cfg0, cfg1, ecc_bch_cfg;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
if (read) {
if (host->use_ecc)
@ -762,7 +763,8 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i
nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0);
nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1);
nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
if (!nandc->props->qpic_v2)
nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
nandc_set_reg(chip, NAND_EXEC_CMD, 1);
@ -1133,7 +1135,8 @@ static void config_nand_page_read(struct nand_chip *chip)
write_reg_dma(nandc, NAND_ADDR0, 2, 0);
write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
if (!nandc->props->qpic_v2)
write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
@ -1191,8 +1194,9 @@ static void config_nand_page_write(struct nand_chip *chip)
write_reg_dma(nandc, NAND_ADDR0, 2, 0);
write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
NAND_BAM_NEXT_SGL);
if (!nandc->props->qpic_v2)
write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
NAND_BAM_NEXT_SGL);
}
/*
@ -1248,7 +1252,8 @@ static int nandc_param(struct qcom_nand_host *host)
| 2 << WR_RD_BSY_GAP
| 0 << WIDE_FLASH
| 1 << DEV0_CFG1_ECC_DISABLE);
nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
if (!nandc->props->qpic_v2)
nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
/* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
if (!nandc->props->qpic_v2) {
@ -1850,8 +1855,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
* ERASED_CW bits are set.
*/
if (host->bch_enabled) {
erased = (erased_cw & ERASED_CW) == ERASED_CW ?
true : false;
erased = (erased_cw & ERASED_CW) == ERASED_CW;
/*
* For RS ECC, HW reports the erased CW by placing
* special characters at certain offsets in the buffer.
@ -2689,7 +2693,8 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
| ecc_mode << ECC_MODE
| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
host->ecc_buf_cfg = 0x203 << NUM_STEPS;
if (!nandc->props->qpic_v2)
host->ecc_buf_cfg = 0x203 << NUM_STEPS;
host->clrflashstatus = FS_READY_BSY_N;
host->clrreadstatus = 0xc0;
@ -2882,7 +2887,7 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
return 0;
}
static const char * const probes[] = { "qcomsmem", NULL };
static const char * const probes[] = { "cmdlinepart", "ofpart", "qcomsmem", NULL };
static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
struct qcom_nand_host *host,

View File

@ -583,8 +583,8 @@ static void r852_update_card_detect(struct r852_device *dev)
r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg);
}
static ssize_t r852_media_type_show(struct device *sys_dev,
struct device_attribute *attr, char *buf)
static ssize_t media_type_show(struct device *sys_dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev);
struct r852_device *dev = r852_get_dev(mtd);
@ -593,8 +593,7 @@ static ssize_t r852_media_type_show(struct device *sys_dev,
strcpy(buf, data);
return strlen(data);
}
static DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
static DEVICE_ATTR_RO(media_type);
/* Detect properties of card in slot */

View File

@ -138,20 +138,12 @@ int spinand_select_target(struct spinand_device *spinand, unsigned int target)
return 0;
}
static int spinand_init_cfg_cache(struct spinand_device *spinand)
static int spinand_read_cfg(struct spinand_device *spinand)
{
struct nand_device *nand = spinand_to_nand(spinand);
struct device *dev = &spinand->spimem->spi->dev;
unsigned int target;
int ret;
spinand->cfg_cache = devm_kcalloc(dev,
nand->memorg.ntargets,
sizeof(*spinand->cfg_cache),
GFP_KERNEL);
if (!spinand->cfg_cache)
return -ENOMEM;
for (target = 0; target < nand->memorg.ntargets; target++) {
ret = spinand_select_target(spinand, target);
if (ret)
@ -170,6 +162,21 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand)
return 0;
}
static int spinand_init_cfg_cache(struct spinand_device *spinand)
{
struct nand_device *nand = spinand_to_nand(spinand);
struct device *dev = &spinand->spimem->spi->dev;
spinand->cfg_cache = devm_kcalloc(dev,
nand->memorg.ntargets,
sizeof(*spinand->cfg_cache),
GFP_KERNEL);
if (!spinand->cfg_cache)
return -ENOMEM;
return 0;
}
static int spinand_init_quad_enable(struct spinand_device *spinand)
{
bool enable = false;
@ -290,6 +297,8 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand,
{
struct spinand_ondie_ecc_conf *engine_conf = nand->ecc.ctx.priv;
struct spinand_device *spinand = nand_to_spinand(nand);
struct mtd_info *mtd = spinand_to_mtd(spinand);
int ret;
if (req->mode == MTD_OPS_RAW)
return 0;
@ -299,7 +308,13 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand,
return 0;
/* Finish a page write: check the status, report errors/bitflips */
return spinand_check_ecc_status(spinand, engine_conf->status);
ret = spinand_check_ecc_status(spinand, engine_conf->status);
if (ret == -EBADMSG)
mtd->ecc_stats.failed++;
else if (ret > 0)
mtd->ecc_stats.corrected += ret;
return ret;
}
static struct nand_ecc_engine_ops spinand_ondie_ecc_engine_ops = {
@ -620,13 +635,10 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
if (ret < 0 && ret != -EBADMSG)
break;
if (ret == -EBADMSG) {
if (ret == -EBADMSG)
ecc_failed = true;
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += ret;
else
max_bitflips = max_t(unsigned int, max_bitflips, ret);
}
ret = 0;
ops->retlen += iter.req.datalen;
@ -1074,12 +1086,71 @@ static int spinand_detect(struct spinand_device *spinand)
return 0;
}
static int spinand_init_flash(struct spinand_device *spinand)
{
struct device *dev = &spinand->spimem->spi->dev;
struct nand_device *nand = spinand_to_nand(spinand);
int ret, i;
ret = spinand_read_cfg(spinand);
if (ret)
return ret;
ret = spinand_init_quad_enable(spinand);
if (ret)
return ret;
ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0);
if (ret)
return ret;
ret = spinand_manufacturer_init(spinand);
if (ret) {
dev_err(dev,
"Failed to initialize the SPI NAND chip (err = %d)\n",
ret);
return ret;
}
/* After power up, all blocks are locked, so unlock them here. */
for (i = 0; i < nand->memorg.ntargets; i++) {
ret = spinand_select_target(spinand, i);
if (ret)
break;
ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
if (ret)
break;
}
if (ret)
spinand_manufacturer_cleanup(spinand);
return ret;
}
static void spinand_mtd_resume(struct mtd_info *mtd)
{
struct spinand_device *spinand = mtd_to_spinand(mtd);
int ret;
ret = spinand_reset_op(spinand);
if (ret)
return;
ret = spinand_init_flash(spinand);
if (ret)
return;
spinand_ecc_enable(spinand, false);
}
static int spinand_init(struct spinand_device *spinand)
{
struct device *dev = &spinand->spimem->spi->dev;
struct mtd_info *mtd = spinand_to_mtd(spinand);
struct nand_device *nand = mtd_to_nanddev(mtd);
int ret, i;
int ret;
/*
* We need a scratch buffer because the spi_mem interface requires that
@ -1112,22 +1183,10 @@ static int spinand_init(struct spinand_device *spinand)
if (ret)
goto err_free_bufs;
ret = spinand_init_quad_enable(spinand);
ret = spinand_init_flash(spinand);
if (ret)
goto err_free_bufs;
ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0);
if (ret)
goto err_free_bufs;
ret = spinand_manufacturer_init(spinand);
if (ret) {
dev_err(dev,
"Failed to initialize the SPI NAND chip (err = %d)\n",
ret);
goto err_free_bufs;
}
ret = spinand_create_dirmaps(spinand);
if (ret) {
dev_err(dev,
@ -1136,17 +1195,6 @@ static int spinand_init(struct spinand_device *spinand)
goto err_manuf_cleanup;
}
/* After power up, all blocks are locked, so unlock them here. */
for (i = 0; i < nand->memorg.ntargets; i++) {
ret = spinand_select_target(spinand, i);
if (ret)
goto err_manuf_cleanup;
ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
if (ret)
goto err_manuf_cleanup;
}
ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
if (ret)
goto err_manuf_cleanup;
@ -1167,6 +1215,7 @@ static int spinand_init(struct spinand_device *spinand)
mtd->_block_isreserved = spinand_mtd_block_isreserved;
mtd->_erase = spinand_mtd_erase;
mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
mtd->_resume = spinand_mtd_resume;
if (nand->ecc.engine) {
ret = mtd_ooblayout_count_freebytes(mtd);

View File

@ -186,6 +186,118 @@ static const struct spinand_info macronix_spinand_table[] = {
0 /*SPINAND_HAS_QE_BIT*/,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35LF2G14AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF4G24AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF4GE4AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF2G14AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF2G24AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF2GE4AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF2GE4AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF1G14AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF1G24AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF1GE4AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF1GE4AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
};
static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {

View File

@ -11,6 +11,7 @@
#define __LINUX_MTD_ONFI_H
#include <linux/types.h>
#include <linux/bitfield.h>
/* ONFI version bits */
#define ONFI_VERSION_1_0 BIT(1)
@ -24,17 +25,22 @@
#define ONFI_VERSION_4_0 BIT(9)
/* ONFI features */
#define ONFI_FEATURE_16_BIT_BUS (1 << 0)
#define ONFI_FEATURE_EXT_PARAM_PAGE (1 << 7)
#define ONFI_FEATURE_16_BIT_BUS BIT(0)
#define ONFI_FEATURE_NV_DDR BIT(5)
#define ONFI_FEATURE_EXT_PARAM_PAGE BIT(7)
/* ONFI timing mode, used in both asynchronous and synchronous mode */
#define ONFI_TIMING_MODE_0 (1 << 0)
#define ONFI_TIMING_MODE_1 (1 << 1)
#define ONFI_TIMING_MODE_2 (1 << 2)
#define ONFI_TIMING_MODE_3 (1 << 3)
#define ONFI_TIMING_MODE_4 (1 << 4)
#define ONFI_TIMING_MODE_5 (1 << 5)
#define ONFI_TIMING_MODE_UNKNOWN (1 << 6)
#define ONFI_DATA_INTERFACE_SDR 0
#define ONFI_DATA_INTERFACE_NVDDR BIT(4)
#define ONFI_DATA_INTERFACE_NVDDR2 BIT(5)
#define ONFI_TIMING_MODE_0 BIT(0)
#define ONFI_TIMING_MODE_1 BIT(1)
#define ONFI_TIMING_MODE_2 BIT(2)
#define ONFI_TIMING_MODE_3 BIT(3)
#define ONFI_TIMING_MODE_4 BIT(4)
#define ONFI_TIMING_MODE_5 BIT(5)
#define ONFI_TIMING_MODE_UNKNOWN BIT(6)
#define ONFI_TIMING_MODE_PARAM(x) FIELD_GET(GENMASK(3, 0), (x))
/* ONFI feature number/address */
#define ONFI_FEATURE_NUMBER 256
@ -49,7 +55,7 @@
#define ONFI_SUBFEATURE_PARAM_LEN 4
/* ONFI optional commands SET/GET FEATURES supported? */
#define ONFI_OPT_CMD_SET_GET_FEATURES (1 << 2)
#define ONFI_OPT_CMD_SET_GET_FEATURES BIT(2)
struct nand_onfi_params {
/* rev info and features block */
@ -93,14 +99,15 @@ struct nand_onfi_params {
/* electrical parameter block */
u8 io_pin_capacitance_max;
__le16 async_timing_mode;
__le16 sdr_timing_modes;
__le16 program_cache_timing_mode;
__le16 t_prog;
__le16 t_bers;
__le16 t_r;
__le16 t_ccs;
__le16 src_sync_timing_mode;
u8 src_ssync_features;
u8 nvddr_timing_modes;
u8 nvddr2_timing_modes;
u8 nvddr_nvddr2_features;
__le16 clk_pin_capacitance_typ;
__le16 io_pin_capacitance_typ;
__le16 input_pin_capacitance_typ;
@ -160,7 +167,9 @@ struct onfi_ext_param_page {
* @tBERS: Block erase time
* @tR: Page read time
* @tCCS: Change column setup time
* @async_timing_mode: Supported asynchronous timing mode
* @fast_tCAD: Command/Address/Data slow or fast delay (NV-DDR only)
* @sdr_timing_modes: Supported asynchronous/SDR timing modes
* @nvddr_timing_modes: Supported source synchronous/NV-DDR timing modes
* @vendor_revision: Vendor specific revision number
* @vendor: Vendor specific data
*/
@ -170,7 +179,9 @@ struct onfi_params {
u16 tBERS;
u16 tR;
u16 tCCS;
u16 async_timing_mode;
bool fast_tCAD;
u16 sdr_timing_modes;
u16 nvddr_timing_modes;
u16 vendor_revision;
u8 vendor[88];
};

View File

@ -24,6 +24,7 @@
#include <linux/types.h>
struct nand_chip;
struct gpio_desc;
/* The maximum number of NAND chips in an array */
#define NAND_MAX_CHIPS 8
@ -385,8 +386,8 @@ struct nand_ecc_ctrl {
* This struct defines the timing requirements of a SDR NAND chip.
* These information can be found in every NAND datasheets and the timings
* meaning are described in the ONFI specifications:
* www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
* Parameters)
* https://media-www.micron.com/-/media/client/onfi/specs/onfi_3_1_spec.pdf
* (chapter 4.15 Timing Parameters)
*
* All these timings are expressed in picoseconds.
*
@ -471,12 +472,128 @@ struct nand_sdr_timings {
u32 tWW_min;
};
/**
* struct nand_nvddr_timings - NV-DDR NAND chip timings
*
* This struct defines the timing requirements of a NV-DDR NAND data interface.
* These information can be found in every NAND datasheets and the timings
* meaning are described in the ONFI specifications:
* https://media-www.micron.com/-/media/client/onfi/specs/onfi_4_1_gold.pdf
* (chapter 4.18.2 NV-DDR)
*
* All these timings are expressed in picoseconds.
*
* @tBERS_max: Block erase time
* @tCCS_min: Change column setup time
* @tPROG_max: Page program time
* @tR_max: Page read time
* @tAC_min: Access window of DQ[7:0] from CLK
* @tAC_max: Access window of DQ[7:0] from CLK
* @tADL_min: ALE to data loading time
* @tCAD_min: Command, Address, Data delay
* @tCAH_min: Command/Address DQ hold time
* @tCALH_min: W/R_n, CLE and ALE hold time
* @tCALS_min: W/R_n, CLE and ALE setup time
* @tCAS_min: Command/address DQ setup time
* @tCEH_min: CE# high hold time
* @tCH_min: CE# hold time
* @tCK_min: Average clock cycle time
* @tCS_min: CE# setup time
* @tDH_min: Data hold time
* @tDQSCK_min: Start of the access window of DQS from CLK
* @tDQSCK_max: End of the access window of DQS from CLK
* @tDQSD_min: Min W/R_n low to DQS/DQ driven by device
* @tDQSD_max: Max W/R_n low to DQS/DQ driven by device
* @tDQSHZ_max: W/R_n high to DQS/DQ tri-state by device
* @tDQSQ_max: DQS-DQ skew, DQS to last DQ valid, per access
* @tDS_min: Data setup time
* @tDSC_min: DQS cycle time
* @tFEAT_max: Busy time for Set Features and Get Features
* @tITC_max: Interface and Timing Mode Change time
* @tQHS_max: Data hold skew factor
* @tRHW_min: Data output cycle to command, address, or data input cycle
* @tRR_min: Ready to RE# low (data only)
* @tRST_max: Device reset time, measured from the falling edge of R/B# to the
* rising edge of R/B#.
* @tWB_max: WE# high to SR[6] low
* @tWHR_min: WE# high to RE# low
* @tWRCK_min: W/R_n low to data output cycle
* @tWW_min: WP# transition to WE# low
*/
struct nand_nvddr_timings {
u64 tBERS_max;
u32 tCCS_min;
u64 tPROG_max;
u64 tR_max;
u32 tAC_min;
u32 tAC_max;
u32 tADL_min;
u32 tCAD_min;
u32 tCAH_min;
u32 tCALH_min;
u32 tCALS_min;
u32 tCAS_min;
u32 tCEH_min;
u32 tCH_min;
u32 tCK_min;
u32 tCS_min;
u32 tDH_min;
u32 tDQSCK_min;
u32 tDQSCK_max;
u32 tDQSD_min;
u32 tDQSD_max;
u32 tDQSHZ_max;
u32 tDQSQ_max;
u32 tDS_min;
u32 tDSC_min;
u32 tFEAT_max;
u32 tITC_max;
u32 tQHS_max;
u32 tRHW_min;
u32 tRR_min;
u32 tRST_max;
u32 tWB_max;
u32 tWHR_min;
u32 tWRCK_min;
u32 tWW_min;
};
/*
* While timings related to the data interface itself are mostly different
* between SDR and NV-DDR, timings related to the internal chip behavior are
* common. IOW, the following entries which describe the internal delays have
* the same definition and are shared in both SDR and NV-DDR timing structures:
* - tADL_min
* - tBERS_max
* - tCCS_min
* - tFEAT_max
* - tPROG_max
* - tR_max
* - tRR_min
* - tRST_max
* - tWB_max
*
* The below macros return the value of a given timing, no matter the interface.
*/
#define NAND_COMMON_TIMING_PS(conf, timing_name) \
nand_interface_is_sdr(conf) ? \
nand_get_sdr_timings(conf)->timing_name : \
nand_get_nvddr_timings(conf)->timing_name
#define NAND_COMMON_TIMING_MS(conf, timing_name) \
PSEC_TO_MSEC(NAND_COMMON_TIMING_PS((conf), timing_name))
#define NAND_COMMON_TIMING_NS(conf, timing_name) \
PSEC_TO_NSEC(NAND_COMMON_TIMING_PS((conf), timing_name))
/**
* enum nand_interface_type - NAND interface type
* @NAND_SDR_IFACE: Single Data Rate interface
* @NAND_NVDDR_IFACE: Double Data Rate interface
*/
enum nand_interface_type {
NAND_SDR_IFACE,
NAND_NVDDR_IFACE,
};
/**
@ -485,6 +602,7 @@ enum nand_interface_type {
* @timings: The timing information
* @timings.mode: Timing mode as defined in the specification
* @timings.sdr: Use it when @type is %NAND_SDR_IFACE.
* @timings.nvddr: Use it when @type is %NAND_NVDDR_IFACE.
*/
struct nand_interface_config {
enum nand_interface_type type;
@ -492,10 +610,29 @@ struct nand_interface_config {
unsigned int mode;
union {
struct nand_sdr_timings sdr;
struct nand_nvddr_timings nvddr;
};
} timings;
};
/**
* nand_interface_is_sdr - get the interface type
* @conf: The data interface
*/
static bool nand_interface_is_sdr(const struct nand_interface_config *conf)
{
return conf->type == NAND_SDR_IFACE;
}
/**
* nand_interface_is_nvddr - get the interface type
* @conf: The data interface
*/
static bool nand_interface_is_nvddr(const struct nand_interface_config *conf)
{
return conf->type == NAND_NVDDR_IFACE;
}
/**
* nand_get_sdr_timings - get SDR timing from data interface
* @conf: The data interface
@ -503,12 +640,25 @@ struct nand_interface_config {
static inline const struct nand_sdr_timings *
nand_get_sdr_timings(const struct nand_interface_config *conf)
{
if (conf->type != NAND_SDR_IFACE)
if (!nand_interface_is_sdr(conf))
return ERR_PTR(-EINVAL);
return &conf->timings.sdr;
}
/**
* nand_get_nvddr_timings - get NV-DDR timing from data interface
* @conf: The data interface
*/
static inline const struct nand_nvddr_timings *
nand_get_nvddr_timings(const struct nand_interface_config *conf)
{
if (!nand_interface_is_nvddr(conf))
return ERR_PTR(-EINVAL);
return &conf->timings.nvddr;
}
/**
* struct nand_op_cmd_instr - Definition of a command instruction
* @opcode: the command to issue in one cycle
@ -1413,7 +1563,6 @@ void nand_cleanup(struct nand_chip *chip);
* instruction and have no physical pin to check it.
*/
int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms);
struct gpio_desc;
int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod,
unsigned long timeout_ms);
@ -1446,4 +1595,8 @@ static inline void *nand_get_data_buf(struct nand_chip *chip)
return chip->data_buf;
}
/* Parse the gpio-cs property */
int rawnand_dt_parse_gpio_cs(struct device *dev, struct gpio_desc ***cs_array,
unsigned int *ncs_array);
#endif /* __LINUX_MTD_RAWNAND_H */

View File

@ -1,30 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ARM PL353 SMC Driver Header
*
* Copyright (C) 2012 - 2018 Xilinx, Inc
*/
#ifndef __LINUX_PL353_SMC_H
#define __LINUX_PL353_SMC_H
enum pl353_smc_ecc_mode {
PL353_SMC_ECCMODE_BYPASS = 0,
PL353_SMC_ECCMODE_APB = 1,
PL353_SMC_ECCMODE_MEM = 2
};
enum pl353_smc_mem_width {
PL353_SMC_MEM_WIDTH_8 = 0,
PL353_SMC_MEM_WIDTH_16 = 1
};
u32 pl353_smc_get_ecc_val(int ecc_reg);
bool pl353_smc_ecc_is_busy(void);
int pl353_smc_get_nand_int_status_raw(void);
void pl353_smc_clr_nand_int(void);
int pl353_smc_set_ecc_mode(enum pl353_smc_ecc_mode mode);
int pl353_smc_set_ecc_pg_size(unsigned int pg_sz);
int pl353_smc_set_buswidth(unsigned int bw);
void pl353_smc_set_cycles(u32 timings[]);
#endif