]> git.sur5r.net Git - u-boot/blob - nand_spl/nand_boot.c
[PATCH] Update AMCC Luan 440SP eval board support
[u-boot] / nand_spl / nand_boot.c
1 /*
2  * (C) Copyright 2006
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 extern void board_nand_init(struct nand_chip *nand);
28 extern void ndfc_hwcontrol(struct mtd_info *mtdinfo, int cmd);
29 extern void ndfc_write_byte(struct mtd_info *mtdinfo, u_char byte);
30 extern u_char ndfc_read_byte(struct mtd_info *mtdinfo);
31 extern int ndfc_dev_ready(struct mtd_info *mtdinfo);
32 extern int jump_to_ram(ulong delta);
33 extern int jump_to_uboot(ulong addr);
34
35 static int nand_is_bad_block(struct mtd_info *mtd, int block)
36 {
37         struct nand_chip *this = mtd->priv;
38         int page_addr = block * CFG_NAND_PAGE_COUNT;
39
40         /* Begin command latch cycle */
41         this->hwcontrol(mtd, NAND_CTL_SETCLE);
42         this->write_byte(mtd, NAND_CMD_READOOB);
43         /* Set ALE and clear CLE to start address cycle */
44         this->hwcontrol(mtd, NAND_CTL_CLRCLE);
45         this->hwcontrol(mtd, NAND_CTL_SETALE);
46         /* Column address */
47         this->write_byte(mtd, CFG_NAND_BAD_BLOCK_POS);                  /* A[7:0] */
48         this->write_byte(mtd, (uchar)(page_addr & 0xff));               /* A[16:9] */
49         this->write_byte(mtd, (uchar)((page_addr >> 8) & 0xff));        /* A[24:17] */
50 #ifdef CFG_NAND_4_ADDR_CYCLE
51         /* One more address cycle for devices > 32MiB */
52         this->write_byte(mtd, (uchar)((page_addr >> 16) & 0x0f));       /* A[xx:25] */
53 #endif
54         /* Latch in address */
55         this->hwcontrol(mtd, NAND_CTL_CLRALE);
56
57         /*
58          * Wait a while for the data to be ready
59          */
60         if (this->dev_ready)
61                 this->dev_ready(mtd);
62         else
63                 CFG_NAND_READ_DELAY;
64
65         /*
66          * Read on byte
67          */
68         if (this->read_byte(mtd) != 0xff)
69                 return 1;
70
71         return 0;
72 }
73
74 static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
75 {
76         struct nand_chip *this = mtd->priv;
77         int page_addr = page + block * CFG_NAND_PAGE_COUNT;
78         int i;
79
80         /* Begin command latch cycle */
81         this->hwcontrol(mtd, NAND_CTL_SETCLE);
82         this->write_byte(mtd, NAND_CMD_READ0);
83         /* Set ALE and clear CLE to start address cycle */
84         this->hwcontrol(mtd, NAND_CTL_CLRCLE);
85         this->hwcontrol(mtd, NAND_CTL_SETALE);
86         /* Column address */
87         this->write_byte(mtd, 0);                                       /* A[7:0] */
88         this->write_byte(mtd, (uchar)(page_addr & 0xff));               /* A[16:9] */
89         this->write_byte(mtd, (uchar)((page_addr >> 8) & 0xff));        /* A[24:17] */
90 #ifdef CFG_NAND_4_ADDR_CYCLE
91         /* One more address cycle for devices > 32MiB */
92         this->write_byte(mtd, (uchar)((page_addr >> 16) & 0x0f));       /* A[xx:25] */
93 #endif
94         /* Latch in address */
95         this->hwcontrol(mtd, NAND_CTL_CLRALE);
96
97         /*
98          * Wait a while for the data to be ready
99          */
100         if (this->dev_ready)
101                 this->dev_ready(mtd);
102         else
103                 CFG_NAND_READ_DELAY;
104
105         /*
106          * Read page into buffer
107          */
108         for (i=0; i<CFG_NAND_PAGE_SIZE; i++)
109                 *dst++ = this->read_byte(mtd);
110
111         return 0;
112 }
113
114 static int nand_load(struct mtd_info *mtd, int offs, int uboot_size, uchar *dst)
115 {
116         int block;
117         int blockcopy_count;
118         int page;
119
120         /*
121          * offs has to be aligned to a block address!
122          */
123         block = offs / CFG_NAND_BLOCK_SIZE;
124         blockcopy_count = 0;
125
126         while (blockcopy_count < (uboot_size / CFG_NAND_BLOCK_SIZE)) {
127                 if (!nand_is_bad_block(mtd, block)) {
128                         /*
129                          * Skip bad blocks
130                          */
131                         for (page = 0; page < CFG_NAND_PAGE_COUNT; page++) {
132                                 nand_read_page(mtd, block, page, dst);
133                                 dst += CFG_NAND_PAGE_SIZE;
134                         }
135
136                         blockcopy_count++;
137                 }
138
139                 block++;
140         }
141
142         return 0;
143 }
144
145 void nand_boot(void)
146 {
147         ulong mem_size;
148         struct nand_chip nand_chip;
149         nand_info_t nand_info;
150         int ret;
151         void (*uboot)(void);
152
153         /*
154          * Init sdram, so we have access to memory
155          */
156         mem_size = initdram(0);
157
158         /*
159          * Init board specific nand support
160          */
161         nand_info.priv = &nand_chip;
162         nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = (void  __iomem *)CFG_NAND_BASE;
163         nand_chip.dev_ready = NULL;     /* preset to NULL */
164         board_nand_init(&nand_chip);
165
166         /*
167          * Load U-Boot image from NAND into RAM
168          */
169         ret = nand_load(&nand_info, CFG_NAND_U_BOOT_OFFS, CFG_NAND_U_BOOT_SIZE,
170                         (uchar *)CFG_NAND_U_BOOT_DST);
171
172         /*
173          * Jump to U-Boot image
174          */
175         uboot = (void (*)(void))CFG_NAND_U_BOOT_START;
176         (*uboot)();
177 }