[<prev] [next>] [day] [month] [year] [list]
Message-ID: <alpine.DEB.2.02.1410021408380.19786@lnxricardw1.se.axis.com>
Date: Thu, 2 Oct 2014 14:14:12 +0200
From: Ricard Wanderlof <ricard.wanderlof@...s.com>
To: Linux mtd <linux-mtd@...ts.infradead.org>
CC: <linux-kernel@...r.kernel.org>
Subject: [PATCH RFC]: mtd: nand: Driver for Evatronix NAND flash controller
From: Ricard Wanderlof <ricardw@...s.com>
This is a request for comments for a driver for the Evatronix NANDFLASH-CTRL
IP (version 1.15). It is designed to be applied to Linux 3.16 or the current
linux-mtd tree.
Currently, it supports one instance of the NANDFLASH-CTRL IP, with up
to two connected NAND flash chips, one per bank. (The IP itself is very
configurable, but the intent has been to get something working for a
specific configuration.)
Signed-off-by: Ricard Wanderlof <ricardw@...s.com>
---
I haven't had actual hardware to test this on, only a software
model, which is why the code is sprinkled with TODOs. I still felt it was worth
posting it here for comments.
The driver has been tested by running a number of UBI operations on a
simulated flash connected to the driver in a software model: ubiattach,
ubimkvol, mount volume, write files, read files, umount volume, as well as
some different nanddump and nandwrite invokations.
.../devicetree/bindings/mtd/evatronix-nand.txt | 29 +
.../devicetree/bindings/vendor-prefixes.txt | 1 +
drivers/mtd/nand/Kconfig | 17 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/evatronix_nand.c | 1358 ++++++++++++++++++++
drivers/mtd/nand/evatronix_nand.h | 401 ++++++
6 files changed, 1807 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/evatronix-nand.txt
create mode 100644 drivers/mtd/nand/evatronix_nand.c
create mode 100644 drivers/mtd/nand/evatronix_nand.h
diff --git a/Documentation/devicetree/bindings/mtd/evatronix-nand.txt b/Documentation/devicetree/bindings/mtd/evatronix-nand.txt
new file mode 100644
index 0000000..d7d017b
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/evatronix-nand.txt
@@ -0,0 +1,29 @@
+Evatronix NANDFLASH-CTRL NAND flash controller
+
+Required properties:
+- compatible : "evatronix,nandflash-ctrl"
+- reg : specify bus address and register area size.
+- interrupts : controller interrupt number and irq type.
+- nand-ecc-mode : See nand.txt. Supported values "hw", "soft_bch".
+- nand-ecc-strength : See nand.txt. Supported values: 4, 8, 16, 24, 32.
+- nand-ecc-step-size : See nand.txt. Supported values: 256, 512, 1024.
+
+Optional properties:
+- nand-on-flash-bbt: See nand.txt.
+
+Example:
+
+nand: nand@...1e000 {
+ compatible = "evatronix,nandflash-ctrl";
+ reg = <0xf801e000 0x0200>;
+ interrupts = <0 139 IRQ_TYPE_LEVEL_HIGH>;
+ /* ONFi mode 0 timing. */
+ /* Order is TIME_SEQ_0, TIME_SEQ_1, TIMINGS_ASYN,
+ * TIME_GEN_SEQ_0, _1, _2, _3 */
+ timings = <0x0d151533 0x000b0515 0x00000046
+ 0x00150000 0x00000000 0x00000005 0x00000015>;
+ nand-ecc-mode = "hw";
+ nand-on-flash-bbt;
+ nand-ecc-strength = <8>;
+ nand-ecc-step-size = <512>;
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 46a311e..49d66b3 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -46,6 +46,7 @@ epfl Ecole Polytechnique Fédérale de Lausanne
epson Seiko Epson Corp.
est ESTeem Wireless Modems
eukrea Eukréa Electromatique
+evatronix Evatronix SA
excito Excito
fsl Freescale Semiconductor
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f1cf503..6510aa2 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -74,6 +74,23 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
scratch register here to enable this feature. On Intel Moorestown
boards, the scratch register is at 0xFF108018.
+config MTD_NAND_EVATRONIX
+ bool "Enable Evatronix NANDFLASH-CTRL driver"
+ help
+ NAND hardware driver for Evatronix NANDFLASH-CTRL
+ NAND flash controller.
+
+config MTD_NAND_EVATRONIX_CHIPS
+ int "Number of NAND chips probed by Evatronix NAND flash driver"
+ default 1
+ range 1 2
+ depends on MTD_NAND_EVATRONIX
+ help
+ Number of NAND chips that should be supported by Evatronix NAND flash
+ driver. If multiple chips are detected, they will be concatenated
+ and presented as one large NAND device.
+ Currently a maximum of two chips are supported.
+
config MTD_NAND_GPIO
tristate "GPIO NAND Flash driver"
depends on GPIOLIB
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 542b568..c5bb52c 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
+obj-$(CONFIG_MTD_NAND_EVATRONIX) += evatronix_nand.o
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
diff --git a/drivers/mtd/nand/evatronix_nand.c b/drivers/mtd/nand/evatronix_nand.c
new file mode 100644
index 0000000..d87d13f
--- /dev/null
+++ b/drivers/mtd/nand/evatronix_nand.c
@@ -0,0 +1,1358 @@
+/*
+ * evatronix_nand.c - NAND Flash Driver for Evatronix NANDFLASH-CTRL
+ * NAND Flash Controller IP.
+ *
+ * Intended to handle one NFC, with up to two connected NAND flash chips,
+ * one per bank.
+ *
+ * This implementation has been designed against Rev 1.15 of the
+ * NANDFLASH-CTRL Design Specification.
+ *
+ * Copyright (c) 2014 Axis Communication AB, Lund, Sweden.
+ * Portions Copyright (c) 2010 ST Microelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <asm/dma.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_mtd.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/concat.h>
+#include <linux/mtd/partitions.h>
+#include <linux/version.h>
+
+#include "evatronix_nand.h"
+
+/* Driver configuration */
+
+#define ETX_CE_BANK_SEL /* Separate chips connected as separate banks */
+#define ETX_RB_WIRED_AND /* Use wired-AND for ready/busy from flash chip */
+
+#undef POLLED_XFERS
+
+/* Workarounds for development environment */
+
+#define WORKAROUND_NO_ECC_CNT
+
+/* Debugging */
+
+#if 0
+#define MTD_TRACE(FORMAT, ...) \
+ pr_info("mtd trace: %s: " FORMAT, __func__, ## __VA_ARGS__)
+#else
+#define MTD_TRACE(FORMAT, ...) do { } while (0)
+#endif
+
+#ifndef CONFIG_MTD_NAND_EVATRONIX_CHIPS
+#define CONFIG_MTD_NAND_EVATRONIX_CHIPS 1
+#endif
+
+/* Read modes */
+enum etx_read_mode {
+ ETX_READ_STD, /* Standard page read with ECC */
+ ETX_READ_RAW, /* Raw mode read of main area without ECC */
+ ETX_READ_OOB, /* Read oob only (no ECC) */
+ ETX_READ_ALL /* Read main+oob in raw mode (no ECC) */
+};
+
+#define DMA_BUF_SIZE (8192 + 640) /* main + spare for 8k page flash */
+
+/* # bytes into the OOB we put our ECC */
+#define ECC_OFFSET 2
+
+/* Timing parameters, from dt */
+struct etx_timings {
+ uint32_t time_seq_0;
+ uint32_t time_seq_1;
+ uint32_t timings_asyn;
+ uint32_t time_gen_seq_0;
+ uint32_t time_gen_seq_1;
+ uint32_t time_gen_seq_2;
+ uint32_t time_gen_seq_3;
+};
+
+/* Configuration, from dt */
+struct etx_setup {
+ nand_ecc_modes_t ecc_mode;
+ int ecc_blksize;
+ int ecc_strength;
+ bool on_flash_bbt;
+ struct etx_timings timings;
+};
+
+/* DMA buffer, from both software (buf) and hardware (phys) perspective. */
+struct etx_dma {
+ void *buf; /* mapped address */
+ dma_addr_t phys; /* physical address */
+ int bytes_left; /* how much data left to read from buffer? */
+ uint8_t *ptr; /* work pointer */
+};
+
+#ifndef POLLED_XFERS
+/* Interrupt management */
+struct etx_irq {
+ int done; /* interrupt triggered, consequently we're done. */
+ uint32_t int_status; /* INT_STATUS at time of interrupt */
+ wait_queue_head_t wq; /* For waiting on controller interrupt */
+};
+#endif
+
+/* Information common to all chips, including the NANDFLASH-CTRL IP */
+struct etx_info {
+ unsigned char __iomem *regbase;
+ struct device *dev;
+ struct nand_hw_control *controller;
+ spinlock_t lock;
+ struct etx_setup *setup;
+ struct etx_dma dma;
+#ifndef POLLED_XFERS
+ struct etx_irq irq;
+#endif
+};
+
+/* Per-chip controller configuration */
+struct etx_config {
+ uint32_t mem_ctrl;
+ uint32_t control;
+ uint32_t ecc_ctrl;
+ uint32_t ecc_offset;
+ uint32_t mem_status_mask;
+};
+
+/* Cache for info that we need to save across calls to etx_nand_command */
+struct etx_cmd_cache {
+ unsigned int command;
+ int page;
+ int column;
+ int oob_required;
+ int write_raw;
+};
+
+/* Information for each physical NAND chip. */
+struct chip_info {
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ struct etx_cmd_cache cmd_cache;
+ struct etx_config etx_config;
+};
+
+/* What we tell mtd is an mtd_info actually is a complete chip_info */
+#define TO_CHIP_INFO(mtd) ((struct chip_info *)(mtd))
+
+/* This is a global pointer, as we only support one single instance of the NFC.
+ * For multiple instances, we would need to add etx_info as a parameter to
+ * several functions, as well as adding it as a member of the chip_info struct.
+ * Since most likely a system would only have one NFC instance, we don't
+ * go all the way implementing that feature now. */
+static struct etx_info *etx_info;
+
+/* The timing setup is expected to come via DT. We keep some default timings
+ * here for reference, based on a 100 MHz reference clock. */
+
+static const struct etx_timings default_mode0_pll_enabled = {
+ 0x0d151533, 0x000b0515, 0x00000046,
+ 0x00150000, 0x00000000, 0x00000005, 0x00000015 };
+
+/**** Utility routines. */
+
+/* Count the number of 0's in buff upto a max of max_bits */
+/* Used to determine how many bit flips there are in an allegely erased block */
+static int count_zero_bits(uint8_t *buff, int size, int max_bits)
+{
+ int k, zero_bits = 0;
+
+ for (k = 0; k < size; k++) {
+ zero_bits += hweight8(~buff[k]);
+ if (zero_bits > max_bits)
+ break;
+ }
+
+ return zero_bits;
+}
+
+/**** Low level stuff. Read and write registers, interrupt routine, etc. */
+
+/* Read and write NFC SFR registers */
+
+static uint32_t etx_read(uint reg_offset)
+{
+ return ioread32(etx_info->regbase + reg_offset);
+}
+
+static void etx_write(uint32_t data, uint reg_offset)
+{
+ /* Note: According to NANDFLASH-CTRL Design Specification, rev 1.14,
+ * p19, the NFC SFR's can only be written when STATUS.CTRL_STAT is 0.
+ * So, should really check for that here. */
+ iowrite32(data, etx_info->regbase + reg_offset);
+}
+
+#ifndef POLLED_XFERS
+static irqreturn_t etx_irq(int irq, void *device_info)
+{
+ /* Note that device_info = etx_info, so if we don't want a global
+ * etx_info we can get it via device_info. */
+
+ /* Save interrupt status in case caller wants to check what actually
+ * happened. */
+ etx_info->irq.int_status = etx_read(INT_STATUS_REG);
+
+ MTD_TRACE("Got interrupt %d, INT_STATUS 0x%08x\n",
+ irq, etx_info->irq.int_status);
+
+ /* Note: We can't (at least in the software model) clear the interrupts
+ * by clearing CONTROL.INT_EN, as that does not disable the interrupt
+ * output port from the nfc towards the gic. */
+ etx_write(0, INT_STATUS_REG);
+
+ etx_info->irq.done = 1;
+ wake_up(&etx_info->irq.wq);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+/* Get resources from platform: register bank mapping, irqs, etc */
+static int etx_init_resources(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *resource;
+#ifndef POLLED_XFERS
+ int irq;
+#endif
+ int res;
+
+ /* Register base for controller, ultimately from device tree */
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!resource) {
+ dev_err(dev, "No register addresses configured!\n");
+ return -ENOMEM;
+ }
+ etx_info->regbase = devm_ioremap_resource(dev, resource);
+ if (IS_ERR(etx_info->regbase))
+ return PTR_ERR(etx_info->regbase);
+
+ dev_info(dev, "Got SFRs at phys %p..%p, mapped to %p\n",
+ (void *)resource->start, (void *)resource->end,
+ etx_info->regbase);
+
+ /* A DMA buffer */
+ etx_info->dma.buf =
+ dma_alloc_coherent(dev, DMA_BUF_SIZE,
+ &etx_info->dma.phys, GFP_KERNEL);
+ if (etx_info->dma.buf == NULL) {
+ dev_err(dev, "dma_alloc_coherent failed!\n");
+ return -ENOMEM;
+ }
+
+ dev_info(dev, "DMA buffer %p at physical %p\n",
+ etx_info->dma.buf, (void *)etx_info->dma.phys);
+
+#ifndef POLLED_XFERS
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "No irq configured\n");
+ return irq;
+ }
+ res = request_irq(irq, etx_irq, 0, "evatronix-nand", etx_info);
+ if (res < 0) {
+ dev_err(dev, "request_irq failed\n");
+ return res;
+ }
+ dev_info(dev, "Successfully registered IRQ %d\n", irq);
+#endif
+
+ return 0;
+}
+
+/* Write timing setup to controller */
+static void setup_etx_timing(struct etx_setup *etx_setup)
+{
+ etx_write(etx_setup->timings.time_seq_0, TIME_SEQ_0_REG);
+ etx_write(etx_setup->timings.time_seq_1, TIME_SEQ_1_REG);
+ etx_write(etx_setup->timings.timings_asyn, TIMINGS_ASYN_REG);
+ etx_write(etx_setup->timings.time_gen_seq_0, TIME_GEN_SEQ_0_REG);
+ etx_write(etx_setup->timings.time_gen_seq_1, TIME_GEN_SEQ_1_REG);
+ etx_write(etx_setup->timings.time_gen_seq_2, TIME_GEN_SEQ_2_REG);
+ etx_write(etx_setup->timings.time_gen_seq_3, TIME_GEN_SEQ_3_REG);
+}
+
+/* Write per-chip specific config to controller */
+static void config_etx(struct etx_config *etx_config, void *ref)
+{
+ static void *saved_ref;
+
+ /* To avoid rewriting these unnecessarily every time, we only do
+ * it when the ref has changed, or if ref == NULL (=> force). */
+ if (ref) {
+ if (ref == saved_ref)
+ return;
+ saved_ref = ref; /* only save if non-null */
+ }
+
+ etx_write(etx_config->mem_ctrl, MEM_CTRL_REG);
+ etx_write(etx_config->control, CONTROL_REG);
+ etx_write(etx_config->ecc_ctrl, ECC_CTRL_REG);
+ etx_write(etx_config->ecc_offset, ECC_OFFSET_REG);
+}
+
+
+#ifndef POLLED_XFERS
+/* Set up interrupt and wq, with supplied interrupt mask */
+static void setup_int(uint32_t what)
+{
+ /* Flag waited on by wq */
+ etx_info->irq.done = 0;
+
+ /* clear interrupt status bits */
+ etx_write(0, INT_STATUS_REG);
+
+ /* set interrupt mask */
+ etx_write(what, INT_MASK_REG);
+
+ /* enable global NFC interrupt. Ooooh... */
+ etx_write(etx_read(CONTROL_REG) | CONTROL_INT_EN, CONTROL_REG);
+}
+#endif
+
+/* Set up interrupt, send command, then wait for (any bit of) expected state */
+/* Before issuing a command, we should check if the controller is ready.
+ * We can't check INT_STATUS_REG.MEM0_RDY_INT_FL as it is not a status bit,
+ * it is set on an nfc state transition after the completion of for
+ * instance a page program command, so we can use it as a command
+ * completed trigger however.
+ * (See NFC Design Spec (rev 1.15) figure 35 for illustration.)
+ * TODO: However, we could check STATUS.CTRL_STAT, which should always
+ * be 0 prior to issuing a command, indicating the controller is not
+ * busy. */
+static void command_and_wait(uint32_t etx_command, uint32_t int_state)
+#ifndef POLLED_XFERS
+{
+ long timeout;
+
+ /* Set up interrupt condition. Here we utilize the fact that the
+ * bits in INT_STATE are the same as in INT_MASK. */
+ setup_int(int_state);
+
+ /* Send command */
+ etx_write(etx_command, COMMAND_REG);
+
+ /* The timeout should only trigger in abnormal situations, so
+ * we leave it at one second for now. (nand_base uses 20ms for write
+ * and 400ms for erase, respectively.) */
+ /* TODO: A special case might be to consider the case of an
+ * unconnected flash chip during probe. If that causes the timeout
+ * to be triggered, we might want to lower it, and even make it
+ * dependent on the NAND flash command being executed. */
+ timeout = wait_event_timeout(etx_info->irq.wq, etx_info->irq.done,
+ 1 * HZ);
+ if (timeout <= 0) {
+ dev_info(etx_info->dev,
+ "Request 0x%08x timed out waiting for 0x%08x\n",
+ etx_command, int_state);
+ /* TODO: Do something useful here? */
+ }
+}
+#else /* POLLED_XFERS */
+{
+ int cmd_loops = 0;
+ uint32_t read_status, read_int_status, dma_status;
+
+ /* Clear interrupt status bits */
+ etx_write(0, INT_STATUS_REG);
+
+ /* Send command */
+ etx_write(etx_command, COMMAND_REG);
+
+ /* Wait for command to complete */
+ MTD_TRACE("Waiting for 0x%08x bit(s) to be set in int_status\n",
+ int_state);
+
+#define MAX_CMD_LOOPS 100000
+ do {
+ cmd_loops++;
+ read_status = etx_read(STATUS_REG);
+ read_int_status = etx_read(INT_STATUS_REG);
+ dma_status = etx_read(DMA_CTRL_REG);
+ MTD_TRACE("Wait for command done: 0x%08x/0x%08x/0x%08x (%d)\n",
+ read_status, read_int_status, dma_status, cmd_loops);
+ } while (!(read_int_status & int_state) && cmd_loops < MAX_CMD_LOOPS);
+
+ if (cmd_loops >= MAX_CMD_LOOPS)
+ MTD_TRACE("Int wait for 0x%08x timed out after %d loops: "
+ "STATUS = 0x%08x, INT_STATUS=0x%08x, "
+ "DMA_CTRL = 0x%08x, command 0x%08x\n",
+ cmd_loops, int_state, read_status, read_int_status,
+ dma_status, etx_command);
+}
+#endif
+
+/* Initialize DMA, wq and interrupt status for upcoming transfer. */
+static void init_dma(uint64_t addr, int bytes)
+{
+ int dma_trig_level;
+
+ /* DMA control */
+
+ /* Start when COMMAND register written, set burst type/size */
+ etx_write(DMA_CTRL_DMA_START | DMA_CTRL_DMA_BURST_I_P_4, DMA_CTRL_REG);
+
+ /* DMA address and length */
+#ifdef EVATRONIX_DMA64BIT
+ /* The manual says this register does not 'occur' (sic) unless
+ * 64 bit DMA support is included. */
+ etx_write(addr >> 32, DMA_ADDR_H_REG);
+#endif
+ etx_write(addr, DMA_ADDR_L_REG);
+
+ /* Byte counter */
+ /* Round up to nearest 32-bit word */
+ etx_write((bytes + 3) & 0xfffffffc, DMA_CNT_REG);
+
+ /* Cap DMA trigger level at FIFO size */
+ dma_trig_level = bytes * 8 / 32; /* 32-bit entities */
+ if (dma_trig_level > DMA_TLVL_MAX)
+ dma_trig_level = DMA_TLVL_MAX;
+ etx_write(dma_trig_level, DMA_TLVL_REG);
+}
+
+/* Initialize transfer to or from DMA buffer */
+static void init_dmabuf(int bytes)
+{
+ etx_info->dma.ptr = etx_info->dma.buf;
+ etx_info->dma.bytes_left = bytes;
+}
+
+/* Initialize controller for DATA_REG readout */
+static void init_dreg_read(int bytes)
+{
+ /* Transfer to DATA_REG register */
+ etx_write(DATA_REG_SIZE_DATA_REG_SIZE(bytes), DATA_REG_SIZE_REG);
+}
+
+/* Set up CONTROL depending on whether we want ECC or not */
+static void setup_control(int enable_ecc)
+{
+ uint32_t control;
+
+ /* When reading the oob, we never want ECC, when reading the
+ * main area, it depends. */
+ control = etx_read(CONTROL_REG) & ~CONTROL_ECC_EN;
+ if (enable_ecc)
+ control |= CONTROL_ECC_EN;
+ etx_write(control, CONTROL_REG);
+}
+
+/* Read from flash using DMA */
+/* Assumes basic setup for DMA has been done previously. */
+/* The MTD framework never reads a complete page (main + oob) in one go
+ * when using HW ECC, so we don't need to support ETX_READ_ALL in this mode.
+ * For SW ECC we read the whole page on one go in ALL mode however. */
+static void read_dma(struct chip_info *info, int page, int column,
+ enum etx_read_mode m)
+{
+ int size;
+ uint32_t command;
+
+ switch (m) {
+ case ETX_READ_OOB:
+ size = info->mtd.oobsize;
+ break;
+ case ETX_READ_ALL:
+ size = info->mtd.oobsize + info->mtd.writesize;
+ break;
+ case ETX_READ_STD:
+ case ETX_READ_RAW:
+ size = info->mtd.writesize;
+ break;
+ default:
+ BUG();
+ }
+
+ /* Set up ECC depending on mode */
+ setup_control(m == ETX_READ_STD);
+
+ /* Set up DMA and transfer size */
+
+ init_dmabuf(size);
+ init_dma(etx_info->dma.phys, size);
+ etx_write(size, DATA_SIZE_REG);
+
+ /* Set up addresses */
+
+ if (m == ETX_READ_OOB)
+ column += info->mtd.writesize;
+ etx_write(column, ADDR0_COL_REG);
+ etx_write(page, ADDR0_ROW_REG);
+
+ /* For devices > 128 MiB we have 5 address cycles and can use a
+ * standard NFC command sequence. For smaller devices we have
+ * 4 address cycles and need to use a Generic Command Sequence. */
+ if (info->chip.chipsize > (128 << 20)) {
+ command = COMMAND_READ_PAGE_DMA_STD;
+ } else {
+ etx_write(GEN_SEQ_CTRL_READ_PAGE_4CYCLE, GEN_SEQ_CTRL_REG);
+ command = COMMAND_READ_PAGE_DMA_GEN;
+ }
+
+ command_and_wait(command, INT_STATUS_DMA_INT_FL);
+}
+
+/* Write using DMA */
+/* Assumes DMA has been set up previously and buffer contains data. */
+/* Contrary to read, column is set to writesize when writing to oob, by mtd.
+ * oob is set when the caller wants to write oob data along with the main data.
+ */
+static void write_dma(struct chip_info *info, int page, int column,
+ int oob, int raw)
+{
+ int size;
+ uint32_t command;
+
+ /* Since the controller handles ECC on its own, raw mode doesn't
+ * come into the size calculations. */
+ if (column >= info->mtd.writesize) { /* oob write only */
+ size = info->mtd.oobsize;
+ raw = 1;
+ } else {
+ size = info->mtd.writesize;
+ if (oob) {
+ size += info->mtd.oobsize;
+ raw = 1;
+ }
+ }
+
+ setup_control(!raw);
+
+ /* Dump selected parts of buffer */
+ MTD_TRACE("Write %d bytes: 0x%08x 0x%08x .. 0x%08x\n", size,
+ ((uint32_t *)(etx_info->dma.buf))[0],
+ ((uint32_t *)(etx_info->dma.buf))[1],
+ ((uint32_t *)(etx_info->dma.buf))[size / 4 - 1]);
+
+ /* Set up DMA and transfer size */
+ init_dma(etx_info->dma.phys, size);
+ etx_write(size, DATA_SIZE_REG);
+
+ /* Set up addresses */
+
+ etx_write(column, ADDR0_COL_REG);
+ etx_write(page, ADDR0_ROW_REG);
+
+
+ /* For devices > 128 MiB we have 5 address cycles and can use a
+ * standard NFC command sequence. For smaller devices we have
+ * 4 address cycles and need to use a Generic Command Sequence. */
+ if (info->chip.chipsize > (128 << 20)) {
+ command = COMMAND_WRITE_PAGE_DMA_STD;
+ } else {
+ etx_write(GEN_SEQ_CTRL_WRITE_PAGE_4CYCLE, GEN_SEQ_CTRL_REG);
+ command = COMMAND_WRITE_PAGE_DMA_GEN;
+ }
+
+ /* TODO: Use INT_STATUS_MEM0_RDY_INT_FL instead ? */
+ command_and_wait(command, INT_STATUS_DMA_INT_FL);
+
+ /* Wait for Ready from device */
+ /* TODO: ?needed ?how */
+ /* TODO: In the same way as for erase, we could check INT_STATUS_REG.
+ * STAT_ERR_INT0_FL, but nand_base will check the device by reading
+ * error status anyway after the write command. */
+
+ /* clear buffer so it doesn't contain the written data anymore */
+ /* TODO: remove this, just useful during development to verify
+ * that a subsequent read just doesn't read what happens to be
+ * lying around in the buffer. */
+ memset(etx_info->dma.buf, 0, DMA_BUF_SIZE);
+}
+
+/* Block erase */
+static void block_erase(int page)
+{
+ /* Set up addresses */
+ etx_write(page, ADDR0_ROW_REG);
+ MTD_TRACE("Erase block containing page %d\n", page);
+
+ /* Send 3 address cycle block erase command */
+ command_and_wait(COMMAND_BLOCK_ERASE, INT_STATUS_MEM0_RDY_INT_FL);
+
+#ifndef POLLED_XFERS
+ MTD_TRACE("Erase block: INT_STATUS 0x%08x\n", etx_info->irq.int_status);
+#endif
+ /* TODO: What to do if we get an error bit set here (i.e.INT_STATUS_REG.
+ * STAT_ERR_INT0_FL) ? Normally, error status is checked by nand_base
+ * by doing a status read after the erase command. So we can probably
+ * ignore STAT_ERR_INT0_FL here. If need be, we can save the
+ * status so a subsequent status right might use it for something.
+ * The err bit probably just indicates that the flash didn't pull
+ * R/_B low within tWB. */
+}
+
+/* Check for erased page.
+ * The prerequisite to calling this routine is: page has been read with
+ * HW ECC, which has returned an 'ecc uncorrectable' status, so either the
+ * page does in fact contain too many bitflips for the ECC algorithm to correct
+ * or the page is in fact erased, which results in the all-FF's ECC to
+ * be invalid relative to the all-FF's data on the page.
+ * Since with the Evatronix NFC we don't have access to either the ECC bytes
+ * or the oob area after a HW ECC read, the following algorithm is adopted:
+ * - Count the number of 0's in the main area. If there are more than
+ * the ECC strength per ECC block we assume the page wasn't in fact erased,
+ * and return with an error status.
+ * - If the main area appears erased, we still need to determine if the oob is
+ * also erased, if not, it would appear that the page wasn't in fact erased,
+ * and what we're looking at is a page of mostly-FF data with an invalid ECC.
+ * - Thus we need to read the oob, leaving the main area at the start of the
+ * DMA buffer in case someone actually wants to read the data later (e.g.
+ * nanddump).
+ * - We then count the number of non-zero bits in the oob. The accepted
+ * number of zeros could be determined by figuring the the size ratio
+ * of the oob compared to an ECC block. For instance, if the oob is 64
+ * bytes, an ECC block 512 bytes, and the error correction capability
+ * of 8 bits, then the accepted number of zeros for the oob to be
+ * considered erased would be 64/512 * 8 = 1. Alternatively we could just
+ * accept an error correction capability number of zeros.
+ * If there are less than this threshold number of zero bits, the page
+ * is considered erased. In this case we return an all-FF page to the user.
+ * Otherwise, we consider ourselves to have an ECC error on our hands,
+ * and we return the apropriate error status while at the same time leaving
+ * original main area data in place, for potential scrutiny by a user space
+ * application (e.g. nanddump).
+ * Caveat: It could be that there are some cases for which an almost-FF page
+ * yields an almost-FF ECC. If there are fewer than the error correction
+ * capability number of zero bits, we could conclude that such a page would
+ * be erased when in fact it actually contains data with too many bitflips.
+ * Experience will have to determine whether this can actually occur. From
+ * past experiences with ECC codes it seems unlikely that that trivial
+ * data will in fact result in a trivial ECC code. Even the fairly basic
+ * 1-bit error correction capability Hamming code does not on its own return
+ * an all-FF ECC for all-FF data.
+ *
+ * Function returns 1 if the page is in fact (considered) erased, 0 if not.
+ */
+static int check_erased_page(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct chip_info *info = TO_CHIP_INFO(mtd);
+ struct nand_chip *chip = &info->chip;
+
+ /* We calculate the number of steps here rather than grabbing
+ * ecc.steps to handle the case of a subpage read where we
+ * haven't read a complete page. */
+ int eccsteps = len / chip->ecc.size;
+ int eccsize = chip->ecc.size;
+ int eccstrength = chip->ecc.strength;
+
+ int main_area_zeros = 0;
+
+ int step;
+ uint8_t *bufpos = buf;
+
+ MTD_TRACE("%s: %d byte page, ecc steps %d, size %d, strength %d\n",
+ __func__, len, eccsteps, eccsize, eccstrength);
+
+ /* Check that main area appears erased. If not, return */
+
+ for (step = 0; step < eccsteps; step++) {
+ int zeros = count_zero_bits(bufpos, eccsize, eccstrength);
+
+ if (zeros > eccstrength)
+ return 0;
+ bufpos += eccsize;
+ main_area_zeros += zeros;
+ }
+
+ /* Ok, main area seems erased. Read oob so we can check it too. */
+
+ /* Note that this will overwrite the DMA buffer with the oob data,
+ * which is ok since the main area data has already been copied
+ * to buf earlier. */
+ read_dma(info, info->cmd_cache.page, info->cmd_cache.column,
+ ETX_READ_OOB);
+
+ /* We go for the simple approach and accept eccstrength zero bits */
+ if (count_zero_bits(etx_info->dma.buf, mtd->oobsize, eccstrength) >
+ eccstrength)
+ return 0;
+
+ MTD_TRACE("%s: Page is erased.%s\n", __func__,
+ main_area_zeros != 0 ? " Clearing main area to 0xff." : "");
+
+ if (main_area_zeros != 0)
+ memset(buf, 0xff, len);
+
+ return 1;
+}
+
+
+/**** MTD API ****/
+
+/* For cmd_ctrl (and possibly others) we need to do absolutely nothing, but the
+ * pointer is still required to point to a valid function. */
+static void etx_dummy_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+}
+
+/* Read state of ready pin */
+static int etx_dev_ready(struct mtd_info *mtd)
+{
+ struct chip_info *info = TO_CHIP_INFO(mtd);
+ struct etx_config *etx_config = &info->etx_config;
+
+ MTD_TRACE("%p\n", mtd);
+
+ return !!(etx_read(STATUS_REG) & etx_config->mem_status_mask);
+
+}
+
+/* Read byte from DMA buffer */
+/* Not used directly, only via etx_read_byte */
+static uint8_t etx_read_dmabuf_byte(struct mtd_info *mtd)
+{
+ MTD_TRACE("%p\n", mtd);
+ if (etx_info->dma.bytes_left) {
+ etx_info->dma.bytes_left--;
+ return *etx_info->dma.ptr++;
+ } else
+ return 0; /* no data */
+}
+
+/* Read block of data from DMA buffer */
+static void etx_read_dmabuf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ MTD_TRACE("%p, buf %p, len %d\n", mtd, buf, len);
+ if (len > etx_info->dma.bytes_left) {
+ dev_crit(etx_info->dev,
+ "Trying to read %d bytes with %d bytes remaining\n",
+ len, etx_info->dma.bytes_left);
+ BUG();
+ }
+ memcpy(buf, etx_info->dma.ptr, len);
+ etx_info->dma.ptr += len;
+ etx_info->dma.bytes_left -= len;
+}
+
+/* Write block of data to DMA buffer */
+static void etx_write_dmabuf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ MTD_TRACE("%p, buf %p, len %d\n", mtd, buf, len);
+ /* TODO: Grab info pointer from mtd instead of using same always ? */
+ if (len > etx_info->dma.bytes_left) {
+ dev_crit(etx_info->dev,
+ "Trying to write %d bytes with %d bytes remaining\n",
+ len, etx_info->dma.bytes_left);
+ BUG();
+ }
+ memcpy(etx_info->dma.ptr, buf, len);
+ etx_info->dma.ptr += len;
+ etx_info->dma.bytes_left -= len;
+}
+
+/* Read byte from DMA buffer or DATA_REG, depending on previous command. */
+/* Used by MTD for reading ID bytes, and chip status */
+static uint8_t etx_read_byte(struct mtd_info *mtd)
+{
+ struct chip_info *info = TO_CHIP_INFO(mtd);
+ uint8_t status_value;
+
+ if (info->cmd_cache.command != NAND_CMD_STATUS)
+ return etx_read_dmabuf_byte(mtd);
+
+ MTD_TRACE("Read status\n");
+
+ /* In order to read status, we need to send a READ_STATUS command
+ * to the NFC first, in order to get the data into the DATA_REG */
+ init_dreg_read(1);
+ /* We want to read all status bits from the device */
+ etx_write(STATUS_MASK_STATE_MASK(0xff), STATUS_MASK_REG);
+ command_and_wait(COMMAND_READ_STATUS, INT_STATUS_DATA_REG_FL);
+ status_value = etx_read(DATA_REG_REG) & 0xff;
+ status_value = 0xC0; /* Bit 7 : No write prot., Bit 6: Device ready */
+ MTD_TRACE("Status 0x%08x\n", status_value);
+ return status_value;
+}
+
+/* Do the dirty work for read_page_foo */
+static int etx_read_page_mode(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page, enum etx_read_mode m)
+{
+ struct chip_info *info = TO_CHIP_INFO(mtd);
+ unsigned int max_bitflips;
+ uint32_t ecc_status;
+
+ if (page != info->cmd_cache.page) {
+ MTD_TRACE("Warning: Read page has different page number than "
+ "READ0: %d vs. %d\n", page, info->cmd_cache.page);
+ }
+
+ if (m == ETX_READ_STD) {
+ /* ECC error flags and counters are not cleared automatically
+ * so we do it here. */
+ /* Note that the design spec says nothing about having to
+ * zero ECC_STAT (although it explicitly says that ECC_CNT
+ * needs to be zeroed by software), but testing on actual
+ * hardware (RTL at this stage) reveals that this is in fact
+ * the case. */
+ etx_write(0, ECC_STAT_REG);
+ etx_write(0, ECC_CNT_REG);
+ }
+
+ read_dma(info, info->cmd_cache.page, info->cmd_cache.column, m);
+
+ /* This is actually etx_read_dmabuf */
+ chip->read_buf(mtd, buf, mtd->writesize);
+
+ if (m == ETX_READ_RAW)
+ return 0;
+
+ /* Get ECC status from controller */
+ ecc_status = etx_read(ECC_STAT_REG);
+ max_bitflips = etx_read(ECC_CNT_REG) & ECC_CNT_ERR_LVL_MASK;
+
+#ifdef WORKAROUND_NO_ECC_CNT
+ /* If we get an ERROR bit set, but ECC_CNT is 0, we assume
+ * a single bit flip has occurred for want of better information. */
+ if ((ecc_status & ECC_STAT_ERROR_0) && max_bitflips == 0)
+ max_bitflips = 1;
+#endif
+
+ if (ecc_status & ECC_STAT_UNC_0)
+ if (!check_erased_page(mtd, buf, mtd->writesize))
+ mtd->ecc_stats.failed++;
+
+ /* The following is actually not really correct, as the stats should
+ * reflect _all_ bitflips, not just the largest one in the latest read.
+ * We could rectify this by reading chip->ecc.bytes at a time,
+ * and accumulating the statistics per read, but at least for now
+ * the additional overhead doesn't seem to warrant the increased
+ * accuracy of the statistics, since the important figure is the
+ * max number of bitflips in a single ECC block returned by this
+ * function. */
+ mtd->ecc_stats.corrected += max_bitflips;
+
+ MTD_TRACE("ECC read status: %s%s%s%s, correction count %d\n",
+ ecc_status & ECC_STAT_UNC_0 ? "Uncorrected " : "",
+ ecc_status & ECC_STAT_ERROR_0 ? "Corrected " : "",
+ ecc_status & ECC_STAT_OVER_0 ? "Over limit " : "",
+ ecc_status & (ECC_STAT_UNC_0 | ECC_STAT_ERROR_0 |
+ ECC_STAT_OVER_0) ? "" : "ok", max_bitflips);
+
+ /* We shouldn't see oob_required for ECC reads. */
+ if (oob_required) {
+ dev_crit(etx_info->dev, "Need separate read for the OOB\n");
+ BUG();
+ }
+
+ return max_bitflips;
+}
+
+/* Read page with HW ECC */
+static int etx_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page)
+{
+ MTD_TRACE("page %d, oobreq %d\n", page, oob_required);
+ return etx_read_page_mode(mtd, chip, buf, oob_required, page,
+ ETX_READ_STD);
+}
+
+/* Read page with no ECC */
+static int etx_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page)
+{
+ MTD_TRACE("page %d, oobreq %d\n", page, oob_required);
+ return etx_read_page_mode(mtd, chip, buf, oob_required, page,
+ ETX_READ_RAW);
+}
+
+/* Write page with HW ECC */
+/* This is the only place where we know we'll be writing w/ ECC */
+static int etx_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int oob_required)
+{
+ struct chip_info *info = TO_CHIP_INFO(mtd);
+
+ MTD_TRACE("oob_required %d\n", oob_required);
+
+ /* The controller can't write data to the oob when ECC is enabled,
+ * so we set oob_required to 0 here and don't process the oob
+ * further even if requested. This could happen for instance if
+ * using nandwrite -o without -n . */
+ if (oob_required)
+ dev_warn(etx_info->dev, "Tried to write OOB with ECC!\n");
+ info->cmd_cache.oob_required = 0;
+ info->cmd_cache.write_raw = 0;
+
+ /* A bit silly this, this is actually etx_write_dmabuf */
+ chip->write_buf(mtd, buf, mtd->writesize);
+
+ return 0;
+}
+
+/* Write page with no ECC */
+/* This is the only place where we know we won't be writing w/ ECC */
+static int etx_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int oob_required)
+{
+ struct chip_info *info = TO_CHIP_INFO(mtd);
+
+ MTD_TRACE("oob_required %d\n", oob_required);
+
+ /* We need this for the upcoming PAGEPROG command */
+ info->cmd_cache.oob_required = oob_required;
+ info->cmd_cache.write_raw = 1;
+
+ /* A bit silly this, this is actually etx_write_dmabuf */
+ chip->write_buf(mtd, buf, mtd->writesize);
+
+ if (oob_required)
+ chip->write_buf(mtd, info->chip.oob_poi, mtd->oobsize);
+
+ return 0;
+}
+
+
+/* Handle commands from MTD NAND layer */
+static void etx_nand_command(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+{
+ /* We know that an mtd belonging to us is actually only the first
+ * struct in a multi-struct structure. */
+ struct chip_info *info = TO_CHIP_INFO(mtd);
+
+ /* Save command so that other parts of the API can figure out
+ * what's actually going on. */
+ info->cmd_cache.command = command;
+
+ /* Configure the NFC for the flash chip in question. */
+ config_etx(&info->etx_config, info);
+
+ /* Some commands we execute immediately, while some need to be
+ * deferred until we have all the data needed, i.e. for page read,
+ * we can't initiate the read until we know if we are going to be
+ * using raw mode or not.
+ */
+ switch (command) {
+ case NAND_CMD_READ0:
+ MTD_TRACE("READ0 page %d, column %d\n", page_addr, column);
+ if (etx_info->setup->ecc_mode == NAND_ECC_HW) {
+ /* We do not yet know if the caller wants to
+ * read the page with or without ECC, so we
+ * just store the page number and main/oob flag
+ * here.
+ * TODO: Since the page number arrives via the
+ * read_page call, we don't really need to
+ * store it. */
+ info->cmd_cache.page = page_addr;
+ info->cmd_cache.column = column;
+ } else {
+ /* Read the whole page including oob */
+ info->cmd_cache.oob_required = 1;
+ read_dma(info, page_addr, column, ETX_READ_ALL);
+ }
+ break;
+ case NAND_CMD_READOOB:
+ MTD_TRACE("READOOB page %d, column %d\n", page_addr, column);
+ /* In contrast to READ0, where nand_base always calls
+ * a read_page_foo function before reading the data,
+ * for READOOB, read_buf is called instead.
+ * We don't want the actual read in read_buf, so
+ * we put it here. */
+ read_dma(info, page_addr, column, ETX_READ_OOB);
+ break;
+ case NAND_CMD_ERASE1:
+ MTD_TRACE("ERASE1 page %d\n", page_addr);
+ /* Just grab page parameter, wait until ERASE2 to do
+ * something. */
+ info->cmd_cache.page = page_addr;
+ break;
+ case NAND_CMD_ERASE2:
+ MTD_TRACE("ERASE2 page %d, do it\n", info->cmd_cache.page);
+ /* Off we go! */
+ block_erase(info->cmd_cache.page);
+ break;
+ case NAND_CMD_RESET:
+ MTD_TRACE("chip reset\n");
+
+ command_and_wait(COMMAND_RESET,
+ INT_STATUS_CMD_END_INT_FL);
+ break;
+ case NAND_CMD_SEQIN:
+ MTD_TRACE("SEQIN column %d, page %d\n", column, page_addr);
+ /* Just grab some parameters, then wait until
+ * PAGEPROG to do the actual operation. */
+ info->cmd_cache.page = page_addr;
+ info->cmd_cache.column = column;
+ /* Prepare DMA buffer for data. We don't yet know
+ * how much data there is, so set size to max. */
+ init_dmabuf(DMA_BUF_SIZE);
+ break;
+ case NAND_CMD_PAGEPROG:
+ /* Used for both main area and oob */
+ MTD_TRACE("PAGEPROG page %d, column %d, w/oob %d, raw %d\n",
+ info->cmd_cache.page, info->cmd_cache.column,
+ info->cmd_cache.oob_required,
+ info->cmd_cache.write_raw);
+ write_dma(info, info->cmd_cache.page,
+ info->cmd_cache.column,
+ info->cmd_cache.oob_required,
+ info->cmd_cache.write_raw);
+ break;
+ case NAND_CMD_READID:
+ MTD_TRACE("READID (0x%02x)\n", column);
+
+ /* Read specified ID bytes */
+ /* 0x00 would be NAND_READ_ID_ADDR_STD
+ * 0x20 would be NAND_READ_ID_ADDR_ONFI,
+ * but NAND subsystem knows this and sends us the
+ * address values directly */
+ etx_write(column, ADDR0_COL_REG);
+
+ /* Set up expected number of returned bytes */
+ init_dmabuf(column == NAND_READ_ID_ADDR_STD ? 5 : 4);
+ init_dma(etx_info->dma.phys,
+ column == NAND_READ_ID_ADDR_STD ? 5 : 4);
+
+ /* Send read id command */
+ command_and_wait(COMMAND_READ_ID,
+ INT_STATUS_DMA_INT_FL);
+ break;
+ case NAND_CMD_STATUS:
+ MTD_TRACE("STATUS, defer to later read byte\n");
+ /* Don't do anything now, wait until we need to
+ * actually read status. */
+ break;
+ default:
+ MTD_TRACE("Unhandled command 0x%02x (col %d, page addr %d)\n",
+ command, column, page_addr);
+ break;
+ }
+}
+
+
+/**** Top level probing and device management ****/
+
+/* Get configuration from device tree */
+#ifdef CONFIG_OF
+static int etx_get_dt_config(struct platform_device *pdev)
+{
+ struct etx_setup *etx_setup = dev_get_platdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ int res, timings;
+
+ if (!np) {
+ dev_err(dev, "No configuration\n");
+ return -EINVAL;
+ }
+
+ /* ECC parameters */
+ res = of_get_nand_ecc_mode(np);
+ if (res == NAND_ECC_HW || res == NAND_ECC_SOFT_BCH)
+ etx_setup->ecc_mode = res;
+ else
+ dev_warn(dev, "Unsupported/unset ECC mode, using default\n");
+
+ res = of_get_nand_ecc_strength(np);
+ /* NFC can handle 2 bits but ECC_BYTES macro can't and it's
+ * highly unlikely we'd ever need to support 2 bits correction
+ * in practice, so don't allow that case here. */
+ if (res < 0 ||
+ (res != 4 && res != 8 && res != 16 && res != 24 && res != 32))
+ dev_warn(dev, "Unsupported ECC strength, using default\n");
+ else
+ etx_setup->ecc_strength = res;
+
+ res = of_get_nand_ecc_step_size(np);
+ if (res < 0 || (res != 256 && res != 512 && res != 1024))
+ dev_warn(dev, "Unsupported ECC step size, using default\n");
+ else
+ etx_setup->ecc_blksize = res;
+
+ etx_setup->on_flash_bbt = of_get_nand_on_flash_bbt(np);
+
+ timings = sizeof(etx_setup->timings) / sizeof(u32);
+ res = of_property_read_u32_array(np, "timings",
+ (u32 *)&etx_setup->timings, timings);
+ if (res < 0) {
+ dev_warn(dev, "NAND timing setup missing, using defaults\n");
+ /* Default values have been set, but we don't know what
+ * read_u32_array does if it fails during parsing, so reset
+ * them here again. */
+ memcpy(&etx_setup->timings, &default_mode0_pll_enabled,
+ sizeof(etx_setup->timings));
+ }
+
+ return 0;
+}
+#else
+static int etx_get_dt_config(struct platform_device *pdev)
+{
+ return -ENOSYS;
+}
+#endif
+
+
+/* Per-NAND-chip initialization. */
+static __init
+struct mtd_info *etx_nand_flash_probe(struct platform_device *pdev,
+ unsigned bank_no)
+{
+ struct chip_info *this;
+ struct device *dev = &pdev->dev;
+ int pages_per_block, ecc_blksize, ecc_strength;
+
+ /* Allocate memory for MTD device structure and private data */
+ this = devm_kzalloc(dev, sizeof(struct chip_info), GFP_KERNEL);
+ if (!this) {
+ dev_err(dev, "Unable to allocate local device structure.\n");
+ return NULL;
+ }
+
+ /* Link the private data with the mtd structure */
+ this->mtd.priv = &this->chip;
+
+ /* Set up basic config for NAND controller hardware */
+
+ /* Device control. */
+#ifdef ETX_CE_BANK_SEL
+ /* Separate chips regarded as different banks. */
+ this->etx_config.mem_ctrl = MEM_CTRL_BANK_SEL(bank_no);
+#else
+ /* Separate chips regarded as different chip selects. */
+ this->etx_config.mem_ctrl = MEM_CTRL_MEM_CE(bank_no);
+#endif
+
+#ifdef ETX_RB_WIRED_AND
+ /* Ready/busy from nand flash arrives via wired-AND for device 0 */
+ this->etx_config.mem_status_mask = STATUS_MEM0_ST;
+#else
+ /* Ready/busy from nand flash as separate per-device signals */
+ this->etx_config.mem_status_mask = STATUS_MEM_ST(bank_no);
+#endif
+
+ /* Our interface to the mtd API */
+ this->chip.cmdfunc = etx_nand_command;
+ this->chip.cmd_ctrl = etx_dummy_cmd_ctrl;
+ this->chip.dev_ready = etx_dev_ready;
+ this->chip.read_byte = etx_read_byte;
+ this->chip.read_buf = etx_read_dmabuf;
+ this->chip.write_buf = etx_write_dmabuf;
+
+ /* Scan to find existence of the device */
+ /* Note that the NFC is not completely set up at this time, but
+ * that is ok as we only need to identify the device here. */
+ if (nand_scan_ident(&this->mtd, 1, NULL))
+ goto outta_here;
+
+ /* Set up rest of config for NAND controller hardware */
+
+ /* set ECC block size and pages per block */
+ pages_per_block = this->mtd.erasesize / this->mtd.writesize;
+ ecc_blksize = etx_info->setup->ecc_blksize;
+ ecc_strength = etx_info->setup->ecc_strength;
+ this->etx_config.control = CONTROL_ECC_BLOCK_SIZE(ecc_blksize) |
+ CONTROL_BLOCK_SIZE(pages_per_block);
+
+ /* Set up ECC control and offset of ECC data */
+ /* We don't use the threshold capability of the controller, as we
+ * let mtd handle that, so set the threshold to same as capability. */
+ this->etx_config.ecc_ctrl = ECC_CTRL_ECC_THRESHOLD(ecc_strength) |
+ ECC_CTRL_ECC_CAP(ecc_strength);
+ /* Put ECC bytes into OOB at an offset, to skip bad block marker */
+ this->etx_config.ecc_offset = this->mtd.writesize + ECC_OFFSET;
+
+ /* Since we've now completed the configuration, we need to force it to
+ * be written to the NFC, else the caching in config_etx will leave
+ * the etx_config values written since nand_scan_ident unwritten. */
+ config_etx(&this->etx_config, NULL);
+
+ /* ECC setup */
+
+ /* ECC API */
+ /* Override the following functions when using hardware ECC,
+ * otherwise we use the defaults set up by nand_base. */
+ if (etx_info->setup->ecc_mode == NAND_ECC_HW) {
+ this->chip.ecc.read_page = etx_read_page_hwecc;
+ this->chip.ecc.read_page_raw = etx_read_page_raw;
+ this->chip.ecc.write_page = etx_write_page_hwecc;
+ this->chip.ecc.write_page_raw = etx_write_page_raw;
+ }
+
+ this->chip.ecc.mode = etx_info->setup->ecc_mode;
+
+ /* TODO: Not sure if these really need to be set for HW ECC; if
+ * nothing else though we can use the values for our lower level
+ * driver to have a common point where it is all set up .*/
+ this->chip.ecc.size = ecc_blksize;
+ this->chip.ecc.strength = ecc_strength;
+ this->chip.ecc.bytes = ECC_BYTES(ecc_strength, ecc_blksize);
+
+ /* We set the bitflip_threshold at 75% of the error correction
+ * level to get some margin in case bitflips happen in parts of the
+ * flash that we don't read that often. */
+ /* We add 1 so that an ECC strength of 1 gives us a threshold of 1;
+ * rather academic though, as we only support BCH anyway... */
+ this->mtd.bitflip_threshold = (ecc_strength + 1) * 3 / 4;
+
+ if (etx_info->setup->on_flash_bbt)
+ /* Enable the use of a flash based bad block table.
+ * Since the OOB is not ECC protected we don't put BBT stuff
+ * there. We also don't mark user-detected badblocks as bad in
+ * their oob, only in the BBT, to avoid potential chip problems
+ * when attempting to write bad blocks (writing to bad blocks
+ * is not recommended according to flash manufacturers). */
+ this->chip.bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB |
+ NAND_BBT_NO_OOB_BBM;
+
+ this->chip.controller = etx_info->controller;
+
+ /* Finalize NAND scan, including BBT if requested */
+ if (nand_scan_tail(&this->mtd))
+ goto outta_here;
+
+ this->mtd.dev.parent = &pdev->dev;
+
+ return &this->mtd;
+
+outta_here:
+ kfree(this);
+ return NULL;
+}
+
+/* Main probe function. Called to probe and set up device. */
+static int __init etx_nand_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtd_info *main_mtd = NULL;
+ struct mtd_info *mtds[CONFIG_MTD_NAND_EVATRONIX_CHIPS];
+ struct etx_setup *etx_setup;
+ struct nand_hw_control *controller;
+ int err = 0;
+
+ dev_info(dev, "Initializing Evatronix NANDFLASH-CTRL driver\n");
+
+ /* etx_info is where we keep runtime information about the NFC */
+ etx_info = devm_kzalloc(dev, sizeof(*etx_info), GFP_KERNEL);
+ if (!etx_info) {
+ dev_err(dev, "Unable to allocate device control structure.\n");
+ return -ENOMEM;
+ }
+ etx_info->dev = dev;
+ spin_lock_init(&etx_info->lock);
+
+ /* Set up a controller struct to act as shared lock for all devices */
+ controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL);
+ if (controller == NULL) {
+ dev_err(dev, "Unable to allocate controller structure.\n");
+ return -ENOMEM;
+ }
+ spin_lock_init(&controller->lock);
+ init_waitqueue_head(&controller->wq);
+ etx_info->controller = controller;
+
+ /* etx_setup is where we keep settings from DT, in digested form */
+ etx_setup = devm_kzalloc(dev, sizeof(*etx_setup), GFP_KERNEL);
+ if (!etx_setup) {
+ dev_err(dev, "Unable to allocate device setup structure.\n");
+ return -ENOMEM;
+ }
+ pdev->dev.platform_data = etx_setup;
+ etx_info->setup = etx_setup;
+
+ /* Default parameters, potentially overriden by DT */
+ etx_setup->ecc_mode = NAND_ECC_HW;
+ etx_setup->ecc_strength = 8;
+ etx_setup->ecc_blksize = 512;
+ memcpy(&etx_setup->timings, &default_mode0_pll_enabled,
+ sizeof(etx_setup->timings));
+
+ /* Get config from device tree. */
+ err = etx_get_dt_config(pdev);
+ if (err) {
+ dev_err(dev, "Can't retrieve dt config\n");
+ return err;
+ }
+
+ dev_info(dev, "ECC using %s mode with strength %i and block size %i.\n",
+ etx_setup->ecc_mode == NAND_ECC_HW ? "hardware" : "software",
+ etx_setup->ecc_strength, etx_setup->ecc_blksize);
+
+ /* Initialize interrupts and DMA etc. */
+ err = etx_init_resources(pdev);
+ if (err)
+ return err;
+
+ setup_etx_timing(etx_setup);
+
+#ifndef POLLED_XFERS
+ init_waitqueue_head(&etx_info->irq.wq);
+#endif
+
+ mtds[0] = etx_nand_flash_probe(pdev, 0);
+ if (mtds[0] == NULL)
+ return -ENXIO;
+
+#if CONFIG_MTD_NAND_EVATRONIX_CHIPS > 1
+ mtds[1] = etx_nand_flash_probe(pdev, 1);
+ if (mtds[1] != NULL) {
+ /* Two devices found, combine them into one */
+ main_mtd = mtd_concat_create(mtds, 2, "axisflash");
+
+ if (main_mtd == NULL) {
+ dev_err(dev, "mtd concat failed, using first chip\n");
+ main_mtd = mtds[0];
+ }
+ }
+#endif
+ if (main_mtd == NULL) {
+ /* No concat device, use first chip only */
+ main_mtd = mtds[0];
+ }
+
+ /* We have our mtd now, insert call to mapping driver here. */
+
+ return err;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id etx_nand_id_table[] = {
+ { .compatible = "evatronix,nandflash-ctrl" },
+ {} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, etx_nand_id_table);
+#endif
+
+static struct platform_driver etx_nand_driver = {
+ .driver = {
+ .name = "evatronix-nand",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = of_match_ptr(etx_nand_id_table),
+#endif
+ },
+ .probe = etx_nand_probe,
+};
+
+module_platform_driver(etx_nand_driver);
+
+MODULE_AUTHOR("Ricard Wanderlof <ricardw@...s.com>");
+MODULE_DESCRIPTION("Evatronix NANDFLASH-CTRL driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/evatronix_nand.h b/drivers/mtd/nand/evatronix_nand.h
new file mode 100644
index 0000000..115d1be
--- /dev/null
+++ b/drivers/mtd/nand/evatronix_nand.h
@@ -0,0 +1,401 @@
+/*
+ * evatronix_nand.h - NAND Flash Driver for Evatronix NANDFLASH-CTRL
+ * NAND Flash Controller IP.
+ *
+ * This implementation has been designed against Rev 1.15 of the
+ * NANDFLASH-CTRL Design Specification.
+ *
+ * Copyright (c) 2014 Axis Communication AB, Lund, Sweden.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _EVATRONIX_NAND_H_
+#define _EVATRONIX_NAND_H_
+
+#include <linux/bitops.h> /* for ffs() */
+
+/* Register offsets for Evatronix NANDFLASH-CTRL IP */
+/* Register field shift values and masks are interespersed as it makes
+ * them easier to locate. */
+/* We use shift values rather than direct masks (e.g. 0x0000d000), as the
+ * hardware manual lists the bit number, making the definitions below
+ * easier to verify against the manual. */
+/* All (known) registers are here, but we only put in the bit fields
+ * for the fields we need. */
+/* We try to be consistent regarding _SIZE/_MASK/_value macros so as to
+ * get a consistent layout here, except for trivial cases where there is
+ * only a single bit or field in a register at bit offset 0. */
+
+#define COMMAND_REG 0x00
+/* The masks reflect the input data to the MAKE_COMMAND macro, rather than
+ * the bits in the register itself. These macros are not intended to be
+ * used by the user, who should use the MAKE_COMMAND et al macros. */
+#define _CMD_SEQ_SHIFT 0
+#define _INPUT_SEL_SHIFT 6
+#define _DATA_SEL_SHIFT 7
+#define _CMD_0_SHIFT 8
+#define _CMD_1_3_SHIFT 16
+#define _CMD_2_SHIFT 24
+
+#define _CMD_SEQ_MASK 0x3f
+#define _INPUT_SEL_MASK 1
+#define _DATA_SEL_MASK 1
+#define _CMD_MASK 0xff /* for all CMD_foo */
+
+#define MAKE_COMMAND(CMD_SEQ, INPUT_SEL, DATA_SEL, CMD_0, CMD_1_3, CMD_2) \
+ ((((CMD_SEQ) & _CMD_SEQ_MASK) << _CMD_SEQ_SHIFT) | \
+ (((INPUT_SEL) & _INPUT_SEL_MASK) << _INPUT_SEL_SHIFT) | \
+ (((DATA_SEL) & _DATA_SEL_MASK) << _DATA_SEL_SHIFT) | \
+ (((CMD_0) & _CMD_MASK) << _CMD_0_SHIFT) | \
+ (((CMD_1_3) & _CMD_MASK) << _CMD_1_3_SHIFT) | \
+ (((CMD_2) & _CMD_MASK) << _CMD_2_SHIFT))
+
+#define INPUT_SEL_SIU 0
+#define INPUT_SEL_DMA 1
+#define DATA_SEL_FIFO 0
+#define DATA_SEL_DATA_REG 1
+
+#define CONTROL_REG 0x04
+#define CONTROL_BLOCK_SIZE_32 (0 << 6)
+#define CONTROL_BLOCK_SIZE_64 (1 << 6)
+#define CONTROL_BLOCK_SIZE_128 (2 << 6)
+#define CONTROL_BLOCK_SIZE_256 (3 << 6)
+#define CONTROL_BLOCK_SIZE(SIZE) ((ffs(SIZE) - 6) << 6)
+#define CONTROL_ECC_EN (1 << 5)
+#define CONTROL_INT_EN (1 << 4)
+#define CONTROL_ECC_BLOCK_SIZE_256 (0 << 1)
+#define CONTROL_ECC_BLOCK_SIZE_512 (1 << 1)
+#define CONTROL_ECC_BLOCK_SIZE_1024 (2 << 1)
+#define CONTROL_ECC_BLOCK_SIZE(SIZE) ((ffs(SIZE) - 9) << 1)
+#define STATUS_REG 0x08
+#define STATUS_MEM_ST(DEVICE) (1 << (DEVICE))
+#define STATUS_MEM0_ST (1 << 0)
+#define STATUS_MEM1_ST (2 << 0)
+#define STATUS_CTRL_STAT (1 << 8)
+#define STATUS_MASK_REG 0x0C
+#define STATE_MASK_SHIFT 0
+#define STATUS_MASK_STATE_MASK(MASK) (((MASK) & 0xff) << STATE_MASK_SHIFT)
+#define ERROR_MASK_SHIFT 8
+#define STATUS_MASK_ERROR_MASK(MASK) (((MASK) & 0xff) << ERROR_MASK_SHIFT)
+#define INT_MASK_REG 0x10
+#define INT_MASK_ECC_INT0_EN (1 << 24)
+#define INT_MASK_STAT_ERR_INT0_EN (1 << 16)
+#define INT_MASK_MEM0_RDY_INT_EN (1 << 8)
+#define INT_MASK_DMA_INT_EN (1 << 3)
+#define INT_MASK_DATA_REG_EN (1 << 2)
+#define INT_MASK_CMD_END_INT_EN (1 << 1)
+#define INT_STATUS_REG 0x14
+#define INT_STATUS_ECC_INT0_FL (1 << 24)
+#define INT_STATUS_STAT_ERR_INT0_FL (1 << 16)
+#define INT_STATUS_MEM0_RDY_INT_FL (1 << 8)
+#define INT_STATUS_DMA_INT_FL (1 << 3)
+#define INT_STATUS_DATA_REG_FL (1 << 2)
+#define INT_STATUS_CMD_END_INT_FL (1 << 1)
+#define ECC_CTRL_REG 0x18
+#define ECC_CTRL_ECC_CAP_2 (0 << 0)
+#define ECC_CTRL_ECC_CAP_4 (1 << 0)
+#define ECC_CTRL_ECC_CAP_8 (2 << 0)
+#define ECC_CTRL_ECC_CAP_16 (3 << 0)
+#define ECC_CTRL_ECC_CAP_24 (4 << 0)
+#define ECC_CTRL_ECC_CAP_32 (5 << 0)
+#define ECC_CTRL_ECC_CAP(B) ((B) < 24 ? ffs(B) - 2 : (B) / 6)
+/* # ECC corrections that are acceptable during read before setting OVER flag */
+#define ECC_CTRL_ECC_THRESHOLD(VAL) (((VAL) & 0x3f) << 8)
+#define ECC_OFFSET_REG 0x1C
+#define ECC_STAT_REG 0x20
+/* Correctable error flag(s) */
+#define ECC_STAT_ERROR_0 (1 << 0)
+/* Uncorrectable error flag(s) */
+#define ECC_STAT_UNC_0 (1 << 8)
+/* Acceptable errors level overflow flag(s) */
+#define ECC_STAT_OVER_0 (1 << 16)
+#define ADDR0_COL_REG 0x24
+#define ADDR0_ROW_REG 0x28
+#define ADDR1_COL_REG 0x2C
+#define ADDR1_ROW_REG 0x30
+#define PROTECT_REG 0x34
+#define FIFO_DATA_REG 0x38
+#define DATA_REG_REG 0x3C
+#define DATA_REG_SIZE_REG 0x40
+#define DATA_REG_SIZE_DATA_REG_SIZE(SIZE) (((SIZE) - 1) & 3)
+#define DEV0_PTR_REG 0x44
+#define DEV1_PTR_REG 0x48
+#define DEV2_PTR_REG 0x4C
+#define DEV3_PTR_REG 0x50
+#define DEV4_PTR_REG 0x54
+#define DEV5_PTR_REG 0x58
+#define DEV6_PTR_REG 0x5C
+#define DEV7_PTR_REG 0x60
+#define DMA_ADDR_L_REG 0x64
+#define DMA_ADDR_H_REG 0x68
+#define DMA_CNT_REG 0x6C
+#define DMA_CTRL_REG 0x70
+#define DMA_CTRL_DMA_START (1 << 7) /* start on command */
+#define DMA_CTRL_DMA_MODE_SG (1 << 5) /* scatter/gather mode */
+#define DMA_CTRL_DMA_BURST_I_P_4 (0 << 2) /* incr. precise burst */
+#define DMA_CTRL_DMA_BURST_S_P_16 (1 << 2) /* stream precise burst */
+#define DMA_CTRL_DMA_BURST_SINGLE (2 << 2) /* single transfer */
+#define DMA_CTRL_DMA_BURST_UNSPEC (3 << 2) /* burst of unspec. length */
+#define DMA_CTRL_DMA_BURST_I_P_8 (4 << 2) /* incr. precise burst */
+#define DMA_CTRL_DMA_BURST_I_P_16 (5 << 2) /* incr. precise burst */
+#define DMA_CTRL_ERR_FLAG (1 << 1) /* read only */
+#define DMA_CTRL_DMA_READY (1 << 0) /* read only */
+#define BBM_CTRL_REG 0x74
+#define MEM_CTRL_REG 0x80
+#define MEM_CTRL_MEM_CE(CE) (((CE) & 7) << 0)
+#define MEM_CTRL_BANK_SEL(BANK) (((BANK) & 7) << 16)
+#define DATA_SIZE_REG 0x84
+#define TIMINGS_ASYN_REG 0x88
+#define TIMINGS_SYN_REG 0x8C
+#define TIME_SEQ_0_REG 0x90
+#define TIME_SEQ_1_REG 0x94
+#define TIME_GEN_SEQ_0_REG 0x98
+#define TIME_GEN_SEQ_1_REG 0x9C
+#define TIME_GEN_SEQ_2_REG 0xA0
+#define FIFO_INIT_REG 0xB0
+#define FIFO_INIT_FIFO_INIT 1 /* Flush FIFO */
+#define FIFO_STATE_REG 0xB4
+#define FIFO_STATE_DF_W_EMPTY (1 << 7)
+#define FIFO_STATE_DF_R_FULL (1 << 6)
+#define FIFO_STATE_CF_ACCPT_W (1 << 5)
+#define FIFO_STATE_CF_ACCPT_R (1 << 4)
+#define FIFO_STATE_CF_FULL (1 << 3)
+#define FIFO_STATE_CF_EMPTY (1 << 2)
+#define FIFO_STATE_DF_W_FULL (1 << 1)
+#define FIFO_STATE_DF_R_EMPTY (1 << 0)
+#define GEN_SEQ_CTRL_REG 0xB8 /* aka GENERIC_SEQ_CTRL */
+#define _CMD0_EN_SHIFT 0
+#define _CMD1_EN_SHIFT 1
+#define _CMD2_EN_SHIFT 2
+#define _CMD3_EN_SHIFT 3
+#define _COL_A0_SHIFT 4
+#define _COL_A1_SHIFT 6
+#define _ROW_A0_SHIFT 8
+#define _ROW_A1_SHIFT 10
+#define _DATA_EN_SHIFT 12
+#define _DELAY_EN_SHIFT 13
+#define _IMD_SEQ_SHIFT 15
+#define _CMD3_SHIFT 16
+#define ECC_CNT_REG 0x14C
+#define ECC_CNT_ERR_LVL_MASK 0x3F
+
+#define _CMD0_EN_MASK 1
+#define _CMD1_EN_MASK 1
+#define _CMD2_EN_MASK 1
+#define _CMD3_EN_MASK 1
+#define _COL_A0_MASK 3
+#define _COL_A1_MASK 3
+#define _ROW_A0_MASK 3
+#define _ROW_A1_MASK 3
+#define _DATA_EN_MASK 1
+#define _DELAY_EN_MASK 3
+#define _IMD_SEQ_MASK 1
+#define _CMD3_MASK 0xff
+
+/* DELAY_EN field values, non-shifted */
+#define _BUSY_NONE 0
+#define _BUSY_0 1
+#define _BUSY_1 2
+
+/* Slightly confusingly, the DELAYx_EN fields enable BUSY phases. */
+#define MAKE_GEN_CMD(CMD0_EN, CMD1_EN, CMD2_EN, CMD3_EN, \
+ COL_A0, ROW_A0, COL_A1, ROW_A1, \
+ DATA_EN, BUSY_EN, IMMEDIATE_SEQ, CMD3) \
+ ((((CMD0_EN) & _CMD0_EN_MASK) << _CMD0_EN_SHIFT) | \
+ (((CMD1_EN) & _CMD1_EN_MASK) << _CMD1_EN_SHIFT) | \
+ (((CMD2_EN) & _CMD2_EN_MASK) << _CMD2_EN_SHIFT) | \
+ (((CMD3_EN) & _CMD3_EN_MASK) << _CMD3_EN_SHIFT) | \
+ (((COL_A0) & _COL_A0_MASK) << _COL_A0_SHIFT) | \
+ (((COL_A1) & _COL_A1_MASK) << _COL_A1_SHIFT) | \
+ (((ROW_A0) & _ROW_A0_MASK) << _ROW_A0_SHIFT) | \
+ (((ROW_A1) & _ROW_A1_MASK) << _ROW_A1_SHIFT) | \
+ (((DATA_EN) & _DATA_EN_MASK) << _DATA_EN_SHIFT) | \
+ (((BUSY_EN) & _DELAY_EN_MASK) << _DELAY_EN_SHIFT) | \
+ (((IMMEDIATE_SEQ) & _IMD_SEQ_MASK) << _IMD_SEQ_SHIFT) | \
+ (((CMD3) & _CMD3_MASK) << _CMD3_SHIFT))
+
+/* The sequence encodings are not trivial. The ones we use are listed here. */
+#define _SEQ_0 0x00 /* send one cmd, then wait for ready */
+#define _SEQ_1 0x21 /* send one cmd, one addr, fetch data */
+#define _SEQ_4 0x24 /* single cycle write then read */
+#define _SEQ_10 0x2A /* read page */
+#define _SEQ_12 0x0C /* write page, don't wait for R/B */
+#define _SEQ_18 0x32 /* read page using general cycle */
+#define _SEQ_19 0x13 /* write page using general cycle */
+#define _SEQ_14 0x0E /* 3 address cycles, for block erase */
+
+#define MLUN_REG 0xBC
+#define DEV0_SIZE_REG 0xC0
+#define DEV1_SIZE_REG 0xC4
+#define DEV2_SIZE_REG 0xC8
+#define DEV3_SIZE_REG 0xCC
+#define DEV4_SIZE_REG 0xD0
+#define DEV5_SIZE_REG 0xD4
+#define DEV6_SIZE_REG 0xD8
+#define DEV7_SIZE_REG 0xDC
+#define SS_CCNT0_REG 0xE0
+#define SS_CCNT1_REG 0xE4
+#define SS_SCNT_REG 0xE8
+#define SS_ADDR_DEV_CTRL_REG 0xEC
+#define SS_CMD0_REG 0xF0
+#define SS_CMD1_REG 0xF4
+#define SS_CMD2_REG 0xF8
+#define SS_CMD3_REG 0xFC
+#define SS_ADDR_REG 0x100
+#define SS_MSEL_REG 0x104
+#define SS_REQ_REG 0x108
+#define SS_BRK_REG 0x10C
+#define DMA_TLVL_REG 0x114
+#define DMA_TLVL_MAX 0xFF
+#define AES_CTRL_REG 0x118
+#define AES_DATAW_REG 0x11C
+#define AES_SVECT_REG 0x120
+#define CMD_MARK_REG 0x124
+#define LUN_STATUS_0_REG 0x128
+#define LUN_STATUS_1_REG 0x12C
+#define TIMINGS_TOGGLE_REG 0x130
+#define TIME_GEN_SEQ_3_REG 0x134
+#define SQS_DELAY_REG 0x138
+#define CNE_MASK_REG 0x13C
+#define CNE_VAL_REG 0x140
+#define CNA_CTRL_REG 0x144
+#define INTERNAL_STATUS_REG 0x148
+#define ECC_CNT_REG 0x14C
+#define PARAM_REG_REG 0x150
+
+/* NAND flash command generation */
+
+/* NAND flash command codes */
+#define NAND_RESET 0xff
+#define NAND_READ_STATUS 0x70
+#define NAND_READ_ID 0x90
+#define NAND_READ_ID_ADDR_STD 0x00 /* address written to ADDR0_COL */
+#define NAND_READ_ID_ADDR_ONFI 0x20 /* address written to ADDR0_COL */
+#define NAND_PAGE_READ 0x00
+#define NAND_PAGE_READ_END 0x30
+#define NAND_BLOCK_ERASE 0x60
+#define NAND_BLOCK_ERASE_END 0xd0
+#define NAND_PAGE_WRITE 0x80
+#define NAND_PAGE_WRITE_END 0x10
+
+#define _DONT_CARE 0x00 /* When we don't have anything better to say */
+
+
+/* Assembled values for putting into COMMAND register */
+
+/* Reset NAND flash */
+
+/* Uses SEQ_0: non-directional sequence, single command, wait for ready */
+#define COMMAND_RESET \
+ MAKE_COMMAND(_SEQ_0, INPUT_SEL_SIU, DATA_SEL_FIFO, \
+ NAND_RESET, _DONT_CARE, _DONT_CARE)
+
+/* Read status */
+
+/* Uses SEQ_4: single command, then read data via DATA_REG */
+#define COMMAND_READ_STATUS \
+ MAKE_COMMAND(_SEQ_4, INPUT_SEL_SIU, DATA_SEL_DATA_REG, \
+ NAND_READ_STATUS, _DONT_CARE, _DONT_CARE)
+
+/* Read ID */
+
+/* Uses SEQ_1: single command, ADDR0_COL, then read data via FIFO */
+/* ADDR0_COL is set to NAND_READ_ID_ADDR_STD for non-ONFi, and
+ * NAND_READ_ID_ADDR_ONFI for ONFi.
+ * The controller reads 5 bytes in the non-ONFi case, and 4 bytes in the
+ * ONFi case, so the data reception (DMA or FIFO_REG) needs to be set up
+ * accordingly. */
+#define COMMAND_READ_ID \
+ MAKE_COMMAND(_SEQ_1, INPUT_SEL_DMA, DATA_SEL_FIFO, \
+ NAND_READ_ID, _DONT_CARE, _DONT_CARE)
+
+/* Page read via slave interface (FIFO_DATA register) */
+
+/* Standard 5-cycle read command, with 0x30 end-of-cycle marker */
+/* Uses SEQ_10: CMD0 + 5 address cycles + CMD2, read data */
+#define COMMAND_READ_PAGE_STD \
+ MAKE_COMMAND(_SEQ_10, INPUT_SEL_SIU, DATA_SEL_FIFO, \
+ NAND_PAGE_READ, _DONT_CARE, NAND_PAGE_READ_END)
+
+/* 4-cycle read command, together with GEN_SEQ_CTRL_READ_PAGE_4CYCLE */
+/* Uses SEQ_18 (generic command sequence, see GEN_SEQ_ECTRL_READ_PAGE_4CYCLE)):
+ CMD0 + 2+2 address cycles + CMD2, read data */
+#define COMMAND_READ_PAGE_GEN \
+ MAKE_COMMAND(_SEQ_18, INPUT_SEL_SIU, DATA_SEL_FIFO, \
+ NAND_PAGE_READ, _DONT_CARE, NAND_PAGE_READ_END)
+
+/* Page read via master interface (DMA) */
+
+/* Standard 5-cycle read command, with 0x30 end-of-cycle marker */
+/* Uses SEQ_10: CMD0 + 5 address cycles + CMD2, read data */
+#define COMMAND_READ_PAGE_DMA_STD \
+ MAKE_COMMAND(_SEQ_10, INPUT_SEL_DMA, DATA_SEL_FIFO, \
+ NAND_PAGE_READ, _DONT_CARE, NAND_PAGE_READ_END)
+
+/* 4-cycle read command, together with GEN_SEQ_CTRL_READ_PAGE_4CYCLE */
+/* Uses SEQ_18 (generic command sequence, see GEN_SEQ_ECTRL_READ_PAGE_4CYCLE)):
+ CMD0 + 2+2 address cycles + CMD2, read data */
+#define COMMAND_READ_PAGE_DMA_GEN \
+ MAKE_COMMAND(_SEQ_18, INPUT_SEL_DMA, DATA_SEL_FIFO, \
+ NAND_PAGE_READ, _DONT_CARE, NAND_PAGE_READ_END)
+
+/* Page write via master interface (DMA) */
+
+/* Uses SEQ_12: CMD0 + 5 address cycles + write data + CMD1 */
+#define COMMAND_WRITE_PAGE_DMA_STD \
+ MAKE_COMMAND(_SEQ_12, INPUT_SEL_DMA, DATA_SEL_FIFO, \
+ NAND_PAGE_WRITE, NAND_PAGE_WRITE_END, _DONT_CARE)
+
+/* Uses SEQ_19: CMD0 + 4 address cycles + write data + CMD1 */
+#define COMMAND_WRITE_PAGE_DMA_GEN \
+ MAKE_COMMAND(_SEQ_19, INPUT_SEL_DMA, DATA_SEL_FIFO, \
+ NAND_PAGE_WRITE, NAND_PAGE_WRITE_END, _DONT_CARE)
+
+/* Block erase */
+
+/* Uses SEQ_14: CMD0 + 3 address cycles + CMD1 */
+#define COMMAND_BLOCK_ERASE \
+ MAKE_COMMAND(_SEQ_14, INPUT_SEL_SIU, DATA_SEL_FIFO, \
+ NAND_BLOCK_ERASE, NAND_BLOCK_ERASE_END, _DONT_CARE)
+
+/* Assembled values for putting into GEN_SEQ_CTRL register */
+
+/* General command sequence specification for 4 cycle PAGE_READ command */
+#define GEN_SEQ_CTRL_READ_PAGE_4CYCLE \
+ MAKE_GEN_CMD(1, 0, 1, 0, /* enable command 0 and 2 phases */ \
+ 2, 2, /* col A0 2 cycles, row A0 2 cycles */ \
+ 0, 0, /* col A1, row A1 not used */ \
+ 1, /* data phase enabled */ \
+ _BUSY_0, /* busy0 phase enabled */ \
+ 0, /* immediate cmd execution disabled */ \
+ _DONT_CARE) /* command 3 code not needed */
+
+/* General command sequence specification for 4 cycle PAGE_PROGRAM command */
+#define GEN_SEQ_CTRL_WRITE_PAGE_4CYCLE \
+ MAKE_GEN_CMD(1, 1, 0, 0, /* enable command 0 and 1 phases */ \
+ 2, 2, /* col A0 2 cycles, row A0 2 cycles */ \
+ 0, 0, /* col A1, row A1 not used */ \
+ 1, /* data phase enabled */ \
+ _BUSY_1, /* busy1 phase enabled */ \
+ 0, /* immediate cmd execution disabled */ \
+ _DONT_CARE) /* command 3 code not needed */
+
+/* BCH ECC size calculations. Should really go somewhere else? */
+/* From "Mr. NAND's Wild Ride: Warning: Suprises Ahead", by Robert Pierce,
+ * Denali Software Inc. 2009, table on page 5 */
+/* Use 8 bit correction as base. */
+#define ECC8_BYTES(BLKSIZE) (ffs(BLKSIZE) + 3)
+/* The following is valid for 4..24 bits of correction. */
+#define ECC_BYTES(CAP, BLKSIZE) ((ECC8_BYTES(BLKSIZE) * (CAP) + 7) / 8)
+
+#endif /* _EVATRONIX_NAND_H_ */
--
Ricard Wolf Wanderlöf ricardw(at)axis.com
Axis Communications AB, Lund, Sweden www.axis.com
Phone +46 46 272 2016 Fax +46 46 13 61 30
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists