blob: 840a59659674f442829c2038770b6293e559ea4a [file] [log] [blame]
Stefan Roese42fbddd2006-09-07 11:51:23 +02001/*
Stefan Roese39013542007-06-01 15:23:04 +02002 * (C) Copyright 2006-2007
Stefan Roese42fbddd2006-09-07 11:51:23 +02003 * Stefan Roese, DENX Software Engineering, sr@denx.de.
4 *
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.
9 *
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.
14 *
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
19 */
20
21#include <common.h>
22#include <nand.h>
23
24#define CFG_NAND_READ_DELAY \
25 { volatile int dummy; int i; for (i=0; i<10000; i++) dummy = i; }
26
Stefan Roese39013542007-06-01 15:23:04 +020027static int nand_ecc_pos[] = CFG_NAND_ECCPOS;
28
Stefan Roese42fbddd2006-09-07 11:51:23 +020029extern void board_nand_init(struct nand_chip *nand);
Stefan Roese42fbddd2006-09-07 11:51:23 +020030
Stefan Roese39013542007-06-01 15:23:04 +020031static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 cmd)
Stefan Roese42fbddd2006-09-07 11:51:23 +020032{
Wolfgang Denk4df0da52006-10-09 00:42:01 +020033 struct nand_chip *this = mtd->priv;
Stefan Roese39013542007-06-01 15:23:04 +020034 int page_addr = page + block * CFG_NAND_PAGE_COUNT;
35
36 if (this->dev_ready)
37 this->dev_ready(mtd);
38 else
39 CFG_NAND_READ_DELAY;
Stefan Roese42fbddd2006-09-07 11:51:23 +020040
41 /* Begin command latch cycle */
42 this->hwcontrol(mtd, NAND_CTL_SETCLE);
Stefan Roese39013542007-06-01 15:23:04 +020043 this->write_byte(mtd, cmd);
Stefan Roese42fbddd2006-09-07 11:51:23 +020044 /* 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 */
Stefan Roese39013542007-06-01 15:23:04 +020048 this->write_byte(mtd, offs); /* A[7:0] */
Stefan Roese42fbddd2006-09-07 11:51:23 +020049 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);
57
58 /*
59 * Wait a while for the data to be ready
60 */
61 if (this->dev_ready)
62 this->dev_ready(mtd);
63 else
64 CFG_NAND_READ_DELAY;
65
Stefan Roese39013542007-06-01 15:23:04 +020066 return 0;
67}
68
69static int nand_is_bad_block(struct mtd_info *mtd, int block)
70{
71 struct nand_chip *this = mtd->priv;
72
73 nand_command(mtd, block, 0, CFG_NAND_BAD_BLOCK_POS, NAND_CMD_READOOB);
74
Stefan Roese42fbddd2006-09-07 11:51:23 +020075 /*
76 * Read on byte
77 */
78 if (this->read_byte(mtd) != 0xff)
79 return 1;
80
81 return 0;
82}
83
84static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
85{
Wolfgang Denk4df0da52006-10-09 00:42:01 +020086 struct nand_chip *this = mtd->priv;
Stefan Roese39013542007-06-01 15:23:04 +020087 u_char *ecc_calc;
88 u_char *ecc_code;
89 u_char *oob_data;
Stefan Roese42fbddd2006-09-07 11:51:23 +020090 int i;
Stefan Roese39013542007-06-01 15:23:04 +020091 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;
Stefan Roese42fbddd2006-09-07 11:51:23 +020096
Stefan Roese39013542007-06-01 15:23:04 +020097 nand_command(mtd, block, page, 0, NAND_CMD_READ0);
Stefan Roese42fbddd2006-09-07 11:51:23 +020098
Stefan Roese39013542007-06-01 15:23:04 +020099 /* No malloc available for now, just use some temporary locations
100 * in SDRAM
Stefan Roese42fbddd2006-09-07 11:51:23 +0200101 */
Stefan Roese39013542007-06-01 15:23:04 +0200102 ecc_calc = (u_char *)(CFG_SDRAM_BASE + 0x10000);
103 ecc_code = ecc_calc + 0x100;
104 oob_data = ecc_calc + 0x200;
Stefan Roese42fbddd2006-09-07 11:51:23 +0200105
Stefan Roese39013542007-06-01 15:23:04 +0200106 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]);
110 }
111 this->read_buf(mtd, oob_data, CFG_NAND_OOBSIZE);
112
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]];
116
117 eccsteps = CFG_NAND_ECCSTEPS;
118 p = dst;
119
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.
124 */
125 stat = this->correct_data(mtd, p, &ecc_code[i], &ecc_calc[i]);
126 }
Stefan Roese42fbddd2006-09-07 11:51:23 +0200127
128 return 0;
129}
130
131static int nand_load(struct mtd_info *mtd, int offs, int uboot_size, uchar *dst)
132{
133 int block;
134 int blockcopy_count;
135 int page;
136
137 /*
138 * offs has to be aligned to a block address!
139 */
140 block = offs / CFG_NAND_BLOCK_SIZE;
141 blockcopy_count = 0;
142
143 while (blockcopy_count < (uboot_size / CFG_NAND_BLOCK_SIZE)) {
144 if (!nand_is_bad_block(mtd, block)) {
145 /*
146 * Skip bad blocks
147 */
148 for (page = 0; page < CFG_NAND_PAGE_COUNT; page++) {
149 nand_read_page(mtd, block, page, dst);
150 dst += CFG_NAND_PAGE_SIZE;
151 }
152
153 blockcopy_count++;
154 }
155
156 block++;
157 }
158
159 return 0;
160}
161
162void nand_boot(void)
163{
164 ulong mem_size;
165 struct nand_chip nand_chip;
166 nand_info_t nand_info;
167 int ret;
168 void (*uboot)(void);
169
170 /*
171 * Init sdram, so we have access to memory
172 */
173 mem_size = initdram(0);
174
175 /*
176 * Init board specific nand support
177 */
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);
182
183 /*
184 * Load U-Boot image from NAND into RAM
185 */
Stefan Roesebbfcbb72006-09-12 20:19:10 +0200186 ret = nand_load(&nand_info, CFG_NAND_U_BOOT_OFFS, CFG_NAND_U_BOOT_SIZE,
Stefan Roese42fbddd2006-09-07 11:51:23 +0200187 (uchar *)CFG_NAND_U_BOOT_DST);
188
189 /*
190 * Jump to U-Boot image
191 */
192 uboot = (void (*)(void))CFG_NAND_U_BOOT_START;
193 (*uboot)();
194}