summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
authorWolfgang Denk <wd@denx.de>2010-04-01 11:28:32 +0200
committerWolfgang Denk <wd@denx.de>2010-04-01 11:28:32 +0200
commitffa37fc98d71ef930bccd4e9eed37f6ce6b4d6af (patch)
tree206908754219b5cc6e9f03518d34fb95a247bef9 /drivers/mtd
parentca6e1c136ddb720c3bb2cc043b99f7f06bc46c55 (diff)
parentfd03ea89641d6f6ade6d1a8580c1bb9f52b8542c (diff)
downloadu-boot-imx-ffa37fc98d71ef930bccd4e9eed37f6ce6b4d6af.zip
u-boot-imx-ffa37fc98d71ef930bccd4e9eed37f6ce6b4d6af.tar.gz
u-boot-imx-ffa37fc98d71ef930bccd4e9eed37f6ce6b4d6af.tar.bz2
Merge branch 'next'
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/cfi_flash.c93
-rw-r--r--drivers/mtd/nand/atmel_nand.c265
-rw-r--r--drivers/mtd/nand/atmel_nand_ecc.h36
-rw-r--r--drivers/mtd/nand/davinci_nand.c128
4 files changed, 456 insertions, 66 deletions
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index cd1a86e..d0240f5 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -605,6 +605,63 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
return retcode;
}
+static int use_flash_status_poll(flash_info_t *info)
+{
+#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL
+ if (info->vendor == CFI_CMDSET_AMD_EXTENDED ||
+ info->vendor == CFI_CMDSET_AMD_STANDARD)
+ return 1;
+#endif
+ return 0;
+}
+
+static int flash_status_poll(flash_info_t *info, void *src, void *dst,
+ ulong tout, char *prompt)
+{
+#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL
+ ulong start;
+ int ready;
+
+#if CONFIG_SYS_HZ != 1000
+ if ((ulong)CONFIG_SYS_HZ > 100000)
+ tout *= (ulong)CONFIG_SYS_HZ / 1000; /* for a big HZ, avoid overflow */
+ else
+ tout = DIV_ROUND_UP(tout * (ulong)CONFIG_SYS_HZ, 1000);
+#endif
+
+ /* Wait for command completion */
+ start = get_timer(0);
+ while (1) {
+ switch (info->portwidth) {
+ case FLASH_CFI_8BIT:
+ ready = flash_read8(dst) == flash_read8(src);
+ break;
+ case FLASH_CFI_16BIT:
+ ready = flash_read16(dst) == flash_read16(src);
+ break;
+ case FLASH_CFI_32BIT:
+ ready = flash_read32(dst) == flash_read32(src);
+ break;
+ case FLASH_CFI_64BIT:
+ ready = flash_read64(dst) == flash_read64(src);
+ break;
+ default:
+ ready = 0;
+ break;
+ }
+ if (ready)
+ break;
+ if (get_timer(start) > tout) {
+ printf("Flash %s timeout at address %lx data %lx\n",
+ prompt, (ulong)dst, (ulong)flash_read8(dst));
+ return ERR_TIMOUT;
+ }
+ udelay(1); /* also triggers watchdog */
+ }
+#endif /* CONFIG_SYS_CFI_FLASH_STATUS_POLL */
+ return ERR_OK;
+}
+
/*-----------------------------------------------------------------------
*/
static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
@@ -752,7 +809,12 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,
if (!sect_found)
sect = find_sector (info, dest);
- return flash_full_status_check (info, sect, info->write_tout, "write");
+ if (use_flash_status_poll(info))
+ return flash_status_poll(info, &cword, dstaddr,
+ info->write_tout, "write");
+ else
+ return flash_full_status_check(info, sect,
+ info->write_tout, "write");
}
#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
@@ -914,9 +976,15 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
}
flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
- retcode = flash_full_status_check (info, sector,
- info->buffer_write_tout,
- "buffer write");
+ if (use_flash_status_poll(info))
+ retcode = flash_status_poll(info, src - (1 << shift),
+ dst - (1 << shift),
+ info->buffer_write_tout,
+ "buffer write");
+ else
+ retcode = flash_full_status_check(info, sector,
+ info->buffer_write_tout,
+ "buffer write");
break;
default:
@@ -938,6 +1006,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
int rcode = 0;
int prot;
flash_sect_t sect;
+ int st;
if (info->flash_id != FLASH_MAN_CFI) {
puts ("Can't erase unknown flash type - aborted\n");
@@ -1001,10 +1070,20 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
break;
}
- if (flash_full_status_check
- (info, sect, info->erase_blk_tout, "erase")) {
+ if (use_flash_status_poll(info)) {
+ cfiword_t cword = (cfiword_t)0xffffffffffffffffULL;
+ void *dest;
+ dest = flash_map(info, sect, 0);
+ st = flash_status_poll(info, &cword, dest,
+ info->erase_blk_tout, "erase");
+ flash_unmap(info, sect, 0, dest);
+ } else
+ st = flash_full_status_check(info, sect,
+ info->erase_blk_tout,
+ "erase");
+ if (st)
rcode = 1;
- } else if (flash_verbose)
+ else if (flash_verbose)
putc ('.');
}
}
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 40002be..d5eb54a 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -31,6 +31,209 @@
#include <nand.h>
+#ifdef CONFIG_ATMEL_NAND_HWECC
+
+/* Register access macros */
+#define ecc_readl(add, reg) \
+ readl(AT91_BASE_SYS + add + ATMEL_ECC_##reg)
+#define ecc_writel(add, reg, value) \
+ writel((value), AT91_BASE_SYS + add + ATMEL_ECC_##reg)
+
+#include "atmel_nand_ecc.h" /* Hardware ECC registers */
+
+/* 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
+ */
+static struct nand_ecclayout atmel_oobinfo_large = {
+ .eccbytes = 4,
+ .eccpos = {60, 61, 62, 63},
+ .oobfree = {
+ {2, 58}
+ },
+};
+
+/* 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 struct nand_ecclayout atmel_oobinfo_small = {
+ .eccbytes = 4,
+ .eccpos = {0, 1, 2, 3},
+ .oobfree = {
+ {6, 10}
+ },
+};
+
+/*
+ * 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->priv;
+ unsigned int ecc_value;
+
+ /* get the first 2 ECC bytes */
+ ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR);
+
+ ecc_code[0] = ecc_value & 0xFF;
+ ecc_code[1] = (ecc_value >> 8) & 0xFF;
+
+ /* get the last 2 ECC bytes */
+ ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, 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
+ */
+static int atmel_nand_read_page(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int page)
+{
+ int eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint8_t *p = buf;
+ uint8_t *oob = chip->oob_poi;
+ uint8_t *ecc_pos;
+ int stat;
+
+ /* read the page */
+ chip->read_buf(mtd, p, eccsize);
+
+ /* move to ECC position if needed */
+ if (eccpos[0] != 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 eccpos[0] == 0
+ */
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+ mtd->writesize + eccpos[0], -1);
+ }
+
+ /* the ECC controller needs to read the ECC just after the data */
+ ecc_pos = oob + eccpos[0];
+ 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;
+
+ /* 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 0;
+}
+
+/*
+ * 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->priv;
+ unsigned int ecc_status, ecc_parity, ecc_mode;
+ unsigned int ecc_word, ecc_bit;
+
+ /* get the status from the Status Register */
+ ecc_status = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, 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(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_BITADDR;
+ /* get word address (12 bits) */
+ ecc_word = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, 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 */
+ printk(KERN_WARNING "atmel_nand : multiple errors detected."
+ " Unable to correct.\n");
+ return -EIO;
+ }
+
+ /* 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.
+ */
+ printk(KERN_WARNING "atmel_nand : one bit error on ECC code."
+ " Nothing to correct\n");
+ return 0;
+ }
+
+ printk(KERN_WARNING "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);
+ }
+ printk(KERN_WARNING "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)
+{
+}
+#endif
+
static void at91_nand_hwcontrol(struct mtd_info *mtd,
int cmd, unsigned int ctrl)
{
@@ -64,6 +267,11 @@ static int at91_nand_ready(struct mtd_info *mtd)
int board_nand_init(struct nand_chip *nand)
{
+#ifdef CONFIG_ATMEL_NAND_HWECC
+ static int chip_nr = 0;
+ struct mtd_info *mtd;
+#endif
+
nand->ecc.mode = NAND_ECC_SOFT;
#ifdef CONFIG_SYS_NAND_DBW_16
nand->options = NAND_BUSWIDTH_16;
@@ -74,5 +282,62 @@ int board_nand_init(struct nand_chip *nand)
#endif
nand->chip_delay = 20;
+#ifdef CONFIG_ATMEL_NAND_HWECC
+ nand->ecc.mode = NAND_ECC_HW;
+ nand->ecc.calculate = atmel_nand_calculate;
+ nand->ecc.correct = atmel_nand_correct;
+ nand->ecc.hwctl = atmel_nand_hwctl;
+ nand->ecc.read_page = atmel_nand_read_page;
+ nand->ecc.bytes = 4;
+#endif
+
+#ifdef CONFIG_ATMEL_NAND_HWECC
+ mtd = &nand_info[chip_nr++];
+ mtd->priv = nand;
+
+ /* Detect NAND chips */
+ if (nand_scan_ident(mtd, 1)) {
+ printk(KERN_WARNING "NAND Flash not found !\n");
+ return -ENXIO;
+ }
+
+ if (nand->ecc.mode == NAND_ECC_HW) {
+ /* ECC is calculated for the whole page (1 step) */
+ nand->ecc.size = mtd->writesize;
+
+ /* set ECC page size and oob layout */
+ switch (mtd->writesize) {
+ case 512:
+ nand->ecc.layout = &atmel_oobinfo_small;
+ ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_528);
+ break;
+ case 1024:
+ nand->ecc.layout = &atmel_oobinfo_large;
+ ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_1056);
+ break;
+ case 2048:
+ nand->ecc.layout = &atmel_oobinfo_large;
+ ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_2112);
+ break;
+ case 4096:
+ nand->ecc.layout = &atmel_oobinfo_large;
+ ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_4224);
+ break;
+ default:
+ /* page size not handled by HW ECC */
+ /* switching back to soft ECC */
+ nand->ecc.mode = NAND_ECC_SOFT;
+ nand->ecc.calculate = NULL;
+ nand->ecc.correct = NULL;
+ nand->ecc.hwctl = NULL;
+ nand->ecc.read_page = NULL;
+ nand->ecc.postpad = 0;
+ nand->ecc.prepad = 0;
+ nand->ecc.bytes = 0;
+ break;
+ }
+ }
+#endif
+
return 0;
}
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
new file mode 100644
index 0000000..1ee7f99
--- /dev/null
+++ b/drivers/mtd/nand/atmel_nand_ecc.h
@@ -0,0 +1,36 @@
+/*
+ * Error Corrected Code Controller (ECC) - System peripherals regsters.
+ * Based on AT91SAM9260 datasheet revision B.
+ *
+ * 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 */
+
+#endif
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index bfc2acf..4ca738e 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -57,8 +57,6 @@
#define ECC_STATE_ERR_CORR_COMP_P 0x2
#define ECC_STATE_ERR_CORR_COMP_N 0x3
-static emif_registers *const emif_regs = (void *) DAVINCI_ASYNC_EMIF_CNTRL_BASE;
-
/*
* Exploit the little endianness of the ARM to do multi-byte transfers
* per device read. This can perform over twice as quickly as individual
@@ -93,7 +91,7 @@ static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
/* copy aligned data */
while (len >= 4) {
- *(u32 *)buf = readl(nand);
+ *(u32 *)buf = __raw_readl(nand);
buf += 4;
len -= 4;
}
@@ -138,7 +136,7 @@ static void nand_davinci_write_buf(struct mtd_info *mtd, const uint8_t *buf,
/* copy aligned data */
while (len >= 4) {
- writel(*(u32 *)buf, nand);
+ __raw_writel(*(u32 *)buf, nand);
buf += 4;
len -= 4;
}
@@ -156,7 +154,8 @@ static void nand_davinci_write_buf(struct mtd_info *mtd, const uint8_t *buf,
}
}
-static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
{
struct nand_chip *this = mtd->priv;
u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W;
@@ -164,9 +163,9 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int c
if (ctrl & NAND_CTRL_CHANGE) {
IO_ADDR_W &= ~(MASK_ALE|MASK_CLE);
- if ( ctrl & NAND_CLE )
+ if (ctrl & NAND_CLE)
IO_ADDR_W |= MASK_CLE;
- if ( ctrl & NAND_ALE )
+ if (ctrl & NAND_ALE)
IO_ADDR_W |= MASK_ALE;
this->IO_ADDR_W = (void __iomem *) IO_ADDR_W;
}
@@ -181,24 +180,26 @@ static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode)
{
u_int32_t val;
- (void)readl(&(emif_regs->NANDFECC[CONFIG_SYS_NAND_CS - 2]));
+ (void)__raw_readl(&(davinci_emif_regs->nandfecc[
+ CONFIG_SYS_NAND_CS - 2]));
- val = readl(&emif_regs->NANDFCR);
+ val = __raw_readl(&davinci_emif_regs->nandfcr);
val |= DAVINCI_NANDFCR_NAND_ENABLE(CONFIG_SYS_NAND_CS);
val |= DAVINCI_NANDFCR_1BIT_ECC_START(CONFIG_SYS_NAND_CS);
- writel(val, &emif_regs->NANDFCR);
+ __raw_writel(val, &davinci_emif_regs->nandfcr);
}
static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t region)
{
u_int32_t ecc = 0;
- ecc = readl(&(emif_regs->NANDFECC[region - 1]));
+ ecc = __raw_readl(&(davinci_emif_regs->nandfecc[region - 1]));
- return(ecc);
+ return ecc;
}
-static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
{
u_int32_t tmp;
const int region = 1;
@@ -232,7 +233,8 @@ static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
return 0;
}
-static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
{
struct nand_chip *this = mtd->priv;
u_int32_t ecc_nand = read_ecc[0] | (read_ecc[1] << 8) |
@@ -268,7 +270,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *
return -1;
}
}
- return(0);
+ return 0;
}
#endif /* CONFIG_SYS_NAND_HW_ECC */
@@ -315,15 +317,15 @@ static void nand_davinci_4bit_enable_hwecc(struct mtd_info *mtd, int mode)
* Start a new ECC calculation for reading or writing 512 bytes
* of data.
*/
- val = readl(&emif_regs->NANDFCR);
+ val = __raw_readl(&davinci_emif_regs->nandfcr);
val &= ~DAVINCI_NANDFCR_4BIT_ECC_SEL_MASK;
val |= DAVINCI_NANDFCR_NAND_ENABLE(CONFIG_SYS_NAND_CS);
val |= DAVINCI_NANDFCR_4BIT_ECC_SEL(CONFIG_SYS_NAND_CS);
val |= DAVINCI_NANDFCR_4BIT_ECC_START;
- writel(val, &emif_regs->NANDFCR);
+ __raw_writel(val, &davinci_emif_regs->nandfcr);
break;
case NAND_ECC_READSYN:
- val = emif_regs->NAND4BITECC1;
+ val = __raw_readl(&davinci_emif_regs->nand4bitecc[0]);
break;
default:
break;
@@ -332,10 +334,12 @@ static void nand_davinci_4bit_enable_hwecc(struct mtd_info *mtd, int mode)
static u32 nand_davinci_4bit_readecc(struct mtd_info *mtd, unsigned int ecc[4])
{
- ecc[0] = emif_regs->NAND4BITECC1 & NAND_4BITECC_MASK;
- ecc[1] = emif_regs->NAND4BITECC2 & NAND_4BITECC_MASK;
- ecc[2] = emif_regs->NAND4BITECC3 & NAND_4BITECC_MASK;
- ecc[3] = emif_regs->NAND4BITECC4 & NAND_4BITECC_MASK;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ ecc[i] = __raw_readl(&davinci_emif_regs->nand4bitecc[i]) &
+ NAND_4BITECC_MASK;
+ }
return 0;
}
@@ -418,32 +422,36 @@ static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat,
*/
/*Take 2 bits from 8th byte and 8 bits from 9th byte */
- writel(((ecc16[4]) >> 6) & 0x3FF, &emif_regs->NAND4BITECCLOAD);
+ __raw_writel(((ecc16[4]) >> 6) & 0x3FF,
+ &davinci_emif_regs->nand4biteccload);
/* Take 4 bits from 7th byte and 6 bits from 8th byte */
- writel((((ecc16[3]) >> 12) & 0xF) | ((((ecc16[4])) << 4) & 0x3F0),
- &emif_regs->NAND4BITECCLOAD);
+ __raw_writel((((ecc16[3]) >> 12) & 0xF) | ((((ecc16[4])) << 4) & 0x3F0),
+ &davinci_emif_regs->nand4biteccload);
/* Take 6 bits from 6th byte and 4 bits from 7th byte */
- writel((ecc16[3] >> 2) & 0x3FF, &emif_regs->NAND4BITECCLOAD);
+ __raw_writel((ecc16[3] >> 2) & 0x3FF,
+ &davinci_emif_regs->nand4biteccload);
/* Take 8 bits from 5th byte and 2 bits from 6th byte */
- writel(((ecc16[2]) >> 8) | ((((ecc16[3])) << 8) & 0x300),
- &emif_regs->NAND4BITECCLOAD);
+ __raw_writel(((ecc16[2]) >> 8) | ((((ecc16[3])) << 8) & 0x300),
+ &davinci_emif_regs->nand4biteccload);
/*Take 2 bits from 3rd byte and 8 bits from 4th byte */
- writel((((ecc16[1]) >> 14) & 0x3) | ((((ecc16[2])) << 2) & 0x3FC),
- &emif_regs->NAND4BITECCLOAD);
+ __raw_writel((((ecc16[1]) >> 14) & 0x3) | ((((ecc16[2])) << 2) & 0x3FC),
+ &davinci_emif_regs->nand4biteccload);
/* Take 4 bits form 2nd bytes and 6 bits from 3rd bytes */
- writel(((ecc16[1]) >> 4) & 0x3FF, &emif_regs->NAND4BITECCLOAD);
+ __raw_writel(((ecc16[1]) >> 4) & 0x3FF,
+ &davinci_emif_regs->nand4biteccload);
/* Take 6 bits from 1st byte and 4 bits from 2nd byte */
- writel((((ecc16[0]) >> 10) & 0x3F) | (((ecc16[1]) << 6) & 0x3C0),
- &emif_regs->NAND4BITECCLOAD);
+ __raw_writel((((ecc16[0]) >> 10) & 0x3F) | (((ecc16[1]) << 6) & 0x3C0),
+ &davinci_emif_regs->nand4biteccload);
/* Take 10 bits from 0th and 1st bytes */
- writel((ecc16[0]) & 0x3FF, &emif_regs->NAND4BITECCLOAD);
+ __raw_writel((ecc16[0]) & 0x3FF,
+ &davinci_emif_regs->nand4biteccload);
/*
* Perform a dummy read to the EMIF Revision Code and Status register.
@@ -451,7 +459,7 @@ static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat,
* writing the ECC values in previous step.
*/
- val = emif_regs->NANDFSR;
+ val = __raw_readl(&davinci_emif_regs->nandfsr);
/*
* Read the syndrome from the NAND Flash 4-Bit ECC 1-4 registers.
@@ -467,13 +475,13 @@ static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat,
* Clear any previous address calculation by doing a dummy read of an
* error address register.
*/
- val = emif_regs->NANDERRADD1;
+ val = __raw_readl(&davinci_emif_regs->nanderradd1);
/*
* Set the addr_calc_st bit(bit no 13) in the NAND Flash Control
* register to 1.
*/
- emif_regs->NANDFCR |= 1 << 13;
+ __raw_writel(1 << 13, &davinci_emif_regs->nandfcr);
/*
* Wait for the corr_state field (bits 8 to 11)in the
@@ -481,12 +489,12 @@ static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat,
*/
i = NAND_TIMEOUT;
do {
- val = emif_regs->NANDFSR;
+ val = __raw_readl(&davinci_emif_regs->nandfsr);
val &= 0xc00;
i--;
} while ((i > 0) && val);
- iserror = emif_regs->NANDFSR;
+ iserror = __raw_readl(&davinci_emif_regs->nandfsr);
iserror &= EMIF_NANDFSR_ECC_STATE_MASK;
iserror = iserror >> 8;
@@ -501,32 +509,33 @@ static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat,
*/
if (iserror == ECC_STATE_NO_ERR) {
- val = emif_regs->NANDERRVAL1;
+ val = __raw_readl(&davinci_emif_regs->nanderrval1);
return 0;
} else if (iserror == ECC_STATE_TOO_MANY_ERRS) {
- val = emif_regs->NANDERRVAL1;
+ val = __raw_readl(&davinci_emif_regs->nanderrval1);
return -1;
}
- numerrors = ((emif_regs->NANDFSR >> 16) & 0x3) + 1;
+ numerrors = ((__raw_readl(&davinci_emif_regs->nandfsr) >> 16)
+ & 0x3) + 1;
/* Read the error address, error value and correct */
for (i = 0; i < numerrors; i++) {
if (i > 1) {
erroraddress =
- ((emif_regs->NANDERRADD2 >>
+ ((__raw_readl(&davinci_emif_regs->nanderradd2) >>
(16 * (i & 1))) & 0x3FF);
erroraddress = ((512 + 7) - erroraddress);
errorvalue =
- ((emif_regs->NANDERRVAL2 >>
+ ((__raw_readl(&davinci_emif_regs->nanderrval2) >>
(16 * (i & 1))) & 0xFF);
} else {
erroraddress =
- ((emif_regs->NANDERRADD1 >>
+ ((__raw_readl(&davinci_emif_regs->nanderradd1) >>
(16 * (i & 1))) & 0x3FF);
erroraddress = ((512 + 7) - erroraddress);
errorvalue =
- ((emif_regs->NANDERRVAL1 >>
+ ((__raw_readl(&davinci_emif_regs->nanderrval1) >>
(16 * (i & 1))) & 0xFF);
}
/* xor the corrupt data with error value */
@@ -540,7 +549,7 @@ static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat,
static int nand_davinci_dev_ready(struct mtd_info *mtd)
{
- return emif_regs->NANDFSR & 0x1;
+ return __raw_readl(&davinci_emif_regs->nandfsr) & 0x1;
}
static void nand_flash_init(void)
@@ -561,21 +570,22 @@ static void nand_flash_init(void)
* *
*------------------------------------------------------------------*/
acfg1 = 0
- | (0 << 31 ) /* selectStrobe */
- | (0 << 30 ) /* extWait */
- | (1 << 26 ) /* writeSetup 10 ns */
- | (3 << 20 ) /* writeStrobe 40 ns */
- | (1 << 17 ) /* writeHold 10 ns */
- | (1 << 13 ) /* readSetup 10 ns */
- | (5 << 7 ) /* readStrobe 60 ns */
- | (1 << 4 ) /* readHold 10 ns */
- | (3 << 2 ) /* turnAround ?? ns */
- | (0 << 0 ) /* asyncSize 8-bit bus */
+ | (0 << 31) /* selectStrobe */
+ | (0 << 30) /* extWait */
+ | (1 << 26) /* writeSetup 10 ns */
+ | (3 << 20) /* writeStrobe 40 ns */
+ | (1 << 17) /* writeHold 10 ns */
+ | (1 << 13) /* readSetup 10 ns */
+ | (5 << 7) /* readStrobe 60 ns */
+ | (1 << 4) /* readHold 10 ns */
+ | (3 << 2) /* turnAround ?? ns */
+ | (0 << 0) /* asyncSize 8-bit bus */
;
- emif_regs->AB1CR = acfg1; /* CS2 */
+ __raw_writel(acfg1, &davinci_emif_regs->ab1cr); /* CS2 */
- emif_regs->NANDFCR = 0x00000101; /* NAND flash on CS2 */
+ /* NAND flash on CS2 */
+ __raw_writel(0x00000101, &davinci_emif_regs->nandfcr);
#endif
}