Commit ef4ed780 authored by Richard Weinberger's avatar Richard Weinberger

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

MTD core:
* Handle possible -EPROBE_DEFER from parse_mtd_partitions()

NAND core:
* Fix error handling in nand_prog_page_op() (x2)
* Add a helper to retrieve the number of ECC bytes per step
* Add a helper to retrieve the number of ECC steps
* Let ECC engines advertize the exact number of steps
* ECC Hamming:
  - Populate the public nsteps field
  - Use the public nsteps field
* ECC BCH:
  - Populate the public nsteps field
  - Use the public nsteps field

Raw NAND core:
* Add support for secure regions in NAND memory
* Try not to use the ECC private structures
* Remove duplicate include in rawnand.h
* BBT:
  - Skip bad blocks when searching for the BBT in NAND

Raw NAND controller drivers:
* Qcom:
  - Convert bindings to YAML
  - Use dma_mapping_error() for error check
  - Add missing nand_cleanup() in error path
  - Return actual error code instead of -ENODEV
  - Update last code word register
  - Add helper to configure location register
  - Rename parameter name in macro
  - Add helper to check last code word
  - Convert nandc to chip in Read/Write helper
  - Update register macro name for 0x2c offset
* GPMI:
  - Fix a double free in gpmi_nand_init
* Rockchip:
  - Use flexible-array member instead of zero-length array
* Atmel:
  - Update ecc_stats.corrected counter
* MXC:
  - Remove unneeded of_match_ptr()
* R852:
  - replace spin_lock_irqsave by spin_lock in hard IRQ
* Brcmnand:
  - Move to polling in pio mode on oops write
  - Read/write oob during EDU transfer
  - Fix OOB R/W with Hamming ECC
* FSMC:
  - Fix error code in fsmc_nand_probe()
* OMAP:
  - Use ECC information from the generic structures

SPI-NAND core:
* Add missing MODULE_DEVICE_TABLE()

