]>
Commit | Line | Data |
---|---|---|
983fda83 WD |
1 | /* |
2 | * (C) Copyright 2001 | |
3 | * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net | |
4 | * | |
5 | * (C) Copyright 2001-2004 | |
6 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
7 | * | |
8 | * See file CREDITS for list of people who contributed to this | |
9 | * project. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License as | |
13 | * published by the Free Software Foundation; either version 2 of | |
14 | * the License, or (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
24 | * MA 02111-1307 USA | |
25 | */ | |
26 | ||
27 | #include <common.h> | |
28 | #include <linux/byteorder/swab.h> | |
29 | ||
30 | ||
6d0f6bcf | 31 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */ |
983fda83 WD |
32 | |
33 | /* Board support for 1 or 2 flash devices */ | |
34 | #define FLASH_PORT_WIDTH8 | |
35 | ||
36 | typedef unsigned char FLASH_PORT_WIDTH; | |
37 | typedef volatile unsigned char FLASH_PORT_WIDTHV; | |
38 | ||
39 | #define SWAP(x) (x) | |
40 | ||
41 | /* Intel-compatible flash ID */ | |
42 | #define INTEL_COMPAT 0x89 | |
43 | #define INTEL_ALT 0xB0 | |
44 | ||
45 | /* Intel-compatible flash commands */ | |
46 | #define INTEL_PROGRAM 0x10 | |
47 | #define INTEL_ERASE 0x20 | |
48 | #define INTEL_CLEAR 0x50 | |
49 | #define INTEL_LOCKBIT 0x60 | |
50 | #define INTEL_PROTECT 0x01 | |
51 | #define INTEL_STATUS 0x70 | |
52 | #define INTEL_READID 0x90 | |
53 | #define INTEL_CONFIRM 0xD0 | |
54 | #define INTEL_RESET 0xFF | |
55 | ||
56 | /* Intel-compatible flash status bits */ | |
57 | #define INTEL_FINISHED 0x80 | |
58 | #define INTEL_OK 0x80 | |
59 | ||
60 | #define FPW FLASH_PORT_WIDTH | |
61 | #define FPWV FLASH_PORT_WIDTHV | |
62 | ||
63 | #define FLASH_CYCLE1 0x0555 | |
64 | #define FLASH_CYCLE2 0x02aa | |
65 | ||
66 | #define WR_BLOCK 0x20 | |
983fda83 WD |
67 | /*----------------------------------------------------------------------- |
68 | * Functions | |
69 | */ | |
70 | static ulong flash_get_size (FPW * addr, flash_info_t * info); | |
71 | static int write_data (flash_info_t * info, ulong dest, FPW data); | |
72 | static int write_data_block (flash_info_t * info, ulong src, ulong dest); | |
73 | static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data); | |
74 | static void flash_get_offsets (ulong base, flash_info_t * info); | |
75 | void inline spin_wheel (void); | |
010162eb WD |
76 | static void flash_sync_real_protect (flash_info_t * info); |
77 | static unsigned char intel_sector_protected (flash_info_t *info, ushort sector); | |
78 | static unsigned char same_chip_banks (int bank1, int bank2); | |
983fda83 WD |
79 | |
80 | /*----------------------------------------------------------------------- | |
81 | */ | |
82 | ||
83 | unsigned long flash_init (void) | |
84 | { | |
85 | int i; | |
86 | ulong size = 0; | |
87 | ulong fsize = 0; | |
88 | ||
6d0f6bcf | 89 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
983fda83 WD |
90 | memset (&flash_info[i], 0, sizeof (flash_info_t)); |
91 | ||
92 | switch (i) { | |
93 | case 0: | |
6d0f6bcf | 94 | flash_get_size ((FPW *) CONFIG_SYS_FLASH1_BASE, |
983fda83 | 95 | &flash_info[i]); |
6d0f6bcf | 96 | flash_get_offsets (CONFIG_SYS_FLASH1_BASE, &flash_info[i]); |
983fda83 WD |
97 | break; |
98 | case 1: | |
6d0f6bcf | 99 | flash_get_size ((FPW *) CONFIG_SYS_FLASH1_BASE, |
983fda83 | 100 | &flash_info[i]); |
6d0f6bcf | 101 | fsize = CONFIG_SYS_FLASH1_BASE + flash_info[i - 1].size; |
983fda83 WD |
102 | flash_get_offsets (fsize, &flash_info[i]); |
103 | break; | |
104 | case 2: | |
6d0f6bcf | 105 | flash_get_size ((FPW *) CONFIG_SYS_FLASH0_BASE, |
983fda83 | 106 | &flash_info[i]); |
6d0f6bcf | 107 | flash_get_offsets (CONFIG_SYS_FLASH0_BASE, &flash_info[i]); |
983fda83 WD |
108 | break; |
109 | case 3: | |
6d0f6bcf | 110 | flash_get_size ((FPW *) CONFIG_SYS_FLASH0_BASE, |
983fda83 | 111 | &flash_info[i]); |
6d0f6bcf | 112 | fsize = CONFIG_SYS_FLASH0_BASE + flash_info[i - 1].size; |
983fda83 WD |
113 | flash_get_offsets (fsize, &flash_info[i]); |
114 | break; | |
115 | default: | |
116 | panic ("configured to many flash banks!\n"); | |
117 | break; | |
118 | } | |
119 | size += flash_info[i].size; | |
010162eb WD |
120 | |
121 | /* get the h/w and s/w protection status in sync */ | |
122 | flash_sync_real_protect(&flash_info[i]); | |
983fda83 WD |
123 | } |
124 | ||
125 | /* Protect monitor and environment sectors | |
126 | */ | |
6d0f6bcf | 127 | #if defined (CONFIG_SYS_AMD_BOOT) |
983fda83 | 128 | flash_protect (FLAG_PROTECT_SET, |
6d0f6bcf JCPV |
129 | CONFIG_SYS_MONITOR_BASE, |
130 | CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, | |
983fda83 WD |
131 | &flash_info[2]); |
132 | flash_protect (FLAG_PROTECT_SET, | |
6d0f6bcf JCPV |
133 | CONFIG_SYS_INTEL_BASE, |
134 | CONFIG_SYS_INTEL_BASE + monitor_flash_len - 1, | |
983fda83 WD |
135 | &flash_info[1]); |
136 | #else | |
137 | flash_protect (FLAG_PROTECT_SET, | |
6d0f6bcf JCPV |
138 | CONFIG_SYS_MONITOR_BASE, |
139 | CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, | |
983fda83 WD |
140 | &flash_info[3]); |
141 | flash_protect (FLAG_PROTECT_SET, | |
6d0f6bcf JCPV |
142 | CONFIG_SYS_AMD_BASE, |
143 | CONFIG_SYS_AMD_BASE + monitor_flash_len - 1, &flash_info[0]); | |
983fda83 WD |
144 | #endif |
145 | ||
146 | flash_protect (FLAG_PROTECT_SET, | |
0e8d1586 JCPV |
147 | CONFIG_ENV1_ADDR, |
148 | CONFIG_ENV1_ADDR + CONFIG_ENV1_SIZE - 1, &flash_info[1]); | |
983fda83 | 149 | flash_protect (FLAG_PROTECT_SET, |
0e8d1586 JCPV |
150 | CONFIG_ENV_ADDR, |
151 | CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[3]); | |
983fda83 WD |
152 | |
153 | return size; | |
154 | } | |
155 | ||
156 | /*----------------------------------------------------------------------- | |
157 | */ | |
158 | static void flash_get_offsets (ulong base, flash_info_t * info) | |
159 | { | |
160 | int i; | |
161 | ||
162 | if (info->flash_id == FLASH_UNKNOWN) | |
163 | return; | |
164 | ||
165 | if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD) { | |
166 | for (i = 0; i < info->sector_count; i++) { | |
167 | info->start[i] = base + (i * PHYS_AMD_SECT_SIZE); | |
168 | info->protect[i] = 0; | |
169 | } | |
170 | } | |
171 | ||
172 | if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { | |
173 | for (i = 0; i < info->sector_count; i++) { | |
174 | info->start[i] = base + (i * PHYS_INTEL_SECT_SIZE); | |
983fda83 WD |
175 | } |
176 | } | |
177 | } | |
178 | ||
179 | /*----------------------------------------------------------------------- | |
180 | */ | |
181 | void flash_print_info (flash_info_t * info) | |
182 | { | |
183 | int i; | |
184 | ||
185 | if (info->flash_id == FLASH_UNKNOWN) { | |
186 | printf ("missing or unknown FLASH type\n"); | |
187 | return; | |
188 | } | |
189 | ||
190 | switch (info->flash_id & FLASH_VENDMASK) { | |
191 | case FLASH_MAN_INTEL: | |
192 | printf ("INTEL "); | |
193 | break; | |
194 | case FLASH_MAN_AMD: | |
195 | printf ("AMD "); | |
196 | break; | |
197 | default: | |
198 | printf ("Unknown Vendor "); | |
199 | break; | |
200 | } | |
201 | ||
202 | switch (info->flash_id & FLASH_TYPEMASK) { | |
203 | case FLASH_28F128J3A: | |
204 | printf ("28F128J3A\n"); | |
205 | break; | |
206 | ||
207 | case FLASH_AM040: | |
208 | printf ("AMD29F040B\n"); | |
209 | break; | |
210 | ||
211 | default: | |
212 | printf ("Unknown Chip Type\n"); | |
213 | break; | |
214 | } | |
215 | ||
216 | printf (" Size: %ld MB in %d Sectors\n", | |
217 | info->size >> 20, info->sector_count); | |
218 | ||
219 | printf (" Sector Start Addresses:"); | |
220 | for (i = 0; i < info->sector_count; ++i) { | |
221 | if ((i % 5) == 0) | |
222 | printf ("\n "); | |
223 | printf (" %08lX%s", | |
224 | info->start[i], info->protect[i] ? " (RO)" : " "); | |
225 | } | |
226 | printf ("\n"); | |
227 | return; | |
228 | } | |
229 | ||
230 | /* | |
231 | * The following code cannot be run from FLASH! | |
232 | */ | |
233 | static ulong flash_get_size (FPW * addr, flash_info_t * info) | |
234 | { | |
235 | FPWV value; | |
236 | static int amd = 0; | |
237 | ||
238 | /* Write auto select command: read Manufacturer ID */ | |
239 | /* Write auto select command sequence and test FLASH answer */ | |
240 | addr[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* for AMD, Intel ignores this */ | |
241 | __asm__ ("sync"); | |
242 | addr[FLASH_CYCLE2] = (FPW) 0x00550055; /* for AMD, Intel ignores this */ | |
243 | __asm__ ("sync"); | |
244 | addr[FLASH_CYCLE1] = (FPW) 0x00900090; /* selects Intel or AMD */ | |
245 | __asm__ ("sync"); | |
246 | ||
247 | udelay (100); | |
248 | ||
249 | switch (addr[0] & 0xff) { | |
250 | ||
251 | case (uchar) AMD_MANUFACT: | |
252 | info->flash_id = FLASH_MAN_AMD; | |
253 | value = addr[1]; | |
254 | break; | |
255 | ||
256 | case (uchar) INTEL_MANUFACT: | |
257 | info->flash_id = FLASH_MAN_INTEL; | |
258 | value = addr[2]; | |
259 | break; | |
260 | ||
261 | default: | |
262 | printf ("unknown\n"); | |
263 | info->flash_id = FLASH_UNKNOWN; | |
264 | info->sector_count = 0; | |
265 | info->size = 0; | |
266 | addr[0] = (FPW) 0x00FF00FF; /* restore read mode */ | |
267 | return (0); /* no or unknown flash */ | |
268 | } | |
269 | ||
270 | switch (value) { | |
271 | ||
272 | case (FPW) INTEL_ID_28F128J3A: | |
273 | info->flash_id += FLASH_28F128J3A; | |
274 | info->sector_count = 64; | |
275 | info->size = 0x00800000; /* => 16 MB */ | |
276 | break; | |
277 | ||
278 | case (FPW) AMD_ID_LV040B: | |
279 | info->flash_id += FLASH_AM040; | |
280 | if (amd == 0) { | |
281 | info->sector_count = 7; | |
282 | info->size = 0x00070000; /* => 448 KB */ | |
283 | amd = 1; | |
284 | } else { | |
285 | /* for Environment settings */ | |
286 | info->sector_count = 1; | |
287 | info->size = PHYS_AMD_SECT_SIZE; /* => 64 KB */ | |
288 | amd = 0; | |
289 | } | |
290 | break; | |
291 | ||
292 | default: | |
293 | info->flash_id = FLASH_UNKNOWN; | |
294 | break; | |
295 | } | |
296 | ||
6d0f6bcf | 297 | if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) { |
983fda83 | 298 | printf ("** ERROR: sector count %d > max (%d) **\n", |
6d0f6bcf JCPV |
299 | info->sector_count, CONFIG_SYS_MAX_FLASH_SECT); |
300 | info->sector_count = CONFIG_SYS_MAX_FLASH_SECT; | |
983fda83 WD |
301 | } |
302 | ||
303 | if (value == (FPW) INTEL_ID_28F128J3A) | |
304 | addr[0] = (FPW) 0x00FF00FF; /* restore read mode */ | |
305 | else | |
306 | addr[0] = (FPW) 0x00F000F0; /* restore read mode */ | |
307 | ||
308 | return (info->size); | |
309 | } | |
310 | ||
311 | ||
010162eb WD |
312 | /* |
313 | * This function gets the u-boot flash sector protection status | |
314 | * (flash_info_t.protect[]) in sync with the sector protection | |
315 | * status stored in hardware. | |
316 | */ | |
317 | static void flash_sync_real_protect (flash_info_t * info) | |
318 | { | |
319 | int i; | |
320 | ||
321 | switch (info->flash_id & FLASH_TYPEMASK) { | |
322 | case FLASH_28F128J3A: | |
323 | for (i = 0; i < info->sector_count; ++i) { | |
324 | info->protect[i] = intel_sector_protected(info, i); | |
325 | } | |
326 | break; | |
327 | case FLASH_AM040: | |
328 | default: | |
329 | /* no h/w protect support */ | |
330 | break; | |
331 | } | |
332 | } | |
333 | ||
334 | ||
335 | /* | |
336 | * checks if "sector" in bank "info" is protected. Should work on intel | |
337 | * strata flash chips 28FxxxJ3x in 8-bit mode. | |
338 | * Returns 1 if sector is protected (or timed-out while trying to read | |
339 | * protection status), 0 if it is not. | |
340 | */ | |
341 | static unsigned char intel_sector_protected (flash_info_t *info, ushort sector) | |
342 | { | |
343 | FPWV *addr; | |
344 | FPWV *lock_conf_addr; | |
345 | ulong start; | |
346 | unsigned char ret; | |
347 | ||
348 | /* | |
349 | * first, wait for the WSM to be finished. The rationale for | |
350 | * waiting for the WSM to become idle for at most | |
6d0f6bcf | 351 | * CONFIG_SYS_FLASH_ERASE_TOUT is as follows. The WSM can be busy |
010162eb WD |
352 | * because of: (1) erase, (2) program or (3) lock bit |
353 | * configuration. So we just wait for the longest timeout of | |
354 | * the (1)-(3), i.e. the erase timeout. | |
355 | */ | |
356 | ||
357 | /* wait at least 35ns (W12) before issuing Read Status Register */ | |
358 | udelay(1); | |
359 | addr = (FPWV *) info->start[sector]; | |
360 | *addr = (FPW) INTEL_STATUS; | |
361 | ||
362 | start = get_timer (0); | |
363 | while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) { | |
6d0f6bcf | 364 | if (get_timer (start) > CONFIG_SYS_FLASH_ERASE_TOUT) { |
010162eb WD |
365 | *addr = (FPW) INTEL_RESET; /* restore read mode */ |
366 | printf("WSM busy too long, can't get prot status\n"); | |
367 | return 1; | |
368 | } | |
369 | } | |
370 | ||
371 | /* issue the Read Identifier Codes command */ | |
372 | *addr = (FPW) INTEL_READID; | |
373 | ||
374 | /* wait at least 35ns (W12) before reading */ | |
375 | udelay(1); | |
376 | ||
377 | /* Intel example code uses offset of 4 for 8-bit flash */ | |
378 | lock_conf_addr = (FPWV *) info->start[sector] + 4; | |
379 | ret = (*lock_conf_addr & (FPW) INTEL_PROTECT) ? 1 : 0; | |
380 | ||
381 | /* put flash back in read mode */ | |
382 | *addr = (FPW) INTEL_RESET; | |
383 | ||
384 | return ret; | |
385 | } | |
386 | ||
387 | ||
388 | /* | |
389 | * Checks if "bank1" and "bank2" are on the same chip. Returns 1 if they | |
390 | * are and 0 otherwise. | |
391 | */ | |
392 | static unsigned char same_chip_banks (int bank1, int bank2) | |
393 | { | |
6d0f6bcf | 394 | unsigned char same_chip[CONFIG_SYS_MAX_FLASH_BANKS][CONFIG_SYS_MAX_FLASH_BANKS] = { |
010162eb WD |
395 | {1, 1, 0, 0}, |
396 | {1, 1, 0, 0}, | |
397 | {0, 0, 1, 1}, | |
398 | {0, 0, 1, 1} | |
399 | }; | |
400 | return same_chip[bank1][bank2]; | |
401 | } | |
402 | ||
403 | ||
983fda83 WD |
404 | /*----------------------------------------------------------------------- |
405 | */ | |
406 | int flash_erase (flash_info_t * info, int s_first, int s_last) | |
407 | { | |
408 | int flag, prot, sect; | |
409 | ulong type, start, last; | |
410 | int rcode = 0, intel = 0; | |
411 | ||
412 | if ((s_first < 0) || (s_first > s_last)) { | |
413 | if (info->flash_id == FLASH_UNKNOWN) | |
414 | printf ("- missing\n"); | |
415 | else | |
416 | printf ("- no sectors to erase\n"); | |
417 | return 1; | |
418 | } | |
419 | ||
420 | type = (info->flash_id & FLASH_VENDMASK); | |
421 | if ((type != FLASH_MAN_INTEL)) { | |
422 | type = (info->flash_id & FLASH_VENDMASK); | |
423 | if ((type != FLASH_MAN_AMD)) { | |
424 | printf ("Can't erase unknown flash type %08lx - aborted\n", | |
425 | info->flash_id); | |
426 | return 1; | |
427 | } | |
428 | } | |
429 | ||
430 | if (type == FLASH_MAN_INTEL) | |
431 | intel = 1; | |
432 | ||
433 | prot = 0; | |
434 | for (sect = s_first; sect <= s_last; ++sect) { | |
435 | if (info->protect[sect]) { | |
436 | prot++; | |
437 | } | |
438 | } | |
439 | ||
440 | if (prot) { | |
441 | printf ("- Warning: %d protected sectors will not be erased!\n", prot); | |
442 | } else { | |
443 | printf ("\n"); | |
444 | } | |
445 | ||
446 | start = get_timer (0); | |
447 | last = start; | |
448 | ||
449 | /* Disable interrupts which might cause a timeout here */ | |
450 | flag = disable_interrupts (); | |
451 | ||
452 | /* Start erase on unprotected sectors */ | |
453 | for (sect = s_first; sect <= s_last; sect++) { | |
454 | if (info->protect[sect] == 0) { /* not protected */ | |
455 | FPWV *addr = (FPWV *) (info->start[sect]); | |
456 | FPW status; | |
457 | ||
458 | printf ("Erasing sector %2d ... ", sect); | |
459 | ||
460 | /* arm simple, non interrupt dependent timer */ | |
461 | start = get_timer (0); | |
462 | ||
463 | if (intel) { | |
464 | *addr = (FPW) 0x00500050; /* clear status register */ | |
465 | *addr = (FPW) 0x00200020; /* erase setup */ | |
466 | *addr = (FPW) 0x00D000D0; /* erase confirm */ | |
467 | } else { | |
468 | FPWV *base; /* first address in bank */ | |
469 | ||
6d0f6bcf | 470 | base = (FPWV *) (CONFIG_SYS_AMD_BASE); |
983fda83 WD |
471 | base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */ |
472 | base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */ | |
473 | base[FLASH_CYCLE1] = (FPW) 0x00800080; /* erase mode */ | |
474 | base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */ | |
475 | base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */ | |
476 | *addr = (FPW) 0x00300030; /* erase sector */ | |
477 | } | |
478 | ||
479 | while (((status = | |
480 | *addr) & (FPW) 0x00800080) != | |
481 | (FPW) 0x00800080) { | |
6d0f6bcf | 482 | if (get_timer (start) > CONFIG_SYS_FLASH_ERASE_TOUT) { |
983fda83 WD |
483 | printf ("Timeout\n"); |
484 | if (intel) { | |
485 | *addr = (FPW) 0x00B000B0; /* suspend erase */ | |
486 | *addr = (FPW) 0x00FF00FF; /* reset to read mode */ | |
487 | } else | |
488 | *addr = (FPW) 0x00F000F0; /* reset to read mode */ | |
489 | ||
490 | rcode = 1; | |
491 | break; | |
492 | } | |
493 | } | |
494 | ||
495 | if (intel) { | |
496 | *addr = (FPW) 0x00500050; /* clear status register cmd. */ | |
497 | *addr = (FPW) 0x00FF00FF; /* resest to read mode */ | |
498 | } else | |
499 | *addr = (FPW) 0x00F000F0; /* reset to read mode */ | |
500 | ||
501 | printf (" done\n"); | |
502 | } | |
503 | } | |
504 | return rcode; | |
505 | } | |
506 | ||
507 | /*----------------------------------------------------------------------- | |
508 | * Copy memory to flash, returns: | |
509 | * 0 - OK | |
510 | * 1 - write timeout | |
511 | * 2 - Flash not erased | |
512 | * 4 - Flash not identified | |
513 | */ | |
514 | ||
515 | int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) | |
516 | { | |
517 | if (info->flash_id == FLASH_UNKNOWN) { | |
518 | return 4; | |
519 | } | |
520 | ||
521 | switch (info->flash_id & FLASH_VENDMASK) { | |
522 | case FLASH_MAN_AMD: | |
523 | { | |
524 | FPW data = 0; /* 16 or 32 bit word, matches flash bus width */ | |
525 | int bytes; /* number of bytes to program in current word */ | |
526 | int left; /* number of bytes left to program */ | |
527 | int i, res; | |
528 | ||
529 | for (left = cnt, res = 0; | |
530 | left > 0 && res == 0; | |
531 | addr += sizeof (data), left -= | |
532 | sizeof (data) - bytes) { | |
533 | ||
534 | bytes = addr & (sizeof (data) - 1); | |
535 | addr &= ~(sizeof (data) - 1); | |
536 | ||
537 | /* combine source and destination data so can program | |
538 | * an entire word of 16 or 32 bits | |
539 | */ | |
540 | for (i = 0; i < sizeof (data); i++) { | |
541 | data <<= 8; | |
542 | if (i < bytes || i - bytes >= left) | |
543 | data += *((uchar *) addr + i); | |
544 | else | |
545 | data += *src++; | |
546 | } | |
547 | ||
548 | res = write_word_amd (info, (FPWV *) addr, | |
549 | data); | |
550 | } | |
551 | return res; | |
552 | } /* case FLASH_MAN_AMD */ | |
553 | ||
554 | case FLASH_MAN_INTEL: | |
555 | { | |
556 | ulong cp, wp; | |
557 | FPW data; | |
558 | int count, i, l, rc, port_width; | |
559 | ||
560 | /* get lower word aligned address */ | |
561 | wp = addr; | |
562 | port_width = 1; | |
563 | ||
564 | /* | |
565 | * handle unaligned start bytes | |
566 | */ | |
567 | if ((l = addr - wp) != 0) { | |
568 | data = 0; | |
569 | for (i = 0, cp = wp; i < l; ++i, ++cp) { | |
570 | data = (data << 8) | (*(uchar *) cp); | |
571 | } | |
572 | ||
573 | for (; i < port_width && cnt > 0; ++i) { | |
574 | data = (data << 8) | *src++; | |
575 | --cnt; | |
576 | ++cp; | |
577 | } | |
578 | ||
579 | for (; cnt == 0 && i < port_width; ++i, ++cp) | |
580 | data = (data << 8) | (*(uchar *) cp); | |
581 | ||
582 | if ((rc = | |
583 | write_data (info, wp, SWAP (data))) != 0) | |
584 | return (rc); | |
585 | wp += port_width; | |
586 | } | |
587 | ||
588 | if (cnt > WR_BLOCK) { | |
589 | /* | |
590 | * handle word aligned part | |
591 | */ | |
592 | count = 0; | |
593 | while (cnt >= WR_BLOCK) { | |
594 | ||
595 | if ((rc = | |
596 | write_data_block (info, | |
597 | (ulong) src, | |
598 | wp)) != 0) | |
599 | return (rc); | |
600 | ||
601 | wp += WR_BLOCK; | |
602 | src += WR_BLOCK; | |
603 | cnt -= WR_BLOCK; | |
604 | ||
605 | if (count++ > 0x800) { | |
606 | spin_wheel (); | |
607 | count = 0; | |
608 | } | |
609 | } | |
610 | } | |
611 | ||
612 | if (cnt < WR_BLOCK) { | |
613 | /* | |
614 | * handle word aligned part | |
615 | */ | |
616 | count = 0; | |
617 | while (cnt >= port_width) { | |
618 | data = 0; | |
619 | for (i = 0; i < port_width; ++i) | |
620 | data = (data << 8) | *src++; | |
621 | ||
622 | if ((rc = | |
623 | write_data (info, wp, | |
624 | SWAP (data))) != 0) | |
625 | return (rc); | |
626 | ||
627 | wp += port_width; | |
628 | cnt -= port_width; | |
629 | if (count++ > 0x800) { | |
630 | spin_wheel (); | |
631 | count = 0; | |
632 | } | |
633 | } | |
634 | } | |
635 | ||
636 | if (cnt == 0) | |
637 | return (0); | |
638 | ||
639 | /* | |
640 | * handle unaligned tail bytes | |
641 | */ | |
642 | data = 0; | |
643 | for (i = 0, cp = wp; i < port_width && cnt > 0; | |
644 | ++i, ++cp) { | |
645 | data = (data << 8) | *src++; | |
646 | --cnt; | |
647 | } | |
648 | ||
649 | for (; i < port_width; ++i, ++cp) | |
650 | data = (data << 8) | (*(uchar *) cp); | |
651 | ||
652 | return (write_data (info, wp, SWAP (data))); | |
653 | } /* case FLASH_MAN_INTEL */ | |
654 | ||
655 | } /* switch */ | |
656 | return (0); | |
657 | } | |
658 | ||
659 | /*----------------------------------------------------------------------- | |
660 | * Write a word or halfword to Flash, returns: | |
661 | * 0 - OK | |
662 | * 1 - write timeout | |
663 | * 2 - Flash not erased | |
664 | */ | |
665 | static int write_data (flash_info_t * info, ulong dest, FPW data) | |
666 | { | |
667 | FPWV *addr = (FPWV *) dest; | |
668 | ulong start; | |
669 | int flag; | |
670 | ||
671 | /* Check if Flash is (sufficiently) erased */ | |
672 | if ((*addr & data) != data) { | |
06c53bea | 673 | printf ("not erased at %08lx (%lx)\n", (ulong)addr, (ulong)*addr); |
983fda83 WD |
674 | return (2); |
675 | } | |
676 | /* Disable interrupts which might cause a timeout here */ | |
677 | flag = disable_interrupts (); | |
678 | ||
679 | *addr = (FPW) 0x00400040; /* write setup */ | |
680 | *addr = data; | |
681 | ||
682 | /* arm simple, non interrupt dependent timer */ | |
683 | start = get_timer (0); | |
684 | ||
685 | /* wait while polling the status register */ | |
686 | while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) { | |
6d0f6bcf | 687 | if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
983fda83 WD |
688 | *addr = (FPW) 0x00FF00FF; /* restore read mode */ |
689 | return (1); | |
690 | } | |
691 | } | |
692 | ||
693 | *addr = (FPW) 0x00FF00FF; /* restore read mode */ | |
694 | ||
695 | return (0); | |
696 | } | |
697 | ||
698 | /*----------------------------------------------------------------------- | |
699 | * Write a word or halfword to Flash, returns: | |
700 | * 0 - OK | |
701 | * 1 - write timeout | |
702 | * 2 - Flash not erased | |
703 | */ | |
704 | static int write_data_block (flash_info_t * info, ulong src, ulong dest) | |
705 | { | |
706 | FPWV *srcaddr = (FPWV *) src; | |
707 | FPWV *dstaddr = (FPWV *) dest; | |
708 | ulong start; | |
709 | int flag, i; | |
710 | ||
711 | /* Check if Flash is (sufficiently) erased */ | |
712 | for (i = 0; i < WR_BLOCK; i++) | |
713 | if ((*dstaddr++ & 0xff) != 0xff) { | |
714 | printf ("not erased at %08lx (%lx)\n", | |
06c53bea | 715 | (ulong)dstaddr, (ulong)*dstaddr); |
983fda83 WD |
716 | return (2); |
717 | } | |
718 | ||
719 | dstaddr = (FPWV *) dest; | |
720 | ||
721 | /* Disable interrupts which might cause a timeout here */ | |
722 | flag = disable_interrupts (); | |
723 | ||
724 | *dstaddr = (FPW) 0x00e800e8; /* write block setup */ | |
725 | ||
726 | /* arm simple, non interrupt dependent timer */ | |
727 | start = get_timer (0); | |
728 | ||
729 | /* wait while polling the status register */ | |
730 | while ((*dstaddr & (FPW) 0x00800080) != (FPW) 0x00800080) { | |
6d0f6bcf | 731 | if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
983fda83 WD |
732 | *dstaddr = (FPW) 0x00FF00FF; /* restore read mode */ |
733 | return (1); | |
734 | } | |
735 | } | |
736 | ||
737 | *dstaddr = (FPW) 0x001f001f; /* write 32 to buffer */ | |
738 | for (i = 0; i < WR_BLOCK; i++) | |
739 | *dstaddr++ = *srcaddr++; | |
740 | ||
741 | dstaddr -= 1; | |
742 | *dstaddr = (FPW) 0x00d000d0; /* write 32 to buffer */ | |
743 | ||
744 | /* arm simple, non interrupt dependent timer */ | |
745 | start = get_timer (0); | |
746 | ||
747 | /* wait while polling the status register */ | |
748 | while ((*dstaddr & (FPW) 0x00800080) != (FPW) 0x00800080) { | |
6d0f6bcf | 749 | if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
983fda83 WD |
750 | *dstaddr = (FPW) 0x00FF00FF; /* restore read mode */ |
751 | return (1); | |
752 | } | |
753 | } | |
754 | ||
755 | *dstaddr = (FPW) 0x00FF00FF; /* restore read mode */ | |
756 | ||
757 | return (0); | |
758 | } | |
759 | ||
760 | /*----------------------------------------------------------------------- | |
761 | * Write a word to Flash for AMD FLASH | |
762 | * A word is 16 or 32 bits, whichever the bus width of the flash bank | |
763 | * (not an individual chip) is. | |
764 | * | |
765 | * returns: | |
766 | * 0 - OK | |
767 | * 1 - write timeout | |
768 | * 2 - Flash not erased | |
769 | */ | |
770 | static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data) | |
771 | { | |
772 | ulong start; | |
773 | int flag; | |
774 | int res = 0; /* result, assume success */ | |
775 | FPWV *base; /* first address in flash bank */ | |
776 | ||
777 | /* Check if Flash is (sufficiently) erased */ | |
778 | if ((*dest & data) != data) { | |
779 | return (2); | |
780 | } | |
781 | ||
6d0f6bcf | 782 | base = (FPWV *) (CONFIG_SYS_AMD_BASE); |
983fda83 WD |
783 | |
784 | /* Disable interrupts which might cause a timeout here */ | |
785 | flag = disable_interrupts (); | |
786 | ||
787 | base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */ | |
788 | base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */ | |
789 | base[FLASH_CYCLE1] = (FPW) 0x00A000A0; /* selects program mode */ | |
790 | ||
791 | *dest = data; /* start programming the data */ | |
792 | ||
793 | /* re-enable interrupts if necessary */ | |
794 | if (flag) | |
795 | enable_interrupts (); | |
796 | ||
797 | start = get_timer (0); | |
798 | ||
799 | /* data polling for D7 */ | |
800 | while (res == 0 | |
801 | && (*dest & (FPW) 0x00800080) != (data & (FPW) 0x00800080)) { | |
6d0f6bcf | 802 | if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
983fda83 WD |
803 | *dest = (FPW) 0x00F000F0; /* reset bank */ |
804 | res = 1; | |
805 | } | |
806 | } | |
807 | ||
808 | return (res); | |
809 | } | |
810 | ||
811 | void inline spin_wheel (void) | |
812 | { | |
813 | static int p = 0; | |
814 | static char w[] = "\\/-"; | |
815 | ||
816 | printf ("\010%c", w[p]); | |
817 | (++p == 3) ? (p = 0) : 0; | |
818 | } | |
819 | ||
820 | /*----------------------------------------------------------------------- | |
821 | * Set/Clear sector's lock bit, returns: | |
822 | * 0 - OK | |
823 | * 1 - Error (timeout, voltage problems, etc.) | |
824 | */ | |
825 | int flash_real_protect (flash_info_t * info, long sector, int prot) | |
826 | { | |
827 | ulong start; | |
010162eb WD |
828 | int i, j; |
829 | int curr_bank; | |
830 | int bank; | |
983fda83 WD |
831 | int rc = 0; |
832 | FPWV *addr = (FPWV *) (info->start[sector]); | |
833 | int flag = disable_interrupts (); | |
834 | ||
835 | /* | |
836 | * 29F040B AMD flash does not support software protection/unprotection, | |
837 | * the only way to protect the AMD flash is marked it as prot bit. | |
838 | * This flash only support hardware protection, by supply or not supply | |
839 | * 12vpp to the flash | |
840 | */ | |
841 | if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD) { | |
842 | info->protect[sector] = prot; | |
843 | ||
844 | return 0; | |
845 | } | |
846 | ||
847 | *addr = INTEL_CLEAR; /* Clear status register */ | |
848 | if (prot) { /* Set sector lock bit */ | |
849 | *addr = INTEL_LOCKBIT; /* Sector lock bit */ | |
850 | *addr = INTEL_PROTECT; /* set */ | |
851 | } else { /* Clear sector lock bit */ | |
852 | *addr = INTEL_LOCKBIT; /* All sectors lock bits */ | |
853 | *addr = INTEL_CONFIRM; /* clear */ | |
854 | } | |
855 | ||
856 | start = get_timer (0); | |
857 | ||
858 | while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) { | |
6d0f6bcf | 859 | if (get_timer (start) > CONFIG_SYS_FLASH_UNLOCK_TOUT) { |
983fda83 WD |
860 | printf ("Flash lock bit operation timed out\n"); |
861 | rc = 1; | |
862 | break; | |
863 | } | |
864 | } | |
865 | ||
866 | if (*addr != INTEL_OK) { | |
867 | printf ("Flash lock bit operation failed at %08X, CSR=%08X\n", | |
868 | (uint) addr, (uint) * addr); | |
869 | rc = 1; | |
870 | } | |
871 | ||
872 | if (!rc) | |
873 | info->protect[sector] = prot; | |
874 | ||
875 | /* | |
876 | * Clear lock bit command clears all sectors lock bits, so | |
877 | * we have to restore lock bits of protected sectors. | |
878 | */ | |
879 | if (!prot) { | |
010162eb WD |
880 | /* |
881 | * re-locking must be done for all banks that belong on one | |
882 | * FLASH chip, as all the sectors on the chip were unlocked | |
883 | * by INTEL_LOCKBIT/INTEL_CONFIRM commands. (let's hope | |
884 | * that banks never span chips, in particular chips which | |
885 | * support h/w protection differently). | |
886 | */ | |
887 | ||
888 | /* find the current bank number */ | |
6d0f6bcf JCPV |
889 | curr_bank = CONFIG_SYS_MAX_FLASH_BANKS + 1; |
890 | for (j = 0; j < CONFIG_SYS_MAX_FLASH_BANKS; ++j) { | |
010162eb WD |
891 | if (&flash_info[j] == info) { |
892 | curr_bank = j; | |
893 | } | |
894 | } | |
6d0f6bcf | 895 | if (curr_bank == CONFIG_SYS_MAX_FLASH_BANKS + 1) { |
010162eb WD |
896 | printf("Error: can't determine bank number!\n"); |
897 | } | |
898 | ||
6d0f6bcf | 899 | for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { |
010162eb WD |
900 | if (!same_chip_banks(curr_bank, bank)) { |
901 | continue; | |
902 | } | |
903 | info = &flash_info[bank]; | |
904 | for (i = 0; i < info->sector_count; i++) { | |
905 | if (info->protect[i]) { | |
906 | start = get_timer (0); | |
907 | addr = (FPWV *) (info->start[i]); | |
908 | *addr = INTEL_LOCKBIT; /* Sector lock bit */ | |
909 | *addr = INTEL_PROTECT; /* set */ | |
910 | while ((*addr & INTEL_FINISHED) != | |
911 | INTEL_FINISHED) { | |
912 | if (get_timer (start) > | |
6d0f6bcf | 913 | CONFIG_SYS_FLASH_UNLOCK_TOUT) { |
010162eb WD |
914 | printf ("Flash lock bit operation timed out\n"); |
915 | rc = 1; | |
916 | break; | |
917 | } | |
983fda83 WD |
918 | } |
919 | } | |
920 | } | |
921 | } | |
010162eb WD |
922 | |
923 | /* | |
924 | * get the s/w sector protection status in sync with the h/w, | |
925 | * in case something went wrong during the re-locking. | |
926 | */ | |
927 | flash_sync_real_protect(info); /* resets flash to read mode */ | |
983fda83 WD |
928 | } |
929 | ||
930 | if (flag) | |
931 | enable_interrupts (); | |
932 | ||
933 | *addr = INTEL_RESET; /* Reset to read array mode */ | |
934 | ||
935 | return rc; | |
936 | } |