]>
Commit | Line | Data |
---|---|---|
3e38691e WD |
1 | /* |
2 | * Copyright (C) 2003 ETC s.r.o. | |
3 | * | |
4 | * This code was inspired by Marius Groeger and Kyle Harris code | |
5 | * available in other board ports for U-Boot | |
6 | * | |
7 | * See file CREDITS for list of people who contributed to this | |
8 | * project. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public License as | |
12 | * published by the Free Software Foundation; either version 2 of | |
13 | * the License, or (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | * MA 02111-1307 USA | |
24 | * | |
25 | * Written by Peter Figuli <[email protected]>, 2003. | |
26 | * | |
27 | */ | |
28 | ||
29 | #include <common.h> | |
30 | #include "intel.h" | |
31 | ||
32 | ||
33 | /* | |
34 | * This code should handle CFI FLASH memory device. This code is very | |
35 | * minimalistic approach without many essential error handling code as well. | |
36 | * Because U-Boot actually is missing smart handling of FLASH device, | |
37 | * we just set flash_id to anything else to FLASH_UNKNOW, so common code | |
38 | * can call us without any restrictions. | |
39 | * TODO: Add CFI Query, to be able to determine FLASH device. | |
40 | * TODO: Add error handling code | |
41 | * NOTE: This code was tested with BUS_WIDTH 4 and ITERLEAVE 2 only, but | |
42 | * hopefully may work with other configurations. | |
43 | */ | |
44 | ||
45 | #if ( WEP_FLASH_BUS_WIDTH == 1 ) | |
46 | # define FLASH_BUS vu_char | |
8412d814 | 47 | # define FLASH_BUS_RET u_char |
3e38691e WD |
48 | # if ( WEP_FLASH_INTERLEAVE == 1 ) |
49 | # define FLASH_CMD( x ) x | |
50 | # else | |
51 | # error "With 8bit bus only one chip is allowed" | |
52 | # endif | |
53 | ||
54 | ||
55 | #elif ( WEP_FLASH_BUS_WIDTH == 2 ) | |
56 | # define FLASH_BUS vu_short | |
8412d814 | 57 | # define FLASH_BUS_RET u_short |
3e38691e WD |
58 | # if ( WEP_FLASH_INTERLEAVE == 1 ) |
59 | # define FLASH_CMD( x ) x | |
60 | # elif ( WEP_FLASH_INTERLEAVE == 2 ) | |
61 | # define FLASH_CMD( x ) (( x << 8 )| x ) | |
62 | # else | |
63 | # error "With 16bit bus only 1 or 2 chip(s) are allowed" | |
64 | # endif | |
65 | ||
66 | ||
67 | #elif ( WEP_FLASH_BUS_WIDTH == 4 ) | |
68 | # define FLASH_BUS vu_long | |
8412d814 | 69 | # define FLASH_BUS_RET u_long |
3e38691e WD |
70 | # if ( WEP_FLASH_INTERLEAVE == 1 ) |
71 | # define FLASH_CMD( x ) x | |
72 | # elif ( WEP_FLASH_INTERLEAVE == 2 ) | |
73 | # define FLASH_CMD( x ) (( x << 16 )| x ) | |
74 | # elif ( WEP_FLASH_INTERLEAVE == 4 ) | |
75 | # define FLASH_CMD( x ) (( x << 24 )|( x << 16 ) ( x << 8 )| x ) | |
76 | # else | |
77 | # error "With 32bit bus only 1,2 or 4 chip(s) are allowed" | |
78 | # endif | |
79 | ||
80 | #else | |
81 | # error "Flash bus width might be 1,2,4 for 8,16,32 bit configuration" | |
82 | #endif | |
83 | ||
84 | ||
6d0f6bcf | 85 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; |
3e38691e | 86 | |
8412d814 | 87 | static FLASH_BUS_RET flash_status_reg (void) |
3e38691e WD |
88 | { |
89 | ||
90 | FLASH_BUS *addr = (FLASH_BUS *) 0; | |
91 | ||
92 | *addr = FLASH_CMD (CFI_INTEL_CMD_READ_STATUS_REGISTER); | |
93 | ||
94 | return *addr; | |
95 | } | |
96 | ||
97 | static int flash_ready (ulong timeout) | |
98 | { | |
99 | int ok = 1; | |
100 | ||
101 | reset_timer_masked (); | |
102 | while ((flash_status_reg () & FLASH_CMD (CFI_INTEL_SR_READY)) != | |
103 | FLASH_CMD (CFI_INTEL_SR_READY)) { | |
104 | if (get_timer_masked () > timeout && timeout != 0) { | |
105 | ok = 0; | |
106 | break; | |
107 | } | |
108 | } | |
109 | return ok; | |
110 | } | |
111 | ||
6d0f6bcf | 112 | #if ( CONFIG_SYS_MAX_FLASH_BANKS != 1 ) |
3e38691e WD |
113 | # error "WEP platform has only one flash bank!" |
114 | #endif | |
115 | ||
116 | ||
117 | ulong flash_init (void) | |
118 | { | |
119 | int i; | |
120 | FLASH_BUS address = WEP_FLASH_BASE; | |
121 | ||
122 | flash_info[0].size = WEP_FLASH_BANK_SIZE; | |
6d0f6bcf | 123 | flash_info[0].sector_count = CONFIG_SYS_MAX_FLASH_SECT; |
3e38691e | 124 | flash_info[0].flash_id = INTEL_MANUFACT; |
6d0f6bcf | 125 | memset (flash_info[0].protect, 0, CONFIG_SYS_MAX_FLASH_SECT); |
3e38691e | 126 | |
6d0f6bcf | 127 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_SECT; i++) { |
3e38691e WD |
128 | flash_info[0].start[i] = address; |
129 | #ifdef WEP_FLASH_UNLOCK | |
130 | /* Some devices are hw locked after start. */ | |
131 | *((FLASH_BUS *) address) = FLASH_CMD (CFI_INTEL_CMD_LOCK_SETUP); | |
132 | *((FLASH_BUS *) address) = FLASH_CMD (CFI_INTEL_CMD_UNLOCK_BLOCK); | |
133 | flash_ready (0); | |
134 | *((FLASH_BUS *) address) = FLASH_CMD (CFI_INTEL_CMD_READ_ARRAY); | |
135 | #endif | |
136 | address += WEP_FLASH_SECT_SIZE; | |
137 | } | |
138 | ||
139 | flash_protect (FLAG_PROTECT_SET, | |
6d0f6bcf JCPV |
140 | CONFIG_SYS_FLASH_BASE, |
141 | CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1, | |
3e38691e WD |
142 | &flash_info[0]); |
143 | ||
144 | flash_protect (FLAG_PROTECT_SET, | |
0e8d1586 JCPV |
145 | CONFIG_ENV_ADDR, |
146 | CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]); | |
3e38691e WD |
147 | |
148 | return WEP_FLASH_BANK_SIZE; | |
149 | } | |
150 | ||
151 | void flash_print_info (flash_info_t * info) | |
152 | { | |
153 | int i; | |
154 | ||
155 | printf (" Intel vendor\n"); | |
156 | printf (" Size: %ld MB in %d Sectors\n", | |
157 | info->size >> 20, info->sector_count); | |
158 | ||
159 | printf (" Sector Start Addresses:"); | |
160 | for (i = 0; i < info->sector_count; i++) { | |
161 | if (!(i % 5)) { | |
162 | printf ("\n"); | |
163 | } | |
164 | ||
165 | printf (" %08lX%s", info->start[i], | |
166 | info->protect[i] ? " (RO)" : " "); | |
167 | } | |
168 | printf ("\n"); | |
169 | } | |
170 | ||
171 | ||
172 | int flash_erase (flash_info_t * info, int s_first, int s_last) | |
173 | { | |
174 | int flag, non_protected = 0, sector; | |
175 | int rc = ERR_OK; | |
176 | ||
177 | FLASH_BUS *address; | |
178 | ||
179 | for (sector = s_first; sector <= s_last; sector++) { | |
180 | if (!info->protect[sector]) { | |
181 | non_protected++; | |
182 | } | |
183 | } | |
184 | ||
185 | if (!non_protected) { | |
186 | return ERR_PROTECTED; | |
187 | } | |
188 | ||
189 | /* | |
190 | * Disable interrupts which might cause a timeout | |
191 | * here. Remember that our exception vectors are | |
192 | * at address 0 in the flash, and we don't want a | |
193 | * (ticker) exception to happen while the flash | |
194 | * chip is in programming mode. | |
195 | */ | |
196 | flag = disable_interrupts (); | |
197 | ||
198 | ||
199 | /* Start erase on unprotected sectors */ | |
200 | for (sector = s_first; sector <= s_last && !ctrlc (); sector++) { | |
201 | if (info->protect[sector]) { | |
202 | printf ("Protected sector %2d skipping...\n", sector); | |
203 | continue; | |
204 | } else { | |
205 | printf ("Erasing sector %2d ... ", sector); | |
206 | } | |
8bde7f77 | 207 | |
3e38691e WD |
208 | address = (FLASH_BUS *) (info->start[sector]); |
209 | ||
210 | *address = FLASH_CMD (CFI_INTEL_CMD_BLOCK_ERASE); | |
211 | *address = FLASH_CMD (CFI_INTEL_CMD_CONFIRM); | |
6d0f6bcf | 212 | if (flash_ready (CONFIG_SYS_FLASH_ERASE_TOUT)) { |
3e38691e WD |
213 | *address = FLASH_CMD (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER); |
214 | printf ("ok.\n"); | |
215 | } else { | |
216 | *address = FLASH_CMD (CFI_INTEL_CMD_SUSPEND); | |
217 | rc = ERR_TIMOUT; | |
218 | printf ("timeout! Aborting...\n"); | |
219 | break; | |
220 | } | |
221 | *address = FLASH_CMD (CFI_INTEL_CMD_READ_ARRAY); | |
222 | } | |
223 | if (ctrlc ()) | |
224 | printf ("User Interrupt!\n"); | |
225 | ||
226 | /* allow flash to settle - wait 10 ms */ | |
227 | udelay_masked (10000); | |
228 | if (flag) { | |
229 | enable_interrupts (); | |
230 | } | |
231 | ||
232 | return rc; | |
233 | } | |
234 | ||
235 | static int write_data (flash_info_t * info, ulong dest, FLASH_BUS data) | |
236 | { | |
237 | FLASH_BUS *address = (FLASH_BUS *) dest; | |
238 | int rc = ERR_OK; | |
239 | int flag; | |
240 | ||
241 | /* Check if Flash is (sufficiently) erased */ | |
242 | if ((*address & data) != data) { | |
243 | return ERR_NOT_ERASED; | |
244 | } | |
245 | ||
246 | /* | |
247 | * Disable interrupts which might cause a timeout | |
248 | * here. Remember that our exception vectors are | |
249 | * at address 0 in the flash, and we don't want a | |
250 | * (ticker) exception to happen while the flash | |
251 | * chip is in programming mode. | |
252 | */ | |
253 | ||
254 | flag = disable_interrupts (); | |
255 | ||
256 | *address = FLASH_CMD (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER); | |
257 | *address = FLASH_CMD (CFI_INTEL_CMD_PROGRAM1); | |
258 | *address = data; | |
259 | ||
6d0f6bcf | 260 | if (!flash_ready (CONFIG_SYS_FLASH_WRITE_TOUT)) { |
3e38691e WD |
261 | *address = FLASH_CMD (CFI_INTEL_CMD_SUSPEND); |
262 | rc = ERR_TIMOUT; | |
263 | printf ("timeout! Aborting...\n"); | |
264 | } | |
265 | ||
266 | *address = FLASH_CMD (CFI_INTEL_CMD_READ_ARRAY); | |
267 | if (flag) { | |
268 | enable_interrupts (); | |
269 | } | |
270 | ||
271 | return rc; | |
272 | } | |
273 | ||
274 | int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) | |
275 | { | |
276 | ulong read_addr, write_addr; | |
277 | FLASH_BUS data; | |
278 | int i, result = ERR_OK; | |
279 | ||
280 | ||
281 | read_addr = addr & ~(sizeof (FLASH_BUS) - 1); | |
282 | write_addr = read_addr; | |
283 | if (read_addr != addr) { | |
284 | data = 0; | |
285 | for (i = 0; i < sizeof (FLASH_BUS); i++) { | |
286 | if (read_addr < addr || cnt == 0) { | |
287 | data |= *((uchar *) read_addr) << i * 8; | |
288 | } else { | |
289 | data |= (*src++) << i * 8; | |
290 | cnt--; | |
291 | } | |
292 | read_addr++; | |
293 | } | |
294 | if ((result = write_data (info, write_addr, data)) != ERR_OK) { | |
295 | return result; | |
296 | } | |
297 | write_addr += sizeof (FLASH_BUS); | |
298 | } | |
299 | for (; cnt >= sizeof (FLASH_BUS); cnt -= sizeof (FLASH_BUS)) { | |
300 | if ((result = write_data (info, write_addr, | |
301 | *((FLASH_BUS *) src))) != ERR_OK) { | |
302 | return result; | |
303 | } | |
304 | write_addr += sizeof (FLASH_BUS); | |
305 | src += sizeof (FLASH_BUS); | |
306 | } | |
307 | if (cnt > 0) { | |
308 | read_addr = write_addr; | |
309 | data = 0; | |
310 | for (i = 0; i < sizeof (FLASH_BUS); i++) { | |
311 | if (cnt > 0) { | |
312 | data |= (*src++) << i * 8; | |
313 | cnt--; | |
314 | } else { | |
315 | data |= *((uchar *) read_addr) << i * 8; | |
316 | } | |
317 | read_addr++; | |
318 | } | |
319 | if ((result = write_data (info, write_addr, data)) != 0) { | |
320 | return result; | |
321 | } | |
322 | } | |
323 | return ERR_OK; | |
324 | } |