]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - nand_spl/nand_boot.c
Merge with /home/wd/git/u-boot/custodian/u-boot-mpc86xx
[karo-tx-uboot.git] / nand_spl / nand_boot.c
1 /*
2  * (C) Copyright 2006-2007
3  * 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
27 static int nand_ecc_pos[] = CFG_NAND_ECCPOS;
28
29 extern void board_nand_init(struct nand_chip *nand);
30
31 static int nand_command(struct mtd_info *mtd, int block, int page, int offs, u8 cmd)
32 {
33         struct nand_chip *this = mtd->priv;
34         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;
40
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);
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
66         return 0;
67 }
68
69 static 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
75         /*
76          * Read on byte
77          */
78         if (this->read_byte(mtd) != 0xff)
79                 return 1;
80
81         return 0;
82 }
83
84 static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
85 {
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;
96
97         nand_command(mtd, block, page, 0, NAND_CMD_READ0);
98
99         /* No malloc available for now, just use some temporary locations
100          * in SDRAM
101          */
102         ecc_calc = (u_char *)(CFG_SDRAM_BASE + 0x10000);
103         ecc_code = ecc_calc + 0x100;
104         oob_data = ecc_calc + 0x200;
105
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]);
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         }
127
128         return 0;
129 }
130
131 static 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
162 void 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          */
186         ret = nand_load(&nand_info, CFG_NAND_U_BOOT_OFFS, CFG_NAND_U_BOOT_SIZE,
187                         (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 }