mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-04 04:06:26 +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,sama5d2-pmecc"
|
||||
"microchip,sam9x60-pmecc"
|
||||
"microchip,sam9x7-pmecc", "atmel,at91sam9g45-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.
|
||||
|
||||
|
@ -9,6 +9,7 @@ title: Broadcom STB NAND Controller
|
||||
maintainers:
|
||||
- Brian Norris <computersforpeace@gmail.com>
|
||||
- Kamal Dasu <kdasu.kdev@gmail.com>
|
||||
- William Zhang <william.zhang@broadcom.com>
|
||||
|
||||
description: |
|
||||
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.
|
||||
|
||||
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.
|
||||
available on a variety of Broadcom SoCs, including some BCM3xxx, MIPS based
|
||||
Broadband SoC (BCM63xx), ARM based Broadband SoC (BCMBCA) and iProc/Cygnus.
|
||||
Its history includes several similar (but not fully register compatible)
|
||||
versions.
|
||||
|
||||
-- Additional SoC-specific NAND controller properties --
|
||||
|
||||
@ -53,7 +55,7 @@ properties:
|
||||
- brcm,brcmnand-v7.2
|
||||
- brcm,brcmnand-v7.3
|
||||
- const: brcm,brcmnand
|
||||
- description: BCM63138 SoC-specific NAND controller
|
||||
- description: BCMBCA SoC-specific NAND controller
|
||||
items:
|
||||
- const: brcm,nand-bcm63138
|
||||
- enum:
|
||||
@ -111,6 +113,13 @@ properties:
|
||||
earlier versions of this core that include WP
|
||||
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:
|
||||
"^nand@[a-f0-9]$":
|
||||
type: object
|
||||
@ -137,6 +146,15 @@ patternProperties:
|
||||
layout.
|
||||
$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
|
||||
|
||||
allOf:
|
||||
@ -177,6 +195,8 @@ allOf:
|
||||
- const: iproc-idm
|
||||
- const: iproc-ext
|
||||
- if:
|
||||
required:
|
||||
- interrupts
|
||||
properties:
|
||||
interrupts:
|
||||
minItems: 2
|
||||
@ -184,12 +204,26 @@ allOf:
|
||||
required:
|
||||
- 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
|
||||
|
||||
required:
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
@ -14,10 +14,11 @@ properties:
|
||||
enum:
|
||||
- st,stm32mp15-fmc2
|
||||
- st,stm32mp1-fmc2-nfc
|
||||
- st,stm32mp25-fmc2-nfc
|
||||
|
||||
reg:
|
||||
minItems: 6
|
||||
maxItems: 7
|
||||
maxItems: 12
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
@ -92,6 +93,28 @@ allOf:
|
||||
- description: Chip select 1 command
|
||||
- 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:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -138,6 +138,20 @@ hsspi: spi@1000 {
|
||||
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 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
|
@ -229,7 +229,12 @@ nand_controller: nand-controller@2000 {
|
||||
reg-names = "nand", "nand-int-base";
|
||||
status = "disabled";
|
||||
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 {
|
||||
|
@ -119,5 +119,19 @@ hsspi: spi@1000 {
|
||||
num-cs = <8>;
|
||||
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";
|
||||
};
|
||||
|
||||
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 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
|
@ -139,6 +139,20 @@ hsspi: spi@1000 {
|
||||
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 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
|
@ -119,5 +119,19 @@ hsspi: spi@1000 {
|
||||
num-cs = <8>;
|
||||
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";
|
||||
};
|
||||
|
||||
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 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
|
@ -120,6 +120,20 @@ hsspi: spi@1000 {
|
||||
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 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
|
@ -32,3 +32,13 @@ &uart0 {
|
||||
&hsspi {
|
||||
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 {
|
||||
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 {
|
||||
brcm,wp-not-connected;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
nand@0 {
|
||||
compatible = "brcm,nandcs";
|
||||
reg = <0>;
|
||||
nand-ecc-strength = <4>;
|
||||
nand-ecc-step-size = <512>;
|
||||
brcm,nand-oob-sectors-size = <16>;
|
||||
};
|
||||
&nandcs {
|
||||
nand-ecc-strength = <4>;
|
||||
nand-ecc-step-size = <512>;
|
||||
brcm,nand-oob-sector-size = <16>;
|
||||
nand-on-flash-bbt;
|
||||
};
|
||||
|
||||
&ahci {
|
||||
|
@ -32,3 +32,13 @@ &uart0 {
|
||||
&hsspi {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
nand-ecc-strength = <4>;
|
||||
nand-ecc-step-size = <512>;
|
||||
|
@ -155,6 +155,11 @@ port@7 {
|
||||
};
|
||||
};
|
||||
|
||||
&nand_controller {
|
||||
brcm,wp-not-connected;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&nandcs {
|
||||
nand-ecc-strength = <4>;
|
||||
nand-ecc-step-size = <512>;
|
||||
|
@ -166,11 +166,15 @@ led@19 {
|
||||
};
|
||||
};
|
||||
|
||||
&nand_controller {
|
||||
brcm,wp-not-connected;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&nandcs {
|
||||
nand-ecc-strength = <4>;
|
||||
nand-ecc-step-size = <512>;
|
||||
nand-on-flash-bbt;
|
||||
brcm,nand-has-wp;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -589,7 +589,7 @@ hsspi: spi@1000 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
nand-controller@1800 {
|
||||
nand_controller: nand-controller@1800 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.1", "brcm,brcmnand";
|
||||
@ -597,7 +597,7 @@ nand-controller@1800 {
|
||||
reg-names = "nand", "nand-int-base";
|
||||
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "nand_ctlrdy";
|
||||
status = "okay";
|
||||
status = "disabled";
|
||||
|
||||
nandcs: nand@0 {
|
||||
compatible = "brcm,nandcs";
|
||||
|
@ -138,6 +138,20 @@ hsspi: spi@1000 {
|
||||
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 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
|
@ -119,6 +119,20 @@ hsspi: spi@1000 {
|
||||
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 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
|
@ -137,6 +137,20 @@ hsspi: spi@1000 {
|
||||
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 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
|
@ -138,6 +138,20 @@ hsspi: spi@1000 {
|
||||
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 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x12000 0x1000>;
|
||||
|
@ -119,5 +119,19 @@ hsspi: spi@1000 {
|
||||
num-cs = <8>;
|
||||
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>;
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
* which gives:
|
||||
*
|
||||
|
@ -2,7 +2,7 @@
|
||||
# link order matters; don't link the more generic brcmstb_nand.o before the
|
||||
# more specific iproc_nand.o, for instance
|
||||
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_BRCMSTB) += brcmstb_nand.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 */
|
||||
#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)
|
||||
{
|
||||
@ -851,6 +851,20 @@ static inline u32 edu_readl(struct brcmnand_controller *ctrl,
|
||||
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)
|
||||
{
|
||||
|
||||
@ -1024,6 +1038,22 @@ static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
***********************************************************************/
|
||||
@ -1084,8 +1151,8 @@ static int bcmnand_ctrl_poll_status(struct brcmnand_host *host,
|
||||
if ((val & mask) == expected_val)
|
||||
return 0;
|
||||
|
||||
dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
|
||||
expected_val, val & mask);
|
||||
dev_err(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
|
||||
expected_val, val & mask);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@ -1690,7 +1757,7 @@ static int brcmnand_waitfunc(struct nand_chip *chip)
|
||||
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 mtd_info *mtd = nand_to_mtd(chip);
|
||||
@ -1701,7 +1768,7 @@ static u8 brcmnand_status(struct brcmnand_host *host)
|
||||
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;
|
||||
|
||||
@ -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_controller *ctrl = host->ctrl;
|
||||
int i, j, ret = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
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)) {
|
||||
brcmnand_soc_data_bus_prepare(ctrl->soc, false);
|
||||
|
||||
for (j = 0; j < FC_WORDS; j++, buf++)
|
||||
*buf = brcmnand_read_fc(ctrl, j);
|
||||
brcmnand_read_data_bus(ctrl, ctrl->nand_fc, buf, FC_WORDS);
|
||||
buf += FC_WORDS;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
mtd->ecc_stats.failed++;
|
||||
/* NAND layer expects zero on ECC errors */
|
||||
@ -2339,7 +2406,7 @@ static int brcmnand_write_oob_raw(struct nand_chip *chip, int page)
|
||||
}
|
||||
|
||||
static int brcmnand_exec_instr(struct brcmnand_host *host, int i,
|
||||
const struct nand_operation *op)
|
||||
const struct nand_operation *op)
|
||||
{
|
||||
const struct nand_op_instr *instr = &op->instrs[i];
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
@ -2353,7 +2420,7 @@ static int brcmnand_exec_instr(struct brcmnand_host *host, int i,
|
||||
* (WAITRDY excepted).
|
||||
*/
|
||||
last_op = ((i == (op->ninstrs - 1)) && (instr->type != NAND_OP_WAITRDY_INSTR)) ||
|
||||
((i == (op->ninstrs - 2)) && (op->instrs[i+1].type == NAND_OP_WAITRDY_INSTR));
|
||||
((i == (op->ninstrs - 2)) && (op->instrs[i + 1].type == NAND_OP_WAITRDY_INSTR));
|
||||
|
||||
switch (instr->type) {
|
||||
case NAND_OP_CMD_INSTR:
|
||||
@ -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)
|
||||
{
|
||||
if ((op->ninstrs == 2) &&
|
||||
(op->instrs[0].type == NAND_OP_CMD_INSTR) &&
|
||||
(op->instrs[0].ctx.cmd.opcode == NAND_CMD_STATUS) &&
|
||||
(op->instrs[1].type == NAND_OP_DATA_IN_INSTR))
|
||||
if (op->ninstrs == 2 &&
|
||||
op->instrs[0].type == NAND_OP_CMD_INSTR &&
|
||||
op->instrs[0].ctx.cmd.opcode == NAND_CMD_STATUS &&
|
||||
op->instrs[1].type == NAND_OP_DATA_IN_INSTR)
|
||||
return 1;
|
||||
|
||||
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)
|
||||
{
|
||||
if ((op->ninstrs == 2) &&
|
||||
(op->instrs[0].type == NAND_OP_CMD_INSTR) &&
|
||||
(op->instrs[0].ctx.cmd.opcode == NAND_CMD_RESET) &&
|
||||
(op->instrs[1].type == NAND_OP_WAITRDY_INSTR))
|
||||
if (op->ninstrs == 2 &&
|
||||
op->instrs[0].type == NAND_OP_CMD_INSTR &&
|
||||
op->instrs[0].ctx.cmd.opcode == NAND_CMD_RESET &&
|
||||
op->instrs[1].type == NAND_OP_WAITRDY_INSTR)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@ -2433,11 +2500,14 @@ static int brcmnand_exec_op(struct nand_chip *chip,
|
||||
|
||||
if (brcmnand_op_is_status(op)) {
|
||||
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;
|
||||
}
|
||||
else if (brcmnand_op_is_reset(op)) {
|
||||
} else if (brcmnand_op_is_reset(op)) {
|
||||
ret = brcmnand_reset(host);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -2608,19 +2678,37 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
|
||||
nanddev_get_memorg(&chip->base);
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
struct brcmnand_cfg *cfg = &host->hwcfg;
|
||||
char msg[128];
|
||||
struct device_node *np = nand_get_flash_node(chip);
|
||||
u32 offs, tmp, oob_sector;
|
||||
bool use_strap = false;
|
||||
char msg[128];
|
||||
int ret;
|
||||
|
||||
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);
|
||||
if (ret) {
|
||||
/* Use detected size */
|
||||
cfg->spare_area_size = mtd->oobsize /
|
||||
(mtd->writesize >> FC_SHIFT);
|
||||
if (use_strap)
|
||||
cfg->spare_area_size = brcmnand_get_spare_size(host);
|
||||
else
|
||||
/* Use detected size */
|
||||
cfg->spare_area_size = mtd->oobsize /
|
||||
(mtd->writesize >> FC_SHIFT);
|
||||
} else {
|
||||
cfg->spare_area_size = oob_sector;
|
||||
}
|
||||
@ -3135,6 +3223,10 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
|
||||
/* Disable XOR addressing */
|
||||
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) {
|
||||
/* Permanently disable write protection */
|
||||
if (wp_on == 2)
|
||||
|
@ -24,6 +24,8 @@ struct brcmnand_soc {
|
||||
void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
|
||||
void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -869,7 +869,8 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
|
||||
struct mtd_info *mtd;
|
||||
|
||||
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;
|
||||
dev = fsl_lbc_ctrl_dev->dev;
|
||||
|
||||
|
@ -303,8 +303,9 @@ static int lpc32xx_nand_device_ready(struct nand_chip *nand_chip)
|
||||
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;
|
||||
|
||||
/* Clear interrupt flag by reading status */
|
||||
@ -780,7 +781,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
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)) {
|
||||
dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
|
||||
res = -ENXIO;
|
||||
|
@ -63,7 +63,7 @@
|
||||
#define CMDRWGEN(cmd_dir, ran, bch, short_mode, page_size, pages) \
|
||||
( \
|
||||
(cmd_dir) | \
|
||||
((ran) << 19) | \
|
||||
(ran) | \
|
||||
((bch) << 14) | \
|
||||
((short_mode) << 13) | \
|
||||
(((page_size) & 0x7f) << 6) | \
|
||||
|
@ -1356,7 +1356,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip) + nsels * sizeof(u8),
|
||||
chip = devm_kzalloc(dev, struct_size(chip, sels, nsels),
|
||||
GFP_KERNEL);
|
||||
if (!chip)
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
pages_per_lun = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun;
|
||||
first_lun = chip->cont_read.first_page / pages_per_lun;
|
||||
last_lun = chip->cont_read.last_page / pages_per_lun;
|
||||
ppl = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun;
|
||||
first_lun = chip->cont_read.first_page / ppl;
|
||||
last_lun = chip->cont_read.last_page / ppl;
|
||||
|
||||
/* Prevent sequential cache reads across LUN boundaries */
|
||||
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
|
||||
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,
|
||||
@ -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)
|
||||
return 0;
|
||||
|
||||
if (page == chip->cont_read.pause_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) {
|
||||
if (page == chip->cont_read.last_page) {
|
||||
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;
|
||||
@ -3466,30 +3480,36 @@ static void rawnand_enable_cont_reads(struct nand_chip *chip, unsigned int page,
|
||||
u32 readlen, int col)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!chip->controller->supported_op.cont_read)
|
||||
return;
|
||||
|
||||
end_page = DIV_ROUND_UP(col + readlen, mtd->writesize);
|
||||
end_col = (col + readlen) % mtd->writesize;
|
||||
|
||||
if (col)
|
||||
page++;
|
||||
|
||||
if (end_col && end_page)
|
||||
end_page--;
|
||||
|
||||
if (page + 1 > end_page)
|
||||
/*
|
||||
* Don't bother making any calculations if the length is too small.
|
||||
* Side effect: avoids possible integer underflows below.
|
||||
*/
|
||||
if (readlen < (2 * mtd->writesize))
|
||||
return;
|
||||
|
||||
chip->cont_read.first_page = page;
|
||||
chip->cont_read.last_page = end_page;
|
||||
chip->cont_read.ongoing = true;
|
||||
/* Derive the page where continuous read should start (the first full page read) */
|
||||
first_page = page;
|
||||
if (col)
|
||||
first_page++;
|
||||
|
||||
rawnand_cap_cont_reads(chip);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
chip->cont_read.first_page++;
|
||||
if (chip->cont_read.first_page == chip->cont_read.pause_page)
|
||||
chip->cont_read.first_page++;
|
||||
if (chip->cont_read.first_page >= chip->cont_read.last_page)
|
||||
chip->cont_read.ongoing = false;
|
||||
rawnand_cap_cont_reads(chip);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3577,7 +3594,8 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
|
||||
oob = ops->oobbuf;
|
||||
oob_required = oob ? 1 : 0;
|
||||
|
||||
rawnand_enable_cont_reads(chip, page, readlen, col);
|
||||
if (likely(ops->mode != MTD_OPS_RAW))
|
||||
rawnand_enable_cont_reads(chip, page, readlen, col);
|
||||
|
||||
while (1) {
|
||||
struct mtd_ecc_stats ecc_stats = mtd->ecc_stats;
|
||||
@ -3710,6 +3728,9 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
|
||||
}
|
||||
nand_deselect_target(chip);
|
||||
|
||||
if (WARN_ON_ONCE(chip->cont_read.ongoing))
|
||||
chip->cont_read.ongoing = false;
|
||||
|
||||
ops->retlen = ops->len - (size_t) readlen;
|
||||
if (oob)
|
||||
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))
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -576,7 +576,6 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf,
|
||||
startblock &= bbtblocks - 1;
|
||||
} else {
|
||||
chips = 1;
|
||||
bbtblocks = mtd->size >> this->bbt_erase_shift;
|
||||
}
|
||||
|
||||
for (i = 0; i < chips; i++) {
|
||||
|
@ -31,7 +31,6 @@ struct hynix_read_retry {
|
||||
|
||||
/**
|
||||
* struct hynix_nand - private Hynix NAND struct
|
||||
* @nand_technology: manufacturing process expressed in picometer
|
||||
* @read_retry: read-retry information
|
||||
*/
|
||||
struct hynix_nand {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -37,7 +38,7 @@
|
||||
#define FMC2_MAX_SG 16
|
||||
|
||||
/* Max chip enable */
|
||||
#define FMC2_MAX_CE 2
|
||||
#define FMC2_MAX_CE 4
|
||||
|
||||
/* Max ECC buffer length */
|
||||
#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);
|
||||
}
|
||||
|
||||
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 nand_controller base;
|
||||
struct stm32_fmc2_nand nand;
|
||||
@ -256,6 +264,7 @@ struct stm32_fmc2_nfc {
|
||||
phys_addr_t data_phys_addr[FMC2_MAX_CE];
|
||||
struct clk *clk;
|
||||
u8 irq_state;
|
||||
const struct stm32_fmc2_nfc_data *data;
|
||||
|
||||
struct dma_chan *dma_tx_ch;
|
||||
struct dma_chan *dma_rx_ch;
|
||||
@ -264,6 +273,8 @@ struct stm32_fmc2_nfc {
|
||||
struct sg_table dma_ecc_sg;
|
||||
u8 *ecc_buf;
|
||||
int dma_ecc_len;
|
||||
u32 tx_dma_max_burst;
|
||||
u32 rx_dma_max_burst;
|
||||
|
||||
struct completion 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_timings_init(chip);
|
||||
|
||||
if (nfc->dma_tx_ch && nfc->dma_rx_ch) {
|
||||
if (nfc->dma_tx_ch) {
|
||||
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.src_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 = 32;
|
||||
dma_cfg.dst_maxburst = nfc->tx_dma_max_burst /
|
||||
dma_cfg.dst_addr_width;
|
||||
|
||||
ret = dmaengine_slave_config(nfc->dma_tx_ch, &dma_cfg);
|
||||
if (ret) {
|
||||
dev_err(nfc->dev, "tx DMA engine slave config failed\n");
|
||||
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);
|
||||
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)
|
||||
{
|
||||
struct dma_slave_caps caps;
|
||||
int ret = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
if (IS_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;
|
||||
}
|
||||
|
||||
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");
|
||||
if (IS_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;
|
||||
}
|
||||
|
||||
if (cs >= FMC2_MAX_CE) {
|
||||
if (cs >= nfc->data->max_ncs) {
|
||||
dev_err(nfc->dev, "invalid reg value: %d\n", cs);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1896,9 +1924,17 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
|
||||
nand_controller_init(&nfc->base);
|
||||
nfc->base.ops = &stm32_fmc2_nfc_controller_ops;
|
||||
|
||||
ret = stm32_fmc2_nfc_set_cdev(nfc);
|
||||
if (ret)
|
||||
return ret;
|
||||
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)
|
||||
return ret;
|
||||
} else {
|
||||
nfc->cdev = dev->parent;
|
||||
}
|
||||
|
||||
ret = stm32_fmc2_nfc_parse_dt(nfc);
|
||||
if (ret)
|
||||
@ -1917,7 +1953,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
|
||||
if (nfc->dev == nfc->cdev)
|
||||
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) {
|
||||
if (!(nfc->cs_assigned & BIT(chip_cs)))
|
||||
continue;
|
||||
@ -2073,7 +2109,7 @@ static int __maybe_unused stm32_fmc2_nfc_resume(struct device *dev)
|
||||
|
||||
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)))
|
||||
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,
|
||||
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[] = {
|
||||
{.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);
|
||||
|
@ -104,7 +104,8 @@ static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
|
||||
|
||||
static const struct spinand_info esmt_c8_spinand_table[] = {
|
||||
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_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@ -113,7 +114,8 @@ static const struct spinand_info esmt_c8_spinand_table[] = {
|
||||
0,
|
||||
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
|
||||
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_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@ -122,7 +124,8 @@ static const struct spinand_info esmt_c8_spinand_table[] = {
|
||||
0,
|
||||
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
|
||||
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_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
|
@ -15,6 +15,8 @@
|
||||
|
||||
#define WINBOND_CFG_BUF_READ BIT(3)
|
||||
|
||||
#define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
@ -118,6 +120,7 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
|
||||
return -EBADMSG;
|
||||
|
||||
case STATUS_ECC_HAS_BITFLIPS:
|
||||
case W25N04KV_STATUS_ECC_5_8_BITFLIPS:
|
||||
/*
|
||||
* Let's try to retrieve the real maximum number of bitflips
|
||||
* 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),
|
||||
0,
|
||||
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)
|
||||
|
@ -169,7 +169,7 @@
|
||||
struct spinand_op;
|
||||
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 :
|
||||
* tBERS (erase) 1ms to 4ms
|
||||
|
Loading…
Reference in New Issue
Block a user