diff options
Diffstat (limited to 'drivers/mtd/nand/raw')
62 files changed, 3747 insertions, 2375 deletions
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index a80a46bb5b8b..113f61052269 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -213,10 +213,6 @@ config MTD_NAND_MLC_LPC32XX Please check the actual NAND chip connected and its support by the MLC NAND controller. -config MTD_NAND_CM_X270 - tristate "CM-X270 modules NAND controller" - depends on MACH_ARMCORE - config MTD_NAND_PASEMI tristate "PA Semi PWRficient NAND controller" depends on PPC_PASEMI @@ -457,6 +453,14 @@ config MTD_NAND_CADENCE Enable the driver for NAND flash on platforms using a Cadence NAND controller. +config MTD_NAND_ARASAN + tristate "Support for Arasan NAND flash controller" + depends on HAS_IOMEM && HAS_DMA + select BCH + help + Enables the driver for the Arasan NAND flash controller on + Zynq Ultrascale+ MPSoC. + comment "Misc" config MTD_SM_COMMON diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 2d136b158fb7..2930f5b9015d 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -25,7 +25,6 @@ obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o 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_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o @@ -58,6 +57,7 @@ obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o obj-$(CONFIG_MTD_NAND_CADENCE) += cadence-nand-controller.o +obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o nand-objs += nand_onfi.o diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index d66dab25df20..3711e7a0436c 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -387,12 +387,15 @@ static int gpio_nand_remove(struct platform_device *pdev) { struct gpio_nand *priv = platform_get_drvdata(pdev); struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip); + int ret; /* Apply write protection */ gpiod_set_value(priv->gpiod_nwp, 1); /* Unregister device */ - nand_release(mtd_to_nand(mtd)); + ret = mtd_device_unregister(mtd); + WARN_ON(ret); + nand_cleanup(mtd_to_nand(mtd)); return 0; } diff --git a/drivers/mtd/nand/raw/arasan-nand-controller.c b/drivers/mtd/nand/raw/arasan-nand-controller.c new file mode 100644 index 000000000000..7141dcccba3c --- /dev/null +++ b/drivers/mtd/nand/raw/arasan-nand-controller.c @@ -0,0 +1,1297 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Arasan NAND Flash Controller Driver + * + * Copyright (C) 2014 - 2020 Xilinx, Inc. + * Author: + * Miquel Raynal <miquel.raynal@bootlin.com> + * Original work (fully rewritten): + * Punnaiah Choudary Kalluri <punnaia@xilinx.com> + * Naga Sureshkumar Relli <nagasure@xilinx.com> + */ + +#include <linux/bch.h> +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/rawnand.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define PKT_REG 0x00 +#define PKT_SIZE(x) FIELD_PREP(GENMASK(10, 0), (x)) +#define PKT_STEPS(x) FIELD_PREP(GENMASK(23, 12), (x)) + +#define MEM_ADDR1_REG 0x04 + +#define MEM_ADDR2_REG 0x08 +#define ADDR2_STRENGTH(x) FIELD_PREP(GENMASK(27, 25), (x)) +#define ADDR2_CS(x) FIELD_PREP(GENMASK(31, 30), (x)) + +#define CMD_REG 0x0C +#define CMD_1(x) FIELD_PREP(GENMASK(7, 0), (x)) +#define CMD_2(x) FIELD_PREP(GENMASK(15, 8), (x)) +#define CMD_PAGE_SIZE(x) FIELD_PREP(GENMASK(25, 23), (x)) +#define CMD_DMA_ENABLE BIT(27) +#define CMD_NADDRS(x) FIELD_PREP(GENMASK(30, 28), (x)) +#define CMD_ECC_ENABLE BIT(31) + +#define PROG_REG 0x10 +#define PROG_PGRD BIT(0) +#define PROG_ERASE BIT(2) +#define PROG_STATUS BIT(3) +#define PROG_PGPROG BIT(4) +#define PROG_RDID BIT(6) +#define PROG_RDPARAM BIT(7) +#define PROG_RST BIT(8) +#define PROG_GET_FEATURE BIT(9) +#define PROG_SET_FEATURE BIT(10) + +#define INTR_STS_EN_REG 0x14 +#define INTR_SIG_EN_REG 0x18 +#define INTR_STS_REG 0x1C +#define WRITE_READY BIT(0) +#define READ_READY BIT(1) +#define XFER_COMPLETE BIT(2) +#define DMA_BOUNDARY BIT(6) +#define EVENT_MASK GENMASK(7, 0) + +#define READY_STS_REG 0x20 + +#define DMA_ADDR0_REG 0x50 +#define DMA_ADDR1_REG 0x24 + +#define FLASH_STS_REG 0x28 + +#define DATA_PORT_REG 0x30 + +#define ECC_CONF_REG 0x34 +#define ECC_CONF_COL(x) FIELD_PREP(GENMASK(15, 0), (x)) +#define ECC_CONF_LEN(x) FIELD_PREP(GENMASK(26, 16), (x)) +#define ECC_CONF_BCH_EN BIT(27) + +#define ECC_ERR_CNT_REG 0x38 +#define GET_PKT_ERR_CNT(x) FIELD_GET(GENMASK(7, 0), (x)) +#define GET_PAGE_ERR_CNT(x) FIELD_GET(GENMASK(16, 8), (x)) + +#define ECC_SP_REG 0x3C +#define ECC_SP_CMD1(x) FIELD_PREP(GENMASK(7, 0), (x)) +#define ECC_SP_CMD2(x) FIELD_PREP(GENMASK(15, 8), (x)) +#define ECC_SP_ADDRS(x) FIELD_PREP(GENMASK(30, 28), (x)) + +#define ECC_1ERR_CNT_REG 0x40 +#define ECC_2ERR_CNT_REG 0x44 + +#define DATA_INTERFACE_REG 0x6C +#define DIFACE_SDR_MODE(x) FIELD_PREP(GENMASK(2, 0), (x)) +#define DIFACE_DDR_MODE(x) FIELD_PREP(GENMASK(5, 3), (X)) +#define DIFACE_SDR 0 +#define DIFACE_NVDDR BIT(9) + +#define ANFC_MAX_CS 2 +#define ANFC_DFLT_TIMEOUT_US 1000000 +#define ANFC_MAX_CHUNK_SIZE SZ_1M +#define ANFC_MAX_PARAM_SIZE SZ_4K +#define ANFC_MAX_STEPS SZ_2K +#define ANFC_MAX_PKT_SIZE (SZ_2K - 1) +#define ANFC_MAX_ADDR_CYC 5U +#define ANFC_RSVD_ECC_BYTES 21 + +#define ANFC_XLNX_SDR_DFLT_CORE_CLK 100000000 +#define ANFC_XLNX_SDR_HS_CORE_CLK 80000000 + +/** + * struct anfc_op - Defines how to execute an operation + * @pkt_reg: Packet register + * @addr1_reg: Memory address 1 register + * @addr2_reg: Memory address 2 register + * @cmd_reg: Command register + * @prog_reg: Program register + * @steps: Number of "packets" to read/write + * @rdy_timeout_ms: Timeout for waits on Ready/Busy pin + * @len: Data transfer length + * @read: Data transfer direction from the controller point of view + */ +struct anfc_op { + u32 pkt_reg; + u32 addr1_reg; + u32 addr2_reg; + u32 cmd_reg; + u32 prog_reg; + int steps; + unsigned int rdy_timeout_ms; + unsigned int len; + bool read; + u8 *buf; +}; + +/** + * struct anand - Defines the NAND chip related information + * @node: Used to store NAND chips into a list + * @chip: NAND chip information structure + * @cs: Chip select line + * @rb: Ready-busy line + * @page_sz: Register value of the page_sz field to use + * @clk: Expected clock frequency to use + * @timings: Data interface timing mode to use + * @ecc_conf: Hardware ECC configuration value + * @strength: Register value of the ECC strength + * @raddr_cycles: Row address cycle information + * @caddr_cycles: Column address cycle information + * @ecc_bits: Exact number of ECC bits per syndrome + * @ecc_total: Total number of ECC bytes + * @errloc: Array of errors located with soft BCH + * @hw_ecc: Buffer to store syndromes computed by hardware + * @bch: BCH structure + */ +struct anand { + struct list_head node; + struct nand_chip chip; + unsigned int cs; + unsigned int rb; + unsigned int page_sz; + unsigned long clk; + u32 timings; + u32 ecc_conf; + u32 strength; + u16 raddr_cycles; + u16 caddr_cycles; + unsigned int ecc_bits; + unsigned int ecc_total; + unsigned int *errloc; + u8 *hw_ecc; + struct bch_control *bch; +}; + +/** + * struct arasan_nfc - Defines the Arasan NAND flash controller driver instance + * @dev: Pointer to the device structure + * @base: Remapped register area + * @controller_clk: Pointer to the system clock + * @bus_clk: Pointer to the flash clock + * @controller: Base controller structure + * @chips: List of all NAND chips attached to the controller + * @assigned_cs: Bitmask describing already assigned CS lines + * @cur_clk: Current clock rate + */ +struct arasan_nfc { + struct device *dev; + void __iomem *base; + struct clk *controller_clk; + struct clk *bus_clk; + struct nand_controller controller; + struct list_head chips; + unsigned long assigned_cs; + unsigned int cur_clk; +}; + +static struct anand *to_anand(struct nand_chip *nand) +{ + return container_of(nand, struct anand, chip); +} + +static struct arasan_nfc *to_anfc(struct nand_controller *ctrl) +{ + return container_of(ctrl, struct arasan_nfc, controller); +} + +static int anfc_wait_for_event(struct arasan_nfc *nfc, unsigned int event) +{ + u32 val; + int ret; + + ret = readl_relaxed_poll_timeout(nfc->base + INTR_STS_REG, val, + val & event, 0, + ANFC_DFLT_TIMEOUT_US); + if (ret) { + dev_err(nfc->dev, "Timeout waiting for event 0x%x\n", event); + return -ETIMEDOUT; + } + + writel_relaxed(event, nfc->base + INTR_STS_REG); + + return 0; +} + +static int anfc_wait_for_rb(struct arasan_nfc *nfc, struct nand_chip *chip, + unsigned int timeout_ms) +{ + struct anand *anand = to_anand(chip); + u32 val; + int ret; + + /* There is no R/B interrupt, we must poll a register */ + ret = readl_relaxed_poll_timeout(nfc->base + READY_STS_REG, val, + val & BIT(anand->rb), + 1, timeout_ms * 1000); + if (ret) { + dev_err(nfc->dev, "Timeout waiting for R/B 0x%x\n", + readl_relaxed(nfc->base + READY_STS_REG)); + return -ETIMEDOUT; + } + + return 0; +} + +static void anfc_trigger_op(struct arasan_nfc *nfc, struct anfc_op *nfc_op) +{ + writel_relaxed(nfc_op->pkt_reg, nfc->base + PKT_REG); + writel_relaxed(nfc_op->addr1_reg, nfc->base + MEM_ADDR1_REG); + writel_relaxed(nfc_op->addr2_reg, nfc->base + MEM_ADDR2_REG); + writel_relaxed(nfc_op->cmd_reg, nfc->base + CMD_REG); + writel_relaxed(nfc_op->prog_reg, nfc->base + PROG_REG); +} + +static int anfc_pkt_len_config(unsigned int len, unsigned int *steps, + unsigned int *pktsize) +{ + unsigned int nb, sz; + + for (nb = 1; nb < ANFC_MAX_STEPS; nb *= 2) { + sz = len / nb; + if (sz <= ANFC_MAX_PKT_SIZE) + break; + } + + if (sz * nb != len) + return -ENOTSUPP; + + if (steps) + *steps = nb; + + if (pktsize) + *pktsize = sz; + + return 0; +} + +/* + * When using the embedded hardware ECC engine, the controller is in charge of + * feeding the engine with, first, the ECC residue present in the data array. + * A typical read operation is: + * 1/ Assert the read operation by sending the relevant command/address cycles + * but targeting the column of the first ECC bytes in the OOB area instead of + * the main data directly. + * 2/ After having read the relevant number of ECC bytes, the controller uses + * the RNDOUT/RNDSTART commands which are set into the "ECC Spare Command + * Register" to move the pointer back at the beginning of the main data. + * 3/ It will read the content of the main area for a given size (pktsize) and + * will feed the ECC engine with this buffer again. + * 4/ The ECC engine derives the ECC bytes for the given data and compare them + * with the ones already received. It eventually trigger status flags and + * then set the "Buffer Read Ready" flag. + * 5/ The corrected data is then available for reading from the data port + * register. + * + * The hardware BCH ECC engine is known to be inconstent in BCH mode and never + * reports uncorrectable errors. Because of this bug, we have to use the + * software BCH implementation in the read path. + */ +static int anfc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf, + int oob_required, int page) +{ + struct arasan_nfc *nfc = to_anfc(chip->controller); + struct mtd_info *mtd = nand_to_mtd(chip); + struct anand *anand = to_anand(chip); + unsigned int len = mtd->writesize + (oob_required ? mtd->oobsize : 0); + unsigned int max_bitflips = 0; + dma_addr_t dma_addr; + int step, ret; + struct anfc_op nfc_op = { + .pkt_reg = + PKT_SIZE(chip->ecc.size) | + PKT_STEPS(chip->ecc.steps), + .addr1_reg = + (page & 0xFF) << (8 * (anand->caddr_cycles)) | + (((page >> 8) & 0xFF) << (8 * (1 + anand->caddr_cycles))), + .addr2_reg = + ((page >> 16) & 0xFF) | + ADDR2_STRENGTH(anand->strength) | + ADDR2_CS(anand->cs), + .cmd_reg = + CMD_1(NAND_CMD_READ0) | + CMD_2(NAND_CMD_READSTART) | + CMD_PAGE_SIZE(anand->page_sz) | + CMD_DMA_ENABLE | + CMD_NADDRS(anand->caddr_cycles + + anand->raddr_cycles), + .prog_reg = PROG_PGRD, + }; + + dma_addr = dma_map_single(nfc->dev, (void *)buf, len, DMA_FROM_DEVICE); + if (dma_mapping_error(nfc->dev, dma_addr)) { + dev_err(nfc->dev, "Buffer mapping error"); + return -EIO; + } + + writel_relaxed(lower_32_bits(dma_addr), nfc->base + DMA_ADDR0_REG); + writel_relaxed(upper_32_bits(dma_addr), nfc->base + DMA_ADDR1_REG); + + anfc_trigger_op(nfc, &nfc_op); + + ret = anfc_wait_for_event(nfc, XFER_COMPLETE); + dma_unmap_single(nfc->dev, dma_addr, len, DMA_FROM_DEVICE); + if (ret) { + dev_err(nfc->dev, "Error reading page %d\n", page); + return ret; + } + + /* Store the raw OOB bytes as well */ + ret = nand_change_read_column_op(chip, mtd->writesize, chip->oob_poi, + mtd->oobsize, 0); + if (ret) + return ret; + + /* + * For each step, compute by softare the BCH syndrome over the raw data. + * Compare the theoretical amount of errors and compare with the + * hardware engine feedback. + */ + for (step = 0; step < chip->ecc.steps; step++) { + u8 *raw_buf = &buf[step * chip->ecc.size]; + unsigned int bit, byte; + int bf, i; + + /* Extract the syndrome, it is not necessarily aligned */ + memset(anand->hw_ecc, 0, chip->ecc.bytes); + nand_extract_bits(anand->hw_ecc, 0, + &chip->oob_poi[mtd->oobsize - anand->ecc_total], + anand->ecc_bits * step, anand->ecc_bits); + + bf = bch_decode(anand->bch, raw_buf, chip->ecc.size, + anand->hw_ecc, NULL, NULL, anand->errloc); + if (!bf) { + continue; + } else if (bf > 0) { + for (i = 0; i < bf; i++) { + /* Only correct the data, not the syndrome */ + if (anand->errloc[i] < (chip->ecc.size * 8)) { + bit = BIT(anand->errloc[i] & 7); + byte = anand->errloc[i] >> 3; + raw_buf[byte] ^= bit; + } + } + + mtd->ecc_stats.corrected += bf; + max_bitflips = max_t(unsigned int, max_bitflips, bf); + + continue; + } + + bf = nand_check_erased_ecc_chunk(raw_buf, chip->ecc.size, + NULL, 0, NULL, 0, + chip->ecc.strength); + if (bf > 0) { + mtd->ecc_stats.corrected += bf; + max_bitflips = max_t(unsigned int, max_bitflips, bf); + memset(raw_buf, 0xFF, chip->ecc.size); + } else if (bf < 0) { + mtd->ecc_stats.failed++; + } + } + + return 0; +} + +static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf, + int oob_required, int page) +{ + struct anand *anand = to_anand(chip); + struct arasan_nfc *nfc = to_anfc(chip->controller); + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned int len = mtd->writesize + (oob_required ? mtd->oobsize : 0); + dma_addr_t dma_addr; + int ret; + struct anfc_op nfc_op = { + .pkt_reg = + PKT_SIZE(chip->ecc.size) | + PKT_STEPS(chip->ecc.steps), + .addr1_reg = + (page & 0xFF) << (8 * (anand->caddr_cycles)) | + (((page >> 8) & 0xFF) << (8 * (1 + anand->caddr_cycles))), + .addr2_reg = + ((page >> 16) & 0xFF) | + ADDR2_STRENGTH(anand->strength) | + ADDR2_CS(anand->cs), + .cmd_reg = + CMD_1(NAND_CMD_SEQIN) | + CMD_2(NAND_CMD_PAGEPROG) | + CMD_PAGE_SIZE(anand->page_sz) | + CMD_DMA_ENABLE | + CMD_NADDRS(anand->caddr_cycles + + anand->raddr_cycles) | + CMD_ECC_ENABLE, + .prog_reg = PROG_PGPROG, + }; + + writel_relaxed(anand->ecc_conf, nfc->base + ECC_CONF_REG); + writel_relaxed(ECC_SP_CMD1(NAND_CMD_RNDIN) | + ECC_SP_ADDRS(anand->caddr_cycles), + nfc->base + ECC_SP_REG); + + dma_addr = dma_map_single(nfc->dev, (void *)buf, len, DMA_TO_DEVICE); + if (dma_mapping_error(nfc->dev, dma_addr)) { + dev_err(nfc->dev, "Buffer mapping error"); + return -EIO; + } + + writel_relaxed(lower_32_bits(dma_addr), nfc->base + DMA_ADDR0_REG); + writel_relaxed(upper_32_bits(dma_addr), nfc->base + DMA_ADDR1_REG); + + anfc_trigger_op(nfc, &nfc_op); + ret = anfc_wait_for_event(nfc, XFER_COMPLETE); + dma_unmap_single(nfc->dev, dma_addr, len, DMA_TO_DEVICE); + if (ret) { + dev_err(nfc->dev, "Error writing page %d\n", page); + return ret; + } + + /* Spare data is not protected */ + if (oob_required) + ret = nand_write_oob_std(chip, page); + + return ret; +} + +/* NAND framework ->exec_op() hooks and related helpers */ +static int anfc_parse_instructions(struct nand_chip *chip, + const struct nand_subop *subop, + struct anfc_op *nfc_op) +{ + struct anand *anand = to_anand(chip); + const struct nand_op_instr *instr = NULL; + bool first_cmd = true; + unsigned int op_id; + int ret, i; + + memset(nfc_op, 0, sizeof(*nfc_op)); + nfc_op->addr2_reg = ADDR2_CS(anand->cs); + nfc_op->cmd_reg = CMD_PAGE_SIZE(anand->page_sz); + + for (op_id = 0; op_id < subop->ninstrs; op_id++) { + unsigned int offset, naddrs, pktsize; |