add SDHC support in mmc driver
[u-boot-openmoko/mini2440.git] / nand_spl / nand_boot.c
blobe2147cb909b28bcd3e480122eac1867e4a5c05be
1 /*
2 * (C) Copyright 2006-2007
3 * Stefan Roese, DENX Software Engineering, sr@denx.de.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18 * MA 02111-1307 USA
21 #include <common.h>
22 #include <nand.h>
24 #define CFG_NAND_READ_DELAY \
25 { volatile int dummy; int i; for (i=0; i<10000; i++) dummy = i; }
27 static int nand_ecc_pos[] = CFG_NAND_ECCPOS;
29 extern void board_nand_init(struct nand_chip *nand);
31 static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 cmd)
33 struct nand_chip *this = mtd->priv;
34 int page_addr = page + block * CFG_NAND_PAGE_COUNT;
36 if (this->dev_ready)
37 this->dev_ready(mtd);
38 else
39 CFG_NAND_READ_DELAY;
41 /* Begin command latch cycle */
42 this->hwcontrol(mtd, NAND_CTL_SETCLE);
43 this->write_byte(mtd, cmd);
44 /* Set ALE and clear CLE to start address cycle */
45 this->hwcontrol(mtd, NAND_CTL_CLRCLE);
46 this->hwcontrol(mtd, NAND_CTL_SETALE);
47 /* Column address */
48 this->write_byte(mtd, offs); /* A[7:0] */
49 this->write_byte(mtd, (uchar)(page_addr & 0xff)); /* A[16:9] */
50 this->write_byte(mtd, (uchar)((page_addr >> 8) & 0xff)); /* A[24:17] */
51 #ifdef CFG_NAND_4_ADDR_CYCLE
52 /* One more address cycle for devices > 32MiB */
53 this->write_byte(mtd, (uchar)((page_addr >> 16) & 0x0f)); /* A[xx:25] */
54 #endif
55 /* Latch in address */
56 this->hwcontrol(mtd, NAND_CTL_CLRALE);
59 * Wait a while for the data to be ready
61 if (this->dev_ready)
62 this->dev_ready(mtd);
63 else
64 CFG_NAND_READ_DELAY;
66 return 0;
69 static int nand_is_bad_block(struct mtd_info *mtd, int block)
71 struct nand_chip *this = mtd->priv;
73 nand_command(mtd, block, 0, CFG_NAND_BAD_BLOCK_POS, NAND_CMD_READOOB);
76 * Read one byte
78 if (this->read_byte(mtd) != 0xff)
79 return 1;
81 return 0;
84 static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
86 struct nand_chip *this = mtd->priv;
87 u_char *ecc_calc;
88 u_char *ecc_code;
89 u_char *oob_data;
90 int i;
91 int eccsize = CFG_NAND_ECCSIZE;
92 int eccbytes = CFG_NAND_ECCBYTES;
93 int eccsteps = CFG_NAND_ECCSTEPS;
94 uint8_t *p = dst;
95 int stat;
97 nand_command(mtd, block, page, 0, NAND_CMD_READ0);
99 /* No malloc available for now, just use some temporary locations
100 * in SDRAM
102 ecc_calc = (u_char *)(CFG_SDRAM_BASE + 0x10000);
103 ecc_code = ecc_calc + 0x100;
104 oob_data = ecc_calc + 0x200;
106 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
107 this->enable_hwecc(mtd, NAND_ECC_READ);
108 this->read_buf(mtd, p, eccsize);
109 this->calculate_ecc(mtd, p, &ecc_calc[i]);
111 this->read_buf(mtd, oob_data, CFG_NAND_OOBSIZE);
113 /* Pick the ECC bytes out of the oob data */
114 for (i = 0; i < CFG_NAND_ECCTOTAL; i++)
115 ecc_code[i] = oob_data[nand_ecc_pos[i]];
117 eccsteps = CFG_NAND_ECCSTEPS;
118 p = dst;
120 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
121 /* No chance to do something with the possible error message
122 * from correct_data(). We just hope that all possible errors
123 * are corrected by this routine.
125 stat = this->correct_data(mtd, p, &ecc_code[i], &ecc_calc[i]);
128 return 0;
131 static int nand_load(struct mtd_info *mtd, int offs, int uboot_size, uchar *dst)
133 int block;
134 int blockcopy_count;
135 int page;
138 * offs has to be aligned to a block address!
140 block = offs / CFG_NAND_BLOCK_SIZE;
141 blockcopy_count = 0;
143 while (blockcopy_count < (uboot_size / CFG_NAND_BLOCK_SIZE)) {
144 if (!nand_is_bad_block(mtd, block)) {
146 * Skip bad blocks
148 for (page = 0; page < CFG_NAND_PAGE_COUNT; page++) {
149 nand_read_page(mtd, block, page, dst);
150 dst += CFG_NAND_PAGE_SIZE;
153 blockcopy_count++;
156 block++;
159 return 0;
162 void nand_boot(void)
164 ulong mem_size;
165 struct nand_chip nand_chip;
166 nand_info_t nand_info;
167 int ret;
168 void (*uboot)(void);
171 * Init sdram, so we have access to memory
173 mem_size = initdram(0);
176 * Init board specific nand support
178 nand_info.priv = &nand_chip;
179 nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = (void __iomem *)CFG_NAND_BASE;
180 nand_chip.dev_ready = NULL; /* preset to NULL */
181 board_nand_init(&nand_chip);
184 * Load U-Boot image from NAND into RAM
186 ret = nand_load(&nand_info, CFG_NAND_U_BOOT_OFFS, CFG_NAND_U_BOOT_SIZE,
187 (uchar *)CFG_NAND_U_BOOT_DST);
190 * Jump to U-Boot image
192 uboot = (void (*)(void))CFG_NAND_U_BOOT_START;
193 (*uboot)();