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