Commit 2e3036a2 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MTD updates from Miquel Raynal:
 "MTD changes:

   - parsers: ofpart: add workaround for #size-cells 0

   - dt-bindings: partitions: Fix partition node name pattern

   - dataflash: remove duplicate SPI ID table

  Raw NAND core changes:

   - Check the data only read pattern only once

   - Prepare the late addition of supported operation checks

   - Support for sequential cache reads

   - Fix nand_chip kdoc

  Raw NAND driver changes:

   - Fsl_elbc: Propagate HW ECC settings to HW

   - Marvell: Add missing layouts

   - Pasemi: Don't use static data to track per-device state

   - Sunxi:
      - Fix the size of the last OOB region
      - Remove an unnecessary check
      - Remove an unnecessary check
      - Clean up chips after failed init
      - Precompute the ECC_CTL register value
      - Embed sunxi_nand_hw_ecc by value
      - Update OOB layout to match hardware

   - tmio_nand: Remove driver

   - vf610_nfc: Use regular comments for functions

  SPI-NAND driver changes:

   - Add support for AllianceMemory AS5F34G04SND

   - Macronix: use scratch buffer for DMA operation

  NAND ECC changes:

   - Mediatek:
      - Add ECC support fot MT7986 IC
      - Add compatible for MT7986
      - dt-bindings: Split ECC engine with rawnand controller

  SPI NOR changes:

   - Misc core fixes

  SPI NOR driver changes:

   - Spansion: Minor fixes"

* tag 'mtd/for-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (33 commits)
  mtd: parsers: ofpart: add workaround for #size-cells 0
  mtd: rawnand: sunxi: Precompute the ECC_CTL register value
  mtd: rawnand: sunxi: Embed sunxi_nand_hw_ecc by value
  mtd: rawnand: sunxi: Update OOB layout to match hardware
  mtd: spi-nor: Sort headers alphabetically
  mtd: spi-nor: Fix shift-out-of-bounds in spi_nor_set_erase_type
  mtd: nand: ecc-mtk: Add ECC support fot MT7986 IC
  dt-bindings: mtd: mediatek,nand-ecc-engine: Add compatible for MT7986
  dt-bindings: mtd: Split ECC engine with rawnand controller
  mtd: rawnand: fsl_elbc: Propagate HW ECC settings to HW
  mtd: spinand: Add support for AllianceMemory AS5F34G04SND
  dt-bindings: mtd: partitions: Fix partition node name pattern
  mtd: spi-nor: Create macros to define chip IDs and geometries
  mtd: spi-nor: spansion: Make CFRx reg fields generic
  mtd: spi-nor: spansion: Consider reserved bits in CFR5 register
  mtd: spi-nor: core: fix implicit declaration warning
  mtd: spinand: macronix: use scratch buffer for DMA operation
  mtd: rawnand: Fix nand_chip kdoc
  mtd: rawnand: vf610_nfc: use regular comments for functions
  mtd: rawnand: Support for sequential cache reads
  ...
