From patchwork Thu Apr 18 09:25:34 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuo-Jung Su X-Patchwork-Id: 237578 X-Patchwork-Delegate: albert.aribaud@free.fr Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 6E92F2C01D3 for ; Thu, 18 Apr 2013 19:27:48 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 1062F4A32A; Thu, 18 Apr 2013 11:26:55 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id cKhn8XdcbWP2; Thu, 18 Apr 2013 11:26:54 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D5E934A32E; Thu, 18 Apr 2013 11:26:23 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 885F44A319 for ; Thu, 18 Apr 2013 11:26:03 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ruFsae5B9U-b for ; Thu, 18 Apr 2013 11:25:54 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-pa0-f54.google.com (mail-pa0-f54.google.com [209.85.220.54]) by theia.denx.de (Postfix) with ESMTPS id 9DD494A345 for ; Thu, 18 Apr 2013 11:25:26 +0200 (CEST) Received: by mail-pa0-f54.google.com with SMTP id fa11so1464740pad.27 for ; Thu, 18 Apr 2013 02:25:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:in-reply-to:references; bh=awKX2oFk1S9Lz5Qe2ttw7zVdwqAu71lStKJsTEgMnfs=; b=C1PfYUcicVqhbi/vnl9CNJp8AQ5BgvSMYs4QT7ALJyytWD8iZ7V7TpthoN0h6eq+P4 0Pbfv8uxhT1ncLCC52Hxzlsjhpo0uqSlfHuUY1ZvA6P7zNJmmHm4hkwajvcPwzC3+h8O 8rT+0RpT2r7Ygwk43L6pYwb+y24zP4wfWwJhyh+uN2k+9oMz6wq03KA+meQ13zW6r/LT u29YDk3E2c5m0OtHu49gtqErGR1t88Xr+R1xk6LcnCYqBDfP1LXMmE+U0nhIc6sSDUUo MOU4mIk4ghK7oclIpITM5CRMX9QNbSX/3KNW7bxel7eD36IFLpfXHhIlIv+t5Tuqy1C4 Gmzw== X-Received: by 10.68.202.4 with SMTP id ke4mr13027059pbc.185.1366277124594; Thu, 18 Apr 2013 02:25:24 -0700 (PDT) Received: from localhost.localdomain ([220.132.37.35]) by mx.google.com with ESMTPS id xl10sm10280496pac.15.2013.04.18.02.25.22 (version=TLSv1 cipher=DES-CBC3-SHA bits=168/168); Thu, 18 Apr 2013 02:25:24 -0700 (PDT) From: Kuo-Jung Su To: u-boot@lists.denx.de Date: Thu, 18 Apr 2013 17:25:34 +0800 Message-Id: <1366277139-29728-8-git-send-email-dantesu@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1366277139-29728-1-git-send-email-dantesu@gmail.com> References: <1366277139-29728-1-git-send-email-dantesu@gmail.com> In-Reply-To: <1364540788-13943-2-git-send-email-dantesu@gmail.com> References: <1364540788-13943-2-git-send-email-dantesu@gmail.com> Cc: Scott Wood , Kuo-Jung Su Subject: [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@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 --- drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/ftnandc021.c | 544 +++++++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/ftnandc021.h | 132 ++++++++++ include/faraday/nand.h | 16 ++ 4 files changed, 693 insertions(+) create mode 100644 drivers/mtd/nand/ftnandc021.c create mode 100644 drivers/mtd/nand/ftnandc021.h create mode 100644 include/faraday/nand.h -- 1.7.9.5 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..58863dc --- /dev/null +++ b/drivers/mtd/nand/ftnandc021.c @@ -0,0 +1,544 @@ +/* + * 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 "ftnandc021.h" + +/* common bitmask of nand flash status register */ +#define NAND_IOSTATUS_ERROR BIT_MASK(0) +#define NAND_IOSTATUS_READY BIT_MASK(6) +#define NAND_IOSTATUS_UNPROTCT BIT_MASK(7) + +struct ftnandc021_chip { + void *iobase; + uint32_t cmd; + + uint32_t pgidx; + + uint32_t off; + uint8_t buf[256]; + + uint32_t adrc; /* address cycle */ + uint32_t pgsz; /* page size */ + uint32_t bksz; /* block size */ +}; + +/* Register access macros */ +#define NAND_READ(r) le32_to_cpu(readl(r)) +#define NAND_WRITE(v, r) writel(cpu_to_le32(v), r) +#define NAND_SETBITS(m, r) setbits_le32(r, m) +#define NAND_CLRBITS(m, r) clrbits_le32(r, m) + +static struct nand_ecclayout ftnandc021_oob_2k = { + .eccbytes = 24, + .eccpos = { + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63 + }, + .oobfree = { + { + .offset = 9, + .length = 3 + } + } +}; + +static int +ftnandc021_reset(struct nand_chip *chip) +{ + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs *regs = priv->iobase; + uint32_t bk = 2; /* 64 pages */ + uint32_t pg = 1; /* 2k */ + uint32_t ac = 2; /* 5 */ + +#ifdef CONFIG_FTNANDC021_ACTIMING_1 + NAND_WRITE(CONFIG_FTNANDC021_ACTIMING_1, ®s->atr[0]); +#endif +#ifdef CONFIG_FTNANDC021_ACTIMING_2 + NAND_WRITE(CONFIG_FTNANDC021_ACTIMING_2, ®s->atr[1]); +#endif + + NAND_WRITE(0, ®s->ier); + NAND_WRITE(0, ®s->pir); + NAND_WRITE(0xff, ®s->bbiwr); + NAND_WRITE(0xffffffff, ®s->lsnwr); + NAND_WRITE(0xffffffff, ®s->crcwr); + + if (chip->options & NAND_BUSWIDTH_16) + NAND_WRITE(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, ®s->fcr); + else + NAND_WRITE(FCR_SWCRC | FCR_IGNCRC, ®s->fcr); + + /* chip reset */ + NAND_WRITE(SRR_CHIP_RESET, ®s->srr); + + /* wait until chip ready */ + while (NAND_READ(®s->srr) & SRR_CHIP_RESET) + ; + + switch (priv->bksz / priv->pgsz) { + case 16: + bk = 0; + break; + case 32: + bk = 1; + break; + case 64: + bk = 2; + break; + case 128: + bk = 3; + break; + } + + switch (priv->pgsz) { + case 512: + pg = 0; + break; + case 2048: + pg = 1; + break; + case 4096: + pg = 2; + break; + } + + switch (priv->adrc) { + case 3: + ac = 0; + break; + case 4: + ac = 1; + break; + case 5: + ac = 2; + break; + } + + NAND_WRITE(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10), + ®s->mcr); + + /* PIO mode */ + NAND_WRITE(0, ®s->ior); + + return 0; +} + +static inline int +ftnandc021_ckst(struct ftnandc021_chip *priv) +{ + struct ftnandc021_regs *regs = priv->iobase; + uint32_t st = NAND_READ(®s->idr[1]); + + if (st & NAND_IOSTATUS_ERROR) + return -NAND_IOSTATUS_ERROR; + + if (!(st & NAND_IOSTATUS_READY)) + return -NAND_IOSTATUS_READY; + + if (!(st & NAND_IOSTATUS_UNPROTCT)) + return -NAND_IOSTATUS_UNPROTCT; + + return 0; +} + +static inline int +ftnandc021_wait(struct ftnandc021_chip *priv) +{ + struct ftnandc021_regs *regs = priv->iobase; + ulong ts; + int rc = -1; + + for (ts = get_timer(0); get_timer(ts) < 200; ) { + if (!(NAND_READ(®s->acr) & ACR_START)) { + rc = 0; + break; + } + } + + return rc; +} + +static int +ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd) +{ + struct ftnandc021_regs *regs = priv->iobase; + int ret = 0; + + NAND_WRITE(ACR_START | ACR_CMD(cmd), ®s->acr); + + /* + * pgread : (We have queued data at the IO port) + * pgwrite : nand_ckst (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: + break; + case FTNANDC021_CMD_WRPG: + ret = ftnandc021_ckst(priv); + break; + case FTNANDC021_CMD_ERBLK: + case FTNANDC021_CMD_WROOB: + ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv); + break; + default: + ret = ftnandc021_wait(priv); + } + + return ret; +} + +/* + * 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; + int ret = 1; + + if (ftnandc021_wait(priv) || ftnandc021_ckst(priv)) + ret = 0; + + 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 *regs = priv->iobase; + uint32_t tmp; + + /* + * Bad Block Information: + * 1. Large Page(2048, 4096): off=0, len=2 + * 2. Small Page(512): off=5, len=1 + */ + buf[0] = NAND_READ(®s->bbird) & 0xFF; + buf[1] = 0xFF; + + tmp = NAND_READ(®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 = NAND_READ(®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 *regs = priv->iobase; + uint32_t tmp; + + tmp = buf[0]; + NAND_WRITE(tmp, ®s->bbiwr); + + tmp = buf[8] | (buf[9] << 8); + if (mtd->writesize >= 4096) + tmp |= (buf[12] << 16) | (buf[13] << 24); + NAND_WRITE(tmp, ®s->crcwr); + + tmp = buf[10] | (buf[11] << 8); + if (mtd->writesize >= 4096) + tmp |= (buf[14] << 16) | (buf[15] << 24); + NAND_WRITE(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 *regs = priv->iobase; + uint8_t ret = 0xff; + + switch (priv->cmd) { + case NAND_CMD_READID: + case NAND_CMD_READOOB: + ret = priv->buf[priv->off % 256]; + priv->off += 1; + break; + case NAND_CMD_STATUS: + ret = (uint8_t)(NAND_READ(®s->idr[1]) & 0xff); + break; + default: + debug("ftnandc021_read_byte: unknown cmd(0x%02X)\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; + + 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 *regs = priv->iobase; + ulong off; + + /* oob read */ + if (len <= mtd->oobsize) { + ftnandc021_read_oob(mtd, buf, len); + return; + } + + /* page read */ + for (off = 0; len > 0; len -= 4, off += 4) { + while (!(NAND_READ(®s->ior) & IOR_READY)) + ; + *(uint32_t *)(buf + off) = NAND_READ(®s->dr); + } + + if (ftnandc021_wait(priv)) + printf("ftnandc021_read_buf: cmd(0x%x) timeout\n", priv->cmd); +} + +/** + * 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 *regs = priv->iobase; + ulong off; + + /* 1. oob write */ + if (len <= mtd->oobsize) + return; + + /* 2. page write */ + for (off = 0; len > 0; len -= 4, off += 4) { + while (!(NAND_READ(®s->ior) & IOR_READY)) + ; + NAND_WRITE(*(uint32_t *)(buf + off), ®s->dr); + } + + /* 3. wait until command finish */ + if (ftnandc021_wait(priv)) + printf("ftnandc021_write_buf: write fail\n"); +} + +/** + * 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 rc = 0; + uint8_t *tmp; + + len = min_t(int, len, mtd->writesize); + tmp = malloc(mtd->writesize); + + if (!tmp) { + printf("ftnandc021_verify_buf: out of memory\n"); + return -1; + } else { + ftnandc021_read_buf(mtd, tmp, len); + if (memcmp(tmp, buf, len)) + rc = -2; + } + + free(tmp); + return rc; +} + +static void +ftnandc021_cmdfunc(struct mtd_info *mtd, unsigned cmd, int column, int pgidx) +{ + struct nand_chip *chip = mtd->priv; + struct ftnandc021_chip *priv = chip->priv; + struct ftnandc021_regs *regs = priv->iobase; + + priv->cmd = cmd; + priv->pgidx = pgidx; + + switch (cmd) { + case NAND_CMD_READID: /* 0x90 */ + if (ftnandc021_command(priv, FTNANDC021_CMD_RDID)) { + printf("ftnandc021: RDID failed.\n"); + } else { + put_unaligned_le32(NAND_READ(®s->idr[0]), + priv->buf); + put_unaligned_le32(NAND_READ(®s->idr[1]), + priv->buf + 4); + priv->off = 0; + } + break; + + case NAND_CMD_READ0: /* 0x00 */ + NAND_WRITE(pgidx, ®s->pir); + NAND_WRITE(1, ®s->pcr); + if (ftnandc021_command(priv, FTNANDC021_CMD_RDPG)) + printf("ftnandc021: RDPG failed.\n"); + break; + + case NAND_CMD_READOOB: /* 0x50 */ + NAND_WRITE(pgidx, ®s->pir); + NAND_WRITE(1, ®s->pcr); + if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) { + printf("ftnandc021: RDOOB failed.\n"); + } else { + ftnandc021_read_oob(mtd, priv->buf, mtd->oobsize); + priv->off = 0; + } + break; + + case NAND_CMD_ERASE1: /* 0x60 */ + NAND_WRITE(pgidx, ®s->pir); + NAND_WRITE(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.) */ + NAND_WRITE(pgidx, ®s->pir); + NAND_WRITE(1, ®s->pcr); + + ftnandc021_write_oob(mtd, chip->oob_poi, mtd->writesize); + if (column >= mtd->writesize) { + if (ftnandc021_command(priv, FTNANDC021_CMD_WROOB)) + printf("ftnandc021: WROOB failed\n"); + } else { + if (ftnandc021_command(priv, FTNANDC021_CMD_WRPG)) + printf("ftnandc021: WRPG failed\n"); + } + break; + + case NAND_CMD_PAGEPROG: /* 0x10 (Write Stage 2.) */ + 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) +{ +} + +int +ftnandc021_probe(struct nand_chip *chip) +{ + struct ftnandc021_chip *priv; + + priv = malloc(sizeof(struct ftnandc021_chip)); + if (!priv) + return -1; + + memset(priv, 0, sizeof(*priv)); + priv->iobase = (void *)CONFIG_NAND_FTNANDC021_BASE; + priv->adrc = (unsigned int)chip->priv; + priv->pgsz = 1 << chip->page_shift; + priv->bksz = 1 << chip->phys_erase_shift; + + chip->priv = priv; + 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; + + chip->ecc.mode = NAND_ECC_NONE; + chip->ecc.layout = &ftnandc021_oob_2k; + + chip->options |= NAND_NO_AUTOINCR; + + ftnandc021_reset(chip); + + debug("ftnandc021: pg=%dK, bk=%dK, adrc=%d\n", + priv->pgsz >> 10, priv->bksz >> 10, priv->adrc); + + return 0; +} diff --git a/drivers/mtd/nand/ftnandc021.h b/drivers/mtd/nand/ftnandc021.h new file mode 100644 index 0000000..b8274c8 --- /dev/null +++ b/drivers/mtd/nand/ftnandc021.h @@ -0,0 +1,132 @@ +/* + * 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 lsnwr; /* LSN Write */ + uint32_t crcwr; /* LSN CRC Write */ + uint32_t lsni; /* LSN Initialize */ + 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 */ +}; + +/* bit mask */ +#define SR_BLANK BIT_MASK(7) /* blanking check failed */ +#define SR_ECC BIT_MASK(6) /* ecc failed */ +#define SR_STS BIT_MASK(4) /* status error */ +#define SR_CRC BIT_MASK(3) /* crc error */ +#define SR_CMD BIT_MASK(2) /* command finished */ +#define SR_BUSY BIT_MASK(1) /* chip busy */ +#define SR_ENA BIT_MASK(0) /* chip enabled */ + +#define ACR_CMD(x) (((x) & 0x1f) << 8) /* command code */ +#define ACR_START BIT_MASK(7) /* command start */ + +#define FCR_SWCRC BIT_MASK(8) /* CRC controlled by Software */ +#define FCR_IGNCRC BIT_MASK(7) /* Bypass/Ignore CRC checking */ +#define FCR_16BIT BIT_MASK(4) /* 16 bit data bus */ +#define FCR_WPROT BIT_MASK(3) /* write protected */ +#define FCR_NOSC BIT_MASK(2) /* bypass status check error */ +#define FCR_MICRON BIT_MASK(1) /* Micron 2-plane command */ +#define FCR_NOBC BIT_MASK(0) /* skip blanking check error */ + +#define IER_ENA BIT_MASK(7) /* interrupt enabled */ +#define IER_ECC BIT_MASK(3) /* ecc error timeout */ +#define IER_STS BIT_MASK(2) /* status error */ +#define IER_CRC BIT_MASK(1) /* crc error */ +#define IER_CMD BIT_MASK(0) /* command finished */ + +#define IOR_READY BIT_MASK(0) /* PIO ready */ + +#define SRR_ECC_ENABLED BIT_MASK(8) /* ECC enabled */ +#define SRR_NANDC_RESET BIT_MASK(2) /* NANDC reset */ +#define SRR_BMC_RESET BIT_MASK(1) /* BMC reset */ +#define SRR_ECC_RESET BIT_MASK(0) /* ECC reset */ +#define SRR_CHIP_RESET (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET) + +#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 integrated command set */ +#define FTNANDC021_CMD_RDID 0x01 /* read id */ +#define FTNANDC021_CMD_RESET 0x02 +#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 */ + +#endif diff --git a/include/faraday/nand.h b/include/faraday/nand.h new file mode 100644 index 0000000..6d8efb2 --- /dev/null +++ b/include/faraday/nand.h @@ -0,0 +1,16 @@ +/* + * 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 _FARADAY_NAND_H +#define _FARADAY_NAND_H + +int ftnandc021_probe(struct nand_chip *chip); + +#endif /* _FARADAY_NAND_H */