uboot/drivers/mtd/nand/nand_spl_simple.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2006-2008
   3 * Stefan Roese, DENX Software Engineering, sr@denx.de.
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <nand.h>
  10#include <asm/io.h>
  11#include <linux/mtd/nand_ecc.h>
  12
  13static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
  14static nand_info_t mtd;
  15static struct nand_chip nand_chip;
  16
  17#define ECCSTEPS        (CONFIG_SYS_NAND_PAGE_SIZE / \
  18                                        CONFIG_SYS_NAND_ECCSIZE)
  19#define ECCTOTAL        (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES)
  20
  21
  22#if (CONFIG_SYS_NAND_PAGE_SIZE <= 512)
  23/*
  24 * NAND command for small page NAND devices (512)
  25 */
  26static int nand_command(int block, int page, uint32_t offs,
  27        u8 cmd)
  28{
  29        struct nand_chip *this = mtd.priv;
  30        int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
  31
  32        while (!this->dev_ready(&mtd))
  33                ;
  34
  35        /* Begin command latch cycle */
  36        this->cmd_ctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
  37        /* Set ALE and clear CLE to start address cycle */
  38        /* Column address */
  39        this->cmd_ctrl(&mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
  40        this->cmd_ctrl(&mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */
  41        this->cmd_ctrl(&mtd, (page_addr >> 8) & 0xff,
  42                       NAND_CTRL_ALE); /* A[24:17] */
  43#ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE
  44        /* One more address cycle for devices > 32MiB */
  45        this->cmd_ctrl(&mtd, (page_addr >> 16) & 0x0f,
  46                       NAND_CTRL_ALE); /* A[28:25] */
  47#endif
  48        /* Latch in address */
  49        this->cmd_ctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
  50
  51        /*
  52         * Wait a while for the data to be ready
  53         */
  54        while (!this->dev_ready(&mtd))
  55                ;
  56
  57        return 0;
  58}
  59#else
  60/*
  61 * NAND command for large page NAND devices (2k)
  62 */
  63static int nand_command(int block, int page, uint32_t offs,
  64        u8 cmd)
  65{
  66        struct nand_chip *this = mtd.priv;
  67        int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
  68        void (*hwctrl)(struct mtd_info *mtd, int cmd,
  69                        unsigned int ctrl) = this->cmd_ctrl;
  70
  71        while (!this->dev_ready(&mtd))
  72                ;
  73
  74        /* Emulate NAND_CMD_READOOB */
  75        if (cmd == NAND_CMD_READOOB) {
  76                offs += CONFIG_SYS_NAND_PAGE_SIZE;
  77                cmd = NAND_CMD_READ0;
  78        }
  79
  80        /* Shift the offset from byte addressing to word addressing. */
  81        if (this->options & NAND_BUSWIDTH_16)
  82                offs >>= 1;
  83
  84        /* Begin command latch cycle */
  85        hwctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
  86        /* Set ALE and clear CLE to start address cycle */
  87        /* Column address */
  88        hwctrl(&mtd, offs & 0xff,
  89                       NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
  90        hwctrl(&mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */
  91        /* Row address */
  92        hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */
  93        hwctrl(&mtd, ((page_addr >> 8) & 0xff),
  94                       NAND_CTRL_ALE); /* A[27:20] */
  95#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
  96        /* One more address cycle for devices > 128MiB */
  97        hwctrl(&mtd, (page_addr >> 16) & 0x0f,
  98                       NAND_CTRL_ALE); /* A[31:28] */
  99#endif
 100        /* Latch in address */
 101        hwctrl(&mtd, NAND_CMD_READSTART,
 102                       NAND_CTRL_CLE | NAND_CTRL_CHANGE);
 103        hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
 104
 105        /*
 106         * Wait a while for the data to be ready
 107         */
 108        while (!this->dev_ready(&mtd))
 109                ;
 110
 111        return 0;
 112}
 113#endif
 114
 115static int nand_is_bad_block(int block)
 116{
 117        struct nand_chip *this = mtd.priv;
 118
 119        nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS,
 120                NAND_CMD_READOOB);
 121
 122        /*
 123         * Read one byte (or two if it's a 16 bit chip).
 124         */
 125        if (this->options & NAND_BUSWIDTH_16) {
 126                if (readw(this->IO_ADDR_R) != 0xffff)
 127                        return 1;
 128        } else {
 129                if (readb(this->IO_ADDR_R) != 0xff)
 130                        return 1;
 131        }
 132
 133        return 0;
 134}
 135
 136#if defined(CONFIG_SYS_NAND_HW_ECC_OOBFIRST)
 137static int nand_read_page(int block, int page, uchar *dst)
 138{
 139        struct nand_chip *this = mtd.priv;
 140        u_char ecc_calc[ECCTOTAL];
 141        u_char ecc_code[ECCTOTAL];
 142        u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
 143        int i;
 144        int eccsize = CONFIG_SYS_NAND_ECCSIZE;
 145        int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
 146        int eccsteps = ECCSTEPS;
 147        uint8_t *p = dst;
 148
 149        nand_command(block, page, 0, NAND_CMD_READOOB);
 150        this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
 151        nand_command(block, page, 0, NAND_CMD_READ0);
 152
 153        /* Pick the ECC bytes out of the oob data */
 154        for (i = 0; i < ECCTOTAL; i++)
 155                ecc_code[i] = oob_data[nand_ecc_pos[i]];
 156
 157
 158        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 159                this->ecc.hwctl(&mtd, NAND_ECC_READ);
 160                this->read_buf(&mtd, p, eccsize);
 161                this->ecc.calculate(&mtd, p, &ecc_calc[i]);
 162                this->ecc.correct(&mtd, p, &ecc_code[i], &ecc_calc[i]);
 163        }
 164
 165        return 0;
 166}
 167#else
 168static int nand_read_page(int block, int page, void *dst)
 169{
 170        struct nand_chip *this = mtd.priv;
 171        u_char ecc_calc[ECCTOTAL];
 172        u_char ecc_code[ECCTOTAL];
 173        u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
 174        int i;
 175        int eccsize = CONFIG_SYS_NAND_ECCSIZE;
 176        int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
 177        int eccsteps = ECCSTEPS;
 178        uint8_t *p = dst;
 179
 180        nand_command(block, page, 0, NAND_CMD_READ0);
 181
 182        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 183                if (this->ecc.mode != NAND_ECC_SOFT)
 184                        this->ecc.hwctl(&mtd, NAND_ECC_READ);
 185                this->read_buf(&mtd, p, eccsize);
 186                this->ecc.calculate(&mtd, p, &ecc_calc[i]);
 187        }
 188        this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
 189
 190        /* Pick the ECC bytes out of the oob data */
 191        for (i = 0; i < ECCTOTAL; i++)
 192                ecc_code[i] = oob_data[nand_ecc_pos[i]];
 193
 194        eccsteps = ECCSTEPS;
 195        p = dst;
 196
 197        for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 198                /* No chance to do something with the possible error message
 199                 * from correct_data(). We just hope that all possible errors
 200                 * are corrected by this routine.
 201                 */
 202                this->ecc.correct(&mtd, p, &ecc_code[i], &ecc_calc[i]);
 203        }
 204
 205        return 0;
 206}
 207#endif
 208
 209int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
 210{
 211        unsigned int block, lastblock;
 212        unsigned int page;
 213
 214        /*
 215         * offs has to be aligned to a page address!
 216         */
 217        block = offs / CONFIG_SYS_NAND_BLOCK_SIZE;
 218        lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE;
 219        page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE;
 220
 221        while (block <= lastblock) {
 222                if (!nand_is_bad_block(block)) {
 223                        /*
 224                         * Skip bad blocks
 225                         */
 226                        while (page < CONFIG_SYS_NAND_PAGE_COUNT) {
 227                                nand_read_page(block, page, dst);
 228                                dst += CONFIG_SYS_NAND_PAGE_SIZE;
 229                                page++;
 230                        }
 231
 232                        page = 0;
 233                } else {
 234                        lastblock++;
 235                }
 236
 237                block++;
 238        }
 239
 240        return 0;
 241}
 242
 243/* nand_init() - initialize data to make nand usable by SPL */
 244void nand_init(void)
 245{
 246        /*
 247         * Init board specific nand support
 248         */
 249        mtd.priv = &nand_chip;
 250        nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
 251                (void  __iomem *)CONFIG_SYS_NAND_BASE;
 252        board_nand_init(&nand_chip);
 253
 254#ifdef CONFIG_SPL_NAND_SOFTECC
 255        if (nand_chip.ecc.mode == NAND_ECC_SOFT) {
 256                nand_chip.ecc.calculate = nand_calculate_ecc;
 257                nand_chip.ecc.correct = nand_correct_data;
 258        }
 259#endif
 260
 261        if (nand_chip.select_chip)
 262                nand_chip.select_chip(&mtd, 0);
 263}
 264
 265/* Unselect after operation */
 266void nand_deselect(void)
 267{
 268        if (nand_chip.select_chip)
 269                nand_chip.select_chip(&mtd, -1);
 270}
 271