From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kuo-Jung Su Date: Thu, 9 May 2013 09:51:52 +0800 Subject: [U-Boot] [PATCH v5] nand: add Faraday FTNANDC021 NAND controller support In-Reply-To: <1367908391-12137-1-git-send-email-dantesu@gmail.com> References: <1367908391-12137-1-git-send-email-dantesu@gmail.com> Message-ID: <1368064312-14216-1-git-send-email-dantesu@gmail.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de From: Kuo-Jung Su Faraday FTNANDC021 is a integrated NAND flash controller. It use a build-in command table to abstract the underlying NAND flash control logic. For example: Issuing a command 0x10 to FTNANDC021 would result in a page write + a read status operation. Signed-off-by: Kuo-Jung Su CC: Scott Wood --- Changes for v5: - Update README for the description of CONFIG_SYS_FTNANDC021_TIMING. - Drop redundant white space. (i.e. if (mtd->writesize >= ' '4096)) Changes for v4: - Make it a separate patch, rather then a part of Faraday A36x patch series - Drop the faraday/nand.h to remove dependency to Faraday A36x patch series. - CONFIG_SYS_NAND_TIMING -> CONFIG_SYS_FTNANDC021_TIMING - Remove non-ECC code. - Implement private hwecc read/write_page functions to get rid of .eccpos & .eccbytes. - Use macro constants for timeout control Changes for v3: - Coding Style cleanup. - Drop macros for wirtel()/readl(), call them directly. - Always insert a blank line between declarations and code. - Replace all the infinite wait loop with a timeout. - Add '__iomem' to all the declaration of HW register pointers. - Re-write this driver with ECC enabled and correct column address handling for OOB read/write, - Fix issuses addressed by Scott. Changes for v2: - Coding Style cleanup. - Use readl(), writel(), clrsetbits_le32() to replace REG() macros. - Use structure based hardware registers to replace the macro constants. - Replace BIT() with BIT_MASK(). README | 6 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/ftnandc021.c | 607 +++++++++++++++++++++++++++++++++++++++++ include/faraday/ftnandc021.h | 146 ++++++++++ 4 files changed, 760 insertions(+) create mode 100644 drivers/mtd/nand/ftnandc021.c create mode 100644 include/faraday/ftnandc021.h diff --git a/README b/README index 0d37d56..94c15e0 100644 --- a/README +++ b/README @@ -3879,6 +3879,12 @@ Low Level (hardware related) configuration options: - drivers/mtd/nand/ndfc.c - drivers/mtd/nand/mxc_nand.c +- CONFIG_SYS_FTNANDC021_TIMING + This option specifies an array of customized timing parameters + for Faraday FTNANDC021 NAND flash controller. + e.g. + #define CONFIG_SYS_FTNANDC021_TIMING { 0x02240264, 0x42054209 } + - CONFIG_SYS_NDFC_EBC0_CFG Sets the EBC0_CFG register for the NDFC. If not defined a default value will be used. diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 35769c5..f6f89f0 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -63,6 +63,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o +COBJS-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c new file mode 100644 index 0000000..213b67a --- /dev/null +++ b/drivers/mtd/nand/ftnandc021.c @@ -0,0 +1,607 @@ +/* + * Faraday NAND Flash Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */ +#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */ +#define CFG_PIO_TIMEOUT (CONFIG_SYS_HZ >> 3) /* 125 ms */ + +struct ftnandc021_chip { + void __iomem *regs; + int alen; + int pgsz; + int bksz; + + int col; /* current column address */ + int page; /* current row address/page index */ + int cmd; /* current NAND command code */ + int cmd_hc; /* current FTNANDC021 command code */ +}; + +static struct nand_ecclayout ftnandc021_ecclayout[] = { + { /* page size = 512 (oob size = 16) */ + .oobfree = { + { 9, 3 }, + } + }, + { /* page size = 2048 (oob size = 64) */ + .oobfree = { + { 9, 3 }, + }, + }, + { /* page size = 4096 (oob size = 128) */ + .oobfree = { + { 9, 7 }, + }, + }, +}; + +static inline int ftnandc021_ckst(struct ftnandc021_chip *priv) +{ + struct ftnandc021_regs __iomem *regs = priv->regs; + uint32_t st = readl(®s->idr[1]); + + if (st & NAND_STATUS_FAIL) + return -EIO; + + if (!(st & NAND_STATUS_READY)) + return -EBUSY; + + if (!(st & NAND_STATUS_WP)) + return -EIO; + + return 0; +} + +static inline int ftnandc021_wait(struct ftnandc021_chip *priv) +{ + struct ftnandc021_regs __iomem *regs = priv->regs; + char rc = 'c'; + ulong ts; + + for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { + if (readl(®s->sr) & SR_ECC) { + rc = 'e'; + break; + } + if (!(readl(®s->acr) & ACR_START)) { + rc = 0; + break; + } + } + + switch (rc) { + case 'e': + printf("ftnandc021: ecc timeout, cmd_hc=%d\n", + priv->cmd_hc); + break; + case 'c': + printf("ftnandc021: cmd timeout, cmd_hc=%d\n", + priv->cmd_hc); + break; + default: + break; + } + + return rc ? -ETIMEDOUT : 0; +} + +static int ftnandc021_read_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int page) +{ + /* + * OOB has been read at ftnandc021_cmdfunc(), + * so we don't have to handle it here. + */ + chip->read_buf(mtd, buf, mtd->writesize); + return 0; +} + +static void ftnandc021_write_page(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + /* + * OOB has been written at ftnandc021_cmdfunc(), + * so we don't have to handle it here. + */ + chip->write_buf(mtd, buf, mtd->writesize); +} + +static int ftnandc021_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int page) +{ + printf("ftnandc021: read_page_raw is not supported\n"); + return -EIO; +} + +static void ftnandc021_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + printf("ftnandc021: write_page_raw is not supported\n"); +} + +static int ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd) +{ + struct ftnandc021_regs __iomem *regs = priv->regs; + int ret = 0; + + priv->cmd_hc = cmd; + + writel(ACR_START | ACR_CMD(cmd), ®s->acr); + + /* + * pgread : (We have queued data at the IO port) + * pgwrite : (We have queued data at the IO port) + * bkerase : nand_wait + nand_ckst + * oobwr : nand_wait + nand_ckst + * otherwise : nand_wait + */ + switch (cmd) { + case FTNANDC021_CMD_RDPG: + case FTNANDC021_CMD_WRPG: + break; + case FTNANDC021_CMD_ERBLK: + case FTNANDC021_CMD_WROOB: + ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv); + break; + default: + ret = ftnandc021_wait(priv); + } + + return ret; +} + +static int ftnandc021_reset(struct nand_chip *chip) +{ + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs __iomem *regs = priv->regs; + uint32_t ts, bk, pg, ac, mask; +#ifdef CONFIG_SYS_FTNANDC021_TIMING + uint32_t timing[] = CONFIG_SYS_FTNANDC021_TIMING; + + writel(timing[0], ®s->atr[0]); + writel(timing[1], ®s->atr[1]); +#endif + + writel(0, ®s->ier); + writel(0, ®s->pir); + writel(0xff, ®s->bbiwr); + writel(0xffffffff, ®s->lsnwr); + writel(0xffffffff, ®s->crcwr); + + if (chip->options & NAND_BUSWIDTH_16) + writel(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, ®s->fcr); + else + writel(FCR_SWCRC | FCR_IGNCRC, ®s->fcr); + + /* chip reset */ + mask = SRR_CHIP_RESET | SRR_ECC_EN; + writel(mask, ®s->srr); + for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) { + if (readl(®s->srr) & SRR_CHIP_RESET) + continue; + break; + } + if (readl(®s->srr) & SRR_CHIP_RESET) { + printf("ftnandc021: reset failed\n"); + return -ENXIO; + } + + /* sanity check on page size */ + if (priv->pgsz != 512 && priv->pgsz != 2048 && priv->pgsz != 4096) { + printf("ftnandc021: invalid page size=%d\n", priv->pgsz); + return -EINVAL; + } + + bk = ffs(priv->bksz / priv->pgsz) - 5; + pg = (priv->pgsz < 2048) ? 0 : (ffs(priv->pgsz) - 11); + ac = priv->alen - 3; + + writel(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10), + ®s->mcr); + + /* IO mode = PIO */ + writel(0, ®s->bcr); + + /* ECC mode */ + chip->ecc.layout = ftnandc021_ecclayout + pg; + chip->ecc.size = priv->pgsz; + chip->ecc.steps = 1; + chip->ecc.read_page = ftnandc021_read_page; + chip->ecc.write_page = ftnandc021_write_page; + chip->ecc.read_page_raw = ftnandc021_read_page_raw; + chip->ecc.write_page_raw = ftnandc021_write_page_raw; + chip->ecc.mode = NAND_ECC_HW; + + /* reset the attached flash */ + if (ftnandc021_command(priv, FTNANDC021_CMD_RESET)) + return -ENXIO; + + return 0; +} + +/* + * Check hardware register for wait status. Returns 1 if device is ready, + * 0 if it is still busy. + */ +static int ftnandc021_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs __iomem *regs = priv->regs; + int ret = 1; + + if (ftnandc021_wait(priv)) + ret = 0; + else if (!(readl(®s->sr) & SR_READY)) + ret = 0; + + return ret; +} + +static int ftnandc021_pio_wait(struct ftnandc021_chip *priv) +{ + struct ftnandc021_regs __iomem *regs = priv->regs; + int ret = -ETIMEDOUT; + uint32_t ts; + + for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) { + if (!(readl(®s->ior) & IOR_READY)) + continue; + ret = 0; + break; + } + + if (ret) + printf("ftnandc021: pio timeout\n"); + + return ret; +} + +static void ftnandc021_read_oob(struct mtd_info *mtd, + uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs __iomem *regs = priv->regs; + uint32_t tmp; + + memset(buf, 0xff, len); + + /* bad block */ + buf[chip->badblockpos] = readl(®s->bbird) & 0xff; + + /* data */ + tmp = readl(®s->crcrd); + buf[8] = (tmp >> 0) & 0xff; + buf[9] = (tmp >> 8) & 0xff; + if (mtd->writesize >= 4096) { + buf[12] = (tmp >> 16) & 0xff; + buf[13] = (tmp >> 24) & 0xff; + } + + tmp = readl(®s->lsnrd); + buf[10] = (tmp >> 0) & 0xff; + buf[11] = (tmp >> 8) & 0xff; + if (mtd->writesize >= 4096) { + buf[14] = (tmp >> 16) & 0xff; + buf[15] = (tmp >> 24) & 0xff; + } +} + +static void ftnandc021_write_oob(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs __iomem *regs = priv->regs; + uint32_t tmp; + + /* bad block */ + tmp = buf[chip->badblockpos]; + writel(tmp, ®s->bbiwr); + + /* mark it as 'not blank' */ + tmp = 'W' | (buf[9] << 8); + if (mtd->writesize >= 4096) + tmp |= (buf[12] << 16) | (buf[13] << 24); + writel(tmp, ®s->crcwr); + + tmp = buf[10] | (buf[11] << 8); + if (mtd->writesize >= 4096) + tmp |= (buf[14] << 16) | (buf[15] << 24); + writel(tmp, ®s->lsnwr); +} + +static uint8_t ftnandc021_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs __iomem *regs = priv->regs; + uint8_t ret = 0xff; + + switch (priv->cmd) { + case NAND_CMD_READID: + if (priv->col < 8) { + uint32_t idx = priv->col >> 2; + uint32_t pos = priv->col & 0x3; + uint32_t tmp = readl(®s->idr[idx]); + + ret = (uint8_t)(tmp >> (pos << 3)); + priv->col += 1; + } + break; + case NAND_CMD_STATUS: + ret = (uint8_t)(readl(®s->idr[1]) & 0xff); + break; + default: + printf("ftnandc021: unknown cmd=0x%x in read_byte\n", + priv->cmd); + break; + } + + return ret; +} + +static uint16_t ftnandc021_read_word(struct mtd_info *mtd) +{ + uint16_t ret = 0xffff; + uint8_t *buf = (uint8_t *)&ret; + + /* LSB format */ + buf[0] = ftnandc021_read_byte(mtd); + buf[1] = ftnandc021_read_byte(mtd); + + return ret; +} + +/** + * Read data from NAND controller into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + */ +static void ftnandc021_read_buf(struct mtd_info *mtd, + uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs __iomem *regs = priv->regs; + int off; + + if (priv->col >= mtd->writesize) + return; + + if (priv->cmd == NAND_CMD_READOOB) + BUG(); /* should never happen */ + + /* skip if it's a blank page */ + if (chip->oob_poi[8] != 'W') { + memset(buf, 0xff, len); + return; + } + + off = 0; + while (off < len && priv->col < mtd->writesize) { + ftnandc021_pio_wait(priv); + *(uint32_t *)(buf + off) = readl(®s->dr); + priv->col += 4; + off += 4; + } + + ftnandc021_wait(priv); +} + +/** + * Write buffer to NAND controller + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + */ +static void ftnandc021_write_buf(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs __iomem *regs = priv->regs; + int off; + + /* + * FTNANDC021 HW design issues: + * + * 1. OOB data must be set before issuing write command, + * so it's too late to do it right here + * 2. Only after command issued, the data register + * could accept data. + */ + if (priv->col >= mtd->writesize) + return; + + for (off = 0; off < len && priv->col < mtd->writesize; ) { + ftnandc021_pio_wait(priv); + writel(*(uint32_t *)(buf + off), ®s->dr); + priv->col += 4; + off += 4; + } + + ftnandc021_wait(priv); +} + +/** + * Verify chip data against buffer + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare + */ +static int ftnandc021_verify_buf(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + int ret = 0; + uint8_t *tmp; + + len = min_t(int, len, mtd->writesize); + tmp = malloc(mtd->writesize); + + if (!tmp) { + printf("ftnandc021: out of memory\n"); + return -ENOMEM; + } else { + ftnandc021_read_buf(mtd, tmp, len); + if (memcmp(tmp, buf, len)) + ret = -EINVAL; + } + + free(tmp); + return ret; +} + +static void ftnandc021_cmdfunc(struct mtd_info *mtd, + unsigned cmd, int col, int page) +{ + struct nand_chip *chip = mtd->priv; + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs __iomem *regs = priv->regs; + + priv->cmd = cmd; + priv->col = col; + priv->page = page; + + switch (cmd) { + case NAND_CMD_READID: /* 0x90 */ + priv->col = 0; + if (ftnandc021_command(priv, FTNANDC021_CMD_RDID)) + printf("ftnandc021: RDID failed.\n"); + break; + + case NAND_CMD_READOOB: /* 0x50 */ + priv->col = mtd->writesize; + /* fall-through */ + case NAND_CMD_READ0: /* 0x00 */ + writel(page, ®s->pir); + writel(1, ®s->pcr); + /* fetch oob to check if it's a blank page */ + if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) { + printf("ftnandc021: RDOOB failed.\n"); + break; + } + ftnandc021_read_oob(mtd, chip->oob_poi, mtd->oobsize); + /* skip if we don't need page data */ + if (priv->col >= mtd->writesize) + break; + /* skip if it's a blank page */ + if (chip->oob_poi[8] != 'W') { + debug("ftnandc021: skip page %d\n", page); + break; + } + if (ftnandc021_command(priv, FTNANDC021_CMD_RDPG)) + printf("ftnandc021: RDPG failed.\n"); + break; + + case NAND_CMD_ERASE1: /* 0x60 */ + writel(page, ®s->pir); + writel(1, ®s->pcr); + break; + + case NAND_CMD_ERASE2: /* 0xD0 */ + if (ftnandc021_command(priv, FTNANDC021_CMD_ERBLK)) + printf("ftnandc021: ERBLK failed\n"); + break; + + case NAND_CMD_STATUS: /* 0x70 */ + if (ftnandc021_command(priv, FTNANDC021_CMD_RDST)) + printf("ftnandc021: RDST failed\n"); + break; + + case NAND_CMD_SEQIN: /* 0x80 (Write Stage 1.) */ + writel(page, ®s->pir); + writel(1, ®s->pcr); + /* OOB data must be set before issuing command */ + ftnandc021_write_oob(mtd, chip->oob_poi, mtd->oobsize); + priv->cmd_hc = (priv->col >= mtd->writesize) + ? FTNANDC021_CMD_WROOB : FTNANDC021_CMD_WRPG; + if (ftnandc021_command(priv, priv->cmd_hc)) + printf("ftnandc021: CMD_HC=%d failed\n", priv->cmd_hc); + break; + + case NAND_CMD_PAGEPROG: /* 0x10 (Write Stage 2.) */ + /* nothing needs to be done */ + break; + + case NAND_CMD_RESET: /* 0xFF */ + if (ftnandc021_command(priv, FTNANDC021_CMD_RESET)) + printf("ftnandc021: RESET failed.\n"); + break; + + default: + printf("ftnandc021: unknown cmd=0x%x\n", cmd); + } +} + +/** + * hardware specific access to control-lines + * @mtd: MTD device structure + * @cmd: command to device + * @ctrl: + * NAND_NCE: bit 0 -> don't care + * NAND_CLE: bit 1 -> Command Latch + * NAND_ALE: bit 2 -> Address Latch + * + * NOTE: boards may use different bits for these!! + */ +static void ftnandc021_hwcontrol(struct mtd_info *mtd, + int cmd, unsigned int ctrl) +{ + /* nothing needs to be done */ +} + +int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen) +{ + struct ftnandc021_chip *priv; + + priv = calloc(1, sizeof(struct ftnandc021_chip)); + if (!priv) + return -ENOMEM; + + priv->regs = (void __iomem *)iobase; + priv->pgsz = 1 << chip->page_shift; + priv->bksz = 1 << chip->phys_erase_shift; + priv->alen = alen; + + chip->priv = priv; + + debug("ftnandc021: pg=%dK, bk=%dK, alen=%d\n", + priv->pgsz, priv->bksz, priv->alen); + + /* hardware reset */ + if (ftnandc021_reset(chip)) + return -EINVAL; + + /* hwcontrol always must be implemented */ + chip->cmd_ctrl = ftnandc021_hwcontrol; + chip->cmdfunc = ftnandc021_cmdfunc; + chip->dev_ready = ftnandc021_dev_ready; + chip->chip_delay = 0; + + chip->read_byte = ftnandc021_read_byte; + chip->read_word = ftnandc021_read_word; + chip->read_buf = ftnandc021_read_buf; + chip->write_buf = ftnandc021_write_buf; + chip->verify_buf = ftnandc021_verify_buf; + + return 0; +} diff --git a/include/faraday/ftnandc021.h b/include/faraday/ftnandc021.h new file mode 100644 index 0000000..c70e91e --- /dev/null +++ b/include/faraday/ftnandc021.h @@ -0,0 +1,146 @@ +/* + * Faraday NAND Flash Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#ifndef __FTNANDC021_H +#define __FTNANDC021_H + +/* NANDC control registers */ +struct ftnandc021_regs { + /* 0x000 ~ 0x0fc */ + uint32_t ecc_pr[4];/* ECC Parity Register */ + uint32_t ecc_sr; /* ECC Status Register */ + uint32_t rsvd0[59]; + + /* 0x100 ~ 0x1fc */ + uint32_t sr; /* Status Register */ + uint32_t acr; /* Access Control Register */ + uint32_t fcr; /* Flow Control Register */ + uint32_t pir; /* Page Index Register */ + uint32_t mcr; /* Memory Configuration Register */ + uint32_t atr[2]; /* AC Timing Register */ + uint32_t rsvd1[1]; + uint32_t idr[2]; /* Device ID Register */ + uint32_t ier; /* Interrupt Enable Register */ + uint32_t iscr; /* Interrupt Status Clear Register */ + uint32_t rsvd2[4]; + uint32_t bbiwr; /* Bad Block Info Write */ + uint32_t lsn; /* LSN Initialize */ + uint32_t crcwr; /* LSN CRC Write */ + uint32_t lsnwr; /* LSN Write */ + uint32_t bbird; /* Bad Block Info Read */ + uint32_t lsnrd; /* LSN Read */ + uint32_t crcrd; /* CRC Read */ + uint32_t rsvd3[41]; + + /* 0x200 ~ 0x2fc */ + uint32_t rsvd4[1]; + uint32_t icr; /* BMC Interrupt Control Register */ + uint32_t ior; /* BMC PIO Status Register */ + uint32_t bcr; /* BMC Burst Control Register */ + uint32_t rsvd5[60]; + + /* 0x300 ~ 0x3fc */ + uint32_t dr; /* MLC Data Register */ + uint32_t isr; /* MLC Interrupt Status Register */ + uint32_t pcr; /* Page Count Register */ + uint32_t srr; /* MLC Software Reset Register */ + uint32_t rsvd7[58]; + uint32_t revr; /* Revision Register */ + uint32_t cfgr; /* Configuration Register */ +}; + +/* ECC Status Register */ +#define ECC_SR_CERR (1 << 3) /* correction error */ +#define ECC_SR_ERR (1 << 2) /* ecc error */ +#define ECC_SR_DEC (1 << 1) /* ecc decode finished */ +#define ECC_SR_ENC (1 << 0) /* ecc encode finished */ + +/* Status Register */ +#define SR_BLANK (1 << 7) /* blanking check failed */ +#define SR_ECC (1 << 6) /* ecc timeout */ +#define SR_STS (1 << 4) /* status error */ +#define SR_CRC (1 << 3) /* crc error */ +#define SR_CMD (1 << 2) /* command finished */ +#define SR_READY (1 << 1) /* chip ready/busy */ +#define SR_ENA (1 << 0) /* chip enabled */ + +/* Access Control Register */ +#define ACR_CMD(x) (((x) & 0x1f) << 8) /* command code */ +#define ACR_START (1 << 7) /* command start */ + +/* Flow Control Register */ +#define FCR_SWCRC (1 << 8) /* CRC controlled by Software */ +#define FCR_IGNCRC (1 << 7) /* Bypass/Ignore CRC checking */ +#define FCR_16BIT (1 << 4) /* 16 bit data bus */ +#define FCR_WPROT (1 << 3) /* write protected */ +#define FCR_NOSC (1 << 2) /* bypass status check error */ +#define FCR_MICRON (1 << 1) /* Micron 2-plane command */ +#define FCR_NOBC (1 << 0) /* skip blanking check error */ + +/* Interrupt Enable Register */ +#define IER_ENA (1 << 7) /* interrupt enabled */ +#define IER_ECC (1 << 3) /* ecc error timeout */ +#define IER_STS (1 << 2) /* status error */ +#define IER_CRC (1 << 1) /* crc error */ +#define IER_CMD (1 << 0) /* command finished */ + +/* BMC PIO Status Register */ +#define IOR_READY (1 << 0) /* PIO ready */ + +/* MLC Software Reset Register */ +#define SRR_ECC_EN (1 << 8) /* ECC enabled */ +#define SRR_NANDC_RESET (1 << 2) /* NANDC reset */ +#define SRR_BMC_RESET (1 << 1) /* BMC reset */ +#define SRR_ECC_RESET (1 << 0) /* ECC reset */ +#define SRR_CHIP_RESET (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET) + +/* Memory Configuration Register */ +#define MCR_BS16P (0 << 16) /* page count per block */ +#define MCR_BS32P (1 << 16) +#define MCR_BS64P (2 << 16) +#define MCR_BS128P (3 << 16) +#define MCR_1PLANE (0 << 14) /* memory architecture */ +#define MCR_2PLANE (1 << 14) +#define MCR_SERIAL (0 << 12) /* interleaving: off, 2 flash, 4 flash */ +#define MCR_IL2 (1 << 12) +#define MCR_IL4 (2 << 12) +#define MCR_ALEN3 (0 << 10) /* address length */ +#define MCR_ALEN4 (1 << 10) +#define MCR_ALEN5 (2 << 10) +#define MCR_PS512 (0 << 8) /* size per page (bytes) */ +#define MCR_PS2048 (1 << 8) +#define MCR_PS4096 (2 << 8) +#define MCR_16MB (0 << 4) /* flash size */ +#define MCR_32MB (1 << 4) +#define MCR_64MB (2 << 4) +#define MCR_128MB (3 << 4) +#define MCR_256MB (4 << 4) +#define MCR_512MB (5 << 4) +#define MCR_1GB (6 << 4) +#define MCR_2GB (7 << 4) +#define MCR_4GB (8 << 4) +#define MCR_8GB (9 << 4) +#define MCR_16GB (10 << 4) +#define MCR_32GB (11 << 4) +#define MCR_ME(n) (1 << (n)) /* module enable, 0 <= n <= 3 */ + +/* FTNANDC021 built-in command set */ +#define FTNANDC021_CMD_RDID 0x01 /* read id */ +#define FTNANDC021_CMD_RESET 0x02 /* reset flash */ +#define FTNANDC021_CMD_RDST 0x04 /* read status */ +#define FTNANDC021_CMD_RDPG 0x05 /* read page (data + oob) */ +#define FTNANDC021_CMD_RDOOB 0x06 /* read oob */ +#define FTNANDC021_CMD_WRPG 0x10 /* write page (data + oob) */ +#define FTNANDC021_CMD_ERBLK 0x11 /* erase block */ +#define FTNANDC021_CMD_WROOB 0x13 /* write oob */ + +int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen); + +#endif /* EOF */ -- 1.7.9.5