uboot/drivers/mtd/nand/atmel_nand.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2007-2008
   3 * Stelian Pop <stelian.pop@leadtechdesign.com>
   4 * Lead Tech Design <www.leadtechdesign.com>
   5 *
   6 * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
   7 *
   8 * See file CREDITS for list of people who contributed to this
   9 * project.
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License as
  13 * published by the Free Software Foundation; either version 2 of
  14 * the License, or (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24 * MA 02111-1307 USA
  25 */
  26
  27#include <common.h>
  28#include <asm/arch/hardware.h>
  29#include <asm/arch/gpio.h>
  30#include <asm/arch/at91_pio.h>
  31
  32#include <nand.h>
  33
  34#ifdef CONFIG_ATMEL_NAND_HWECC
  35
  36/* Register access macros */
  37#define ecc_readl(add, reg)                             \
  38        readl(AT91_BASE_SYS + add + ATMEL_ECC_##reg)
  39#define ecc_writel(add, reg, value)                     \
  40        writel((value), AT91_BASE_SYS + add + ATMEL_ECC_##reg)
  41
  42#include "atmel_nand_ecc.h"     /* Hardware ECC registers */
  43
  44/* oob layout for large page size
  45 * bad block info is on bytes 0 and 1
  46 * the bytes have to be consecutives to avoid
  47 * several NAND_CMD_RNDOUT during read
  48 */
  49static struct nand_ecclayout atmel_oobinfo_large = {
  50        .eccbytes = 4,
  51        .eccpos = {60, 61, 62, 63},
  52        .oobfree = {
  53                {2, 58}
  54        },
  55};
  56
  57/* oob layout for small page size
  58 * bad block info is on bytes 4 and 5
  59 * the bytes have to be consecutives to avoid
  60 * several NAND_CMD_RNDOUT during read
  61 */
  62static struct nand_ecclayout atmel_oobinfo_small = {
  63        .eccbytes = 4,
  64        .eccpos = {0, 1, 2, 3},
  65        .oobfree = {
  66                {6, 10}
  67        },
  68};
  69
  70/*
  71 * Calculate HW ECC
  72 *
  73 * function called after a write
  74 *
  75 * mtd:        MTD block structure
  76 * dat:        raw data (unused)
  77 * ecc_code:   buffer for ECC
  78 */
  79static int atmel_nand_calculate(struct mtd_info *mtd,
  80                const u_char *dat, unsigned char *ecc_code)
  81{
  82        struct nand_chip *nand_chip = mtd->priv;
  83        unsigned int ecc_value;
  84
  85        /* get the first 2 ECC bytes */
  86        ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR);
  87
  88        ecc_code[0] = ecc_value & 0xFF;
  89        ecc_code[1] = (ecc_value >> 8) & 0xFF;
  90
  91        /* get the last 2 ECC bytes */
  92        ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, NPR) & ATMEL_ECC_NPARITY;
  93
  94        ecc_code[2] = ecc_value & 0xFF;
  95        ecc_code[3] = (ecc_value >> 8) & 0xFF;
  96
  97        return 0;
  98}
  99
 100/*
 101 * HW ECC read page function
 102 *
 103 * mtd:        mtd info structure
 104 * chip:       nand chip info structure
 105 * buf:        buffer to store read data
 106 */
 107static int atmel_nand_read_page(struct mtd_info *mtd,
 108                struct nand_chip *chip, uint8_t *buf, int page)
 109{
 110        int eccsize = chip->ecc.size;
 111        int eccbytes = chip->ecc.bytes;
 112        uint32_t *eccpos = chip->ecc.layout->eccpos;
 113        uint8_t *p = buf;
 114        uint8_t *oob = chip->oob_poi;
 115        uint8_t *ecc_pos;
 116        int stat;
 117
 118        /* read the page */
 119        chip->read_buf(mtd, p, eccsize);
 120
 121        /* move to ECC position if needed */
 122        if (eccpos[0] != 0) {
 123                /* This only works on large pages
 124                 * because the ECC controller waits for
 125                 * NAND_CMD_RNDOUTSTART after the
 126                 * NAND_CMD_RNDOUT.
 127                 * anyway, for small pages, the eccpos[0] == 0
 128                 */
 129                chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
 130                                mtd->writesize + eccpos[0], -1);
 131        }
 132
 133        /* the ECC controller needs to read the ECC just after the data */
 134        ecc_pos = oob + eccpos[0];
 135        chip->read_buf(mtd, ecc_pos, eccbytes);
 136
 137        /* check if there's an error */
 138        stat = chip->ecc.correct(mtd, p, oob, NULL);
 139
 140        if (stat < 0)
 141                mtd->ecc_stats.failed++;
 142        else
 143                mtd->ecc_stats.corrected += stat;
 144
 145        /* get back to oob start (end of page) */
 146        chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
 147
 148        /* read the oob */
 149        chip->read_buf(mtd, oob, mtd->oobsize);
 150
 151        return 0;
 152}
 153
 154/*
 155 * HW ECC Correction
 156 *
 157 * function called after a read
 158 *
 159 * mtd:        MTD block structure
 160 * dat:        raw data read from the chip
 161 * read_ecc:   ECC from the chip (unused)
 162 * isnull:     unused
 163 *
 164 * Detect and correct a 1 bit error for a page
 165 */
 166static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
 167                u_char *read_ecc, u_char *isnull)
 168{
 169        struct nand_chip *nand_chip = mtd->priv;
 170        unsigned int ecc_status, ecc_parity, ecc_mode;
 171        unsigned int ecc_word, ecc_bit;
 172
 173        /* get the status from the Status Register */
 174        ecc_status = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, SR);
 175
 176        /* if there's no error */
 177        if (likely(!(ecc_status & ATMEL_ECC_RECERR)))
 178                return 0;
 179
 180        /* get error bit offset (4 bits) */
 181        ecc_bit = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_BITADDR;
 182        /* get word address (12 bits) */
 183        ecc_word = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_WORDADDR;
 184        ecc_word >>= 4;
 185
 186        /* if there are multiple errors */
 187        if (ecc_status & ATMEL_ECC_MULERR) {
 188                /* check if it is a freshly erased block
 189                 * (filled with 0xff) */
 190                if ((ecc_bit == ATMEL_ECC_BITADDR)
 191                                && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) {
 192                        /* the block has just been erased, return OK */
 193                        return 0;
 194                }
 195                /* it doesn't seems to be a freshly
 196                 * erased block.
 197                 * We can't correct so many errors */
 198                printk(KERN_WARNING "atmel_nand : multiple errors detected."
 199                                " Unable to correct.\n");
 200                return -EIO;
 201        }
 202
 203        /* if there's a single bit error : we can correct it */
 204        if (ecc_status & ATMEL_ECC_ECCERR) {
 205                /* there's nothing much to do here.
 206                 * the bit error is on the ECC itself.
 207                 */
 208                printk(KERN_WARNING "atmel_nand : one bit error on ECC code."
 209                                " Nothing to correct\n");
 210                return 0;
 211        }
 212
 213        printk(KERN_WARNING "atmel_nand : one bit error on data."
 214                        " (word offset in the page :"
 215                        " 0x%x bit offset : 0x%x)\n",
 216                        ecc_word, ecc_bit);
 217        /* correct the error */
 218        if (nand_chip->options & NAND_BUSWIDTH_16) {
 219                /* 16 bits words */
 220                ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit);
 221        } else {
 222                /* 8 bits words */
 223                dat[ecc_word] ^= (1 << ecc_bit);
 224        }
 225        printk(KERN_WARNING "atmel_nand : error corrected\n");
 226        return 1;
 227}
 228
 229/*
 230 * Enable HW ECC : unused on most chips
 231 */
 232static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 233{
 234}
 235#endif
 236
 237static void at91_nand_hwcontrol(struct mtd_info *mtd,
 238                                         int cmd, unsigned int ctrl)
 239{
 240        struct nand_chip *this = mtd->priv;
 241
 242        if (ctrl & NAND_CTRL_CHANGE) {
 243                ulong IO_ADDR_W = (ulong) this->IO_ADDR_W;
 244                IO_ADDR_W &= ~(CONFIG_SYS_NAND_MASK_ALE
 245                             | CONFIG_SYS_NAND_MASK_CLE);
 246
 247                if (ctrl & NAND_CLE)
 248                        IO_ADDR_W |= CONFIG_SYS_NAND_MASK_CLE;
 249                if (ctrl & NAND_ALE)
 250                        IO_ADDR_W |= CONFIG_SYS_NAND_MASK_ALE;
 251
 252#ifdef CONFIG_SYS_NAND_ENABLE_PIN
 253                at91_set_gpio_value(CONFIG_SYS_NAND_ENABLE_PIN,
 254                                    !(ctrl & NAND_NCE));
 255#endif
 256                this->IO_ADDR_W = (void *) IO_ADDR_W;
 257        }
 258
 259        if (cmd != NAND_CMD_NONE)
 260                writeb(cmd, this->IO_ADDR_W);
 261}
 262
 263#ifdef CONFIG_SYS_NAND_READY_PIN
 264static int at91_nand_ready(struct mtd_info *mtd)
 265{
 266        return at91_get_gpio_value(CONFIG_SYS_NAND_READY_PIN);
 267}
 268#endif
 269
 270int board_nand_init(struct nand_chip *nand)
 271{
 272#ifdef CONFIG_ATMEL_NAND_HWECC
 273        static int chip_nr = 0;
 274        struct mtd_info *mtd;
 275#endif
 276
 277        nand->ecc.mode = NAND_ECC_SOFT;
 278#ifdef CONFIG_SYS_NAND_DBW_16
 279        nand->options = NAND_BUSWIDTH_16;
 280#endif
 281        nand->cmd_ctrl = at91_nand_hwcontrol;
 282#ifdef CONFIG_SYS_NAND_READY_PIN
 283        nand->dev_ready = at91_nand_ready;
 284#endif
 285        nand->chip_delay = 20;
 286
 287#ifdef CONFIG_ATMEL_NAND_HWECC
 288        nand->ecc.mode = NAND_ECC_HW;
 289        nand->ecc.calculate = atmel_nand_calculate;
 290        nand->ecc.correct = atmel_nand_correct;
 291        nand->ecc.hwctl = atmel_nand_hwctl;
 292        nand->ecc.read_page = atmel_nand_read_page;
 293        nand->ecc.bytes = 4;
 294#endif
 295
 296#ifdef CONFIG_ATMEL_NAND_HWECC
 297        mtd = &nand_info[chip_nr++];
 298        mtd->priv = nand;
 299
 300        /* Detect NAND chips */
 301        if (nand_scan_ident(mtd, 1, NULL)) {
 302                printk(KERN_WARNING "NAND Flash not found !\n");
 303                return -ENXIO;
 304        }
 305
 306        if (nand->ecc.mode == NAND_ECC_HW) {
 307                /* ECC is calculated for the whole page (1 step) */
 308                nand->ecc.size = mtd->writesize;
 309
 310                /* set ECC page size and oob layout */
 311                switch (mtd->writesize) {
 312                case 512:
 313                        nand->ecc.layout = &atmel_oobinfo_small;
 314                        ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_528);
 315                        break;
 316                case 1024:
 317                        nand->ecc.layout = &atmel_oobinfo_large;
 318                        ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_1056);
 319                        break;
 320                case 2048:
 321                        nand->ecc.layout = &atmel_oobinfo_large;
 322                        ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_2112);
 323                        break;
 324                case 4096:
 325                        nand->ecc.layout = &atmel_oobinfo_large;
 326                        ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_4224);
 327                        break;
 328                default:
 329                        /* page size not handled by HW ECC */
 330                        /* switching back to soft ECC */
 331                        nand->ecc.mode = NAND_ECC_SOFT;
 332                        nand->ecc.calculate = NULL;
 333                        nand->ecc.correct = NULL;
 334                        nand->ecc.hwctl = NULL;
 335                        nand->ecc.read_page = NULL;
 336                        nand->ecc.postpad = 0;
 337                        nand->ecc.prepad = 0;
 338                        nand->ecc.bytes = 0;
 339                        break;
 340                }
 341        }
 342#endif
 343
 344        return 0;
 345}
 346