]>
Commit | Line | Data |
---|---|---|
887e2ec9 SR |
1 | /* |
2 | * (C) Copyright 2006 | |
3 | * Stefan Roese, DENX Software Engineering, [email protected]. | |
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 | */ | |
d12ae808 | 169 | ret = nand_load(&nand_info, CFG_NAND_U_BOOT_OFFS, CFG_NAND_U_BOOT_SIZE, |
887e2ec9 SR |
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 | } |