SPI-NAND drivers:
* gigadevice: Support GD5F1GQ5UExxG
parents 256437eb 32cbc7cb
...@@ -143,6 +143,13 @@ patternProperties: ...@@ -143,6 +143,13 @@ patternProperties:
Ready/Busy pins. Active state refers to the NAND ready state and Ready/Busy pins. Active state refers to the NAND ready state and
should be set to GPIOD_ACTIVE_HIGH unless the signal is inverted. should be set to GPIOD_ACTIVE_HIGH unless the signal is inverted.
secure-regions:
$ref: /schemas/types.yaml#/definitions/uint64-matrix
description:
Regions in the NAND chip which are protected using a secure element
like Trustzone. This property contains the start address and size of
the secure regions present.
required: required:
- reg - reg
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mtd/qcom,nandc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm NAND controller
maintainers:
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
properties:
compatible:
enum:
- qcom,ipq806x-nand
- qcom,ipq4019-nand
- qcom,ipq6018-nand
- qcom,ipq8074-nand
- qcom,sdx55-nand
reg:
maxItems: 1
clocks:
items:
- description: Core Clock
- description: Always ON Clock
clock-names:
items:
- const: core
- const: aon
"#address-cells": true
"#size-cells": true
patternProperties:
"^nand@[a-f0-9]$":
type: object
properties:
nand-bus-width:
const: 8
nand-ecc-strength:
enum: [1, 4, 8]
nand-ecc-step-size:
enum:
- 512
allOf:
- $ref: "nand-controller.yaml#"
- if:
properties:
compatible:
contains:
const: qcom,ipq806x-nand
then:
properties:
dmas:
items:
- description: rxtx DMA channel
dma-names:
items:
- const: rxtx
qcom,cmd-crci:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Must contain the ADM command type CRCI block instance number
specified for the NAND controller on the given platform
qcom,data-crci:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Must contain the ADM data type CRCI block instance number
specified for the NAND controller on the given platform
- if:
properties:
compatible:
contains:
enum:
- qcom,ipq4019-nand
- qcom,ipq6018-nand
- qcom,ipq8074-nand
- qcom,sdx55-nand
then:
properties:
dmas:
items:
- description: tx DMA channel
- description: rx DMA channel
- description: cmd DMA channel
dma-names:
items:
- const: tx
- const: rx
- const: cmd
required:
- compatible
- reg
- clocks
- clock-names
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-ipq806x.h>
nand-controller@1ac00000 {
compatible = "qcom,ipq806x-nand";
reg = <0x1ac00000 0x800>;
clocks = <&gcc EBI2_CLK>,
<&gcc EBI2_AON_CLK>;
clock-names = "core", "aon";
dmas = <&adm_dma 3>;
dma-names = "rxtx";
qcom,cmd-crci = <15>;
qcom,data-crci = <3>;
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>;
nand-ecc-strength = <4>;
nand-bus-width = <8>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "boot-nand";
reg = <0 0x58a0000>;
};
partition@58a0000 {
label = "fs-nand";
reg = <0x58a0000 0x4000000>;
};
};
};
};
#include <dt-bindings/clock/qcom,gcc-ipq4019.h>
nand-controller@79b0000 {
compatible = "qcom,ipq4019-nand";
reg = <0x79b0000 0x1000>;
clocks = <&gcc GCC_QPIC_CLK>,
<&gcc GCC_QPIC_AHB_CLK>;
clock-names = "core", "aon";
dmas = <&qpicbam 0>,
<&qpicbam 1>,
<&qpicbam 2>;
dma-names = "tx", "rx", "cmd";
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>;
nand-ecc-strength = <4>;
nand-bus-width = <8>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "boot-nand";
reg = <0 0x58a0000>;
};
partition@58a0000 {
label = "fs-nand";
reg = <0x58a0000 0x4000000>;
};
};
};
};
...
* Qualcomm NAND controller
Required properties:
- compatible: must be one of the following:
* "qcom,ipq806x-nand" - for EBI2 NAND controller being used in IPQ806x
SoC and it uses ADM DMA
* "qcom,ipq4019-nand" - for QPIC NAND controller v1.4.0 being used in
IPQ4019 SoC and it uses BAM DMA
* "qcom,ipq6018-nand" - for QPIC NAND controller v1.5.0 being used in
IPQ6018 SoC and it uses BAM DMA
* "qcom,ipq8074-nand" - for QPIC NAND controller v1.5.0 being used in
IPQ8074 SoC and it uses BAM DMA
* "qcom,sdx55-nand" - for QPIC NAND controller v2.0.0 being used in
SDX55 SoC and it uses BAM DMA
- reg: MMIO address range
- clocks: must contain core clock and always on clock
- clock-names: must contain "core" for the core clock and "aon" for the
always on clock
EBI2 specific properties:
- dmas: DMA specifier, consisting of a phandle to the ADM DMA
controller node and the channel number to be used for
NAND. Refer to dma.txt and qcom_adm.txt for more details
- dma-names: must be "rxtx"
- qcom,cmd-crci: must contain the ADM command type CRCI block instance
number specified for the NAND controller on the given
platform
- qcom,data-crci: must contain the ADM data type CRCI block instance
number specified for the NAND controller on the given
platform
QPIC specific properties:
- dmas: DMA specifier, consisting of a phandle to the BAM DMA
and the channel number to be used for NAND. Refer to
dma.txt, qcom_bam_dma.txt for more details
- dma-names: must contain all 3 channel names : "tx", "rx", "cmd"
- #address-cells: <1> - subnodes give the chip-select number
- #size-cells: <0>
* NAND chip-select
Each controller may contain one or more subnodes to represent enabled
chip-selects which (may) contain NAND flash chips. Their properties are as
follows.
Required properties:
- reg: a single integer representing the chip-select
number (e.g., 0, 1, 2, etc.)
- #address-cells: see partition.txt
- #size-cells: see partition.txt
Optional properties:
- nand-bus-width: see nand-controller.yaml
- nand-ecc-strength: see nand-controller.yaml. If not specified, then ECC strength will
be used according to chip requirement and available
OOB size.
Each nandcs device node may optionally contain a 'partitions' sub-node, which
further contains sub-nodes describing the flash partition mapping. See
partition.txt for more detail.
Example:
nand-controller@1ac00000 {
compatible = "qcom,ipq806x-nand";
reg = <0x1ac00000 0x800>;
clocks = <&gcc EBI2_CLK>,
<&gcc EBI2_AON_CLK>;
clock-names = "core", "aon";
dmas = <&adm_dma 3>;
dma-names = "rxtx";
qcom,cmd-crci = <15>;
qcom,data-crci = <3>;
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>;
nand-ecc-strength = <4>;
nand-bus-width = <8>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "boot-nand";
reg = <0 0x58a0000>;
};
partition@58a0000 {
label = "fs-nand";
reg = <0x58a0000 0x4000000>;
};
};
};
};
nand-controller@79b0000 {
compatible = "qcom,ipq4019-nand";
reg = <0x79b0000 0x1000>;
clocks = <&gcc GCC_QPIC_CLK>,
<&gcc GCC_QPIC_AHB_CLK>;
clock-names = "core", "aon";
dmas = <&qpicbam 0>,
<&qpicbam 1>,
<&qpicbam 2>;
dma-names = "tx", "rx", "cmd";
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>;
nand-ecc-strength = <4>;
nand-bus-width = <8>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "boot-nand";
reg = <0 0x58a0000>;
};
partition@58a0000 {
label = "fs-nand";
reg = <0x58a0000 0x4000000>;
};
};
};
};
...@@ -822,6 +822,9 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, ...@@ -822,6 +822,9 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
/* Prefer parsed partitions over driver-provided fallback */ /* Prefer parsed partitions over driver-provided fallback */
ret = parse_mtd_partitions(mtd, types, parser_data); ret = parse_mtd_partitions(mtd, types, parser_data);
if (ret == -EPROBE_DEFER)
goto out;
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
else if (nr_parts) else if (nr_parts)
......
...@@ -236,7 +236,6 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand) ...@@ -236,7 +236,6 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand)
goto free_engine_conf; goto free_engine_conf;
engine_conf->code_size = code_size; engine_conf->code_size = code_size;
engine_conf->nsteps = nsteps;
engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL); engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL); engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
if (!engine_conf->calc_buf || !engine_conf->code_buf) { if (!engine_conf->calc_buf || !engine_conf->code_buf) {
...@@ -245,6 +244,7 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand) ...@@ -245,6 +244,7 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand)
} }
nand->ecc.ctx.priv = engine_conf; nand->ecc.ctx.priv = engine_conf;
nand->ecc.ctx.nsteps = nsteps;
nand->ecc.ctx.total = nsteps * code_size; nand->ecc.ctx.total = nsteps * code_size;
ret = nand_ecc_sw_bch_init(nand); ret = nand_ecc_sw_bch_init(nand);
...@@ -253,7 +253,7 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand) ...@@ -253,7 +253,7 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand)
/* Verify the layout validity */ /* Verify the layout validity */
if (mtd_ooblayout_count_eccbytes(mtd) != if (mtd_ooblayout_count_eccbytes(mtd) !=
engine_conf->nsteps * engine_conf->code_size) { nand->ecc.ctx.nsteps * engine_conf->code_size) {
pr_err("Invalid ECC layout\n"); pr_err("Invalid ECC layout\n");
ret = -EINVAL; ret = -EINVAL;
goto cleanup_bch_ctx; goto cleanup_bch_ctx;
...@@ -295,7 +295,7 @@ static int nand_ecc_sw_bch_prepare_io_req(struct nand_device *nand, ...@@ -295,7 +295,7 @@ static int nand_ecc_sw_bch_prepare_io_req(struct nand_device *nand,
struct mtd_info *mtd = nanddev_to_mtd(nand); struct mtd_info *mtd = nanddev_to_mtd(nand);
int eccsize = nand->ecc.ctx.conf.step_size; int eccsize = nand->ecc.ctx.conf.step_size;
int eccbytes = engine_conf->code_size; int eccbytes = engine_conf->code_size;
int eccsteps = engine_conf->nsteps; int eccsteps = nand->ecc.ctx.nsteps;
int total = nand->ecc.ctx.total; int total = nand->ecc.ctx.total;
u8 *ecccalc = engine_conf->calc_buf; u8 *ecccalc = engine_conf->calc_buf;
const u8 *data; const u8 *data;
...@@ -333,7 +333,7 @@ static int nand_ecc_sw_bch_finish_io_req(struct nand_device *nand, ...@@ -333,7 +333,7 @@ static int nand_ecc_sw_bch_finish_io_req(struct nand_device *nand,
int eccsize = nand->ecc.ctx.conf.step_size; int eccsize = nand->ecc.ctx.conf.step_size;
int total = nand->ecc.ctx.total; int total = nand->ecc.ctx.total;
int eccbytes = engine_conf->code_size; int eccbytes = engine_conf->code_size;
int eccsteps = engine_conf->nsteps; int eccsteps = nand->ecc.ctx.nsteps;
u8 *ecccalc = engine_conf->calc_buf; u8 *ecccalc = engine_conf->calc_buf;
u8 *ecccode = engine_conf->code_buf; u8 *ecccode = engine_conf->code_buf;
unsigned int max_bitflips = 0; unsigned int max_bitflips = 0;
...@@ -365,7 +365,7 @@ static int nand_ecc_sw_bch_finish_io_req(struct nand_device *nand, ...@@ -365,7 +365,7 @@ static int nand_ecc_sw_bch_finish_io_req(struct nand_device *nand,
nand_ecc_sw_bch_calculate(nand, data, &ecccalc[i]); nand_ecc_sw_bch_calculate(nand, data, &ecccalc[i]);
/* Finish a page read: compare and correct */ /* Finish a page read: compare and correct */
for (eccsteps = engine_conf->nsteps, i = 0, data = req->databuf.in; for (eccsteps = nand->ecc.ctx.nsteps, i = 0, data = req->databuf.in;
eccsteps; eccsteps;
eccsteps--, i += eccbytes, data += eccsize) { eccsteps--, i += eccbytes, data += eccsize) {
int stat = nand_ecc_sw_bch_correct(nand, data, int stat = nand_ecc_sw_bch_correct(nand, data,
......
...@@ -504,7 +504,6 @@ int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand) ...@@ -504,7 +504,6 @@ int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand)
goto free_engine_conf; goto free_engine_conf;
engine_conf->code_size = 3; engine_conf->code_size = 3;
engine_conf->nsteps = mtd->writesize / conf->step_size;
engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL); engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL); engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
if (!engine_conf->calc_buf || !engine_conf->code_buf) { if (!engine_conf->calc_buf || !engine_conf->code_buf) {
...@@ -513,7 +512,8 @@ int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand) ...@@ -513,7 +512,8 @@ int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand)
} }
nand->ecc.ctx.priv = engine_conf; nand->ecc.ctx.priv = engine_conf;
nand->ecc.ctx.total = engine_conf->nsteps * engine_conf->code_size; nand->ecc.ctx.nsteps = mtd->writesize / conf->step_size;
nand->ecc.ctx.total = nand->ecc.ctx.nsteps * engine_conf->code_size;
return 0; return 0;
...@@ -548,7 +548,7 @@ static int nand_ecc_sw_hamming_prepare_io_req(struct nand_device *nand, ...@@ -548,7 +548,7 @@ static int nand_ecc_sw_hamming_prepare_io_req(struct nand_device *nand,
struct mtd_info *mtd = nanddev_to_mtd(nand); struct mtd_info *mtd = nanddev_to_mtd(nand);
int eccsize = nand->ecc.ctx.conf.step_size; int eccsize = nand->ecc.ctx.conf.step_size;
int eccbytes = engine_conf->code_size; int eccbytes = engine_conf->code_size;
int eccsteps = engine_conf->nsteps; int eccsteps = nand->ecc.ctx.nsteps;
int total = nand->ecc.ctx.total; int total = nand->ecc.ctx.total;
u8 *ecccalc = engine_conf->calc_buf; u8 *ecccalc = engine_conf->calc_buf;
const u8 *data; const u8 *data;
...@@ -586,7 +586,7 @@ static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand, ...@@ -586,7 +586,7 @@ static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand,
int eccsize = nand->ecc.ctx.conf.step_size; int eccsize = nand->ecc.ctx.conf.step_size;
int total = nand->ecc.ctx.total; int total = nand->ecc.ctx.total;
int eccbytes = engine_conf->code_size; int eccbytes = engine_conf->code_size;
int eccsteps = engine_conf->nsteps; int eccsteps = nand->ecc.ctx.nsteps;
u8 *ecccalc = engine_conf->calc_buf; u8 *ecccalc = engine_conf->calc_buf;
u8 *ecccode = engine_conf->code_buf; u8 *ecccode = engine_conf->code_buf;
unsigned int max_bitflips = 0; unsigned int max_bitflips = 0;
...@@ -618,7 +618,7 @@ static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand, ...@@ -618,7 +618,7 @@ static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand,
nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]); nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]);
/* Finish a page read: compare and correct */ /* Finish a page read: compare and correct */
for (eccsteps = engine_conf->nsteps, i = 0, data = req->databuf.in; for (eccsteps = nand->ecc.ctx.nsteps, i = 0, data = req->databuf.in;
eccsteps; eccsteps;
eccsteps--, i += eccbytes, data += eccsize) { eccsteps--, i += eccbytes, data += eccsize) {
int stat = nand_ecc_sw_hamming_correct(nand, data, int stat = nand_ecc_sw_hamming_correct(nand, data,
......
...@@ -883,10 +883,12 @@ static int atmel_nand_pmecc_correct_data(struct nand_chip *chip, void *buf, ...@@ -883,10 +883,12 @@ static int atmel_nand_pmecc_correct_data(struct nand_chip *chip, void *buf,
NULL, 0, NULL, 0,
chip->ecc.strength); chip->ecc.strength);
if (ret >= 0) if (ret >= 0) {
mtd->ecc_stats.corrected += ret;
max_bitflips = max(ret, max_bitflips); max_bitflips = max(ret, max_bitflips);
else } else {
mtd->ecc_stats.failed++; mtd->ecc_stats.failed++;
}
databuf += chip->ecc.size; databuf += chip->ecc.size;
eccbuf += chip->ecc.bytes; eccbuf += chip->ecc.bytes;
......
...@@ -242,6 +242,9 @@ struct brcmnand_controller { ...@@ -242,6 +242,9 @@ struct brcmnand_controller {
u32 edu_ext_addr; u32 edu_ext_addr;
u32 edu_cmd; u32 edu_cmd;
u32 edu_config; u32 edu_config;
int sas; /* spare area size, per flash cache */
int sector_size_1k;
u8 *oob;
/* flash_dma reg */ /* flash_dma reg */
const u16 *flash_dma_offsets; const u16 *flash_dma_offsets;
...@@ -249,7 +252,7 @@ struct brcmnand_controller { ...@@ -249,7 +252,7 @@ struct brcmnand_controller {
dma_addr_t dma_pa; dma_addr_t dma_pa;
int (*dma_trans)(struct brcmnand_host *host, u64 addr, u32 *buf, int (*dma_trans)(struct brcmnand_host *host, u64 addr, u32 *buf,
u32 len, u8 dma_cmd); u8 *oob, u32 len, u8 dma_cmd);
/* in-memory cache of the FLASH_CACHE, used only for some commands */ /* in-memory cache of the FLASH_CACHE, used only for some commands */
u8 flash_cache[FC_BYTES]; u8 flash_cache[FC_BYTES];
...@@ -1479,6 +1482,23 @@ static irqreturn_t brcmnand_edu_irq(int irq, void *data) ...@@ -1479,6 +1482,23 @@ static irqreturn_t brcmnand_edu_irq(int irq, void *data)
edu_writel(ctrl, EDU_EXT_ADDR, ctrl->edu_ext_addr); edu_writel(ctrl, EDU_EXT_ADDR, ctrl->edu_ext_addr);
edu_readl(ctrl, EDU_EXT_ADDR); edu_readl(ctrl, EDU_EXT_ADDR);
if (ctrl->oob) {
if (ctrl->edu_cmd == EDU_CMD_READ) {
ctrl->oob += read_oob_from_regs(ctrl,
ctrl->edu_count + 1,
ctrl->oob, ctrl->sas,
ctrl->sector_size_1k);
} else {
brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
ctrl->edu_ext_addr);
brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
ctrl->oob += write_oob_to_regs(ctrl,
ctrl->edu_count,
ctrl->oob, ctrl->sas,
ctrl->sector_size_1k);
}
}
mb(); /* flush previous writes */ mb(); /* flush previous writes */
edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd); edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd);
edu_readl(ctrl, EDU_CMD); edu_readl(ctrl, EDU_CMD);
...@@ -1850,9 +1870,10 @@ static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf, ...@@ -1850,9 +1870,10 @@ static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf,
* Kick EDU engine * Kick EDU engine
*/ */
static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
u32 len, u8 cmd) u8 *oob, u32 len, u8 cmd)
{ {
struct brcmnand_controller *ctrl = host->ctrl; struct brcmnand_controller *ctrl = host->ctrl;
struct brcmnand_cfg *cfg = &host->hwcfg;
unsigned long timeo = msecs_to_jiffies(200); unsigned long timeo = msecs_to_jiffies(200);
int ret = 0; int ret = 0;
int dir = (cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE); int dir = (cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
...@@ -1860,6 +1881,9 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, ...@@ -1860,6 +1881,9 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
unsigned int trans = len >> FC_SHIFT; unsigned int trans = len >> FC_SHIFT;
dma_addr_t pa; dma_addr_t pa;
dev_dbg(ctrl->dev, "EDU %s %p:%p\n", ((edu_cmd == EDU_CMD_READ) ?
"read" : "write"), buf, oob);
pa = dma_map_single(ctrl->dev, buf, len, dir); pa = dma_map_single(ctrl->dev, buf, len, dir);
if (dma_mapping_error(ctrl->dev, pa)) { if (dma_mapping_error(ctrl->dev, pa)) {
dev_err(ctrl->dev, "unable to map buffer for EDU DMA\n"); dev_err(ctrl->dev, "unable to map buffer for EDU DMA\n");
...@@ -1871,6 +1895,8 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, ...@@ -1871,6 +1895,8 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
ctrl->edu_ext_addr = addr; ctrl->edu_ext_addr = addr;
ctrl->edu_cmd = edu_cmd; ctrl->edu_cmd = edu_cmd;
ctrl->edu_count = trans; ctrl->edu_count = trans;
ctrl->sas = cfg->spare_area_size;
ctrl->oob = oob;
edu_writel(ctrl, EDU_DRAM_ADDR, (u32)ctrl->edu_dram_addr); edu_writel(ctrl, EDU_DRAM_ADDR, (u32)ctrl->edu_dram_addr);
edu_readl(ctrl, EDU_DRAM_ADDR); edu_readl(ctrl, EDU_DRAM_ADDR);
...@@ -1879,6 +1905,16 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, ...@@ -1879,6 +1905,16 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
edu_writel(ctrl, EDU_LENGTH, FC_BYTES); edu_writel(ctrl, EDU_LENGTH, FC_BYTES);
edu_readl(ctrl, EDU_LENGTH); edu_readl(ctrl, EDU_LENGTH);
if (ctrl->oob && (ctrl->edu_cmd == EDU_CMD_WRITE)) {
brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
ctrl->edu_ext_addr);
brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
ctrl->oob += write_oob_to_regs(ctrl,
1,
ctrl->oob, ctrl->sas,
ctrl->sector_size_1k);
}
/* Start edu engine */ /* Start edu engine */
mb(); /* flush previous writes */ mb(); /* flush previous writes */
edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd); edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd);
...@@ -1893,6 +1929,14 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, ...@@ -1893,6 +1929,14 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
dma_unmap_single(ctrl->dev, pa, len, dir); dma_unmap_single(ctrl->dev, pa, len, dir);
/* read last subpage oob */
if (ctrl->oob && (ctrl->edu_cmd == EDU_CMD_READ)) {
ctrl->oob += read_oob_from_regs(ctrl,
1,
ctrl->oob, ctrl->sas,
ctrl->sector_size_1k);
}
/* for program page check NAND status */ /* for program page check NAND status */
if (((brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) & if (((brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
INTFC_FLASH_STATUS) & NAND_STATUS_FAIL) && INTFC_FLASH_STATUS) & NAND_STATUS_FAIL) &&
...@@ -2002,7 +2046,7 @@ static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc) ...@@ -2002,7 +2046,7 @@ static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
} }
static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf, static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
u32 len, u8 dma_cmd) u8 *oob, u32 len, u8 dma_cmd)
{ {
struct brcmnand_controller *ctrl = host->ctrl; struct brcmnand_controller *ctrl = host->ctrl;
dma_addr_t buf_pa; dma_addr_t buf_pa;
...@@ -2147,8 +2191,9 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2147,8 +2191,9 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
try_dmaread: try_dmaread:
brcmnand_clear_ecc_addr(ctrl); brcmnand_clear_ecc_addr(ctrl);
if (ctrl->dma_trans && !oob && flash_dma_buf_ok(buf)) { if (ctrl->dma_trans && (has_edu(ctrl) || !oob) &&
err = ctrl->dma_trans(host, addr, buf, flash_dma_buf_ok(buf)) {
err = ctrl->dma_trans(host, addr, buf, oob,
trans * FC_BYTES, trans * FC_BYTES,
CMD_PAGE_READ); CMD_PAGE_READ);
...@@ -2296,8 +2341,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2296,8 +2341,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < ctrl->max_oob; i += 4) for (i = 0; i < ctrl->max_oob; i += 4)
oob_reg_write(ctrl, i, 0xffffffff); oob_reg_write(ctrl, i, 0xffffffff);
if (use_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) { if (mtd->oops_panic_write)
if (ctrl->dma_trans(host, addr, (u32 *)buf, mtd->writesize, /* switch to interrupt polling and PIO mode */
disable_ctrl_irqs(ctrl);
if (use_dma(ctrl) && (has_edu(ctrl) || !oob) && flash_dma_buf_ok(buf)) {
if (ctrl->dma_trans(host, addr, (u32 *)buf, oob, mtd->writesize,
CMD_PROGRAM_PAGE)) CMD_PROGRAM_PAGE))
ret = -EIO; ret = -EIO;
...@@ -2688,6 +2737,12 @@ static int brcmnand_attach_chip(struct nand_chip *chip) ...@@ -2688,6 +2737,12 @@ static int brcmnand_attach_chip(struct nand_chip *chip)
ret = brcmstb_choose_ecc_layout(host); ret = brcmstb_choose_ecc_layout(host);
/* If OOB is written with ECC enabled it will cause ECC errors */
if (is_hamming_ecc(host->ctrl, &host->hwcfg)) {
chip->ecc.write_oob = brcmnand_write_oob_raw;
chip->ecc.read_oob = brcmnand_read_oob_raw;
}
return ret; return ret;
} }
......
...@@ -1078,11 +1078,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -1078,11 +1078,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
host->read_dma_chan = dma_request_channel(mask, filter, NULL); host->read_dma_chan = dma_request_channel(mask, filter, NULL);
if (!host->read_dma_chan) { if (!host->read_dma_chan) {
dev_err(&pdev->dev, "Unable to get read dma channel\n"); dev_err(&pdev->dev, "Unable to get read dma channel\n");
ret = -ENODEV;
goto disable_clk; goto disable_clk;
} }
host->write_dma_chan = dma_request_channel(mask, filter, NULL); host->write_dma_chan = dma_request_channel(mask, filter, NULL);
if (!host->write_dma_chan) { if (!host->write_dma_chan) {
dev_err(&pdev->dev, "Unable to get write dma channel\n"); dev_err(&pdev->dev, "Unable to get write dma channel\n");
ret = -ENODEV;
goto release_dma_read_chan; goto release_dma_read_chan;
} }
} }
......
...@@ -2449,7 +2449,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) ...@@ -2449,7 +2449,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
this->bch_geometry.auxiliary_size = 128; this->bch_geometry.auxiliary_size = 128;
ret = gpmi_alloc_dma_buffer(this); ret = gpmi_alloc_dma_buffer(this);
if (ret) if (ret)
goto err_out; return ret;
nand_controller_init(&this->base); nand_controller_init(&this->base);
this->base.ops = &gpmi_nand_controller_ops; this->base.ops = &gpmi_nand_controller_ops;
......
...@@ -1849,7 +1849,7 @@ static int mxcnd_remove(struct platform_device *pdev) ...@@ -1849,7 +1849,7 @@ static int mxcnd_remove(struct platform_device *pdev)
static struct platform_driver mxcnd_driver = { static struct platform_driver mxcnd_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = of_match_ptr(mxcnd_dt_ids), .of_match_table = mxcnd_dt_ids,
}, },
.probe = mxcnd_probe, .probe = mxcnd_probe,
.remove = mxcnd_remove, .remove = mxcnd_remove,
......
...@@ -278,11 +278,48 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs) ...@@ -278,11 +278,48 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
return 0; return 0;
} }
/**
* nand_region_is_secured() - Check if the region is secured
* @chip: NAND chip object
* @offset: Offset of the region to check
* @size: Size of the region to check
*
* Checks if the region is secured by comparing the offset and size with the
* list of secure regions obtained from DT. Returns true if the region is
* secured else false.
*/
static bool nand_region_is_secured(struct nand_chip *chip, loff_t offset, u64 size)
{
int i;
/* Skip touching the secure regions if present */
for (i = 0; i < chip->nr_secure_regions; i++) {
const struct nand_secure_region *region = &chip->secure_regions[i];
if (offset + size <= region->offset ||
offset >= region->offset + region->size)
continue;
pr_debug("%s: Region 0x%llx - 0x%llx is secured!",
__func__, offset, offset + size);
return true;
}
return false;
}
static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
{ {
struct mtd_info *mtd = nand_to_mtd(chip);
if (chip->options & NAND_NO_BBM_QUIRK) if (chip->options & NAND_NO_BBM_QUIRK)
return 0; return 0;
/* Check if the region is secured */
if (nand_region_is_secured(chip, ofs, mtd->erasesize))
return -EIO;
if (chip->legacy.block_bad) if (chip->legacy.block_bad)
return chip->legacy.block_bad(chip, ofs); return chip->legacy.block_bad(chip, ofs);
...@@ -397,6 +434,10 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to, ...@@ -397,6 +434,10 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
return -EINVAL; return -EINVAL;
} }
/* Check if the region is secured */
if (nand_region_is_secured(chip, to, ops->ooblen))
return -EIO;
chipnr = (int)(to >> chip->chip_shift); chipnr = (int)(to >> chip->chip_shift);
/* /*
...@@ -1294,8 +1335,6 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page, ...@@ -1294,8 +1335,6 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
}; };
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page); int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page);
int ret;
u8 status;
if (naddrs < 0) if (naddrs < 0)
return naddrs; return naddrs;
...@@ -1335,15 +1374,7 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page, ...@@ -1335,15 +1374,7 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
op.ninstrs--; op.ninstrs--;
} }
ret = nand_exec_op(chip, &op); return nand_exec_op(chip, &op);
if (!prog || ret)
return ret;
ret = nand_status_op(chip, &status);
if (ret)
return ret;
return status;
} }
/** /**
...@@ -1449,7 +1480,8 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page, ...@@ -1449,7 +1480,8 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
unsigned int len) unsigned int len)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
int status; u8 status;
int ret;
if (!len || !buf) if (!len || !buf)
return -EINVAL; return -EINVAL;
...@@ -1458,14 +1490,24 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page, ...@@ -1458,14 +1490,24 @@ int nand_prog_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)) {
status = nand_exec_prog_page_op(chip, page, offset_in_page, buf, ret = nand_exec_prog_page_op(chip, page, offset_in_page, buf,
len, true); len, true);
if (ret)
return ret;
ret = nand_status_op(chip, &status);
if (ret)
return ret;
} else { } else {
chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page, chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page,
page); page);
chip->legacy.write_buf(chip, buf, len); chip->legacy.write_buf(chip, buf, len);
chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1); chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
status = chip->legacy.waitfunc(chip); ret = chip->legacy.waitfunc(chip);
if (ret < 0)
return ret;
status = ret;
} }
if (status & NAND_STATUS_FAIL) if (status & NAND_STATUS_FAIL)
...@@ -3127,6 +3169,10 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from, ...@@ -3127,6 +3169,10 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
int retry_mode = 0; int retry_mode = 0;
bool ecc_fail = false; bool ecc_fail = false;
/* Check if the region is secured */
if (nand_region_is_secured(chip, from, readlen))
return -EIO;
chipnr = (int)(from >> chip->chip_shift); chipnr = (int)(from >> chip->chip_shift);
nand_select_target(chip, chipnr); nand_select_target(chip, chipnr);
...@@ -3458,6 +3504,10 @@ static int nand_do_read_oob(struct nand_chip *chip, loff_t from, ...@@ -3458,6 +3504,10 @@ static int nand_do_read_oob(struct nand_chip *chip, loff_t from,
pr_debug("%s: from = 0x%08Lx, len = %i\n", pr_debug("%s: from = 0x%08Lx, len = %i\n",
__func__, (unsigned long long)from, readlen); __func__, (unsigned long long)from, readlen);
/* Check if the region is secured */
if (nand_region_is_secured(chip, from, readlen))
return -EIO;
stats = mtd->ecc_stats; stats = mtd->ecc_stats;
len = mtd_oobavail(mtd, ops); len = mtd_oobavail(mtd, ops);
...@@ -3979,6 +4029,10 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to, ...@@ -3979,6 +4029,10 @@ static int nand_do_write_ops(struct nand_chip *chip, loff_t to,
return -EINVAL; return -EINVAL;
} }
/* Check if the region is secured */
if (nand_region_is_secured(chip, to, writelen))
return -EIO;
column = to & (mtd->writesize - 1); column = to & (mtd->writesize - 1);
chipnr = (int)(to >> chip->chip_shift); chipnr = (int)(to >> chip->chip_shift);
...@@ -4180,6 +4234,10 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, ...@@ -4180,6 +4234,10 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
if (check_offs_len(chip, instr->addr, instr->len)) if (check_offs_len(chip, instr->addr, instr->len))
return -EINVAL; return -EINVAL;
/* Check if the region is secured */
if (nand_region_is_secured(chip, instr->addr, instr->len))
return -EIO;
/* Grab the lock and see if the device is available */ /* Grab the lock and see if the device is available */
ret = nand_get_device(chip); ret = nand_get_device(chip);
if (ret) if (ret)
...@@ -4995,6 +5053,31 @@ static bool of_get_nand_on_flash_bbt(struct device_node *np) ...@@ -4995,6 +5053,31 @@ static bool of_get_nand_on_flash_bbt(struct device_node *np)
return of_property_read_bool(np, "nand-on-flash-bbt"); return of_property_read_bool(np, "nand-on-flash-bbt");
} }
static int of_get_nand_secure_regions(struct nand_chip *chip)
{
struct device_node *dn = nand_get_flash_node(chip);
int nr_elem, i, j;
nr_elem = of_property_count_elems_of_size(dn, "secure-regions", sizeof(u64));
if (!nr_elem)
return 0;
chip->nr_secure_regions = nr_elem / 2;
chip->secure_regions = kcalloc(chip->nr_secure_regions, sizeof(*chip->secure_regions),
GFP_KERNEL);
if (!chip->secure_regions)
return -ENOMEM;
for (i = 0, j = 0; i < chip->nr_secure_regions; i++, j += 2) {
of_property_read_u64_index(dn, "secure-regions", j,
&chip->secure_regions[i].offset);
of_property_read_u64_index(dn, "secure-regions", j + 1,
&chip->secure_regions[i].size);
}
return 0;
}
static int rawnand_dt_init(struct nand_chip *chip) static int rawnand_dt_init(struct nand_chip *chip)
{ {
struct nand_device *nand = mtd_to_nanddev(nand_to_mtd(chip)); struct nand_device *nand = mtd_to_nanddev(nand_to_mtd(chip));
...@@ -5162,8 +5245,8 @@ int rawnand_sw_hamming_init(struct nand_chip *chip) ...@@ -5162,8 +5245,8 @@ int rawnand_sw_hamming_init(struct nand_chip *chip)
chip->ecc.size = base->ecc.ctx.conf.step_size; chip->ecc.size = base->ecc.ctx.conf.step_size;
chip->ecc.strength = base->ecc.ctx.conf.strength; chip->ecc.strength = base->ecc.ctx.conf.strength;
chip->ecc.total = base->ecc.ctx.total; chip->ecc.total = base->ecc.ctx.total;
chip->ecc.steps = engine_conf->nsteps; chip->ecc.steps = nanddev_get_ecc_nsteps(base);
chip->ecc.bytes = engine_conf->code_size; chip->ecc.bytes = base->ecc.ctx.total / nanddev_get_ecc_nsteps(base);
return 0; return 0;
} }
...@@ -5201,7 +5284,7 @@ EXPORT_SYMBOL(rawnand_sw_hamming_cleanup); ...@@ -5201,7 +5284,7 @@ EXPORT_SYMBOL(rawnand_sw_hamming_cleanup);
int rawnand_sw_bch_init(struct nand_chip *chip) int rawnand_sw_bch_init(struct nand_chip *chip)
{ {
struct nand_device *base = &chip->base; struct nand_device *base = &chip->base;
struct nand_ecc_sw_bch_conf *engine_conf; const struct nand_ecc_props *ecc_conf = nanddev_get_ecc_conf(base);
int ret; int ret;
base->ecc.user_conf.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; base->ecc.user_conf.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
...@@ -5213,13 +5296,11 @@ int rawnand_sw_bch_init(struct nand_chip *chip) ...@@ -5213,13 +5296,11 @@ int rawnand_sw_bch_init(struct nand_chip *chip)
if (ret) if (ret)
return ret; return ret;
engine_conf = base->ecc.ctx.priv; chip->ecc.size = ecc_conf->step_size;
chip->ecc.strength = ecc_conf->strength;
chip->ecc.size = base->ecc.ctx.conf.step_size;
chip->ecc.strength = base->ecc.ctx.conf.strength;
chip->ecc.total = base->ecc.ctx.total; chip->ecc.total = base->ecc.ctx.total;
chip->ecc.steps = engine_conf->nsteps; chip->ecc.steps = nanddev_get_ecc_nsteps(base);
chip->ecc.bytes = engine_conf->code_size; chip->ecc.bytes = base->ecc.ctx.total / nanddev_get_ecc_nsteps(base);
return 0; return 0;
} }
...@@ -5953,6 +6034,16 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5953,6 +6034,16 @@ static int nand_scan_tail(struct nand_chip *chip)
goto err_free_interface_config; goto err_free_interface_config;
} }
/*
* 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
* accesses to these regions will be blocked in the runtime by this
* driver.
*/
ret = of_get_nand_secure_regions(chip);
if (ret)
goto err_free_interface_config;
/* Check, if we should skip the bad block table scan */ /* Check, if we should skip the bad block table scan */
if (chip->options & NAND_SKIP_BBTSCAN) if (chip->options & NAND_SKIP_BBTSCAN)
return 0; return 0;
...@@ -5960,10 +6051,13 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5960,10 +6051,13 @@ static int nand_scan_tail(struct nand_chip *chip)
/* Build bad block table */ /* Build bad block table */
ret = nand_create_bbt(chip); ret = nand_create_bbt(chip);
if (ret) if (ret)
goto err_free_interface_config; goto err_free_secure_regions;
return 0; return 0;
err_free_secure_regions:
kfree(chip->secure_regions);
err_free_interface_config: err_free_interface_config:
kfree(chip->best_interface_config); kfree(chip->best_interface_config);
...@@ -6051,6 +6145,9 @@ void nand_cleanup(struct nand_chip *chip) ...@@ -6051,6 +6145,9 @@ void nand_cleanup(struct nand_chip *chip)
nanddev_cleanup(&chip->base); nanddev_cleanup(&chip->base);
/* Free secure regions data */
kfree(chip->secure_regions);
/* Free bad block table memory */ /* Free bad block table memory */
kfree(chip->bbt); kfree(chip->bbt);
kfree(chip->data_buf); kfree(chip->data_buf);
......
...@@ -525,6 +525,7 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf, ...@@ -525,6 +525,7 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf,
{ {
u64 targetsize = nanddev_target_size(&this->base); u64 targetsize = nanddev_target_size(&this->base);
struct mtd_info *mtd = nand_to_mtd(this); struct mtd_info *mtd = nand_to_mtd(this);
struct nand_bbt_descr *bd = this->badblock_pattern;
int i, chips; int i, chips;
int startblock, block, dir; int startblock, block, dir;
int scanlen = mtd->writesize + mtd->oobsize; int scanlen = mtd->writesize + mtd->oobsize;
...@@ -560,6 +561,10 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf, ...@@ -560,6 +561,10 @@ static int search_bbt(struct nand_chip *this, uint8_t *buf,
int actblock = startblock + dir * block; int actblock = startblock + dir * block;
loff_t offs = (loff_t)actblock << this->bbt_erase_shift; loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
/* Check if block is marked bad */
if (scan_block_fast(this, bd, offs, buf))
continue;
/* Read first page */ /* Read first page */
scan_read(this, buf, offs, mtd->writesize, td); scan_read(this, buf, offs, mtd->writesize, td);
if (!check_pattern(buf, scanlen, mtd->writesize, td)) { if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
......
...@@ -1868,18 +1868,19 @@ static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section, ...@@ -1868,18 +1868,19 @@ static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion) struct mtd_oob_region *oobregion)
{ {
struct nand_device *nand = mtd_to_nanddev(mtd); struct nand_device *nand = mtd_to_nanddev(mtd);
const struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv; unsigned int nsteps = nanddev_get_ecc_nsteps(nand);
unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand);
int off = BADBLOCK_MARKER_LENGTH; int off = BADBLOCK_MARKER_LENGTH;
if (section >= engine_conf->nsteps) if (section >= nsteps)
return -ERANGE; return -ERANGE;
/* /*
* When SW correction is employed, one OMAP specific marker byte is * When SW correction is employed, one OMAP specific marker byte is
* reserved after each ECC step. * reserved after each ECC step.
*/ */
oobregion->offset = off + (section * (engine_conf->code_size + 1)); oobregion->offset = off + (section * (ecc_bytes + 1));
oobregion->length = engine_conf->code_size; oobregion->length = ecc_bytes;
return 0; return 0;
} }
...@@ -1888,7 +1889,8 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section, ...@@ -1888,7 +1889,8 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion) struct mtd_oob_region *oobregion)
{ {
struct nand_device *nand = mtd_to_nanddev(mtd); struct nand_device *nand = mtd_to_nanddev(mtd);
const struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv; unsigned int nsteps = nanddev_get_ecc_nsteps(nand);
unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand);
int off = BADBLOCK_MARKER_LENGTH; int off = BADBLOCK_MARKER_LENGTH;
if (section) if (section)
...@@ -1898,7 +1900,7 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section, ...@@ -1898,7 +1900,7 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
* When SW correction is employed, one OMAP specific marker byte is * When SW correction is employed, one OMAP specific marker byte is
* reserved after each ECC step. * reserved after each ECC step.
*/ */
off += ((engine_conf->code_size + 1) * engine_conf->nsteps); off += ((ecc_bytes + 1) * nsteps);
if (off >= mtd->oobsize) if (off >= mtd->oobsize)
return -ERANGE; return -ERANGE;
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#define NAND_DEV0_CFG0 0x20 #define NAND_DEV0_CFG0 0x20
#define NAND_DEV0_CFG1 0x24 #define NAND_DEV0_CFG1 0x24
#define NAND_DEV0_ECC_CFG 0x28 #define NAND_DEV0_ECC_CFG 0x28
#define NAND_DEV1_ECC_CFG 0x2c #define NAND_AUTO_STATUS_EN 0x2c
#define NAND_DEV1_CFG0 0x30 #define NAND_DEV1_CFG0 0x30
#define NAND_DEV1_CFG1 0x34 #define NAND_DEV1_CFG1 0x34
#define NAND_READ_ID 0x40 #define NAND_READ_ID 0x40
...@@ -48,6 +48,10 @@ ...@@ -48,6 +48,10 @@
#define NAND_READ_LOCATION_1 0xf24 #define NAND_READ_LOCATION_1 0xf24
#define NAND_READ_LOCATION_2 0xf28 #define NAND_READ_LOCATION_2 0xf28
#define NAND_READ_LOCATION_3 0xf2c #define NAND_READ_LOCATION_3 0xf2c
#define NAND_READ_LOCATION_LAST_CW_0 0xf40
#define NAND_READ_LOCATION_LAST_CW_1 0xf44
#define NAND_READ_LOCATION_LAST_CW_2 0xf48
#define NAND_READ_LOCATION_LAST_CW_3 0xf4c
/* dummy register offsets, used by write_reg_dma */ /* dummy register offsets, used by write_reg_dma */
#define NAND_DEV_CMD1_RESTORE 0xdead #define NAND_DEV_CMD1_RESTORE 0xdead
...@@ -181,12 +185,17 @@ ...@@ -181,12 +185,17 @@
#define ECC_BCH_4BIT BIT(2) #define ECC_BCH_4BIT BIT(2)
#define ECC_BCH_8BIT BIT(3) #define ECC_BCH_8BIT BIT(3)
#define nandc_set_read_loc(nandc, reg, offset, size, is_last) \ #define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc) \
nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ nandc_set_reg(chip, reg, \
((offset) << READ_LOCATION_OFFSET) | \ ((cw_offset) << READ_LOCATION_OFFSET) | \
((size) << READ_LOCATION_SIZE) | \ ((read_size) << READ_LOCATION_SIZE) | \
((is_last) << READ_LOCATION_LAST)) ((is_last_read_loc) << READ_LOCATION_LAST))
#define nandc_set_read_loc_last(chip, reg, cw_offset, read_size, is_last_read_loc) \
nandc_set_reg(chip, reg, \
((cw_offset) << READ_LOCATION_OFFSET) | \
((read_size) << READ_LOCATION_SIZE) | \
((is_last_read_loc) << READ_LOCATION_LAST))
/* /*
* Returns the actual register address for all NAND_DEV_ registers * Returns the actual register address for all NAND_DEV_ registers
* (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD)
...@@ -316,6 +325,10 @@ struct nandc_regs { ...@@ -316,6 +325,10 @@ struct nandc_regs {
__le32 read_location1; __le32 read_location1;
__le32 read_location2; __le32 read_location2;
__le32 read_location3; __le32 read_location3;
__le32 read_location_last0;
__le32 read_location_last1;
__le32 read_location_last2;
__le32 read_location_last3;
__le32 erased_cw_detect_cfg_clr; __le32 erased_cw_detect_cfg_clr;
__le32 erased_cw_detect_cfg_set; __le32 erased_cw_detect_cfg_set;
...@@ -644,14 +657,23 @@ static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset) ...@@ -644,14 +657,23 @@ static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
return &regs->read_location2; return &regs->read_location2;
case NAND_READ_LOCATION_3: case NAND_READ_LOCATION_3:
return &regs->read_location3; return &regs->read_location3;
case NAND_READ_LOCATION_LAST_CW_0:
return &regs->read_location_last0;
case NAND_READ_LOCATION_LAST_CW_1:
return &regs->read_location_last1;
case NAND_READ_LOCATION_LAST_CW_2:
return &regs->read_location_last2;
case NAND_READ_LOCATION_LAST_CW_3:
return &regs->read_location_last3;
default: default:
return NULL; return NULL;
} }
} }
static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset, static void nandc_set_reg(struct nand_chip *chip, int offset,
u32 val) u32 val)
{ {
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nandc_regs *regs = nandc->regs; struct nandc_regs *regs = nandc->regs;
__le32 *reg; __le32 *reg;
...@@ -661,17 +683,43 @@ static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset, ...@@ -661,17 +683,43 @@ static void nandc_set_reg(struct qcom_nand_controller *nandc, int offset,
*reg = cpu_to_le32(val); *reg = cpu_to_le32(val);
} }
/* Helper to check the code word, whether it is last cw or not */
static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw)
{
return cw == (ecc->steps - 1);
}
/* helper to configure location register values */
static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg,
int cw_offset, int read_size, int is_last_read_loc)
{
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int reg_base = NAND_READ_LOCATION_0;
if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
reg_base = NAND_READ_LOCATION_LAST_CW_0;
reg_base += reg * 4;
if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
return nandc_set_read_loc_last(chip, reg_base, cw_offset,
read_size, is_last_read_loc);
else
return nandc_set_read_loc_first(chip, reg_base, cw_offset,
read_size, is_last_read_loc);
}
/* helper to configure address register values */ /* helper to configure address register values */
static void set_address(struct qcom_nand_host *host, u16 column, int page) static void set_address(struct qcom_nand_host *host, u16 column, int page)
{ {
struct nand_chip *chip = &host->chip; struct nand_chip *chip = &host->chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
if (chip->options & NAND_BUSWIDTH_16) if (chip->options & NAND_BUSWIDTH_16)
column >>= 1; column >>= 1;
nandc_set_reg(nandc, NAND_ADDR0, page << 16 | column); nandc_set_reg(chip, NAND_ADDR0, page << 16 | column);
nandc_set_reg(nandc, NAND_ADDR1, page >> 16 & 0xff); nandc_set_reg(chip, NAND_ADDR1, page >> 16 & 0xff);
} }
/* /*
...@@ -680,11 +728,11 @@ static void set_address(struct qcom_nand_host *host, u16 column, int page) ...@@ -680,11 +728,11 @@ static void set_address(struct qcom_nand_host *host, u16 column, int page)
* *
* @num_cw: number of steps for the read/write operation * @num_cw: number of steps for the read/write operation
* @read: read or write operation * @read: read or write operation
* @cw : which code word
*/ */
static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, int cw)
{ {
struct nand_chip *chip = &host->chip; struct nand_chip *chip = &host->chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
u32 cmd, cfg0, cfg1, ecc_bch_cfg; u32 cmd, cfg0, cfg1, ecc_bch_cfg;
if (read) { if (read) {
...@@ -710,17 +758,17 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) ...@@ -710,17 +758,17 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read)
ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
} }
nandc_set_reg(nandc, NAND_FLASH_CMD, cmd); nandc_set_reg(chip, NAND_FLASH_CMD, cmd);
nandc_set_reg(nandc, NAND_DEV0_CFG0, cfg0); nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0);
nandc_set_reg(nandc, NAND_DEV0_CFG1, cfg1); nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1);
nandc_set_reg(nandc, NAND_DEV0_ECC_CFG, ecc_bch_cfg); nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg); nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus); nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus); nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
nandc_set_reg(nandc, NAND_EXEC_CMD, 1); nandc_set_reg(chip, NAND_EXEC_CMD, 1);
if (read) if (read)
nandc_set_read_loc(nandc, 0, 0, host->use_ecc ? nandc_set_read_loc(chip, cw, 0, 0, host->use_ecc ?
host->cw_data : host->cw_size, 1); host->cw_data : host->cw_size, 1);
} }
...@@ -1079,8 +1127,10 @@ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, ...@@ -1079,8 +1127,10 @@ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off,
* Helper to prepare DMA descriptors for configuring registers * Helper to prepare DMA descriptors for configuring registers
* before reading a NAND page. * before reading a NAND page.
*/ */
static void config_nand_page_read(struct qcom_nand_controller *nandc) static void config_nand_page_read(struct nand_chip *chip)
{ {
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
write_reg_dma(nandc, NAND_ADDR0, 2, 0); write_reg_dma(nandc, NAND_ADDR0, 2, 0);
write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0); write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
...@@ -1094,11 +1144,18 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc) ...@@ -1094,11 +1144,18 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc)
* before reading each codeword in NAND page. * before reading each codeword in NAND page.
*/ */
static void static void
config_nand_cw_read(struct qcom_nand_controller *nandc, bool use_ecc) config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw)
{ {
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int reg = NAND_READ_LOCATION_0;
if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw))
reg = NAND_READ_LOCATION_LAST_CW_0;
if (nandc->props->is_bam) if (nandc->props->is_bam)
write_reg_dma(nandc, NAND_READ_LOCATION_0, 4, write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL);
NAND_BAM_NEXT_SGL);
write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
...@@ -1117,19 +1174,21 @@ config_nand_cw_read(struct qcom_nand_controller *nandc, bool use_ecc) ...@@ -1117,19 +1174,21 @@ config_nand_cw_read(struct qcom_nand_controller *nandc, bool use_ecc)
* single codeword in page * single codeword in page
*/ */
static void static void
config_nand_single_cw_page_read(struct qcom_nand_controller *nandc, config_nand_single_cw_page_read(struct nand_chip *chip,
bool use_ecc) bool use_ecc, int cw)
{ {
config_nand_page_read(nandc); config_nand_page_read(chip);
config_nand_cw_read(nandc, use_ecc); config_nand_cw_read(chip, use_ecc, cw);
} }
/* /*
* Helper to prepare DMA descriptors used to configure registers needed for * Helper to prepare DMA descriptors used to configure registers needed for
* before writing a NAND page. * before writing a NAND page.
*/ */
static void config_nand_page_write(struct qcom_nand_controller *nandc) static void config_nand_page_write(struct nand_chip *chip)
{ {
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
write_reg_dma(nandc, NAND_ADDR0, 2, 0); write_reg_dma(nandc, NAND_ADDR0, 2, 0);
write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
...@@ -1140,8 +1199,10 @@ static void config_nand_page_write(struct qcom_nand_controller *nandc) ...@@ -1140,8 +1199,10 @@ static void config_nand_page_write(struct qcom_nand_controller *nandc)
* Helper to prepare DMA descriptors for configuring registers * Helper to prepare DMA descriptors for configuring registers
* before writing each codeword in NAND page. * before writing each codeword in NAND page.
*/ */
static void config_nand_cw_write(struct qcom_nand_controller *nandc) static void config_nand_cw_write(struct nand_chip *chip)
{ {
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
...@@ -1168,44 +1229,44 @@ static int nandc_param(struct qcom_nand_host *host) ...@@ -1168,44 +1229,44 @@ static int nandc_param(struct qcom_nand_host *host)
* bytes to read onfi params * bytes to read onfi params
*/ */
if (nandc->props->qpic_v2) if (nandc->props->qpic_v2)
nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ_ONFI_READ | nandc_set_reg(chip, NAND_FLASH_CMD, OP_PAGE_READ_ONFI_READ |
PAGE_ACC | LAST_PAGE); PAGE_ACC | LAST_PAGE);
else else
nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ | nandc_set_reg(chip, NAND_FLASH_CMD, OP_PAGE_READ |
PAGE_ACC | LAST_PAGE); PAGE_ACC | LAST_PAGE);
nandc_set_reg(nandc, NAND_ADDR0, 0); nandc_set_reg(chip, NAND_ADDR0, 0);
nandc_set_reg(nandc, NAND_ADDR1, 0); nandc_set_reg(chip, NAND_ADDR1, 0);
nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
| 512 << UD_SIZE_BYTES | 512 << UD_SIZE_BYTES
| 5 << NUM_ADDR_CYCLES | 5 << NUM_ADDR_CYCLES
| 0 << SPARE_SIZE_BYTES); | 0 << SPARE_SIZE_BYTES);
nandc_set_reg(nandc, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
| 0 << CS_ACTIVE_BSY | 0 << CS_ACTIVE_BSY
| 17 << BAD_BLOCK_BYTE_NUM | 17 << BAD_BLOCK_BYTE_NUM
| 1 << BAD_BLOCK_IN_SPARE_AREA | 1 << BAD_BLOCK_IN_SPARE_AREA
| 2 << WR_RD_BSY_GAP | 2 << WR_RD_BSY_GAP
| 0 << WIDE_FLASH | 0 << WIDE_FLASH
| 1 << DEV0_CFG1_ECC_DISABLE); | 1 << DEV0_CFG1_ECC_DISABLE);
nandc_set_reg(nandc, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE); nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
/* configure CMD1 and VLD for ONFI param probing in QPIC v1 */ /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
if (!nandc->props->qpic_v2) { if (!nandc->props->qpic_v2) {
nandc_set_reg(nandc, NAND_DEV_CMD_VLD, nandc_set_reg(chip, NAND_DEV_CMD_VLD,
(nandc->vld & ~READ_START_VLD)); (nandc->vld & ~READ_START_VLD));
nandc_set_reg(nandc, NAND_DEV_CMD1, nandc_set_reg(chip, NAND_DEV_CMD1,
(nandc->cmd1 & ~(0xFF << READ_ADDR)) (nandc->cmd1 & ~(0xFF << READ_ADDR))
| NAND_CMD_PARAM << READ_ADDR); | NAND_CMD_PARAM << READ_ADDR);
} }
nandc_set_reg(nandc, NAND_EXEC_CMD, 1); nandc_set_reg(chip, NAND_EXEC_CMD, 1);
if (!nandc->props->qpic_v2) { if (!nandc->props->qpic_v2) {
nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1); nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1);
nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld);
} }
nandc_set_read_loc(nandc, 0, 0, 512, 1); nandc_set_read_loc(chip, 0, 0, 0, 512, 1);
if (!nandc->props->qpic_v2) { if (!nandc->props->qpic_v2) {
write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0);
...@@ -1215,7 +1276,7 @@ static int nandc_param(struct qcom_nand_host *host) ...@@ -1215,7 +1276,7 @@ static int nandc_param(struct qcom_nand_host *host)
nandc->buf_count = 512; nandc->buf_count = 512;
memset(nandc->data_buffer, 0xff, nandc->buf_count); memset(nandc->data_buffer, 0xff, nandc->buf_count);
config_nand_single_cw_page_read(nandc, false); config_nand_single_cw_page_read(chip, false, 0);
read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer,
nandc->buf_count, 0); nandc->buf_count, 0);
...@@ -1235,16 +1296,16 @@ static int erase_block(struct qcom_nand_host *host, int page_addr) ...@@ -1235,16 +1296,16 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
struct nand_chip *chip = &host->chip; struct nand_chip *chip = &host->chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
nandc_set_reg(nandc, NAND_FLASH_CMD, nandc_set_reg(chip, NAND_FLASH_CMD,
OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE); OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
nandc_set_reg(nandc, NAND_ADDR0, page_addr); nandc_set_reg(chip, NAND_ADDR0, page_addr);
nandc_set_reg(nandc, NAND_ADDR1, 0); nandc_set_reg(chip, NAND_ADDR1, 0);
nandc_set_reg(nandc, NAND_DEV0_CFG0, nandc_set_reg(chip, NAND_DEV0_CFG0,
host->cfg0_raw & ~(7 << CW_PER_PAGE)); host->cfg0_raw & ~(7 << CW_PER_PAGE));
nandc_set_reg(nandc, NAND_DEV0_CFG1, host->cfg1_raw); nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
nandc_set_reg(nandc, NAND_EXEC_CMD, 1); nandc_set_reg(chip, NAND_EXEC_CMD, 1);
nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus); nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus); nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
...@@ -1267,12 +1328,12 @@ static int read_id(struct qcom_nand_host *host, int column) ...@@ -1267,12 +1328,12 @@ static int read_id(struct qcom_nand_host *host, int column)
if (column == -1) if (column == -1)
return 0; return 0;
nandc_set_reg(nandc, NAND_FLASH_CMD, OP_FETCH_ID); nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
nandc_set_reg(nandc, NAND_ADDR0, column); nandc_set_reg(chip, NAND_ADDR0, column);
nandc_set_reg(nandc, NAND_ADDR1, 0); nandc_set_reg(chip, NAND_ADDR1, 0);
nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
nandc->props->is_bam ? 0 : DM_EN); nandc->props->is_bam ? 0 : DM_EN);
nandc_set_reg(nandc, NAND_EXEC_CMD, 1); nandc_set_reg(chip, NAND_EXEC_CMD, 1);
write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
...@@ -1288,8 +1349,8 @@ static int reset(struct qcom_nand_host *host) ...@@ -1288,8 +1349,8 @@ static int reset(struct qcom_nand_host *host)
struct nand_chip *chip = &host->chip; struct nand_chip *chip = &host->chip;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
nandc_set_reg(nandc, NAND_FLASH_CMD, OP_RESET_DEVICE); nandc_set_reg(chip, NAND_FLASH_CMD, OP_RESET_DEVICE);
nandc_set_reg(nandc, NAND_EXEC_CMD, 1); nandc_set_reg(chip, NAND_EXEC_CMD, 1);
write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
...@@ -1492,7 +1553,7 @@ static void qcom_nandc_command(struct nand_chip *chip, unsigned int command, ...@@ -1492,7 +1553,7 @@ static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
host->use_ecc = true; host->use_ecc = true;
set_address(host, 0, page_addr); set_address(host, 0, page_addr);
update_rw_regs(host, ecc->steps, true); update_rw_regs(host, ecc->steps, true, 0);
break; break;
case NAND_CMD_SEQIN: case NAND_CMD_SEQIN:
...@@ -1616,13 +1677,13 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1616,13 +1677,13 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip,
clear_bam_transaction(nandc); clear_bam_transaction(nandc);
set_address(host, host->cw_size * cw, page); set_address(host, host->cw_size * cw, page);
update_rw_regs(host, 1, true); update_rw_regs(host, 1, true, cw);
config_nand_page_read(nandc); config_nand_page_read(chip);
data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
oob_size1 = host->bbm_size; oob_size1 = host->bbm_size;
if (cw == (ecc->steps - 1)) { if (qcom_nandc_is_last_cw(ecc, cw)) {
data_size2 = ecc->size - data_size1 - data_size2 = ecc->size - data_size1 -
((ecc->steps - 1) * 4); ((ecc->steps - 1) * 4);
oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw +
...@@ -1633,19 +1694,19 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1633,19 +1694,19 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip,
} }
if (nandc->props->is_bam) { if (nandc->props->is_bam) {
nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0); nandc_set_read_loc(chip, cw, 0, read_loc, data_size1, 0);
read_loc += data_size1; read_loc += data_size1;
nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0); nandc_set_read_loc(chip, cw, 1, read_loc, oob_size1, 0);
read_loc += oob_size1; read_loc += oob_size1;
nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0); nandc_set_read_loc(chip, cw, 2, read_loc, data_size2, 0);
read_loc += data_size2; read_loc += data_size2;
nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1); nandc_set_read_loc(chip, cw, 3, read_loc, oob_size2, 1);
} }
config_nand_cw_read(nandc, false); config_nand_cw_read(chip, false, cw);
read_data_dma(nandc, reg_off, data_buf, data_size1, 0); read_data_dma(nandc, reg_off, data_buf, data_size1, 0);
reg_off += data_size1; reg_off += data_size1;
...@@ -1703,7 +1764,7 @@ check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf, ...@@ -1703,7 +1764,7 @@ check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf,
} }
for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) {
if (cw == (ecc->steps - 1)) { if (qcom_nandc_is_last_cw(ecc, cw)) {
data_size = ecc->size - ((ecc->steps - 1) * 4); data_size = ecc->size - ((ecc->steps - 1) * 4);
oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; oob_size = (ecc->steps * 4) + host->ecc_bytes_hw;
} else { } else {
...@@ -1763,7 +1824,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf, ...@@ -1763,7 +1824,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
u32 flash, buffer, erased_cw; u32 flash, buffer, erased_cw;
int data_len, oob_len; int data_len, oob_len;
if (i == (ecc->steps - 1)) { if (qcom_nandc_is_last_cw(ecc, i)) {
data_len = ecc->size - ((ecc->steps - 1) << 2); data_len = ecc->size - ((ecc->steps - 1) << 2);
oob_len = ecc->steps << 2; oob_len = ecc->steps << 2;
} else { } else {
...@@ -1856,13 +1917,13 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, ...@@ -1856,13 +1917,13 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf; u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf;
int i, ret; int i, ret;
config_nand_page_read(nandc); config_nand_page_read(chip);
/* queue cmd descs for each codeword */ /* queue cmd descs for each codeword */
for (i = 0; i < ecc->steps; i++) { for (i = 0; i < ecc->steps; i++) {
int data_size, oob_size; int data_size, oob_size;
if (i == (ecc->steps - 1)) { if (qcom_nandc_is_last_cw(ecc, i)) {
data_size = ecc->size - ((ecc->steps - 1) << 2); data_size = ecc->size - ((ecc->steps - 1) << 2);
oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
host->spare_bytes; host->spare_bytes;
...@@ -1873,18 +1934,18 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, ...@@ -1873,18 +1934,18 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf,
if (nandc->props->is_bam) { if (nandc->props->is_bam) {
if (data_buf && oob_buf) { if (data_buf && oob_buf) {
nandc_set_read_loc(nandc, 0, 0, data_size, 0); nandc_set_read_loc(chip, i, 0, 0, data_size, 0);
nandc_set_read_loc(nandc, 1, data_size, nandc_set_read_loc(chip, i, 1, data_size,
oob_size, 1); oob_size, 1);
} else if (data_buf) { } else if (data_buf) {
nandc_set_read_loc(nandc, 0, 0, data_size, 1); nandc_set_read_loc(chip, i, 0, 0, data_size, 1);
} else { } else {
nandc_set_read_loc(nandc, 0, data_size, nandc_set_read_loc(chip, i, 0, data_size,
oob_size, 1); oob_size, 1);
} }
} }
config_nand_cw_read(nandc, true); config_nand_cw_read(chip, true, i);
if (data_buf) if (data_buf)
read_data_dma(nandc, FLASH_BUF_ACC, data_buf, read_data_dma(nandc, FLASH_BUF_ACC, data_buf,
...@@ -1944,9 +2005,9 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) ...@@ -1944,9 +2005,9 @@ static int copy_last_cw(struct qcom_nand_host *host, int page)
memset(nandc->data_buffer, 0xff, size); memset(nandc->data_buffer, 0xff, size);
set_address(host, host->cw_size * (ecc->steps - 1), page); set_address(host, host->cw_size * (ecc->steps - 1), page);
update_rw_regs(host, 1, true); update_rw_regs(host, 1, true, ecc->steps - 1);
config_nand_single_cw_page_read(nandc, host->use_ecc); config_nand_single_cw_page_read(chip, host->use_ecc, ecc->steps - 1);
read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0); read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0);
...@@ -2011,7 +2072,7 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page) ...@@ -2011,7 +2072,7 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page)
host->use_ecc = true; host->use_ecc = true;
set_address(host, 0, page); set_address(host, 0, page);
update_rw_regs(host, ecc->steps, true); update_rw_regs(host, ecc->steps, true, 0);
return read_page_ecc(host, NULL, chip->oob_poi, page); return read_page_ecc(host, NULL, chip->oob_poi, page);
} }
...@@ -2035,13 +2096,13 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, ...@@ -2035,13 +2096,13 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf,
oob_buf = chip->oob_poi; oob_buf = chip->oob_poi;
host->use_ecc = true; host->use_ecc = true;
update_rw_regs(host, ecc->steps, false); update_rw_regs(host, ecc->steps, false, 0);
config_nand_page_write(nandc); config_nand_page_write(chip);
for (i = 0; i < ecc->steps; i++) { for (i = 0; i < ecc->steps; i++) {
int data_size, oob_size; int data_size, oob_size;
if (i == (ecc->steps - 1)) { if (qcom_nandc_is_last_cw(ecc, i)) {
data_size = ecc->size - ((ecc->steps - 1) << 2); data_size = ecc->size - ((ecc->steps - 1) << 2);
oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw +
host->spare_bytes; host->spare_bytes;
...@@ -2061,14 +2122,14 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, ...@@ -2061,14 +2122,14 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf,
* itself. For the last codeword, we skip the bbm positions and * itself. For the last codeword, we skip the bbm positions and
* write to the free oob area. * write to the free oob area.
*/ */
if (i == (ecc->steps - 1)) { if (qcom_nandc_is_last_cw(ecc, i)) {
oob_buf += host->bbm_size; oob_buf += host->bbm_size;
write_data_dma(nandc, FLASH_BUF_ACC + data_size, write_data_dma(nandc, FLASH_BUF_ACC + data_size,
oob_buf, oob_size, 0); oob_buf, oob_size, 0);
} }
config_nand_cw_write(nandc); config_nand_cw_write(chip);
data_buf += data_size; data_buf += data_size;
oob_buf += oob_size; oob_buf += oob_size;
...@@ -2106,8 +2167,8 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, ...@@ -2106,8 +2167,8 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip,
oob_buf = chip->oob_poi; oob_buf = chip->oob_poi;
host->use_ecc = false; host->use_ecc = false;
update_rw_regs(host, ecc->steps, false); update_rw_regs(host, ecc->steps, false, 0);
config_nand_page_write(nandc); config_nand_page_write(chip);
for (i = 0; i < ecc->steps; i++) { for (i = 0; i < ecc->steps; i++) {
int data_size1, data_size2, oob_size1, oob_size2; int data_size1, data_size2, oob_size1, oob_size2;
...@@ -2116,7 +2177,7 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, ...@@ -2116,7 +2177,7 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip,
data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1);
oob_size1 = host->bbm_size; oob_size1 = host->bbm_size;
if (i == (ecc->steps - 1)) { if (qcom_nandc_is_last_cw(ecc, i)) {
data_size2 = ecc->size - data_size1 - data_size2 = ecc->size - data_size1 -
((ecc->steps - 1) << 2); ((ecc->steps - 1) << 2);
oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw +
...@@ -2144,7 +2205,7 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, ...@@ -2144,7 +2205,7 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip,
write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0);
oob_buf += oob_size2; oob_buf += oob_size2;
config_nand_cw_write(nandc); config_nand_cw_write(chip);
} }
ret = submit_descs(nandc); ret = submit_descs(nandc);
...@@ -2189,12 +2250,12 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page) ...@@ -2189,12 +2250,12 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
0, mtd->oobavail); 0, mtd->oobavail);
set_address(host, host->cw_size * (ecc->steps - 1), page); set_address(host, host->cw_size * (ecc->steps - 1), page);
update_rw_regs(host, 1, false); update_rw_regs(host, 1, false, 0);
config_nand_page_write(nandc); config_nand_page_write(chip);
write_data_dma(nandc, FLASH_BUF_ACC, write_data_dma(nandc, FLASH_BUF_ACC,
nandc->data_buffer, data_size + oob_size, 0); nandc->data_buffer, data_size + oob_size, 0);
config_nand_cw_write(nandc); config_nand_cw_write(chip);
ret = submit_descs(nandc); ret = submit_descs(nandc);
...@@ -2268,12 +2329,12 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs) ...@@ -2268,12 +2329,12 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
/* prepare write */ /* prepare write */
host->use_ecc = false; host->use_ecc = false;
set_address(host, host->cw_size * (ecc->steps - 1), page); set_address(host, host->cw_size * (ecc->steps - 1), page);
update_rw_regs(host, 1, false); update_rw_regs(host, 1, false, ecc->steps - 1);
config_nand_page_write(nandc); config_nand_page_write(chip);
write_data_dma(nandc, FLASH_BUF_ACC, write_data_dma(nandc, FLASH_BUF_ACC,
nandc->data_buffer, host->cw_size, 0); nandc->data_buffer, host->cw_size, 0);
config_nand_cw_write(nandc); config_nand_cw_write(chip);
ret = submit_descs(nandc); ret = submit_descs(nandc);
...@@ -2882,6 +2943,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, ...@@ -2882,6 +2943,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
if (!nandc->bam_txn) { if (!nandc->bam_txn) {
dev_err(nandc->dev, dev_err(nandc->dev,
"failed to allocate bam transaction\n"); "failed to allocate bam transaction\n");
nand_cleanup(chip);
return -ENOMEM; return -ENOMEM;
} }
} }
...@@ -2898,7 +2960,7 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc) ...@@ -2898,7 +2960,7 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
struct device *dev = nandc->dev; struct device *dev = nandc->dev;
struct device_node *dn = dev->of_node, *child; struct device_node *dn = dev->of_node, *child;
struct qcom_nand_host *host; struct qcom_nand_host *host;
int ret; int ret = -ENODEV;
for_each_available_child_of_node(dn, child) { for_each_available_child_of_node(dn, child) {
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
...@@ -2916,10 +2978,7 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc) ...@@ -2916,10 +2978,7 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
list_add_tail(&host->node, &nandc->host_list); list_add_tail(&host->node, &nandc->host_list);
} }
if (list_empty(&nandc->host_list)) return ret;
return -ENODEV;
return 0;
} }
/* parse custom DT properties here */ /* parse custom DT properties here */
...@@ -2992,7 +3051,7 @@ static int qcom_nandc_probe(struct platform_device *pdev) ...@@ -2992,7 +3051,7 @@ static int qcom_nandc_probe(struct platform_device *pdev)
nandc->base_dma = dma_map_resource(dev, res->start, nandc->base_dma = dma_map_resource(dev, res->start,
resource_size(res), resource_size(res),
DMA_BIDIRECTIONAL, 0); DMA_BIDIRECTIONAL, 0);
if (!nandc->base_dma) if (dma_mapping_error(dev, nandc->base_dma))
return -ENXIO; return -ENXIO;
ret = qcom_nandc_alloc(nandc); ret = qcom_nandc_alloc(nandc);
......
...@@ -724,10 +724,9 @@ static irqreturn_t r852_irq(int irq, void *data) ...@@ -724,10 +724,9 @@ static irqreturn_t r852_irq(int irq, void *data)
struct r852_device *dev = (struct r852_device *)data; struct r852_device *dev = (struct r852_device *)data;
uint8_t card_status, dma_status; uint8_t card_status, dma_status;
unsigned long flags;
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
spin_lock_irqsave(&dev->irqlock, flags); spin_lock(&dev->irqlock);
/* handle card detection interrupts first */ /* handle card detection interrupts first */
card_status = r852_read_reg(dev, R852_CARD_IRQ_STA); card_status = r852_read_reg(dev, R852_CARD_IRQ_STA);
...@@ -813,7 +812,7 @@ static irqreturn_t r852_irq(int irq, void *data) ...@@ -813,7 +812,7 @@ static irqreturn_t r852_irq(int irq, void *data)
dbg("strange card status = %x", card_status); dbg("strange card status = %x", card_status);
out: out:
spin_unlock_irqrestore(&dev->irqlock, flags); spin_unlock(&dev->irqlock);
return ret; return ret;
} }
......
...@@ -159,7 +159,7 @@ struct rk_nfc_nand_chip { ...@@ -159,7 +159,7 @@ struct rk_nfc_nand_chip {
u32 timing; u32 timing;
u8 nsels; u8 nsels;
u8 sels[0]; u8 sels[];
/* Nothing after this field. */ /* Nothing after this field. */
}; };
......
...@@ -1263,12 +1263,14 @@ static const struct spi_device_id spinand_ids[] = { ...@@ -1263,12 +1263,14 @@ static const struct spi_device_id spinand_ids[] = {
{ .name = "spi-nand" }, { .name = "spi-nand" },
{ /* sentinel */ }, { /* sentinel */ },
}; };
MODULE_DEVICE_TABLE(spi, spinand_ids);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id spinand_of_ids[] = { static const struct of_device_id spinand_of_ids[] = {
{ .compatible = "spi-nand" }, { .compatible = "spi-nand" },
{ /* sentinel */ }, { /* sentinel */ },
}; };
MODULE_DEVICE_TABLE(of, spinand_of_ids);
#endif #endif
static struct spi_mem_driver spinand_drv = { static struct spi_mem_driver spinand_drv = {
......
...@@ -13,7 +13,10 @@ ...@@ -13,7 +13,10 @@
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4) #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4) #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
#define GD5FXGQ4UEXXG_REG_STATUS2 0xf0 #define GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS (1 << 4)
#define GD5FXGQ5XE_STATUS_ECC_4_BITFLIPS (3 << 4)
#define GD5FXGQXXEXXG_REG_STATUS2 0xf0
#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK (7 << 4) #define GD5FXGQ4UXFXXG_STATUS_ECC_MASK (7 << 4)
#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4) #define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4)
...@@ -102,7 +105,7 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand, ...@@ -102,7 +105,7 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
return -EINVAL; return -EINVAL;
} }
static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section, static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region) struct mtd_oob_region *region)
{ {
if (section) if (section)
...@@ -114,7 +117,7 @@ static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section, ...@@ -114,7 +117,7 @@ static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
return 0; return 0;
} }
static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section, static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region) struct mtd_oob_region *region)
{ {
if (section) if (section)
...@@ -127,9 +130,10 @@ static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section, ...@@ -127,9 +130,10 @@ static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section,
return 0; return 0;
} }
static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = { /* Valid for Q4/Q5 and Q6 (untested) devices */
.ecc = gd5fxgq4_variant2_ooblayout_ecc, static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
.free = gd5fxgq4_variant2_ooblayout_free, .ecc = gd5fxgqx_variant2_ooblayout_ecc,
.free = gd5fxgqx_variant2_ooblayout_free,
}; };
static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section, static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
...@@ -165,7 +169,7 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand, ...@@ -165,7 +169,7 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
u8 status) u8 status)
{ {
u8 status2; u8 status2;
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4UEXXG_REG_STATUS2, struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
&status2); &status2);
int ret; int ret;
...@@ -203,6 +207,43 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand, ...@@ -203,6 +207,43 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
return -EINVAL; return -EINVAL;
} }
static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
u8 status2;
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
&status2);
int ret;
switch (status & STATUS_ECC_MASK) {
case STATUS_ECC_NO_BITFLIPS:
return 0;
case GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS:
/*
* Read status2 register to determine a more fine grained
* bit error status
*/
ret = spi_mem_exec_op(spinand->spimem, &op);
if (ret)
return ret;
/*
* 1 ... 4 bits are flipped (and corrected)
*/
/* bits sorted this way (1...0): ECCSE1, ECCSE0 */
return ((status2 & STATUS_ECC_MASK) >> 4) + 1;
case STATUS_ECC_UNCOR_ERROR:
return -EBADMSG;
default:
break;
}
return -EINVAL;
}
static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand, static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
u8 status) u8 status)
{ {
...@@ -282,7 +323,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { ...@@ -282,7 +323,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
SPINAND_HAS_QE_BIT, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout, SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
gd5fxgq4uexxg_ecc_get_status)), gd5fxgq4uexxg_ecc_get_status)),
SPINAND_INFO("GD5F1GQ4UFxxG", SPINAND_INFO("GD5F1GQ4UFxxG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48), SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
...@@ -292,8 +333,18 @@ static const struct spinand_info gigadevice_spinand_table[] = { ...@@ -292,8 +333,18 @@ static const struct spinand_info gigadevice_spinand_table[] = {
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
SPINAND_HAS_QE_BIT, SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout, SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
gd5fxgq4ufxxg_ecc_get_status)), gd5fxgq4ufxxg_ecc_get_status)),
SPINAND_INFO("GD5F1GQ5UExxG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
gd5fxgq5xexxg_ecc_get_status)),
}; };
static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
* @req_ctx: Save request context and tweak the original request to fit the * @req_ctx: Save request context and tweak the original request to fit the
* engine needs * engine needs
* @code_size: Number of bytes needed to store a code (one code per step) * @code_size: Number of bytes needed to store a code (one code per step)
* @nsteps: Number of steps
* @calc_buf: Buffer to use when calculating ECC bytes * @calc_buf: Buffer to use when calculating ECC bytes
* @code_buf: Buffer to use when reading (raw) ECC bytes from the chip * @code_buf: Buffer to use when reading (raw) ECC bytes from the chip
* @bch: BCH control structure * @bch: BCH control structure
...@@ -26,7 +25,6 @@ ...@@ -26,7 +25,6 @@
struct nand_ecc_sw_bch_conf { struct nand_ecc_sw_bch_conf {
struct nand_ecc_req_tweak_ctx req_ctx; struct nand_ecc_req_tweak_ctx req_ctx;
unsigned int code_size; unsigned int code_size;
unsigned int nsteps;
u8 *calc_buf; u8 *calc_buf;
u8 *code_buf; u8 *code_buf;
struct bch_control *bch; struct bch_control *bch;
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
* @req_ctx: Save request context and tweak the original request to fit the * @req_ctx: Save request context and tweak the original request to fit the
* engine needs * engine needs
* @code_size: Number of bytes needed to store a code (one code per step) * @code_size: Number of bytes needed to store a code (one code per step)
* @nsteps: Number of steps
* @calc_buf: Buffer to use when calculating ECC bytes * @calc_buf: Buffer to use when calculating ECC bytes
* @code_buf: Buffer to use when reading (raw) ECC bytes from the chip * @code_buf: Buffer to use when reading (raw) ECC bytes from the chip
* @sm_order: Smart Media special ordering * @sm_order: Smart Media special ordering
...@@ -25,7 +24,6 @@ ...@@ -25,7 +24,6 @@
struct nand_ecc_sw_hamming_conf { struct nand_ecc_sw_hamming_conf {
struct nand_ecc_req_tweak_ctx req_ctx; struct nand_ecc_req_tweak_ctx req_ctx;
unsigned int code_size; unsigned int code_size;
unsigned int nsteps;
u8 *calc_buf; u8 *calc_buf;
u8 *code_buf; u8 *code_buf;
unsigned int sm_order; unsigned int sm_order;
......
...@@ -231,12 +231,14 @@ struct nand_ops { ...@@ -231,12 +231,14 @@ struct nand_ops {
/** /**
* struct nand_ecc_context - Context for the ECC engine * struct nand_ecc_context - Context for the ECC engine
* @conf: basic ECC engine parameters * @conf: basic ECC engine parameters
* @nsteps: number of ECC steps
* @total: total number of bytes used for storing ECC codes, this is used by * @total: total number of bytes used for storing ECC codes, this is used by
* generic OOB layouts * generic OOB layouts
* @priv: ECC engine driver private data * @priv: ECC engine driver private data
*/ */
struct nand_ecc_context { struct nand_ecc_context {
struct nand_ecc_props conf; struct nand_ecc_props conf;
unsigned int nsteps;
unsigned int total; unsigned int total;
void *priv; void *priv;
}; };
...@@ -585,6 +587,26 @@ nanddev_get_ecc_conf(struct nand_device *nand) ...@@ -585,6 +587,26 @@ nanddev_get_ecc_conf(struct nand_device *nand)
return &nand->ecc.ctx.conf; return &nand->ecc.ctx.conf;
} }
/**
* nanddev_get_ecc_nsteps() - Extract the number of ECC steps
* @nand: NAND device
*/
static inline unsigned int
nanddev_get_ecc_nsteps(struct nand_device *nand)
{
return nand->ecc.ctx.nsteps;
}
/**
* nanddev_get_ecc_bytes_per_step() - Extract the number of ECC bytes per step
* @nand: NAND device
*/
static inline unsigned int
nanddev_get_ecc_bytes_per_step(struct nand_device *nand)
{
return nand->ecc.ctx.total / nand->ecc.ctx.nsteps;
}
/** /**
* nanddev_get_ecc_requirements() - Extract the ECC requirements from a NAND * nanddev_get_ecc_requirements() - Extract the ECC requirements from a NAND
* device * device
......
...@@ -1035,6 +1035,16 @@ struct nand_manufacturer { ...@@ -1035,6 +1035,16 @@ struct nand_manufacturer {
void *priv; void *priv;
}; };
/**
* struct nand_secure_region - NAND secure region structure
* @offset: Offset of the start of the secure region
* @size: Size of the secure region
*/
struct nand_secure_region {
u64 offset;
u64 size;
};
/** /**
* struct nand_chip - NAND Private Flash Chip Data * struct nand_chip - NAND Private Flash Chip Data
* @base: Inherit from the generic NAND device * @base: Inherit from the generic NAND device
...@@ -1085,6 +1095,8 @@ struct nand_manufacturer { ...@@ -1085,6 +1095,8 @@ struct nand_manufacturer {
* NAND Controller drivers should not modify this value, but they're * NAND Controller drivers should not modify this value, but they're
* allowed to read it. * allowed to read it.
* @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
* @nr_secure_regions: Number of secure regions
* @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
...@@ -1134,6 +1146,8 @@ struct nand_chip { ...@@ -1134,6 +1146,8 @@ struct nand_chip {
unsigned int suspended : 1; unsigned int suspended : 1;
int cur_cs; int cur_cs;
int read_retries; int read_retries;
struct nand_secure_region *secure_regions;
u8 nr_secure_regions;
/* Externals */ /* Externals */
struct nand_controller *controller; struct nand_controller *controller;
......
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