Commit f4440abc authored by Miquel Raynal's avatar Miquel Raynal

Merge tag 'nand/for-6.3' into mtd/next

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 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 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
parents 27121864 ef3e6327
# 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";
};
......@@ -13213,7 +13213,7 @@ F: drivers/phy/ralink/phy-mt7621-pci.c
MEDIATEK NAND CONTROLLER DRIVER
L: linux-mtd@lists.infradead.org
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_*
MEDIATEK PMIC LED DRIVER
......
......@@ -40,6 +40,10 @@
#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_ERRMASK_MT7622 GENMASK(4, 0)
#define ECC_ERRMASK_MT2701 GENMASK(5, 0)
#define ECC_ERRMASK_MT2712 GENMASK(6, 0)
struct mtk_ecc_caps {
u32 err_mask;
u32 err_shift;
......@@ -79,6 +83,10 @@ static const u8 ecc_strength_mt7622[] = {
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 {
ECC_ENCPAR00,
ECC_ENCIRQ_EN,
......@@ -451,7 +459,7 @@ unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc)
EXPORT_SYMBOL(mtk_ecc_get_parity_bits);
static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
.err_mask = 0x3f,
.err_mask = ECC_ERRMASK_MT2701,
.err_shift = 8,
.ecc_strength = ecc_strength_mt2701,
.ecc_regs = mt2701_ecc_regs,
......@@ -462,7 +470,7 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
};
static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
.err_mask = 0x7f,
.err_mask = ECC_ERRMASK_MT2712,
.err_shift = 8,
.ecc_strength = ecc_strength_mt2712,
.ecc_regs = mt2712_ecc_regs,
......@@ -473,7 +481,7 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
};
static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
.err_mask = 0x1f,
.err_mask = ECC_ERRMASK_MT7622,
.err_shift = 5,
.ecc_strength = ecc_strength_mt7622,
.ecc_regs = mt7622_ecc_regs,
......@@ -483,6 +491,17 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
.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[] = {
{
.compatible = "mediatek,mt2701-ecc",
......@@ -493,6 +512,9 @@ static const struct of_device_id mtk_ecc_dt_match[] = {
}, {
.compatible = "mediatek,mt7622-ecc",
.data = &mtk_ecc_caps_mt7622,
}, {
.compatible = "mediatek,mt7986-ecc",
.data = &mtk_ecc_caps_mt7986,
},
{},
};
......
......@@ -193,13 +193,6 @@ config MTD_NAND_PASEMI
Enables support for NAND Flash interface on PA Semi PWRficient
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"
config MTD_NAND_BCM47XXNFLASH
......
......@@ -23,7 +23,6 @@ omap2_nand-objs := omap2.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.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_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
......
......@@ -725,6 +725,7 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
unsigned int al;
u32 br;
/*
* 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)
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 */
al = 0;
if (chip->pagemask & 0xffff0000)
......
......@@ -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, 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,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, 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, 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,
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
* @chip: The NAND chip
......@@ -1233,10 +1300,16 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page,
return -EINVAL;
if (nand_has_exec_op(chip)) {
if (mtd->writesize > 512)
return nand_lp_exec_read_page_op(chip, page,
offset_in_page, buf,
len);
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,
offset_in_page, buf,
len);
}
return nand_sp_exec_read_page_op(chip, page, offset_in_page,
buf, len);
......@@ -3353,6 +3426,27 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
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
* @chip: NAND chip object
......@@ -3426,6 +3520,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);
while (1) {
struct mtd_ecc_stats ecc_stats = mtd->ecc_stats;
......@@ -4991,6 +5087,47 @@ nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc)
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.
*/
......@@ -5023,6 +5160,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
/* Select the device */
nand_select_target(chip, 0);
rawnand_early_check_supported_ops(chip);
/* Send the command for reading device ID */
ret = nand_readid_op(chip, 0, id_data, 2);
if (ret)
......@@ -6325,6 +6464,8 @@ static int nand_scan_tail(struct nand_chip *chip)
goto err_free_interface_config;
}
rawnand_late_check_supported_ops(chip);
/*
* 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
......
......@@ -46,8 +46,7 @@ int nand_jedec_detect(struct nand_chip *chip)
if (!p)
return -ENOMEM;
if (!nand_has_exec_op(chip) ||
!nand_read_data_op(chip, p, sizeof(*p), true, true))
if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read)
use_datain = true;
for (i = 0; i < JEDEC_PARAM_PAGES; i++) {
......
......@@ -166,8 +166,7 @@ int nand_onfi_detect(struct nand_chip *chip)
if (!pbuf)
return -ENOMEM;
if (!nand_has_exec_op(chip) ||
!nand_read_data_op(chip, &pbuf[0], sizeof(*pbuf), true, true))
if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read)
use_datain = true;
for (i = 0; i < ONFI_PARAM_PAGES; i++) {
......
......@@ -26,9 +26,12 @@
#define CLE_PIN_CTL 15
#define ALE_PIN_CTL 14
static unsigned int lpcctl;
static struct mtd_info *pasemi_nand_mtd;
static struct nand_controller controller;
struct pasemi_ddata {
struct nand_chip chip;
unsigned int lpcctl;
struct nand_controller controller;
};
static const char driver_name[] = "pasemi-nand";
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,
static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
struct pasemi_ddata *ddata = container_of(chip, struct pasemi_ddata, chip);
if (cmd == NAND_CMD_NONE)
return;
......@@ -65,12 +70,14 @@ static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
/* Push out posted writes */
eieio();
inl(lpcctl);
inl(ddata->lpcctl);
}
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)
......@@ -93,29 +100,31 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
struct device_node *np = dev->of_node;
struct resource res;
struct nand_chip *chip;
struct nand_controller *controller;
int err = 0;
struct pasemi_ddata *ddata;
struct mtd_info *pasemi_nand_mtd;
err = of_address_to_resource(np, 0, &res);
if (err)
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);
/* Allocate memory for MTD device structure and private data */
chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
if (!chip) {
ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
if (!ddata) {
err = -ENOMEM;
goto out;
}
platform_set_drvdata(ofdev, ddata);
chip = &ddata->chip;
controller = &ddata->controller;
controller.ops = &pasemi_ops;
nand_controller_init(&controller);
chip->controller = &controller;
controller->ops = &pasemi_ops;
nand_controller_init(controller);
chip->controller = controller;
pasemi_nand_mtd = nand_to_mtd(chip);
......@@ -136,10 +145,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
goto out_ior;
}
lpcctl = pci_resource_start(pdev, 0);
ddata->lpcctl = pci_resource_start(pdev, 0);
pci_dev_put(pdev);
if (!request_region(lpcctl, 4, driver_name)) {
if (!request_region(ddata->lpcctl, 4, driver_name)) {
err = -EBUSY;
goto out_ior;
}
......@@ -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,
lpcctl);
ddata->lpcctl);
return 0;
out_cleanup_nand:
nand_cleanup(chip);
out_lpc:
release_region(lpcctl, 4);
release_region(ddata->lpcctl, 4);
out_ior:
iounmap(chip->legacy.IO_ADDR_R);
out_mtd:
kfree(chip);
kfree(ddata);
out:
return err;
}
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;
struct nand_chip *chip;
if (!pasemi_nand_mtd)
return 0;
chip = mtd_to_nand(pasemi_nand_mtd);
chip = &ddata->chip;
pasemi_nand_mtd = nand_to_mtd(chip);
/* Release resources, unregister device */
ret = mtd_device_unregister(pasemi_nand_mtd);
WARN_ON(ret);
nand_cleanup(chip);
release_region(lpcctl, 4);
release_region(ddata->lpcctl, 4);
iounmap(chip->legacy.IO_ADDR_R);
/* Free the MTD device structure */
kfree(chip);
pasemi_nand_mtd = NULL;
kfree(ddata);
return 0;
}
......
......@@ -172,10 +172,10 @@ struct sunxi_nand_chip_sel {
/**
* 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 {
int mode;
u32 ecc_ctl;
};
/**
......@@ -193,7 +193,7 @@ struct sunxi_nand_hw_ecc {
struct sunxi_nand_chip {
struct list_head node;
struct nand_chip nand;
struct sunxi_nand_hw_ecc *ecc;
struct sunxi_nand_hw_ecc ecc;
unsigned long clk_rate;
u32 timing_cfg;
u32 timing_ctl;
......@@ -421,7 +421,7 @@ static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
struct sunxi_nand_chip_sel *sel;
u32 ctl;
if (cs > 0 && cs >= sunxi_nand->nsels)
if (cs >= sunxi_nand->nsels)
return;
ctl = readl(nfc->regs + NFC_REG_CTL) &
......@@ -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_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)
{
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
nfc->regs + NFC_REG_ECC_CTL);
writel(0, nfc->regs + NFC_REG_ECC_CTL);
}
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,
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);
if (section < ecc->steps)
oobregion->length = 4;
else
oobregion->offset = mtd->oobsize - oobregion->offset;
oobregion->length = mtd->oobsize - oobregion->offset;
return 0;
}
......@@ -1619,11 +1615,6 @@ static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
.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,
struct nand_ecc_ctrl *ecc,
struct device_node *np)
......@@ -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 nand_device *nanddev = mtd_to_nanddev(mtd);
int nsectors;
int ret;
int i;
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,
if (ecc->size != 512 && ecc->size != 1024)
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 */
if (ecc->size == 512 && mtd->writesize > 512) {
ecc->size = 1024;
......@@ -1693,12 +1679,9 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
if (i >= ARRAY_SIZE(strengths)) {
dev_err(nfc->dev, "unsupported strength\n");
ret = -ENOTSUPP;
goto err;
return -ENOTSUPP;
}
sunxi_nand->ecc->mode = i;
/* HW ECC always request ECC bytes for 1024 bytes blocks */
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,
nsectors = mtd->writesize / ecc->size;
if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
ret = -EINVAL;
goto err;
}
if (mtd->oobsize < ((ecc->bytes + 4) * nsectors))
return -EINVAL;
ecc->read_oob = sunxi_nfc_hw_ecc_read_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,
ecc->read_oob_raw = nand_read_oob_std;
ecc->write_oob_raw = nand_write_oob_std;
return 0;
err:
kfree(sunxi_nand->ecc);
sunxi_nand->ecc.ecc_ctl = NFC_ECC_MODE(i) | NFC_ECC_EXCEPTION |
NFC_ECC_PIPELINE | NFC_ECC_EN;
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)
{
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;
}
return 0;
}
static int sunxi_nand_attach_chip(struct nand_chip *nand)
......@@ -1950,6 +1918,24 @@ static const struct nand_controller_ops sunxi_nand_controller_ops = {
.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,
struct device_node *np)
{
......@@ -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 *nand_np;
int nchips = of_get_child_count(np);
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) {
ret = sunxi_nand_chip_init(dev, nfc, nand_np);
if (ret) {
of_node_put(nand_np);
sunxi_nand_chips_cleanup(nfc);
return ret;
}
}
......@@ -2060,25 +2041,6 @@ static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
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)
{
int ret;
......
This diff is collapsed.
......@@ -206,7 +206,7 @@ static inline bool vf610_nfc_kernel_is_little_endian(void)
#endif
}
/**
/*
* Read accessor for internal SRAM buffer
* @dst: destination address in regular memory
* @src: source address in SRAM buffer
......@@ -241,7 +241,7 @@ static inline void vf610_nfc_rd_from_sram(void *dst, const void __iomem *src,
}
}
/**
/*
* Write accessor for internal SRAM buffer
* @dst: destination address in SRAM buffer
* @src: source address in regular memory
......
# 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
// 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 = {
};
static const struct spinand_manufacturer *spinand_manufacturers[] = {
&alliancememory_spinand_manufacturer,
&ato_spinand_manufacturer,
&gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer,
......
......@@ -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
* 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;
eccsr = *spinand->scratchbuf;
if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength ||
!eccsr))
return nanddev_get_ecc_conf(nand)->strength;
......
......@@ -67,6 +67,8 @@ struct gpio_desc;
/* Extended commands for large page devices */
#define NAND_CMD_READSTART 0x30
#define NAND_CMD_READCACHESEQ 0x31
#define NAND_CMD_READCACHEEND 0x3f
#define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15
......@@ -1094,10 +1096,20 @@ struct nand_controller_ops {
*
* @lock: lock used to serialize accesses to the NAND controller
* @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 mutex lock;
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)
......@@ -1248,6 +1260,10 @@ struct nand_secure_region {
* @read_retries: The number of read retry modes supported
* @secure_regions: Structure containing the secure regions info
* @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
* independent devices
* @ecc: The ECC controller structure
......@@ -1300,6 +1316,11 @@ struct nand_chip {
int read_retries;
struct nand_secure_region *secure_regions;
u8 nr_secure_regions;
struct {
bool ongoing;
unsigned int first_page;
unsigned int last_page;
} cont_read;
/* Externals */
struct nand_controller *controller;
......
......@@ -260,6 +260,7 @@ struct spinand_manufacturer {
};
/* SPI NAND manufacturers */
extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
extern const struct spinand_manufacturer ato_spinand_manufacturer;
extern const struct spinand_manufacturer gigadevice_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