parents 60e2bf7d f4440abc
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mtd/mediatek,mtk-nfc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek(MTK) SoCs raw NAND FLASH controller (NFC)
maintainers:
- Xiangsheng Hou <xiangsheng.hou@mediatek.com>
properties:
compatible:
enum:
- mediatek,mt2701-nfc
- mediatek,mt2712-nfc
- mediatek,mt7622-nfc
reg:
items:
- description: Base physical address and size of NFI.
interrupts:
items:
- description: NFI interrupt
clocks:
items:
- description: clock used for the controller
- description: clock used for the pad
clock-names:
items:
- const: nfi_clk
- const: pad_clk
ecc-engine:
description: device-tree node of the required ECC engine.
$ref: /schemas/types.yaml#/definitions/phandle
patternProperties:
"^nand@[a-f0-9]$":
$ref: nand-chip.yaml#
unevaluatedProperties: false
properties:
reg:
maximum: 1
nand-on-flash-bbt: true
nand-ecc-mode:
const: hw
allOf:
- $ref: nand-controller.yaml#
- if:
properties:
compatible:
contains:
const: mediatek,mt2701-nfc
then:
patternProperties:
"^nand@[a-f0-9]$":
properties:
nand-ecc-step-size:
enum: [ 512, 1024 ]
nand-ecc-strength:
enum: [4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
40, 44, 48, 52, 56, 60]
- if:
properties:
compatible:
contains:
const: mediatek,mt2712-nfc
then:
patternProperties:
"^nand@[a-f0-9]$":
properties:
nand-ecc-step-size:
enum: [ 512, 1024 ]
nand-ecc-strength:
enum: [4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
40, 44, 48, 52, 56, 60, 68, 72, 80]
- if:
properties:
compatible:
contains:
const: mediatek,mt7622-nfc
then:
patternProperties:
"^nand@[a-f0-9]$":
properties:
nand-ecc-step-size:
const: 512
nand-ecc-strength:
enum: [4, 6, 8, 10, 12]
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- ecc-engine
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/mt2701-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
nand-controller@1100d000 {
compatible = "mediatek,mt2701-nfc";
reg = <0 0x1100d000 0 0x1000>;
interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_NFI>,
<&pericfg CLK_PERI_NFI_PAD>;
clock-names = "nfi_clk", "pad_clk";
ecc-engine = <&bch>;
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>;
nand-on-flash-bbt;
nand-ecc-mode = "hw";
nand-ecc-step-size = <1024>;
nand-ecc-strength = <24>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
preloader@0 {
label = "pl";
read-only;
reg = <0x0 0x400000>;
};
android@400000 {
label = "android";
reg = <0x400000 0x12c00000>;
};
};
};
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mtd/mediatek,nand-ecc-engine.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek(MTK) SoCs NAND ECC engine
maintainers:
- Xiangsheng Hou <xiangsheng.hou@mediatek.com>
description: |
MTK NAND ECC engine can cowork with MTK raw NAND and SPI NAND controller.
properties:
compatible:
enum:
- mediatek,mt2701-ecc
- mediatek,mt2712-ecc
- mediatek,mt7622-ecc
- mediatek,mt7986-ecc
reg:
items:
- description: Base physical address and size of ECC.
interrupts:
items:
- description: ECC interrupt
clocks:
maxItems: 1
clock-names:
const: nfiecc_clk
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt2701-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
bch: ecc@1100e000 {
compatible = "mediatek,mt2701-ecc";
reg = <0 0x1100e000 0 0x1000>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_NFI_ECC>;
clock-names = "nfiecc_clk";
};
};
MTK SoCs NAND FLASH controller (NFC) DT binding
This file documents the device tree bindings for MTK SoCs NAND controllers.
The functional split of the controller requires two drivers to operate:
the nand controller interface driver and the ECC engine driver.
The hardware description for both devices must be captured as device
tree nodes.
1) NFC NAND Controller Interface (NFI):
=======================================
The first part of NFC is NAND Controller Interface (NFI) HW.
Required NFI properties:
- compatible: Should be one of
"mediatek,mt2701-nfc",
"mediatek,mt2712-nfc",
"mediatek,mt7622-nfc".
- reg: Base physical address and size of NFI.
- interrupts: Interrupts of NFI.
- clocks: NFI required clocks.
- clock-names: NFI clocks internal name.
- ecc-engine: Required ECC Engine node.
- #address-cells: NAND chip index, should be 1.
- #size-cells: Should be 0.
Example:
nandc: nfi@1100d000 {
compatible = "mediatek,mt2701-nfc";
reg = <0 0x1100d000 0 0x1000>;
interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_NFI>,
<&pericfg CLK_PERI_NFI_PAD>;
clock-names = "nfi_clk", "pad_clk";
ecc-engine = <&bch>;
#address-cells = <1>;
#size-cells = <0>;
};
Platform related properties, should be set in {platform_name}.dts:
- children nodes: NAND chips.
Children nodes properties:
- reg: Chip Select Signal, default 0.
Set as reg = <0>, <1> when need 2 CS.
Optional:
- nand-on-flash-bbt: Store BBT on NAND Flash.
- nand-ecc-mode: the NAND ecc mode (check driver for supported modes)
- nand-ecc-step-size: Number of data bytes covered by a single ECC step.
valid values:
512 and 1024 on mt2701 and mt2712.
512 only on mt7622.
1024 is recommended for large page NANDs.
- nand-ecc-strength: Number of bits to correct per ECC step.
The valid values that each controller supports:
mt2701: 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28,
32, 36, 40, 44, 48, 52, 56, 60.
mt2712: 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28,
32, 36, 40, 44, 48, 52, 56, 60, 68, 72, 80.
mt7622: 4, 6, 8, 10, 12, 14, 16.
The strength should be calculated as follows:
E = (S - F) * 8 / B
S = O / (P / Q)
E : nand-ecc-strength.
S : spare size per sector.
F : FDM size, should be in the range [1,8].
It is used to store free oob data.
O : oob size.
P : page size.
Q : nand-ecc-step-size.
B : number of parity bits needed to correct
1 bitflip.
According to MTK NAND controller design,
this number depends on max ecc step size
that MTK NAND controller supports.
If max ecc step size supported is 1024,
then it should be always 14. And if max
ecc step size is 512, then it should be
always 13.
If the result does not match any one of the listed
choices above, please select the smaller valid value from
the list.
(otherwise the driver will do the adjustment at runtime)
- pinctrl-names: Default NAND pin GPIO setting name.
- pinctrl-0: GPIO setting node.
Example:
&pio {
nand_pins_default: nanddefault {
pins_dat {
pinmux = <MT2701_PIN_111_MSDC0_DAT7__FUNC_NLD7>,
<MT2701_PIN_112_MSDC0_DAT6__FUNC_NLD6>,
<MT2701_PIN_114_MSDC0_DAT4__FUNC_NLD4>,
<MT2701_PIN_118_MSDC0_DAT3__FUNC_NLD3>,
<MT2701_PIN_121_MSDC0_DAT0__FUNC_NLD0>,
<MT2701_PIN_120_MSDC0_DAT1__FUNC_NLD1>,
<MT2701_PIN_113_MSDC0_DAT5__FUNC_NLD5>,
<MT2701_PIN_115_MSDC0_RSTB__FUNC_NLD8>,
<MT2701_PIN_119_MSDC0_DAT2__FUNC_NLD2>;
input-enable;
drive-strength = <MTK_DRIVE_8mA>;
bias-pull-up;
};
pins_we {
pinmux = <MT2701_PIN_117_MSDC0_CLK__FUNC_NWEB>;
drive-strength = <MTK_DRIVE_8mA>;
bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
};
pins_ale {
pinmux = <MT2701_PIN_116_MSDC0_CMD__FUNC_NALE>;
drive-strength = <MTK_DRIVE_8mA>;
bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
};
};
};
&nandc {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&nand_pins_default>;
nand@0 {
reg = <0>;
nand-on-flash-bbt;
nand-ecc-mode = "hw";
nand-ecc-strength = <24>;
nand-ecc-step-size = <1024>;
};
};
NAND chip optional subnodes:
- Partitions, see Documentation/devicetree/bindings/mtd/mtd.yaml
Example:
nand@0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
preloader@0 {
label = "pl";
read-only;
reg = <0x00000000 0x00400000>;
};
android@00400000 {
label = "android";
reg = <0x00400000 0x12c00000>;
};
};
};
2) ECC Engine:
==============
Required BCH properties:
- compatible: Should be one of
"mediatek,mt2701-ecc",
"mediatek,mt2712-ecc",
"mediatek,mt7622-ecc".
- reg: Base physical address and size of ECC.
- interrupts: Interrupts of ECC.
- clocks: ECC required clocks.
- clock-names: ECC clocks internal name.
Example:
bch: ecc@1100e000 {
compatible = "mediatek,mt2701-ecc";
reg = <0 0x1100e000 0 0x1000>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_NFI_ECC>;
clock-names = "nfiecc_clk";
};
...@@ -32,7 +32,7 @@ properties: ...@@ -32,7 +32,7 @@ properties:
enum: [1, 2] enum: [1, 2]
patternProperties: patternProperties:
"partition(-.+|@[0-9a-f]+)": "^partition(-.+|@[0-9a-f]+)$":
$ref: partition.yaml $ref: partition.yaml
required: required:
......
...@@ -13139,7 +13139,7 @@ F: drivers/phy/ralink/phy-mt7621-pci.c ...@@ -13139,7 +13139,7 @@ F: drivers/phy/ralink/phy-mt7621-pci.c
MEDIATEK NAND CONTROLLER DRIVER MEDIATEK NAND CONTROLLER DRIVER
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
S: Orphan S: Orphan
F: Documentation/devicetree/bindings/mtd/mtk-nand.txt F: Documentation/devicetree/bindings/mtd/mediatek,mtk-nfc.yaml
F: drivers/mtd/nand/raw/mtk_* F: drivers/mtd/nand/raw/mtk_*
MEDIATEK PMIC LED DRIVER MEDIATEK PMIC LED DRIVER
......
...@@ -96,13 +96,6 @@ struct dataflash { ...@@ -96,13 +96,6 @@ struct dataflash {
struct mtd_info mtd; struct mtd_info mtd;
}; };
static const struct spi_device_id dataflash_dev_ids[] = {
{ "at45" },
{ "dataflash" },
{ },
};
MODULE_DEVICE_TABLE(spi, dataflash_dev_ids);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id dataflash_dt_ids[] = { static const struct of_device_id dataflash_dt_ids[] = {
{ .compatible = "atmel,at45", }, { .compatible = "atmel,at45", },
...@@ -939,8 +932,6 @@ static struct spi_driver dataflash_driver = { ...@@ -939,8 +932,6 @@ static struct spi_driver dataflash_driver = {
.name = "mtd_dataflash", .name = "mtd_dataflash",
.of_match_table = of_match_ptr(dataflash_dt_ids), .of_match_table = of_match_ptr(dataflash_dt_ids),
}, },
.id_table = dataflash_dev_ids,
.probe = dataflash_probe, .probe = dataflash_probe,
.remove = dataflash_remove, .remove = dataflash_remove,
.id_table = dataflash_spi_ids, .id_table = dataflash_spi_ids,
......
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
#define ECC_IDLE_REG(op) ((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE) #define ECC_IDLE_REG(op) ((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
#define ECC_CTL_REG(op) ((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON) #define ECC_CTL_REG(op) ((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
#define ECC_ERRMASK_MT7622 GENMASK(4, 0)
#define ECC_ERRMASK_MT2701 GENMASK(5, 0)
#define ECC_ERRMASK_MT2712 GENMASK(6, 0)
struct mtk_ecc_caps { struct mtk_ecc_caps {
u32 err_mask; u32 err_mask;
u32 err_shift; u32 err_shift;
...@@ -79,6 +83,10 @@ static const u8 ecc_strength_mt7622[] = { ...@@ -79,6 +83,10 @@ static const u8 ecc_strength_mt7622[] = {
4, 6, 8, 10, 12 4, 6, 8, 10, 12
}; };
static const u8 ecc_strength_mt7986[] = {
4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24
};
enum mtk_ecc_regs { enum mtk_ecc_regs {
ECC_ENCPAR00, ECC_ENCPAR00,
ECC_ENCIRQ_EN, ECC_ENCIRQ_EN,
...@@ -451,7 +459,7 @@ unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc) ...@@ -451,7 +459,7 @@ unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc)
EXPORT_SYMBOL(mtk_ecc_get_parity_bits); EXPORT_SYMBOL(mtk_ecc_get_parity_bits);
static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = { static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
.err_mask = 0x3f, .err_mask = ECC_ERRMASK_MT2701,
.err_shift = 8, .err_shift = 8,
.ecc_strength = ecc_strength_mt2701, .ecc_strength = ecc_strength_mt2701,
.ecc_regs = mt2701_ecc_regs, .ecc_regs = mt2701_ecc_regs,
...@@ -462,7 +470,7 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = { ...@@ -462,7 +470,7 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
}; };
static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = { static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
.err_mask = 0x7f, .err_mask = ECC_ERRMASK_MT2712,
.err_shift = 8, .err_shift = 8,
.ecc_strength = ecc_strength_mt2712, .ecc_strength = ecc_strength_mt2712,
.ecc_regs = mt2712_ecc_regs, .ecc_regs = mt2712_ecc_regs,
...@@ -473,7 +481,7 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = { ...@@ -473,7 +481,7 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
}; };
static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = { static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
.err_mask = 0x1f, .err_mask = ECC_ERRMASK_MT7622,
.err_shift = 5, .err_shift = 5,
.ecc_strength = ecc_strength_mt7622, .ecc_strength = ecc_strength_mt7622,
.ecc_regs = mt7622_ecc_regs, .ecc_regs = mt7622_ecc_regs,
...@@ -483,6 +491,17 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = { ...@@ -483,6 +491,17 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
.pg_irq_sel = 0, .pg_irq_sel = 0,
}; };
static const struct mtk_ecc_caps mtk_ecc_caps_mt7986 = {
.err_mask = ECC_ERRMASK_MT7622,
.err_shift = 8,
.ecc_strength = ecc_strength_mt7986,
.ecc_regs = mt2712_ecc_regs,
.num_ecc_strength = 11,
.ecc_mode_shift = 5,
.parity_bits = 14,
.pg_irq_sel = 1,
};
static const struct of_device_id mtk_ecc_dt_match[] = { static const struct of_device_id mtk_ecc_dt_match[] = {
{ {
.compatible = "mediatek,mt2701-ecc", .compatible = "mediatek,mt2701-ecc",
...@@ -493,6 +512,9 @@ static const struct of_device_id mtk_ecc_dt_match[] = { ...@@ -493,6 +512,9 @@ static const struct of_device_id mtk_ecc_dt_match[] = {
}, { }, {
.compatible = "mediatek,mt7622-ecc", .compatible = "mediatek,mt7622-ecc",
.data = &mtk_ecc_caps_mt7622, .data = &mtk_ecc_caps_mt7622,
}, {
.compatible = "mediatek,mt7986-ecc",
.data = &mtk_ecc_caps_mt7986,
}, },
{}, {},
}; };
......
...@@ -193,13 +193,6 @@ config MTD_NAND_PASEMI ...@@ -193,13 +193,6 @@ config MTD_NAND_PASEMI
Enables support for NAND Flash interface on PA Semi PWRficient Enables support for NAND Flash interface on PA Semi PWRficient
based boards based boards
config MTD_NAND_TMIO
tristate "Toshiba Mobile IO NAND controller"
depends on MFD_TMIO
help
Support for NAND flash connected to a Toshiba Mobile IO
Controller in some PDAs, including the Sharp SL6000x.
source "drivers/mtd/nand/raw/brcmnand/Kconfig" source "drivers/mtd/nand/raw/brcmnand/Kconfig"
config MTD_NAND_BCM47XXNFLASH config MTD_NAND_BCM47XXNFLASH
......
...@@ -23,7 +23,6 @@ omap2_nand-objs := omap2.o ...@@ -23,7 +23,6 @@ omap2_nand-objs := omap2.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
......
...@@ -725,6 +725,7 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip) ...@@ -725,6 +725,7 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs; struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
unsigned int al; unsigned int al;
u32 br;
/* /*
* if ECC was not chosen in DT, decide whether to use HW or SW ECC from * if ECC was not chosen in DT, decide whether to use HW or SW ECC from
...@@ -764,6 +765,13 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip) ...@@ -764,6 +765,13 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
return -EINVAL; return -EINVAL;
} }
/* enable/disable HW ECC checking and generating based on if HW ECC was chosen */
br = in_be32(&lbc->bank[priv->bank].br) & ~BR_DECC;
if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
out_be32(&lbc->bank[priv->bank].br, br | BR_DECC_CHK_GEN);
else
out_be32(&lbc->bank[priv->bank].br, br | BR_DECC_OFF);
/* calculate FMR Address Length field */ /* calculate FMR Address Length field */
al = 0; al = 0;
if (chip->pagemask & 0xffff0000) if (chip->pagemask & 0xffff0000)
......
...@@ -288,10 +288,17 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = { ...@@ -288,10 +288,17 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
MARVELL_LAYOUT( 2048, 512, 1, 1, 1, 2048, 40, 24, 0, 0, 0), MARVELL_LAYOUT( 2048, 512, 1, 1, 1, 2048, 40, 24, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0), MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30), MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30),
MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,64, 30),
MARVELL_LAYOUT( 2048, 512, 12, 3, 2, 704, 0, 30,640, 0, 30),
MARVELL_LAYOUT( 2048, 512, 16, 5, 4, 512, 0, 30, 0, 32, 30),
MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0), MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0),
MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30), MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30),
MARVELL_LAYOUT( 4096, 512, 12, 6, 5, 704, 0, 30,576, 32, 30),
MARVELL_LAYOUT( 4096, 512, 16, 9, 8, 512, 0, 30, 0, 32, 30),
MARVELL_LAYOUT( 8192, 512, 4, 4, 4, 2048, 0, 30, 0, 0, 0), MARVELL_LAYOUT( 8192, 512, 4, 4, 4, 2048, 0, 30, 0, 0, 0),
MARVELL_LAYOUT( 8192, 512, 8, 9, 8, 1024, 0, 30, 0, 160, 30), MARVELL_LAYOUT( 8192, 512, 8, 9, 8, 1024, 0, 30, 0, 160, 30),
MARVELL_LAYOUT( 8192, 512, 12, 12, 11, 704, 0, 30,448, 64, 30),
MARVELL_LAYOUT( 8192, 512, 16, 17, 16, 512, 0, 30, 0, 32, 30),
}; };
/** /**
......
...@@ -1208,6 +1208,73 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page, ...@@ -1208,6 +1208,73 @@ 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 int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf,
unsigned int len, bool check_only)
{
const struct nand_interface_config *conf =
nand_get_interface_config(chip);
u8 addrs[5];
struct nand_op_instr start_instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
NAND_OP_ADDR(4, addrs, 0),
NAND_OP_CMD(NAND_CMD_READSTART, NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max), 0),
NAND_OP_CMD(NAND_CMD_READCACHESEQ, NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_op_instr cont_instrs[] = {
NAND_OP_CMD(page == chip->cont_read.last_page ?
NAND_CMD_READCACHEEND : NAND_CMD_READCACHESEQ,
NAND_COMMON_TIMING_NS(conf, tWB_max)),
NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_operation start_op = NAND_OPERATION(chip->cur_cs, start_instrs);
struct nand_operation cont_op = NAND_OPERATION(chip->cur_cs, cont_instrs);
int ret;
if (!len) {
start_op.ninstrs--;
cont_op.ninstrs--;
}
ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
if (ret < 0)
return ret;
addrs[2] = page;
addrs[3] = page >> 8;
if (chip->options & NAND_ROW_ADDR_3) {
addrs[4] = page >> 16;
start_instrs[1].ctx.addr.naddrs++;
}
/* Check if cache reads are supported */
if (check_only) {
if (nand_check_op(chip, &start_op) || nand_check_op(chip, &cont_op))
return -EOPNOTSUPP;
return 0;
}
if (page == chip->cont_read.first_page)
return nand_exec_op(chip, &start_op);
else
return nand_exec_op(chip, &cont_op);
}
static bool rawnand_cont_read_ongoing(struct nand_chip *chip, unsigned int page)
{
return chip->cont_read.ongoing &&
page >= chip->cont_read.first_page &&
page <= chip->cont_read.last_page;
}
/** /**
* nand_read_page_op - Do a READ PAGE operation * nand_read_page_op - Do a READ PAGE operation
* @chip: The NAND chip * @chip: The NAND chip
...@@ -1233,10 +1300,16 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page, ...@@ -1233,10 +1300,16 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page,
return -EINVAL; return -EINVAL;
if (nand_has_exec_op(chip)) { if (nand_has_exec_op(chip)) {
if (mtd->writesize > 512) if (mtd->writesize > 512) {
if (rawnand_cont_read_ongoing(chip, page))
return nand_lp_exec_cont_read_page_op(chip, page,
offset_in_page,
buf, len, false);
else
return nand_lp_exec_read_page_op(chip, page, return nand_lp_exec_read_page_op(chip, page,
offset_in_page, buf, offset_in_page, buf,
len); len);
}
return nand_sp_exec_read_page_op(chip, page, offset_in_page, return nand_sp_exec_read_page_op(chip, page, offset_in_page,
buf, len); buf, len);
...@@ -3353,6 +3426,27 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, ...@@ -3353,6 +3426,27 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
return NULL; return NULL;
} }
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);
if (!chip->controller->supported_op.cont_read)
return;
if ((col && col + readlen < (3 * mtd->writesize)) ||
(!col && readlen < (2 * mtd->writesize))) {
chip->cont_read.ongoing = false;
return;
}
chip->cont_read.ongoing = true;
chip->cont_read.first_page = page;
if (col)
chip->cont_read.first_page++;
chip->cont_read.last_page = page + ((readlen >> chip->page_shift) & chip->pagemask);
}
/** /**
* nand_setup_read_retry - [INTERN] Set the READ RETRY mode * nand_setup_read_retry - [INTERN] Set the READ RETRY mode
* @chip: NAND chip object * @chip: NAND chip object
...@@ -3426,6 +3520,8 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from, ...@@ -3426,6 +3520,8 @@ 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;
rawnand_enable_cont_reads(chip, page, readlen, col);
while (1) { while (1) {
struct mtd_ecc_stats ecc_stats = mtd->ecc_stats; struct mtd_ecc_stats ecc_stats = mtd->ecc_stats;
...@@ -4991,6 +5087,47 @@ nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc) ...@@ -4991,6 +5087,47 @@ nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc)
return manufacturer_desc ? manufacturer_desc->name : "Unknown"; return manufacturer_desc ? manufacturer_desc->name : "Unknown";
} }
static void rawnand_check_data_only_read_support(struct nand_chip *chip)
{
/* Use an arbitrary size for the check */
if (!nand_read_data_op(chip, NULL, SZ_512, true, true))
chip->controller->supported_op.data_only_read = 1;
}
static void rawnand_early_check_supported_ops(struct nand_chip *chip)
{
/* The supported_op fields should not be set by individual drivers */
WARN_ON_ONCE(chip->controller->supported_op.data_only_read);
if (!nand_has_exec_op(chip))
return;
rawnand_check_data_only_read_support(chip);
}
static void rawnand_check_cont_read_support(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (chip->read_retries)
return;
if (!nand_lp_exec_cont_read_page_op(chip, 0, 0, NULL,
mtd->writesize, true))
chip->controller->supported_op.cont_read = 1;
}
static void rawnand_late_check_supported_ops(struct nand_chip *chip)
{
/* The supported_op fields should not be set by individual drivers */
WARN_ON_ONCE(chip->controller->supported_op.cont_read);
if (!nand_has_exec_op(chip))
return;
rawnand_check_cont_read_support(chip);
}
/* /*
* Get the flash and manufacturer id and lookup if the type is supported. * Get the flash and manufacturer id and lookup if the type is supported.
*/ */
...@@ -5023,6 +5160,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) ...@@ -5023,6 +5160,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
/* Select the device */ /* Select the device */
nand_select_target(chip, 0); nand_select_target(chip, 0);
rawnand_early_check_supported_ops(chip);
/* Send the command for reading device ID */ /* Send the command for reading device ID */
ret = nand_readid_op(chip, 0, id_data, 2); ret = nand_readid_op(chip, 0, id_data, 2);
if (ret) if (ret)
...@@ -6325,6 +6464,8 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -6325,6 +6464,8 @@ static int nand_scan_tail(struct nand_chip *chip)
goto err_free_interface_config; goto err_free_interface_config;
} }
rawnand_late_check_supported_ops(chip);
/* /*
* Look for secure regions in the NAND chip. These regions are supposed * Look for secure regions in the NAND chip. These regions are supposed
* to be protected by a secure element like Trustzone. So the read/write * to be protected by a secure element like Trustzone. So the read/write
......
...@@ -46,8 +46,7 @@ int nand_jedec_detect(struct nand_chip *chip) ...@@ -46,8 +46,7 @@ int nand_jedec_detect(struct nand_chip *chip)
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
if (!nand_has_exec_op(chip) || if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read)
!nand_read_data_op(chip, p, sizeof(*p), true, true))
use_datain = true; use_datain = true;
for (i = 0; i < JEDEC_PARAM_PAGES; i++) { for (i = 0; i < JEDEC_PARAM_PAGES; i++) {
......
...@@ -166,8 +166,7 @@ int nand_onfi_detect(struct nand_chip *chip) ...@@ -166,8 +166,7 @@ int nand_onfi_detect(struct nand_chip *chip)
if (!pbuf) if (!pbuf)
return -ENOMEM; return -ENOMEM;
if (!nand_has_exec_op(chip) || if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read)
!nand_read_data_op(chip, &pbuf[0], sizeof(*pbuf), true, true))
use_datain = true; use_datain = true;
for (i = 0; i < ONFI_PARAM_PAGES; i++) { for (i = 0; i < ONFI_PARAM_PAGES; i++) {
......
...@@ -26,9 +26,12 @@ ...@@ -26,9 +26,12 @@
#define CLE_PIN_CTL 15 #define CLE_PIN_CTL 15
#define ALE_PIN_CTL 14 #define ALE_PIN_CTL 14
static unsigned int lpcctl; struct pasemi_ddata {
static struct mtd_info *pasemi_nand_mtd; struct nand_chip chip;
static struct nand_controller controller; unsigned int lpcctl;
struct nand_controller controller;
};
static const char driver_name[] = "pasemi-nand"; static const char driver_name[] = "pasemi-nand";
static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len) static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len)
...@@ -55,6 +58,8 @@ static void pasemi_write_buf(struct nand_chip *chip, const u_char *buf, ...@@ -55,6 +58,8 @@ static void pasemi_write_buf(struct nand_chip *chip, const u_char *buf,
static void pasemi_hwcontrol(struct nand_chip *chip, int cmd, static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl) unsigned int ctrl)
{ {
struct pasemi_ddata *ddata = container_of(chip, struct pasemi_ddata, chip);
if (cmd == NAND_CMD_NONE) if (cmd == NAND_CMD_NONE)
return; return;
...@@ -65,12 +70,14 @@ static void pasemi_hwcontrol(struct nand_chip *chip, int cmd, ...@@ -65,12 +70,14 @@ static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
/* Push out posted writes */ /* Push out posted writes */
eieio(); eieio();
inl(lpcctl); inl(ddata->lpcctl);
} }
static int pasemi_device_ready(struct nand_chip *chip) static int pasemi_device_ready(struct nand_chip *chip)
{ {
return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR); struct pasemi_ddata *ddata = container_of(chip, struct pasemi_ddata, chip);
return !!(inl(ddata->lpcctl) & LBICTRL_LPCCTL_NR);
} }
static int pasemi_attach_chip(struct nand_chip *chip) static int pasemi_attach_chip(struct nand_chip *chip)
...@@ -93,29 +100,31 @@ static int pasemi_nand_probe(struct platform_device *ofdev) ...@@ -93,29 +100,31 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct resource res; struct resource res;
struct nand_chip *chip; struct nand_chip *chip;
struct nand_controller *controller;
int err = 0; int err = 0;
struct pasemi_ddata *ddata;
struct mtd_info *pasemi_nand_mtd;
err = of_address_to_resource(np, 0, &res); err = of_address_to_resource(np, 0, &res);
if (err) if (err)
return -EINVAL; return -EINVAL;
/* We only support one device at the moment */
if (pasemi_nand_mtd)
return -ENODEV;
dev_dbg(dev, "pasemi_nand at %pR\n", &res); dev_dbg(dev, "pasemi_nand at %pR\n", &res);
/* Allocate memory for MTD device structure and private data */ /* Allocate memory for MTD device structure and private data */
chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
if (!chip) { if (!ddata) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
platform_set_drvdata(ofdev, ddata);
chip = &ddata->chip;
controller = &ddata->controller;
controller.ops = &pasemi_ops; controller->ops = &pasemi_ops;
nand_controller_init(&controller); nand_controller_init(controller);
chip->controller = &controller; chip->controller = controller;
pasemi_nand_mtd = nand_to_mtd(chip); pasemi_nand_mtd = nand_to_mtd(chip);
...@@ -136,10 +145,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev) ...@@ -136,10 +145,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
goto out_ior; goto out_ior;
} }
lpcctl = pci_resource_start(pdev, 0); ddata->lpcctl = pci_resource_start(pdev, 0);
pci_dev_put(pdev); pci_dev_put(pdev);
if (!request_region(lpcctl, 4, driver_name)) { if (!request_region(ddata->lpcctl, 4, driver_name)) {
err = -EBUSY; err = -EBUSY;
goto out_ior; goto out_ior;
} }
...@@ -172,45 +181,43 @@ static int pasemi_nand_probe(struct platform_device *ofdev) ...@@ -172,45 +181,43 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
} }
dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res, dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res,
lpcctl); ddata->lpcctl);
return 0; return 0;
out_cleanup_nand: out_cleanup_nand:
nand_cleanup(chip); nand_cleanup(chip);
out_lpc: out_lpc:
release_region(lpcctl, 4); release_region(ddata->lpcctl, 4);
out_ior: out_ior:
iounmap(chip->legacy.IO_ADDR_R); iounmap(chip->legacy.IO_ADDR_R);
out_mtd: out_mtd:
kfree(chip); kfree(ddata);
out: out:
return err; return err;
} }
static int pasemi_nand_remove(struct platform_device *ofdev) static int pasemi_nand_remove(struct platform_device *ofdev)
{ {
struct nand_chip *chip; struct pasemi_ddata *ddata = platform_get_drvdata(ofdev);
struct mtd_info *pasemi_nand_mtd;
int ret; int ret;
struct nand_chip *chip;
if (!pasemi_nand_mtd) chip = &ddata->chip;
return 0; pasemi_nand_mtd = nand_to_mtd(chip);
chip = mtd_to_nand(pasemi_nand_mtd);
/* Release resources, unregister device */ /* Release resources, unregister device */
ret = mtd_device_unregister(pasemi_nand_mtd); ret = mtd_device_unregister(pasemi_nand_mtd);
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(chip); nand_cleanup(chip);
release_region(lpcctl, 4); release_region(ddata->lpcctl, 4);
iounmap(chip->legacy.IO_ADDR_R); iounmap(chip->legacy.IO_ADDR_R);
/* Free the MTD device structure */ /* Free the MTD device structure */
kfree(chip); kfree(ddata);
pasemi_nand_mtd = NULL;
return 0; return 0;
} }
......
...@@ -172,10 +172,10 @@ struct sunxi_nand_chip_sel { ...@@ -172,10 +172,10 @@ struct sunxi_nand_chip_sel {
/** /**
* struct sunxi_nand_hw_ecc - stores information related to HW ECC support * struct sunxi_nand_hw_ecc - stores information related to HW ECC support
* *
* @mode: the sunxi ECC mode field deduced from ECC requirements * @ecc_ctl: ECC_CTL register value for this NAND chip
*/ */
struct sunxi_nand_hw_ecc { struct sunxi_nand_hw_ecc {
int mode; u32 ecc_ctl;
}; };
/** /**
...@@ -193,7 +193,7 @@ struct sunxi_nand_hw_ecc { ...@@ -193,7 +193,7 @@ struct sunxi_nand_hw_ecc {
struct sunxi_nand_chip { struct sunxi_nand_chip {
struct list_head node; struct list_head node;
struct nand_chip nand; struct nand_chip nand;
struct sunxi_nand_hw_ecc *ecc; struct sunxi_nand_hw_ecc ecc;
unsigned long clk_rate; unsigned long clk_rate;
u32 timing_cfg; u32 timing_cfg;
u32 timing_ctl; u32 timing_ctl;
...@@ -421,7 +421,7 @@ static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs) ...@@ -421,7 +421,7 @@ static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
struct sunxi_nand_chip_sel *sel; struct sunxi_nand_chip_sel *sel;
u32 ctl; u32 ctl;
if (cs > 0 && cs >= sunxi_nand->nsels) if (cs >= sunxi_nand->nsels)
return; return;
ctl = readl(nfc->regs + NFC_REG_CTL) & ctl = readl(nfc->regs + NFC_REG_CTL) &
...@@ -689,26 +689,15 @@ static void sunxi_nfc_hw_ecc_enable(struct nand_chip *nand) ...@@ -689,26 +689,15 @@ static void sunxi_nfc_hw_ecc_enable(struct nand_chip *nand)
{ {
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
u32 ecc_ctl;
ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
NFC_ECC_BLOCK_SIZE_MSK);
ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(sunxi_nand->ecc->mode) |
NFC_ECC_EXCEPTION | NFC_ECC_PIPELINE;
if (nand->ecc.size == 512)
ecc_ctl |= NFC_ECC_BLOCK_512;
writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL); writel(sunxi_nand->ecc.ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
} }
static void sunxi_nfc_hw_ecc_disable(struct nand_chip *nand) static void sunxi_nfc_hw_ecc_disable(struct nand_chip *nand)
{ {
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, writel(0, nfc->regs + NFC_REG_ECC_CTL);
nfc->regs + NFC_REG_ECC_CTL);
} }
static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf) static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
...@@ -1604,12 +1593,19 @@ static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section, ...@@ -1604,12 +1593,19 @@ static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
return 0; return 0;
} }
/*
* The controller does not provide access to OOB bytes
* past the end of the ECC data.
*/
if (section == ecc->steps && ecc->engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
return -ERANGE;
oobregion->offset = section * (ecc->bytes + 4); oobregion->offset = section * (ecc->bytes + 4);
if (section < ecc->steps) if (section < ecc->steps)
oobregion->length = 4; oobregion->length = 4;
else else
oobregion->offset = mtd->oobsize - oobregion->offset; oobregion->length = mtd->oobsize - oobregion->offset;
return 0; return 0;
} }
...@@ -1619,11 +1615,6 @@ static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = { ...@@ -1619,11 +1615,6 @@ static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
.free = sunxi_nand_ooblayout_free, .free = sunxi_nand_ooblayout_free,
}; };
static void sunxi_nand_hw_ecc_ctrl_cleanup(struct sunxi_nand_chip *sunxi_nand)
{
kfree(sunxi_nand->ecc);
}
static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
struct nand_ecc_ctrl *ecc, struct nand_ecc_ctrl *ecc,
struct device_node *np) struct device_node *np)
...@@ -1634,7 +1625,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, ...@@ -1634,7 +1625,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
struct mtd_info *mtd = nand_to_mtd(nand); struct mtd_info *mtd = nand_to_mtd(nand);
struct nand_device *nanddev = mtd_to_nanddev(mtd); struct nand_device *nanddev = mtd_to_nanddev(mtd);
int nsectors; int nsectors;
int ret;
int i; int i;
if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) { if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) {
...@@ -1669,10 +1659,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, ...@@ -1669,10 +1659,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
if (ecc->size != 512 && ecc->size != 1024) if (ecc->size != 512 && ecc->size != 1024)
return -EINVAL; return -EINVAL;
sunxi_nand->ecc = kzalloc(sizeof(*sunxi_nand->ecc), GFP_KERNEL);
if (!sunxi_nand->ecc)
return -ENOMEM;
/* Prefer 1k ECC chunk over 512 ones */ /* Prefer 1k ECC chunk over 512 ones */
if (ecc->size == 512 && mtd->writesize > 512) { if (ecc->size == 512 && mtd->writesize > 512) {
ecc->size = 1024; ecc->size = 1024;
...@@ -1693,12 +1679,9 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, ...@@ -1693,12 +1679,9 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
if (i >= ARRAY_SIZE(strengths)) { if (i >= ARRAY_SIZE(strengths)) {
dev_err(nfc->dev, "unsupported strength\n"); dev_err(nfc->dev, "unsupported strength\n");
ret = -ENOTSUPP; return -ENOTSUPP;
goto err;
} }
sunxi_nand->ecc->mode = i;
/* HW ECC always request ECC bytes for 1024 bytes blocks */ /* HW ECC always request ECC bytes for 1024 bytes blocks */
ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8); ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
...@@ -1707,10 +1690,8 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, ...@@ -1707,10 +1690,8 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
nsectors = mtd->writesize / ecc->size; nsectors = mtd->writesize / ecc->size;
if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) { if (mtd->oobsize < ((ecc->bytes + 4) * nsectors))
ret = -EINVAL; return -EINVAL;
goto err;
}
ecc->read_oob = sunxi_nfc_hw_ecc_read_oob; ecc->read_oob = sunxi_nfc_hw_ecc_read_oob;
ecc->write_oob = sunxi_nfc_hw_ecc_write_oob; ecc->write_oob = sunxi_nfc_hw_ecc_write_oob;
...@@ -1732,26 +1713,13 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, ...@@ -1732,26 +1713,13 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
ecc->read_oob_raw = nand_read_oob_std; ecc->read_oob_raw = nand_read_oob_std;
ecc->write_oob_raw = nand_write_oob_std; ecc->write_oob_raw = nand_write_oob_std;
return 0; sunxi_nand->ecc.ecc_ctl = NFC_ECC_MODE(i) | NFC_ECC_EXCEPTION |
NFC_ECC_PIPELINE | NFC_ECC_EN;
err:
kfree(sunxi_nand->ecc);
return ret; if (ecc->size == 512)
} sunxi_nand->ecc.ecc_ctl |= NFC_ECC_BLOCK_512;
static void sunxi_nand_ecc_cleanup(struct sunxi_nand_chip *sunxi_nand) return 0;
{
struct nand_ecc_ctrl *ecc = &sunxi_nand->nand.ecc;
switch (ecc->engine_type) {
case NAND_ECC_ENGINE_TYPE_ON_HOST:
sunxi_nand_hw_ecc_ctrl_cleanup(sunxi_nand);
break;
case NAND_ECC_ENGINE_TYPE_NONE:
default:
break;
}
} }
static int sunxi_nand_attach_chip(struct nand_chip *nand) static int sunxi_nand_attach_chip(struct nand_chip *nand)
...@@ -1950,6 +1918,24 @@ static const struct nand_controller_ops sunxi_nand_controller_ops = { ...@@ -1950,6 +1918,24 @@ static const struct nand_controller_ops sunxi_nand_controller_ops = {
.exec_op = sunxi_nfc_exec_op, .exec_op = sunxi_nfc_exec_op,
}; };
static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
{
struct sunxi_nand_chip *sunxi_nand;
struct nand_chip *chip;
int ret;
while (!list_empty(&nfc->chips)) {
sunxi_nand = list_first_entry(&nfc->chips,
struct sunxi_nand_chip,
node);
chip = &sunxi_nand->nand;
ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
nand_cleanup(chip);
list_del(&sunxi_nand->node);
}
}
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np) struct device_node *np)
{ {
...@@ -2041,18 +2027,13 @@ static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc) ...@@ -2041,18 +2027,13 @@ static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
{ {
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct device_node *nand_np; struct device_node *nand_np;
int nchips = of_get_child_count(np);
int ret; int ret;
if (nchips > 8) {
dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips);
return -EINVAL;
}
for_each_child_of_node(np, nand_np) { for_each_child_of_node(np, nand_np) {
ret = sunxi_nand_chip_init(dev, nfc, nand_np); ret = sunxi_nand_chip_init(dev, nfc, nand_np);
if (ret) { if (ret) {
of_node_put(nand_np); of_node_put(nand_np);
sunxi_nand_chips_cleanup(nfc);
return ret; return ret;
} }
} }
...@@ -2060,25 +2041,6 @@ static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc) ...@@ -2060,25 +2041,6 @@ static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
return 0; return 0;
} }
static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
{
struct sunxi_nand_chip *sunxi_nand;
struct nand_chip *chip;
int ret;
while (!list_empty(&nfc->chips)) {
sunxi_nand = list_first_entry(&nfc->chips,
struct sunxi_nand_chip,
node);
chip = &sunxi_nand->nand;
ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
nand_cleanup(chip);
sunxi_nand_ecc_cleanup(sunxi_nand);
list_del(&sunxi_nand->node);
}
}
static int sunxi_nfc_dma_init(struct sunxi_nfc *nfc, struct resource *r) static int sunxi_nfc_dma_init(struct sunxi_nfc *nfc, struct resource *r)
{ {
int ret; int ret;
......
This diff is collapsed.
...@@ -206,7 +206,7 @@ static inline bool vf610_nfc_kernel_is_little_endian(void) ...@@ -206,7 +206,7 @@ static inline bool vf610_nfc_kernel_is_little_endian(void)
#endif #endif
} }
/** /*
* Read accessor for internal SRAM buffer * Read accessor for internal SRAM buffer
* @dst: destination address in regular memory * @dst: destination address in regular memory
* @src: source address in SRAM buffer * @src: source address in SRAM buffer
...@@ -241,7 +241,7 @@ static inline void vf610_nfc_rd_from_sram(void *dst, const void __iomem *src, ...@@ -241,7 +241,7 @@ static inline void vf610_nfc_rd_from_sram(void *dst, const void __iomem *src,
} }
} }
/** /*
* Write accessor for internal SRAM buffer * Write accessor for internal SRAM buffer
* @dst: destination address in SRAM buffer * @dst: destination address in SRAM buffer
* @src: source address in regular memory * @src: source address in regular memory
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
spinand-objs := core.o ato.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o spinand-objs := core.o alliancememory.o ato.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
// SPDX-License-Identifier: GPL-2.0
/*
* Author: Mario Kicherer <dev@kicherer.org>
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_ALLIANCEMEMORY 0x52
#define AM_STATUS_ECC_BITMASK (3 << 4)
#define AM_STATUS_ECC_NONE_DETECTED (0 << 4)
#define AM_STATUS_ECC_CORRECTED (1 << 4)
#define AM_STATUS_ECC_ERRORED (2 << 4)
#define AM_STATUS_ECC_MAX_CORRECTED (3 << 4)
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
static int am_get_eccsize(struct mtd_info *mtd)
{
if (mtd->oobsize == 64)
return 0x20;
else if (mtd->oobsize == 128)
return 0x38;
else if (mtd->oobsize == 256)
return 0x70;
else
return -EINVAL;
}
static int am_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
int ecc_bytes;
ecc_bytes = am_get_eccsize(mtd);
if (ecc_bytes < 0)
return ecc_bytes;
region->offset = mtd->oobsize - ecc_bytes;
region->length = ecc_bytes;
return 0;
}
static int am_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
int ecc_bytes;
if (section)
return -ERANGE;
ecc_bytes = am_get_eccsize(mtd);
if (ecc_bytes < 0)
return ecc_bytes;
/*
* It is unclear how many bytes are used for the bad block marker. We
* reserve the common two bytes here.
*
* The free area in this kind of flash is divided into chunks where the
* first 4 bytes of each chunk are unprotected. The number of chunks
* depends on the specific model. The models with 4096+256 bytes pages
* have 8 chunks, the others 4 chunks.
*/
region->offset = 2;
region->length = mtd->oobsize - 2 - ecc_bytes;
return 0;
}
static const struct mtd_ooblayout_ops am_ooblayout = {
.ecc = am_ooblayout_ecc,
.free = am_ooblayout_free,
};
static int am_ecc_get_status(struct spinand_device *spinand, u8 status)
{
switch (status & AM_STATUS_ECC_BITMASK) {
case AM_STATUS_ECC_NONE_DETECTED:
return 0;
case AM_STATUS_ECC_CORRECTED:
/*
* use oobsize to determine the flash model and the maximum of
* correctable errors and return maximum - 1 by convention
*/
if (spinand->base.mtd.oobsize == 64)
return 3;
else
return 7;
case AM_STATUS_ECC_ERRORED:
return -EBADMSG;
case AM_STATUS_ECC_MAX_CORRECTED:
/*
* use oobsize to determine the flash model and the maximum of
* correctable errors
*/
if (spinand->base.mtd.oobsize == 64)
return 4;
else
return 8;
default:
break;
}
return -EINVAL;
}
static const struct spinand_info alliancememory_spinand_table[] = {
SPINAND_INFO("AS5F34G04SND",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x2f),
NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&am_ooblayout,
am_ecc_get_status)),
};
static const struct spinand_manufacturer_ops alliancememory_spinand_manuf_ops = {
};
const struct spinand_manufacturer alliancememory_spinand_manufacturer = {
.id = SPINAND_MFR_ALLIANCEMEMORY,
.name = "AllianceMemory",
.chips = alliancememory_spinand_table,
.nchips = ARRAY_SIZE(alliancememory_spinand_table),
.ops = &alliancememory_spinand_manuf_ops,
};
...@@ -937,6 +937,7 @@ static const struct nand_ops spinand_ops = { ...@@ -937,6 +937,7 @@ static const struct nand_ops spinand_ops = {
}; };
static const struct spinand_manufacturer *spinand_manufacturers[] = { static const struct spinand_manufacturer *spinand_manufacturers[] = {
&alliancememory_spinand_manufacturer,
&ato_spinand_manufacturer, &ato_spinand_manufacturer,
&gigadevice_spinand_manufacturer, &gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer, &macronix_spinand_manufacturer,
......
...@@ -83,9 +83,10 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand, ...@@ -83,9 +83,10 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
* in order to avoid forcing the wear-leveling layer to move * in order to avoid forcing the wear-leveling layer to move
* data around if it's not necessary. * data around if it's not necessary.
*/ */
if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr)) if (mx35lf1ge4ab_get_eccsr(spinand, spinand->scratchbuf))
return nanddev_get_ecc_conf(nand)->strength; return nanddev_get_ecc_conf(nand)->strength;
eccsr = *spinand->scratchbuf;
if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength || if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength ||
!eccsr)) !eccsr))
return nanddev_get_ecc_conf(nand)->strength; return nanddev_get_ecc_conf(nand)->strength;
......
...@@ -122,6 +122,25 @@ static int parse_fixed_partitions(struct mtd_info *master, ...@@ -122,6 +122,25 @@ static int parse_fixed_partitions(struct mtd_info *master,
a_cells = of_n_addr_cells(pp); a_cells = of_n_addr_cells(pp);
s_cells = of_n_size_cells(pp); s_cells = of_n_size_cells(pp);
if (!dedicated && s_cells == 0) {
/*
* This is a ugly workaround to not create
* regression on devices that are still creating
* partitions as direct children of the nand controller.
* This can happen in case the nand controller node has
* #size-cells equal to 0 and the firmware (e.g.
* U-Boot) just add the partitions there assuming
* 32-bit addressing.
*
* If you get this warning your firmware and/or DTS
* should be really fixed.
*
* This is working only for devices smaller than 4GiB.
*/
pr_warn("%s: ofpart partition %pOF (%pOF) #size-cells is wrongly set to <0>, assuming <1> for parsing partitions.\n",
master->name, pp, mtd_node);
s_cells = 1;
}
if (len / 4 != a_cells + s_cells) { if (len / 4 != a_cells + s_cells) {
pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
master->name, pp, master->name, pp,
......
...@@ -9,19 +9,18 @@ ...@@ -9,19 +9,18 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/mutex.h>
#include <linux/math64.h> #include <linux/math64.h>
#include <linux/sizes.h> #include <linux/module.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/spi-nor.h>
#include <linux/mutex.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/sched/task_stack.h> #include <linux/sched/task_stack.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/spi/flash.h> #include <linux/spi/flash.h>
#include <linux/mtd/spi-nor.h>
#include "core.h" #include "core.h"
...@@ -2026,6 +2025,15 @@ void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, u32 size, ...@@ -2026,6 +2025,15 @@ void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, u32 size,
erase->size_mask = (1 << erase->size_shift) - 1; erase->size_mask = (1 << erase->size_shift) - 1;
} }
/**
* spi_nor_mask_erase_type() - mask out a SPI NOR erase type
* @erase: pointer to a structure that describes a SPI NOR erase type
*/
void spi_nor_mask_erase_type(struct spi_nor_erase_type *erase)
{
erase->size = 0;
}
/** /**
* spi_nor_init_uniform_erase_map() - Initialize uniform erase map * spi_nor_init_uniform_erase_map() - Initialize uniform erase map
* @map: the erase map of the SPI NOR * @map: the erase map of the SPI NOR
......
...@@ -529,33 +529,30 @@ struct flash_info { ...@@ -529,33 +529,30 @@ struct flash_info {
const struct spi_nor_fixups *fixups; const struct spi_nor_fixups *fixups;
}; };
/* Used when the "_ext_id" is two bytes at most */ #define SPI_NOR_ID_2ITEMS(_id) ((_id) >> 8) & 0xff, (_id) & 0xff
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors) \ #define SPI_NOR_ID_3ITEMS(_id) ((_id) >> 16) & 0xff, SPI_NOR_ID_2ITEMS(_id)
.id = { \
((_jedec_id) >> 16) & 0xff, \ #define SPI_NOR_ID(_jedec_id, _ext_id) \
((_jedec_id) >> 8) & 0xff, \ .id = { SPI_NOR_ID_3ITEMS(_jedec_id), SPI_NOR_ID_2ITEMS(_ext_id) }, \
(_jedec_id) & 0xff, \ .id_len = !(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))
((_ext_id) >> 8) & 0xff, \
(_ext_id) & 0xff, \ #define SPI_NOR_ID6(_jedec_id, _ext_id) \
}, \ .id = { SPI_NOR_ID_3ITEMS(_jedec_id), SPI_NOR_ID_3ITEMS(_ext_id) }, \
.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \ .id_len = 6
#define SPI_NOR_GEOMETRY(_sector_size, _n_sectors) \
.sector_size = (_sector_size), \ .sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \ .n_sectors = (_n_sectors), \
.page_size = 256, \ .page_size = 256
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors) \
SPI_NOR_ID((_jedec_id), (_ext_id)), \
SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)),
#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors) \ #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors) \
.id = { \ SPI_NOR_ID6((_jedec_id), (_ext_id)), \
((_jedec_id) >> 16) & 0xff, \ SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)),
((_jedec_id) >> 8) & 0xff, \
(_jedec_id) & 0xff, \
((_ext_id) >> 16) & 0xff, \
((_ext_id) >> 8) & 0xff, \
(_ext_id) & 0xff, \
}, \
.id_len = 6, \
.sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \
.page_size = 256, \
#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_nbytes) \ #define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_nbytes) \
.sector_size = (_sector_size), \ .sector_size = (_sector_size), \
...@@ -684,6 +681,7 @@ void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode, ...@@ -684,6 +681,7 @@ void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode,
void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, u32 size, void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, u32 size,
u8 opcode); u8 opcode);
void spi_nor_mask_erase_type(struct spi_nor_erase_type *erase);
struct spi_nor_erase_region * struct spi_nor_erase_region *
spi_nor_region_next(struct spi_nor_erase_region *region); spi_nor_region_next(struct spi_nor_erase_region *region);
void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map, void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <linux/debugfs.h>
#include <linux/mtd/spi-nor.h> #include <linux/mtd/spi-nor.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h> #include <linux/spi/spi-mem.h>
#include <linux/debugfs.h>
#include "core.h" #include "core.h"
......
...@@ -18,7 +18,7 @@ is25lp256_post_bfpt_fixups(struct spi_nor *nor, ...@@ -18,7 +18,7 @@ is25lp256_post_bfpt_fixups(struct spi_nor *nor,
* BFPT_DWORD1_ADDRESS_BYTES_3_ONLY. * BFPT_DWORD1_ADDRESS_BYTES_3_ONLY.
* Overwrite the number of address bytes advertised by the BFPT. * Overwrite the number of address bytes advertised by the BFPT.
*/ */
if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) == if ((bfpt->dwords[SFDP_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) ==
BFPT_DWORD1_ADDRESS_BYTES_3_ONLY) BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
nor->params->addr_nbytes = 4; nor->params->addr_nbytes = 4;
......
...@@ -22,7 +22,7 @@ mx25l25635_post_bfpt_fixups(struct spi_nor *nor, ...@@ -22,7 +22,7 @@ mx25l25635_post_bfpt_fixups(struct spi_nor *nor,
* seems that the F version advertises support for Fast Read 4-4-4 in * seems that the F version advertises support for Fast Read 4-4-4 in
* its BFPT table. * its BFPT table.
*/ */
if (bfpt->dwords[BFPT_DWORD(5)] & BFPT_DWORD5_FAST_READ_4_4_4) if (bfpt->dwords[SFDP_DWORD(5)] & BFPT_DWORD5_FAST_READ_4_4_4)
nor->flags |= SNOR_F_4B_OPCODES; nor->flags |= SNOR_F_4B_OPCODES;
return 0; return 0;
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
*/ */
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/mtd/spi-nor.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sort.h> #include <linux/sort.h>
#include <linux/mtd/spi-nor.h>
#include "core.h" #include "core.h"
...@@ -242,64 +242,64 @@ static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = { ...@@ -242,64 +242,64 @@ static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = {
/* Fast Read 1-1-2 */ /* Fast Read 1-1-2 */
{ {
SNOR_HWCAPS_READ_1_1_2, SNOR_HWCAPS_READ_1_1_2,
BFPT_DWORD(1), BIT(16), /* Supported bit */ SFDP_DWORD(1), BIT(16), /* Supported bit */
BFPT_DWORD(4), 0, /* Settings */ SFDP_DWORD(4), 0, /* Settings */
SNOR_PROTO_1_1_2, SNOR_PROTO_1_1_2,
}, },
/* Fast Read 1-2-2 */ /* Fast Read 1-2-2 */
{ {
SNOR_HWCAPS_READ_1_2_2, SNOR_HWCAPS_READ_1_2_2,
BFPT_DWORD(1), BIT(20), /* Supported bit */ SFDP_DWORD(1), BIT(20), /* Supported bit */
BFPT_DWORD(4), 16, /* Settings */ SFDP_DWORD(4), 16, /* Settings */
SNOR_PROTO_1_2_2, SNOR_PROTO_1_2_2,
}, },
/* Fast Read 2-2-2 */ /* Fast Read 2-2-2 */
{ {
SNOR_HWCAPS_READ_2_2_2, SNOR_HWCAPS_READ_2_2_2,
BFPT_DWORD(5), BIT(0), /* Supported bit */ SFDP_DWORD(5), BIT(0), /* Supported bit */
BFPT_DWORD(6), 16, /* Settings */ SFDP_DWORD(6), 16, /* Settings */
SNOR_PROTO_2_2_2, SNOR_PROTO_2_2_2,
}, },
/* Fast Read 1-1-4 */ /* Fast Read 1-1-4 */
{ {
SNOR_HWCAPS_READ_1_1_4, SNOR_HWCAPS_READ_1_1_4,
BFPT_DWORD(1), BIT(22), /* Supported bit */ SFDP_DWORD(1), BIT(22), /* Supported bit */
BFPT_DWORD(3), 16, /* Settings */ SFDP_DWORD(3), 16, /* Settings */
SNOR_PROTO_1_1_4, SNOR_PROTO_1_1_4,
}, },
/* Fast Read 1-4-4 */ /* Fast Read 1-4-4 */
{ {
SNOR_HWCAPS_READ_1_4_4, SNOR_HWCAPS_READ_1_4_4,
BFPT_DWORD(1), BIT(21), /* Supported bit */ SFDP_DWORD(1), BIT(21), /* Supported bit */
BFPT_DWORD(3), 0, /* Settings */ SFDP_DWORD(3), 0, /* Settings */
SNOR_PROTO_1_4_4, SNOR_PROTO_1_4_4,
}, },
/* Fast Read 4-4-4 */ /* Fast Read 4-4-4 */
{ {
SNOR_HWCAPS_READ_4_4_4, SNOR_HWCAPS_READ_4_4_4,
BFPT_DWORD(5), BIT(4), /* Supported bit */ SFDP_DWORD(5), BIT(4), /* Supported bit */
BFPT_DWORD(7), 16, /* Settings */ SFDP_DWORD(7), 16, /* Settings */
SNOR_PROTO_4_4_4, SNOR_PROTO_4_4_4,
}, },
}; };
static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = { static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
/* Erase Type 1 in DWORD8 bits[15:0] */ /* Erase Type 1 in DWORD8 bits[15:0] */
{BFPT_DWORD(8), 0}, {SFDP_DWORD(8), 0},
/* Erase Type 2 in DWORD8 bits[31:16] */ /* Erase Type 2 in DWORD8 bits[31:16] */
{BFPT_DWORD(8), 16}, {SFDP_DWORD(8), 16},
/* Erase Type 3 in DWORD9 bits[15:0] */ /* Erase Type 3 in DWORD9 bits[15:0] */
{BFPT_DWORD(9), 0}, {SFDP_DWORD(9), 0},
/* Erase Type 4 in DWORD9 bits[31:16] */ /* Erase Type 4 in DWORD9 bits[31:16] */
{BFPT_DWORD(9), 16}, {SFDP_DWORD(9), 16},
}; };
/** /**
...@@ -458,7 +458,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, ...@@ -458,7 +458,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
le32_to_cpu_array(bfpt.dwords, BFPT_DWORD_MAX); le32_to_cpu_array(bfpt.dwords, BFPT_DWORD_MAX);
/* Number of address bytes. */ /* Number of address bytes. */
switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) { switch (bfpt.dwords[SFDP_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) {
case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY: case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY:
case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4: case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4:
params->addr_nbytes = 3; params->addr_nbytes = 3;
...@@ -475,7 +475,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, ...@@ -475,7 +475,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
} }
/* Flash Memory Density (in bits). */ /* Flash Memory Density (in bits). */
val = bfpt.dwords[BFPT_DWORD(2)]; val = bfpt.dwords[SFDP_DWORD(2)];
if (val & BIT(31)) { if (val & BIT(31)) {
val &= ~BIT(31); val &= ~BIT(31);
...@@ -555,13 +555,13 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, ...@@ -555,13 +555,13 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt); return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt);
/* Page size: this field specifies 'N' so the page size = 2^N bytes. */ /* Page size: this field specifies 'N' so the page size = 2^N bytes. */
val = bfpt.dwords[BFPT_DWORD(11)]; val = bfpt.dwords[SFDP_DWORD(11)];
val &= BFPT_DWORD11_PAGE_SIZE_MASK; val &= BFPT_DWORD11_PAGE_SIZE_MASK;
val >>= BFPT_DWORD11_PAGE_SIZE_SHIFT; val >>= BFPT_DWORD11_PAGE_SIZE_SHIFT;
params->page_size = 1U << val; params->page_size = 1U << val;
/* Quad Enable Requirements. */ /* Quad Enable Requirements. */
switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) { switch (bfpt.dwords[SFDP_DWORD(15)] & BFPT_DWORD15_QER_MASK) {
case BFPT_DWORD15_QER_NONE: case BFPT_DWORD15_QER_NONE:
params->quad_enable = NULL; params->quad_enable = NULL;
break; break;
...@@ -608,7 +608,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, ...@@ -608,7 +608,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
} }
/* Soft Reset support. */ /* Soft Reset support. */
if (bfpt.dwords[BFPT_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST) if (bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST)
nor->flags |= SNOR_F_SOFT_RESET; nor->flags |= SNOR_F_SOFT_RESET;
/* Stop here if not JESD216 rev C or later. */ /* Stop here if not JESD216 rev C or later. */
...@@ -616,7 +616,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, ...@@ -616,7 +616,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt); return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt);
/* 8D-8D-8D command extension. */ /* 8D-8D-8D command extension. */
switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) { switch (bfpt.dwords[SFDP_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) {
case BFPT_DWORD18_CMD_EXT_REP: case BFPT_DWORD18_CMD_EXT_REP:
nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
break; break;
...@@ -875,7 +875,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, ...@@ -875,7 +875,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
*/ */
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
if (!(regions_erase_type & BIT(erase[i].idx))) if (!(regions_erase_type & BIT(erase[i].idx)))
spi_nor_set_erase_type(&erase[i], 0, 0xFF); spi_nor_mask_erase_type(&erase[i]);
return 0; return 0;
} }
...@@ -1004,7 +1004,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor, ...@@ -1004,7 +1004,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
discard_hwcaps |= read->hwcaps; discard_hwcaps |= read->hwcaps;
if ((params->hwcaps.mask & read->hwcaps) && if ((params->hwcaps.mask & read->hwcaps) &&
(dwords[0] & read->supported_bit)) (dwords[SFDP_DWORD(1)] & read->supported_bit))
read_hwcaps |= read->hwcaps; read_hwcaps |= read->hwcaps;
} }
...@@ -1023,7 +1023,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor, ...@@ -1023,7 +1023,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
* authority for specifying Page Program support. * authority for specifying Page Program support.
*/ */
discard_hwcaps |= program->hwcaps; discard_hwcaps |= program->hwcaps;
if (dwords[0] & program->supported_bit) if (dwords[SFDP_DWORD(1)] & program->supported_bit)
pp_hwcaps |= program->hwcaps; pp_hwcaps |= program->hwcaps;
} }
...@@ -1035,7 +1035,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor, ...@@ -1035,7 +1035,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) { for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
const struct sfdp_4bait *erase = &erases[i]; const struct sfdp_4bait *erase = &erases[i];
if (dwords[0] & erase->supported_bit) if (dwords[SFDP_DWORD(1)] & erase->supported_bit)
erase_mask |= BIT(i); erase_mask |= BIT(i);
} }
...@@ -1086,10 +1086,10 @@ static int spi_nor_parse_4bait(struct spi_nor *nor, ...@@ -1086,10 +1086,10 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) { for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
if (erase_mask & BIT(i)) if (erase_mask & BIT(i))
erase_type[i].opcode = (dwords[1] >> erase_type[i].opcode = (dwords[SFDP_DWORD(2)] >>
erase_type[i].idx * 8) & 0xFF; erase_type[i].idx * 8) & 0xFF;
else else
spi_nor_set_erase_type(&erase_type[i], 0u, 0xFF); spi_nor_mask_erase_type(&erase_type[i]);
} }
/* /*
...@@ -1145,15 +1145,15 @@ static int spi_nor_parse_profile1(struct spi_nor *nor, ...@@ -1145,15 +1145,15 @@ static int spi_nor_parse_profile1(struct spi_nor *nor,
le32_to_cpu_array(dwords, profile1_header->length); le32_to_cpu_array(dwords, profile1_header->length);
/* Get 8D-8D-8D fast read opcode and dummy cycles. */ /* Get 8D-8D-8D fast read opcode and dummy cycles. */
opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, dwords[0]); opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, dwords[SFDP_DWORD(1)]);
/* Set the Read Status Register dummy cycles and dummy address bytes. */ /* Set the Read Status Register dummy cycles and dummy address bytes. */
if (dwords[0] & PROFILE1_DWORD1_RDSR_DUMMY) if (dwords[SFDP_DWORD(1)] & PROFILE1_DWORD1_RDSR_DUMMY)
nor->params->rdsr_dummy = 8; nor->params->rdsr_dummy = 8;
else else
nor->params->rdsr_dummy = 4; nor->params->rdsr_dummy = 4;
if (dwords[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES) if (dwords[SFDP_DWORD(1)] & PROFILE1_DWORD1_RDSR_ADDR_BYTES)
nor->params->rdsr_addr_nbytes = 4; nor->params->rdsr_addr_nbytes = 4;
else else
nor->params->rdsr_addr_nbytes = 0; nor->params->rdsr_addr_nbytes = 0;
...@@ -1167,13 +1167,16 @@ static int spi_nor_parse_profile1(struct spi_nor *nor, ...@@ -1167,13 +1167,16 @@ static int spi_nor_parse_profile1(struct spi_nor *nor,
* Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let * Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let
* flashes set the correct value if needed in their fixup hooks. * flashes set the correct value if needed in their fixup hooks.
*/ */
dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, dwords[3]); dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, dwords[SFDP_DWORD(4)]);
if (!dummy) if (!dummy)
dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, dwords[4]); dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ,
dwords[SFDP_DWORD(5)]);
if (!dummy) if (!dummy)
dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, dwords[4]); dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ,
dwords[SFDP_DWORD(5)]);
if (!dummy) if (!dummy)
dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, dwords[4]); dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ,
dwords[SFDP_DWORD(5)]);
if (!dummy) if (!dummy)
dev_dbg(nor->dev, dev_dbg(nor->dev,
"Can't find dummy cycles from Profile 1.0 table\n"); "Can't find dummy cycles from Profile 1.0 table\n");
...@@ -1228,7 +1231,8 @@ static int spi_nor_parse_sccr(struct spi_nor *nor, ...@@ -1228,7 +1231,8 @@ static int spi_nor_parse_sccr(struct spi_nor *nor,
le32_to_cpu_array(dwords, sccr_header->length); le32_to_cpu_array(dwords, sccr_header->length);
if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, dwords[22])) if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE,
dwords[SFDP_DWORD(22)]))
nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
out: out:
......
...@@ -13,13 +13,12 @@ ...@@ -13,13 +13,12 @@
#define SFDP_JESD216A_MINOR 5 #define SFDP_JESD216A_MINOR 5
#define SFDP_JESD216B_MINOR 6 #define SFDP_JESD216B_MINOR 6
/* SFDP DWORDS are indexed from 1 but C arrays are indexed from 0. */
#define SFDP_DWORD(i) ((i) - 1)
/* Basic Flash Parameter Table */ /* Basic Flash Parameter Table */
/* /* JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs. */
* JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs.
* They are indexed from 1 but C arrays are indexed from 0.
*/
#define BFPT_DWORD(i) ((i) - 1)
#define BFPT_DWORD_MAX 20 #define BFPT_DWORD_MAX 20
struct sfdp_bfpt { struct sfdp_bfpt {
......
...@@ -15,14 +15,19 @@ ...@@ -15,14 +15,19 @@
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */ #define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */ #define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
#define SPINOR_REG_CYPRESS_CFR1V 0x00800002 #define SPINOR_REG_CYPRESS_CFR1V 0x00800002
#define SPINOR_REG_CYPRESS_CFR1V_QUAD_EN BIT(1) /* Quad Enable */ #define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */
#define SPINOR_REG_CYPRESS_CFR2V 0x00800003 #define SPINOR_REG_CYPRESS_CFR2V 0x00800003
#define SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24 0xb #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb
#define SPINOR_REG_CYPRESS_CFR3V 0x00800004 #define SPINOR_REG_CYPRESS_CFR3V 0x00800004
#define SPINOR_REG_CYPRESS_CFR3V_PGSZ BIT(4) /* Page size. */ #define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */
#define SPINOR_REG_CYPRESS_CFR5V 0x00800006 #define SPINOR_REG_CYPRESS_CFR5V 0x00800006
#define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN 0x3 #define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6)
#define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS 0 #define SPINOR_REG_CYPRESS_CFR5_DDR BIT(1)
#define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0)
#define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN \
(SPINOR_REG_CYPRESS_CFR5_BIT6 | SPINOR_REG_CYPRESS_CFR5_DDR | \
SPINOR_REG_CYPRESS_CFR5_OPI)
#define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS SPINOR_REG_CYPRESS_CFR5_BIT6
#define SPINOR_OP_CYPRESS_RD_FAST 0xee #define SPINOR_OP_CYPRESS_RD_FAST 0xee
/* Cypress SPI NOR flash operations. */ /* Cypress SPI NOR flash operations. */
...@@ -52,7 +57,7 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) ...@@ -52,7 +57,7 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
/* Use 24 dummy cycles for memory array reads. */ /* Use 24 dummy cycles for memory array reads. */
*buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24; *buf = SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24;
op = (struct spi_mem_op) op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR2V, 1, buf); SPINOR_REG_CYPRESS_CFR2V, 1, buf);
...@@ -64,7 +69,7 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) ...@@ -64,7 +69,7 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
nor->read_dummy = 24; nor->read_dummy = 24;
/* Set the octal and DTR enable bits. */ /* Set the octal and DTR enable bits. */
buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN; buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN;
op = (struct spi_mem_op) op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR5V, 1, buf); SPINOR_REG_CYPRESS_CFR5V, 1, buf);
...@@ -98,7 +103,7 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) ...@@ -98,7 +103,7 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
* in 8D-8D-8D mode. Since there is no register at the next location, * in 8D-8D-8D mode. Since there is no register at the next location,
* just initialize the value to 0 and let the transaction go on. * just initialize the value to 0 and let the transaction go on.
*/ */
buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS; buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS;
buf[1] = 0; buf[1] = 0;
op = (struct spi_mem_op) op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes,
...@@ -150,11 +155,11 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) ...@@ -150,11 +155,11 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
if (ret) if (ret)
return ret; return ret;
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1V_QUAD_EN) if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1_QUAD_EN)
return 0; return 0;
/* Update the Quad Enable bit. */ /* Update the Quad Enable bit. */
nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1V_QUAD_EN; nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1_QUAD_EN;
op = (struct spi_mem_op) op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR1V, 1, SPINOR_REG_CYPRESS_CFR1V, 1,
...@@ -205,7 +210,7 @@ static int cypress_nor_set_page_size(struct spi_nor *nor) ...@@ -205,7 +210,7 @@ static int cypress_nor_set_page_size(struct spi_nor *nor)
if (ret) if (ret)
return ret; return ret;
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3V_PGSZ) if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ)
nor->params->page_size = 512; nor->params->page_size = 512;
else else
nor->params->page_size = 256; nor->params->page_size = 256;
......
...@@ -67,6 +67,8 @@ struct gpio_desc; ...@@ -67,6 +67,8 @@ struct gpio_desc;
/* Extended commands for large page devices */ /* Extended commands for large page devices */
#define NAND_CMD_READSTART 0x30 #define NAND_CMD_READSTART 0x30
#define NAND_CMD_READCACHESEQ 0x31
#define NAND_CMD_READCACHEEND 0x3f
#define NAND_CMD_RNDOUTSTART 0xE0 #define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15 #define NAND_CMD_CACHEDPROG 0x15
...@@ -1094,10 +1096,20 @@ struct nand_controller_ops { ...@@ -1094,10 +1096,20 @@ struct nand_controller_ops {
* *
* @lock: lock used to serialize accesses to the NAND controller * @lock: lock used to serialize accesses to the NAND controller
* @ops: NAND controller operations. * @ops: NAND controller operations.
* @supported_op: NAND controller known-to-be-supported operations,
* only writable by the core after initial checking.
* @supported_op.data_only_read: The controller supports reading more data from
* the bus without restarting an entire read operation nor
* changing the column.
* @supported_op.cont_read: The controller supports sequential cache reads.
*/ */
struct nand_controller { struct nand_controller {
struct mutex lock; struct mutex lock;
const struct nand_controller_ops *ops; const struct nand_controller_ops *ops;
struct {
unsigned int data_only_read: 1;
unsigned int cont_read: 1;
} supported_op;
}; };
static inline void nand_controller_init(struct nand_controller *nfc) static inline void nand_controller_init(struct nand_controller *nfc)
...@@ -1248,6 +1260,10 @@ struct nand_secure_region { ...@@ -1248,6 +1260,10 @@ struct nand_secure_region {
* @read_retries: The number of read retry modes supported * @read_retries: The number of read retry modes supported
* @secure_regions: Structure containing the secure regions info * @secure_regions: Structure containing the secure regions info
* @nr_secure_regions: Number of secure regions * @nr_secure_regions: Number of secure regions
* @cont_read: Sequential page read internals
* @cont_read.ongoing: Whether a continuous read is ongoing or not
* @cont_read.first_page: Start of the continuous read operation
* @cont_read.last_page: End of the continuous read operation
* @controller: The hardware controller structure which is shared among multiple * @controller: The hardware controller structure which is shared among multiple
* independent devices * independent devices
* @ecc: The ECC controller structure * @ecc: The ECC controller structure
...@@ -1300,6 +1316,11 @@ struct nand_chip { ...@@ -1300,6 +1316,11 @@ struct nand_chip {
int read_retries; int read_retries;
struct nand_secure_region *secure_regions; struct nand_secure_region *secure_regions;
u8 nr_secure_regions; u8 nr_secure_regions;
struct {
bool ongoing;
unsigned int first_page;
unsigned int last_page;
} cont_read;
/* Externals */ /* Externals */
struct nand_controller *controller; struct nand_controller *controller;
......
...@@ -260,6 +260,7 @@ struct spinand_manufacturer { ...@@ -260,6 +260,7 @@ struct spinand_manufacturer {
}; };
/* SPI NAND manufacturers */ /* SPI NAND manufacturers */
extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
extern const struct spinand_manufacturer ato_spinand_manufacturer; extern const struct spinand_manufacturer ato_spinand_manufacturer;
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
extern const struct spinand_manufacturer macronix_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment