mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 13:43:51 +00:00
Raw NAND
The main series brought is an update of the Broadcom support to support all BCMBCA SoCs and their specificity (ECC, write protection, configuration straps), plus a few misc fixes and changes in the main driver. Device tree updates are also part of this PR, initially because of a misunderstanding on my side. The STM32_FMC2 controller driver is also upgraded to properly support MP1 and MP25 SoCs. A new compatible is added for an Atmel flavor. Among all these feature changes, there is as well a load of continuous read related fixes, avoiding more corner conditions and clarifying the logic. Finally a few miscellaneous fixes are made to the core, the lpx32xx_mlc, fsl_lbc, Meson and Atmel controller driver, as well as final one in the Hynix vendor driver. SPI-NAND The ESMT support has been extended to match 5 bytes ID to avoid collisions. Winbond support on its side receives support for W25N04KV chips. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAmXzgv4ACgkQJWrqGEe9 VoTwUAgAqwzuaAbhMuHABS2IJnn9KZHCo4f2goXhtrtRP2oDSgzsT8Yke2vfJTIx KBtjWRYdp5n8GRSmDmO1n/oNnKdjkzbOhP0ow8aZqhKYtjQ7O0xxd4gxQu3gCoVz ypWq3tpMkKH0MyD8d+HulFhldMmyGv5BqXeioLi2azeALCbpgVcGAHaMxUlRB/p3 iM3GtBr9hUbai6HlynnPsiAAmyUc1gvGGHJ8t2ShjaW5LzK7uBqJLhSVizfP8I6g N6l0C+KKwFmXlprtgMcg/HjW2QWKOyeqrhmgTzcJIHRiPjySnmfOVeHBLu6y+1wl MC3BC5kHNSmOfuU76/93LUQUwkWvUA== =TaNQ -----END PGP SIGNATURE----- Merge tag 'nand/for-6.9' into mtd/next Raw NAND The main series brought is an update of the Broadcom support to support all BCMBCA SoCs and their specificity (ECC, write protection, configuration straps), plus a few misc fixes and changes in the main driver. Device tree updates are also part of this PR, initially because of a misunderstanding on my side. The STM32_FMC2 controller driver is also upgraded to properly support MP1 and MP25 SoCs. A new compatible is added for an Atmel flavor. Among all these feature changes, there is as well a load of continuous read related fixes, avoiding more corner conditions and clarifying the logic. Finally a few miscellaneous fixes are made to the core, the lpx32xx_mlc, fsl_lbc, Meson and Atmel controller driver, as well as final one in the Hynix vendor driver. SPI-NAND The ESMT support has been extended to match 5 bytes ID to avoid collisions. Winbond support on its side receives support for W25N04KV chips.
This commit is contained in:
commit
09888e973c
@ -56,6 +56,7 @@ Required properties:
|
|||||||
"atmel,sama5d4-pmecc"
|
"atmel,sama5d4-pmecc"
|
||||||
"atmel,sama5d2-pmecc"
|
"atmel,sama5d2-pmecc"
|
||||||
"microchip,sam9x60-pmecc"
|
"microchip,sam9x60-pmecc"
|
||||||
|
"microchip,sam9x7-pmecc", "atmel,at91sam9g45-pmecc"
|
||||||
- reg: should contain 2 register ranges. The first one is pointing to the PMECC
|
- reg: should contain 2 register ranges. The first one is pointing to the PMECC
|
||||||
block, and the second one to the PMECC_ERRLOC block.
|
block, and the second one to the PMECC_ERRLOC block.
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ title: Broadcom STB NAND Controller
|
|||||||
maintainers:
|
maintainers:
|
||||||
- Brian Norris <computersforpeace@gmail.com>
|
- Brian Norris <computersforpeace@gmail.com>
|
||||||
- Kamal Dasu <kdasu.kdev@gmail.com>
|
- Kamal Dasu <kdasu.kdev@gmail.com>
|
||||||
|
- William Zhang <william.zhang@broadcom.com>
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
The Broadcom Set-Top Box NAND controller supports low-level access to raw NAND
|
The Broadcom Set-Top Box NAND controller supports low-level access to raw NAND
|
||||||
@ -18,9 +19,10 @@ description: |
|
|||||||
supports basic PROGRAM and READ functions, among other features.
|
supports basic PROGRAM and READ functions, among other features.
|
||||||
|
|
||||||
This controller was originally designed for STB SoCs (BCM7xxx) but is now
|
This controller was originally designed for STB SoCs (BCM7xxx) but is now
|
||||||
available on a variety of Broadcom SoCs, including some BCM3xxx, BCM63xx, and
|
available on a variety of Broadcom SoCs, including some BCM3xxx, MIPS based
|
||||||
iProc/Cygnus. Its history includes several similar (but not fully register
|
Broadband SoC (BCM63xx), ARM based Broadband SoC (BCMBCA) and iProc/Cygnus.
|
||||||
compatible) versions.
|
Its history includes several similar (but not fully register compatible)
|
||||||
|
versions.
|
||||||
|
|
||||||
-- Additional SoC-specific NAND controller properties --
|
-- Additional SoC-specific NAND controller properties --
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ properties:
|
|||||||
- brcm,brcmnand-v7.2
|
- brcm,brcmnand-v7.2
|
||||||
- brcm,brcmnand-v7.3
|
- brcm,brcmnand-v7.3
|
||||||
- const: brcm,brcmnand
|
- const: brcm,brcmnand
|
||||||
- description: BCM63138 SoC-specific NAND controller
|
- description: BCMBCA SoC-specific NAND controller
|
||||||
items:
|
items:
|
||||||
- const: brcm,nand-bcm63138
|
- const: brcm,nand-bcm63138
|
||||||
- enum:
|
- enum:
|
||||||
@ -111,6 +113,13 @@ properties:
|
|||||||
earlier versions of this core that include WP
|
earlier versions of this core that include WP
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
||||||
|
brcm,wp-not-connected:
|
||||||
|
description:
|
||||||
|
Use this property when WP pin is not physically wired to the NAND chip.
|
||||||
|
Write protection feature cannot be used. By default, controller assumes
|
||||||
|
the pin is connected and feature is used.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
|
||||||
patternProperties:
|
patternProperties:
|
||||||
"^nand@[a-f0-9]$":
|
"^nand@[a-f0-9]$":
|
||||||
type: object
|
type: object
|
||||||
@ -137,6 +146,15 @@ patternProperties:
|
|||||||
layout.
|
layout.
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
brcm,nand-ecc-use-strap:
|
||||||
|
description:
|
||||||
|
This property requires the host system to get the ECC related
|
||||||
|
settings from the SoC NAND boot strap configuration instead of
|
||||||
|
the generic NAND ECC settings. This is a common hardware design
|
||||||
|
on BCMBCA based boards. This strap ECC option and generic NAND
|
||||||
|
ECC option can not be specified at the same time.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
@ -177,6 +195,8 @@ allOf:
|
|||||||
- const: iproc-idm
|
- const: iproc-idm
|
||||||
- const: iproc-ext
|
- const: iproc-ext
|
||||||
- if:
|
- if:
|
||||||
|
required:
|
||||||
|
- interrupts
|
||||||
properties:
|
properties:
|
||||||
interrupts:
|
interrupts:
|
||||||
minItems: 2
|
minItems: 2
|
||||||
@ -184,12 +204,26 @@ allOf:
|
|||||||
required:
|
required:
|
||||||
- interrupt-names
|
- interrupt-names
|
||||||
|
|
||||||
|
- if:
|
||||||
|
patternProperties:
|
||||||
|
"^nand@[a-f0-9]$":
|
||||||
|
required:
|
||||||
|
- brcm,nand-ecc-use-strap
|
||||||
|
then:
|
||||||
|
patternProperties:
|
||||||
|
"^nand@[a-f0-9]$":
|
||||||
|
properties:
|
||||||
|
nand-ecc-strength: false
|
||||||
|
nand-ecc-step-size: false
|
||||||
|
nand-ecc-maximize: false
|
||||||
|
nand-ecc-algo: false
|
||||||
|
brcm,nand-oob-sector-size: false
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- reg
|
- reg
|
||||||
- reg-names
|
- reg-names
|
||||||
- interrupts
|
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
|
@ -14,10 +14,11 @@ properties:
|
|||||||
enum:
|
enum:
|
||||||
- st,stm32mp15-fmc2
|
- st,stm32mp15-fmc2
|
||||||
- st,stm32mp1-fmc2-nfc
|
- st,stm32mp1-fmc2-nfc
|
||||||
|
- st,stm32mp25-fmc2-nfc
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
minItems: 6
|
minItems: 6
|
||||||
maxItems: 7
|
maxItems: 12
|
||||||
|
|
||||||
interrupts:
|
interrupts:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
@ -92,6 +93,28 @@ allOf:
|
|||||||
- description: Chip select 1 command
|
- description: Chip select 1 command
|
||||||
- description: Chip select 1 address space
|
- description: Chip select 1 address space
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
const: st,stm32mp25-fmc2-nfc
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
items:
|
||||||
|
- description: Chip select 0 data
|
||||||
|
- description: Chip select 0 command
|
||||||
|
- description: Chip select 0 address space
|
||||||
|
- description: Chip select 1 data
|
||||||
|
- description: Chip select 1 command
|
||||||
|
- description: Chip select 1 address space
|
||||||
|
- description: Chip select 2 data
|
||||||
|
- description: Chip select 2 command
|
||||||
|
- description: Chip select 2 address space
|
||||||
|
- description: Chip select 3 data
|
||||||
|
- description: Chip select 3 command
|
||||||
|
- description: Chip select 3 address space
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
|
@ -138,6 +138,20 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "arm,pl011", "arm,primecell";
|
compatible = "arm,pl011", "arm,primecell";
|
||||||
reg = <0x12000 0x1000>;
|
reg = <0x12000 0x1000>;
|
||||||
|
@ -229,7 +229,12 @@ nand_controller: nand-controller@2000 {
|
|||||||
reg-names = "nand", "nand-int-base";
|
reg-names = "nand", "nand-int-base";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
interrupt-names = "nand";
|
interrupt-names = "nand_ctlrdy";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
serial@4400 {
|
serial@4400 {
|
||||||
|
@ -119,5 +119,19 @@ hsspi: spi@1000 {
|
|||||||
num-cs = <8>;
|
num-cs = <8>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@2000 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x2000 0x600>, <0xf0 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -129,6 +129,20 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "arm,pl011", "arm,primecell";
|
compatible = "arm,pl011", "arm,primecell";
|
||||||
reg = <0x12000 0x1000>;
|
reg = <0x12000 0x1000>;
|
||||||
|
@ -139,6 +139,20 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "arm,pl011", "arm,primecell";
|
compatible = "arm,pl011", "arm,primecell";
|
||||||
reg = <0x12000 0x1000>;
|
reg = <0x12000 0x1000>;
|
||||||
|
@ -119,5 +119,19 @@ hsspi: spi@1000 {
|
|||||||
num-cs = <8>;
|
num-cs = <8>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -129,6 +129,20 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "arm,pl011", "arm,primecell";
|
compatible = "arm,pl011", "arm,primecell";
|
||||||
reg = <0x12000 0x1000>;
|
reg = <0x12000 0x1000>;
|
||||||
|
@ -120,6 +120,20 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "arm,pl011", "arm,primecell";
|
compatible = "arm,pl011", "arm,primecell";
|
||||||
reg = <0x12000 0x1000>;
|
reg = <0x12000 0x1000>;
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -29,3 +29,13 @@ &serial0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,15 +32,15 @@ &serial1 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
&nand_controller {
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
nand@0 {
|
&nandcs {
|
||||||
compatible = "brcm,nandcs";
|
|
||||||
reg = <0>;
|
|
||||||
nand-ecc-strength = <4>;
|
nand-ecc-strength = <4>;
|
||||||
nand-ecc-step-size = <512>;
|
nand-ecc-step-size = <512>;
|
||||||
brcm,nand-oob-sectors-size = <16>;
|
brcm,nand-oob-sector-size = <16>;
|
||||||
};
|
nand-on-flash-bbt;
|
||||||
};
|
};
|
||||||
|
|
||||||
&ahci {
|
&ahci {
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -125,6 +125,11 @@ port@7 {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
&nandcs {
|
&nandcs {
|
||||||
nand-ecc-strength = <4>;
|
nand-ecc-strength = <4>;
|
||||||
nand-ecc-step-size = <512>;
|
nand-ecc-step-size = <512>;
|
||||||
|
@ -155,6 +155,11 @@ port@7 {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
&nandcs {
|
&nandcs {
|
||||||
nand-ecc-strength = <4>;
|
nand-ecc-strength = <4>;
|
||||||
nand-ecc-step-size = <512>;
|
nand-ecc-step-size = <512>;
|
||||||
|
@ -166,11 +166,15 @@ led@19 {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
&nandcs {
|
&nandcs {
|
||||||
nand-ecc-strength = <4>;
|
nand-ecc-strength = <4>;
|
||||||
nand-ecc-step-size = <512>;
|
nand-ecc-step-size = <512>;
|
||||||
nand-on-flash-bbt;
|
nand-on-flash-bbt;
|
||||||
brcm,nand-has-wp;
|
|
||||||
|
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
@ -589,7 +589,7 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
nand-controller@1800 {
|
nand_controller: nand-controller@1800 {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
@ -597,7 +597,7 @@ nand-controller@1800 {
|
|||||||
reg-names = "nand", "nand-int-base";
|
reg-names = "nand", "nand-int-base";
|
||||||
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
interrupt-names = "nand_ctlrdy";
|
interrupt-names = "nand_ctlrdy";
|
||||||
status = "okay";
|
status = "disabled";
|
||||||
|
|
||||||
nandcs: nand@0 {
|
nandcs: nand@0 {
|
||||||
compatible = "brcm,nandcs";
|
compatible = "brcm,nandcs";
|
||||||
|
@ -138,6 +138,20 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "arm,pl011", "arm,primecell";
|
compatible = "arm,pl011", "arm,primecell";
|
||||||
reg = <0x12000 0x1000>;
|
reg = <0x12000 0x1000>;
|
||||||
|
@ -119,6 +119,20 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "arm,pl011", "arm,primecell";
|
compatible = "arm,pl011", "arm,primecell";
|
||||||
reg = <0x12000 0x1000>;
|
reg = <0x12000 0x1000>;
|
||||||
|
@ -137,6 +137,20 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "arm,pl011", "arm,primecell";
|
compatible = "arm,pl011", "arm,primecell";
|
||||||
reg = <0x12000 0x1000>;
|
reg = <0x12000 0x1000>;
|
||||||
|
@ -138,6 +138,20 @@ hsspi: spi@1000 {
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uart0: serial@12000 {
|
uart0: serial@12000 {
|
||||||
compatible = "arm,pl011", "arm,primecell";
|
compatible = "arm,pl011", "arm,primecell";
|
||||||
reg = <0x12000 0x1000>;
|
reg = <0x12000 0x1000>;
|
||||||
|
@ -119,5 +119,19 @@ hsspi: spi@1000 {
|
|||||||
num-cs = <8>;
|
num-cs = <8>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -156,5 +156,19 @@ hsspi: spi@1000 {
|
|||||||
num-cs = <8>;
|
num-cs = <8>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nand_controller: nand-controller@1800 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||||
|
reg = <0x1800 0x600>, <0x2000 0x10>;
|
||||||
|
reg-names = "nand", "nand-int-base";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
nandcs: nand@0 {
|
||||||
|
compatible = "brcm,nandcs";
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -32,3 +32,13 @@ &uart0 {
|
|||||||
&hsspi {
|
&hsspi {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&nand_controller {
|
||||||
|
brcm,wp-not-connected;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&nandcs {
|
||||||
|
nand-on-flash-bbt;
|
||||||
|
brcm,nand-ecc-use-strap;
|
||||||
|
};
|
||||||
|
@ -1378,7 +1378,7 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The write cycle timing is directly matching tWC, but is also
|
* The read cycle timing is directly matching tRC, but is also
|
||||||
* dependent on the setup and hold timings we calculated earlier,
|
* dependent on the setup and hold timings we calculated earlier,
|
||||||
* which gives:
|
* which gives:
|
||||||
*
|
*
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# link order matters; don't link the more generic brcmstb_nand.o before the
|
# link order matters; don't link the more generic brcmstb_nand.o before the
|
||||||
# more specific iproc_nand.o, for instance
|
# more specific iproc_nand.o, for instance
|
||||||
obj-$(CONFIG_MTD_NAND_BRCMNAND_IPROC) += iproc_nand.o
|
obj-$(CONFIG_MTD_NAND_BRCMNAND_IPROC) += iproc_nand.o
|
||||||
obj-$(CONFIG_MTD_NAND_BRCMNAND_BCMBCA) += bcm63138_nand.o
|
obj-$(CONFIG_MTD_NAND_BRCMNAND_BCMBCA) += bcmbca_nand.o
|
||||||
obj-$(CONFIG_MTD_NAND_BRCMNAND_BCM63XX) += bcm6368_nand.o
|
obj-$(CONFIG_MTD_NAND_BRCMNAND_BCM63XX) += bcm6368_nand.o
|
||||||
obj-$(CONFIG_MTD_NAND_BRCMNAND_BRCMSTB) += brcmstb_nand.o
|
obj-$(CONFIG_MTD_NAND_BRCMNAND_BRCMSTB) += brcmstb_nand.o
|
||||||
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand.o
|
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand.o
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
/*
|
|
||||||
* Copyright © 2015 Broadcom Corporation
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/ioport.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/of_address.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
|
|
||||||
#include "brcmnand.h"
|
|
||||||
|
|
||||||
struct bcm63138_nand_soc {
|
|
||||||
struct brcmnand_soc soc;
|
|
||||||
void __iomem *base;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define BCM63138_NAND_INT_STATUS 0x00
|
|
||||||
#define BCM63138_NAND_INT_EN 0x04
|
|
||||||
|
|
||||||
enum {
|
|
||||||
BCM63138_CTLRDY = BIT(4),
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
|
|
||||||
{
|
|
||||||
struct bcm63138_nand_soc *priv =
|
|
||||||
container_of(soc, struct bcm63138_nand_soc, soc);
|
|
||||||
void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS;
|
|
||||||
u32 val = brcmnand_readl(mmio);
|
|
||||||
|
|
||||||
if (val & BCM63138_CTLRDY) {
|
|
||||||
brcmnand_writel(val & ~BCM63138_CTLRDY, mmio);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
|
|
||||||
{
|
|
||||||
struct bcm63138_nand_soc *priv =
|
|
||||||
container_of(soc, struct bcm63138_nand_soc, soc);
|
|
||||||
void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN;
|
|
||||||
u32 val = brcmnand_readl(mmio);
|
|
||||||
|
|
||||||
if (en)
|
|
||||||
val |= BCM63138_CTLRDY;
|
|
||||||
else
|
|
||||||
val &= ~BCM63138_CTLRDY;
|
|
||||||
|
|
||||||
brcmnand_writel(val, mmio);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bcm63138_nand_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct device *dev = &pdev->dev;
|
|
||||||
struct bcm63138_nand_soc *priv;
|
|
||||||
struct brcmnand_soc *soc;
|
|
||||||
|
|
||||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
||||||
if (!priv)
|
|
||||||
return -ENOMEM;
|
|
||||||
soc = &priv->soc;
|
|
||||||
|
|
||||||
priv->base = devm_platform_ioremap_resource_byname(pdev, "nand-int-base");
|
|
||||||
if (IS_ERR(priv->base))
|
|
||||||
return PTR_ERR(priv->base);
|
|
||||||
|
|
||||||
soc->ctlrdy_ack = bcm63138_nand_intc_ack;
|
|
||||||
soc->ctlrdy_set_enabled = bcm63138_nand_intc_set;
|
|
||||||
|
|
||||||
return brcmnand_probe(pdev, soc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id bcm63138_nand_of_match[] = {
|
|
||||||
{ .compatible = "brcm,nand-bcm63138" },
|
|
||||||
{},
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, bcm63138_nand_of_match);
|
|
||||||
|
|
||||||
static struct platform_driver bcm63138_nand_driver = {
|
|
||||||
.probe = bcm63138_nand_probe,
|
|
||||||
.remove_new = brcmnand_remove,
|
|
||||||
.driver = {
|
|
||||||
.name = "bcm63138_nand",
|
|
||||||
.pm = &brcmnand_pm_ops,
|
|
||||||
.of_match_table = bcm63138_nand_of_match,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
module_platform_driver(bcm63138_nand_driver);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
|
||||||
MODULE_AUTHOR("Brian Norris");
|
|
||||||
MODULE_DESCRIPTION("NAND driver for BCM63138");
|
|
126
drivers/mtd/nand/raw/brcmnand/bcmbca_nand.c
Normal file
126
drivers/mtd/nand/raw/brcmnand/bcmbca_nand.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Copyright © 2015 Broadcom Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include "brcmnand.h"
|
||||||
|
|
||||||
|
struct bcmbca_nand_soc {
|
||||||
|
struct brcmnand_soc soc;
|
||||||
|
void __iomem *base;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BCMBCA_NAND_INT_STATUS 0x00
|
||||||
|
#define BCMBCA_NAND_INT_EN 0x04
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BCMBCA_CTLRDY = BIT(4),
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(CONFIG_ARM64)
|
||||||
|
#define ALIGN_REQ 8
|
||||||
|
#else
|
||||||
|
#define ALIGN_REQ 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline bool bcmbca_nand_is_buf_aligned(void *flash_cache, void *buffer)
|
||||||
|
{
|
||||||
|
return IS_ALIGNED((uintptr_t)buffer, ALIGN_REQ) &&
|
||||||
|
IS_ALIGNED((uintptr_t)flash_cache, ALIGN_REQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bcmbca_nand_intc_ack(struct brcmnand_soc *soc)
|
||||||
|
{
|
||||||
|
struct bcmbca_nand_soc *priv =
|
||||||
|
container_of(soc, struct bcmbca_nand_soc, soc);
|
||||||
|
void __iomem *mmio = priv->base + BCMBCA_NAND_INT_STATUS;
|
||||||
|
u32 val = brcmnand_readl(mmio);
|
||||||
|
|
||||||
|
if (val & BCMBCA_CTLRDY) {
|
||||||
|
brcmnand_writel(val & ~BCMBCA_CTLRDY, mmio);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bcmbca_nand_intc_set(struct brcmnand_soc *soc, bool en)
|
||||||
|
{
|
||||||
|
struct bcmbca_nand_soc *priv =
|
||||||
|
container_of(soc, struct bcmbca_nand_soc, soc);
|
||||||
|
void __iomem *mmio = priv->base + BCMBCA_NAND_INT_EN;
|
||||||
|
u32 val = brcmnand_readl(mmio);
|
||||||
|
|
||||||
|
if (en)
|
||||||
|
val |= BCMBCA_CTLRDY;
|
||||||
|
else
|
||||||
|
val &= ~BCMBCA_CTLRDY;
|
||||||
|
|
||||||
|
brcmnand_writel(val, mmio);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bcmbca_read_data_bus(struct brcmnand_soc *soc,
|
||||||
|
void __iomem *flash_cache, u32 *buffer, int fc_words)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* memcpy can do unaligned aligned access depending on source
|
||||||
|
* and dest address, which is incompatible with nand cache. Fallback
|
||||||
|
* to the memcpy_fromio in such case
|
||||||
|
*/
|
||||||
|
if (bcmbca_nand_is_buf_aligned((void __force *)flash_cache, buffer))
|
||||||
|
memcpy((void *)buffer, (void __force *)flash_cache, fc_words * 4);
|
||||||
|
else
|
||||||
|
memcpy_fromio((void *)buffer, flash_cache, fc_words * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bcmbca_nand_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct bcmbca_nand_soc *priv;
|
||||||
|
struct brcmnand_soc *soc;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
soc = &priv->soc;
|
||||||
|
|
||||||
|
priv->base = devm_platform_ioremap_resource_byname(pdev, "nand-int-base");
|
||||||
|
if (IS_ERR(priv->base))
|
||||||
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
|
soc->ctlrdy_ack = bcmbca_nand_intc_ack;
|
||||||
|
soc->ctlrdy_set_enabled = bcmbca_nand_intc_set;
|
||||||
|
soc->read_data_bus = bcmbca_read_data_bus;
|
||||||
|
|
||||||
|
return brcmnand_probe(pdev, soc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id bcmbca_nand_of_match[] = {
|
||||||
|
{ .compatible = "brcm,nand-bcm63138" },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, bcmbca_nand_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver bcmbca_nand_driver = {
|
||||||
|
.probe = bcmbca_nand_probe,
|
||||||
|
.remove_new = brcmnand_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "bcmbca_nand",
|
||||||
|
.pm = &brcmnand_pm_ops,
|
||||||
|
.of_match_table = bcmbca_nand_of_match,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
module_platform_driver(bcmbca_nand_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_AUTHOR("Brian Norris");
|
||||||
|
MODULE_DESCRIPTION("NAND driver for BCMBCA");
|
@ -625,7 +625,7 @@ enum {
|
|||||||
/* Only for v7.2 */
|
/* Only for v7.2 */
|
||||||
#define ACC_CONTROL_ECC_EXT_SHIFT 13
|
#define ACC_CONTROL_ECC_EXT_SHIFT 13
|
||||||
|
|
||||||
static u8 brcmnand_status(struct brcmnand_host *host);
|
static int brcmnand_status(struct brcmnand_host *host);
|
||||||
|
|
||||||
static inline bool brcmnand_non_mmio_ops(struct brcmnand_controller *ctrl)
|
static inline bool brcmnand_non_mmio_ops(struct brcmnand_controller *ctrl)
|
||||||
{
|
{
|
||||||
@ -851,6 +851,20 @@ static inline u32 edu_readl(struct brcmnand_controller *ctrl,
|
|||||||
return brcmnand_readl(ctrl->edu_base + offs);
|
return brcmnand_readl(ctrl->edu_base + offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void brcmnand_read_data_bus(struct brcmnand_controller *ctrl,
|
||||||
|
void __iomem *flash_cache, u32 *buffer, int fc_words)
|
||||||
|
{
|
||||||
|
struct brcmnand_soc *soc = ctrl->soc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (soc->read_data_bus) {
|
||||||
|
soc->read_data_bus(soc, flash_cache, buffer, fc_words);
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < fc_words; i++)
|
||||||
|
buffer[i] = brcmnand_read_fc(ctrl, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void brcmnand_clear_ecc_addr(struct brcmnand_controller *ctrl)
|
static void brcmnand_clear_ecc_addr(struct brcmnand_controller *ctrl)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -1024,6 +1038,22 @@ static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool brcmnand_get_sector_size_1k(struct brcmnand_host *host)
|
||||||
|
{
|
||||||
|
struct brcmnand_controller *ctrl = host->ctrl;
|
||||||
|
int sector_size_bit = brcmnand_sector_1k_shift(ctrl);
|
||||||
|
u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
|
||||||
|
BRCMNAND_CS_ACC_CONTROL);
|
||||||
|
u32 acc_control;
|
||||||
|
|
||||||
|
if (sector_size_bit < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
acc_control = nand_readreg(ctrl, acc_control_offs);
|
||||||
|
|
||||||
|
return ((acc_control & BIT(sector_size_bit)) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
|
static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
|
||||||
{
|
{
|
||||||
struct brcmnand_controller *ctrl = host->ctrl;
|
struct brcmnand_controller *ctrl = host->ctrl;
|
||||||
@ -1041,6 +1071,43 @@ static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
|
|||||||
nand_writereg(ctrl, acc_control_offs, tmp);
|
nand_writereg(ctrl, acc_control_offs, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int brcmnand_get_spare_size(struct brcmnand_host *host)
|
||||||
|
{
|
||||||
|
struct brcmnand_controller *ctrl = host->ctrl;
|
||||||
|
u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
|
||||||
|
BRCMNAND_CS_ACC_CONTROL);
|
||||||
|
u32 acc = nand_readreg(ctrl, acc_control_offs);
|
||||||
|
|
||||||
|
return (acc & brcmnand_spare_area_mask(ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void brcmnand_get_ecc_settings(struct brcmnand_host *host, struct nand_chip *chip)
|
||||||
|
{
|
||||||
|
struct brcmnand_controller *ctrl = host->ctrl;
|
||||||
|
u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
|
||||||
|
BRCMNAND_CS_ACC_CONTROL);
|
||||||
|
bool sector_size_1k = brcmnand_get_sector_size_1k(host);
|
||||||
|
int spare_area_size, ecc_level;
|
||||||
|
u32 acc;
|
||||||
|
|
||||||
|
spare_area_size = brcmnand_get_spare_size(host);
|
||||||
|
acc = nand_readreg(ctrl, acc_control_offs);
|
||||||
|
ecc_level = (acc & brcmnand_ecc_level_mask(ctrl)) >> ctrl->ecc_level_shift;
|
||||||
|
if (sector_size_1k)
|
||||||
|
chip->ecc.strength = ecc_level * 2;
|
||||||
|
else if (spare_area_size == 16 && ecc_level == 15)
|
||||||
|
chip->ecc.strength = 1; /* hamming */
|
||||||
|
else
|
||||||
|
chip->ecc.strength = ecc_level;
|
||||||
|
|
||||||
|
if (chip->ecc.size == 0) {
|
||||||
|
if (sector_size_1k)
|
||||||
|
chip->ecc.size = 1024;
|
||||||
|
else
|
||||||
|
chip->ecc.size = 512;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* CS_NAND_SELECT
|
* CS_NAND_SELECT
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
@ -1084,7 +1151,7 @@ static int bcmnand_ctrl_poll_status(struct brcmnand_host *host,
|
|||||||
if ((val & mask) == expected_val)
|
if ((val & mask) == expected_val)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
|
dev_err(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
|
||||||
expected_val, val & mask);
|
expected_val, val & mask);
|
||||||
|
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
@ -1690,7 +1757,7 @@ static int brcmnand_waitfunc(struct nand_chip *chip)
|
|||||||
INTFC_FLASH_STATUS;
|
INTFC_FLASH_STATUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 brcmnand_status(struct brcmnand_host *host)
|
static int brcmnand_status(struct brcmnand_host *host)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = &host->chip;
|
struct nand_chip *chip = &host->chip;
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
@ -1701,7 +1768,7 @@ static u8 brcmnand_status(struct brcmnand_host *host)
|
|||||||
return brcmnand_waitfunc(chip);
|
return brcmnand_waitfunc(chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 brcmnand_reset(struct brcmnand_host *host)
|
static int brcmnand_reset(struct brcmnand_host *host)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = &host->chip;
|
struct nand_chip *chip = &host->chip;
|
||||||
|
|
||||||
@ -1975,7 +2042,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
|
|||||||
{
|
{
|
||||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||||
struct brcmnand_controller *ctrl = host->ctrl;
|
struct brcmnand_controller *ctrl = host->ctrl;
|
||||||
int i, j, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
brcmnand_clear_ecc_addr(ctrl);
|
brcmnand_clear_ecc_addr(ctrl);
|
||||||
|
|
||||||
@ -1988,8 +2055,8 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
|
|||||||
if (likely(buf)) {
|
if (likely(buf)) {
|
||||||
brcmnand_soc_data_bus_prepare(ctrl->soc, false);
|
brcmnand_soc_data_bus_prepare(ctrl->soc, false);
|
||||||
|
|
||||||
for (j = 0; j < FC_WORDS; j++, buf++)
|
brcmnand_read_data_bus(ctrl, ctrl->nand_fc, buf, FC_WORDS);
|
||||||
*buf = brcmnand_read_fc(ctrl, j);
|
buf += FC_WORDS;
|
||||||
|
|
||||||
brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
|
brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
|
||||||
}
|
}
|
||||||
@ -2137,7 +2204,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(ctrl->dev, "uncorrectable error at 0x%llx\n",
|
dev_err(ctrl->dev, "uncorrectable error at 0x%llx\n",
|
||||||
(unsigned long long)err_addr);
|
(unsigned long long)err_addr);
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
/* NAND layer expects zero on ECC errors */
|
/* NAND layer expects zero on ECC errors */
|
||||||
@ -2398,10 +2465,10 @@ static int brcmnand_exec_instr(struct brcmnand_host *host, int i,
|
|||||||
|
|
||||||
static int brcmnand_op_is_status(const struct nand_operation *op)
|
static int brcmnand_op_is_status(const struct nand_operation *op)
|
||||||
{
|
{
|
||||||
if ((op->ninstrs == 2) &&
|
if (op->ninstrs == 2 &&
|
||||||
(op->instrs[0].type == NAND_OP_CMD_INSTR) &&
|
op->instrs[0].type == NAND_OP_CMD_INSTR &&
|
||||||
(op->instrs[0].ctx.cmd.opcode == NAND_CMD_STATUS) &&
|
op->instrs[0].ctx.cmd.opcode == NAND_CMD_STATUS &&
|
||||||
(op->instrs[1].type == NAND_OP_DATA_IN_INSTR))
|
op->instrs[1].type == NAND_OP_DATA_IN_INSTR)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2409,10 +2476,10 @@ static int brcmnand_op_is_status(const struct nand_operation *op)
|
|||||||
|
|
||||||
static int brcmnand_op_is_reset(const struct nand_operation *op)
|
static int brcmnand_op_is_reset(const struct nand_operation *op)
|
||||||
{
|
{
|
||||||
if ((op->ninstrs == 2) &&
|
if (op->ninstrs == 2 &&
|
||||||
(op->instrs[0].type == NAND_OP_CMD_INSTR) &&
|
op->instrs[0].type == NAND_OP_CMD_INSTR &&
|
||||||
(op->instrs[0].ctx.cmd.opcode == NAND_CMD_RESET) &&
|
op->instrs[0].ctx.cmd.opcode == NAND_CMD_RESET &&
|
||||||
(op->instrs[1].type == NAND_OP_WAITRDY_INSTR))
|
op->instrs[1].type == NAND_OP_WAITRDY_INSTR)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2433,11 +2500,14 @@ static int brcmnand_exec_op(struct nand_chip *chip,
|
|||||||
|
|
||||||
if (brcmnand_op_is_status(op)) {
|
if (brcmnand_op_is_status(op)) {
|
||||||
status = op->instrs[1].ctx.data.buf.in;
|
status = op->instrs[1].ctx.data.buf.in;
|
||||||
*status = brcmnand_status(host);
|
ret = brcmnand_status(host);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*status = ret & 0xFF;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} else if (brcmnand_op_is_reset(op)) {
|
||||||
else if (brcmnand_op_is_reset(op)) {
|
|
||||||
ret = brcmnand_reset(host);
|
ret = brcmnand_reset(host);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
@ -2608,16 +2678,34 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
|
|||||||
nanddev_get_memorg(&chip->base);
|
nanddev_get_memorg(&chip->base);
|
||||||
struct brcmnand_controller *ctrl = host->ctrl;
|
struct brcmnand_controller *ctrl = host->ctrl;
|
||||||
struct brcmnand_cfg *cfg = &host->hwcfg;
|
struct brcmnand_cfg *cfg = &host->hwcfg;
|
||||||
char msg[128];
|
struct device_node *np = nand_get_flash_node(chip);
|
||||||
u32 offs, tmp, oob_sector;
|
u32 offs, tmp, oob_sector;
|
||||||
|
bool use_strap = false;
|
||||||
|
char msg[128];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(cfg, 0, sizeof(*cfg));
|
memset(cfg, 0, sizeof(*cfg));
|
||||||
|
use_strap = of_property_read_bool(np, "brcm,nand-ecc-use-strap");
|
||||||
|
|
||||||
ret = of_property_read_u32(nand_get_flash_node(chip),
|
/*
|
||||||
"brcm,nand-oob-sector-size",
|
* Either nand-ecc-xxx or brcm,nand-ecc-use-strap can be set. Error out
|
||||||
|
* if both exist.
|
||||||
|
*/
|
||||||
|
if (chip->ecc.strength && use_strap) {
|
||||||
|
dev_err(ctrl->dev,
|
||||||
|
"ECC strap and DT ECC configuration properties are mutually exclusive\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_strap)
|
||||||
|
brcmnand_get_ecc_settings(host, chip);
|
||||||
|
|
||||||
|
ret = of_property_read_u32(np, "brcm,nand-oob-sector-size",
|
||||||
&oob_sector);
|
&oob_sector);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
if (use_strap)
|
||||||
|
cfg->spare_area_size = brcmnand_get_spare_size(host);
|
||||||
|
else
|
||||||
/* Use detected size */
|
/* Use detected size */
|
||||||
cfg->spare_area_size = mtd->oobsize /
|
cfg->spare_area_size = mtd->oobsize /
|
||||||
(mtd->writesize >> FC_SHIFT);
|
(mtd->writesize >> FC_SHIFT);
|
||||||
@ -3135,6 +3223,10 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
|
|||||||
/* Disable XOR addressing */
|
/* Disable XOR addressing */
|
||||||
brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
|
brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
|
||||||
|
|
||||||
|
/* Check if the board connects the WP pin */
|
||||||
|
if (of_property_read_bool(dn, "brcm,wp-not-connected"))
|
||||||
|
wp_on = 0;
|
||||||
|
|
||||||
if (ctrl->features & BRCMNAND_HAS_WP) {
|
if (ctrl->features & BRCMNAND_HAS_WP) {
|
||||||
/* Permanently disable write protection */
|
/* Permanently disable write protection */
|
||||||
if (wp_on == 2)
|
if (wp_on == 2)
|
||||||
|
@ -24,6 +24,8 @@ struct brcmnand_soc {
|
|||||||
void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
|
void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
|
||||||
void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
|
void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
|
||||||
bool is_param);
|
bool is_param);
|
||||||
|
void (*read_data_bus)(struct brcmnand_soc *soc, void __iomem *flash_cache,
|
||||||
|
u32 *buffer, int fc_words);
|
||||||
const struct brcmnand_io_ops *ops;
|
const struct brcmnand_io_ops *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -869,7 +869,8 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
|
|||||||
struct mtd_info *mtd;
|
struct mtd_info *mtd;
|
||||||
|
|
||||||
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
|
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
|
||||||
return -ENODEV;
|
return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "lbc_ctrl_dev missing\n");
|
||||||
|
|
||||||
lbc = fsl_lbc_ctrl_dev->regs;
|
lbc = fsl_lbc_ctrl_dev->regs;
|
||||||
dev = fsl_lbc_ctrl_dev->dev;
|
dev = fsl_lbc_ctrl_dev->dev;
|
||||||
|
|
||||||
|
@ -303,8 +303,9 @@ static int lpc32xx_nand_device_ready(struct nand_chip *nand_chip)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
|
static irqreturn_t lpc3xxx_nand_irq(int irq, void *data)
|
||||||
{
|
{
|
||||||
|
struct lpc32xx_nand_host *host = data;
|
||||||
uint8_t sr;
|
uint8_t sr;
|
||||||
|
|
||||||
/* Clear interrupt flag by reading status */
|
/* Clear interrupt flag by reading status */
|
||||||
@ -780,7 +781,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
|||||||
goto release_dma_chan;
|
goto release_dma_chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
|
if (request_irq(host->irq, &lpc3xxx_nand_irq,
|
||||||
IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
|
IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
|
||||||
dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
|
dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
|
||||||
res = -ENXIO;
|
res = -ENXIO;
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
#define CMDRWGEN(cmd_dir, ran, bch, short_mode, page_size, pages) \
|
#define CMDRWGEN(cmd_dir, ran, bch, short_mode, page_size, pages) \
|
||||||
( \
|
( \
|
||||||
(cmd_dir) | \
|
(cmd_dir) | \
|
||||||
((ran) << 19) | \
|
(ran) | \
|
||||||
((bch) << 14) | \
|
((bch) << 14) | \
|
||||||
((short_mode) << 13) | \
|
((short_mode) << 13) | \
|
||||||
(((page_size) & 0x7f) << 6) | \
|
(((page_size) & 0x7f) << 6) | \
|
||||||
|
@ -1356,7 +1356,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
chip = devm_kzalloc(dev, sizeof(*chip) + nsels * sizeof(u8),
|
chip = devm_kzalloc(dev, struct_size(chip, sels, nsels),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!chip)
|
if (!chip)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1211,21 +1211,36 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
|
|||||||
return nand_exec_op(chip, &op);
|
return nand_exec_op(chip, &op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int rawnand_last_page_of_lun(unsigned int pages_per_lun, unsigned int lun)
|
||||||
|
{
|
||||||
|
/* lun is expected to be very small */
|
||||||
|
return (lun * pages_per_lun) + pages_per_lun - 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void rawnand_cap_cont_reads(struct nand_chip *chip)
|
static void rawnand_cap_cont_reads(struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
struct nand_memory_organization *memorg;
|
struct nand_memory_organization *memorg;
|
||||||
unsigned int pages_per_lun, first_lun, last_lun;
|
unsigned int ppl, first_lun, last_lun;
|
||||||
|
|
||||||
memorg = nanddev_get_memorg(&chip->base);
|
memorg = nanddev_get_memorg(&chip->base);
|
||||||
pages_per_lun = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun;
|
ppl = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun;
|
||||||
first_lun = chip->cont_read.first_page / pages_per_lun;
|
first_lun = chip->cont_read.first_page / ppl;
|
||||||
last_lun = chip->cont_read.last_page / pages_per_lun;
|
last_lun = chip->cont_read.last_page / ppl;
|
||||||
|
|
||||||
/* Prevent sequential cache reads across LUN boundaries */
|
/* Prevent sequential cache reads across LUN boundaries */
|
||||||
if (first_lun != last_lun)
|
if (first_lun != last_lun)
|
||||||
chip->cont_read.pause_page = first_lun * pages_per_lun + pages_per_lun - 1;
|
chip->cont_read.pause_page = rawnand_last_page_of_lun(ppl, first_lun);
|
||||||
else
|
else
|
||||||
chip->cont_read.pause_page = chip->cont_read.last_page;
|
chip->cont_read.pause_page = chip->cont_read.last_page;
|
||||||
|
|
||||||
|
if (chip->cont_read.first_page == chip->cont_read.pause_page) {
|
||||||
|
chip->cont_read.first_page++;
|
||||||
|
chip->cont_read.pause_page = min(chip->cont_read.last_page,
|
||||||
|
rawnand_last_page_of_lun(ppl, first_lun + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chip->cont_read.first_page >= chip->cont_read.last_page)
|
||||||
|
chip->cont_read.ongoing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int page,
|
static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int page,
|
||||||
@ -1292,12 +1307,11 @@ static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int p
|
|||||||
if (!chip->cont_read.ongoing)
|
if (!chip->cont_read.ongoing)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (page == chip->cont_read.pause_page &&
|
if (page == chip->cont_read.last_page) {
|
||||||
page != chip->cont_read.last_page) {
|
|
||||||
chip->cont_read.first_page = chip->cont_read.pause_page + 1;
|
|
||||||
rawnand_cap_cont_reads(chip);
|
|
||||||
} else if (page == chip->cont_read.last_page) {
|
|
||||||
chip->cont_read.ongoing = false;
|
chip->cont_read.ongoing = false;
|
||||||
|
} else if (page == chip->cont_read.pause_page) {
|
||||||
|
chip->cont_read.first_page++;
|
||||||
|
rawnand_cap_cont_reads(chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -3466,31 +3480,37 @@ static void rawnand_enable_cont_reads(struct nand_chip *chip, unsigned int page,
|
|||||||
u32 readlen, int col)
|
u32 readlen, int col)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||||
unsigned int end_page, end_col;
|
unsigned int first_page, last_page;
|
||||||
|
|
||||||
chip->cont_read.ongoing = false;
|
chip->cont_read.ongoing = false;
|
||||||
|
|
||||||
if (!chip->controller->supported_op.cont_read)
|
if (!chip->controller->supported_op.cont_read)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
end_page = DIV_ROUND_UP(col + readlen, mtd->writesize);
|
/*
|
||||||
end_col = (col + readlen) % mtd->writesize;
|
* Don't bother making any calculations if the length is too small.
|
||||||
|
* Side effect: avoids possible integer underflows below.
|
||||||
if (col)
|
*/
|
||||||
page++;
|
if (readlen < (2 * mtd->writesize))
|
||||||
|
|
||||||
if (end_col && end_page)
|
|
||||||
end_page--;
|
|
||||||
|
|
||||||
if (page + 1 > end_page)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
chip->cont_read.first_page = page;
|
/* Derive the page where continuous read should start (the first full page read) */
|
||||||
chip->cont_read.last_page = end_page;
|
first_page = page;
|
||||||
chip->cont_read.ongoing = true;
|
if (col)
|
||||||
|
first_page++;
|
||||||
|
|
||||||
|
/* Derive the page where continuous read should stop (the last full page read) */
|
||||||
|
last_page = page + ((col + readlen) / mtd->writesize) - 1;
|
||||||
|
|
||||||
|
/* Configure and enable continuous read when suitable */
|
||||||
|
if (first_page < last_page) {
|
||||||
|
chip->cont_read.first_page = first_page;
|
||||||
|
chip->cont_read.last_page = last_page;
|
||||||
|
chip->cont_read.ongoing = true;
|
||||||
|
/* May reset the ongoing flag */
|
||||||
rawnand_cap_cont_reads(chip);
|
rawnand_cap_cont_reads(chip);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void rawnand_cont_read_skip_first_page(struct nand_chip *chip, unsigned int page)
|
static void rawnand_cont_read_skip_first_page(struct nand_chip *chip, unsigned int page)
|
||||||
{
|
{
|
||||||
@ -3498,10 +3518,7 @@ static void rawnand_cont_read_skip_first_page(struct nand_chip *chip, unsigned i
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
chip->cont_read.first_page++;
|
chip->cont_read.first_page++;
|
||||||
if (chip->cont_read.first_page == chip->cont_read.pause_page)
|
rawnand_cap_cont_reads(chip);
|
||||||
chip->cont_read.first_page++;
|
|
||||||
if (chip->cont_read.first_page >= chip->cont_read.last_page)
|
|
||||||
chip->cont_read.ongoing = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3577,6 +3594,7 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
|
|||||||
oob = ops->oobbuf;
|
oob = ops->oobbuf;
|
||||||
oob_required = oob ? 1 : 0;
|
oob_required = oob ? 1 : 0;
|
||||||
|
|
||||||
|
if (likely(ops->mode != MTD_OPS_RAW))
|
||||||
rawnand_enable_cont_reads(chip, page, readlen, col);
|
rawnand_enable_cont_reads(chip, page, readlen, col);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -3710,6 +3728,9 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
|
|||||||
}
|
}
|
||||||
nand_deselect_target(chip);
|
nand_deselect_target(chip);
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(chip->cont_read.ongoing))
|
||||||
|
chip->cont_read.ongoing = false;
|
||||||
|
|
||||||
ops->retlen = ops->len - (size_t) readlen;
|
ops->retlen = ops->len - (size_t) readlen;
|
||||||
if (oob)
|
if (oob)
|
||||||
ops->oobretlen = ops->ooblen - oobreadlen;
|
ops->oobretlen = ops->ooblen - oobreadlen;
|
||||||
@ -5195,6 +5216,15 @@ static void rawnand_late_check_supported_ops(struct nand_chip *chip)
|
|||||||
if (!nand_has_exec_op(chip))
|
if (!nand_has_exec_op(chip))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For now, continuous reads can only be used with the core page helpers.
|
||||||
|
* This can be extended later.
|
||||||
|
*/
|
||||||
|
if (!(chip->ecc.read_page == nand_read_page_hwecc ||
|
||||||
|
chip->ecc.read_page == nand_read_page_syndrome ||
|
||||||
|
chip->ecc.read_page == nand_read_page_swecc))
|
||||||
|
return;
|
||||||
|
|
||||||
rawnand_check_cont_read_support(chip);
|
rawnand_check_cont_read_support(chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,7 +576,6 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf,
|
|||||||
startblock &= bbtblocks - 1;
|
startblock &= bbtblocks - 1;
|
||||||
} else {
|
} else {
|
||||||
chips = 1;
|
chips = 1;
|
||||||
bbtblocks = mtd->size >> this->bbt_erase_shift;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < chips; i++) {
|
for (i = 0; i < chips; i++) {
|
||||||
|
@ -31,7 +31,6 @@ struct hynix_read_retry {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* struct hynix_nand - private Hynix NAND struct
|
* struct hynix_nand - private Hynix NAND struct
|
||||||
* @nand_technology: manufacturing process expressed in picometer
|
|
||||||
* @read_retry: read-retry information
|
* @read_retry: read-retry information
|
||||||
*/
|
*/
|
||||||
struct hynix_nand {
|
struct hynix_nand {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mtd/rawnand.h>
|
#include <linux/mtd/rawnand.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
@ -37,7 +38,7 @@
|
|||||||
#define FMC2_MAX_SG 16
|
#define FMC2_MAX_SG 16
|
||||||
|
|
||||||
/* Max chip enable */
|
/* Max chip enable */
|
||||||
#define FMC2_MAX_CE 2
|
#define FMC2_MAX_CE 4
|
||||||
|
|
||||||
/* Max ECC buffer length */
|
/* Max ECC buffer length */
|
||||||
#define FMC2_MAX_ECC_BUF_LEN (FMC2_BCHDSRS_LEN * FMC2_MAX_SG)
|
#define FMC2_MAX_ECC_BUF_LEN (FMC2_BCHDSRS_LEN * FMC2_MAX_SG)
|
||||||
@ -243,6 +244,13 @@ static inline struct stm32_fmc2_nand *to_fmc2_nand(struct nand_chip *chip)
|
|||||||
return container_of(chip, struct stm32_fmc2_nand, chip);
|
return container_of(chip, struct stm32_fmc2_nand, chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct stm32_fmc2_nfc;
|
||||||
|
|
||||||
|
struct stm32_fmc2_nfc_data {
|
||||||
|
int max_ncs;
|
||||||
|
int (*set_cdev)(struct stm32_fmc2_nfc *nfc);
|
||||||
|
};
|
||||||
|
|
||||||
struct stm32_fmc2_nfc {
|
struct stm32_fmc2_nfc {
|
||||||
struct nand_controller base;
|
struct nand_controller base;
|
||||||
struct stm32_fmc2_nand nand;
|
struct stm32_fmc2_nand nand;
|
||||||
@ -256,6 +264,7 @@ struct stm32_fmc2_nfc {
|
|||||||
phys_addr_t data_phys_addr[FMC2_MAX_CE];
|
phys_addr_t data_phys_addr[FMC2_MAX_CE];
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
u8 irq_state;
|
u8 irq_state;
|
||||||
|
const struct stm32_fmc2_nfc_data *data;
|
||||||
|
|
||||||
struct dma_chan *dma_tx_ch;
|
struct dma_chan *dma_tx_ch;
|
||||||
struct dma_chan *dma_rx_ch;
|
struct dma_chan *dma_rx_ch;
|
||||||
@ -264,6 +273,8 @@ struct stm32_fmc2_nfc {
|
|||||||
struct sg_table dma_ecc_sg;
|
struct sg_table dma_ecc_sg;
|
||||||
u8 *ecc_buf;
|
u8 *ecc_buf;
|
||||||
int dma_ecc_len;
|
int dma_ecc_len;
|
||||||
|
u32 tx_dma_max_burst;
|
||||||
|
u32 rx_dma_max_burst;
|
||||||
|
|
||||||
struct completion complete;
|
struct completion complete;
|
||||||
struct completion dma_data_complete;
|
struct completion dma_data_complete;
|
||||||
@ -347,20 +358,26 @@ static int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr)
|
|||||||
stm32_fmc2_nfc_setup(chip);
|
stm32_fmc2_nfc_setup(chip);
|
||||||
stm32_fmc2_nfc_timings_init(chip);
|
stm32_fmc2_nfc_timings_init(chip);
|
||||||
|
|
||||||
if (nfc->dma_tx_ch && nfc->dma_rx_ch) {
|
if (nfc->dma_tx_ch) {
|
||||||
memset(&dma_cfg, 0, sizeof(dma_cfg));
|
memset(&dma_cfg, 0, sizeof(dma_cfg));
|
||||||
dma_cfg.src_addr = nfc->data_phys_addr[nfc->cs_sel];
|
|
||||||
dma_cfg.dst_addr = nfc->data_phys_addr[nfc->cs_sel];
|
dma_cfg.dst_addr = nfc->data_phys_addr[nfc->cs_sel];
|
||||||
dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
|
||||||
dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||||
dma_cfg.src_maxburst = 32;
|
dma_cfg.dst_maxburst = nfc->tx_dma_max_burst /
|
||||||
dma_cfg.dst_maxburst = 32;
|
dma_cfg.dst_addr_width;
|
||||||
|
|
||||||
ret = dmaengine_slave_config(nfc->dma_tx_ch, &dma_cfg);
|
ret = dmaengine_slave_config(nfc->dma_tx_ch, &dma_cfg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(nfc->dev, "tx DMA engine slave config failed\n");
|
dev_err(nfc->dev, "tx DMA engine slave config failed\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nfc->dma_rx_ch) {
|
||||||
|
memset(&dma_cfg, 0, sizeof(dma_cfg));
|
||||||
|
dma_cfg.src_addr = nfc->data_phys_addr[nfc->cs_sel];
|
||||||
|
dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||||
|
dma_cfg.src_maxburst = nfc->rx_dma_max_burst /
|
||||||
|
dma_cfg.src_addr_width;
|
||||||
|
|
||||||
ret = dmaengine_slave_config(nfc->dma_rx_ch, &dma_cfg);
|
ret = dmaengine_slave_config(nfc->dma_rx_ch, &dma_cfg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -1545,6 +1562,7 @@ static int stm32_fmc2_nfc_setup_interface(struct nand_chip *chip, int chipnr,
|
|||||||
|
|
||||||
static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc)
|
static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc)
|
||||||
{
|
{
|
||||||
|
struct dma_slave_caps caps;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
nfc->dma_tx_ch = dma_request_chan(nfc->dev, "tx");
|
nfc->dma_tx_ch = dma_request_chan(nfc->dev, "tx");
|
||||||
@ -1557,6 +1575,11 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc)
|
|||||||
goto err_dma;
|
goto err_dma;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = dma_get_slave_caps(nfc->dma_tx_ch, &caps);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
nfc->tx_dma_max_burst = caps.max_burst;
|
||||||
|
|
||||||
nfc->dma_rx_ch = dma_request_chan(nfc->dev, "rx");
|
nfc->dma_rx_ch = dma_request_chan(nfc->dev, "rx");
|
||||||
if (IS_ERR(nfc->dma_rx_ch)) {
|
if (IS_ERR(nfc->dma_rx_ch)) {
|
||||||
ret = PTR_ERR(nfc->dma_rx_ch);
|
ret = PTR_ERR(nfc->dma_rx_ch);
|
||||||
@ -1567,6 +1590,11 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc)
|
|||||||
goto err_dma;
|
goto err_dma;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = dma_get_slave_caps(nfc->dma_rx_ch, &caps);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
nfc->rx_dma_max_burst = caps.max_burst;
|
||||||
|
|
||||||
nfc->dma_ecc_ch = dma_request_chan(nfc->dev, "ecc");
|
nfc->dma_ecc_ch = dma_request_chan(nfc->dev, "ecc");
|
||||||
if (IS_ERR(nfc->dma_ecc_ch)) {
|
if (IS_ERR(nfc->dma_ecc_ch)) {
|
||||||
ret = PTR_ERR(nfc->dma_ecc_ch);
|
ret = PTR_ERR(nfc->dma_ecc_ch);
|
||||||
@ -1790,7 +1818,7 @@ static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cs >= FMC2_MAX_CE) {
|
if (cs >= nfc->data->max_ncs) {
|
||||||
dev_err(nfc->dev, "invalid reg value: %d\n", cs);
|
dev_err(nfc->dev, "invalid reg value: %d\n", cs);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -1896,9 +1924,17 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
|
|||||||
nand_controller_init(&nfc->base);
|
nand_controller_init(&nfc->base);
|
||||||
nfc->base.ops = &stm32_fmc2_nfc_controller_ops;
|
nfc->base.ops = &stm32_fmc2_nfc_controller_ops;
|
||||||
|
|
||||||
ret = stm32_fmc2_nfc_set_cdev(nfc);
|
nfc->data = of_device_get_match_data(dev);
|
||||||
|
if (!nfc->data)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (nfc->data->set_cdev) {
|
||||||
|
ret = nfc->data->set_cdev(nfc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
} else {
|
||||||
|
nfc->cdev = dev->parent;
|
||||||
|
}
|
||||||
|
|
||||||
ret = stm32_fmc2_nfc_parse_dt(nfc);
|
ret = stm32_fmc2_nfc_parse_dt(nfc);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1917,7 +1953,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
|
|||||||
if (nfc->dev == nfc->cdev)
|
if (nfc->dev == nfc->cdev)
|
||||||
start_region = 1;
|
start_region = 1;
|
||||||
|
|
||||||
for (chip_cs = 0, mem_region = start_region; chip_cs < FMC2_MAX_CE;
|
for (chip_cs = 0, mem_region = start_region; chip_cs < nfc->data->max_ncs;
|
||||||
chip_cs++, mem_region += 3) {
|
chip_cs++, mem_region += 3) {
|
||||||
if (!(nfc->cs_assigned & BIT(chip_cs)))
|
if (!(nfc->cs_assigned & BIT(chip_cs)))
|
||||||
continue;
|
continue;
|
||||||
@ -2073,7 +2109,7 @@ static int __maybe_unused stm32_fmc2_nfc_resume(struct device *dev)
|
|||||||
|
|
||||||
stm32_fmc2_nfc_wp_disable(nand);
|
stm32_fmc2_nfc_wp_disable(nand);
|
||||||
|
|
||||||
for (chip_cs = 0; chip_cs < FMC2_MAX_CE; chip_cs++) {
|
for (chip_cs = 0; chip_cs < nfc->data->max_ncs; chip_cs++) {
|
||||||
if (!(nfc->cs_assigned & BIT(chip_cs)))
|
if (!(nfc->cs_assigned & BIT(chip_cs)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -2086,9 +2122,28 @@ static int __maybe_unused stm32_fmc2_nfc_resume(struct device *dev)
|
|||||||
static SIMPLE_DEV_PM_OPS(stm32_fmc2_nfc_pm_ops, stm32_fmc2_nfc_suspend,
|
static SIMPLE_DEV_PM_OPS(stm32_fmc2_nfc_pm_ops, stm32_fmc2_nfc_suspend,
|
||||||
stm32_fmc2_nfc_resume);
|
stm32_fmc2_nfc_resume);
|
||||||
|
|
||||||
|
static const struct stm32_fmc2_nfc_data stm32_fmc2_nfc_mp1_data = {
|
||||||
|
.max_ncs = 2,
|
||||||
|
.set_cdev = stm32_fmc2_nfc_set_cdev,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct stm32_fmc2_nfc_data stm32_fmc2_nfc_mp25_data = {
|
||||||
|
.max_ncs = 4,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id stm32_fmc2_nfc_match[] = {
|
static const struct of_device_id stm32_fmc2_nfc_match[] = {
|
||||||
{.compatible = "st,stm32mp15-fmc2"},
|
{
|
||||||
{.compatible = "st,stm32mp1-fmc2-nfc"},
|
.compatible = "st,stm32mp15-fmc2",
|
||||||
|
.data = &stm32_fmc2_nfc_mp1_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "st,stm32mp1-fmc2-nfc",
|
||||||
|
.data = &stm32_fmc2_nfc_mp1_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "st,stm32mp25-fmc2-nfc",
|
||||||
|
.data = &stm32_fmc2_nfc_mp25_data,
|
||||||
|
},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match);
|
MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match);
|
||||||
|
@ -104,7 +104,8 @@ static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
|
|||||||
|
|
||||||
static const struct spinand_info esmt_c8_spinand_table[] = {
|
static const struct spinand_info esmt_c8_spinand_table[] = {
|
||||||
SPINAND_INFO("F50L1G41LB",
|
SPINAND_INFO("F50L1G41LB",
|
||||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
|
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f,
|
||||||
|
0x7f, 0x7f),
|
||||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||||
NAND_ECCREQ(1, 512),
|
NAND_ECCREQ(1, 512),
|
||||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||||
@ -113,7 +114,8 @@ static const struct spinand_info esmt_c8_spinand_table[] = {
|
|||||||
0,
|
0,
|
||||||
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
|
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
|
||||||
SPINAND_INFO("F50D1G41LB",
|
SPINAND_INFO("F50D1G41LB",
|
||||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11),
|
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11, 0x7f,
|
||||||
|
0x7f, 0x7f),
|
||||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||||
NAND_ECCREQ(1, 512),
|
NAND_ECCREQ(1, 512),
|
||||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||||
@ -122,7 +124,8 @@ static const struct spinand_info esmt_c8_spinand_table[] = {
|
|||||||
0,
|
0,
|
||||||
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
|
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
|
||||||
SPINAND_INFO("F50D2G41KA",
|
SPINAND_INFO("F50D2G41KA",
|
||||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51),
|
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51, 0x7f,
|
||||||
|
0x7f, 0x7f),
|
||||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
|
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
|
||||||
NAND_ECCREQ(8, 512),
|
NAND_ECCREQ(8, 512),
|
||||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
#define WINBOND_CFG_BUF_READ BIT(3)
|
#define WINBOND_CFG_BUF_READ BIT(3)
|
||||||
|
|
||||||
|
#define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4)
|
||||||
|
|
||||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||||
@ -118,6 +120,7 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
|
|||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
|
|
||||||
case STATUS_ECC_HAS_BITFLIPS:
|
case STATUS_ECC_HAS_BITFLIPS:
|
||||||
|
case W25N04KV_STATUS_ECC_5_8_BITFLIPS:
|
||||||
/*
|
/*
|
||||||
* Let's try to retrieve the real maximum number of bitflips
|
* Let's try to retrieve the real maximum number of bitflips
|
||||||
* in order to avoid forcing the wear-leveling layer to move
|
* in order to avoid forcing the wear-leveling layer to move
|
||||||
@ -214,6 +217,15 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||||||
&update_cache_variants),
|
&update_cache_variants),
|
||||||
0,
|
0,
|
||||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, w25n02kv_ecc_get_status)),
|
SPINAND_ECCINFO(&w25m02gv_ooblayout, w25n02kv_ecc_get_status)),
|
||||||
|
SPINAND_INFO("W25N04KV",
|
||||||
|
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
|
||||||
|
NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1),
|
||||||
|
NAND_ECCREQ(8, 512),
|
||||||
|
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||||
|
&write_cache_variants,
|
||||||
|
&update_cache_variants),
|
||||||
|
0,
|
||||||
|
SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int winbond_spinand_init(struct spinand_device *spinand)
|
static int winbond_spinand_init(struct spinand_device *spinand)
|
||||||
|
@ -169,7 +169,7 @@
|
|||||||
struct spinand_op;
|
struct spinand_op;
|
||||||
struct spinand_device;
|
struct spinand_device;
|
||||||
|
|
||||||
#define SPINAND_MAX_ID_LEN 4
|
#define SPINAND_MAX_ID_LEN 5
|
||||||
/*
|
/*
|
||||||
* For erase, write and read operation, we got the following timings :
|
* For erase, write and read operation, we got the following timings :
|
||||||
* tBERS (erase) 1ms to 4ms
|
* tBERS (erase) 1ms to 4ms
|
||||||
|
Loading…
Reference in New Issue
Block a user