Commit 57e363b8 authored by Brian Norris's avatar Brian Norris

Merge tag 'nand/for-4.12' of github.com:linux-nand/linux into MTD

From Boris:
"""
This pull request contains:

 - some minor fixes/improvements on existing drivers (fsmc, gpio, ifc,
   davinci, brcmnand, omap)
 - a huge cleanup/rework of the denali driver accompanied with core
   fixes/improvements to simplify the driver code
 - a complete rewrite of the atmel driver to support new DT bindings
   make future evolution easier
 - the addition of per-vendor detection/initialization steps to avoid
   extending the nand_ids table with more extended-id entries
"""
parents da4b1caa 9d2ee0a6
Atmel NAND flash
Atmel NAND flash controller bindings
The NAND flash controller node should be defined under the EBI bus (see
Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt).
One or several NAND devices can be defined under this NAND controller.
The NAND controller might be connected to an ECC engine.
* NAND controller bindings:
Required properties:
- compatible: should be one of the following
"atmel,at91rm9200-nand-controller"
"atmel,at91sam9260-nand-controller"
"atmel,at91sam9261-nand-controller"
"atmel,at91sam9g45-nand-controller"
"atmel,sama5d3-nand-controller"
- ranges: empty ranges property to forward EBI ranges definitions.
- #address-cells: should be set to 2.
- #size-cells: should be set to 1.
- atmel,nfc-io: phandle to the NFC IO block. Only required for sama5d3
controllers.
- atmel,nfc-sram: phandle to the NFC SRAM block. Only required for sama5d3
controllers.
Optional properties:
- ecc-engine: phandle to the PMECC block. Only meaningful if the SoC embeds
a PMECC engine.
* NAND device/chip bindings:
Required properties:
- reg: describes the CS lines assigned to the NAND device. If the NAND device
exposes multiple CS lines (multi-dies chips), your reg property will
contain X tuples of 3 entries.
1st entry: the CS line this NAND chip is connected to
2nd entry: the base offset of the memory region assigned to this
device (always 0)
3rd entry: the memory region size (always 0x800000)
Optional properties:
- rb-gpios: the GPIO(s) used to check the Ready/Busy status of the NAND.
- cs-gpios: the GPIO(s) used to control the CS line.
- det-gpios: the GPIO used to detect if a Smartmedia Card is present.
- atmel,rb: an integer identifying the native Ready/Busy pin. Only meaningful
on sama5 SoCs.
All generic properties described in
Documentation/devicetree/bindings/mtd/{common,nand}.txt also apply to the NAND
device node, and NAND partitions should be defined under the NAND node as
described in Documentation/devicetree/bindings/mtd/partition.txt.
* ECC engine (PMECC) bindings:
Required properties:
- compatible: should be one of the following
"atmel,at91sam9g45-pmecc"
"atmel,sama5d4-pmecc"
"atmel,sama5d2-pmecc"
- reg: should contain 2 register ranges. The first one is pointing to the PMECC
block, and the second one to the PMECC_ERRLOC block.
Example:
pmecc: ecc-engine@ffffc070 {
compatible = "atmel,at91sam9g45-pmecc";
reg = <0xffffc070 0x490>,
<0xffffc500 0x100>;
};
ebi: ebi@10000000 {
compatible = "atmel,sama5d3-ebi";
#address-cells = <2>;
#size-cells = <1>;
atmel,smc = <&hsmc>;
reg = <0x10000000 0x10000000
0x40000000 0x30000000>;
ranges = <0x0 0x0 0x10000000 0x10000000
0x1 0x0 0x40000000 0x10000000
0x2 0x0 0x50000000 0x10000000
0x3 0x0 0x60000000 0x10000000>;
clocks = <&mck>;
nand_controller: nand-controller {
compatible = "atmel,sama5d3-nand-controller";
atmel,nfc-sram = <&nfc_sram>;
atmel,nfc-io = <&nfc_io>;
ecc-engine = <&pmecc>;
#address-cells = <2>;
#size-cells = <1>;
ranges;
nand@3 {
reg = <0x3 0x0 0x800000>;
atmel,rb = <0>;
/*
* Put generic NAND/MTD properties and
* subnodes here.
*/
};
};
};
-----------------------------------------------------------------------
Deprecated bindings (should not be used in new device trees):
Required properties:
- compatible: The possible values are:
......
* Denali NAND controller
Required properties:
- compatible : should be "denali,denali-nand-dt"
- compatible : should be one of the following:
"altr,socfpga-denali-nand" - for Altera SOCFPGA
- reg : should contain registers location and length for data and reg.
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
- dm-mask : DMA bit mask
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
......@@ -15,9 +15,8 @@ Examples:
nand: nand@ff900000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "denali,denali-nand-dt";
compatible = "altr,socfpga-denali-nand";
reg = <0xff900000 0x100000>, <0xffb80000 0x10000>;
reg-names = "nand_data", "denali_reg";
interrupts = <0 144 4>;
dma-mask = <0xffffffff>;
};
......@@ -2244,7 +2244,7 @@ M: Wenyou Yang <wenyou.yang@atmel.com>
M: Josh Wu <rainyfeeling@outlook.com>
L: linux-mtd@lists.infradead.org
S: Supported
F: drivers/mtd/nand/atmel_nand*
F: drivers/mtd/nand/atmel/*
ATMEL SDMMC DRIVER
M: Ludovic Desroches <ludovic.desroches@microchip.com>
......
......@@ -136,7 +136,6 @@ config ETRAX_NANDFLASH
bool "NAND flash support"
depends on ETRAX_ARCH_V32
select MTD_NAND
select MTD_NAND_IDS
help
This option enables MTD mapping of NAND flash devices. Needed to use
NAND flash memories. If unsure, say Y.
......
......@@ -115,7 +115,7 @@ config FSL_CORENET_CF
config FSL_IFC
bool
depends on FSL_SOC || ARCH_LAYERSCAPE
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
config JZ4780_NEMC
bool "Ingenic JZ4780 SoC NEMC driver"
......
......@@ -13,7 +13,6 @@ config MTD_NAND_ECC_SMC
menuconfig MTD_NAND
tristate "NAND Device Support"
depends on MTD
select MTD_NAND_IDS
select MTD_NAND_ECC
help
This enables support for accessing all type of NAND flash
......@@ -60,17 +59,6 @@ config MTD_NAND_DENALI_DT
Enable the driver for NAND flash on platforms using a Denali NAND
controller as a DT device.
config MTD_NAND_DENALI_SCRATCH_REG_ADDR
hex "Denali NAND size scratch register address"
default "0xFF108018"
depends on MTD_NAND_DENALI_PCI
help
Some platforms place the NAND chip size in a scratch register
because (some versions of) the driver aren't able to automatically
determine the size of certain chips. Set the address of the
scratch register here to enable this feature. On Intel Moorestown
boards, the scratch register is at 0xFF108018.
config MTD_NAND_GPIO
tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB || COMPILE_TEST
......@@ -109,9 +97,6 @@ config MTD_NAND_OMAP_BCH
config MTD_NAND_OMAP_BCH_BUILD
def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
config MTD_NAND_IDS
tristate
config MTD_NAND_RICOH
tristate "Ricoh xD card reader"
default n
......@@ -321,11 +306,11 @@ config MTD_NAND_CS553X
If you say "m", the module will be called cs553x_nand.
config MTD_NAND_ATMEL
tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32"
depends on ARCH_AT91 || AVR32
tristate "Support for NAND Flash / SmartMedia on AT91"
depends on ARCH_AT91
help
Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 and AVR32 processors.
on Atmel AT91 processors.
config MTD_NAND_PXA3xx
tristate "NAND support on PXA3xx and Armada 370/XP"
......@@ -443,7 +428,7 @@ config MTD_NAND_FSL_ELBC
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on FSL_SOC || ARCH_LAYERSCAPE
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A
select FSL_IFC
select MEMORY
help
......
......@@ -5,7 +5,6 @@
obj-$(CONFIG_MTD_NAND) += nand.o
obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
......@@ -25,7 +24,7 @@ obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel/
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
omap2_nand-objs := omap2.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o
......@@ -61,4 +60,10 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_nand.o mtk_ecc.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_amd.o
nand-objs += nand_hynix.o
nand-objs += nand_macronix.o
nand-objs += nand_micron.o
nand-objs += nand_samsung.o
nand-objs += nand_toshiba.o
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel-nand-controller.o atmel-pmecc.o
atmel-nand-controller-objs := nand-controller.o
atmel-pmecc-objs := pmecc.o
/*
* Copyright 2017 ATMEL
* Copyright 2017 Free Electrons
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* Derived from the atmel_nand.c driver which contained the following
* copyrights:
*
* Copyright 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
* Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
* Copyright 2000 Steven J. Hill (sjhill@cotw.com)
*
*
* Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
* Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
*
* Derived from Das U-Boot source code
* (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
* Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
*
* Add Programmable Multibit ECC support for various AT91 SoC
* Copyright 2012 ATMEL, Hong Xu
*
* Add Nand Flash Controller support for SAMA5 SoC
* Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* A few words about the naming convention in this file. This convention
* applies to structure and function names.
*
* Prefixes:
*
* - atmel_nand_: all generic structures/functions
* - atmel_smc_nand_: all structures/functions specific to the SMC interface
* (at91sam9 and avr32 SoCs)
* - atmel_hsmc_nand_: all structures/functions specific to the HSMC interface
* (sama5 SoCs and later)
* - atmel_nfc_: all structures/functions used to manipulate the NFC sub-block
* that is available in the HSMC block
* - <soc>_nand_: all SoC specific structures/functions
*/
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/genalloc.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/atmel-matrix.h>
#include <linux/module.h>
#include <linux/mtd/nand.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/iopoll.h>
#include <linux/platform_device.h>
#include <linux/platform_data/atmel.h>
#include <linux/regmap.h>
#include "pmecc.h"
#define ATMEL_HSMC_NFC_CFG 0x0
#define ATMEL_HSMC_NFC_CFG_SPARESIZE(x) (((x) / 4) << 24)
#define ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK GENMASK(30, 24)
#define ATMEL_HSMC_NFC_CFG_DTO(cyc, mul) (((cyc) << 16) | ((mul) << 20))
#define ATMEL_HSMC_NFC_CFG_DTO_MAX GENMASK(22, 16)
#define ATMEL_HSMC_NFC_CFG_RBEDGE BIT(13)
#define ATMEL_HSMC_NFC_CFG_FALLING_EDGE BIT(12)
#define ATMEL_HSMC_NFC_CFG_RSPARE BIT(9)
#define ATMEL_HSMC_NFC_CFG_WSPARE BIT(8)
#define ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK GENMASK(2, 0)
#define ATMEL_HSMC_NFC_CFG_PAGESIZE(x) (fls((x) / 512) - 1)
#define ATMEL_HSMC_NFC_CTRL 0x4
#define ATMEL_HSMC_NFC_CTRL_EN BIT(0)
#define ATMEL_HSMC_NFC_CTRL_DIS BIT(1)
#define ATMEL_HSMC_NFC_SR 0x8
#define ATMEL_HSMC_NFC_IER 0xc
#define ATMEL_HSMC_NFC_IDR 0x10
#define ATMEL_HSMC_NFC_IMR 0x14
#define ATMEL_HSMC_NFC_SR_ENABLED BIT(1)
#define ATMEL_HSMC_NFC_SR_RB_RISE BIT(4)
#define ATMEL_HSMC_NFC_SR_RB_FALL BIT(5)
#define ATMEL_HSMC_NFC_SR_BUSY BIT(8)
#define ATMEL_HSMC_NFC_SR_WR BIT(11)
#define ATMEL_HSMC_NFC_SR_CSID GENMASK(14, 12)
#define ATMEL_HSMC_NFC_SR_XFRDONE BIT(16)
#define ATMEL_HSMC_NFC_SR_CMDDONE BIT(17)
#define ATMEL_HSMC_NFC_SR_DTOE BIT(20)
#define ATMEL_HSMC_NFC_SR_UNDEF BIT(21)
#define ATMEL_HSMC_NFC_SR_AWB BIT(22)
#define ATMEL_HSMC_NFC_SR_NFCASE BIT(23)
#define ATMEL_HSMC_NFC_SR_ERRORS (ATMEL_HSMC_NFC_SR_DTOE | \
ATMEL_HSMC_NFC_SR_UNDEF | \
ATMEL_HSMC_NFC_SR_AWB | \
ATMEL_HSMC_NFC_SR_NFCASE)
#define ATMEL_HSMC_NFC_SR_RBEDGE(x) BIT((x) + 24)
#define ATMEL_HSMC_NFC_ADDR 0x18
#define ATMEL_HSMC_NFC_BANK 0x1c
#define ATMEL_NFC_MAX_RB_ID 7
#define ATMEL_NFC_SRAM_SIZE 0x2400
#define ATMEL_NFC_CMD(pos, cmd) ((cmd) << (((pos) * 8) + 2))
#define ATMEL_NFC_VCMD2 BIT(18)
#define ATMEL_NFC_ACYCLE(naddrs) ((naddrs) << 19)
#define ATMEL_NFC_CSID(cs) ((cs) << 22)
#define ATMEL_NFC_DATAEN BIT(25)
#define ATMEL_NFC_NFCWR BIT(26)
#define ATMEL_NFC_MAX_ADDR_CYCLES 5
#define ATMEL_NAND_ALE_OFFSET BIT(21)
#define ATMEL_NAND_CLE_OFFSET BIT(22)
#define DEFAULT_TIMEOUT_MS 1000
#define MIN_DMA_LEN 128
enum atmel_nand_rb_type {
ATMEL_NAND_NO_RB,
ATMEL_NAND_NATIVE_RB,
ATMEL_NAND_GPIO_RB,
};
struct atmel_nand_rb {
enum atmel_nand_rb_type type;
union {
struct gpio_desc *gpio;
int id;
};
};
struct atmel_nand_cs {
int id;
struct atmel_nand_rb rb;
struct gpio_desc *csgpio;
struct {
void __iomem *virt;
dma_addr_t dma;
} io;
};
struct atmel_nand {
struct list_head node;
struct device *dev;
struct nand_chip base;
struct atmel_nand_cs *activecs;
struct atmel_pmecc_user *pmecc;
struct gpio_desc *cdgpio;
int numcs;
struct atmel_nand_cs cs[];
};
static inline struct atmel_nand *to_atmel_nand(struct nand_chip *chip)
{
return container_of(chip, struct atmel_nand, base);
}
enum atmel_nfc_data_xfer {
ATMEL_NFC_NO_DATA,
ATMEL_NFC_READ_DATA,
ATMEL_NFC_WRITE_DATA,
};
struct atmel_nfc_op {
u8 cs;
u8 ncmds;
u8 cmds[2];
u8 naddrs;
u8 addrs[5];
enum atmel_nfc_data_xfer data;
u32 wait;
u32 errors;
};
struct atmel_nand_controller;
struct atmel_nand_controller_caps;
struct atmel_nand_controller_ops {
int (*probe)(struct platform_device *pdev,
const struct atmel_nand_controller_caps *caps);
int (*remove)(struct atmel_nand_controller *nc);
void (*nand_init)(struct atmel_nand_controller *nc,
struct atmel_nand *nand);
int (*ecc_init)(struct atmel_nand *nand);
};
struct atmel_nand_controller_caps {
bool has_dma;
bool legacy_of_bindings;
u32 ale_offs;
u32 cle_offs;
const struct atmel_nand_controller_ops *ops;
};
struct atmel_nand_controller {
struct nand_hw_control base;
const struct atmel_nand_controller_caps *caps;
struct device *dev;
struct regmap *smc;
struct dma_chan *dmac;
struct atmel_pmecc *pmecc;
struct list_head chips;
struct clk *mck;
};
static inline struct atmel_nand_controller *
to_nand_controller(struct nand_hw_control *ctl)
{
return container_of(ctl, struct atmel_nand_controller, base);
}
struct atmel_smc_nand_controller {
struct atmel_nand_controller base;
struct regmap *matrix;
unsigned int ebi_csa_offs;
};
static inline struct atmel_smc_nand_controller *
to_smc_nand_controller(struct nand_hw_control *ctl)
{
return container_of(to_nand_controller(ctl),
struct atmel_smc_nand_controller, base);
}
struct atmel_hsmc_nand_controller {
struct atmel_nand_controller base;
struct {
struct gen_pool *pool;
void __iomem *virt;
dma_addr_t dma;
} sram;
struct regmap *io;
struct atmel_nfc_op op;
struct completion complete;
int irq;
/* Only used when instantiating from legacy DT bindings. */
struct clk *clk;
};
static inline struct atmel_hsmc_nand_controller *
to_hsmc_nand_controller(struct nand_hw_control *ctl)
{
return container_of(to_nand_controller(ctl),
struct atmel_hsmc_nand_controller, base);
}
static bool atmel_nfc_op_done(struct atmel_nfc_op *op, u32 status)
{
op->errors |= status & ATMEL_HSMC_NFC_SR_ERRORS;
op->wait ^= status & op->wait;
return !op->wait || op->errors;
}
static irqreturn_t atmel_nfc_interrupt(int irq, void *data)
{
struct atmel_hsmc_nand_controller *nc = data;
u32 sr, rcvd;
bool done;
regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &sr);
rcvd = sr & (nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
done = atmel_nfc_op_done(&nc->op, sr);
if (rcvd)
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, rcvd);
if (done)
complete(&nc->complete);
return rcvd ? IRQ_HANDLED : IRQ_NONE;
}
static int atmel_nfc_wait(struct atmel_hsmc_nand_controller *nc, bool poll,
unsigned int timeout_ms)
{
int ret;
if (!timeout_ms)
timeout_ms = DEFAULT_TIMEOUT_MS;
if (poll) {
u32 status;
ret = regmap_read_poll_timeout(nc->base.smc,
ATMEL_HSMC_NFC_SR, status,
atmel_nfc_op_done(&nc->op,
status),
0, timeout_ms * 1000);
} else {
init_completion(&nc->complete);
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IER,
nc->op.wait | ATMEL_HSMC_NFC_SR_ERRORS);
ret = wait_for_completion_timeout(&nc->complete,
msecs_to_jiffies(timeout_ms));
if (!ret)
ret = -ETIMEDOUT;
else
ret = 0;
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
}
if (nc->op.errors & ATMEL_HSMC_NFC_SR_DTOE) {
dev_err(nc->base.dev, "Waiting NAND R/B Timeout\n");
ret = -ETIMEDOUT;
}
if (nc->op.errors & ATMEL_HSMC_NFC_SR_UNDEF) {
dev_err(nc->base.dev, "Access to an undefined area\n");
ret = -EIO;
}
if (nc->op.errors & ATMEL_HSMC_NFC_SR_AWB) {
dev_err(nc->base.dev, "Access while busy\n");
ret = -EIO;
}
if (nc->op.errors & ATMEL_HSMC_NFC_SR_NFCASE) {
dev_err(nc->base.dev, "Wrong access size\n");
ret = -EIO;
}
return ret;
}
static void atmel_nand_dma_transfer_finished(void *data)
{
struct completion *finished = data;
complete(finished);
}
static int atmel_nand_dma_transfer(struct atmel_nand_controller *nc,
void *buf, dma_addr_t dev_dma, size_t len,
enum dma_data_direction dir)
{
DECLARE_COMPLETION_ONSTACK(finished);
dma_addr_t src_dma, dst_dma, buf_dma;
struct dma_async_tx_descriptor *tx;
dma_cookie_t cookie;
buf_dma = dma_map_single(nc->dev, buf, len, dir);
if (dma_mapping_error(nc->dev, dev_dma)) {
dev_err(nc->dev,
"Failed to prepare a buffer for DMA access\n");
goto err;
}
if (dir == DMA_FROM_DEVICE) {
src_dma = dev_dma;
dst_dma = buf_dma;
} else {
src_dma = buf_dma;
dst_dma = dev_dma;
}
tx = dmaengine_prep_dma_memcpy(nc->dmac, dst_dma, src_dma, len,
DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
if (!tx) {
dev_err(nc->dev, "Failed to prepare DMA memcpy\n");
goto err_unmap;
}
tx->callback = atmel_nand_dma_transfer_finished;
tx->callback_param = &finished;
cookie = dmaengine_submit(tx);
if (dma_submit_error(cookie)) {
dev_err(nc->dev, "Failed to do DMA tx_submit\n");
goto err_unmap;
}
dma_async_issue_pending(nc->dmac);
wait_for_completion(&finished);
return 0;
err_unmap:
dma_unmap_single(nc->dev, buf_dma, len, dir);
err:
dev_dbg(nc->dev, "Fall back to CPU I/O\n");
return -EIO;
}
static u8 atmel_nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
return ioread8(nand->activecs->io.virt);
}
static u16 atmel_nand_read_word(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
return ioread16(nand->activecs->io.virt);
}
static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
if (chip->options & NAND_BUSWIDTH_16)
iowrite16(byte | (byte << 8), nand->activecs->io.virt);
else
iowrite8(byte, nand->activecs->io.virt);
}
static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
nc = to_nand_controller(chip->controller);
/*
* If the controller supports DMA, the buffer address is DMA-able and
* len is long enough to make DMA transfers profitable, let's trigger
* a DMA transfer. If it fails, fallback to PIO mode.
*/
if (nc->dmac && virt_addr_valid(buf) &&
len >= MIN_DMA_LEN &&
!atmel_nand_dma_transfer(nc, buf, nand->activecs->io.dma, len,
DMA_FROM_DEVICE))
return;
if (chip->options & NAND_BUSWIDTH_16)
ioread16_rep(nand->activecs->io.virt, buf, len / 2);
else
ioread8_rep(nand->activecs->io.virt, buf, len);
}
static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
nc = to_nand_controller(chip->controller);
/*
* If the controller supports DMA, the buffer address is DMA-able and
* len is long enough to make DMA transfers profitable, let's trigger
* a DMA transfer. If it fails, fallback to PIO mode.
*/
if (nc->dmac && virt_addr_valid(buf) &&
len >= MIN_DMA_LEN &&
!atmel_nand_dma_transfer(nc, (void *)buf, nand->activecs->io.dma,
len, DMA_TO_DEVICE))
return;
if (chip->options & NAND_BUSWIDTH_16)
iowrite16_rep(nand->activecs->io.virt, buf, len / 2);
else
iowrite8_rep(nand->activecs->io.virt, buf, len);
}
static int atmel_nand_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
return gpiod_get_value(nand->activecs->rb.gpio);
}
static void atmel_nand_select_chip(struct mtd_info *mtd, int cs)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
if (cs < 0 || cs >= nand->numcs) {
nand->activecs = NULL;
chip->dev_ready = NULL;
return;
}
nand->activecs = &nand->cs[cs];
if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
chip->dev_ready = atmel_nand_dev_ready;
}
static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
u32 status;
nc = to_hsmc_nand_controller(chip->controller);
regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &status);
return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
}
static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
nc = to_hsmc_nand_controller(chip->controller);
atmel_nand_select_chip(mtd, cs);
if (!nand->activecs) {
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
ATMEL_HSMC_NFC_CTRL_DIS);
return;
}
if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
chip->dev_ready = atmel_hsmc_nand_dev_ready;
regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK |
ATMEL_HSMC_NFC_CFG_RSPARE |
ATMEL_HSMC_NFC_CFG_WSPARE,
ATMEL_HSMC_NFC_CFG_PAGESIZE(mtd->writesize) |
ATMEL_HSMC_NFC_CFG_SPARESIZE(mtd->oobsize) |
ATMEL_HSMC_NFC_CFG_RSPARE);
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
ATMEL_HSMC_NFC_CTRL_EN);
}
static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
{
u8 *addrs = nc->op.addrs;
unsigned int op = 0;
u32 addr, val;
int i, ret;
nc->op.wait = ATMEL_HSMC_NFC_SR_CMDDONE;
for (i = 0; i < nc->op.ncmds; i++)
op |= ATMEL_NFC_CMD(i, nc->op.cmds[i]);
if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_ADDR, *addrs++);
op |= ATMEL_NFC_CSID(nc->op.cs) |
ATMEL_NFC_ACYCLE(nc->op.naddrs);
if (nc->op.ncmds > 1)
op |= ATMEL_NFC_VCMD2;
addr = addrs[0] | (addrs[1] << 8) | (addrs[2] << 16) |
(addrs[3] << 24);
if (nc->op.data != ATMEL_NFC_NO_DATA) {
op |= ATMEL_NFC_DATAEN;
nc->op.wait |= ATMEL_HSMC_NFC_SR_XFRDONE;
if (nc->op.data == ATMEL_NFC_WRITE_DATA)
op |= ATMEL_NFC_NFCWR;
}
/* Clear all flags. */
regmap_read(nc->base.smc, ATMEL_HSMC_NFC_SR, &val);
/* Send the command. */
regmap_write(nc->io, op, addr);
ret = atmel_nfc_wait(nc, poll, 0);
if (ret)
dev_err(nc->base.dev,
"Failed to send NAND command (err = %d)!",
ret);
/* Reset the op state. */
memset(&nc->op, 0, sizeof(nc->op));
return ret;
}
static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
unsigned int ctrl)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
nc = to_hsmc_nand_controller(chip->controller);
if (ctrl & NAND_ALE) {
if (nc->op.naddrs == ATMEL_NFC_MAX_ADDR_CYCLES)
return;
nc->op.addrs[nc->op.naddrs++] = dat;
} else if (ctrl & NAND_CLE) {
if (nc->op.ncmds > 1)
return;
nc->op.cmds[nc->op.ncmds++] = dat;
}
if (dat == NAND_CMD_NONE) {
nc->op.cs = nand->activecs->id;
atmel_nfc_exec_op(nc, true);
}
}
static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
nc = to_nand_controller(chip->controller);
if ((ctrl & NAND_CTRL_CHANGE) && nand->activecs->csgpio) {
if (ctrl & NAND_NCE)
gpiod_set_value(nand->activecs->csgpio, 0);
else
gpiod_set_value(nand->activecs->csgpio, 1);
}
if (ctrl & NAND_ALE)
writeb(cmd, nand->activecs->io.virt + nc->caps->ale_offs);
else if (ctrl & NAND_CLE)
writeb(cmd, nand->activecs->io.virt + nc->caps->cle_offs);
}
static void atmel_nfc_copy_to_sram(struct nand_chip *chip, const u8 *buf,
bool oob_required)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_hsmc_nand_controller *nc;
int ret = -EIO;
nc = to_hsmc_nand_controller(chip->controller);
if (nc->base.dmac)
ret = atmel_nand_dma_transfer(&nc->base, (void *)buf,
nc->sram.dma, mtd->writesize,
DMA_TO_DEVICE);
/* Falling back to CPU copy. */
if (ret)
memcpy_toio(nc->sram.virt, buf, mtd->writesize);
if (oob_required)
memcpy_toio(nc->sram.virt + mtd->writesize, chip->oob_poi,
mtd->oobsize);
}
static void atmel_nfc_copy_from_sram(struct nand_chip *chip, u8 *buf,
bool oob_required)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_hsmc_nand_controller *nc;
int ret = -EIO;
nc = to_hsmc_nand_controller(chip->controller);
if (nc->base.dmac)
ret = atmel_nand_dma_transfer(&nc->base, buf, nc->sram.dma,
mtd->writesize, DMA_FROM_DEVICE);
/* Falling back to CPU copy. */
if (ret)
memcpy_fromio(buf, nc->sram.virt, mtd->writesize);
if (oob_required)
memcpy_fromio(chip->oob_poi, nc->sram.virt + mtd->writesize,
mtd->oobsize);
}
static void atmel_nfc_set_op_addr(struct nand_chip *chip, int page, int column)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_hsmc_nand_controller *nc;
nc = to_hsmc_nand_controller(chip->controller);
if (column >= 0) {
nc->op.addrs[nc->op.naddrs++] = column;
/*
* 2 address cycles for the column offset on large page NANDs.
*/
if (mtd->writesize > 512)
nc->op.addrs[nc->op.naddrs++] = column >> 8;
}
if (page >= 0) {
nc->op.addrs[nc->op.naddrs++] = page;
nc->op.addrs[nc->op.naddrs++] = page >> 8;
if ((mtd->writesize > 512 && chip->chipsize > SZ_128M) ||
(mtd->writesize <= 512 && chip->chipsize > SZ_32M))
nc->op.addrs[nc->op.naddrs++] = page >> 16;
}
}
static int atmel_nand_pmecc_enable(struct nand_chip *chip, int op, bool raw)
{
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
int ret;
nc = to_nand_controller(chip->controller);
if (raw)
return 0;
ret = atmel_pmecc_enable(nand->pmecc, op);
if (ret)
dev_err(nc->dev,
"Failed to enable ECC engine (err = %d)\n", ret);
return ret;
}
static void atmel_nand_pmecc_disable(struct nand_chip *chip, bool raw)
{
struct atmel_nand *nand = to_atmel_nand(chip);
if (!raw)
atmel_pmecc_disable(nand->pmecc);
}
static int atmel_nand_pmecc_generate_eccbytes(struct nand_chip *chip, bool raw)
{
struct atmel_nand *nand = to_atmel_nand(chip);
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand_controller *nc;
struct mtd_oob_region oobregion;
void *eccbuf;
int ret, i;
nc = to_nand_controller(chip->controller);
if (raw)
return 0;
ret = atmel_pmecc_wait_rdy(nand->pmecc);
if (ret) {
dev_err(nc->dev,
"Failed to transfer NAND page data (err = %d)\n",
ret);
return ret;
}
mtd_ooblayout_ecc(mtd, 0, &oobregion);
eccbuf = chip->oob_poi + oobregion.offset;
for (i = 0; i < chip->ecc.steps; i++) {
atmel_pmecc_get_generated_eccbytes(nand->pmecc, i,
eccbuf);
eccbuf += chip->ecc.bytes;
}
return 0;
}
static int atmel_nand_pmecc_correct_data(struct nand_chip *chip, void *buf,
bool raw)
{
struct atmel_nand *nand = to_atmel_nand(chip);
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand_controller *nc;
struct mtd_oob_region oobregion;
int ret, i, max_bitflips = 0;
void *databuf, *eccbuf;
nc = to_nand_controller(chip->controller);
if (raw)
return 0;
ret = atmel_pmecc_wait_rdy(nand->pmecc);
if (ret) {
dev_err(nc->dev,
"Failed to read NAND page data (err = %d)\n",
ret);
return ret;
}
mtd_ooblayout_ecc(mtd, 0, &oobregion);
eccbuf = chip->oob_poi + oobregion.offset;
databuf = buf;
for (i = 0; i < chip->ecc.steps; i++) {
ret = atmel_pmecc_correct_sector(nand->pmecc, i, databuf,
eccbuf);
if (ret < 0 && !atmel_pmecc_correct_erased_chunks(nand->pmecc))
ret = nand_check_erased_ecc_chunk(databuf,
chip->ecc.size,
eccbuf,
chip->ecc.bytes,
NULL, 0,
chip->ecc.strength);
if (ret >= 0)
max_bitflips = max(ret, max_bitflips);
else
mtd->ecc_stats.failed++;
databuf += chip->ecc.size;
eccbuf += chip->ecc.bytes;
}
return max_bitflips;
}
static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
bool oob_required, int page, bool raw)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand *nand = to_atmel_nand(chip);
int ret;
ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
if (ret)
return ret;
atmel_nand_write_buf(mtd, buf, mtd->writesize);
ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
if (ret) {
atmel_pmecc_disable(nand->pmecc);
return ret;
}
atmel_nand_pmecc_disable(chip, raw);
atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false);
}
static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd,
struct nand_chip *chip,
const u8 *buf, int oob_required,
int page)
{
return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, true);
}
static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
bool oob_required, int page, bool raw)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
if (ret)
return ret;
atmel_nand_read_buf(mtd, buf, mtd->writesize);
atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
atmel_nand_pmecc_disable(chip, raw);
return ret;
}
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false);
}
static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true);
}
static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
const u8 *buf, bool oob_required,
int page, bool raw)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
int ret;
nc = to_hsmc_nand_controller(chip->controller);
atmel_nfc_copy_to_sram(chip, buf, false);
nc->op.cmds[0] = NAND_CMD_SEQIN;
nc->op.ncmds = 1;
atmel_nfc_set_op_addr(chip, page, 0x0);
nc->op.cs = nand->activecs->id;
nc->op.data = ATMEL_NFC_WRITE_DATA;
ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
if (ret)
return ret;
ret = atmel_nfc_exec_op(nc, false);
if (ret) {
atmel_nand_pmecc_disable(chip, raw);
dev_err(nc->base.dev,
"Failed to transfer NAND page data (err = %d)\n",
ret);
return ret;
}
ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
atmel_nand_pmecc_disable(chip, raw);
if (ret)
return ret;
atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
nc->op.cmds[0] = NAND_CMD_PAGEPROG;
nc->op.ncmds = 1;
nc->op.cs = nand->activecs->id;
ret = atmel_nfc_exec_op(nc, false);
if (ret)
dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
ret);
return ret;
}
static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
struct nand_chip *chip,
const u8 *buf, int oob_required,
int page)
{
return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
false);
}
static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd,
struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
return atmel_hsmc_nand_pmecc_write_pg(chip, buf, oob_required, page,
true);
}
static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
bool oob_required, int page,
bool raw)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
int ret;
nc = to_hsmc_nand_controller(chip->controller);
/*
* Optimized read page accessors only work when the NAND R/B pin is
* connected to a native SoC R/B pin. If that's not the case, fallback
* to the non-optimized one.
*/
if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page,
raw);
}
nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READ0;
if (mtd->writesize > 512)
nc->op.cmds[nc->op.ncmds++] = NAND_CMD_READSTART;
atmel_nfc_set_op_addr(chip, page, 0x0);
nc->op.cs = nand->activecs->id;
nc->op.data = ATMEL_NFC_READ_DATA;
ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
if (ret)
return ret;
ret = atmel_nfc_exec_op(nc, false);
if (ret) {
atmel_nand_pmecc_disable(chip, raw);
dev_err(nc->base.dev,
"Failed to load NAND page data (err = %d)\n",
ret);
return ret;
}
atmel_nfc_copy_from_sram(chip, buf, true);
ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
atmel_nand_pmecc_disable(chip, raw);
return ret;
}
static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd,
struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
false);
}
static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd,
struct nand_chip *chip,
u8 *buf, int oob_required,
int page)
{
return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
true);
}
static int atmel_nand_pmecc_init(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
struct atmel_pmecc_user_req req;
nc = to_nand_controller(chip->controller);
if (!nc->pmecc) {
dev_err(nc->dev, "HW ECC not supported\n");
return -ENOTSUPP;
}
if (nc->caps->legacy_of_bindings) {
u32 val;
if (!of_property_read_u32(nc->dev->of_node, "atmel,pmecc-cap",
&val))
chip->ecc.strength = val;
if (!of_property_read_u32(nc->dev->of_node,
"atmel,pmecc-sector-size",
&val))
chip->ecc.size = val;
}
if (chip->ecc.options & NAND_ECC_MAXIMIZE)
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
else if (chip->ecc.strength)
req.ecc.strength = chip->ecc.strength;
else if (chip->ecc_strength_ds)
req.ecc.strength = chip->ecc_strength_ds;
else
req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;
if (chip->ecc.size)
req.ecc.sectorsize = chip->ecc.size;
else if (chip->ecc_step_ds)
req.ecc.sectorsize = chip->ecc_step_ds;
else
req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO;
req.pagesize = mtd->writesize;
req.oobsize = mtd->oobsize;
if (mtd->writesize <= 512) {
req.ecc.bytes = 4;
req.ecc.ooboffset = 0;
} else {
req.ecc.bytes = mtd->oobsize - 2;
req.ecc.ooboffset = ATMEL_PMECC_OOBOFFSET_AUTO;
}
nand->pmecc = atmel_pmecc_create_user(nc->pmecc, &req);
if (IS_ERR(nand->pmecc))
return PTR_ERR(nand->pmecc);
chip->ecc.algo = NAND_ECC_BCH;
chip->ecc.size = req.ecc.sectorsize;
chip->ecc.bytes = req.ecc.bytes / req.ecc.nsectors;
chip->ecc.strength = req.ecc.strength;
chip->options |= NAND_NO_SUBPAGE_WRITE;
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
return 0;
}
static int atmel_nand_ecc_init(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct atmel_nand_controller *nc;
int ret;
nc = to_nand_controller(chip->controller);
switch (chip->ecc.mode) {
case NAND_ECC_NONE:
case NAND_ECC_SOFT:
/*
* Nothing to do, the core will initialize everything for us.
*/
break;
case NAND_ECC_HW:
ret = atmel_nand_pmecc_init(chip);
if (ret)
return ret;
chip->ecc.read_page = atmel_nand_pmecc_read_page;
chip->ecc.write_page = atmel_nand_pmecc_write_page;
chip->ecc.read_page_raw = atmel_nand_pmecc_read_page_raw;
chip->ecc.write_page_raw = atmel_nand_pmecc_write_page_raw;
break;
default:
/* Other modes are not supported. */
dev_err(nc->dev, "Unsupported ECC mode: %d\n",
chip->ecc.mode);
return -ENOTSUPP;
}
return 0;
}
static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
int ret;
ret = atmel_nand_ecc_init(nand);
if (ret)
return ret;
if (chip->ecc.mode != NAND_ECC_HW)
return 0;
/* Adjust the ECC operations for the HSMC IP. */
chip->ecc.read_page = atmel_hsmc_nand_pmecc_read_page;
chip->ecc.write_page = atmel_hsmc_nand_pmecc_write_page;
chip->ecc.read_page_raw = atmel_hsmc_nand_pmecc_read_page_raw;
chip->ecc.write_page_raw = atmel_hsmc_nand_pmecc_write_page_raw;
chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
return 0;
}
static void atmel_nand_init(struct atmel_nand_controller *nc,
struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
mtd->dev.parent = nc->dev;
nand->base.controller = &nc->base;
chip->cmd_ctrl = atmel_nand_cmd_ctrl;
chip->read_byte = atmel_nand_read_byte;
chip->read_word = atmel_nand_read_word;
chip->write_byte = atmel_nand_write_byte;
chip->read_buf = atmel_nand_read_buf;
chip->write_buf = atmel_nand_write_buf;
chip->select_chip = atmel_nand_select_chip;
/* Some NANDs require a longer delay than the default one (20us). */
chip->chip_delay = 40;
/*
* Use a bounce buffer when the buffer passed by the MTD user is not
* suitable for DMA.
*/
if (nc->dmac)
chip->options |= NAND_USE_BOUNCE_BUFFER;
/* Default to HW ECC if pmecc is available. */
if (nc->pmecc)
chip->ecc.mode = NAND_ECC_HW;
}
static void atmel_smc_nand_init(struct atmel_nand_controller *nc,
struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct atmel_smc_nand_controller *smc_nc;
int i;
atmel_nand_init(nc, nand);
smc_nc = to_smc_nand_controller(chip->controller);
if (!smc_nc->matrix)
return;
/* Attach the CS to the NAND Flash logic. */
for (i = 0; i < nand->numcs; i++)
regmap_update_bits(smc_nc->matrix, smc_nc->ebi_csa_offs,
BIT(nand->cs[i].id), BIT(nand->cs[i].id));
}
static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
atmel_nand_init(nc, nand);
/* Overload some methods for the HSMC controller. */
chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
chip->select_chip = atmel_hsmc_nand_select_chip;
}
static int atmel_nand_detect(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand_controller *nc;
int ret;
nc = to_nand_controller(chip->controller);
ret = nand_scan_ident(mtd, nand->numcs, NULL);
if (ret)
dev_err(nc->dev, "nand_scan_ident() failed: %d\n", ret);
return ret;
}
static int atmel_nand_unregister(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = mtd_device_unregister(mtd);
if (ret)
return ret;
nand_cleanup(chip);
list_del(&nand->node);
return 0;
}
static int atmel_nand_register(struct atmel_nand *nand)
{
struct nand_chip *chip = &nand->base;
struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand_controller *nc;
int ret;
nc = to_nand_controller(chip->controller);
if (nc->caps->legacy_of_bindings || !nc->dev->of_node) {
/*
* We keep the MTD name unchanged to avoid breaking platforms
* where the MTD cmdline parser is used and the bootloader
* has not been updated to use the new naming scheme.
*/
mtd->name = "atmel_nand";
} else if (!mtd->name) {
/*
* If the new bindings are used and the bootloader has not been
* updated to pass a new mtdparts parameter on the cmdline, you
* should define the following property in your nand node:
*
* label = "atmel_nand";
*
* This way, mtd->name will be set by the core when
* nand_set_flash_node() is called.
*/
mtd->name = devm_kasprintf(nc->dev, GFP_KERNEL,
"%s:nand.%d", dev_name(nc->dev),
nand->cs[0].id);
if (!mtd->name) {
dev_err(nc->dev, "Failed to allocate mtd->name\n");
return -ENOMEM;
}
}
ret = nand_scan_tail(mtd);
if (ret) {
dev_err(nc->dev, "nand_scan_tail() failed: %d\n", ret);
return ret;
}
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(nc->dev, "Failed to register mtd device: %d\n", ret);
nand_cleanup(chip);
return ret;
}
list_add_tail(&nand->node, &nc->chips);
return 0;
}
static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
struct device_node *np,
int reg_cells)
{
struct atmel_nand *nand;
struct gpio_desc *gpio;
int numcs, ret, i;
numcs = of_property_count_elems_of_size(np, "reg",
reg_cells * sizeof(u32));
if (numcs < 1) {
dev_err(nc->dev, "Missing or invalid reg property\n");
return ERR_PTR(-EINVAL);
}
nand = devm_kzalloc(nc->dev,
sizeof(*nand) + (numcs * sizeof(*nand->cs)),
GFP_KERNEL);
if (!nand) {
dev_err(nc->dev, "Failed to allocate NAND object\n");
return ERR_PTR(-ENOMEM);
}
nand->numcs = numcs;
gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "det", 0,
&np->fwnode, GPIOD_IN,
"nand-det");
if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
dev_err(nc->dev,
"Failed to get detect gpio (err = %ld)\n",
PTR_ERR(gpio));
return ERR_CAST(gpio);
}
if (!IS_ERR(gpio))
nand->cdgpio = gpio;
for (i = 0; i < numcs; i++) {
struct resource res;
u32 val;
ret = of_address_to_resource(np, 0, &res);
if (ret) {
dev_err(nc->dev, "Invalid reg property (err = %d)\n",
ret);
return ERR_PTR(ret);
}
ret = of_property_read_u32_index(np, "reg", i * reg_cells,
&val);
if (ret) {
dev_err(nc->dev, "Invalid reg property (err = %d)\n",
ret);
return ERR_PTR(ret);
}
nand->cs[i].id = val;
nand->cs[i].io.dma = res.start;
nand->cs[i].io.virt = devm_ioremap_resource(nc->dev, &res);
if (IS_ERR(nand->cs[i].io.virt))
return ERR_CAST(nand->cs[i].io.virt);
if (!of_property_read_u32(np, "atmel,rb", &val)) {
if (val > ATMEL_NFC_MAX_RB_ID)
return ERR_PTR(-EINVAL);
nand->cs[i].rb.type = ATMEL_NAND_NATIVE_RB;
nand->cs[i].rb.id = val;
} else {
gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev,
"rb", i, &np->fwnode,
GPIOD_IN, "nand-rb");
if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
dev_err(nc->dev,
"Failed to get R/B gpio (err = %ld)\n",
PTR_ERR(gpio));
return ERR_CAST(gpio);
}
if (!IS_ERR(gpio)) {
nand->cs[i].rb.type = ATMEL_NAND_GPIO_RB;
nand->cs[i].rb.gpio = gpio;
}
}
gpio = devm_fwnode_get_index_gpiod_from_child(nc->dev, "cs",
i, &np->fwnode,
GPIOD_OUT_HIGH,
"nand-cs");
if (IS_ERR(gpio) && PTR_ERR(gpio) != -ENOENT) {
dev_err(nc->dev,
"Failed to get CS gpio (err = %ld)\n",
PTR_ERR(gpio));
return ERR_CAST(gpio);
}
if (!IS_ERR(gpio))
nand->cs[i].csgpio = gpio;
}
nand_set_flash_node(&nand->base, np);
return nand;
}
static int
atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
struct atmel_nand *nand)
{
int ret;
/* No card inserted, skip this NAND. */
if (nand->cdgpio && gpiod_get_value(nand->cdgpio)) {
dev_info(nc->dev, "No SmartMedia card inserted.\n");
return 0;
}
nc->caps->ops->nand_init(nc, nand);
ret = atmel_nand_detect(nand);
if (ret)
return ret;
ret = nc->caps->ops->ecc_init(nand);
if (ret)
return ret;
return atmel_nand_register(nand);
}
static int
atmel_nand_controller_remove_nands(struct atmel_nand_controller *nc)
{
struct atmel_nand *nand, *tmp;
int ret;
list_for_each_entry_safe(nand, tmp, &nc->chips, node) {
ret = atmel_nand_unregister(nand);
if (ret)
return ret;
}
return 0;
}
static int
atmel_nand_controller_legacy_add_nands(struct atmel_nand_controller *nc)
{
struct device *dev = nc->dev;
struct platform_device *pdev = to_platform_device(dev);
struct atmel_nand *nand;
struct gpio_desc *gpio;
struct resource *res;
/*
* Legacy bindings only allow connecting a single NAND with a unique CS
* line to the controller.
*/
nand = devm_kzalloc(nc->dev, sizeof(*nand) + sizeof(*nand->cs),
GFP_KERNEL);
if (!nand)
return -ENOMEM;
nand->numcs = 1;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nand->cs[0].io.virt = devm_ioremap_resource(dev, res);
if (IS_ERR(nand->cs[0].io.virt))
return PTR_ERR(nand->cs[0].io.virt);
nand->cs[0].io.dma = res->start;
/*
* The old driver was hardcoding the CS id to 3 for all sama5
* controllers. Since this id is only meaningful for the sama5
* controller we can safely assign this id to 3 no matter the
* controller.
* If one wants to connect a NAND to a different CS line, he will
* have to use the new bindings.
*/
nand->cs[0].id = 3;
/* R/B GPIO. */
gpio = devm_gpiod_get_index_optional(dev, NULL, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "Failed to get R/B gpio (err = %ld)\n",
PTR_ERR(gpio));
return PTR_ERR(gpio);
}
if (gpio) {
nand->cs[0].rb.type = ATMEL_NAND_GPIO_RB;
nand->cs[0].rb.gpio = gpio;
}
/* CS GPIO. */
gpio = devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_HIGH);
if (IS_ERR(gpio)) {
dev_err(dev, "Failed to get CS gpio (err = %ld)\n",
PTR_ERR(gpio));
return PTR_ERR(gpio);
}
nand->cs[0].csgpio = gpio;
/* Card detect GPIO. */
gpio = devm_gpiod_get_index_optional(nc->dev, NULL, 2, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev,
"Failed to get detect gpio (err = %ld)\n",
PTR_ERR(gpio));
return PTR_ERR(gpio);
}
nand->cdgpio = gpio;
nand_set_flash_node(&nand->base, nc->dev->of_node);
return atmel_nand_controller_add_nand(nc, nand);
}
static int atmel_nand_controller_add_nands(struct atmel_nand_controller *nc)
{
struct device_node *np, *nand_np;
struct device *dev = nc->dev;
int ret, reg_cells;
u32 val;
/* We do not retrieve the SMC syscon when parsing old DTs. */
if (nc->caps->legacy_of_bindings)
return atmel_nand_controller_legacy_add_nands(nc);
np = dev->of_node;
ret = of_property_read_u32(np, "#address-cells", &val);
if (ret) {
dev_err(dev, "missing #address-cells property\n");
return ret;
}
reg_cells = val;
ret = of_property_read_u32(np, "#size-cells", &val);
if (ret) {
dev_err(dev, "missing #address-cells property\n");
return ret;
}
reg_cells += val;
for_each_child_of_node(np, nand_np) {
struct atmel_nand *nand;
nand = atmel_nand_create(nc, nand_np, reg_cells);
if (IS_ERR(nand)) {
ret = PTR_ERR(nand);
goto err;
}
ret = atmel_nand_controller_add_nand(nc, nand);
if (ret)
goto err;
}
return 0;
err:
atmel_nand_controller_remove_nands(nc);
return ret;
}
static void atmel_nand_controller_cleanup(struct atmel_nand_controller *nc)
{
if (nc->dmac)
dma_release_channel(nc->dmac);
clk_put(nc->mck);
}
static const struct of_device_id atmel_matrix_of_ids[] = {
{
.compatible = "atmel,at91sam9260-matrix",
.data = (void *)AT91SAM9260_MATRIX_EBICSA,
},
{
.compatible = "atmel,at91sam9261-matrix",
.data = (void *)AT91SAM9261_MATRIX_EBICSA,
},
{
.compatible = "atmel,at91sam9263-matrix",
.data = (void *)AT91SAM9263_MATRIX_EBI0CSA,
},
{
.compatible = "atmel,at91sam9rl-matrix",
.data = (void *)AT91SAM9RL_MATRIX_EBICSA,
},
{
.compatible = "atmel,at91sam9g45-matrix",
.data = (void *)AT91SAM9G45_MATRIX_EBICSA,
},
{
.compatible = "atmel,at91sam9n12-matrix",
.data = (void *)AT91SAM9N12_MATRIX_EBICSA,
},
{
.compatible = "atmel,at91sam9x5-matrix",
.data = (void *)AT91SAM9X5_MATRIX_EBICSA,
},
{ /* sentinel */ },
};
static int atmel_nand_controller_init(struct atmel_nand_controller *nc,
struct platform_device *pdev,
const struct atmel_nand_controller_caps *caps)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int ret;
nand_hw_control_init(&nc->base);
INIT_LIST_HEAD(&nc->chips);
nc->dev = dev;
nc->caps = caps;
platform_set_drvdata(pdev, nc);
nc->pmecc = devm_atmel_pmecc_get(dev);
if (IS_ERR(nc->pmecc)) {
ret = PTR_ERR(nc->pmecc);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Could not get PMECC object (err = %d)\n",
ret);
return ret;
}
if (nc->caps->has_dma) {
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
nc->dmac = dma_request_channel(mask, NULL, NULL);
if (!nc->dmac)
dev_err(nc->dev, "Failed to request DMA channel\n");
}
/* We do not retrieve the SMC syscon when parsing old DTs. */
if (nc->caps->legacy_of_bindings)
return 0;
np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
if (!np) {
dev_err(dev, "Missing or invalid atmel,smc property\n");
return -EINVAL;
}
nc->smc = syscon_node_to_regmap(np);
of_node_put(np);
if (IS_ERR(nc->smc)) {
ret = PTR_ERR(nc->smc);
dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret);
return ret;
}
return 0;
}
static int
atmel_smc_nand_controller_init(struct atmel_smc_nand_controller *nc)
{
struct device *dev = nc->base.dev;
const struct of_device_id *match;
struct device_node *np;
int ret;
/* We do not retrieve the matrix syscon when parsing old DTs. */
if (nc->base.caps->legacy_of_bindings)
return 0;
np = of_parse_phandle(dev->parent->of_node, "atmel,matrix", 0);
if (!np)
return 0;
match = of_match_node(atmel_matrix_of_ids, np);
if (!match) {
of_node_put(np);
return 0;
}
nc->matrix = syscon_node_to_regmap(np);
of_node_put(np);
if (IS_ERR(nc->matrix)) {
ret = PTR_ERR(nc->matrix);
dev_err(dev, "Could not get Matrix regmap (err = %d)\n", ret);
return ret;
}
nc->ebi_csa_offs = (unsigned int)match->data;
/*
* The at91sam9263 has 2 EBIs, if the NAND controller is under EBI1
* add 4 to ->ebi_csa_offs.
*/
if (of_device_is_compatible(dev->parent->of_node,
"atmel,at91sam9263-ebi1"))
nc->ebi_csa_offs += 4;
return 0;
}
static int
atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
{
struct regmap_config regmap_conf = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
struct device *dev = nc->base.dev;
struct device_node *nand_np, *nfc_np;
void __iomem *iomem;
struct resource res;
int ret;
nand_np = dev->of_node;
nfc_np = of_find_compatible_node(dev->of_node, NULL,
"atmel,sama5d3-nfc");
nc->clk = of_clk_get(nfc_np, 0);
if (IS_ERR(nc->clk)) {
ret = PTR_ERR(nc->clk);
dev_err(dev, "Failed to retrieve HSMC clock (err = %d)\n",
ret);
goto out;
}
ret = clk_prepare_enable(nc->clk);
if (ret) {
dev_err(dev, "Failed to enable the HSMC clock (err = %d)\n",
ret);
goto out;
}
nc->irq = of_irq_get(nand_np, 0);
if (nc->irq < 0) {
ret = nc->irq;
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get IRQ number (err = %d)\n",
ret);
goto out;
}
ret = of_address_to_resource(nfc_np, 0, &res);
if (ret) {
dev_err(dev, "Invalid or missing NFC IO resource (err = %d)\n",
ret);
goto out;
}
iomem = devm_ioremap_resource(dev, &res);
if (IS_ERR(iomem)) {
ret = PTR_ERR(iomem);
goto out;
}
regmap_conf.name = "nfc-io";
regmap_conf.max_register = resource_size(&res) - 4;
nc->io = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
if (IS_ERR(nc->io)) {
ret = PTR_ERR(nc->io);
dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
ret);
goto out;
}
ret = of_address_to_resource(nfc_np, 1, &res);
if (ret) {
dev_err(dev, "Invalid or missing HSMC resource (err = %d)\n",
ret);
goto out;
}
iomem = devm_ioremap_resource(dev, &res);
if (IS_ERR(iomem)) {
ret = PTR_ERR(iomem);
goto out;
}
regmap_conf.name = "smc";
regmap_conf.max_register = resource_size(&res) - 4;
nc->base.smc = devm_regmap_init_mmio(dev, iomem, &regmap_conf);
if (IS_ERR(nc->base.smc)) {
ret = PTR_ERR(nc->base.smc);
dev_err(dev, "Could not create NFC IO regmap (err = %d)\n",
ret);
goto out;
}
ret = of_address_to_resource(nfc_np, 2, &res);
if (ret) {
dev_err(dev, "Invalid or missing SRAM resource (err = %d)\n",
ret);
goto out;
}
nc->sram.virt = devm_ioremap_resource(dev, &res);
if (IS_ERR(nc->sram.virt)) {
ret = PTR_ERR(nc->sram.virt);
goto out;
}
nc->sram.dma = res.start;
out:
of_node_put(nfc_np);
return ret;
}
static int
atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc)
{
struct device *dev = nc->base.dev;
struct device_node *np;
int ret;
np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0);
if (!np) {
dev_err(dev, "Missing or invalid atmel,smc property\n");
return -EINVAL;
}
nc->irq = of_irq_get(np, 0);
of_node_put(np);
if (nc->irq < 0) {
if (nc->irq != -EPROBE_DEFER)
dev_err(dev, "Failed to get IRQ number (err = %d)\n",
nc->irq);
return nc->irq;
}
np = of_parse_phandle(dev->of_node, "atmel,nfc-io", 0);
if (!np) {
dev_err(dev, "Missing or invalid atmel,nfc-io property\n");
return -EINVAL;
}
nc->io = syscon_node_to_regmap(np);
of_node_put(np);
if (IS_ERR(nc->io)) {
ret = PTR_ERR(nc->io);
dev_err(dev, "Could not get NFC IO regmap (err = %d)\n", ret);
return ret;
}
nc->sram.pool = of_gen_pool_get(nc->base.dev->of_node,
"atmel,nfc-sram", 0);
if (!nc->sram.pool) {
dev_err(nc->base.dev, "Missing SRAM\n");
return -ENOMEM;
}
nc->sram.virt = gen_pool_dma_alloc(nc->sram.pool,
ATMEL_NFC_SRAM_SIZE,
&nc->sram.dma);
if (!nc->sram.virt) {
dev_err(nc->base.dev,
"Could not allocate memory from the NFC SRAM pool\n");
return -ENOMEM;
}
return 0;
}
static int
atmel_hsmc_nand_controller_remove(struct atmel_nand_controller *nc)
{
struct atmel_hsmc_nand_controller *hsmc_nc;
int ret;
ret = atmel_nand_controller_remove_nands(nc);
if (ret)
return ret;
hsmc_nc = container_of(nc, struct atmel_hsmc_nand_controller, base);
if (hsmc_nc->sram.pool)
gen_pool_free(hsmc_nc->sram.pool,
(unsigned long)hsmc_nc->sram.virt,
ATMEL_NFC_SRAM_SIZE);
if (hsmc_nc->clk) {
clk_disable_unprepare(hsmc_nc->clk);
clk_put(hsmc_nc->clk);
}
atmel_nand_controller_cleanup(nc);
return 0;
}
static int atmel_hsmc_nand_controller_probe(struct platform_device *pdev,
const struct atmel_nand_controller_caps *caps)
{
struct device *dev = &pdev->dev;
struct atmel_hsmc_nand_controller *nc;
int ret;
nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
if (!nc)
return -ENOMEM;
ret = atmel_nand_controller_init(&nc->base, pdev, caps);
if (ret)
return ret;
if (caps->legacy_of_bindings)
ret = atmel_hsmc_nand_controller_legacy_init(nc);
else
ret = atmel_hsmc_nand_controller_init(nc);
if (ret)
return ret;
/* Make sure all irqs are masked before registering our IRQ handler. */
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_IDR, 0xffffffff);
ret = devm_request_irq(dev, nc->irq, atmel_nfc_interrupt,
IRQF_SHARED, "nfc", nc);
if (ret) {
dev_err(dev,
"Could not get register NFC interrupt handler (err = %d)\n",
ret);
goto err;
}
/* Initial NFC configuration. */
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CFG,
ATMEL_HSMC_NFC_CFG_DTO_MAX);
ret = atmel_nand_controller_add_nands(&nc->base);
if (ret)
goto err;
return 0;
err:
atmel_hsmc_nand_controller_remove(&nc->base);
return ret;
}
static const struct atmel_nand_controller_ops atmel_hsmc_nc_ops = {
.probe = atmel_hsmc_nand_controller_probe,
.remove = atmel_hsmc_nand_controller_remove,
.ecc_init = atmel_hsmc_nand_ecc_init,
.nand_init = atmel_hsmc_nand_init,
};
static const struct atmel_nand_controller_caps atmel_sama5_nc_caps = {
.has_dma = true,
.ale_offs = BIT(21),
.cle_offs = BIT(22),
.ops = &atmel_hsmc_nc_ops,
};
/* Only used to parse old bindings. */
static const struct atmel_nand_controller_caps atmel_sama5_nand_caps = {
.has_dma = true,
.ale_offs = BIT(21),
.cle_offs = BIT(22),
.ops = &atmel_hsmc_nc_ops,
.legacy_of_bindings = true,
};
static int atmel_smc_nand_controller_probe(struct platform_device *pdev,
const struct atmel_nand_controller_caps *caps)
{
struct device *dev = &pdev->dev;
struct atmel_smc_nand_controller *nc;
int ret;
nc = devm_kzalloc(dev, sizeof(*nc), GFP_KERNEL);
if (!nc)
return -ENOMEM;
ret = atmel_nand_controller_init(&nc->base, pdev, caps);
if (ret)
return ret;
ret = atmel_smc_nand_controller_init(nc);
if (ret)
return ret;
return atmel_nand_controller_add_nands(&nc->base);
}
static int
atmel_smc_nand_controller_remove(struct atmel_nand_controller *nc)
{
int ret;
ret = atmel_nand_controller_remove_nands(nc);
if (ret)
return ret;
atmel_nand_controller_cleanup(nc);
return 0;
}
static const struct atmel_nand_controller_ops atmel_smc_nc_ops = {
.probe = atmel_smc_nand_controller_probe,
.remove = atmel_smc_nand_controller_remove,
.ecc_init = atmel_nand_ecc_init,
.nand_init = atmel_smc_nand_init,
};
static const struct atmel_nand_controller_caps atmel_rm9200_nc_caps = {
.ale_offs = BIT(21),
.cle_offs = BIT(22),
.ops = &atmel_smc_nc_ops,
};
static const struct atmel_nand_controller_caps atmel_sam9261_nc_caps = {
.ale_offs = BIT(22),
.cle_offs = BIT(21),
.ops = &atmel_smc_nc_ops,
};
static const struct atmel_nand_controller_caps atmel_sam9g45_nc_caps = {
.has_dma = true,
.ale_offs = BIT(21),
.cle_offs = BIT(22),
.ops = &atmel_smc_nc_ops,
};
/* Only used to parse old bindings. */
static const struct atmel_nand_controller_caps atmel_rm9200_nand_caps = {
.ale_offs = BIT(21),
.cle_offs = BIT(22),
.ops = &atmel_smc_nc_ops,
.legacy_of_bindings = true,
};
static const struct atmel_nand_controller_caps atmel_sam9261_nand_caps = {
.ale_offs = BIT(22),
.cle_offs = BIT(21),
.ops = &atmel_smc_nc_ops,
.legacy_of_bindings = true,
};
static const struct atmel_nand_controller_caps atmel_sam9g45_nand_caps = {
.has_dma = true,
.ale_offs = BIT(21),
.cle_offs = BIT(22),
.ops = &atmel_smc_nc_ops,
.legacy_of_bindings = true,
};
static const struct of_device_id atmel_nand_controller_of_ids[] = {
{
.compatible = "atmel,at91rm9200-nand-controller",
.data = &atmel_rm9200_nc_caps,
},
{
.compatible = "atmel,at91sam9260-nand-controller",
.data = &atmel_rm9200_nc_caps,
},
{
.compatible = "atmel,at91sam9261-nand-controller",
.data = &atmel_sam9261_nc_caps,
},
{
.compatible = "atmel,at91sam9g45-nand-controller",
.data = &atmel_sam9g45_nc_caps,
},
{
.compatible = "atmel,sama5d3-nand-controller",
.data = &atmel_sama5_nc_caps,
},
/* Support for old/deprecated bindings: */
{
.compatible = "atmel,at91rm9200-nand",
.data = &atmel_rm9200_nand_caps,
},
{
.compatible = "atmel,sama5d4-nand",
.data = &atmel_rm9200_nand_caps,
},
{
.compatible = "atmel,sama5d2-nand",
.data = &atmel_rm9200_nand_caps,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, atmel_nand_controller_of_ids);
static int atmel_nand_controller_probe(struct platform_device *pdev)
{
const struct atmel_nand_controller_caps *caps;
if (pdev->id_entry)
caps = (void *)pdev->id_entry->driver_data;
else
caps = of_device_get_match_data(&pdev->dev);
if (!caps) {
dev_err(&pdev->dev, "Could not retrieve NFC caps\n");
return -EINVAL;
}
if (caps->legacy_of_bindings) {
u32 ale_offs = 21;
/*
* If we are parsing legacy DT props and the DT contains a
* valid NFC node, forward the request to the sama5 logic.
*/
if (of_find_compatible_node(pdev->dev.of_node, NULL,
"atmel,sama5d3-nfc"))
caps = &atmel_sama5_nand_caps;
/*
* Even if the compatible says we are dealing with an
* at91rm9200 controller, the atmel,nand-has-dma specify that
* this controller supports DMA, which means we are in fact
* dealing with an at91sam9g45+ controller.
*/
if (!caps->has_dma &&
of_property_read_bool(pdev->dev.of_node,
"atmel,nand-has-dma"))
caps = &atmel_sam9g45_nand_caps;
/*
* All SoCs except the at91sam9261 are assigning ALE to A21 and
* CLE to A22. If atmel,nand-addr-offset != 21 this means we're
* actually dealing with an at91sam9261 controller.
*/
of_property_read_u32(pdev->dev.of_node,
"atmel,nand-addr-offset", &ale_offs);
if (ale_offs != 21)
caps = &atmel_sam9261_nand_caps;
}
return caps->ops->probe(pdev, caps);
}
static int atmel_nand_controller_remove(struct platform_device *pdev)
{
struct atmel_nand_controller *nc = platform_get_drvdata(pdev);
return nc->caps->ops->remove(nc);
}
static struct platform_driver atmel_nand_controller_driver = {
.driver = {
.name = "atmel-nand-controller",
.of_match_table = of_match_ptr(atmel_nand_controller_of_ids),
},
.probe = atmel_nand_controller_probe,
.remove = atmel_nand_controller_remove,
};
module_platform_driver(atmel_nand_controller_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
MODULE_DESCRIPTION("NAND Flash Controller driver for Atmel SoCs");
MODULE_ALIAS("platform:atmel-nand-controller");
/*
* Copyright 2017 ATMEL
* Copyright 2017 Free Electrons
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* Derived from the atmel_nand.c driver which contained the following
* copyrights:
*
* Copyright 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
* Copyright 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
* Copyright 2000 Steven J. Hill (sjhill@cotw.com)
*
* Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
* Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright 2007
*
* Derived from Das U-Boot source code
* (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
* Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
*
* Add Programmable Multibit ECC support for various AT91 SoC
* Copyright 2012 ATMEL, Hong Xu
*
* Add Nand Flash Controller support for SAMA5 SoC
* Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* The PMECC is an hardware assisted BCH engine, which means part of the
* ECC algorithm is left to the software. The hardware/software repartition
* is explained in the "PMECC Controller Functional Description" chapter in
* Atmel datasheets, and some of the functions in this file are directly
* implementing the algorithms described in the "Software Implementation"
* sub-section.
*
* TODO: it seems that the software BCH implementation in lib/bch.c is already
* providing some of the logic we are implementing here. It would be smart
* to expose the needed lib/bch.c helpers/functions and re-use them here.
*/
#include <linux/genalloc.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mtd/nand.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "pmecc.h"
/* Galois field dimension */
#define PMECC_GF_DIMENSION_13 13
#define PMECC_GF_DIMENSION_14 14
/* Primitive Polynomial used by PMECC */
#define PMECC_GF_13_PRIMITIVE_POLY 0x201b
#define PMECC_GF_14_PRIMITIVE_POLY 0x4443
#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
/* Time out value for reading PMECC status register */
#define PMECC_MAX_TIMEOUT_MS 100
/* PMECC Register Definitions */
#define ATMEL_PMECC_CFG 0x0
#define PMECC_CFG_BCH_STRENGTH(x) (x)
#define PMECC_CFG_BCH_STRENGTH_MASK GENMASK(2, 0)
#define PMECC_CFG_SECTOR512 (0 << 4)
#define PMECC_CFG_SECTOR1024 (1 << 4)
#define PMECC_CFG_NSECTORS(x) ((fls(x) - 1) << 8)
#define PMECC_CFG_READ_OP (0 << 12)
#define PMECC_CFG_WRITE_OP (1 << 12)
#define PMECC_CFG_SPARE_ENABLE BIT(16)
#define PMECC_CFG_AUTO_ENABLE BIT(20)
#define ATMEL_PMECC_SAREA 0x4
#define ATMEL_PMECC_SADDR 0x8
#define ATMEL_PMECC_EADDR 0xc
#define ATMEL_PMECC_CLK 0x10
#define PMECC_CLK_133MHZ (2 << 0)
#define ATMEL_PMECC_CTRL 0x14
#define PMECC_CTRL_RST BIT(0)
#define PMECC_CTRL_DATA BIT(1)
#define PMECC_CTRL_USER BIT(2)
#define PMECC_CTRL_ENABLE BIT(4)
#define PMECC_CTRL_DISABLE BIT(5)
#define ATMEL_PMECC_SR 0x18
#define PMECC_SR_BUSY BIT(0)
#define PMECC_SR_ENABLE BIT(4)
#define ATMEL_PMECC_IER 0x1c
#define ATMEL_PMECC_IDR 0x20
#define ATMEL_PMECC_IMR 0x24
#define ATMEL_PMECC_ISR 0x28
#define PMECC_ERROR_INT BIT(0)
#define ATMEL_PMECC_ECC(sector, n) \
((((sector) + 1) * 0x40) + (n))
#define ATMEL_PMECC_REM(sector, n) \
((((sector) + 1) * 0x40) + ((n) * 4) + 0x200)
/* PMERRLOC Register Definitions */
#define ATMEL_PMERRLOC_ELCFG 0x0
#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
#define ATMEL_PMERRLOC_ELPRIM 0x4
#define ATMEL_PMERRLOC_ELEN 0x8
#define ATMEL_PMERRLOC_ELDIS 0xc
#define PMERRLOC_DISABLE BIT(0)
#define ATMEL_PMERRLOC_ELSR 0x10
#define PMERRLOC_ELSR_BUSY BIT(0)
#define ATMEL_PMERRLOC_ELIER 0x14
#define ATMEL_PMERRLOC_ELIDR 0x18
#define ATMEL_PMERRLOC_ELIMR 0x1c
#define ATMEL_PMERRLOC_ELISR 0x20
#define PMERRLOC_ERR_NUM_MASK GENMASK(12, 8)
#define PMERRLOC_CALC_DONE BIT(0)
#define ATMEL_PMERRLOC_SIGMA(x) (((x) * 0x4) + 0x28)
#define ATMEL_PMERRLOC_EL(offs, x) (((x) * 0x4) + (offs))
struct atmel_pmecc_gf_tables {
u16 *alpha_to;
u16 *index_of;
};
struct atmel_pmecc_caps {
const int *strengths;
int nstrengths;
int el_offset;
bool correct_erased_chunks;
};
struct atmel_pmecc {
struct device *dev;
const struct atmel_pmecc_caps *caps;
struct {
void __iomem *base;
void __iomem *errloc;
} regs;
struct mutex lock;
};
struct atmel_pmecc_user_conf_cache {
u32 cfg;
u32 sarea;
u32 saddr;
u32 eaddr;
};
struct atmel_pmecc_user {
struct atmel_pmecc_user_conf_cache cache;
struct atmel_pmecc *pmecc;
const struct atmel_pmecc_gf_tables *gf_tables;
int eccbytes;
s16 *partial_syn;
s16 *si;
s16 *lmu;
s16 *smu;
s32 *mu;
s32 *dmu;
s32 *delta;
u32 isr;
};
static DEFINE_MUTEX(pmecc_gf_tables_lock);
static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_512;
static const struct atmel_pmecc_gf_tables *pmecc_gf_tables_1024;
static inline int deg(unsigned int poly)
{
/* polynomial degree is the most-significant bit index */
return fls(poly) - 1;
}
static int atmel_pmecc_build_gf_tables(int mm, unsigned int poly,
struct atmel_pmecc_gf_tables *gf_tables)
{
unsigned int i, x = 1;
const unsigned int k = BIT(deg(poly));
unsigned int nn = BIT(mm) - 1;
/* primitive polynomial must be of degree m */
if (k != (1u << mm))
return -EINVAL;
for (i = 0; i < nn; i++) {
gf_tables->alpha_to[i] = x;
gf_tables->index_of[x] = i;
if (i && (x == 1))
/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
return -EINVAL;
x <<= 1;
if (x & k)
x ^= poly;
}
gf_tables->alpha_to[nn] = 1;
gf_tables->index_of[0] = 0;
return 0;
}
static const struct atmel_pmecc_gf_tables *
atmel_pmecc_create_gf_tables(const struct atmel_pmecc_user_req *req)
{
struct atmel_pmecc_gf_tables *gf_tables;
unsigned int poly, degree, table_size;
int ret;
if (req->ecc.sectorsize == 512) {
degree = PMECC_GF_DIMENSION_13;
poly = PMECC_GF_13_PRIMITIVE_POLY;
table_size = PMECC_LOOKUP_TABLE_SIZE_512;
} else {
degree = PMECC_GF_DIMENSION_14;
poly = PMECC_GF_14_PRIMITIVE_POLY;
table_size = PMECC_LOOKUP_TABLE_SIZE_1024;
}
gf_tables = kzalloc(sizeof(*gf_tables) +
(2 * table_size * sizeof(u16)),
GFP_KERNEL);
if (!gf_tables)
return ERR_PTR(-ENOMEM);
gf_tables->alpha_to = (void *)(gf_tables + 1);
gf_tables->index_of = gf_tables->alpha_to + table_size;
ret = atmel_pmecc_build_gf_tables(degree, poly, gf_tables);
if (ret) {
kfree(gf_tables);
return ERR_PTR(ret);
}
return gf_tables;
}
static const struct atmel_pmecc_gf_tables *
atmel_pmecc_get_gf_tables(const struct atmel_pmecc_user_req *req)
{
const struct atmel_pmecc_gf_tables **gf_tables, *ret;
mutex_lock(&pmecc_gf_tables_lock);
if (req->ecc.sectorsize == 512)
gf_tables = &pmecc_gf_tables_512;
else
gf_tables = &pmecc_gf_tables_1024;
ret = *gf_tables;
if (!ret) {
ret = atmel_pmecc_create_gf_tables(req);
if (!IS_ERR(ret))
*gf_tables = ret;
}
mutex_unlock(&pmecc_gf_tables_lock);
return ret;
}
static int atmel_pmecc_prepare_user_req(struct atmel_pmecc *pmecc,
struct atmel_pmecc_user_req *req)
{
int i, max_eccbytes, eccbytes = 0, eccstrength = 0;
if (req->pagesize <= 0 || req->oobsize <= 0 || req->ecc.bytes <= 0)
return -EINVAL;
if (req->ecc.ooboffset >= 0 &&
req->ecc.ooboffset + req->ecc.bytes > req->oobsize)
return -EINVAL;
if (req->ecc.sectorsize == ATMEL_PMECC_SECTOR_SIZE_AUTO) {
if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
return -EINVAL;
if (req->pagesize > 512)
req->ecc.sectorsize = 1024;
else
req->ecc.sectorsize = 512;
}
if (req->ecc.sectorsize != 512 && req->ecc.sectorsize != 1024)
return -EINVAL;
if (req->pagesize % req->ecc.sectorsize)
return -EINVAL;
req->ecc.nsectors = req->pagesize / req->ecc.sectorsize;
max_eccbytes = req->ecc.bytes;
for (i = 0; i < pmecc->caps->nstrengths; i++) {
int nbytes, strength = pmecc->caps->strengths[i];
if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH &&
strength < req->ecc.strength)
continue;
nbytes = DIV_ROUND_UP(strength * fls(8 * req->ecc.sectorsize),
8);
nbytes *= req->ecc.nsectors;
if (nbytes > max_eccbytes)
break;
eccstrength = strength;
eccbytes = nbytes;
if (req->ecc.strength != ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH)
break;
}
if (!eccstrength)
return -EINVAL;
req->ecc.bytes = eccbytes;
req->ecc.strength = eccstrength;
if (req->ecc.ooboffset < 0)
req->ecc.ooboffset = req->oobsize - eccbytes;
return 0;
}
struct atmel_pmecc_user *
atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
struct atmel_pmecc_user_req *req)
{
struct atmel_pmecc_user *user;
const struct atmel_pmecc_gf_tables *gf_tables;
int strength, size, ret;
ret = atmel_pmecc_prepare_user_req(pmecc, req);
if (ret)
return ERR_PTR(ret);
size = sizeof(*user);
size = ALIGN(size, sizeof(u16));
/* Reserve space for partial_syn, si and smu */
size += ((2 * req->ecc.strength) + 1) * sizeof(u16) *
(2 + req->ecc.strength + 2);
/* Reserve space for lmu. */
size += (req->ecc.strength + 1) * sizeof(u16);
/* Reserve space for mu, dmu and delta. */
size = ALIGN(size, sizeof(s32));
size += (req->ecc.strength + 1) * sizeof(s32);
user = kzalloc(size, GFP_KERNEL);
if (!user)
return ERR_PTR(-ENOMEM);
user->pmecc = pmecc;
user->partial_syn = (s16 *)PTR_ALIGN(user + 1, sizeof(u16));
user->si = user->partial_syn + ((2 * req->ecc.strength) + 1);
user->lmu = user->si + ((2 * req->ecc.strength) + 1);
user->smu = user->lmu + (req->ecc.strength + 1);
user->mu = (s32 *)PTR_ALIGN(user->smu +
(((2 * req->ecc.strength) + 1) *
(req->ecc.strength + 2)),
sizeof(s32));
user->dmu = user->mu + req->ecc.strength + 1;
user->delta = user->dmu + req->ecc.strength + 1;
gf_tables = atmel_pmecc_get_gf_tables(req);
if (IS_ERR(gf_tables)) {
kfree(user);
return ERR_CAST(gf_tables);
}
user->gf_tables = gf_tables;
user->eccbytes = req->ecc.bytes / req->ecc.nsectors;
for (strength = 0; strength < pmecc->caps->nstrengths; strength++) {
if (pmecc->caps->strengths[strength] == req->ecc.strength)
break;
}
user->cache.cfg = PMECC_CFG_BCH_STRENGTH(strength) |
PMECC_CFG_NSECTORS(req->ecc.nsectors);
if (req->ecc.sectorsize == 1024)
user->cache.cfg |= PMECC_CFG_SECTOR1024;
user->cache.sarea = req->oobsize - 1;
user->cache.saddr = req->ecc.ooboffset;
user->cache.eaddr = req->ecc.ooboffset + req->ecc.bytes - 1;
return user;
}
EXPORT_SYMBOL_GPL(atmel_pmecc_create_user);
void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user)
{
kfree(user);
}
EXPORT_SYMBOL_GPL(atmel_pmecc_destroy_user);
static int get_strength(struct atmel_pmecc_user *user)
{
const int *strengths = user->pmecc->caps->strengths;
return strengths[user->cache.cfg & PMECC_CFG_BCH_STRENGTH_MASK];
}
static int get_sectorsize(struct atmel_pmecc_user *user)
{
return user->cache.cfg & PMECC_LOOKUP_TABLE_SIZE_1024 ? 1024 : 512;
}
static void atmel_pmecc_gen_syndrome(struct atmel_pmecc_user *user, int sector)
{
int strength = get_strength(user);
u32 value;
int i;
/* Fill odd syndromes */
for (i = 0; i < strength; i++) {
value = readl_relaxed(user->pmecc->regs.base +
ATMEL_PMECC_REM(sector, i / 2));
if (i & 1)
value >>= 16;
user->partial_syn[(2 * i) + 1] = value;
}
}
static void atmel_pmecc_substitute(struct atmel_pmecc_user *user)
{
int degree = get_sectorsize(user) == 512 ? 13 : 14;
int cw_len = BIT(degree) - 1;
int strength = get_strength(user);
s16 *alpha_to = user->gf_tables->alpha_to;
s16 *index_of = user->gf_tables->index_of;
s16 *partial_syn = user->partial_syn;
s16 *si;
int i, j;
/*
* si[] is a table that holds the current syndrome value,
* an element of that table belongs to the field
*/
si = user->si;
memset(&si[1], 0, sizeof(s16) * ((2 * strength) - 1));
/* Computation 2t syndromes based on S(x) */
/* Odd syndromes */
for (i = 1; i < 2 * strength; i += 2) {
for (j = 0; j < degree; j++) {
if (partial_syn[i] & BIT(j))
si[i] = alpha_to[i * j] ^ si[i];
}
}
/* Even syndrome = (Odd syndrome) ** 2 */
for (i = 2, j = 1; j <= strength; i = ++j << 1) {
if (si[j] == 0) {
si[i] = 0;
} else {
s16 tmp;
tmp = index_of[si[j]];
tmp = (tmp * 2) % cw_len;
si[i] = alpha_to[tmp];
}
}
}
static void atmel_pmecc_get_sigma(struct atmel_pmecc_user *user)
{
s16 *lmu = user->lmu;
s16 *si = user->si;
s32 *mu = user->mu;
s32 *dmu = user->dmu;
s32 *delta = user->delta;
int degree = get_sectorsize(user) == 512 ? 13 : 14;
int cw_len = BIT(degree) - 1;
int strength = get_strength(user);
int num = 2 * strength + 1;
s16 *index_of = user->gf_tables->index_of;
s16 *alpha_to = user->gf_tables->alpha_to;
int i, j, k;
u32 dmu_0_count, tmp;
s16 *smu = user->smu;
/* index of largest delta */
int ro;
int largest;
int diff;
dmu_0_count = 0;
/* First Row */
/* Mu */
mu[0] = -1;
memset(smu, 0, sizeof(s16) * num);
smu[0] = 1;
/* discrepancy set to 1 */
dmu[0] = 1;
/* polynom order set to 0 */
lmu[0] = 0;
delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
/* Second Row */
/* Mu */
mu[1] = 0;
/* Sigma(x) set to 1 */
memset(&smu[num], 0, sizeof(s16) * num);
smu[num] = 1;
/* discrepancy set to S1 */
dmu[1] = si[1];
/* polynom order set to 0 */
lmu[1] = 0;
delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
/* Init the Sigma(x) last row */
memset(&smu[(strength + 1) * num], 0, sizeof(s16) * num);
for (i = 1; i <= strength; i++) {
mu[i + 1] = i << 1;
/* Begin Computing Sigma (Mu+1) and L(mu) */
/* check if discrepancy is set to 0 */
if (dmu[i] == 0) {
dmu_0_count++;
tmp = ((strength - (lmu[i] >> 1) - 1) / 2);
if ((strength - (lmu[i] >> 1) - 1) & 0x1)
tmp += 2;
else
tmp += 1;
if (dmu_0_count == tmp) {
for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
smu[(strength + 1) * num + j] =
smu[i * num + j];
lmu[strength + 1] = lmu[i];
return;
}
/* copy polynom */
for (j = 0; j <= lmu[i] >> 1; j++)
smu[(i + 1) * num + j] = smu[i * num + j];
/* copy previous polynom order to the next */
lmu[i + 1] = lmu[i];
} else {
ro = 0;
largest = -1;
/* find largest delta with dmu != 0 */
for (j = 0; j < i; j++) {
if ((dmu[j]) && (delta[j] > largest)) {
largest = delta[j];
ro = j;
}
}
/* compute difference */
diff = (mu[i] - mu[ro]);
/* Compute degree of the new smu polynomial */
if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
lmu[i + 1] = lmu[i];
else
lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
/* Init smu[i+1] with 0 */
for (k = 0; k < num; k++)
smu[(i + 1) * num + k] = 0;
/* Compute smu[i+1] */
for (k = 0; k <= lmu[ro] >> 1; k++) {
s16 a, b, c;
if (!(smu[ro * num + k] && dmu[i]))
continue;
a = index_of[dmu[i]];
b = index_of[dmu[ro]];
c = index_of[smu[ro * num + k]];
tmp = a + (cw_len - b) + c;
a = alpha_to[tmp % cw_len];
smu[(i + 1) * num + (k + diff)] = a;
}
for (k = 0; k <= lmu[i] >> 1; k++)
smu[(i + 1) * num + k] ^= smu[i * num + k];
}
/* End Computing Sigma (Mu+1) and L(mu) */
/* In either case compute delta */
delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
/* Do not compute discrepancy for the last iteration */
if (i >= strength)
continue;
for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
tmp = 2 * (i - 1);
if (k == 0) {
dmu[i + 1] = si[tmp + 3];
} else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
s16 a, b, c;
a = index_of[smu[(i + 1) * num + k]];
b = si[2 * (i - 1) + 3 - k];
c = index_of[b];
tmp = a + c;
tmp %= cw_len;
dmu[i + 1] = alpha_to[tmp] ^ dmu[i + 1];
}
}
}
}
static int atmel_pmecc_err_location(struct atmel_pmecc_user *user)
{
int sector_size = get_sectorsize(user);
int degree = sector_size == 512 ? 13 : 14;
struct atmel_pmecc *pmecc = user->pmecc;
int strength = get_strength(user);
int ret, roots_nbr, i, err_nbr = 0;
int num = (2 * strength) + 1;
s16 *smu = user->smu;
u32 val;
writel(PMERRLOC_DISABLE, pmecc->regs.errloc + ATMEL_PMERRLOC_ELDIS);
for (i = 0; i <= user->lmu[strength + 1] >> 1; i++) {
writel_relaxed(smu[(strength + 1) * num + i],
pmecc->regs.errloc + ATMEL_PMERRLOC_SIGMA(i));
err_nbr++;
}
val = (err_nbr - 1) << 16;
if (sector_size == 1024)
val |= 1;
writel(val, pmecc->regs.errloc + ATMEL_PMERRLOC_ELCFG);
writel((sector_size * 8) + (degree * strength),
pmecc->regs.errloc + ATMEL_PMERRLOC_ELEN);
ret = readl_relaxed_poll_timeout(pmecc->regs.errloc +
ATMEL_PMERRLOC_ELISR,
val, val & PMERRLOC_CALC_DONE, 0,
PMECC_MAX_TIMEOUT_MS * 1000);
if (ret) {
dev_err(pmecc->dev,
"PMECC: Timeout to calculate error location.\n");
return ret;
}
roots_nbr = (val & PMERRLOC_ERR_NUM_MASK) >> 8;
/* Number of roots == degree of smu hence <= cap */
if (roots_nbr == user->lmu[strength + 1] >> 1)
return err_nbr - 1;
/*
* Number of roots does not match the degree of smu
* unable to correct error.
*/
return -EBADMSG;
}
int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
void *data, void *ecc)
{
struct atmel_pmecc *pmecc = user->pmecc;
int sectorsize = get_sectorsize(user);
int eccbytes = user->eccbytes;
int i, nerrors;
if (!(user->isr & BIT(sector)))
return 0;
atmel_pmecc_gen_syndrome(user, sector);
atmel_pmecc_substitute(user);
atmel_pmecc_get_sigma(user);
nerrors = atmel_pmecc_err_location(user);
if (nerrors < 0)
return nerrors;
for (i = 0; i < nerrors; i++) {
const char *area;
int byte, bit;
u32 errpos;
u8 *ptr;
errpos = readl_relaxed(pmecc->regs.errloc +
ATMEL_PMERRLOC_EL(pmecc->caps->el_offset, i));
errpos--;
byte = errpos / 8;
bit = errpos % 8;
if (byte < sectorsize) {
ptr = data + byte;
area = "data";
} else if (byte < sectorsize + eccbytes) {
ptr = ecc + byte - sectorsize;
area = "ECC";
} else {
dev_dbg(pmecc->dev,
"Invalid errpos value (%d, max is %d)\n",
errpos, (sectorsize + eccbytes) * 8);
return -EINVAL;
}
dev_dbg(pmecc->dev,
"Bit flip in %s area, byte %d: 0x%02x -> 0x%02x\n",
area, byte, *ptr, (unsigned int)(*ptr ^ BIT(bit)));
*ptr ^= BIT(bit);
}
return nerrors;
}
EXPORT_SYMBOL_GPL(atmel_pmecc_correct_sector);
bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user)
{
return user->pmecc->caps->correct_erased_chunks;
}
EXPORT_SYMBOL_GPL(atmel_pmecc_correct_erased_chunks);
void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
int sector, void *ecc)
{
struct atmel_pmecc *pmecc = user->pmecc;
u8 *ptr = ecc;
int i;
for (i = 0; i < user->eccbytes; i++)
ptr[i] = readb_relaxed(pmecc->regs.base +
ATMEL_PMECC_ECC(sector, i));
}
EXPORT_SYMBOL_GPL(atmel_pmecc_get_generated_eccbytes);
int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op)
{
struct atmel_pmecc *pmecc = user->pmecc;
u32 cfg;
if (op != NAND_ECC_READ && op != NAND_ECC_WRITE) {
dev_err(pmecc->dev, "Bad ECC operation!");
return -EINVAL;
}
mutex_lock(&user->pmecc->lock);
cfg = user->cache.cfg;
if (op == NAND_ECC_WRITE)
cfg |= PMECC_CFG_WRITE_OP;
else
cfg |= PMECC_CFG_AUTO_ENABLE;
writel(cfg, pmecc->regs.base + ATMEL_PMECC_CFG);
writel(user->cache.sarea, pmecc->regs.base + ATMEL_PMECC_SAREA);
writel(user->cache.saddr, pmecc->regs.base + ATMEL_PMECC_SADDR);
writel(user->cache.eaddr, pmecc->regs.base + ATMEL_PMECC_EADDR);
writel(PMECC_CTRL_ENABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
writel(PMECC_CTRL_DATA, pmecc->regs.base + ATMEL_PMECC_CTRL);
return 0;
}
EXPORT_SYMBOL_GPL(atmel_pmecc_enable);
void atmel_pmecc_disable(struct atmel_pmecc_user *user)
{
struct atmel_pmecc *pmecc = user->pmecc;
writel(PMECC_CTRL_RST, pmecc->regs.base + ATMEL_PMECC_CTRL);
writel(PMECC_CTRL_DISABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
mutex_unlock(&user->pmecc->lock);
}
EXPORT_SYMBOL_GPL(atmel_pmecc_disable);
int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user)
{
struct atmel_pmecc *pmecc = user->pmecc;
u32 status;
int ret;
ret = readl_relaxed_poll_timeout(pmecc->regs.base +
ATMEL_PMECC_SR,
status, !(status & PMECC_SR_BUSY), 0,
PMECC_MAX_TIMEOUT_MS * 1000);
if (ret) {
dev_err(pmecc->dev,
"Timeout while waiting for PMECC ready.\n");
return ret;
}
user->isr = readl_relaxed(pmecc->regs.base + ATMEL_PMECC_ISR);
return 0;
}
EXPORT_SYMBOL_GPL(atmel_pmecc_wait_rdy);
static struct atmel_pmecc *atmel_pmecc_create(struct platform_device *pdev,
const struct atmel_pmecc_caps *caps,
int pmecc_res_idx, int errloc_res_idx)
{
struct device *dev = &pdev->dev;
struct atmel_pmecc *pmecc;
struct resource *res;
pmecc = devm_kzalloc(dev, sizeof(*pmecc), GFP_KERNEL);
if (!pmecc)
return ERR_PTR(-ENOMEM);
pmecc->caps = caps;
pmecc->dev = dev;
mutex_init(&pmecc->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, pmecc_res_idx);
pmecc->regs.base = devm_ioremap_resource(dev, res);
if (IS_ERR(pmecc->regs.base))
return ERR_CAST(pmecc->regs.base);
res = platform_get_resource(pdev, IORESOURCE_MEM, errloc_res_idx);
pmecc->regs.errloc = devm_ioremap_resource(dev, res);
if (IS_ERR(pmecc->regs.errloc))
return ERR_CAST(pmecc->regs.errloc);
/* Disable all interrupts before registering the PMECC handler. */
writel(0xffffffff, pmecc->regs.base + ATMEL_PMECC_IDR);
/* Reset the ECC engine */
writel(PMECC_CTRL_RST, pmecc->regs.base + ATMEL_PMECC_CTRL);
writel(PMECC_CTRL_DISABLE, pmecc->regs.base + ATMEL_PMECC_CTRL);
return pmecc;
}
static void devm_atmel_pmecc_put(struct device *dev, void *res)
{
struct atmel_pmecc **pmecc = res;
put_device((*pmecc)->dev);
}
static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev,
struct device_node *np)
{
struct platform_device *pdev;
struct atmel_pmecc *pmecc, **ptr;
pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev))
return ERR_PTR(-EPROBE_DEFER);
ptr = devres_alloc(devm_atmel_pmecc_put, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
get_device(&pdev->dev);
pmecc = platform_get_drvdata(pdev);
*ptr = pmecc;
devres_add(userdev, ptr);
return pmecc;
}
static const int atmel_pmecc_strengths[] = { 2, 4, 8, 12, 24, 32 };
static struct atmel_pmecc_caps at91sam9g45_caps = {
.strengths = atmel_pmecc_strengths,
.nstrengths = 5,
.el_offset = 0x8c,
};
static struct atmel_pmecc_caps sama5d4_caps = {
.strengths = atmel_pmecc_strengths,
.nstrengths = 5,
.el_offset = 0x8c,
.correct_erased_chunks = true,
};
static struct atmel_pmecc_caps sama5d2_caps = {
.strengths = atmel_pmecc_strengths,
.nstrengths = 6,
.el_offset = 0xac,
.correct_erased_chunks = true,
};
static const struct of_device_id atmel_pmecc_legacy_match[] = {
{ .compatible = "atmel,sama5d4-nand", &sama5d4_caps },
{ .compatible = "atmel,sama5d2-nand", &sama5d2_caps },
{ /* sentinel */ }
};
struct atmel_pmecc *devm_atmel_pmecc_get(struct device *userdev)
{
struct atmel_pmecc *pmecc;
struct device_node *np;
if (!userdev)
return ERR_PTR(-EINVAL);
if (!userdev->of_node)
return NULL;
np = of_parse_phandle(userdev->of_node, "ecc-engine", 0);
if (np) {
pmecc = atmel_pmecc_get_by_node(userdev, np);
of_node_put(np);
} else {
/*
* Support old DT bindings: in this case the PMECC iomem
* resources are directly defined in the user pdev at position
* 1 and 2. Extract all relevant information from there.
*/
struct platform_device *pdev = to_platform_device(userdev);
const struct atmel_pmecc_caps *caps;
/* No PMECC engine available. */
if (!of_property_read_bool(userdev->of_node,
"atmel,has-pmecc"))
return NULL;
caps = &at91sam9g45_caps;
/*
* Try to find the NFC subnode and extract the associated caps
* from there.
*/
np = of_find_compatible_node(userdev->of_node, NULL,
"atmel,sama5d3-nfc");
if (np) {
const struct of_device_id *match;
match = of_match_node(atmel_pmecc_legacy_match, np);
if (match && match->data)
caps = match->data;
of_node_put(np);
}
pmecc = atmel_pmecc_create(pdev, caps, 1, 2);
}
return pmecc;
}
EXPORT_SYMBOL(devm_atmel_pmecc_get);
static const struct of_device_id atmel_pmecc_match[] = {
{ .compatible = "atmel,at91sam9g45-pmecc", &at91sam9g45_caps },
{ .compatible = "atmel,sama5d4-pmecc", &sama5d4_caps },
{ .compatible = "atmel,sama5d2-pmecc", &sama5d2_caps },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_pmecc_match);
static int atmel_pmecc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct atmel_pmecc_caps *caps;
struct atmel_pmecc *pmecc;
caps = of_device_get_match_data(&pdev->dev);
if (!caps) {
dev_err(dev, "Invalid caps\n");
return -EINVAL;
}
pmecc = atmel_pmecc_create(pdev, caps, 0, 1);
if (IS_ERR(pmecc))
return PTR_ERR(pmecc);
platform_set_drvdata(pdev, pmecc);
return 0;
}
static struct platform_driver atmel_pmecc_driver = {
.driver = {
.name = "atmel-pmecc",
.of_match_table = of_match_ptr(atmel_pmecc_match),
},
.probe = atmel_pmecc_probe,
};
module_platform_driver(atmel_pmecc_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
MODULE_DESCRIPTION("PMECC engine driver");
MODULE_ALIAS("platform:atmel_pmecc");
/*
* © Copyright 2016 ATMEL
* © Copyright 2016 Free Electrons
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* Derived from the atmel_nand.c driver which contained the following
* copyrights:
*
* Copyright © 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
* Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
* Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
*
*
* Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
* Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007
*
* Derived from Das U-Boot source code
* (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
* © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
*
* Add Programmable Multibit ECC support for various AT91 SoC
* © Copyright 2012 ATMEL, Hong Xu
*
* Add Nand Flash Controller support for SAMA5 SoC
* © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef ATMEL_PMECC_H
#define ATMEL_PMECC_H
#define ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH 0
#define ATMEL_PMECC_SECTOR_SIZE_AUTO 0
#define ATMEL_PMECC_OOBOFFSET_AUTO -1
struct atmel_pmecc_user_req {
int pagesize;
int oobsize;
struct {
int strength;
int bytes;
int sectorsize;
int nsectors;
int ooboffset;
} ecc;
};
struct atmel_pmecc *devm_atmel_pmecc_get(struct device *dev);
struct atmel_pmecc_user *
atmel_pmecc_create_user(struct atmel_pmecc *pmecc,
struct atmel_pmecc_user_req *req);
void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user);
int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op);
void atmel_pmecc_disable(struct atmel_pmecc_user *user);
int atmel_pmecc_wait_rdy(struct atmel_pmecc_user *user);
int atmel_pmecc_correct_sector(struct atmel_pmecc_user *user, int sector,
void *data, void *ecc);
bool atmel_pmecc_correct_erased_chunks(struct atmel_pmecc_user *user);
void atmel_pmecc_get_generated_eccbytes(struct atmel_pmecc_user *user,
int sector, void *ecc);
#endif /* ATMEL_PMECC_H */
/*
* Copyright © 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
* Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
* Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
*
*
* Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
* Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007
*
* Derived from Das U-Boot source code
* (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
* © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
*
* Add Programmable Multibit ECC support for various AT91 SoC
* © Copyright 2012 ATMEL, Hong Xu
*
* Add Nand Flash Controller support for SAMA5 SoC
* © Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_data/atmel.h>
static int use_dma = 1;
module_param(use_dma, int, 0);
static int on_flash_bbt = 0;
module_param(on_flash_bbt, int, 0);
/* Register access macros */
#define ecc_readl(add, reg) \
__raw_readl(add + ATMEL_ECC_##reg)
#define ecc_writel(add, reg, value) \
__raw_writel((value), add + ATMEL_ECC_##reg)
#include "atmel_nand_ecc.h" /* Hardware ECC registers */
#include "atmel_nand_nfc.h" /* Nand Flash Controller definition */
struct atmel_nand_caps {
bool pmecc_correct_erase_page;
uint8_t pmecc_max_correction;
};
/*
* oob layout for large page size
* bad block info is on bytes 0 and 1
* the bytes have to be consecutives to avoid
* several NAND_CMD_RNDOUT during read
*
* oob layout for small page size
* bad block info is on bytes 4 and 5
* the bytes have to be consecutives to avoid
* several NAND_CMD_RNDOUT during read
*/
static int atmel_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section)
return -ERANGE;
oobregion->length = 4;
oobregion->offset = 0;
return 0;
}
static int atmel_ooblayout_free_sp(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section)
return -ERANGE;
oobregion->offset = 6;
oobregion->length = mtd->oobsize - oobregion->offset;
return 0;
}
static const struct mtd_ooblayout_ops atmel_ooblayout_sp_ops = {
.ecc = atmel_ooblayout_ecc_sp,
.free = atmel_ooblayout_free_sp,
};
struct atmel_nfc {
void __iomem *base_cmd_regs;
void __iomem *hsmc_regs;
void *sram_bank0;
dma_addr_t sram_bank0_phys;
bool use_nfc_sram;
bool write_by_sram;
struct clk *clk;
bool is_initialized;
struct completion comp_ready;
struct completion comp_cmd_done;
struct completion comp_xfer_done;
/* Point to the sram bank which include readed data via NFC */
void *data_in_sram;
bool will_write_sram;
};
static struct atmel_nfc nand_nfc;
struct atmel_nand_host {
struct nand_chip nand_chip;
void __iomem *io_base;
dma_addr_t io_phys;
struct atmel_nand_data board;
struct device *dev;
void __iomem *ecc;
struct completion comp;
struct dma_chan *dma_chan;
struct atmel_nfc *nfc;
const struct atmel_nand_caps *caps;
bool has_pmecc;
u8 pmecc_corr_cap;
u16 pmecc_sector_size;
bool has_no_lookup_table;
u32 pmecc_lookup_table_offset;
u32 pmecc_lookup_table_offset_512;
u32 pmecc_lookup_table_offset_1024;
int pmecc_degree; /* Degree of remainders */
int pmecc_cw_len; /* Length of codeword */
void __iomem *pmerrloc_base;
void __iomem *pmerrloc_el_base;
void __iomem *pmecc_rom_base;
/* lookup table for alpha_to and index_of */
void __iomem *pmecc_alpha_to;
void __iomem *pmecc_index_of;
/* data for pmecc computation */
int16_t *pmecc_partial_syn;
int16_t *pmecc_si;
int16_t *pmecc_smu; /* Sigma table */
int16_t *pmecc_lmu; /* polynomal order */
int *pmecc_mu;
int *pmecc_dmu;
int *pmecc_delta;
};
/*
* Enable NAND.
*/
static void atmel_nand_enable(struct atmel_nand_host *host)
{
if (gpio_is_valid(host->board.enable_pin))
gpio_set_value(host->board.enable_pin, 0);
}
/*
* Disable NAND.
*/
static void atmel_nand_disable(struct atmel_nand_host *host)
{
if (gpio_is_valid(host->board.enable_pin))
gpio_set_value(host->board.enable_pin, 1);
}
/*
* Hardware specific access to control-lines
*/
static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_NCE)
atmel_nand_enable(host);
else
atmel_nand_disable(host);
}
if (cmd == NAND_CMD_NONE)
return;
if (ctrl & NAND_CLE)
writeb(cmd, host->io_base + (1 << host->board.cle));
else
writeb(cmd, host->io_base + (1 << host->board.ale));
}
/*
* Read the Device Ready pin.
*/
static int atmel_nand_device_ready(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
return gpio_get_value(host->board.rdy_pin) ^
!!host->board.rdy_pin_active_low;
}
/* Set up for hardware ready pin and enable pin. */
static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(chip);
int res = 0;
if (gpio_is_valid(host->board.rdy_pin)) {
res = devm_gpio_request(host->dev,
host->board.rdy_pin, "nand_rdy");
if (res < 0) {
dev_err(host->dev,
"can't request rdy gpio %d\n",
host->board.rdy_pin);
return res;
}
res = gpio_direction_input(host->board.rdy_pin);
if (res < 0) {
dev_err(host->dev,
"can't request input direction rdy gpio %d\n",
host->board.rdy_pin);
return res;
}
chip->dev_ready = atmel_nand_device_ready;
}
if (gpio_is_valid(host->board.enable_pin)) {
res = devm_gpio_request(host->dev,
host->board.enable_pin, "nand_enable");
if (res < 0) {
dev_err(host->dev,
"can't request enable gpio %d\n",
host->board.enable_pin);
return res;
}
res = gpio_direction_output(host->board.enable_pin, 1);
if (res < 0) {
dev_err(host->dev,
"can't request output direction enable gpio %d\n",
host->board.enable_pin);
return res;
}
}
return res;
}
/*
* Minimal-overhead PIO for data access.
*/
static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
memcpy(buf, host->nfc->data_in_sram, len);
host->nfc->data_in_sram += len;
} else {
__raw_readsb(nand_chip->IO_ADDR_R, buf, len);
}
}
static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
memcpy(buf, host->nfc->data_in_sram, len);
host->nfc->data_in_sram += len;
} else {
__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
}
}
static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
__raw_writesb(nand_chip->IO_ADDR_W, buf, len);
}
static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
__raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2);
}
static void dma_complete_func(void *completion)
{
complete(completion);
}
static int nfc_set_sram_bank(struct atmel_nand_host *host, unsigned int bank)
{
/* NFC only has two banks. Must be 0 or 1 */
if (bank > 1)
return -EINVAL;
if (bank) {
struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
/* Only for a 2k-page or lower flash, NFC can handle 2 banks */
if (mtd->writesize > 2048)
return -EINVAL;
nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK1);
} else {
nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK0);
}
return 0;
}
static uint nfc_get_sram_off(struct atmel_nand_host *host)
{
if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
return NFC_SRAM_BANK1_OFFSET;
else
return 0;
}
static dma_addr_t nfc_sram_phys(struct atmel_nand_host *host)
{
if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
return host->nfc->sram_bank0_phys + NFC_SRAM_BANK1_OFFSET;
else
return host->nfc->sram_bank0_phys;
}
static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
int is_read)
{
struct dma_device *dma_dev;
enum dma_ctrl_flags flags;
dma_addr_t dma_src_addr, dma_dst_addr, phys_addr;
struct dma_async_tx_descriptor *tx = NULL;
dma_cookie_t cookie;
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(chip);
void *p = buf;
int err = -EIO;
enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
struct atmel_nfc *nfc = host->nfc;
if (buf >= high_memory)
goto err_buf;
dma_dev = host->dma_chan->device;
flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
phys_addr = dma_map_single(dma_dev->dev, p, len, dir);
if (dma_mapping_error(dma_dev->dev, phys_addr)) {
dev_err(host->dev, "Failed to dma_map_single\n");
goto err_buf;
}
if (is_read) {
if (nfc && nfc->data_in_sram)
dma_src_addr = nfc_sram_phys(host) + (nfc->data_in_sram
- (nfc->sram_bank0 + nfc_get_sram_off(host)));
else
dma_src_addr = host->io_phys;
dma_dst_addr = phys_addr;
} else {
dma_src_addr = phys_addr;
if (nfc && nfc->write_by_sram)
dma_dst_addr = nfc_sram_phys(host);
else
dma_dst_addr = host->io_phys;
}
tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,
dma_src_addr, len, flags);
if (!tx) {
dev_err(host->dev, "Failed to prepare DMA memcpy\n");
goto err_dma;
}
init_completion(&host->comp);
tx->callback = dma_complete_func;
tx->callback_param = &host->comp;
cookie = tx->tx_submit(tx);
if (dma_submit_error(cookie)) {
dev_err(host->dev, "Failed to do DMA tx_submit\n");
goto err_dma;
}
dma_async_issue_pending(host->dma_chan);
wait_for_completion(&host->comp);
if (is_read && nfc && nfc->data_in_sram)
/* After read data from SRAM, need to increase the position */
nfc->data_in_sram += len;
err = 0;
err_dma:
dma_unmap_single(dma_dev->dev, phys_addr, len, dir);
err_buf:
if (err != 0)
dev_dbg(host->dev, "Fall back to CPU I/O\n");
return err;
}
static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if (use_dma && len > mtd->oobsize)
/* only use DMA for bigger than oob size: better performances */
if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)
return;
if (chip->options & NAND_BUSWIDTH_16)
atmel_read_buf16(mtd, buf, len);
else
atmel_read_buf8(mtd, buf, len);
}
static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if (use_dma && len > mtd->oobsize)
/* only use DMA for bigger than oob size: better performances */
if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)
return;
if (chip->options & NAND_BUSWIDTH_16)
atmel_write_buf16(mtd, buf, len);
else
atmel_write_buf8(mtd, buf, len);
}
/*
* Return number of ecc bytes per sector according to sector size and
* correction capability
*
* Following table shows what at91 PMECC supported:
* Correction Capability Sector_512_bytes Sector_1024_bytes
* ===================== ================ =================
* 2-bits 4-bytes 4-bytes
* 4-bits 7-bytes 7-bytes
* 8-bits 13-bytes 14-bytes
* 12-bits 20-bytes 21-bytes
* 24-bits 39-bytes 42-bytes
* 32-bits 52-bytes 56-bytes
*/
static int pmecc_get_ecc_bytes(int cap, int sector_size)
{
int m = 12 + sector_size / 512;
return (m * cap + 7) / 8;
}
static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
{
int table_size;
table_size = host->pmecc_sector_size == 512 ?
PMECC_LOOKUP_TABLE_SIZE_512 : PMECC_LOOKUP_TABLE_SIZE_1024;
return host->pmecc_rom_base + host->pmecc_lookup_table_offset +
table_size * sizeof(int16_t);
}
static int pmecc_data_alloc(struct atmel_nand_host *host)
{
const int cap = host->pmecc_corr_cap;
int size;
size = (2 * cap + 1) * sizeof(int16_t);
host->pmecc_partial_syn = devm_kzalloc(host->dev, size, GFP_KERNEL);
host->pmecc_si = devm_kzalloc(host->dev, size, GFP_KERNEL);
host->pmecc_lmu = devm_kzalloc(host->dev,
(cap + 1) * sizeof(int16_t), GFP_KERNEL);
host->pmecc_smu = devm_kzalloc(host->dev,
(cap + 2) * size, GFP_KERNEL);
size = (cap + 1) * sizeof(int);
host->pmecc_mu = devm_kzalloc(host->dev, size, GFP_KERNEL);
host->pmecc_dmu = devm_kzalloc(host->dev, size, GFP_KERNEL);
host->pmecc_delta = devm_kzalloc(host->dev, size, GFP_KERNEL);
if (!host->pmecc_partial_syn ||
!host->pmecc_si ||
!host->pmecc_lmu ||
!host->pmecc_smu ||
!host->pmecc_mu ||
!host->pmecc_dmu ||
!host->pmecc_delta)
return -ENOMEM;
return 0;
}
static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int i;
uint32_t value;
/* Fill odd syndromes */
for (i = 0; i < host->pmecc_corr_cap; i++) {
value = pmecc_readl_rem_relaxed(host->ecc, sector, i / 2);
if (i & 1)
value >>= 16;
value &= 0xffff;
host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value;
}
}
static void pmecc_substitute(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int16_t __iomem *alpha_to = host->pmecc_alpha_to;
int16_t __iomem *index_of = host->pmecc_index_of;
int16_t *partial_syn = host->pmecc_partial_syn;
const int cap = host->pmecc_corr_cap;
int16_t *si;
int i, j;
/* si[] is a table that holds the current syndrome value,
* an element of that table belongs to the field
*/
si = host->pmecc_si;
memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1));
/* Computation 2t syndromes based on S(x) */
/* Odd syndromes */
for (i = 1; i < 2 * cap; i += 2) {
for (j = 0; j < host->pmecc_degree; j++) {
if (partial_syn[i] & ((unsigned short)0x1 << j))
si[i] = readw_relaxed(alpha_to + i * j) ^ si[i];
}
}
/* Even syndrome = (Odd syndrome) ** 2 */
for (i = 2, j = 1; j <= cap; i = ++j << 1) {
if (si[j] == 0) {
si[i] = 0;
} else {
int16_t tmp;
tmp = readw_relaxed(index_of + si[j]);
tmp = (tmp * 2) % host->pmecc_cw_len;
si[i] = readw_relaxed(alpha_to + tmp);
}
}
return;
}
static void pmecc_get_sigma(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int16_t *lmu = host->pmecc_lmu;
int16_t *si = host->pmecc_si;
int *mu = host->pmecc_mu;
int *dmu = host->pmecc_dmu; /* Discrepancy */
int *delta = host->pmecc_delta; /* Delta order */
int cw_len = host->pmecc_cw_len;
const int16_t cap = host->pmecc_corr_cap;
const int num = 2 * cap + 1;
int16_t __iomem *index_of = host->pmecc_index_of;
int16_t __iomem *alpha_to = host->pmecc_alpha_to;
int i, j, k;
uint32_t dmu_0_count, tmp;
int16_t *smu = host->pmecc_smu;
/* index of largest delta */
int ro;
int largest;
int diff;
dmu_0_count = 0;
/* First Row */
/* Mu */
mu[0] = -1;
memset(smu, 0, sizeof(int16_t) * num);
smu[0] = 1;
/* discrepancy set to 1 */
dmu[0] = 1;
/* polynom order set to 0 */
lmu[0] = 0;
delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
/* Second Row */
/* Mu */
mu[1] = 0;
/* Sigma(x) set to 1 */
memset(&smu[num], 0, sizeof(int16_t) * num);
smu[num] = 1;
/* discrepancy set to S1 */
dmu[1] = si[1];
/* polynom order set to 0 */
lmu[1] = 0;
delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
/* Init the Sigma(x) last row */
memset(&smu[(cap + 1) * num], 0, sizeof(int16_t) * num);
for (i = 1; i <= cap; i++) {
mu[i + 1] = i << 1;
/* Begin Computing Sigma (Mu+1) and L(mu) */
/* check if discrepancy is set to 0 */
if (dmu[i] == 0) {
dmu_0_count++;
tmp = ((cap - (lmu[i] >> 1) - 1) / 2);
if ((cap - (lmu[i] >> 1) - 1) & 0x1)
tmp += 2;
else
tmp += 1;
if (dmu_0_count == tmp) {
for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
smu[(cap + 1) * num + j] =
smu[i * num + j];
lmu[cap + 1] = lmu[i];
return;
}
/* copy polynom */
for (j = 0; j <= lmu[i] >> 1; j++)
smu[(i + 1) * num + j] = smu[i * num + j];
/* copy previous polynom order to the next */
lmu[i + 1] = lmu[i];
} else {
ro = 0;
largest = -1;
/* find largest delta with dmu != 0 */
for (j = 0; j < i; j++) {
if ((dmu[j]) && (delta[j] > largest)) {
largest = delta[j];
ro = j;
}
}
/* compute difference */
diff = (mu[i] - mu[ro]);
/* Compute degree of the new smu polynomial */
if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
lmu[i + 1] = lmu[i];
else
lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
/* Init smu[i+1] with 0 */
for (k = 0; k < num; k++)
smu[(i + 1) * num + k] = 0;
/* Compute smu[i+1] */
for (k = 0; k <= lmu[ro] >> 1; k++) {
int16_t a, b, c;
if (!(smu[ro * num + k] && dmu[i]))
continue;
a = readw_relaxed(index_of + dmu[i]);
b = readw_relaxed(index_of + dmu[ro]);
c = readw_relaxed(index_of + smu[ro * num + k]);
tmp = a + (cw_len - b) + c;
a = readw_relaxed(alpha_to + tmp % cw_len);
smu[(i + 1) * num + (k + diff)] = a;
}
for (k = 0; k <= lmu[i] >> 1; k++)
smu[(i + 1) * num + k] ^= smu[i * num + k];
}
/* End Computing Sigma (Mu+1) and L(mu) */
/* In either case compute delta */
delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
/* Do not compute discrepancy for the last iteration */
if (i >= cap)
continue;
for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
tmp = 2 * (i - 1);
if (k == 0) {
dmu[i + 1] = si[tmp + 3];
} else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
int16_t a, b, c;
a = readw_relaxed(index_of +
smu[(i + 1) * num + k]);
b = si[2 * (i - 1) + 3 - k];
c = readw_relaxed(index_of + b);
tmp = a + c;
tmp %= cw_len;
dmu[i + 1] = readw_relaxed(alpha_to + tmp) ^
dmu[i + 1];
}
}
}
return;
}
static int pmecc_err_location(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
unsigned long end_time;
const int cap = host->pmecc_corr_cap;
const int num = 2 * cap + 1;
int sector_size = host->pmecc_sector_size;
int err_nbr = 0; /* number of error */
int roots_nbr; /* number of roots */
int i;
uint32_t val;
int16_t *smu = host->pmecc_smu;
pmerrloc_writel(host->pmerrloc_base, ELDIS, PMERRLOC_DISABLE);
for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) {
pmerrloc_writel_sigma_relaxed(host->pmerrloc_base, i,
smu[(cap + 1) * num + i]);
err_nbr++;
}
val = (err_nbr - 1) << 16;
if (sector_size == 1024)
val |= 1;
pmerrloc_writel(host->pmerrloc_base, ELCFG, val);
pmerrloc_writel(host->pmerrloc_base, ELEN,
sector_size * 8 + host->pmecc_degree * cap);
end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
while (!(pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
& PMERRLOC_CALC_DONE)) {
if (unlikely(time_after(jiffies, end_time))) {
dev_err(host->dev, "PMECC: Timeout to calculate error location.\n");
return -1;
}
cpu_relax();
}
roots_nbr = (pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
& PMERRLOC_ERR_NUM_MASK) >> 8;
/* Number of roots == degree of smu hence <= cap */
if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1)
return err_nbr - 1;
/* Number of roots does not match the degree of smu
* unable to correct error */
return -1;
}
static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
int sector_num, int extra_bytes, int err_nbr)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int i = 0;
int byte_pos, bit_pos, sector_size, pos;
uint32_t tmp;
uint8_t err_byte;
sector_size = host->pmecc_sector_size;
while (err_nbr) {
tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_el_base, i) - 1;
byte_pos = tmp / 8;
bit_pos = tmp % 8;
if (byte_pos >= (sector_size + extra_bytes))
BUG(); /* should never happen */
if (byte_pos < sector_size) {
err_byte = *(buf + byte_pos);
*(buf + byte_pos) ^= (1 << bit_pos);
pos = sector_num * host->pmecc_sector_size + byte_pos;
dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
pos, bit_pos, err_byte, *(buf + byte_pos));
} else {
struct mtd_oob_region oobregion;
/* Bit flip in OOB area */
tmp = sector_num * nand_chip->ecc.bytes
+ (byte_pos - sector_size);
err_byte = ecc[tmp];
ecc[tmp] ^= (1 << bit_pos);
mtd_ooblayout_ecc(mtd, 0, &oobregion);
pos = tmp + oobregion.offset;
dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
pos, bit_pos, err_byte, ecc[tmp]);
}
i++;
err_nbr--;
}
return;
}
static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
u8 *ecc)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int i, err_nbr;
uint8_t *buf_pos;
int max_bitflips = 0;
for (i = 0; i < nand_chip->ecc.steps; i++) {
err_nbr = 0;
if (pmecc_stat & 0x1) {
buf_pos = buf + i * host->pmecc_sector_size;
pmecc_gen_syndrome(mtd, i);
pmecc_substitute(mtd);
pmecc_get_sigma(mtd);
err_nbr = pmecc_err_location(mtd);
if (err_nbr >= 0) {
pmecc_correct_data(mtd, buf_pos, ecc, i,
nand_chip->ecc.bytes,
err_nbr);
} else if (!host->caps->pmecc_correct_erase_page) {
u8 *ecc_pos = ecc + (i * nand_chip->ecc.bytes);
/* Try to detect erased pages */
err_nbr = nand_check_erased_ecc_chunk(buf_pos,
host->pmecc_sector_size,
ecc_pos,
nand_chip->ecc.bytes,
NULL, 0,
nand_chip->ecc.strength);
}
if (err_nbr < 0) {
dev_err(host->dev, "PMECC: Too many errors\n");
mtd->ecc_stats.failed++;
return -EIO;
}
mtd->ecc_stats.corrected += err_nbr;
max_bitflips = max_t(int, max_bitflips, err_nbr);
}
pmecc_stat >>= 1;
}
return max_bitflips;
}
static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
{
u32 val;
if (ecc_op != NAND_ECC_READ && ecc_op != NAND_ECC_WRITE) {
dev_err(host->dev, "atmel_nand: wrong pmecc operation type!");
return;
}
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
val = pmecc_readl_relaxed(host->ecc, CFG);
if (ecc_op == NAND_ECC_READ)
pmecc_writel(host->ecc, CFG, (val & ~PMECC_CFG_WRITE_OP)
| PMECC_CFG_AUTO_ENABLE);
else
pmecc_writel(host->ecc, CFG, (val | PMECC_CFG_WRITE_OP)
& ~PMECC_CFG_AUTO_ENABLE);
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
}
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
{
struct atmel_nand_host *host = nand_get_controller_data(chip);
int eccsize = chip->ecc.size * chip->ecc.steps;
uint8_t *oob = chip->oob_poi;
uint32_t stat;
unsigned long end_time;
int bitflips = 0;
if (!host->nfc || !host->nfc->use_nfc_sram)
pmecc_enable(host, NAND_ECC_READ);
chip->read_buf(mtd, buf, eccsize);
chip->read_buf(mtd, oob, mtd->oobsize);
end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
if (unlikely(time_after(jiffies, end_time))) {
dev_err(host->dev, "PMECC: Timeout to get error status.\n");
return -EIO;
}
cpu_relax();
}
stat = pmecc_readl_relaxed(host->ecc, ISR);
if (stat != 0) {
struct mtd_oob_region oobregion;
mtd_ooblayout_ecc(mtd, 0, &oobregion);
bitflips = pmecc_correction(mtd, stat, buf,
&oob[oobregion.offset]);
if (bitflips < 0)
/* uncorrectable errors */
return 0;
}
return bitflips;
}
static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required,
int page)
{
struct atmel_nand_host *host = nand_get_controller_data(chip);
struct mtd_oob_region oobregion = { };
int i, j, section = 0;
unsigned long end_time;
if (!host->nfc || !host->nfc->write_by_sram) {
pmecc_enable(host, NAND_ECC_WRITE);
chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
}
end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
if (unlikely(time_after(jiffies, end_time))) {
dev_err(host->dev, "PMECC: Timeout to get ECC value.\n");
return -EIO;
}
cpu_relax();
}
for (i = 0; i < chip->ecc.steps; i++) {
for (j = 0; j < chip->ecc.bytes; j++) {
if (!oobregion.length)
mtd_ooblayout_ecc(mtd, section, &oobregion);
chip->oob_poi[oobregion.offset] =
pmecc_readb_ecc_relaxed(host->ecc, i, j);
oobregion.length--;
oobregion.offset++;
section++;
}
}
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
static void atmel_pmecc_core_init(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
int eccbytes = mtd_ooblayout_count_eccbytes(mtd);
uint32_t val = 0;
struct mtd_oob_region oobregion;
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
switch (host->pmecc_corr_cap) {
case 2:
val = PMECC_CFG_BCH_ERR2;
break;
case 4:
val = PMECC_CFG_BCH_ERR4;
break;
case 8:
val = PMECC_CFG_BCH_ERR8;
break;
case 12:
val = PMECC_CFG_BCH_ERR12;
break;
case 24:
val = PMECC_CFG_BCH_ERR24;
break;
case 32:
val = PMECC_CFG_BCH_ERR32;
break;
}
if (host->pmecc_sector_size == 512)
val |= PMECC_CFG_SECTOR512;
else if (host->pmecc_sector_size == 1024)
val |= PMECC_CFG_SECTOR1024;
switch (nand_chip->ecc.steps) {
case 1:
val |= PMECC_CFG_PAGE_1SECTOR;
break;
case 2:
val |= PMECC_CFG_PAGE_2SECTORS;
break;
case 4:
val |= PMECC_CFG_PAGE_4SECTORS;
break;
case 8:
val |= PMECC_CFG_PAGE_8SECTORS;
break;
}
val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE
| PMECC_CFG_AUTO_DISABLE);
pmecc_writel(host->ecc, CFG, val);
pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
mtd_ooblayout_ecc(mtd, 0, &oobregion);
pmecc_writel(host->ecc, SADDR, oobregion.offset);
pmecc_writel(host->ecc, EADDR,
oobregion.offset + eccbytes - 1);
/* See datasheet about PMECC Clock Control Register */
pmecc_writel(host->ecc, CLK, 2);
pmecc_writel(host->ecc, IDR, 0xff);
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
}
/*
* Get minimum ecc requirements from NAND.
* If pmecc-cap, pmecc-sector-size in DTS are not specified, this function
* will set them according to minimum ecc requirement. Otherwise, use the
* value in DTS file.
* return 0 if success. otherwise return error code.
*/
static int pmecc_choose_ecc(struct atmel_nand_host *host,
int *cap, int *sector_size)
{
/* Get minimum ECC requirements */
if (host->nand_chip.ecc_strength_ds) {
*cap = host->nand_chip.ecc_strength_ds;
*sector_size = host->nand_chip.ecc_step_ds;
dev_info(host->dev, "minimum ECC: %d bits in %d bytes\n",
*cap, *sector_size);
} else {
*cap = 2;
*sector_size = 512;
dev_info(host->dev, "can't detect min. ECC, assume 2 bits in 512 bytes\n");
}
/* If device tree doesn't specify, use NAND's minimum ECC parameters */
if (host->pmecc_corr_cap == 0) {
if (*cap > host->caps->pmecc_max_correction)
return -EINVAL;
/* use the most fitable ecc bits (the near bigger one ) */
if (*cap <= 2)
host->pmecc_corr_cap = 2;
else if (*cap <= 4)
host->pmecc_corr_cap = 4;
else if (*cap <= 8)
host->pmecc_corr_cap = 8;
else if (*cap <= 12)
host->pmecc_corr_cap = 12;
else if (*cap <= 24)
host->pmecc_corr_cap = 24;
else if (*cap <= 32)
host->pmecc_corr_cap = 32;
else
return -EINVAL;
}
if (host->pmecc_sector_size == 0) {
/* use the most fitable sector size (the near smaller one ) */
if (*sector_size >= 1024)
host->pmecc_sector_size = 1024;
else if (*sector_size >= 512)
host->pmecc_sector_size = 512;
else
return -EINVAL;
}
return 0;
}
static inline int deg(unsigned int poly)
{
/* polynomial degree is the most-significant bit index */
return fls(poly) - 1;
}
static int build_gf_tables(int mm, unsigned int poly,
int16_t *index_of, int16_t *alpha_to)
{
unsigned int i, x = 1;
const unsigned int k = 1 << deg(poly);
unsigned int nn = (1 << mm) - 1;
/* primitive polynomial must be of degree m */
if (k != (1u << mm))
return -EINVAL;
for (i = 0; i < nn; i++) {
alpha_to[i] = x;
index_of[x] = i;
if (i && (x == 1))
/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
return -EINVAL;
x <<= 1;
if (x & k)
x ^= poly;
}
alpha_to[nn] = 1;
index_of[0] = 0;
return 0;
}
static uint16_t *create_lookup_table(struct device *dev, int sector_size)
{
int degree = (sector_size == 512) ?
PMECC_GF_DIMENSION_13 :
PMECC_GF_DIMENSION_14;
unsigned int poly = (sector_size == 512) ?
PMECC_GF_13_PRIMITIVE_POLY :
PMECC_GF_14_PRIMITIVE_POLY;
int table_size = (sector_size == 512) ?
PMECC_LOOKUP_TABLE_SIZE_512 :
PMECC_LOOKUP_TABLE_SIZE_1024;
int16_t *addr = devm_kzalloc(dev, 2 * table_size * sizeof(uint16_t),
GFP_KERNEL);
if (addr && build_gf_tables(degree, poly, addr, addr + table_size))
return NULL;
return addr;
}
static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
struct atmel_nand_host *host)
{
struct nand_chip *nand_chip = &host->nand_chip;
struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct resource *regs, *regs_pmerr, *regs_rom;
uint16_t *galois_table;
int cap, sector_size, err_no;
err_no = pmecc_choose_ecc(host, &cap, &sector_size);
if (err_no) {
dev_err(host->dev, "The NAND flash's ECC requirement are not support!");
return err_no;
}
if (cap > host->pmecc_corr_cap ||
sector_size != host->pmecc_sector_size)
dev_info(host->dev, "WARNING: Be Caution! Using different PMECC parameters from Nand ONFI ECC reqirement.\n");
cap = host->pmecc_corr_cap;
sector_size = host->pmecc_sector_size;
host->pmecc_lookup_table_offset = (sector_size == 512) ?
host->pmecc_lookup_table_offset_512 :
host->pmecc_lookup_table_offset_1024;
dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n",
cap, sector_size);
regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!regs) {
dev_warn(host->dev,
"Can't get I/O resource regs for PMECC controller, rolling back on software ECC\n");
nand_chip->ecc.mode = NAND_ECC_SOFT;
nand_chip->ecc.algo = NAND_ECC_HAMMING;
return 0;
}
host->ecc = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(host->ecc)) {
err_no = PTR_ERR(host->ecc);
goto err;
}
regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr);
if (IS_ERR(host->pmerrloc_base)) {
err_no = PTR_ERR(host->pmerrloc_base);
goto err;
}
host->pmerrloc_el_base = host->pmerrloc_base + ATMEL_PMERRLOC_SIGMAx +
(host->caps->pmecc_max_correction + 1) * 4;
if (!host->has_no_lookup_table) {
regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev,
regs_rom);
if (IS_ERR(host->pmecc_rom_base)) {
dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n");
host->has_no_lookup_table = true;
}
}
if (host->has_no_lookup_table) {
/* Build the look-up table in runtime */
galois_table = create_lookup_table(host->dev, sector_size);
if (!galois_table) {
dev_err(host->dev, "Failed to build a lookup table in runtime!\n");
err_no = -EINVAL;
goto err;
}
host->pmecc_rom_base = (void __iomem *)galois_table;
host->pmecc_lookup_table_offset = 0;
}
nand_chip->ecc.size = sector_size;
/* set ECC page size and oob layout */
switch (mtd->writesize) {
case 512:
case 1024:
case 2048:
case 4096:
case 8192:
if (sector_size > mtd->writesize) {
dev_err(host->dev, "pmecc sector size is bigger than the page size!\n");
err_no = -EINVAL;
goto err;
}
host->pmecc_degree = (sector_size == 512) ?
PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14;
host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
host->pmecc_alpha_to = pmecc_get_alpha_to(host);
host->pmecc_index_of = host->pmecc_rom_base +
host->pmecc_lookup_table_offset;
nand_chip->ecc.strength = cap;
nand_chip->ecc.bytes = pmecc_get_ecc_bytes(cap, sector_size);
nand_chip->ecc.steps = mtd->writesize / sector_size;
nand_chip->ecc.total = nand_chip->ecc.bytes *
nand_chip->ecc.steps;
if (nand_chip->ecc.total >
mtd->oobsize - PMECC_OOB_RESERVED_BYTES) {
dev_err(host->dev, "No room for ECC bytes\n");
err_no = -EINVAL;
goto err;
}
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
break;
default:
dev_warn(host->dev,
"Unsupported page size for PMECC, use Software ECC\n");
/* page size not handled by HW ECC */
/* switching back to soft ECC */
nand_chip->ecc.mode = NAND_ECC_SOFT;
nand_chip->ecc.algo = NAND_ECC_HAMMING;
return 0;
}
/* Allocate data for PMECC computation */
err_no = pmecc_data_alloc(host);
if (err_no) {
dev_err(host->dev,
"Cannot allocate memory for PMECC computation!\n");
goto err;
}
nand_chip->options |= NAND_NO_SUBPAGE_WRITE;
nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
nand_chip->ecc.write_page = atmel_nand_pmecc_write_page;
atmel_pmecc_core_init(mtd);
return 0;
err:
return err_no;
}
/*
* Calculate HW ECC
*
* function called after a write
*
* mtd: MTD block structure
* dat: raw data (unused)
* ecc_code: buffer for ECC
*/
static int atmel_nand_calculate(struct mtd_info *mtd,
const u_char *dat, unsigned char *ecc_code)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
unsigned int ecc_value;
/* get the first 2 ECC bytes */
ecc_value = ecc_readl(host->ecc, PR);
ecc_code[0] = ecc_value & 0xFF;
ecc_code[1] = (ecc_value >> 8) & 0xFF;
/* get the last 2 ECC bytes */
ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY;
ecc_code[2] = ecc_value & 0xFF;
ecc_code[3] = (ecc_value >> 8) & 0xFF;
return 0;
}
/*
* HW ECC read page function
*
* mtd: mtd info structure
* chip: nand chip info structure
* buf: buffer to store read data
* oob_required: caller expects OOB data read to chip->oob_poi
*/
static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
uint8_t *p = buf;
uint8_t *oob = chip->oob_poi;
uint8_t *ecc_pos;
int stat;
unsigned int max_bitflips = 0;
struct mtd_oob_region oobregion = {};
/*
* Errata: ALE is incorrectly wired up to the ECC controller
* on the AP7000, so it will include the address cycles in the
* ECC calculation.
*
* Workaround: Reset the parity registers before reading the
* actual data.
*/
struct atmel_nand_host *host = nand_get_controller_data(chip);
if (host->board.need_reset_workaround)
ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
/* read the page */
chip->read_buf(mtd, p, eccsize);
/* move to ECC position if needed */
mtd_ooblayout_ecc(mtd, 0, &oobregion);
if (oobregion.offset != 0) {
/*
* This only works on large pages because the ECC controller
* waits for NAND_CMD_RNDOUTSTART after the NAND_CMD_RNDOUT.
* Anyway, for small pages, the first ECC byte is at offset
* 0 in the OOB area.
*/
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
mtd->writesize + oobregion.offset, -1);
}
/* the ECC controller needs to read the ECC just after the data */
ecc_pos = oob + oobregion.offset;
chip->read_buf(mtd, ecc_pos, eccbytes);
/* check if there's an error */
stat = chip->ecc.correct(mtd, p, oob, NULL);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
/* get back to oob start (end of page) */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
/* read the oob */
chip->read_buf(mtd, oob, mtd->oobsize);
return max_bitflips;
}
/*
* HW ECC Correction
*
* function called after a read
*
* mtd: MTD block structure
* dat: raw data read from the chip
* read_ecc: ECC from the chip (unused)
* isnull: unused
*
* Detect and correct a 1 bit error for a page
*/
static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *isnull)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
unsigned int ecc_status;
unsigned int ecc_word, ecc_bit;
/* get the status from the Status Register */
ecc_status = ecc_readl(host->ecc, SR);
/* if there's no error */
if (likely(!(ecc_status & ATMEL_ECC_RECERR)))
return 0;
/* get error bit offset (4 bits) */
ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR;
/* get word address (12 bits) */
ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR;
ecc_word >>= 4;
/* if there are multiple errors */
if (ecc_status & ATMEL_ECC_MULERR) {
/* check if it is a freshly erased block
* (filled with 0xff) */
if ((ecc_bit == ATMEL_ECC_BITADDR)
&& (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) {
/* the block has just been erased, return OK */
return 0;
}
/* it doesn't seems to be a freshly
* erased block.
* We can't correct so many errors */
dev_dbg(host->dev, "atmel_nand : multiple errors detected."
" Unable to correct.\n");
return -EBADMSG;
}
/* if there's a single bit error : we can correct it */
if (ecc_status & ATMEL_ECC_ECCERR) {
/* there's nothing much to do here.
* the bit error is on the ECC itself.
*/
dev_dbg(host->dev, "atmel_nand : one bit error on ECC code."
" Nothing to correct\n");
return 0;
}
dev_dbg(host->dev, "atmel_nand : one bit error on data."
" (word offset in the page :"
" 0x%x bit offset : 0x%x)\n",
ecc_word, ecc_bit);
/* correct the error */
if (nand_chip->options & NAND_BUSWIDTH_16) {
/* 16 bits words */
((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit);
} else {
/* 8 bits words */
dat[ecc_word] ^= (1 << ecc_bit);
}
dev_dbg(host->dev, "atmel_nand : error corrected\n");
return 1;
}
/*
* Enable HW ECC : unused on most chips
*/
static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (host->board.need_reset_workaround)
ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
}
static int atmel_of_init_ecc(struct atmel_nand_host *host,
struct device_node *np)
{
u32 offset[2];
u32 val;
host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
/* Not using PMECC */
if (!(host->nand_chip.ecc.mode == NAND_ECC_HW) || !host->has_pmecc)
return 0;
/* use PMECC, get correction capability, sector size and lookup
* table offset.
* If correction bits and sector size are not specified, then find
* them from NAND ONFI parameters.
*/
if (of_property_read_u32(np, "atmel,pmecc-cap", &val) == 0) {
if (val > host->caps->pmecc_max_correction) {
dev_err(host->dev,
"Required ECC strength too high: %u max %u\n",
val, host->caps->pmecc_max_correction);
return -EINVAL;
}
if ((val != 2) && (val != 4) && (val != 8) &&
(val != 12) && (val != 24) && (val != 32)) {
dev_err(host->dev,
"Required ECC strength not supported: %u\n",
val);
return -EINVAL;
}
host->pmecc_corr_cap = (u8)val;
}
if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) == 0) {
if ((val != 512) && (val != 1024)) {
dev_err(host->dev,
"Required ECC sector size not supported: %u\n",
val);
return -EINVAL;
}
host->pmecc_sector_size = (u16)val;
}
if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset",
offset, 2) != 0) {
dev_err(host->dev, "Cannot get PMECC lookup table offset, will build a lookup table in runtime.\n");
host->has_no_lookup_table = true;
/* Will build a lookup table and initialize the offset later */
return 0;
}
if (!offset[0] && !offset[1]) {
dev_err(host->dev, "Invalid PMECC lookup table offset\n");
return -EINVAL;
}
host->pmecc_lookup_table_offset_512 = offset[0];
host->pmecc_lookup_table_offset_1024 = offset[1];
return 0;
}
static int atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np)
{
u32 val;
struct atmel_nand_data *board = &host->board;
enum of_gpio_flags flags = 0;
host->caps = (struct atmel_nand_caps *)
of_device_get_match_data(host->dev);
if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
if (val >= 32) {
dev_err(host->dev, "invalid addr-offset %u\n", val);
return -EINVAL;
}
board->ale = val;
}
if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) {
if (val >= 32) {
dev_err(host->dev, "invalid cmd-offset %u\n", val);
return -EINVAL;
}
board->cle = val;
}
board->has_dma = of_property_read_bool(np, "atmel,nand-has-dma");
board->rdy_pin = of_get_gpio_flags(np, 0, &flags);
board->rdy_pin_active_low = (flags == OF_GPIO_ACTIVE_LOW);
board->enable_pin = of_get_gpio(np, 1);
board->det_pin = of_get_gpio(np, 2);
/* load the nfc driver if there is */
of_platform_populate(np, NULL, NULL, host->dev);
/*
* Initialize ECC mode to NAND_ECC_SOFT so that we have a correct value
* even if the nand-ecc-mode property is not defined.
*/
host->nand_chip.ecc.mode = NAND_ECC_SOFT;
host->nand_chip.ecc.algo = NAND_ECC_HAMMING;
return 0;
}
static int atmel_hw_nand_init_params(struct platform_device *pdev,
struct atmel_nand_host *host)
{
struct nand_chip *nand_chip = &host->nand_chip;
struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct resource *regs;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!regs) {
dev_err(host->dev,
"Can't get I/O resource regs, use software ECC\n");
nand_chip->ecc.mode = NAND_ECC_SOFT;
nand_chip->ecc.algo = NAND_ECC_HAMMING;
return 0;
}
host->ecc = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(host->ecc))
return PTR_ERR(host->ecc);
/* ECC is calculated for the whole page (1 step) */
nand_chip->ecc.size = mtd->writesize;
/* set ECC page size and oob layout */
switch (mtd->writesize) {
case 512:
mtd_set_ooblayout(mtd, &atmel_ooblayout_sp_ops);
ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
break;
case 1024:
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
break;
case 2048:
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
break;
case 4096:
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
break;
default:
/* page size not handled by HW ECC */
/* switching back to soft ECC */
nand_chip->ecc.mode = NAND_ECC_SOFT;
nand_chip->ecc.algo = NAND_ECC_HAMMING;
return 0;
}
/* set up for HW ECC */
nand_chip->ecc.calculate = atmel_nand_calculate;
nand_chip->ecc.correct = atmel_nand_correct;
nand_chip->ecc.hwctl = atmel_nand_hwctl;
nand_chip->ecc.read_page = atmel_nand_read_page;
nand_chip->ecc.bytes = 4;
nand_chip->ecc.strength = 1;
return 0;
}
static inline u32 nfc_read_status(struct atmel_nand_host *host)
{
u32 err_flags = NFC_SR_DTOE | NFC_SR_UNDEF | NFC_SR_AWB | NFC_SR_ASE;
u32 nfc_status = nfc_readl(host->nfc->hsmc_regs, SR);
if (unlikely(nfc_status & err_flags)) {
if (nfc_status & NFC_SR_DTOE)
dev_err(host->dev, "NFC: Waiting Nand R/B Timeout Error\n");
else if (nfc_status & NFC_SR_UNDEF)
dev_err(host->dev, "NFC: Access Undefined Area Error\n");
else if (nfc_status & NFC_SR_AWB)
dev_err(host->dev, "NFC: Access memory While NFC is busy\n");
else if (nfc_status & NFC_SR_ASE)
dev_err(host->dev, "NFC: Access memory Size Error\n");
}
return nfc_status;
}
/* SMC interrupt service routine */
static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
{
struct atmel_nand_host *host = dev_id;
u32 status, mask, pending;
irqreturn_t ret = IRQ_NONE;
status = nfc_read_status(host);
mask = nfc_readl(host->nfc->hsmc_regs, IMR);
pending = status & mask;
if (pending & NFC_SR_XFR_DONE) {
complete(&host->nfc->comp_xfer_done);
nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
ret = IRQ_HANDLED;
}
if (pending & NFC_SR_RB_EDGE) {
complete(&host->nfc->comp_ready);
nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
ret = IRQ_HANDLED;
}
if (pending & NFC_SR_CMD_DONE) {
complete(&host->nfc->comp_cmd_done);
nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE);
ret = IRQ_HANDLED;
}
return ret;
}
/* NFC(Nand Flash Controller) related functions */
static void nfc_prepare_interrupt(struct atmel_nand_host *host, u32 flag)
{
if (flag & NFC_SR_XFR_DONE)
init_completion(&host->nfc->comp_xfer_done);
if (flag & NFC_SR_RB_EDGE)
init_completion(&host->nfc->comp_ready);
if (flag & NFC_SR_CMD_DONE)
init_completion(&host->nfc->comp_cmd_done);
/* Enable interrupt that need to wait for */
nfc_writel(host->nfc->hsmc_regs, IER, flag);
}
static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
{
int i, index = 0;
struct completion *comp[3]; /* Support 3 interrupt completion */
if (flag & NFC_SR_XFR_DONE)
comp[index++] = &host->nfc->comp_xfer_done;
if (flag & NFC_SR_RB_EDGE)
comp[index++] = &host->nfc->comp_ready;
if (flag & NFC_SR_CMD_DONE)
comp[index++] = &host->nfc->comp_cmd_done;
if (index == 0) {
dev_err(host->dev, "Unknown interrupt flag: 0x%08x\n", flag);
return -EINVAL;
}
for (i = 0; i < index; i++) {
if (wait_for_completion_timeout(comp[i],
msecs_to_jiffies(NFC_TIME_OUT_MS)))
continue; /* wait for next completion */
else
goto err_timeout;
}
return 0;
err_timeout:
dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag);
/* Disable the interrupt as it is not handled by interrupt handler */
nfc_writel(host->nfc->hsmc_regs, IDR, flag);
return -ETIMEDOUT;
}
static int nfc_send_command(struct atmel_nand_host *host,
unsigned int cmd, unsigned int addr, unsigned char cycle0)
{
unsigned long timeout;
u32 flag = NFC_SR_CMD_DONE;
flag |= cmd & NFCADDR_CMD_DATAEN ? NFC_SR_XFR_DONE : 0;
dev_dbg(host->dev,
"nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n",
cmd, addr, cycle0);
timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
while (nfc_readl(host->nfc->hsmc_regs, SR) & NFC_SR_BUSY) {
if (time_after(jiffies, timeout)) {
dev_err(host->dev,
"Time out to wait for NFC ready!\n");
return -ETIMEDOUT;
}
}
nfc_prepare_interrupt(host, flag);
nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0);
nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs);
return nfc_wait_interrupt(host, flag);
}
static int nfc_device_ready(struct mtd_info *mtd)
{
u32 status, mask;
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
status = nfc_read_status(host);
mask = nfc_readl(host->nfc->hsmc_regs, IMR);
/* The mask should be 0. If not we may lost interrupts */
if (unlikely(mask & status))
dev_err(host->dev, "Lost the interrupt flags: 0x%08x\n",
mask & status);
return status & NFC_SR_RB_EDGE;
}
static void nfc_select_chip(struct mtd_info *mtd, int chip)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(nand_chip);
if (chip == -1)
nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_DISABLE);
else
nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_ENABLE);
}
static int nfc_make_addr(struct mtd_info *mtd, int command, int column,
int page_addr, unsigned int *addr1234, unsigned int *cycle0)
{
struct nand_chip *chip = mtd_to_nand(mtd);
int acycle = 0;
unsigned char addr_bytes[8];
int index = 0, bit_shift;
BUG_ON(addr1234 == NULL || cycle0 == NULL);
*cycle0 = 0;
*addr1234 = 0;
if (column != -1) {
if (chip->options & NAND_BUSWIDTH_16 &&
!nand_opcode_8bits(command))
column >>= 1;
addr_bytes[acycle++] = column & 0xff;
if (mtd->writesize > 512)
addr_bytes[acycle++] = (column >> 8) & 0xff;
}
if (page_addr != -1) {
addr_bytes[acycle++] = page_addr & 0xff;
addr_bytes[acycle++] = (page_addr >> 8) & 0xff;
if (chip->chipsize > (128 << 20))
addr_bytes[acycle++] = (page_addr >> 16) & 0xff;
}
if (acycle > 4)
*cycle0 = addr_bytes[index++];
for (bit_shift = 0; index < acycle; bit_shift += 8)
*addr1234 += addr_bytes[index++] << bit_shift;
/* return acycle in cmd register */
return acycle << NFCADDR_CMD_ACYCLE_BIT_POS;
}
static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(chip);
unsigned long timeout;
unsigned int nfc_addr_cmd = 0;
unsigned int cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
/* Set default settings: no cmd2, no addr cycle. read from nand */
unsigned int cmd2 = 0;
unsigned int vcmd2 = 0;
int acycle = NFCADDR_CMD_ACYCLE_NONE;
int csid = NFCADDR_CMD_CSID_3;
int dataen = NFCADDR_CMD_DATADIS;
int nfcwr = NFCADDR_CMD_NFCRD;
unsigned int addr1234 = 0;
unsigned int cycle0 = 0;
bool do_addr = true;
host->nfc->data_in_sram = NULL;
dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
__func__, command, column, page_addr);
switch (command) {
case NAND_CMD_RESET:
nfc_addr_cmd = cmd1 | acycle | csid | dataen | nfcwr;
nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
udelay(chip->chip_delay);
nfc_nand_command(mtd, NAND_CMD_STATUS, -1, -1);
timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) {
if (time_after(jiffies, timeout)) {
dev_err(host->dev,
"Time out to wait status ready!\n");
break;
}
}
return;
case NAND_CMD_STATUS:
do_addr = false;
break;
case NAND_CMD_PARAM:
case NAND_CMD_READID:
do_addr = false;
acycle = NFCADDR_CMD_ACYCLE_1;
if (column != -1)
addr1234 = column;
break;
case NAND_CMD_RNDOUT:
cmd2 = NAND_CMD_RNDOUTSTART << NFCADDR_CMD_CMD2_BIT_POS;
vcmd2 = NFCADDR_CMD_VCMD2;
break;
case NAND_CMD_READ0:
case NAND_CMD_READOOB:
if (command == NAND_CMD_READOOB) {
column += mtd->writesize;
command = NAND_CMD_READ0; /* only READ0 is valid */
cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
}
if (host->nfc->use_nfc_sram) {
/* Enable Data transfer to sram */
dataen = NFCADDR_CMD_DATAEN;
/* Need enable PMECC now, since NFC will transfer
* data in bus after sending nfc read command.
*/
if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
pmecc_enable(host, NAND_ECC_READ);
}
cmd2 = NAND_CMD_READSTART << NFCADDR_CMD_CMD2_BIT_POS;
vcmd2 = NFCADDR_CMD_VCMD2;
break;
/* For prgramming command, the cmd need set to write enable */
case NAND_CMD_PAGEPROG:
case NAND_CMD_SEQIN:
case NAND_CMD_RNDIN:
nfcwr = NFCADDR_CMD_NFCWR;
if (host->nfc->will_write_sram && command == NAND_CMD_SEQIN)
dataen = NFCADDR_CMD_DATAEN;
break;
default:
break;
}
if (do_addr)
acycle = nfc_make_addr(mtd, command, column, page_addr,
&addr1234, &cycle0);
nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
/*
* Program and erase have their own busy handlers status, sequential
* in, and deplete1 need no delay.
*/
switch (command) {
case NAND_CMD_CACHEDPROG:
case NAND_CMD_PAGEPROG:
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
case NAND_CMD_RNDOUT:
case NAND_CMD_SEQIN:
case NAND_CMD_READID:
return;
case NAND_CMD_READ0:
if (dataen == NFCADDR_CMD_DATAEN) {
host->nfc->data_in_sram = host->nfc->sram_bank0 +
nfc_get_sram_off(host);
return;
}
/* fall through */
default:
nfc_prepare_interrupt(host, NFC_SR_RB_EDGE);
nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
}
}
static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw)
{
int cfg, len;
int status = 0;
struct atmel_nand_host *host = nand_get_controller_data(chip);
void *sram = host->nfc->sram_bank0 + nfc_get_sram_off(host);
/* Subpage write is not supported */
if (offset || (data_len < mtd->writesize))
return -EINVAL;
len = mtd->writesize;
/* Copy page data to sram that will write to nand via NFC */
if (use_dma) {
if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
/* Fall back to use cpu copy */
memcpy(sram, buf, len);
} else {
memcpy(sram, buf, len);
}
cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
if (unlikely(raw) && oob_required) {
memcpy(sram + len, chip->oob_poi, mtd->oobsize);
len += mtd->oobsize;
nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
} else {
nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
}
if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
/*
* When use NFC sram, need set up PMECC before send
* NAND_CMD_SEQIN command. Since when the nand command
* is sent, nfc will do transfer from sram and nand.
*/
pmecc_enable(host, NAND_ECC_WRITE);
host->nfc->will_write_sram = true;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
host->nfc->will_write_sram = false;
if (likely(!raw))
/* Need to write ecc into oob */
status = chip->ecc.write_page(mtd, chip, buf, oob_required,
page);
if (status < 0)
return status;
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
status = chip->errstat(mtd, chip, FL_WRITING, status, page);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
static int nfc_sram_init(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand_host *host = nand_get_controller_data(chip);
int res = 0;
/* Initialize the NFC CFG register */
unsigned int cfg_nfc = 0;
/* set page size and oob layout */
switch (mtd->writesize) {
case 512:
cfg_nfc = NFC_CFG_PAGESIZE_512;
break;
case 1024:
cfg_nfc = NFC_CFG_PAGESIZE_1024;
break;
case 2048:
cfg_nfc = NFC_CFG_PAGESIZE_2048;
break;
case 4096:
cfg_nfc = NFC_CFG_PAGESIZE_4096;
break;
case 8192:
cfg_nfc = NFC_CFG_PAGESIZE_8192;
break;
default:
dev_err(host->dev, "Unsupported page size for NFC.\n");
res = -ENXIO;
return res;
}
/* oob bytes size = (NFCSPARESIZE + 1) * 4
* Max support spare size is 512 bytes. */
cfg_nfc |= (((mtd->oobsize / 4) - 1) << NFC_CFG_NFC_SPARESIZE_BIT_POS
& NFC_CFG_NFC_SPARESIZE);
/* default set a max timeout */
cfg_nfc |= NFC_CFG_RSPARE |
NFC_CFG_NFC_DTOCYC | NFC_CFG_NFC_DTOMUL;
nfc_writel(host->nfc->hsmc_regs, CFG, cfg_nfc);
host->nfc->will_write_sram = false;
nfc_set_sram_bank(host, 0);
/* Use Write page with NFC SRAM only for PMECC or ECC NONE. */
if (host->nfc->write_by_sram) {
if ((chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) ||
chip->ecc.mode == NAND_ECC_NONE)
chip->write_page = nfc_sram_write_page;
else
host->nfc->write_by_sram = false;
}
dev_info(host->dev, "Using NFC Sram read %s\n",
host->nfc->write_by_sram ? "and write" : "");
return 0;
}
static struct platform_driver atmel_nand_nfc_driver;
/*
* Probe for the NAND device.
*/
static int atmel_nand_probe(struct platform_device *pdev)
{
struct atmel_nand_host *host;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
struct resource *mem;
int res, irq;
/* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host)
return -ENOMEM;
res = platform_driver_register(&atmel_nand_nfc_driver);
if (res)
dev_err(&pdev->dev, "atmel_nand: can't register NFC driver\n");
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(host->io_base)) {
res = PTR_ERR(host->io_base);
goto err_nand_ioremap;
}
host->io_phys = (dma_addr_t)mem->start;
nand_chip = &host->nand_chip;
mtd = nand_to_mtd(nand_chip);
host->dev = &pdev->dev;
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
nand_set_flash_node(nand_chip, pdev->dev.of_node);
/* Only when CONFIG_OF is enabled of_node can be parsed */
res = atmel_of_init_port(host, pdev->dev.of_node);
if (res)
goto err_nand_ioremap;
} else {
memcpy(&host->board, dev_get_platdata(&pdev->dev),
sizeof(struct atmel_nand_data));
nand_chip->ecc.mode = host->board.ecc_mode;
/*
* When using software ECC every supported avr32 board means
* Hamming algorithm. If that ever changes we'll need to add
* ecc_algo field to the struct atmel_nand_data.
*/
if (nand_chip->ecc.mode == NAND_ECC_SOFT)
nand_chip->ecc.algo = NAND_ECC_HAMMING;
/* 16-bit bus width */
if (host->board.bus_width_16)
nand_chip->options |= NAND_BUSWIDTH_16;
}
/* link the private data structures */
nand_set_controller_data(nand_chip, host);
mtd->dev.parent = &pdev->dev;
/* Set address of NAND IO lines */
nand_chip->IO_ADDR_R = host->io_base;
nand_chip->IO_ADDR_W = host->io_base;
if (nand_nfc.is_initialized) {
/* NFC driver is probed and initialized */
host->nfc = &nand_nfc;
nand_chip->select_chip = nfc_select_chip;
nand_chip->dev_ready = nfc_device_ready;
nand_chip->cmdfunc = nfc_nand_command;
/* Initialize the interrupt for NFC */
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(host->dev, "Cannot get HSMC irq!\n");
res = irq;
goto err_nand_ioremap;
}
res = devm_request_irq(&pdev->dev, irq, hsmc_interrupt,
0, "hsmc", host);
if (res) {
dev_err(&pdev->dev, "Unable to request HSMC irq %d\n",
irq);
goto err_nand_ioremap;
}
} else {
res = atmel_nand_set_enable_ready_pins(mtd);
if (res)
goto err_nand_ioremap;
nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
}
nand_chip->chip_delay = 40; /* 40us command delay time */
nand_chip->read_buf = atmel_read_buf;
nand_chip->write_buf = atmel_write_buf;
platform_set_drvdata(pdev, host);
atmel_nand_enable(host);
if (gpio_is_valid(host->board.det_pin)) {
res = devm_gpio_request(&pdev->dev,
host->board.det_pin, "nand_det");
if (res < 0) {
dev_err(&pdev->dev,
"can't request det gpio %d\n",
host->board.det_pin);
goto err_no_card;
}
res = gpio_direction_input(host->board.det_pin);
if (res < 0) {
dev_err(&pdev->dev,
"can't request input direction det gpio %d\n",
host->board.det_pin);
goto err_no_card;
}
if (gpio_get_value(host->board.det_pin)) {
dev_info(&pdev->dev, "No SmartMedia card inserted.\n");
res = -ENXIO;
goto err_no_card;
}
}
if (!host->board.has_dma)
use_dma = 0;
if (use_dma) {
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
host->dma_chan = dma_request_channel(mask, NULL, NULL);
if (!host->dma_chan) {
dev_err(host->dev, "Failed to request DMA channel\n");
use_dma = 0;
}
}
if (use_dma)
dev_info(host->dev, "Using %s for DMA transfers.\n",
dma_chan_name(host->dma_chan));
else
dev_info(host->dev, "No DMA support for NAND access.\n");
/* first scan to find the device and get the page size */
res = nand_scan_ident(mtd, 1, NULL);
if (res)
goto err_scan_ident;
if (host->board.on_flash_bbt || on_flash_bbt)
nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
if (nand_chip->bbt_options & NAND_BBT_USE_FLASH)
dev_info(&pdev->dev, "Use On Flash BBT\n");
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
res = atmel_of_init_ecc(host, pdev->dev.of_node);
if (res)
goto err_hw_ecc;
}
if (nand_chip->ecc.mode == NAND_ECC_HW) {
if (host->has_pmecc)
res = atmel_pmecc_nand_init_params(pdev, host);
else
res = atmel_hw_nand_init_params(pdev, host);
if (res != 0)
goto err_hw_ecc;
}
/* initialize the nfc configuration register */
if (host->nfc && host->nfc->use_nfc_sram) {
res = nfc_sram_init(mtd);
if (res) {
host->nfc->use_nfc_sram = false;
dev_err(host->dev, "Disable use nfc sram for data transfer.\n");
}
}
/* second phase scan */
res = nand_scan_tail(mtd);
if (res)
goto err_scan_tail;
mtd->name = "atmel_nand";
res = mtd_device_register(mtd, host->board.parts,
host->board.num_parts);
if (!res)
return res;
err_scan_tail:
if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW)
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
err_hw_ecc:
err_scan_ident:
err_no_card:
atmel_nand_disable(host);
if (host->dma_chan)
dma_release_channel(host->dma_chan);
err_nand_ioremap:
return res;
}
/*
* Remove a NAND device.
*/
static int atmel_nand_remove(struct platform_device *pdev)
{
struct atmel_nand_host *host = platform_get_drvdata(pdev);
struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
nand_release(mtd);
atmel_nand_disable(host);
if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
pmerrloc_writel(host->pmerrloc_base, ELDIS,
PMERRLOC_DISABLE);
}
if (host->dma_chan)
dma_release_channel(host->dma_chan);
platform_driver_unregister(&atmel_nand_nfc_driver);
return 0;
}
/*
* AT91RM9200 does not have PMECC or PMECC Errloc peripherals for
* BCH ECC. Combined with the "atmel,has-pmecc", it is used to describe
* devices from the SAM9 family that have those.
*/
static const struct atmel_nand_caps at91rm9200_caps = {
.pmecc_correct_erase_page = false,
.pmecc_max_correction = 24,
};
static const struct atmel_nand_caps sama5d4_caps = {
.pmecc_correct_erase_page = true,
.pmecc_max_correction = 24,
};
/*
* The PMECC Errloc controller starting in SAMA5D2 is not compatible,
* as the increased correction strength requires more registers.
*/
static const struct atmel_nand_caps sama5d2_caps = {
.pmecc_correct_erase_page = true,
.pmecc_max_correction = 32,
};
static const struct of_device_id atmel_nand_dt_ids[] = {
{ .compatible = "atmel,at91rm9200-nand", .data = &at91rm9200_caps },
{ .compatible = "atmel,sama5d4-nand", .data = &sama5d4_caps },
{ .compatible = "atmel,sama5d2-nand", .data = &sama5d2_caps },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
static int atmel_nand_nfc_probe(struct platform_device *pdev)
{
struct atmel_nfc *nfc = &nand_nfc;
struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
int ret;
nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
if (IS_ERR(nfc->base_cmd_regs))
return PTR_ERR(nfc->base_cmd_regs);
nfc_hsmc_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
nfc->hsmc_regs = devm_ioremap_resource(&pdev->dev, nfc_hsmc_regs);
if (IS_ERR(nfc->hsmc_regs))
return PTR_ERR(nfc->hsmc_regs);
nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (nfc_sram) {
nfc->sram_bank0 = (void * __force)
devm_ioremap_resource(&pdev->dev, nfc_sram);
if (IS_ERR(nfc->sram_bank0)) {
dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
PTR_ERR(nfc->sram_bank0));
} else {
nfc->use_nfc_sram = true;
nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
if (pdev->dev.of_node)
nfc->write_by_sram = of_property_read_bool(
pdev->dev.of_node,
"atmel,write-by-sram");
}
}
nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff);
nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */
nfc->clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(nfc->clk)) {
ret = clk_prepare_enable(nfc->clk);
if (ret)
return ret;
} else {
dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree");
}
nfc->is_initialized = true;
dev_info(&pdev->dev, "NFC is probed.\n");
return 0;
}
static int atmel_nand_nfc_remove(struct platform_device *pdev)
{
struct atmel_nfc *nfc = &nand_nfc;
if (!IS_ERR(nfc->clk))
clk_disable_unprepare(nfc->clk);
return 0;
}
static const struct of_device_id atmel_nand_nfc_match[] = {
{ .compatible = "atmel,sama5d3-nfc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_nand_nfc_match);
static struct platform_driver atmel_nand_nfc_driver = {
.driver = {
.name = "atmel_nand_nfc",
.of_match_table = of_match_ptr(atmel_nand_nfc_match),
},
.probe = atmel_nand_nfc_probe,
.remove = atmel_nand_nfc_remove,
};
static struct platform_driver atmel_nand_driver = {
.probe = atmel_nand_probe,
.remove = atmel_nand_remove,
.driver = {
.name = "atmel_nand",
.of_match_table = of_match_ptr(atmel_nand_dt_ids),
},
};
module_platform_driver(atmel_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rick Bronson");
MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32");
MODULE_ALIAS("platform:atmel_nand");
/*
* Error Corrected Code Controller (ECC) - System peripherals regsters.
* Based on AT91SAM9260 datasheet revision B.
*
* Copyright (C) 2007 Andrew Victor
* Copyright (C) 2007 - 2012 Atmel Corporation.
*
* 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.
*/
#ifndef ATMEL_NAND_ECC_H
#define ATMEL_NAND_ECC_H
#define ATMEL_ECC_CR 0x00 /* Control register */
#define ATMEL_ECC_RST (1 << 0) /* Reset parity */
#define ATMEL_ECC_MR 0x04 /* Mode register */
#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */
#define ATMEL_ECC_PAGESIZE_528 (0)
#define ATMEL_ECC_PAGESIZE_1056 (1)
#define ATMEL_ECC_PAGESIZE_2112 (2)
#define ATMEL_ECC_PAGESIZE_4224 (3)
#define ATMEL_ECC_SR 0x08 /* Status register */
#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */
#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */
#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */
#define ATMEL_ECC_PR 0x0c /* Parity register */
#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */
#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */
#define ATMEL_ECC_NPR 0x10 /* NParity register */
#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */
/* PMECC Register Definitions */
#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */
#define PMECC_CFG_BCH_ERR2 (0 << 0)
#define PMECC_CFG_BCH_ERR4 (1 << 0)
#define PMECC_CFG_BCH_ERR8 (2 << 0)
#define PMECC_CFG_BCH_ERR12 (3 << 0)
#define PMECC_CFG_BCH_ERR24 (4 << 0)
#define PMECC_CFG_BCH_ERR32 (5 << 0)
#define PMECC_CFG_SECTOR512 (0 << 4)
#define PMECC_CFG_SECTOR1024 (1 << 4)
#define PMECC_CFG_PAGE_1SECTOR (0 << 8)
#define PMECC_CFG_PAGE_2SECTORS (1 << 8)
#define PMECC_CFG_PAGE_4SECTORS (2 << 8)
#define PMECC_CFG_PAGE_8SECTORS (3 << 8)
#define PMECC_CFG_READ_OP (0 << 12)
#define PMECC_CFG_WRITE_OP (1 << 12)
#define PMECC_CFG_SPARE_ENABLE (1 << 16)
#define PMECC_CFG_SPARE_DISABLE (0 << 16)
#define PMECC_CFG_AUTO_ENABLE (1 << 20)
#define PMECC_CFG_AUTO_DISABLE (0 << 20)
#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */
#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */
#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */
#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */
#define PMECC_CLK_133MHZ (2 << 0)
#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */
#define PMECC_CTRL_RST (1 << 0)
#define PMECC_CTRL_DATA (1 << 1)
#define PMECC_CTRL_USER (1 << 2)
#define PMECC_CTRL_ENABLE (1 << 4)
#define PMECC_CTRL_DISABLE (1 << 5)
#define ATMEL_PMECC_SR 0x018 /* PMECC status register */
#define PMECC_SR_BUSY (1 << 0)
#define PMECC_SR_ENABLE (1 << 4)
#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */
#define PMECC_IER_ENABLE (1 << 0)
#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */
#define PMECC_IER_DISABLE (1 << 0)
#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */
#define PMECC_IER_MASK (1 << 0)
#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */
#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */
#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */
/* PMERRLOC Register Definitions */
#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */
#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */
#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */
#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */
#define PMERRLOC_DISABLE (1 << 0)
#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */
#define PMERRLOC_ELSR_BUSY (1 << 0)
#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */
#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */
#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */
#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */
#define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
#define PMERRLOC_CALC_DONE (1 << 0)
#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */
/*
* The ATMEL_PMERRLOC_ELx register location depends from the number of
* bits corrected by the PMECC controller. Do not use it.
*/
/* Register access macros for PMECC */
#define pmecc_readl_relaxed(addr, reg) \
readl_relaxed((addr) + ATMEL_PMECC_##reg)
#define pmecc_writel(addr, reg, value) \
writel((value), (addr) + ATMEL_PMECC_##reg)
#define pmecc_readb_ecc_relaxed(addr, sector, n) \
readb_relaxed((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
#define pmecc_readl_rem_relaxed(addr, sector, n) \
readl_relaxed((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4))
#define pmerrloc_readl_relaxed(addr, reg) \
readl_relaxed((addr) + ATMEL_PMERRLOC_##reg)
#define pmerrloc_writel(addr, reg, value) \
writel((value), (addr) + ATMEL_PMERRLOC_##reg)
#define pmerrloc_writel_sigma_relaxed(addr, n, value) \
writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
#define pmerrloc_readl_sigma_relaxed(addr, n) \
readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
#define pmerrloc_readl_el_relaxed(addr, n) \
readl_relaxed((addr) + ((n) * 4))
/* Galois field dimension */
#define PMECC_GF_DIMENSION_13 13
#define PMECC_GF_DIMENSION_14 14
/* Primitive Polynomial used by PMECC */
#define PMECC_GF_13_PRIMITIVE_POLY 0x201b
#define PMECC_GF_14_PRIMITIVE_POLY 0x4443
#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
/* Time out value for reading PMECC status register */
#define PMECC_MAX_TIMEOUT_MS 100
/* Reserved bytes in oob area */
#define PMECC_OOB_RESERVED_BYTES 2
#endif
/*
* Atmel Nand Flash Controller (NFC) - System peripherals regsters.
* Based on SAMA5D3 datasheet.
*
* © Copyright 2013 Atmel Corporation.
*
* 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.
*/
#ifndef ATMEL_NAND_NFC_H
#define ATMEL_NAND_NFC_H
/*
* HSMC NFC registers
*/
#define ATMEL_HSMC_NFC_CFG 0x00 /* NFC Configuration Register */
#define NFC_CFG_PAGESIZE (7 << 0)
#define NFC_CFG_PAGESIZE_512 (0 << 0)
#define NFC_CFG_PAGESIZE_1024 (1 << 0)
#define NFC_CFG_PAGESIZE_2048 (2 << 0)
#define NFC_CFG_PAGESIZE_4096 (3 << 0)
#define NFC_CFG_PAGESIZE_8192 (4 << 0)
#define NFC_CFG_WSPARE (1 << 8)
#define NFC_CFG_RSPARE (1 << 9)
#define NFC_CFG_NFC_DTOCYC (0xf << 16)
#define NFC_CFG_NFC_DTOMUL (0x7 << 20)
#define NFC_CFG_NFC_SPARESIZE (0x7f << 24)
#define NFC_CFG_NFC_SPARESIZE_BIT_POS 24
#define ATMEL_HSMC_NFC_CTRL 0x04 /* NFC Control Register */
#define NFC_CTRL_ENABLE (1 << 0)
#define NFC_CTRL_DISABLE (1 << 1)
#define ATMEL_HSMC_NFC_SR 0x08 /* NFC Status Register */
#define NFC_SR_BUSY (1 << 8)
#define NFC_SR_XFR_DONE (1 << 16)
#define NFC_SR_CMD_DONE (1 << 17)
#define NFC_SR_DTOE (1 << 20)
#define NFC_SR_UNDEF (1 << 21)
#define NFC_SR_AWB (1 << 22)
#define NFC_SR_ASE (1 << 23)
#define NFC_SR_RB_EDGE (1 << 24)
#define ATMEL_HSMC_NFC_IER 0x0c
#define ATMEL_HSMC_NFC_IDR 0x10
#define ATMEL_HSMC_NFC_IMR 0x14
#define ATMEL_HSMC_NFC_CYCLE0 0x18 /* NFC Address Cycle Zero */
#define ATMEL_HSMC_NFC_ADDR_CYCLE0 (0xff)
#define ATMEL_HSMC_NFC_BANK 0x1c /* NFC Bank Register */
#define ATMEL_HSMC_NFC_BANK0 (0 << 0)
#define ATMEL_HSMC_NFC_BANK1 (1 << 0)
#define nfc_writel(addr, reg, value) \
writel((value), (addr) + ATMEL_HSMC_NFC_##reg)
#define nfc_readl(addr, reg) \
readl_relaxed((addr) + ATMEL_HSMC_NFC_##reg)
/*
* NFC Address Command definitions
*/
#define NFCADDR_CMD_CMD1 (0xff << 2) /* Command for Cycle 1 */
#define NFCADDR_CMD_CMD1_BIT_POS 2
#define NFCADDR_CMD_CMD2 (0xff << 10) /* Command for Cycle 2 */
#define NFCADDR_CMD_CMD2_BIT_POS 10
#define NFCADDR_CMD_VCMD2 (0x1 << 18) /* Valid Cycle 2 Command */
#define NFCADDR_CMD_ACYCLE (0x7 << 19) /* Number of Address required */
#define NFCADDR_CMD_ACYCLE_NONE (0x0 << 19)
#define NFCADDR_CMD_ACYCLE_1 (0x1 << 19)
#define NFCADDR_CMD_ACYCLE_2 (0x2 << 19)
#define NFCADDR_CMD_ACYCLE_3 (0x3 << 19)
#define NFCADDR_CMD_ACYCLE_4 (0x4 << 19)
#define NFCADDR_CMD_ACYCLE_5 (0x5 << 19)
#define NFCADDR_CMD_ACYCLE_BIT_POS 19
#define NFCADDR_CMD_CSID (0x7 << 22) /* Chip Select Identifier */
#define NFCADDR_CMD_CSID_0 (0x0 << 22)
#define NFCADDR_CMD_CSID_1 (0x1 << 22)
#define NFCADDR_CMD_CSID_2 (0x2 << 22)
#define NFCADDR_CMD_CSID_3 (0x3 << 22)
#define NFCADDR_CMD_CSID_4 (0x4 << 22)
#define NFCADDR_CMD_CSID_5 (0x5 << 22)
#define NFCADDR_CMD_CSID_6 (0x6 << 22)
#define NFCADDR_CMD_CSID_7 (0x7 << 22)
#define NFCADDR_CMD_DATAEN (0x1 << 25) /* Data Transfer Enable */
#define NFCADDR_CMD_DATADIS (0x0 << 25) /* Data Transfer Disable */
#define NFCADDR_CMD_NFCRD (0x0 << 26) /* NFC Read Enable */
#define NFCADDR_CMD_NFCWR (0x1 << 26) /* NFC Write Enable */
#define NFCADDR_CMD_NFCBUSY (0x1 << 27) /* NFC Busy */
#define nfc_cmd_addr1234_writel(cmd, addr1234, nfc_base) \
writel((addr1234), (cmd) + nfc_base)
#define nfc_cmd_readl(bitstatus, nfc_base) \
readl_relaxed((bitstatus) + nfc_base)
#define NFC_TIME_OUT_MS 100
#define NFC_SRAM_BANK1_OFFSET 0x1200
#endif
......@@ -101,6 +101,9 @@ struct brcm_nand_dma_desc {
#define BRCMNAND_MIN_BLOCKSIZE (8 * 1024)
#define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024)
#define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY)
#define NAND_POLL_STATUS_TIMEOUT_MS 100
/* Controller feature flags */
enum {
BRCMNAND_HAS_1K_SECTORS = BIT(0),
......@@ -765,6 +768,31 @@ enum {
CS_SELECT_AUTO_DEVICE_ID_CFG = BIT(30),
};
static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
u32 mask, u32 expected_val,
unsigned long timeout_ms)
{
unsigned long limit;
u32 val;
if (!timeout_ms)
timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
limit = jiffies + msecs_to_jiffies(timeout_ms);
do {
val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
if ((val & mask) == expected_val)
return 0;
cpu_relax();
} while (time_after(limit, jiffies));
dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
expected_val, val & mask);
return -ETIMEDOUT;
}
static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
{
u32 val = en ? CS_SELECT_NAND_WP : 0;
......@@ -1024,12 +1052,39 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)
if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
static int old_wp = -1;
int ret;
if (old_wp != wp) {
dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
old_wp = wp;
}
/*
* make sure ctrl/flash ready before and after
* changing state of #WP pin
*/
ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY |
NAND_STATUS_READY,
NAND_CTRL_RDY |
NAND_STATUS_READY, 0);
if (ret)
return;
brcmnand_set_wp(ctrl, wp);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
ret = bcmnand_ctrl_poll_status(ctrl,
NAND_CTRL_RDY |
NAND_STATUS_READY |
NAND_STATUS_WP,
NAND_CTRL_RDY |
NAND_STATUS_READY |
(wp ? 0 : NAND_STATUS_WP), 0);
if (ret)
dev_err_ratelimited(&host->pdev->dev,
"nand #WP expected %s\n",
wp ? "on" : "off");
}
}
......@@ -1157,15 +1212,15 @@ static irqreturn_t brcmnand_dma_irq(int irq, void *data)
static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
{
struct brcmnand_controller *ctrl = host->ctrl;
u32 intfc;
int ret;
dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
BUG_ON(ctrl->cmd_pending != 0);
ctrl->cmd_pending = cmd;
intfc = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
WARN_ON(!(intfc & INTFC_CTLR_READY));
ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
WARN_ON(ret);
mb(); /* flush previous writes */
brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
......
......@@ -581,6 +581,17 @@ static struct davinci_nand_pdata
"ti,davinci-nand-use-bbt"))
pdata->bbt_options = NAND_BBT_USE_FLASH;
/*
* Since kernel v4.8, this driver has been fixed to enable
* use of 4-bit hardware ECC with subpages and verified on
* TI's keystone EVMs (K2L, K2HK and K2E).
* However, in the interest of not breaking systems using
* existing UBI partitions, sub-page writes are not being
* (re)enabled. If you want to use subpage writes on Keystone
* platforms (i.e. do not have any existing UBI partitions),
* then use "ti,davinci-nand" as the compatible in your
* device-tree file.
*/
if (of_device_is_compatible(pdev->dev.of_node,
"ti,keystone-nand")) {
pdata->options |= NAND_NO_SUBPAGE_WRITE;
......
......@@ -45,16 +45,16 @@ MODULE_PARM_DESC(onfi_timing_mode,
* We define a macro here that combines all interrupts this driver uses into
* a single constant value, for convenience.
*/
#define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \
INTR_STATUS__ECC_TRANSACTION_DONE | \
INTR_STATUS__ECC_ERR | \
INTR_STATUS__PROGRAM_FAIL | \
INTR_STATUS__LOAD_COMP | \
INTR_STATUS__PROGRAM_COMP | \
INTR_STATUS__TIME_OUT | \
INTR_STATUS__ERASE_FAIL | \
INTR_STATUS__RST_COMP | \
INTR_STATUS__ERASE_COMP)
#define DENALI_IRQ_ALL (INTR__DMA_CMD_COMP | \
INTR__ECC_TRANSACTION_DONE | \
INTR__ECC_ERR | \
INTR__PROGRAM_FAIL | \
INTR__LOAD_COMP | \
INTR__PROGRAM_COMP | \
INTR__TIME_OUT | \
INTR__ERASE_FAIL | \
INTR__RST_COMP | \
INTR__ERASE_COMP)
/*
* indicates whether or not the internal value for the flash bank is
......@@ -62,8 +62,6 @@ MODULE_PARM_DESC(onfi_timing_mode,
*/
#define CHIP_SELECT_INVALID -1
#define SUPPORT_8BITECC 1
/*
* This macro divides two integers and rounds fractional values up
* to the nearest integer value.
......@@ -86,16 +84,10 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
#define SPARE_ACCESS 0x41
#define MAIN_ACCESS 0x42
#define MAIN_SPARE_ACCESS 0x43
#define PIPELINE_ACCESS 0x2000
#define DENALI_READ 0
#define DENALI_WRITE 0x100
/* types of device accesses. We can issue commands and get status */
#define COMMAND_CYCLE 0
#define ADDR_CYCLE 1
#define STATUS_CYCLE 2
/*
* this is a helper macro that allows us to
* format the bank into the proper bits for the controller
......@@ -164,7 +156,7 @@ static void read_status(struct denali_nand_info *denali)
static void reset_bank(struct denali_nand_info *denali)
{
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT;
uint32_t irq_mask = INTR__RST_COMP | INTR__TIME_OUT;
clear_interrupts(denali);
......@@ -172,7 +164,7 @@ static void reset_bank(struct denali_nand_info *denali)
irq_status = wait_for_irq(denali, irq_mask);
if (irq_status & INTR_STATUS__TIME_OUT)
if (irq_status & INTR__TIME_OUT)
dev_err(denali->dev, "reset bank failed.\n");
}
......@@ -182,22 +174,22 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali)
int i;
for (i = 0; i < denali->max_banks; i++)
iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
iowrite32(INTR__RST_COMP | INTR__TIME_OUT,
denali->flash_reg + INTR_STATUS(i));
for (i = 0; i < denali->max_banks; i++) {
iowrite32(1 << i, denali->flash_reg + DEVICE_RESET);
while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) &
(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT)))
(INTR__RST_COMP | INTR__TIME_OUT)))
cpu_relax();
if (ioread32(denali->flash_reg + INTR_STATUS(i)) &
INTR_STATUS__TIME_OUT)
INTR__TIME_OUT)
dev_dbg(denali->dev,
"NAND Reset operation timed out on bank %d\n", i);
}
for (i = 0; i < denali->max_banks; i++)
iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
iowrite32(INTR__RST_COMP | INTR__TIME_OUT,
denali->flash_reg + INTR_STATUS(i));
return PASS;
......@@ -347,52 +339,25 @@ static void get_samsung_nand_para(struct denali_nand_info *denali,
static void get_toshiba_nand_para(struct denali_nand_info *denali)
{
uint32_t tmp;
/*
* Workaround to fix a controller bug which reports a wrong
* spare area size for some kind of Toshiba NAND device
*/
if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
(ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) {
(ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64))
iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
tmp = ioread32(denali->flash_reg + DEVICES_CONNECTED) *
ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
iowrite32(tmp,
denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
#if SUPPORT_15BITECC
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
#elif SUPPORT_8BITECC
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
#endif
}
}
static void get_hynix_nand_para(struct denali_nand_info *denali,
uint8_t device_id)
{
uint32_t main_size, spare_size;
switch (device_id) {
case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */
iowrite32(128, denali->flash_reg + PAGES_PER_BLOCK);
iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
main_size = 4096 *
ioread32(denali->flash_reg + DEVICES_CONNECTED);
spare_size = 224 *
ioread32(denali->flash_reg + DEVICES_CONNECTED);
iowrite32(main_size,
denali->flash_reg + LOGICAL_PAGE_DATA_SIZE);
iowrite32(spare_size,
denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
iowrite32(0, denali->flash_reg + DEVICE_WIDTH);
#if SUPPORT_15BITECC
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
#elif SUPPORT_8BITECC
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
#endif
break;
default:
dev_warn(denali->dev,
......@@ -454,17 +419,12 @@ static void find_valid_banks(struct denali_nand_info *denali)
static void detect_max_banks(struct denali_nand_info *denali)
{
uint32_t features = ioread32(denali->flash_reg + FEATURES);
/*
* Read the revision register, so we can calculate the max_banks
* properly: the encoding changed from rev 5.0 to 5.1
*/
u32 revision = MAKE_COMPARABLE_REVISION(
ioread32(denali->flash_reg + REVISION));
if (revision < REVISION_5_1)
denali->max_banks = 2 << (features & FEATURES__N_BANKS);
else
denali->max_banks = 1 << (features & FEATURES__N_BANKS);
denali->max_banks = 1 << (features & FEATURES__N_BANKS);
/* the encoding changed from rev 5.0 to 5.1 */
if (denali->revision < 0x0501)
denali->max_banks <<= 1;
}
static uint16_t denali_nand_timing_set(struct denali_nand_info *denali)
......@@ -653,7 +613,6 @@ static irqreturn_t denali_isr(int irq, void *dev_id)
spin_unlock(&denali->irq_lock);
return result;
}
#define BANK(x) ((x) << 24)
static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
{
......@@ -718,15 +677,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
int access_type, int op)
{
int status = PASS;
uint32_t page_count = 1;
uint32_t addr, cmd, irq_status, irq_mask;
if (op == DENALI_READ)
irq_mask = INTR_STATUS__LOAD_COMP;
else if (op == DENALI_WRITE)
irq_mask = 0;
else
BUG();
uint32_t addr, cmd;
setup_ecc_for_xfer(denali, ecc_en, transfer_spare);
......@@ -749,35 +700,8 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
cmd = MODE_10 | addr;
index_addr(denali, cmd, access_type);
/*
* page 33 of the NAND controller spec indicates we should not
* use the pipeline commands in Spare area only mode.
* So we don't.
*/
if (access_type == SPARE_ACCESS) {
cmd = MODE_01 | addr;
iowrite32(cmd, denali->flash_mem);
} else {
index_addr(denali, cmd,
PIPELINE_ACCESS | op | page_count);
/*
* wait for command to be accepted
* can always use status0 bit as the
* mask is identical for each bank.
*/
irq_status = wait_for_irq(denali, irq_mask);
if (irq_status == 0) {
dev_err(denali->dev,
"cmd, page, addr on timeout (0x%x, 0x%x, 0x%x)\n",
cmd, denali->page, addr);
status = FAIL;
} else {
cmd = MODE_01 | addr;
iowrite32(cmd, denali->flash_mem);
}
}
cmd = MODE_01 | addr;
iowrite32(cmd, denali->flash_mem);
}
return status;
}
......@@ -829,8 +753,7 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP |
INTR_STATUS__PROGRAM_FAIL;
uint32_t irq_mask = INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL;
int status = 0;
denali->page = page;
......@@ -857,7 +780,7 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
uint32_t irq_mask = INTR_STATUS__LOAD_COMP;
uint32_t irq_mask = INTR__LOAD_COMP;
uint32_t irq_status, addr, cmd;
denali->page = page;
......@@ -890,98 +813,158 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
}
}
/*
* this function examines buffers to see if they contain data that
* indicate that the buffer is part of an erased region of flash.
*/
static bool is_erased(uint8_t *buf, int len)
static int denali_check_erased_page(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf,
unsigned long uncor_ecc_flags,
unsigned int max_bitflips)
{
int i;
uint8_t *ecc_code = chip->buffers->ecccode;
int ecc_steps = chip->ecc.steps;
int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes;
int i, ret, stat;
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total);
if (ret)
return ret;
for (i = 0; i < ecc_steps; i++) {
if (!(uncor_ecc_flags & BIT(i)))
continue;
for (i = 0; i < len; i++)
if (buf[i] != 0xFF)
return false;
return true;
stat = nand_check_erased_ecc_chunk(buf, ecc_size,
ecc_code, ecc_bytes,
NULL, 0,
chip->ecc.strength);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
buf += ecc_size;
ecc_code += ecc_bytes;
}
return max_bitflips;
}
static int denali_hw_ecc_fixup(struct mtd_info *mtd,
struct denali_nand_info *denali,
unsigned long *uncor_ecc_flags)
{
struct nand_chip *chip = mtd_to_nand(mtd);
int bank = denali->flash_bank;
uint32_t ecc_cor;
unsigned int max_bitflips;
ecc_cor = ioread32(denali->flash_reg + ECC_COR_INFO(bank));
ecc_cor >>= ECC_COR_INFO__SHIFT(bank);
if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
/*
* This flag is set when uncorrectable error occurs at least in
* one ECC sector. We can not know "how many sectors", or
* "which sector(s)". We need erase-page check for all sectors.
*/
*uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0);
return 0;
}
max_bitflips = ecc_cor & ECC_COR_INFO__MAX_ERRORS;
/*
* The register holds the maximum of per-sector corrected bitflips.
* This is suitable for the return value of the ->read_page() callback.
* Unfortunately, we can not know the total number of corrected bits in
* the page. Increase the stats by max_bitflips. (compromised solution)
*/
mtd->ecc_stats.corrected += max_bitflips;
return max_bitflips;
}
#define ECC_SECTOR_SIZE 512
#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
#define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET))
#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK)
#define ECC_ERROR_CORRECTABLE(x) (!((x) & ERR_CORRECTION_INFO__ERROR_TYPE))
#define ECC_ERROR_UNCORRECTABLE(x) ((x) & ERR_CORRECTION_INFO__ERROR_TYPE)
#define ECC_ERR_DEVICE(x) (((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8)
#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)
static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
uint32_t irq_status, unsigned int *max_bitflips)
static int denali_sw_ecc_fixup(struct mtd_info *mtd,
struct denali_nand_info *denali,
unsigned long *uncor_ecc_flags, uint8_t *buf)
{
bool check_erased_page = false;
unsigned int bitflips = 0;
unsigned int max_bitflips = 0;
uint32_t err_addr, err_cor_info;
unsigned int err_byte, err_sector, err_device;
uint8_t err_cor_value;
unsigned int prev_sector = 0;
if (irq_status & INTR_STATUS__ECC_ERR) {
/* read the ECC errors. we'll ignore them for now */
uint32_t err_address, err_correction_info, err_byte,
err_sector, err_device, err_correction_value;
denali_set_intr_modes(denali, false);
do {
err_address = ioread32(denali->flash_reg +
ECC_ERROR_ADDRESS);
err_sector = ECC_SECTOR(err_address);
err_byte = ECC_BYTE(err_address);
err_correction_info = ioread32(denali->flash_reg +
ERR_CORRECTION_INFO);
err_correction_value =
ECC_CORRECTION_VALUE(err_correction_info);
err_device = ECC_ERR_DEVICE(err_correction_info);
if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
/*
* If err_byte is larger than ECC_SECTOR_SIZE,
* means error happened in OOB, so we ignore
* it. It's no need for us to correct it
* err_device is represented the NAND error
* bits are happened in if there are more
* than one NAND connected.
*/
if (err_byte < ECC_SECTOR_SIZE) {
struct mtd_info *mtd =
nand_to_mtd(&denali->nand);
int offset;
offset = (err_sector *
ECC_SECTOR_SIZE +
err_byte) *
denali->devnum +
err_device;
/* correct the ECC error */
buf[offset] ^= err_correction_value;
mtd->ecc_stats.corrected++;
bitflips++;
}
} else {
/*
* if the error is not correctable, need to
* look at the page to see if it is an erased
* page. if so, then it's not a real ECC error
*/
check_erased_page = true;
}
} while (!ECC_LAST_ERR(err_correction_info));
/*
* Once handle all ecc errors, controller will triger
* a ECC_TRANSACTION_DONE interrupt, so here just wait
* for a while for this interrupt
*/
while (!(read_interrupt_status(denali) &
INTR_STATUS__ECC_TRANSACTION_DONE))
cpu_relax();
clear_interrupts(denali);
denali_set_intr_modes(denali, true);
}
*max_bitflips = bitflips;
return check_erased_page;
/* read the ECC errors. we'll ignore them for now */
denali_set_intr_modes(denali, false);
do {
err_addr = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS);
err_sector = ECC_SECTOR(err_addr);
err_byte = ECC_BYTE(err_addr);
err_cor_info = ioread32(denali->flash_reg + ERR_CORRECTION_INFO);
err_cor_value = ECC_CORRECTION_VALUE(err_cor_info);
err_device = ECC_ERR_DEVICE(err_cor_info);
/* reset the bitflip counter when crossing ECC sector */
if (err_sector != prev_sector)
bitflips = 0;
if (ECC_ERROR_UNCORRECTABLE(err_cor_info)) {
/*
* Check later if this is a real ECC error, or
* an erased sector.
*/
*uncor_ecc_flags |= BIT(err_sector);
} else if (err_byte < ECC_SECTOR_SIZE) {
/*
* If err_byte is larger than ECC_SECTOR_SIZE, means error
* happened in OOB, so we ignore it. It's no need for
* us to correct it err_device is represented the NAND
* error bits are happened in if there are more than
* one NAND connected.
*/
int offset;
unsigned int flips_in_byte;
offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
denali->devnum + err_device;
/* correct the ECC error */
flips_in_byte = hweight8(buf[offset] ^ err_cor_value);
buf[offset] ^= err_cor_value;
mtd->ecc_stats.corrected += flips_in_byte;
bitflips += flips_in_byte;
max_bitflips = max(max_bitflips, bitflips);
}
prev_sector = err_sector;
} while (!ECC_LAST_ERR(err_cor_info));
/*
* Once handle all ecc errors, controller will trigger a
* ECC_TRANSACTION_DONE interrupt, so here just wait for
* a while for this interrupt
*/
while (!(read_interrupt_status(denali) & INTR__ECC_TRANSACTION_DONE))
cpu_relax();
clear_interrupts(denali);
denali_set_intr_modes(denali, true);
return max_bitflips;
}
/* programs the controller to either enable/disable DMA transfers */
......@@ -991,8 +974,30 @@ static void denali_enable_dma(struct denali_nand_info *denali, bool en)
ioread32(denali->flash_reg + DMA_ENABLE);
}
/* setups the HW to perform the data DMA */
static void denali_setup_dma(struct denali_nand_info *denali, int op)
static void denali_setup_dma64(struct denali_nand_info *denali, int op)
{
uint32_t mode;
const int page_count = 1;
uint64_t addr = denali->buf.dma_buf;
mode = MODE_10 | BANK(denali->flash_bank) | denali->page;
/* DMA is a three step process */
/*
* 1. setup transfer type, interrupt when complete,
* burst len = 64 bytes, the number of pages
*/
index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count);
/* 2. set memory low address */
index_addr(denali, mode, addr);
/* 3. set memory high address */
index_addr(denali, mode, addr >> 32);
}
static void denali_setup_dma32(struct denali_nand_info *denali, int op)
{
uint32_t mode;
const int page_count = 1;
......@@ -1015,6 +1020,14 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
index_addr(denali, mode | 0x14000, 0x2400);
}
static void denali_setup_dma(struct denali_nand_info *denali, int op)
{
if (denali->caps & DENALI_CAP_DMA_64BIT)
denali_setup_dma64(denali, op);
else
denali_setup_dma32(denali, op);
}
/*
* writes a page. user specifies type, and this function handles the
* configuration details.
......@@ -1026,8 +1039,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP |
INTR_STATUS__PROGRAM_FAIL;
uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL;
/*
* if it is a raw xfer, we want to disable ecc and send the spare area.
......@@ -1118,16 +1130,15 @@ static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
unsigned int max_bitflips;
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_status;
uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE |
INTR_STATUS__ECC_ERR;
bool check_erased_page = false;
uint32_t irq_mask = denali->caps & DENALI_CAP_HW_ECC_FIXUP ?
INTR__DMA_CMD_COMP | INTR__ECC_UNCOR_ERR :
INTR__ECC_TRANSACTION_DONE | INTR__ECC_ERR;
unsigned long uncor_ecc_flags = 0;
int stat = 0;
if (page != denali->page) {
dev_err(denali->dev,
......@@ -1151,21 +1162,23 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
memcpy(buf, denali->buf.buf, mtd->writesize);
check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips);
if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags);
else if (irq_status & INTR__ECC_ERR)
stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf);
denali_enable_dma(denali, false);
if (check_erased_page) {
if (stat < 0)
return stat;
if (uncor_ecc_flags) {
read_oob_data(mtd, chip->oob_poi, denali->page);
/* check ECC failures that may have occurred on erased pages */
if (check_erased_page) {
if (!is_erased(buf, mtd->writesize))
mtd->ecc_stats.failed++;
if (!is_erased(buf, mtd->oobsize))
mtd->ecc_stats.failed++;
}
stat = denali_check_erased_page(mtd, chip, buf,
uncor_ecc_flags, stat);
}
return max_bitflips;
return stat;
}
static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
......@@ -1174,7 +1187,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
size_t size = mtd->writesize + mtd->oobsize;
uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP;
uint32_t irq_mask = INTR__DMA_CMD_COMP;
if (page != denali->page) {
dev_err(denali->dev,
......@@ -1247,10 +1260,9 @@ static int denali_erase(struct mtd_info *mtd, int page)
index_addr(denali, cmd, 0x1);
/* wait for erase to complete or failure to occur */
irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP |
INTR_STATUS__ERASE_FAIL);
irq_status = wait_for_irq(denali, INTR__ERASE_COMP | INTR__ERASE_FAIL);
return irq_status & INTR_STATUS__ERASE_FAIL ? NAND_STATUS_FAIL : PASS;
return irq_status & INTR__ERASE_FAIL ? NAND_STATUS_FAIL : PASS;
}
static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
......@@ -1302,6 +1314,14 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
/* Initialization code to bring the device up to a known good state */
static void denali_hw_init(struct denali_nand_info *denali)
{
/*
* The REVISION register may not be reliable. Platforms are allowed to
* override it.
*/
if (!denali->revision)
denali->revision =
swab16(ioread32(denali->flash_reg + REVISION));
/*
* tell driver how many bit controller will skip before
* writing ECC code in OOB, this register may be already
......@@ -1413,9 +1433,61 @@ static void denali_drv_init(struct denali_nand_info *denali)
denali->irq_status = 0;
}
static int denali_multidev_fixup(struct denali_nand_info *denali)
{
struct nand_chip *chip = &denali->nand;
struct mtd_info *mtd = nand_to_mtd(chip);
/*
* Support for multi device:
* When the IP configuration is x16 capable and two x8 chips are
* connected in parallel, DEVICES_CONNECTED should be set to 2.
* In this case, the core framework knows nothing about this fact,
* so we should tell it the _logical_ pagesize and anything necessary.
*/
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
/*
* On some SoCs, DEVICES_CONNECTED is not auto-detected.
* For those, DEVICES_CONNECTED is left to 0. Set 1 if it is the case.
*/
if (denali->devnum == 0) {
denali->devnum = 1;
iowrite32(1, denali->flash_reg + DEVICES_CONNECTED);
}
if (denali->devnum == 1)
return 0;
if (denali->devnum != 2) {
dev_err(denali->dev, "unsupported number of devices %d\n",
denali->devnum);
return -EINVAL;
}
/* 2 chips in parallel */
mtd->size <<= 1;
mtd->erasesize <<= 1;
mtd->writesize <<= 1;
mtd->oobsize <<= 1;
chip->chipsize <<= 1;
chip->page_shift += 1;
chip->phys_erase_shift += 1;
chip->bbt_erase_shift += 1;
chip->chip_shift += 1;
chip->pagemask <<= 1;
chip->ecc.size <<= 1;
chip->ecc.bytes <<= 1;
chip->ecc.strength <<= 1;
denali->bbtskipbytes <<= 1;
return 0;
}
int denali_init(struct denali_nand_info *denali)
{
struct mtd_info *mtd = nand_to_mtd(&denali->nand);
struct nand_chip *chip = &denali->nand;
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
if (denali->platform == INTEL_CE4100) {
......@@ -1449,13 +1521,16 @@ int denali_init(struct denali_nand_info *denali)
/* now that our ISR is registered, we can enable interrupts */
denali_set_intr_modes(denali, true);
mtd->name = "denali-nand";
nand_set_flash_node(chip, denali->dev->of_node);
/* Fallback to the default name if DT did not give "label" property */
if (!mtd->name)
mtd->name = "denali-nand";
/* register the driver with the NAND core subsystem */
denali->nand.select_chip = denali_select_chip;
denali->nand.cmdfunc = denali_cmdfunc;
denali->nand.read_byte = denali_read_byte;
denali->nand.waitfunc = denali_waitfunc;
chip->select_chip = denali_select_chip;
chip->cmdfunc = denali_cmdfunc;
chip->read_byte = denali_read_byte;
chip->waitfunc = denali_waitfunc;
/*
* scan for NAND devices attached to the controller
......@@ -1476,8 +1551,9 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
}
/* Is 32-bit DMA supported? */
ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
ret = dma_set_mask(denali->dev,
DMA_BIT_MASK(denali->caps & DENALI_CAP_DMA_64BIT ?
64 : 32));
if (ret) {
dev_err(denali->dev, "No usable DMA configuration\n");
goto failed_req_irq;
......@@ -1492,25 +1568,6 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
}
/*
* support for multi nand
* MTD known nothing about multi nand, so we should tell it
* the real pagesize and anything necessery
*/
denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED);
denali->nand.chipsize <<= denali->devnum - 1;
denali->nand.page_shift += denali->devnum - 1;
denali->nand.pagemask = (denali->nand.chipsize >>
denali->nand.page_shift) - 1;
denali->nand.bbt_erase_shift += denali->devnum - 1;
denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift;
denali->nand.chip_shift += denali->devnum - 1;
mtd->writesize <<= denali->devnum - 1;
mtd->oobsize <<= denali->devnum - 1;
mtd->erasesize <<= denali->devnum - 1;
mtd->size = denali->nand.numchips * denali->nand.chipsize;
denali->bbtskipbytes *= denali->devnum;
/*
* second stage of the NAND scan
* this stage requires information regarding ECC and
......@@ -1518,29 +1575,29 @@ int denali_init(struct denali_nand_info *denali)
*/
/* Bad block management */
denali->nand.bbt_td = &bbt_main_descr;
denali->nand.bbt_md = &bbt_mirror_descr;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
/* skip the scan for now until we have OOB read and write support */
denali->nand.bbt_options |= NAND_BBT_USE_FLASH;
denali->nand.options |= NAND_SKIP_BBTSCAN;
denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
chip->bbt_options |= NAND_BBT_USE_FLASH;
chip->options |= NAND_SKIP_BBTSCAN;
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
/* no subpage writes on denali */
denali->nand.options |= NAND_NO_SUBPAGE_WRITE;
chip->options |= NAND_NO_SUBPAGE_WRITE;
/*
* Denali Controller only support 15bit and 8bit ECC in MRST,
* so just let controller do 15bit ECC for MLC and 8bit ECC for
* SLC if possible.
* */
if (!nand_is_slc(&denali->nand) &&
if (!nand_is_slc(chip) &&
(mtd->oobsize > (denali->bbtskipbytes +
ECC_15BITS * (mtd->writesize /
ECC_SECTOR_SIZE)))) {
/* if MLC OOB size is large enough, use 15bit ECC*/
denali->nand.ecc.strength = 15;
denali->nand.ecc.bytes = ECC_15BITS;
chip->ecc.strength = 15;
chip->ecc.bytes = ECC_15BITS;
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
} else if (mtd->oobsize < (denali->bbtskipbytes +
ECC_8BITS * (mtd->writesize /
......@@ -1548,24 +1605,26 @@ int denali_init(struct denali_nand_info *denali)
pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
goto failed_req_irq;
} else {
denali->nand.ecc.strength = 8;
denali->nand.ecc.bytes = ECC_8BITS;
chip->ecc.strength = 8;
chip->ecc.bytes = ECC_8BITS;
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
}
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
denali->nand.ecc.bytes *= denali->devnum;
denali->nand.ecc.strength *= denali->devnum;
/* override the default read operations */
denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
denali->nand.ecc.read_page = denali_read_page;
denali->nand.ecc.read_page_raw = denali_read_page_raw;
denali->nand.ecc.write_page = denali_write_page;
denali->nand.ecc.write_page_raw = denali_write_page_raw;
denali->nand.ecc.read_oob = denali_read_oob;
denali->nand.ecc.write_oob = denali_write_oob;
denali->nand.erase = denali_erase;
chip->ecc.size = ECC_SECTOR_SIZE;
chip->ecc.read_page = denali_read_page;
chip->ecc.read_page_raw = denali_read_page_raw;
chip->ecc.write_page = denali_write_page;
chip->ecc.write_page_raw = denali_write_page_raw;
chip->ecc.read_oob = denali_read_oob;
chip->ecc.write_oob = denali_write_oob;
chip->erase = denali_erase;
ret = denali_multidev_fixup(denali);
if (ret)
goto failed_req_irq;
ret = nand_scan_tail(mtd);
if (ret)
......
......@@ -20,6 +20,7 @@
#ifndef __DENALI_H__
#define __DENALI_H__
#include <linux/bitops.h>
#include <linux/mtd/nand.h>
#define DEVICE_RESET 0x0
......@@ -178,8 +179,6 @@
#define REVISION 0x370
#define REVISION__VALUE 0xffff
#define MAKE_COMPARABLE_REVISION(x) swab16((x) & REVISION__VALUE)
#define REVISION_5_1 0x00000501
#define ONFI_DEVICE_FEATURES 0x380
#define ONFI_DEVICE_FEATURES__VALUE 0x003f
......@@ -218,65 +217,29 @@
#define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50))
#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50))
#define INTR_STATUS__ECC_TRANSACTION_DONE 0x0001
#define INTR_STATUS__ECC_ERR 0x0002
#define INTR_STATUS__DMA_CMD_COMP 0x0004
#define INTR_STATUS__TIME_OUT 0x0008
#define INTR_STATUS__PROGRAM_FAIL 0x0010
#define INTR_STATUS__ERASE_FAIL 0x0020
#define INTR_STATUS__LOAD_COMP 0x0040
#define INTR_STATUS__PROGRAM_COMP 0x0080
#define INTR_STATUS__ERASE_COMP 0x0100
#define INTR_STATUS__PIPE_CPYBCK_CMD_COMP 0x0200
#define INTR_STATUS__LOCKED_BLK 0x0400
#define INTR_STATUS__UNSUP_CMD 0x0800
#define INTR_STATUS__INT_ACT 0x1000
#define INTR_STATUS__RST_COMP 0x2000
#define INTR_STATUS__PIPE_CMD_ERR 0x4000
#define INTR_STATUS__PAGE_XFER_INC 0x8000
#define INTR_EN__ECC_TRANSACTION_DONE 0x0001
#define INTR_EN__ECC_ERR 0x0002
#define INTR_EN__DMA_CMD_COMP 0x0004
#define INTR_EN__TIME_OUT 0x0008
#define INTR_EN__PROGRAM_FAIL 0x0010
#define INTR_EN__ERASE_FAIL 0x0020
#define INTR_EN__LOAD_COMP 0x0040
#define INTR_EN__PROGRAM_COMP 0x0080
#define INTR_EN__ERASE_COMP 0x0100
#define INTR_EN__PIPE_CPYBCK_CMD_COMP 0x0200
#define INTR_EN__LOCKED_BLK 0x0400
#define INTR_EN__UNSUP_CMD 0x0800
#define INTR_EN__INT_ACT 0x1000
#define INTR_EN__RST_COMP 0x2000
#define INTR_EN__PIPE_CMD_ERR 0x4000
#define INTR_EN__PAGE_XFER_INC 0x8000
/* bit[1:0] is used differently depending on IP version */
#define INTR__ECC_UNCOR_ERR 0x0001 /* new IP */
#define INTR__ECC_TRANSACTION_DONE 0x0001 /* old IP */
#define INTR__ECC_ERR 0x0002 /* old IP */
#define INTR__DMA_CMD_COMP 0x0004
#define INTR__TIME_OUT 0x0008
#define INTR__PROGRAM_FAIL 0x0010
#define INTR__ERASE_FAIL 0x0020
#define INTR__LOAD_COMP 0x0040
#define INTR__PROGRAM_COMP 0x0080
#define INTR__ERASE_COMP 0x0100
#define INTR__PIPE_CPYBCK_CMD_COMP 0x0200
#define INTR__LOCKED_BLK 0x0400
#define INTR__UNSUP_CMD 0x0800
#define INTR__INT_ACT 0x1000
#define INTR__RST_COMP 0x2000
#define INTR__PIPE_CMD_ERR 0x4000
#define INTR__PAGE_XFER_INC 0x8000
#define PAGE_CNT(__bank) (0x430 + ((__bank) * 0x50))
#define ERR_PAGE_ADDR(__bank) (0x440 + ((__bank) * 0x50))
#define ERR_BLOCK_ADDR(__bank) (0x450 + ((__bank) * 0x50))
#define DATA_INTR 0x550
#define DATA_INTR__WRITE_SPACE_AV 0x0001
#define DATA_INTR__READ_DATA_AV 0x0002
#define DATA_INTR_EN 0x560
#define DATA_INTR_EN__WRITE_SPACE_AV 0x0001
#define DATA_INTR_EN__READ_DATA_AV 0x0002
#define GPREG_0 0x570
#define GPREG_0__VALUE 0xffff
#define GPREG_1 0x580
#define GPREG_1__VALUE 0xffff
#define GPREG_2 0x590
#define GPREG_2__VALUE 0xffff
#define GPREG_3 0x5a0
#define GPREG_3__VALUE 0xffff
#define ECC_THRESHOLD 0x600
#define ECC_THRESHOLD__VALUE 0x03ff
......@@ -297,6 +260,11 @@
#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000
#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000
#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10)
#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8)
#define ECC_COR_INFO__MAX_ERRORS 0x007f
#define ECC_COR_INFO__UNCOR_ERR 0x0080
#define DMA_ENABLE 0x700
#define DMA_ENABLE__FLAG 0x0001
......@@ -304,20 +272,13 @@
#define IGNORE_ECC_DONE__FLAG 0x0001
#define DMA_INTR 0x720
#define DMA_INTR_EN 0x730
#define DMA_INTR__TARGET_ERROR 0x0001
#define DMA_INTR__DESC_COMP_CHANNEL0 0x0002
#define DMA_INTR__DESC_COMP_CHANNEL1 0x0004
#define DMA_INTR__DESC_COMP_CHANNEL2 0x0008
#define DMA_INTR__DESC_COMP_CHANNEL3 0x0010
#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020
#define DMA_INTR_EN 0x730
#define DMA_INTR_EN__TARGET_ERROR 0x0001
#define DMA_INTR_EN__DESC_COMP_CHANNEL0 0x0002
#define DMA_INTR_EN__DESC_COMP_CHANNEL1 0x0004
#define DMA_INTR_EN__DESC_COMP_CHANNEL2 0x0008
#define DMA_INTR_EN__DESC_COMP_CHANNEL3 0x0010
#define DMA_INTR_EN__MEMCOPY_DESC_COMP 0x0020
#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020
#define TARGET_ERR_ADDR_LO 0x740
#define TARGET_ERR_ADDR_LO__VALUE 0xffff
......@@ -331,69 +292,12 @@
#define CHNL_ACTIVE__CHANNEL2 0x0004
#define CHNL_ACTIVE__CHANNEL3 0x0008
#define ACTIVE_SRC_ID 0x800
#define ACTIVE_SRC_ID__VALUE 0x00ff
#define PTN_INTR 0x810
#define PTN_INTR__CONFIG_ERROR 0x0001
#define PTN_INTR__ACCESS_ERROR_BANK0 0x0002
#define PTN_INTR__ACCESS_ERROR_BANK1 0x0004
#define PTN_INTR__ACCESS_ERROR_BANK2 0x0008
#define PTN_INTR__ACCESS_ERROR_BANK3 0x0010
#define PTN_INTR__REG_ACCESS_ERROR 0x0020
#define PTN_INTR_EN 0x820
#define PTN_INTR_EN__CONFIG_ERROR 0x0001
#define PTN_INTR_EN__ACCESS_ERROR_BANK0 0x0002
#define PTN_INTR_EN__ACCESS_ERROR_BANK1 0x0004
#define PTN_INTR_EN__ACCESS_ERROR_BANK2 0x0008
#define PTN_INTR_EN__ACCESS_ERROR_BANK3 0x0010
#define PTN_INTR_EN__REG_ACCESS_ERROR 0x0020
#define PERM_SRC_ID(__bank) (0x830 + ((__bank) * 0x40))
#define PERM_SRC_ID__SRCID 0x00ff
#define PERM_SRC_ID__DIRECT_ACCESS_ACTIVE 0x0800
#define PERM_SRC_ID__WRITE_ACTIVE 0x2000
#define PERM_SRC_ID__READ_ACTIVE 0x4000
#define PERM_SRC_ID__PARTITION_VALID 0x8000
#define MIN_BLK_ADDR(__bank) (0x840 + ((__bank) * 0x40))
#define MIN_BLK_ADDR__VALUE 0xffff
#define MAX_BLK_ADDR(__bank) (0x850 + ((__bank) * 0x40))
#define MAX_BLK_ADDR__VALUE 0xffff
#define MIN_MAX_BANK(__bank) (0x860 + ((__bank) * 0x40))
#define MIN_MAX_BANK__MIN_VALUE 0x0003
#define MIN_MAX_BANK__MAX_VALUE 0x000c
/* ffsdefs.h */
#define CLEAR 0 /*use this to clear a field instead of "fail"*/
#define SET 1 /*use this to set a field instead of "pass"*/
#define FAIL 1 /*failed flag*/
#define PASS 0 /*success flag*/
#define ERR -1 /*error flag*/
/* lld.h */
#define GOOD_BLOCK 0
#define DEFECTIVE_BLOCK 1
#define READ_ERROR 2
#define CLK_X 5
#define CLK_MULTI 4
/* KBV - Updated to LNW scratch register address */
#define SCRATCH_REG_ADDR CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR
#define SCRATCH_REG_SIZE 64
#define GLOB_HWCTL_DEFAULT_BLKS 2048
#define SUPPORT_15BITECC 1
#define SUPPORT_8BITECC 1
#define CUSTOM_CONF_PARAMS 0
#define ONFI_BLOOM_TIME 1
#define MODE5_WORKAROUND 0
......@@ -403,31 +307,6 @@
#define MODE_10 0x08000000
#define MODE_11 0x0C000000
#define DATA_TRANSFER_MODE 0
#define PROTECTION_PER_BLOCK 1
#define LOAD_WAIT_COUNT 2
#define PROGRAM_WAIT_COUNT 3
#define ERASE_WAIT_COUNT 4
#define INT_MONITOR_CYCLE_COUNT 5
#define READ_BUSY_PIN_ENABLED 6
#define MULTIPLANE_OPERATION_SUPPORT 7
#define PRE_FETCH_MODE 8
#define CE_DONT_CARE_SUPPORT 9
#define COPYBACK_SUPPORT 10
#define CACHE_WRITE_SUPPORT 11
#define CACHE_READ_SUPPORT 12
#define NUM_PAGES_IN_BLOCK 13
#define ECC_ENABLE_SELECT 14
#define WRITE_ENABLE_2_READ_ENABLE 15
#define ADDRESS_2_DATA 16
#define READ_ENABLE_2_WRITE_ENABLE 17
#define TWO_ROW_ADDRESS_CYCLES 18
#define MULTIPLANE_ADDRESS_RESTRICT 19
#define ACC_CLOCKS 20
#define READ_WRITE_ENABLE_LOW_COUNT 21
#define READ_WRITE_ENABLE_HIGH_COUNT 22
#define ECC_SECTOR_SIZE 512
struct nand_buf {
......@@ -449,23 +328,26 @@ struct denali_nand_info {
struct nand_buf buf;
struct device *dev;
int total_used_banks;
uint32_t block; /* stored for future use */
uint16_t page;
void __iomem *flash_reg; /* Mapped io reg base address */
void __iomem *flash_mem; /* Mapped io reg base address */
int page;
void __iomem *flash_reg; /* Register Interface */
void __iomem *flash_mem; /* Host Data/Command Interface */
/* elements used by ISR */
struct completion complete;
spinlock_t irq_lock;
uint32_t irq_status;
int irq_debug_array[32];
int irq;
uint32_t devnum; /* represent how many nands connected */
uint32_t bbtskipbytes;
uint32_t max_banks;
int devnum; /* represent how many nands connected */
int bbtskipbytes;
int max_banks;
unsigned int revision;
unsigned int caps;
};
#define DENALI_CAP_HW_ECC_FIXUP BIT(0)
#define DENALI_CAP_DMA_64BIT BIT(1)
extern int denali_init(struct denali_nand_info *denali);
extern void denali_remove(struct denali_nand_info *denali);
......
......@@ -29,64 +29,66 @@ struct denali_dt {
struct clk *clk;
};
static const struct of_device_id denali_nand_dt_ids[] = {
{ .compatible = "denali,denali-nand-dt" },
{ /* sentinel */ }
};
struct denali_dt_data {
unsigned int revision;
unsigned int caps;
};
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
static const struct denali_dt_data denali_socfpga_data = {
.caps = DENALI_CAP_HW_ECC_FIXUP,
};
static u64 denali_dma_mask;
static const struct of_device_id denali_nand_dt_ids[] = {
{
.compatible = "altr,socfpga-denali-nand",
.data = &denali_socfpga_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
static int denali_dt_probe(struct platform_device *ofdev)
static int denali_dt_probe(struct platform_device *pdev)
{
struct resource *denali_reg, *nand_data;
struct denali_dt *dt;
const struct denali_dt_data *data;
struct denali_nand_info *denali;
int ret;
const struct of_device_id *of_id;
of_id = of_match_device(denali_nand_dt_ids, &ofdev->dev);
if (of_id) {
ofdev->id_entry = of_id->data;
} else {
pr_err("Failed to find the right device id.\n");
return -ENOMEM;
}
dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL);
dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL);
if (!dt)
return -ENOMEM;
denali = &dt->denali;
data = of_device_get_match_data(&pdev->dev);
if (data) {
denali->revision = data->revision;
denali->caps = data->caps;
}
denali->platform = DT;
denali->dev = &ofdev->dev;
denali->irq = platform_get_irq(ofdev, 0);
denali->dev = &pdev->dev;
denali->irq = platform_get_irq(pdev, 0);
if (denali->irq < 0) {
dev_err(&ofdev->dev, "no irq defined\n");
dev_err(&pdev->dev, "no irq defined\n");
return denali->irq;
}
denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg");
denali->flash_reg = devm_ioremap_resource(&ofdev->dev, denali_reg);
denali_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"denali_reg");
denali->flash_reg = devm_ioremap_resource(&pdev->dev, denali_reg);
if (IS_ERR(denali->flash_reg))
return PTR_ERR(denali->flash_reg);
nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data");
denali->flash_mem = devm_ioremap_resource(&ofdev->dev, nand_data);
nand_data = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"nand_data");
denali->flash_mem = devm_ioremap_resource(&pdev->dev, nand_data);
if (IS_ERR(denali->flash_mem))
return PTR_ERR(denali->flash_mem);
if (!of_property_read_u32(ofdev->dev.of_node,
"dma-mask", (u32 *)&denali_dma_mask)) {
denali->dev->dma_mask = &denali_dma_mask;
} else {
denali->dev->dma_mask = NULL;
}
dt->clk = devm_clk_get(&ofdev->dev, NULL);
dt->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dt->clk)) {
dev_err(&ofdev->dev, "no clk available\n");
dev_err(&pdev->dev, "no clk available\n");
return PTR_ERR(dt->clk);
}
clk_prepare_enable(dt->clk);
......@@ -95,7 +97,7 @@ static int denali_dt_probe(struct platform_device *ofdev)
if (ret)
goto out_disable_clk;
platform_set_drvdata(ofdev, dt);
platform_set_drvdata(pdev, dt);
return 0;
out_disable_clk:
......@@ -104,9 +106,9 @@ static int denali_dt_probe(struct platform_device *ofdev)
return ret;
}
static int denali_dt_remove(struct platform_device *ofdev)
static int denali_dt_remove(struct platform_device *pdev)
{
struct denali_dt *dt = platform_get_drvdata(ofdev);
struct denali_dt *dt = platform_get_drvdata(pdev);
denali_remove(&dt->denali);
clk_disable_unprepare(dt->clk);
......
......@@ -38,15 +38,6 @@
#include <linux/amba/bus.h>
#include <mtd/mtd-abi.h>
#define FSMC_NAND_BW8 1
#define FSMC_NAND_BW16 2
#define FSMC_MAX_NOR_BANKS 4
#define FSMC_MAX_NAND_BANKS 4
#define FSMC_FLASH_WIDTH8 1
#define FSMC_FLASH_WIDTH16 2
/* fsmc controller registers for NOR flash */
#define CTRL 0x0
/* ctrl register definitions */
......@@ -133,33 +124,48 @@ enum access_mode {
};
/**
* fsmc_nand_platform_data - platform specific NAND controller config
* @nand_timings: timing setup for the physical NAND interface
* @partitions: partition table for the platform, use a default fallback
* if this is NULL
* @nr_partitions: the number of partitions in the previous entry
* @options: different options for the driver
* @width: bus width
* @bank: default bank
* @select_bank: callback to select a certain bank, this is
* platform-specific. If the controller only supports one bank
* this may be set to NULL
* struct fsmc_nand_data - structure for FSMC NAND device state
*
* @pid: Part ID on the AMBA PrimeCell format
* @mtd: MTD info for a NAND flash.
* @nand: Chip related info for a NAND flash.
* @partitions: Partition info for a NAND Flash.
* @nr_partitions: Total number of partition of a NAND flash.
*
* @bank: Bank number for probed device.
* @clk: Clock structure for FSMC.
*
* @read_dma_chan: DMA channel for read access
* @write_dma_chan: DMA channel for write access to NAND
* @dma_access_complete: Completion structure
*
* @data_pa: NAND Physical port for Data.
* @data_va: NAND port for Data.
* @cmd_va: NAND port for Command.
* @addr_va: NAND port for Address.
* @regs_va: FSMC regs base address.
*/
struct fsmc_nand_platform_data {
struct fsmc_nand_timings *nand_timings;
struct mtd_partition *partitions;
unsigned int nr_partitions;
unsigned int options;
unsigned int width;
unsigned int bank;
struct fsmc_nand_data {
u32 pid;
struct nand_chip nand;
unsigned int bank;
struct device *dev;
enum access_mode mode;
struct clk *clk;
void (*select_bank)(uint32_t bank, uint32_t busw);
/* DMA related objects */
struct dma_chan *read_dma_chan;
struct dma_chan *write_dma_chan;
struct completion dma_access_complete;
/* priv structures for dma accesses */
void *read_dma_priv;
void *write_dma_priv;
struct fsmc_nand_timings *dev_timings;
dma_addr_t data_pa;
void __iomem *data_va;
void __iomem *cmd_va;
void __iomem *addr_va;
void __iomem *regs_va;
};
static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
......@@ -246,86 +252,11 @@ static const struct mtd_ooblayout_ops fsmc_ecc4_ooblayout_ops = {
.free = fsmc_ecc4_ooblayout_free,
};
/**
* struct fsmc_nand_data - structure for FSMC NAND device state
*
* @pid: Part ID on the AMBA PrimeCell format
* @mtd: MTD info for a NAND flash.
* @nand: Chip related info for a NAND flash.
* @partitions: Partition info for a NAND Flash.
* @nr_partitions: Total number of partition of a NAND flash.
*
* @bank: Bank number for probed device.
* @clk: Clock structure for FSMC.
*
* @read_dma_chan: DMA channel for read access
* @write_dma_chan: DMA channel for write access to NAND
* @dma_access_complete: Completion structure
*
* @data_pa: NAND Physical port for Data.
* @data_va: NAND port for Data.
* @cmd_va: NAND port for Command.
* @addr_va: NAND port for Address.
* @regs_va: FSMC regs base address.
*/
struct fsmc_nand_data {
u32 pid;
struct nand_chip nand;
struct mtd_partition *partitions;
unsigned int nr_partitions;
unsigned int bank;
struct device *dev;
enum access_mode mode;
struct clk *clk;
/* DMA related objects */
struct dma_chan *read_dma_chan;
struct dma_chan *write_dma_chan;
struct completion dma_access_complete;
struct fsmc_nand_timings *dev_timings;
dma_addr_t data_pa;
void __iomem *data_va;
void __iomem *cmd_va;
void __iomem *addr_va;
void __iomem *regs_va;
void (*select_chip)(uint32_t bank, uint32_t busw);
};
static inline struct fsmc_nand_data *mtd_to_fsmc(struct mtd_info *mtd)
{
return container_of(mtd_to_nand(mtd), struct fsmc_nand_data, nand);
}
/* Assert CS signal based on chipnr */
static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct fsmc_nand_data *host;
host = mtd_to_fsmc(mtd);
switch (chipnr) {
case -1:
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
break;
case 0:
case 1:
case 2:
case 3:
if (host->select_chip)
host->select_chip(chipnr,
chip->options & NAND_BUSWIDTH_16);
break;
default:
dev_err(host->dev, "unsupported chip-select %d\n", chipnr);
}
}
/*
* fsmc_cmd_ctrl - For facilitaing Hardware access
* This routine allows hardware specific access to control-lines(ALE,CLE)
......@@ -838,44 +769,46 @@ static bool filter(struct dma_chan *chan, void *slave)
}
static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
struct fsmc_nand_data *host,
struct nand_chip *nand)
{
struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
u32 val;
int ret;
/* Set default NAND width to 8 bits */
pdata->width = 8;
nand->options = 0;
if (!of_property_read_u32(np, "bank-width", &val)) {
if (val == 2) {
pdata->width = 16;
nand->options |= NAND_BUSWIDTH_16;
} else if (val != 1) {
dev_err(&pdev->dev, "invalid bank-width %u\n", val);
return -EINVAL;
}
}
if (of_get_property(np, "nand-skip-bbtscan", NULL))
pdata->options = NAND_SKIP_BBTSCAN;
nand->options |= NAND_SKIP_BBTSCAN;
pdata->nand_timings = devm_kzalloc(&pdev->dev,
sizeof(*pdata->nand_timings), GFP_KERNEL);
if (!pdata->nand_timings)
host->dev_timings = devm_kzalloc(&pdev->dev,
sizeof(*host->dev_timings), GFP_KERNEL);
if (!host->dev_timings)
return -ENOMEM;
ret = of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
sizeof(*pdata->nand_timings));
ret = of_property_read_u8_array(np, "timings", (u8 *)host->dev_timings,
sizeof(*host->dev_timings));
if (ret) {
dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n");
pdata->nand_timings = NULL;
host->dev_timings = NULL;
}
/* Set default NAND bank to 0 */
pdata->bank = 0;
host->bank = 0;
if (!of_property_read_u32(np, "bank", &val)) {
if (val > 3) {
dev_err(&pdev->dev, "invalid bank %u\n", val);
return -EINVAL;
}
pdata->bank = val;
host->bank = val;
}
return 0;
}
......@@ -886,8 +819,6 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
*/
static int __init fsmc_nand_probe(struct platform_device *pdev)
{
struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node __maybe_unused *np = pdev->dev.of_node;
struct fsmc_nand_data *host;
struct mtd_info *mtd;
struct nand_chip *nand;
......@@ -897,22 +828,17 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
u32 pid;
int i;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdev->dev.platform_data = pdata;
ret = fsmc_nand_probe_config_dt(pdev, np);
if (ret) {
dev_err(&pdev->dev, "no platform data\n");
return -ENODEV;
}
/* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host)
return -ENOMEM;
nand = &host->nand;
ret = fsmc_nand_probe_config_dt(pdev, host, nand);
if (ret)
return ret;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
host->data_va = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->data_va))
......@@ -935,7 +861,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (IS_ERR(host->regs_va))
return PTR_ERR(host->regs_va);
host->clk = clk_get(&pdev->dev, NULL);
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk)) {
dev_err(&pdev->dev, "failed to fetch block clock\n");
return PTR_ERR(host->clk);
......@@ -943,7 +869,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
ret = clk_prepare_enable(host->clk);
if (ret)
goto err_clk_prepare_enable;
return ret;
/*
* This device ID is actually a common AMBA ID as used on the
......@@ -957,22 +883,15 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid),
AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid));
host->bank = pdata->bank;
host->select_chip = pdata->select_bank;
host->partitions = pdata->partitions;
host->nr_partitions = pdata->nr_partitions;
host->dev = &pdev->dev;
host->dev_timings = pdata->nand_timings;
host->mode = pdata->mode;
if (host->mode == USE_DMA_ACCESS)
init_completion(&host->dma_access_complete);
/* Link all private pointers */
mtd = nand_to_mtd(&host->nand);
nand = &host->nand;
nand_set_controller_data(nand, host);
nand_set_flash_node(nand, np);
nand_set_flash_node(nand, pdev->dev.of_node);
mtd->dev.parent = &pdev->dev;
nand->IO_ADDR_R = host->data_va;
......@@ -987,26 +906,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.hwctl = fsmc_enable_hwecc;
nand->ecc.size = 512;
nand->options = pdata->options;
nand->select_chip = fsmc_select_chip;
nand->badblockbits = 7;
nand_set_flash_node(nand, np);
if (pdata->width == FSMC_NAND_BW16)
nand->options |= NAND_BUSWIDTH_16;
switch (host->mode) {
case USE_DMA_ACCESS:
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
host->read_dma_chan = dma_request_channel(mask, filter,
pdata->read_dma_priv);
host->read_dma_chan = dma_request_channel(mask, filter, NULL);
if (!host->read_dma_chan) {
dev_err(&pdev->dev, "Unable to get read dma channel\n");
goto err_req_read_chnl;
}
host->write_dma_chan = dma_request_channel(mask, filter,
pdata->write_dma_priv);
host->write_dma_chan = dma_request_channel(mask, filter, NULL);
if (!host->write_dma_chan) {
dev_err(&pdev->dev, "Unable to get write dma channel\n");
goto err_req_write_chnl;
......@@ -1107,18 +1018,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (ret)
goto err_probe;
/*
* The partition information can is accessed by (in the same precedence)
*
* command line through Bootloader,
* platform data,
* default partition information present in driver.
*/
/*
* Check for partition info passed
*/
mtd->name = "nand";
ret = mtd_device_register(mtd, host->partitions, host->nr_partitions);
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
goto err_probe;
......@@ -1135,8 +1036,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
dma_release_channel(host->read_dma_chan);
err_req_read_chnl:
clk_disable_unprepare(host->clk);
err_clk_prepare_enable:
clk_put(host->clk);
return ret;
}
......@@ -1155,7 +1054,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
dma_release_channel(host->read_dma_chan);
}
clk_disable_unprepare(host->clk);
clk_put(host->clk);
}
return 0;
......@@ -1185,20 +1083,18 @@ static int fsmc_nand_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
#ifdef CONFIG_OF
static const struct of_device_id fsmc_nand_id_table[] = {
{ .compatible = "st,spear600-fsmc-nand" },
{ .compatible = "stericsson,fsmc-nand" },
{}
};
MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
#endif
static struct platform_driver fsmc_nand_driver = {
.remove = fsmc_nand_remove,
.driver = {
.name = "fsmc-nand",
.of_match_table = of_match_ptr(fsmc_nand_id_table),
.of_match_table = fsmc_nand_id_table,
.pm = &fsmc_nand_pm_ops,
},
};
......
......@@ -78,7 +78,9 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
gpio_nand_dosync(gpiomtd);
if (ctrl & NAND_CTRL_CHANGE) {
gpio_set_value(gpiomtd->plat.gpio_nce, !(ctrl & NAND_NCE));
if (gpio_is_valid(gpiomtd->plat.gpio_nce))
gpio_set_value(gpiomtd->plat.gpio_nce,
!(ctrl & NAND_NCE));
gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE));
gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE));
gpio_nand_dosync(gpiomtd);
......@@ -201,7 +203,8 @@ static int gpio_nand_remove(struct platform_device *pdev)
if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
gpio_set_value(gpiomtd->plat.gpio_nce, 1);
if (gpio_is_valid(gpiomtd->plat.gpio_nce))
gpio_set_value(gpiomtd->plat.gpio_nce, 1);
return 0;
}
......@@ -239,10 +242,13 @@ static int gpio_nand_probe(struct platform_device *pdev)
if (ret)
return ret;
ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce, "NAND NCE");
if (ret)
return ret;
gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
if (gpio_is_valid(gpiomtd->plat.gpio_nce)) {
ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce,
"NAND NCE");
if (ret)
return ret;
gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
}
if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp,
......
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* 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 <linux/mtd/nand.h>
static void amd_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
nand_decode_ext_id(chip);
/*
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
* some Spansion chips have erasesize that conflicts with size
* listed in nand_ids table.
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
*/
if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 &&
chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 &&
mtd->writesize == 512) {
mtd->erasesize = 128 * 1024;
mtd->erasesize <<= ((chip->id.data[3] & 0x03) << 1);
}
}
static int amd_nand_init(struct nand_chip *chip)
{
if (nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops amd_nand_manuf_ops = {
.detect = amd_nand_decode_id,
.init = amd_nand_init,
};
......@@ -354,40 +354,32 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
*/
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
{
int page, res = 0, i = 0;
int page, page_end, res;
struct nand_chip *chip = mtd_to_nand(mtd);
u16 bad;
u8 bad;
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
ofs += mtd->erasesize - mtd->writesize;
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
do {
if (chip->options & NAND_BUSWIDTH_16) {
chip->cmdfunc(mtd, NAND_CMD_READOOB,
chip->badblockpos & 0xFE, page);
bad = cpu_to_le16(chip->read_word(mtd));
if (chip->badblockpos & 0x1)
bad >>= 8;
else
bad &= 0xFF;
} else {
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
page);
bad = chip->read_byte(mtd);
}
for (; page < page_end; page++) {
res = chip->ecc.read_oob(mtd, chip, page);
if (res)
return res;
bad = chip->oob_poi[chip->badblockpos];
if (likely(chip->badblockbits == 8))
res = bad != 0xFF;
else
res = hweight8(bad) < chip->badblockbits;
ofs += mtd->writesize;
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
i++;
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
if (res)
return res;
}
return res;
return 0;
}
/**
......@@ -676,6 +668,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_STATUS:
case NAND_CMD_READID:
case NAND_CMD_SET_FEATURES:
return;
case NAND_CMD_RESET:
......@@ -794,6 +788,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_STATUS:
case NAND_CMD_READID:
case NAND_CMD_SET_FEATURES:
return;
case NAND_CMD_RNDIN:
......@@ -1958,7 +1954,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if (!aligned)
use_bufpoi = 1;
else if (chip->options & NAND_USE_BOUNCE_BUFFER)
use_bufpoi = !virt_addr_valid(buf);
use_bufpoi = !virt_addr_valid(buf) ||
!IS_ALIGNED((unsigned long)buf,
chip->buf_align);
else
use_bufpoi = 0;
......@@ -1997,8 +1995,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
break;
}
max_bitflips = max_t(unsigned int, max_bitflips, ret);
/* Transfer not aligned data */
if (use_bufpoi) {
if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
......@@ -2049,6 +2045,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
}
buf += bytes;
max_bitflips = max_t(unsigned int, max_bitflips, ret);
} else {
memcpy(buf, chip->buffers->databuf + col, bytes);
buf += bytes;
......@@ -2637,7 +2634,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
}
/**
* nand_write_page - [REPLACEABLE] write one page
* nand_write_page - write one page
* @mtd: MTD device structure
* @chip: NAND chip descriptor
* @offset: address offset within the page
......@@ -2815,7 +2812,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
if (part_pagewr)
use_bufpoi = 1;
else if (chip->options & NAND_USE_BOUNCE_BUFFER)
use_bufpoi = !virt_addr_valid(buf);
use_bufpoi = !virt_addr_valid(buf) ||
!IS_ALIGNED((unsigned long)buf,
chip->buf_align);
else
use_bufpoi = 0;
......@@ -2840,9 +2839,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
/* We still need to erase leftover OOB data */
memset(chip->oob_poi, 0xff, mtd->oobsize);
}
ret = chip->write_page(mtd, chip, column, bytes, wbuf,
oob_required, page, cached,
(ops->mode == MTD_OPS_RAW));
ret = nand_write_page(mtd, chip, column, bytes, wbuf,
oob_required, page, cached,
(ops->mode == MTD_OPS_RAW));
if (ret)
break;
......@@ -3385,8 +3385,10 @@ static void nand_shutdown(struct mtd_info *mtd)
}
/* Set default functions */
static void nand_set_defaults(struct nand_chip *chip, int busw)
static void nand_set_defaults(struct nand_chip *chip)
{
unsigned int busw = chip->options & NAND_BUSWIDTH_16;
/* check for proper chip_delay setup, set 20us if not */
if (!chip->chip_delay)
chip->chip_delay = 20;
......@@ -3431,6 +3433,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
nand_hw_control_init(chip->controller);
}
if (!chip->buf_align)
chip->buf_align = 1;
}
/* Sanitize ONFI strings so we can safely print them */
......@@ -3464,9 +3468,10 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
}
/* Parse the Extended Parameter Page. */
static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
struct nand_chip *chip, struct nand_onfi_params *p)
static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
struct nand_onfi_params *p)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct onfi_ext_param_page *ep;
struct onfi_ext_section *s;
struct onfi_ext_ecc_info *ecc;
......@@ -3534,36 +3539,12 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
return ret;
}
static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
{
struct nand_chip *chip = mtd_to_nand(mtd);
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
feature);
}
/*
* Configure chip properties from Micron vendor-specific ONFI table
*/
static void nand_onfi_detect_micron(struct nand_chip *chip,
struct nand_onfi_params *p)
{
struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
if (le16_to_cpu(p->vendor_revision) < 1)
return;
chip->read_retries = micron->read_retry_options;
chip->setup_read_retry = nand_setup_read_retry_micron;
}
/*
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
*/
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
int *busw)
static int nand_flash_detect_onfi(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_onfi_params *p = &chip->onfi_params;
int i, j;
int val;
......@@ -3633,9 +3614,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
*busw = NAND_BUSWIDTH_16;
else
*busw = 0;
chip->options |= NAND_BUSWIDTH_16;
if (p->ecc_bits != 0xff) {
chip->ecc_strength_ds = p->ecc_bits;
......@@ -3653,24 +3632,21 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip->cmdfunc = nand_command_lp;
/* The Extended Parameter Page is supported since ONFI 2.1. */
if (nand_flash_detect_ext_param_page(mtd, chip, p))
if (nand_flash_detect_ext_param_page(chip, p))
pr_warn("Failed to detect ONFI extended param page\n");
} else {
pr_warn("Could not retrieve ONFI ECC requirements\n");
}
if (p->jedec_id == NAND_MFR_MICRON)
nand_onfi_detect_micron(chip, p);
return 1;
}
/*
* Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
*/
static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
int *busw)
static int nand_flash_detect_jedec(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_jedec_params *p = &chip->jedec_params;
struct jedec_ecc_info *ecc;
int val;
......@@ -3729,9 +3705,7 @@ static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
chip->bits_per_cell = p->bits_per_cell;
if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
*busw = NAND_BUSWIDTH_16;
else
*busw = 0;
chip->options |= NAND_BUSWIDTH_16;
/* ECC info */
ecc = &p->ecc_info[0];
......@@ -3820,165 +3794,46 @@ static int nand_get_bits_per_cell(u8 cellinfo)
* chip. The rest of the parameters must be decoded according to generic or
* manufacturer-specific "extended ID" decoding patterns.
*/
static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
u8 id_data[8], int *busw)
void nand_decode_ext_id(struct nand_chip *chip)
{
int extid, id_len;
struct mtd_info *mtd = nand_to_mtd(chip);
int extid;
u8 *id_data = chip->id.data;
/* The 3rd id byte holds MLC / multichip data */
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
/* The 4th id byte is the important one */
extid = id_data[3];
id_len = nand_id_len(id_data, 8);
/*
* Field definitions are in the following datasheets:
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
* Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
*
* Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
* ID to decide what to do.
*/
if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
!nand_is_slc(chip) && id_data[5] != 0x00) {
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
case 1:
mtd->oobsize = 128;
break;
case 2:
mtd->oobsize = 218;
break;
case 3:
mtd->oobsize = 400;
break;
case 4:
mtd->oobsize = 436;
break;
case 5:
mtd->oobsize = 512;
break;
case 6:
mtd->oobsize = 640;
break;
case 7:
default: /* Other cases are "reserved" (unknown) */
mtd->oobsize = 1024;
break;
}
extid >>= 2;
/* Calc blocksize */
mtd->erasesize = (128 * 1024) <<
(((extid >> 1) & 0x04) | (extid & 0x03));
*busw = 0;
} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
!nand_is_slc(chip)) {
unsigned int tmp;
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
case 0:
mtd->oobsize = 128;
break;
case 1:
mtd->oobsize = 224;
break;
case 2:
mtd->oobsize = 448;
break;
case 3:
mtd->oobsize = 64;
break;
case 4:
mtd->oobsize = 32;
break;
case 5:
mtd->oobsize = 16;
break;
default:
mtd->oobsize = 640;
break;
}
extid >>= 2;
/* Calc blocksize */
tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
if (tmp < 0x03)
mtd->erasesize = (128 * 1024) << tmp;
else if (tmp == 0x03)
mtd->erasesize = 768 * 1024;
else
mtd->erasesize = (64 * 1024) << tmp;
*busw = 0;
} else {
/* Calc pagesize */
mtd->writesize = 1024 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
mtd->oobsize = (8 << (extid & 0x01)) *
(mtd->writesize >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB */
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information */
*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
/*
* Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
* 512B page. For Toshiba SLC, we decode the 5th/6th byte as
* follows:
* - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
* 110b -> 24nm
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
*/
if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
nand_is_slc(chip) &&
(id_data[5] & 0x7) == 0x6 /* 24nm */ &&
!(id_data[4] & 0x80) /* !BENAND */) {
mtd->oobsize = 32 * mtd->writesize >> 9;
}
}
/* Calc pagesize */
mtd->writesize = 1024 << (extid & 0x03);
extid >>= 2;
/* Calc oobsize */
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB */
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information */
if (extid & 0x1)
chip->options |= NAND_BUSWIDTH_16;
}
EXPORT_SYMBOL_GPL(nand_decode_ext_id);
/*
* Old devices have chip data hardcoded in the device ID table. nand_decode_id
* decodes a matching ID table entry and assigns the MTD size parameters for
* the chip.
*/
static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_flash_dev *type, u8 id_data[8],
int *busw)
static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
{
int maf_id = id_data[0];
struct mtd_info *mtd = nand_to_mtd(chip);
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
*busw = type->options & NAND_BUSWIDTH_16;
/* All legacy ID NAND are small-page, SLC */
chip->bits_per_cell = 1;
/*
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
* some Spansion chips have erasesize that conflicts with size
* listed in nand_ids table.
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
*/
if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00
&& id_data[6] == 0x00 && id_data[7] == 0x00
&& mtd->writesize == 512) {
mtd->erasesize = 128 * 1024;
mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
}
}
/*
......@@ -3986,36 +3841,15 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
* heuristic patterns using various detected parameters (e.g., manufacturer,
* page size, cell-type information).
*/
static void nand_decode_bbm_options(struct mtd_info *mtd,
struct nand_chip *chip, u8 id_data[8])
static void nand_decode_bbm_options(struct nand_chip *chip)
{
int maf_id = id_data[0];
struct mtd_info *mtd = nand_to_mtd(chip);
/* Set the bad block position */
if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
else
chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
/*
* Bad block marker is stored in the last page of each block on Samsung
* and Hynix MLC devices; stored in first two pages of each block on
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
* AMD/Spansion, and Macronix. All others scan only the first page.
*/
if (!nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
else if ((nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX ||
maf_id == NAND_MFR_TOSHIBA ||
maf_id == NAND_MFR_AMD ||
maf_id == NAND_MFR_MACRONIX)) ||
(mtd->writesize == 2048 &&
maf_id == NAND_MFR_MICRON))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
}
static inline bool is_full_id_nand(struct nand_flash_dev *type)
......@@ -4023,9 +3857,12 @@ static inline bool is_full_id_nand(struct nand_flash_dev *type)
return type->id_len;
}
static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_flash_dev *type, u8 *id_data, int *busw)
static bool find_full_id_nand(struct nand_chip *chip,
struct nand_flash_dev *type)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 *id_data = chip->id.data;
if (!strncmp(type->id, id_data, type->id_len)) {
mtd->writesize = type->pagesize;
mtd->erasesize = type->erasesize;
......@@ -4039,8 +3876,6 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;
*busw = type->options & NAND_BUSWIDTH_16;
if (!mtd->name)
mtd->name = type->name;
......@@ -4049,16 +3884,64 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
return false;
}
/*
* Manufacturer detection. Only used when the NAND is not ONFI or JEDEC
* compliant and does not have a full-id or legacy-id entry in the nand_ids
* table.
*/
static void nand_manufacturer_detect(struct nand_chip *chip)
{
/*
* Try manufacturer detection if available and use
* nand_decode_ext_id() otherwise.
*/
if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
chip->manufacturer.desc->ops->detect)
chip->manufacturer.desc->ops->detect(chip);
else
nand_decode_ext_id(chip);
}
/*
* Manufacturer initialization. This function is called for all NANDs including
* ONFI and JEDEC compliant ones.
* Manufacturer drivers should put all their specific initialization code in
* their ->init() hook.
*/
static int nand_manufacturer_init(struct nand_chip *chip)
{
if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops ||
!chip->manufacturer.desc->ops->init)
return 0;
return chip->manufacturer.desc->ops->init(chip);
}
/*
* Manufacturer cleanup. This function is called for all NANDs including
* ONFI and JEDEC compliant ones.
* Manufacturer drivers should put all their specific cleanup code in their
* ->cleanup() hook.
*/
static void nand_manufacturer_cleanup(struct nand_chip *chip)
{
/* Release manufacturer private data */
if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
chip->manufacturer.desc->ops->cleanup)
chip->manufacturer.desc->ops->cleanup(chip);
}
/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
int *maf_id, int *dev_id,
struct nand_flash_dev *type)
static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
{
const struct nand_manufacturer *manufacturer;
struct mtd_info *mtd = nand_to_mtd(chip);
int busw;
int i, maf_idx;
u8 id_data[8];
int i, ret;
u8 *id_data = chip->id.data;
u8 maf_id, dev_id;
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
......@@ -4073,8 +3956,8 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
*maf_id = chip->read_byte(mtd);
*dev_id = chip->read_byte(mtd);
maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
/*
* Try again to make sure, as some systems the bus-hold or other
......@@ -4089,20 +3972,41 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < 8; i++)
id_data[i] = chip->read_byte(mtd);
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
if (id_data[0] != maf_id || id_data[1] != dev_id) {
pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
*maf_id, *dev_id, id_data[0], id_data[1]);
maf_id, dev_id, id_data[0], id_data[1]);
return -ENODEV;
}
chip->id.len = nand_id_len(id_data, 8);
/* Try to identify manufacturer */
manufacturer = nand_get_manufacturer(maf_id);
chip->manufacturer.desc = manufacturer;
if (!type)
type = nand_flash_ids;
/*
* Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
* override it.
* This is required to make sure initial NAND bus width set by the
* NAND controller driver is coherent with the real NAND bus width
* (extracted by auto-detection code).
*/
busw = chip->options & NAND_BUSWIDTH_16;
/*
* The flag is only set (never cleared), reset it to its default value
* before starting auto-detection.
*/
chip->options &= ~NAND_BUSWIDTH_16;
for (; type->name != NULL; type++) {
if (is_full_id_nand(type)) {
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
if (find_full_id_nand(chip, type))
goto ident_done;
} else if (*dev_id == type->dev_id) {
} else if (dev_id == type->dev_id) {
break;
}
}
......@@ -4110,11 +4014,11 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
chip->onfi_version = 0;
if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
if (nand_flash_detect_onfi(mtd, chip, &busw))
if (nand_flash_detect_onfi(chip))
goto ident_done;
/* Check if the chip is JEDEC compliant */
if (nand_flash_detect_jedec(mtd, chip, &busw))
if (nand_flash_detect_jedec(chip))
goto ident_done;
}
......@@ -4126,48 +4030,34 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
chip->chipsize = (uint64_t)type->chipsize << 20;
if (!type->pagesize) {
/* Decode parameters from extended ID */
nand_decode_ext_id(mtd, chip, id_data, &busw);
} else {
nand_decode_id(mtd, chip, type, id_data, &busw);
}
if (!type->pagesize)
nand_manufacturer_detect(chip);
else
nand_decode_id(chip, type);
/* Get chip options */
chip->options |= type->options;
/*
* Check if chip is not a Samsung device. Do not clear the
* options for chips which do not have an extended id.
*/
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
ident_done:
/* Try to identify manufacturer */
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
if (nand_manuf_ids[maf_idx].id == *maf_id)
break;
}
if (chip->options & NAND_BUSWIDTH_AUTO) {
WARN_ON(chip->options & NAND_BUSWIDTH_16);
chip->options |= busw;
nand_set_defaults(chip, busw);
WARN_ON(busw & NAND_BUSWIDTH_16);
nand_set_defaults(chip);
} else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
/*
* Check, if buswidth is correct. Hardware drivers should set
* chip correct!
*/
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
*maf_id, *dev_id);
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
pr_warn("bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
busw ? 16 : 8);
maf_id, dev_id);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
mtd->name);
pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8,
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8);
return -EINVAL;
}
nand_decode_bbm_options(mtd, chip, id_data);
nand_decode_bbm_options(chip);
/* Calculate the address shift from the page size */
chip->page_shift = ffs(mtd->writesize) - 1;
......@@ -4190,18 +4080,22 @@ static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip,
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
ret = nand_manufacturer_init(chip);
if (ret)
return ret;
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
*maf_id, *dev_id);
maf_id, dev_id);
if (chip->onfi_version)
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
chip->onfi_params.model);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
chip->onfi_params.model);
else if (chip->jedec_version)
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
chip->jedec_params.model);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
chip->jedec_params.model);
else
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
type->name);
pr_info("%s %s\n", nand_manufacturer_name(manufacturer),
type->name);
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
......@@ -4333,12 +4227,6 @@ static int nand_dt_init(struct nand_chip *chip)
ecc_strength = of_get_nand_ecc_strength(dn);
ecc_step = of_get_nand_ecc_step_size(dn);
if ((ecc_step >= 0 && !(ecc_strength >= 0)) ||
(!(ecc_step >= 0) && ecc_strength >= 0)) {
pr_err("must set both strength and step size in DT\n");
return -EINVAL;
}
if (ecc_mode >= 0)
chip->ecc.mode = ecc_mode;
......@@ -4391,10 +4279,10 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return -EINVAL;
}
/* Set the default functions */
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
nand_set_defaults(chip);
/* Read the flash type */
ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table);
ret = nand_detect(chip, table);
if (ret) {
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
pr_warn("No NAND device found\n");
......@@ -4419,6 +4307,9 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
if (ret)
return ret;
nand_maf_id = chip->id.data[0];
nand_dev_id = chip->id.data[1];
chip->select_chip(mtd, -1);
/* Check for a chip array */
......@@ -4610,7 +4501,7 @@ int nand_scan_tail(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct nand_buffers *nbuf;
struct nand_buffers *nbuf = NULL;
int ret;
/* New bad blocks should be marked in OOB, flash-based BBT, or both */
......@@ -4624,13 +4515,28 @@ int nand_scan_tail(struct mtd_info *mtd)
}
if (!(chip->options & NAND_OWN_BUFFERS)) {
nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
+ mtd->oobsize * 3, GFP_KERNEL);
nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL);
if (!nbuf)
return -ENOMEM;
nbuf->ecccalc = (uint8_t *)(nbuf + 1);
nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
nbuf->databuf = nbuf->ecccode + mtd->oobsize;
nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL);
if (!nbuf->ecccalc) {
ret = -ENOMEM;
goto err_free;
}
nbuf->ecccode = kmalloc(mtd->oobsize, GFP_KERNEL);
if (!nbuf->ecccode) {
ret = -ENOMEM;
goto err_free;
}
nbuf->databuf = kmalloc(mtd->writesize + mtd->oobsize,
GFP_KERNEL);
if (!nbuf->databuf) {
ret = -ENOMEM;
goto err_free;
}
chip->buffers = nbuf;
} else {
......@@ -4663,9 +4569,6 @@ int nand_scan_tail(struct mtd_info *mtd)
}
}
if (!chip->write_page)
chip->write_page = nand_write_page;
/*
* Check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
......@@ -4873,8 +4776,12 @@ int nand_scan_tail(struct mtd_info *mtd)
/* Build bad block table */
return chip->scan_bbt(mtd);
err_free:
if (!(chip->options & NAND_OWN_BUFFERS))
kfree(chip->buffers);
if (nbuf) {
kfree(nbuf->databuf);
kfree(nbuf->ecccode);
kfree(nbuf->ecccalc);
kfree(nbuf);
}
return ret;
}
EXPORT_SYMBOL(nand_scan_tail);
......@@ -4925,13 +4832,20 @@ void nand_cleanup(struct nand_chip *chip)
/* Free bad block table memory */
kfree(chip->bbt);
if (!(chip->options & NAND_OWN_BUFFERS))
if (!(chip->options & NAND_OWN_BUFFERS) && chip->buffers) {
kfree(chip->buffers->databuf);
kfree(chip->buffers->ecccode);
kfree(chip->buffers->ecccalc);
kfree(chip->buffers);
}
/* Free bad block descriptor memory */
if (chip->badblock_pattern && chip->badblock_pattern->options
& NAND_BBT_DYNAMICSTRUCT)
kfree(chip->badblock_pattern);
/* Free manufacturer priv data. */
nand_manufacturer_cleanup(chip);
}
EXPORT_SYMBOL_GPL(nand_cleanup);
......
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* 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 <linux/mtd/nand.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#define NAND_HYNIX_CMD_SET_PARAMS 0x36
#define NAND_HYNIX_CMD_APPLY_PARAMS 0x16
#define NAND_HYNIX_1XNM_RR_REPEAT 8
/**
* struct hynix_read_retry - read-retry data
* @nregs: number of register to set when applying a new read-retry mode
* @regs: register offsets (NAND chip dependent)
* @values: array of values to set in registers. The array size is equal to
* (nregs * nmodes)
*/
struct hynix_read_retry {
int nregs;
const u8 *regs;
u8 values[0];
};
/**
* struct hynix_nand - private Hynix NAND struct
* @nand_technology: manufacturing process expressed in picometer
* @read_retry: read-retry information
*/
struct hynix_nand {
const struct hynix_read_retry *read_retry;
};
/**
* struct hynix_read_retry_otp - structure describing how the read-retry OTP
* area
* @nregs: number of hynix private registers to set before reading the reading
* the OTP area
* @regs: registers that should be configured
* @values: values that should be set in regs
* @page: the address to pass to the READ_PAGE command. Depends on the NAND
* chip
* @size: size of the read-retry OTP section
*/
struct hynix_read_retry_otp {
int nregs;
const u8 *regs;
const u8 *values;
int page;
int size;
};
static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 jedecid[6] = { };
int i = 0;
chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
for (i = 0; i < 5; i++)
jedecid[i] = chip->read_byte(mtd);
return !strcmp("JEDEC", jedecid);
}
static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
const u8 *values;
int status;
int i;
values = hynix->read_retry->values +
(retry_mode * hynix->read_retry->nregs);
/* Enter 'Set Hynix Parameters' mode */
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1);
/*
* Configure the NAND in the requested read-retry mode.
* This is done by setting pre-defined values in internal NAND
* registers.
*
* The set of registers is NAND specific, and the values are either
* predefined or extracted from an OTP area on the NAND (values are
* probably tweaked at production in this case).
*/
for (i = 0; i < hynix->read_retry->nregs; i++) {
int column = hynix->read_retry->regs[i];
column |= column << 8;
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
chip->write_byte(mtd, values[i]);
}
/* Apply the new settings. */
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
}
/**
* hynix_get_majority - get the value that is occurring the most in a given
* set of values
* @in: the array of values to test
* @repeat: the size of the in array
* @out: pointer used to store the output value
*
* This function implements the 'majority check' logic that is supposed to
* overcome the unreliability of MLC NANDs when reading the OTP area storing
* the read-retry parameters.
*
* It's based on a pretty simple assumption: if we repeat the same value
* several times and then take the one that is occurring the most, we should
* find the correct value.
* Let's hope this dummy algorithm prevents us from losing the read-retry
* parameters.
*/
static int hynix_get_majority(const u8 *in, int repeat, u8 *out)
{
int i, j, half = repeat / 2;
/*
* We only test the first half of the in array because we must ensure
* that the value is at least occurring repeat / 2 times.
*
* This loop is suboptimal since we may count the occurrences of the
* same value several time, but we are doing that on small sets, which
* makes it acceptable.
*/
for (i = 0; i < half; i++) {
int cnt = 0;
u8 val = in[i];
/* Count all values that are matching the one at index i. */
for (j = i + 1; j < repeat; j++) {
if (in[j] == val)
cnt++;
}
/* We found a value occurring more than repeat / 2. */
if (cnt > half) {
*out = val;
return 0;
}
}
return -EIO;
}
static int hynix_read_rr_otp(struct nand_chip *chip,
const struct hynix_read_retry_otp *info,
void *buf)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int i;
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1);
for (i = 0; i < info->nregs; i++) {
int column = info->regs[i];
column |= column << 8;
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
chip->write_byte(mtd, info->values[i]);
}
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
/* Sequence to enter OTP mode? */
chip->cmdfunc(mtd, 0x17, -1, -1);
chip->cmdfunc(mtd, 0x04, -1, -1);
chip->cmdfunc(mtd, 0x19, -1, -1);
/* Now read the page */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, info->page);
chip->read_buf(mtd, buf, info->size);
/* Put everything back to normal */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, 0x38, -1);
chip->write_byte(mtd, 0x0);
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, -1);
return 0;
}
#define NAND_HYNIX_1XNM_RR_COUNT_OFFS 0
#define NAND_HYNIX_1XNM_RR_REG_COUNT_OFFS 8
#define NAND_HYNIX_1XNM_RR_SET_OFFS(x, setsize, inv) \
(16 + ((((x) * 2) + ((inv) ? 1 : 0)) * (setsize)))
static int hynix_mlc_1xnm_rr_value(const u8 *buf, int nmodes, int nregs,
int mode, int reg, bool inv, u8 *val)
{
u8 tmp[NAND_HYNIX_1XNM_RR_REPEAT];
int val_offs = (mode * nregs) + reg;
int set_size = nmodes * nregs;
int i, ret;
for (i = 0; i < NAND_HYNIX_1XNM_RR_REPEAT; i++) {
int set_offs = NAND_HYNIX_1XNM_RR_SET_OFFS(i, set_size, inv);
tmp[i] = buf[val_offs + set_offs];
}
ret = hynix_get_majority(tmp, NAND_HYNIX_1XNM_RR_REPEAT, val);
if (ret)
return ret;
if (inv)
*val = ~*val;
return 0;
}
static u8 hynix_1xnm_mlc_read_retry_regs[] = {
0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
};
static int hynix_mlc_1xnm_rr_init(struct nand_chip *chip,
const struct hynix_read_retry_otp *info)
{
struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
struct hynix_read_retry *rr = NULL;
int ret, i, j;
u8 nregs, nmodes;
u8 *buf;
buf = kmalloc(info->size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = hynix_read_rr_otp(chip, info, buf);
if (ret)
goto out;
ret = hynix_get_majority(buf, NAND_HYNIX_1XNM_RR_REPEAT,
&nmodes);
if (ret)
goto out;
ret = hynix_get_majority(buf + NAND_HYNIX_1XNM_RR_REPEAT,
NAND_HYNIX_1XNM_RR_REPEAT,
&nregs);
if (ret)
goto out;
rr = kzalloc(sizeof(*rr) + (nregs * nmodes), GFP_KERNEL);
if (!rr) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < nmodes; i++) {
for (j = 0; j < nregs; j++) {
u8 *val = rr->values + (i * nregs);
ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
false, val);
if (!ret)
continue;
ret = hynix_mlc_1xnm_rr_value(buf, nmodes, nregs, i, j,
true, val);
if (ret)
goto out;
}
}
rr->nregs = nregs;
rr->regs = hynix_1xnm_mlc_read_retry_regs;
hynix->read_retry = rr;
chip->setup_read_retry = hynix_nand_setup_read_retry;
chip->read_retries = nmodes;
out:
kfree(buf);
if (ret)
kfree(rr);
return ret;
}
static const u8 hynix_mlc_1xnm_rr_otp_regs[] = { 0x38 };
static const u8 hynix_mlc_1xnm_rr_otp_values[] = { 0x52 };
static const struct hynix_read_retry_otp hynix_mlc_1xnm_rr_otps[] = {
{
.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
.regs = hynix_mlc_1xnm_rr_otp_regs,
.values = hynix_mlc_1xnm_rr_otp_values,
.page = 0x21f,
.size = 784
},
{
.nregs = ARRAY_SIZE(hynix_mlc_1xnm_rr_otp_regs),
.regs = hynix_mlc_1xnm_rr_otp_regs,
.values = hynix_mlc_1xnm_rr_otp_values,
.page = 0x200,
.size = 528,
},
};
static int hynix_nand_rr_init(struct nand_chip *chip)
{
int i, ret = 0;
bool valid_jedecid;
valid_jedecid = hynix_nand_has_valid_jedecid(chip);
/*
* We only support read-retry for 1xnm NANDs, and those NANDs all
* expose a valid JEDEC ID.
*/
if (valid_jedecid) {
u8 nand_tech = chip->id.data[5] >> 4;
/* 1xnm technology */
if (nand_tech == 4) {
for (i = 0; i < ARRAY_SIZE(hynix_mlc_1xnm_rr_otps);
i++) {
/*
* FIXME: Hynix recommend to copy the
* read-retry OTP area into a normal page.
*/
ret = hynix_mlc_1xnm_rr_init(chip,
hynix_mlc_1xnm_rr_otps);
if (!ret)
break;
}
}
}
if (ret)
pr_warn("failed to initialize read-retry infrastructure");
return 0;
}
static void hynix_nand_extract_oobsize(struct nand_chip *chip,
bool valid_jedecid)
{
struct mtd_info *mtd = nand_to_mtd(chip);
u8 oobsize;
oobsize = ((chip->id.data[3] >> 2) & 0x3) |
((chip->id.data[3] >> 4) & 0x4);
if (valid_jedecid) {
switch (oobsize) {
case 0:
mtd->oobsize = 2048;
break;
case 1:
mtd->oobsize = 1664;
break;
case 2:
mtd->oobsize = 1024;
break;
case 3:
mtd->oobsize = 640;
break;
default:
/*
* We should never reach this case, but if that
* happens, this probably means Hynix decided to use
* a different extended ID format, and we should find
* a way to support it.
*/
WARN(1, "Invalid OOB size");
break;
}
} else {
switch (oobsize) {
case 0:
mtd->oobsize = 128;
break;
case 1:
mtd->oobsize = 224;
break;
case 2:
mtd->oobsize = 448;
break;
case 3:
mtd->oobsize = 64;
break;
case 4:
mtd->oobsize = 32;
break;
case 5:
mtd->oobsize = 16;
break;
case 6:
mtd->oobsize = 640;
break;
default:
/*
* We should never reach this case, but if that
* happens, this probably means Hynix decided to use
* a different extended ID format, and we should find
* a way to support it.
*/
WARN(1, "Invalid OOB size");
break;
}
}
}
static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
bool valid_jedecid)
{
u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
if (valid_jedecid) {
/* Reference: H27UCG8T2E datasheet */
chip->ecc_step_ds = 1024;
switch (ecc_level) {
case 0:
chip->ecc_step_ds = 0;
chip->ecc_strength_ds = 0;
break;
case 1:
chip->ecc_strength_ds = 4;
break;
case 2:
chip->ecc_strength_ds = 24;
break;
case 3:
chip->ecc_strength_ds = 32;
break;
case 4:
chip->ecc_strength_ds = 40;
break;
case 5:
chip->ecc_strength_ds = 50;
break;
case 6:
chip->ecc_strength_ds = 60;
break;
default:
/*
* We should never reach this case, but if that
* happens, this probably means Hynix decided to use
* a different extended ID format, and we should find
* a way to support it.
*/
WARN(1, "Invalid ECC requirements");
}
} else {
/*
* The ECC requirements field meaning depends on the
* NAND technology.
*/
u8 nand_tech = chip->id.data[5] & 0x3;
if (nand_tech < 3) {
/* > 26nm, reference: H27UBG8T2A datasheet */
if (ecc_level < 5) {
chip->ecc_step_ds = 512;
chip->ecc_strength_ds = 1 << ecc_level;
} else if (ecc_level < 7) {
if (ecc_level == 5)
chip->ecc_step_ds = 2048;
else
chip->ecc_step_ds = 1024;
chip->ecc_strength_ds = 24;
} else {
/*
* We should never reach this case, but if that
* happens, this probably means Hynix decided
* to use a different extended ID format, and
* we should find a way to support it.
*/
WARN(1, "Invalid ECC requirements");
}
} else {
/* <= 26nm, reference: H27UBG8T2B datasheet */
if (!ecc_level) {
chip->ecc_step_ds = 0;
chip->ecc_strength_ds = 0;
} else if (ecc_level < 5) {
chip->ecc_step_ds = 512;
chip->ecc_strength_ds = 1 << (ecc_level - 1);
} else {
chip->ecc_step_ds = 1024;
chip->ecc_strength_ds = 24 +
(8 * (ecc_level - 5));
}
}
}
}
static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
bool valid_jedecid)
{
u8 nand_tech;
/* We need scrambling on all TLC NANDs*/
if (chip->bits_per_cell > 2)
chip->options |= NAND_NEED_SCRAMBLING;
/* And on MLC NANDs with sub-3xnm process */
if (valid_jedecid) {
nand_tech = chip->id.data[5] >> 4;
/* < 3xnm */
if (nand_tech > 0)
chip->options |= NAND_NEED_SCRAMBLING;
} else {
nand_tech = chip->id.data[5] & 0x3;
/* < 32nm */
if (nand_tech > 2)
chip->options |= NAND_NEED_SCRAMBLING;
}
}
static void hynix_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
bool valid_jedecid;
u8 tmp;
/*
* Exclude all SLC NANDs from this advanced detection scheme.
* According to the ranges defined in several datasheets, it might
* appear that even SLC NANDs could fall in this extended ID scheme.
* If that the case rework the test to let SLC NANDs go through the
* detection process.
*/
if (chip->id.len < 6 || nand_is_slc(chip)) {
nand_decode_ext_id(chip);
return;
}
/* Extract pagesize */
mtd->writesize = 2048 << (chip->id.data[3] & 0x03);
tmp = (chip->id.data[3] >> 4) & 0x3;
/*
* When bit7 is set that means we start counting at 1MiB, otherwise
* we start counting at 128KiB and shift this value the content of
* ID[3][4:5].
* The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in
* this case the erasesize is set to 768KiB.
*/
if (chip->id.data[3] & 0x80)
mtd->erasesize = SZ_1M << tmp;
else if (tmp == 3)
mtd->erasesize = SZ_512K + SZ_256K;
else
mtd->erasesize = SZ_128K << tmp;
/*
* Modern Toggle DDR NANDs have a valid JEDECID even though they are
* not exposing a valid JEDEC parameter table.
* These NANDs use a different NAND ID scheme.
*/
valid_jedecid = hynix_nand_has_valid_jedecid(chip);
hynix_nand_extract_oobsize(chip, valid_jedecid);
hynix_nand_extract_ecc_requirements(chip, valid_jedecid);
hynix_nand_extract_scrambling_requirements(chip, valid_jedecid);
}
static void hynix_nand_cleanup(struct nand_chip *chip)
{
struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
if (!hynix)
return;
kfree(hynix->read_retry);
kfree(hynix);
nand_set_manufacturer_data(chip, NULL);
}
static int hynix_nand_init(struct nand_chip *chip)
{
struct hynix_nand *hynix;
int ret;
if (!nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
else
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
if (!hynix)
return -ENOMEM;
nand_set_manufacturer_data(chip, hynix);
ret = hynix_nand_rr_init(chip);
if (ret)
hynix_nand_cleanup(chip);
return ret;
}
const struct nand_manufacturer_ops hynix_nand_manuf_ops = {
.detect = hynix_nand_decode_id,
.init = hynix_nand_init,
.cleanup = hynix_nand_cleanup,
};
......@@ -10,7 +10,7 @@
#include <linux/mtd/nand.h>
#include <linux/sizes.h>
#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
#define LP_OPTIONS 0
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
#define SP_OPTIONS NAND_NEED_READRDY
......@@ -169,29 +169,40 @@ struct nand_flash_dev nand_flash_ids[] = {
};
/* Manufacturer IDs */
struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_TOSHIBA, "Toshiba"},
static const struct nand_manufacturer nand_manufacturers[] = {
{NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
{NAND_MFR_ESMT, "ESMT"},
{NAND_MFR_SAMSUNG, "Samsung"},
{NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
{NAND_MFR_FUJITSU, "Fujitsu"},
{NAND_MFR_NATIONAL, "National"},
{NAND_MFR_RENESAS, "Renesas"},
{NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix"},
{NAND_MFR_MICRON, "Micron"},
{NAND_MFR_AMD, "AMD/Spansion"},
{NAND_MFR_MACRONIX, "Macronix"},
{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
{NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
{NAND_MFR_MACRONIX, "Macronix", &macronix_nand_manuf_ops},
{NAND_MFR_EON, "Eon"},
{NAND_MFR_SANDISK, "SanDisk"},
{NAND_MFR_INTEL, "Intel"},
{NAND_MFR_ATO, "ATO"},
{NAND_MFR_WINBOND, "Winbond"},
{0x0, "Unknown"}
};
EXPORT_SYMBOL(nand_manuf_ids);
EXPORT_SYMBOL(nand_flash_ids);
/**
* nand_get_manufacturer - Get manufacturer information from the manufacturer
* ID
* @id: manufacturer ID
*
* Returns a pointer a nand_manufacturer object if the manufacturer is defined
* in the NAND manufacturers database, NULL otherwise.
*/
const struct nand_manufacturer *nand_get_manufacturer(u8 id)
{
int i;
for (i = 0; i < ARRAY_SIZE(nand_manufacturers); i++)
if (nand_manufacturers[i].id == id)
return &nand_manufacturers[i];
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
MODULE_DESCRIPTION("Nand device & manufacturer IDs");
return NULL;
}
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* 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 <linux/mtd/nand.h>
static int macronix_nand_init(struct nand_chip *chip)
{
if (nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops macronix_nand_manuf_ops = {
.init = macronix_nand_init,
};
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* 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 <linux/mtd/nand.h>
struct nand_onfi_vendor_micron {
u8 two_plane_read;
u8 read_cache;
u8 read_unique_id;
u8 dq_imped;
u8 dq_imped_num_settings;
u8 dq_imped_feat_addr;
u8 rb_pulldown_strength;
u8 rb_pulldown_strength_feat_addr;
u8 rb_pulldown_strength_num_settings;
u8 otp_mode;
u8 otp_page_start;
u8 otp_data_prot_addr;
u8 otp_num_pages;
u8 otp_feat_addr;
u8 read_retry_options;
u8 reserved[72];
u8 param_revision;
} __packed;
static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
{
struct nand_chip *chip = mtd_to_nand(mtd);
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
feature);
}
/*
* Configure chip properties from Micron vendor-specific ONFI table
*/
static int micron_nand_onfi_init(struct nand_chip *chip)
{
struct nand_onfi_params *p = &chip->onfi_params;
struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
if (!chip->onfi_version)
return 0;
if (le16_to_cpu(p->vendor_revision) < 1)
return 0;
chip->read_retries = micron->read_retry_options;
chip->setup_read_retry = micron_nand_setup_read_retry;
return 0;
}
static int micron_nand_init(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = micron_nand_onfi_init(chip);
if (ret)
return ret;
if (mtd->writesize == 2048)
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops micron_nand_manuf_ops = {
.init = micron_nand_init,
};
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* 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 <linux/mtd/nand.h>
static void samsung_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
/* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
if (chip->id.len == 6 && !nand_is_slc(chip) &&
chip->id.data[5] != 0x00) {
u8 extid = chip->id.data[3];
/* Get pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
/* Get oobsize */
switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
case 1:
mtd->oobsize = 128;
break;
case 2:
mtd->oobsize = 218;
break;
case 3:
mtd->oobsize = 400;
break;
case 4:
mtd->oobsize = 436;
break;
case 5:
mtd->oobsize = 512;
break;
case 6:
mtd->oobsize = 640;
break;
default:
/*
* We should never reach this case, but if that
* happens, this probably means Samsung decided to use
* a different extended ID format, and we should find
* a way to support it.
*/
WARN(1, "Invalid OOB size value");
break;
}
/* Get blocksize */
extid >>= 2;
mtd->erasesize = (128 * 1024) <<
(((extid >> 1) & 0x04) | (extid & 0x03));
/* Extract ECC requirements from 5th id byte*/
extid = (chip->id.data[4] >> 4) & 0x07;
if (extid < 5) {
chip->ecc_step_ds = 512;
chip->ecc_strength_ds = 1 << extid;
} else {
chip->ecc_step_ds = 1024;
switch (extid) {
case 5:
chip->ecc_strength_ds = 24;
break;
case 6:
chip->ecc_strength_ds = 40;
break;
case 7:
chip->ecc_strength_ds = 60;
break;
}
}
} else {
nand_decode_ext_id(chip);
}
}
static int samsung_nand_init(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (mtd->writesize > 512)
chip->options |= NAND_SAMSUNG_LP_OPTIONS;
if (!nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
else
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
.detect = samsung_nand_decode_id,
.init = samsung_nand_init,
};
/*
* Copyright (C) 2017 Free Electrons
* Copyright (C) 2017 NextThing Co
*
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
*
* 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 <linux/mtd/nand.h>
static void toshiba_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
nand_decode_ext_id(chip);
/*
* Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
* 512B page. For Toshiba SLC, we decode the 5th/6th byte as
* follows:
* - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
* 110b -> 24nm
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
*/
if (chip->id.len >= 6 && nand_is_slc(chip) &&
(chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
!(chip->id.data[4] & 0x80) /* !BENAND */)
mtd->oobsize = 32 * mtd->writesize >> 9;
}
static int toshiba_nand_init(struct nand_chip *chip)
{
if (nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
return 0;
}
const struct nand_manufacturer_ops toshiba_nand_manuf_ops = {
.detect = toshiba_nand_decode_id,
.init = toshiba_nand_init,
};
......@@ -901,7 +901,7 @@ static int parse_weakpages(void)
zero_ok = (*w == '0' ? 1 : 0);
page_no = simple_strtoul(w, &w, 0);
if (!zero_ok && !page_no) {
NS_ERR("invalid weakpagess.\n");
NS_ERR("invalid weakpages.\n");
return -EINVAL;
}
max_writes = 3;
......
......@@ -1856,6 +1856,15 @@ static int omap_nand_probe(struct platform_device *pdev)
nand_chip->ecc.priv = NULL;
nand_set_flash_node(nand_chip, dev->of_node);
if (!mtd->name) {
mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"omap2-nand.%d", info->gpmc_cs);
if (!mtd->name) {
dev_err(&pdev->dev, "Failed to set MTD name\n");
return -ENOMEM;
}
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nand_chip->IO_ADDR_R))
......
......@@ -23,6 +23,11 @@
#include <asm/sizes.h>
#include <linux/platform_data/mtd-orion_nand.h>
struct orion_nand_info {
struct nand_chip chip;
struct clk *clk;
};
static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *nc = mtd_to_nand(mtd);
......@@ -75,20 +80,21 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static int __init orion_nand_probe(struct platform_device *pdev)
{
struct orion_nand_info *info;
struct mtd_info *mtd;
struct nand_chip *nc;
struct orion_nand_data *board;
struct resource *res;
struct clk *clk;
void __iomem *io_base;
int ret = 0;
u32 val = 0;
nc = devm_kzalloc(&pdev->dev,
sizeof(struct nand_chip),
info = devm_kzalloc(&pdev->dev,
sizeof(struct orion_nand_info),
GFP_KERNEL);
if (!nc)
if (!info)
return -ENOMEM;
nc = &info->chip;
mtd = nand_to_mtd(nc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......@@ -145,16 +151,23 @@ static int __init orion_nand_probe(struct platform_device *pdev)
if (board->dev_ready)
nc->dev_ready = board->dev_ready;
platform_set_drvdata(pdev, mtd);
platform_set_drvdata(pdev, info);
/* Not all platforms can gate the clock, so it is not
an error if the clock does not exists. */
clk = clk_get(&pdev->dev, NULL);
if (!IS_ERR(clk)) {
clk_prepare_enable(clk);
clk_put(clk);
info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
ret = PTR_ERR(info->clk);
if (ret == -ENOENT) {
info->clk = NULL;
} else {
dev_err(&pdev->dev, "failed to get clock!\n");
return ret;
}
}
clk_prepare_enable(info->clk);
ret = nand_scan(mtd, 1);
if (ret)
goto no_dev;
......@@ -169,26 +182,19 @@ static int __init orion_nand_probe(struct platform_device *pdev)
return 0;
no_dev:
if (!IS_ERR(clk)) {
clk_disable_unprepare(clk);
clk_put(clk);
}
clk_disable_unprepare(info->clk);
return ret;
}
static int orion_nand_remove(struct platform_device *pdev)
{
struct mtd_info *mtd = platform_get_drvdata(pdev);
struct clk *clk;
struct orion_nand_info *info = platform_get_drvdata(pdev);
struct nand_chip *chip = &info->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
nand_release(mtd);
clk = clk_get(&pdev->dev, NULL);
if (!IS_ERR(clk)) {
clk_disable_unprepare(clk);
clk_put(clk);
}
clk_disable_unprepare(info->clk);
return 0;
}
......
......@@ -2212,17 +2212,17 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
goto out_ahb_clk_unprepare;
nfc->reset = devm_reset_control_get_optional(dev, "ahb");
if (!IS_ERR(nfc->reset)) {
ret = reset_control_deassert(nfc->reset);
if (ret) {
dev_err(dev, "reset err %d\n", ret);
goto out_mod_clk_unprepare;
}
} else if (PTR_ERR(nfc->reset) != -ENOENT) {
if (IS_ERR(nfc->reset)) {
ret = PTR_ERR(nfc->reset);
goto out_mod_clk_unprepare;
}
ret = reset_control_deassert(nfc->reset);
if (ret) {
dev_err(dev, "reset err %d\n", ret);
goto out_mod_clk_unprepare;
}
ret = sunxi_nfc_rst(nfc);
if (ret)
goto out_ahb_reset_reassert;
......@@ -2262,8 +2262,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
if (nfc->dmac)
dma_release_channel(nfc->dmac);
out_ahb_reset_reassert:
if (!IS_ERR(nfc->reset))
reset_control_assert(nfc->reset);
reset_control_assert(nfc->reset);
out_mod_clk_unprepare:
clk_disable_unprepare(nfc->mod_clk);
out_ahb_clk_unprepare:
......@@ -2278,8 +2277,7 @@ static int sunxi_nfc_remove(struct platform_device *pdev)
sunxi_nand_chips_cleanup(nfc);
if (!IS_ERR(nfc->reset))
reset_control_assert(nfc->reset);
reset_control_assert(nfc->reset);
if (nfc->dmac)
dma_release_channel(nfc->dmac);
......
......@@ -223,12 +223,13 @@ static void tango_dma_callback(void *arg)
complete(arg);
}
static int do_dma(struct tango_nfc *nfc, int dir, int cmd, const void *buf,
int len, int page)
static int do_dma(struct tango_nfc *nfc, enum dma_data_direction dir, int cmd,
const void *buf, int len, int page)
{
void __iomem *addr = nfc->reg_base + NFC_STATUS;
struct dma_chan *chan = nfc->chan;
struct dma_async_tx_descriptor *desc;
enum dma_transfer_direction tdir;
struct scatterlist sg;
struct completion tx_done;
int err = -EIO;
......@@ -238,7 +239,8 @@ static int do_dma(struct tango_nfc *nfc, int dir, int cmd, const void *buf,
if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1)
return -EIO;
desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT);
tdir = dir == DMA_TO_DEVICE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
desc = dmaengine_prep_slave_sg(chan, &sg, 1, tdir, DMA_PREP_INTERRUPT);
if (!desc)
goto dma_unmap;
......
......@@ -366,26 +366,6 @@ struct onfi_ext_param_page {
*/
} __packed;
struct nand_onfi_vendor_micron {
u8 two_plane_read;
u8 read_cache;
u8 read_unique_id;
u8 dq_imped;
u8 dq_imped_num_settings;
u8 dq_imped_feat_addr;
u8 rb_pulldown_strength;
u8 rb_pulldown_strength_feat_addr;
u8 rb_pulldown_strength_num_settings;
u8 otp_mode;
u8 otp_page_start;
u8 otp_data_prot_addr;
u8 otp_num_pages;
u8 otp_feat_addr;
u8 read_retry_options;
u8 reserved[72];
u8 param_revision;
} __packed;
struct jedec_ecc_info {
u8 ecc_bits;
u8 codeword_size;
......@@ -464,6 +444,17 @@ struct nand_jedec_params {
__le16 crc;
} __packed;
/**
* struct nand_id - NAND id structure
* @data: buffer containing the id bytes. Currently 8 bytes large, but can
* be extended if required.
* @len: ID length.
*/
struct nand_id {
u8 data[8];
int len;
};
/**
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
* @lock: protection lock
......@@ -525,7 +516,7 @@ static inline void nand_hw_control_init(struct nand_hw_control *nfc)
* out-of-band data).
* @read_page: function to read a page according to the ECC generator
* requirements; returns maximum number of bitflips corrected in
* any single ECC step, 0 if bitflips uncorrectable, -EIO hw error
* any single ECC step, -EIO hw error
* @read_subpage: function to read parts of the page covered by ECC;
* returns same as read_page()
* @write_subpage: function to write parts of the page covered by ECC.
......@@ -720,6 +711,20 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
return &conf->timings.sdr;
}
/**
* struct nand_manufacturer_ops - NAND Manufacturer operations
* @detect: detect the NAND memory organization and capabilities
* @init: initialize all vendor specific fields (like the ->read_retry()
* implementation) if any.
* @cleanup: the ->init() function may have allocated resources, ->cleanup()
* is here to let vendor specific code release those resources.
*/
struct nand_manufacturer_ops {
void (*detect)(struct nand_chip *chip);
int (*init)(struct nand_chip *chip);
void (*cleanup)(struct nand_chip *chip);
};
/**
* struct nand_chip - NAND Private Flash Chip Data
* @mtd: MTD device registered to the MTD framework
......@@ -750,6 +755,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
* setting the read-retry mode. Mostly needed for MLC NAND.
* @ecc: [BOARDSPECIFIC] ECC control structure
* @buffers: buffer structure for read/write
* @buf_align: minimum buffer alignment required by a platform
* @hwcontrol: platform-specific hardware control structure
* @erase: [REPLACEABLE] erase function
* @scan_bbt: [REPLACEABLE] function to scan bad block table
......@@ -793,6 +799,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
* @pagebuf_bitflips: [INTERN] holds the bitflip count for the page which is
* currently in data_buf.
* @subpagesize: [INTERN] holds the subpagesize
* @id: [INTERN] holds NAND ID
* @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded),
* non 0 if ONFI supported.
* @jedec_version: [INTERN] holds the chip JEDEC version (BCD encoded),
......@@ -822,7 +829,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
* @errstat: [OPTIONAL] hardware specific function to perform
* additional error status checks (determine if errors are
* correctable).
* @write_page: [REPLACEABLE] High-level page write function
* @manufacturer: [INTERN] Contains manufacturer information
*/
struct nand_chip {
......@@ -847,9 +854,6 @@ struct nand_chip {
int (*scan_bbt)(struct mtd_info *mtd);
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
int status, int page);
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw);
int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para);
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
......@@ -881,6 +885,7 @@ struct nand_chip {
int badblockpos;
int badblockbits;
struct nand_id id;
int onfi_version;
int jedec_version;
union {
......@@ -901,6 +906,7 @@ struct nand_chip {
struct nand_ecc_ctrl ecc;
struct nand_buffers *buffers;
unsigned long buf_align;
struct nand_hw_control hwcontrol;
uint8_t *bbt;
......@@ -910,6 +916,11 @@ struct nand_chip {
struct nand_bbt_descr *badblock_pattern;
void *priv;
struct {
const struct nand_manufacturer *desc;
void *priv;
} manufacturer;
};
extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
......@@ -946,6 +957,17 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv)
chip->priv = priv;
}
static inline void nand_set_manufacturer_data(struct nand_chip *chip,
void *priv)
{
chip->manufacturer.priv = priv;
}
static inline void *nand_get_manufacturer_data(struct nand_chip *chip)
{
return chip->manufacturer.priv;
}
/*
* NAND Flash Manufacturer ID Codes
*/
......@@ -1049,17 +1071,33 @@ struct nand_flash_dev {
};
/**
* struct nand_manufacturers - NAND Flash Manufacturer ID Structure
* struct nand_manufacturer - NAND Flash Manufacturer structure
* @name: Manufacturer name
* @id: manufacturer ID code of device.
* @ops: manufacturer operations
*/
struct nand_manufacturers {
struct nand_manufacturer {
int id;
char *name;
const struct nand_manufacturer_ops *ops;
};
const struct nand_manufacturer *nand_get_manufacturer(u8 id);
static inline const char *
nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
{
return manufacturer ? manufacturer->name : "Unknown";
}
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];
extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
extern const struct nand_manufacturer_ops hynix_nand_manuf_ops;
extern const struct nand_manufacturer_ops micron_nand_manuf_ops;
extern const struct nand_manufacturer_ops amd_nand_manuf_ops;
extern const struct nand_manufacturer_ops macronix_nand_manuf_ops;
int nand_default_bbt(struct mtd_info *mtd);
int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
......@@ -1226,4 +1264,6 @@ int nand_reset(struct nand_chip *chip, int chipnr);
/* Free resources held by the NAND device */
void nand_cleanup(struct nand_chip *chip);
/* Default extended ID decoding function */
void nand_decode_ext_id(struct nand_chip *chip);
#endif /* __LINUX_MTD_NAND_H */
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