]>
Commit | Line | Data |
---|---|---|
efa329cb 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 */ |
efa329cb WD |
32 | |
33 | /* Board support for 1 or 2 flash devices */ | |
34 | #define FLASH_PORT_WIDTH32 | |
35 | #undef FLASH_PORT_WIDTH16 | |
36 | ||
37 | #ifdef FLASH_PORT_WIDTH16 | |
53677ef1 WD |
38 | #define FLASH_PORT_WIDTH ushort |
39 | #define FLASH_PORT_WIDTHV vu_short | |
40 | #define SWAP(x) (x) | |
efa329cb | 41 | #else |
53677ef1 WD |
42 | #define FLASH_PORT_WIDTH ulong |
43 | #define FLASH_PORT_WIDTHV vu_long | |
44 | #define SWAP(x) (x) | |
efa329cb WD |
45 | #endif |
46 | ||
47 | /* Intel-compatible flash ID */ | |
53677ef1 WD |
48 | #define INTEL_COMPAT 0x00890089 |
49 | #define INTEL_ALT 0x00B000B0 | |
efa329cb WD |
50 | |
51 | /* Intel-compatible flash commands */ | |
53677ef1 WD |
52 | #define INTEL_PROGRAM 0x00100010 |
53 | #define INTEL_ERASE 0x00200020 | |
54 | #define INTEL_CLEAR 0x00500050 | |
55 | #define INTEL_LOCKBIT 0x00600060 | |
56 | #define INTEL_PROTECT 0x00010001 | |
57 | #define INTEL_STATUS 0x00700070 | |
58 | #define INTEL_READID 0x00900090 | |
59 | #define INTEL_CONFIRM 0x00D000D0 | |
60 | #define INTEL_RESET 0xFFFFFFFF | |
efa329cb WD |
61 | |
62 | /* Intel-compatible flash status bits */ | |
53677ef1 WD |
63 | #define INTEL_FINISHED 0x00800080 |
64 | #define INTEL_OK 0x00800080 | |
efa329cb | 65 | |
53677ef1 WD |
66 | #define FPW FLASH_PORT_WIDTH |
67 | #define FPWV FLASH_PORT_WIDTHV | |
efa329cb WD |
68 | |
69 | #define mb() __asm__ __volatile__ ("" : : : "memory") | |
70 | ||
71 | /*----------------------------------------------------------------------- | |
72 | * Functions | |
73 | */ | |
74 | static ulong flash_get_size (FPW *addr, flash_info_t *info); | |
75 | static int write_data (flash_info_t *info, ulong dest, FPW data); | |
76 | static void flash_get_offsets (ulong base, flash_info_t *info); | |
77 | void inline spin_wheel (void); | |
010162eb WD |
78 | static void flash_sync_real_protect (flash_info_t * info); |
79 | static unsigned char intel_sector_protected (flash_info_t *info, ushort sector); | |
efa329cb WD |
80 | |
81 | /*----------------------------------------------------------------------- | |
82 | */ | |
83 | ||
84 | unsigned long flash_init (void) | |
85 | { | |
86 | int i; | |
87 | ulong size = 0; | |
49822e23 WD |
88 | extern void flash_preinit(void); |
89 | extern void flash_afterinit(ulong, ulong); | |
6d0f6bcf | 90 | ulong flashbase = CONFIG_SYS_FLASH_BASE; |
49822e23 WD |
91 | |
92 | flash_preinit(); | |
efa329cb | 93 | |
6d0f6bcf | 94 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
efa329cb WD |
95 | switch (i) { |
96 | case 0: | |
49822e23 WD |
97 | memset(&flash_info[i], 0, sizeof(flash_info_t)); |
98 | flash_get_size ((FPW *) flashbase, &flash_info[i]); | |
99 | flash_get_offsets (flash_info[i].start[0], &flash_info[i]); | |
efa329cb WD |
100 | break; |
101 | default: | |
102 | panic ("configured to many flash banks!\n"); | |
103 | break; | |
104 | } | |
105 | size += flash_info[i].size; | |
010162eb WD |
106 | |
107 | /* get the h/w and s/w protection status in sync */ | |
108 | flash_sync_real_protect(&flash_info[i]); | |
efa329cb WD |
109 | } |
110 | ||
111 | /* Protect monitor and environment sectors | |
112 | */ | |
6d0f6bcf | 113 | #if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE |
49822e23 | 114 | #ifndef CONFIG_BOOT_ROM |
efa329cb | 115 | flash_protect ( FLAG_PROTECT_SET, |
6d0f6bcf JCPV |
116 | CONFIG_SYS_MONITOR_BASE, |
117 | CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, | |
efa329cb | 118 | &flash_info[0] ); |
49822e23 WD |
119 | #endif |
120 | #endif | |
efa329cb | 121 | |
5a1aceb0 | 122 | #ifdef CONFIG_ENV_IS_IN_FLASH |
efa329cb | 123 | flash_protect ( FLAG_PROTECT_SET, |
0e8d1586 JCPV |
124 | CONFIG_ENV_ADDR, |
125 | CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0] ); | |
49822e23 WD |
126 | #endif |
127 | ||
128 | flash_afterinit(flash_info[0].start[0], flash_info[0].size); | |
efa329cb WD |
129 | |
130 | return size; | |
131 | } | |
132 | ||
133 | /*----------------------------------------------------------------------- | |
134 | */ | |
135 | static void flash_get_offsets (ulong base, flash_info_t *info) | |
136 | { | |
137 | int i; | |
138 | ||
139 | if (info->flash_id == FLASH_UNKNOWN) { | |
140 | return; | |
141 | } | |
142 | ||
143 | if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { | |
144 | for (i = 0; i < info->sector_count; i++) { | |
145 | info->start[i] = base + (i * PHYS_FLASH_SECT_SIZE); | |
efa329cb WD |
146 | } |
147 | } | |
148 | } | |
149 | ||
150 | /*----------------------------------------------------------------------- | |
151 | */ | |
152 | void flash_print_info (flash_info_t *info) | |
153 | { | |
154 | int i; | |
155 | ||
156 | if (info->flash_id == FLASH_UNKNOWN) { | |
157 | printf ("missing or unknown FLASH type\n"); | |
158 | return; | |
159 | } | |
160 | ||
161 | switch (info->flash_id & FLASH_VENDMASK) { | |
162 | case FLASH_MAN_INTEL: | |
163 | printf ("INTEL "); | |
164 | break; | |
165 | default: | |
166 | printf ("Unknown Vendor "); | |
167 | break; | |
168 | } | |
169 | ||
170 | switch (info->flash_id & FLASH_TYPEMASK) { | |
c7428d49 WD |
171 | case FLASH_28F256J3A: |
172 | printf ("28F256J3A\n"); | |
173 | break; | |
174 | ||
efa329cb WD |
175 | case FLASH_28F128J3A: |
176 | printf ("28F128J3A\n"); | |
177 | break; | |
178 | ||
179 | case FLASH_28F640J3A: | |
180 | printf ("28F640J3A\n"); | |
181 | break; | |
182 | ||
183 | case FLASH_28F320J3A: | |
184 | printf ("28F320J3A\n"); | |
185 | break; | |
186 | ||
187 | default: | |
188 | printf ("Unknown Chip Type\n"); | |
189 | break; | |
190 | } | |
191 | ||
192 | printf (" Size: %ld MB in %d Sectors\n", | |
193 | info->size >> 20, info->sector_count); | |
194 | ||
195 | printf (" Sector Start Addresses:"); | |
196 | for (i = 0; i < info->sector_count; ++i) { | |
197 | if ((i % 5) == 0) | |
198 | printf ("\n "); | |
199 | printf (" %08lX%s", | |
200 | info->start[i], | |
201 | info->protect[i] ? " (RO)" : " "); | |
202 | } | |
203 | printf ("\n"); | |
204 | return; | |
205 | } | |
206 | ||
207 | /* | |
208 | * The following code cannot be run from FLASH! | |
209 | */ | |
210 | static ulong flash_get_size (FPW *addr, flash_info_t *info) | |
211 | { | |
212 | volatile FPW value; | |
213 | ||
214 | /* Write auto select command: read Manufacturer ID */ | |
215 | addr[0x5555] = (FPW) 0x00AA00AA; | |
216 | addr[0x2AAA] = (FPW) 0x00550055; | |
217 | addr[0x5555] = (FPW) 0x00900090; | |
218 | ||
219 | mb (); | |
49822e23 WD |
220 | udelay(100); |
221 | ||
efa329cb WD |
222 | value = addr[0]; |
223 | ||
224 | switch (value) { | |
225 | ||
226 | case (FPW) INTEL_MANUFACT: | |
227 | info->flash_id = FLASH_MAN_INTEL; | |
228 | break; | |
229 | ||
230 | default: | |
231 | info->flash_id = FLASH_UNKNOWN; | |
232 | info->sector_count = 0; | |
233 | info->size = 0; | |
234 | addr[0] = (FPW) 0x00FF00FF; /* restore read mode */ | |
235 | return (0); /* no or unknown flash */ | |
236 | } | |
237 | ||
238 | mb (); | |
239 | value = addr[1]; /* device ID */ | |
240 | ||
241 | switch (value) { | |
242 | ||
c7428d49 WD |
243 | case (FPW) INTEL_ID_28F256J3A: |
244 | info->flash_id += FLASH_28F256J3A; | |
c4b465f6 WD |
245 | /* In U-Boot we support only 32 MB (no bank-switching) */ |
246 | info->sector_count = 256 / 2; | |
247 | info->size = 0x04000000 / 2; | |
6d0f6bcf | 248 | info->start[0] = CONFIG_SYS_FLASH_BASE + 0x02000000; |
c4b465f6 | 249 | break; /* => 32 MB */ |
c7428d49 | 250 | |
efa329cb WD |
251 | case (FPW) INTEL_ID_28F128J3A: |
252 | info->flash_id += FLASH_28F128J3A; | |
253 | info->sector_count = 128; | |
254 | info->size = 0x02000000; | |
6d0f6bcf | 255 | info->start[0] = CONFIG_SYS_FLASH_BASE + 0x02000000; |
efa329cb WD |
256 | break; /* => 32 MB */ |
257 | ||
258 | case (FPW) INTEL_ID_28F640J3A: | |
259 | info->flash_id += FLASH_28F640J3A; | |
260 | info->sector_count = 64; | |
261 | info->size = 0x01000000; | |
6d0f6bcf | 262 | info->start[0] = CONFIG_SYS_FLASH_BASE + 0x03000000; |
efa329cb WD |
263 | break; /* => 16 MB */ |
264 | ||
265 | case (FPW) INTEL_ID_28F320J3A: | |
266 | info->flash_id += FLASH_28F320J3A; | |
267 | info->sector_count = 32; | |
49822e23 | 268 | info->size = 0x800000; |
6d0f6bcf | 269 | info->start[0] = CONFIG_SYS_FLASH_BASE + 0x03800000; |
efa329cb WD |
270 | break; /* => 8 MB */ |
271 | ||
272 | default: | |
273 | info->flash_id = FLASH_UNKNOWN; | |
274 | break; | |
275 | } | |
276 | ||
6d0f6bcf | 277 | if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) { |
efa329cb | 278 | printf ("** ERROR: sector count %d > max (%d) **\n", |
6d0f6bcf JCPV |
279 | info->sector_count, CONFIG_SYS_MAX_FLASH_SECT); |
280 | info->sector_count = CONFIG_SYS_MAX_FLASH_SECT; | |
efa329cb WD |
281 | } |
282 | ||
283 | addr[0] = (FPW) 0x00FF00FF; /* restore read mode */ | |
284 | ||
285 | return (info->size); | |
286 | } | |
287 | ||
288 | ||
010162eb WD |
289 | /* |
290 | * This function gets the u-boot flash sector protection status | |
291 | * (flash_info_t.protect[]) in sync with the sector protection | |
292 | * status stored in hardware. | |
293 | */ | |
294 | static void flash_sync_real_protect (flash_info_t * info) | |
295 | { | |
296 | int i; | |
297 | ||
298 | switch (info->flash_id & FLASH_TYPEMASK) { | |
299 | ||
c7428d49 | 300 | case FLASH_28F256J3A: |
010162eb WD |
301 | case FLASH_28F128J3A: |
302 | case FLASH_28F640J3A: | |
303 | case FLASH_28F320J3A: | |
304 | for (i = 0; i < info->sector_count; ++i) { | |
305 | info->protect[i] = intel_sector_protected(info, i); | |
306 | } | |
307 | break; | |
308 | default: | |
309 | /* no h/w protect support */ | |
310 | break; | |
311 | } | |
312 | } | |
313 | ||
314 | ||
315 | /* | |
316 | * checks if "sector" in bank "info" is protected. Should work on intel | |
317 | * strata flash chips 28FxxxJ3x in 8-bit mode. | |
318 | * Returns 1 if sector is protected (or timed-out while trying to read | |
319 | * protection status), 0 if it is not. | |
320 | */ | |
321 | static unsigned char intel_sector_protected (flash_info_t *info, ushort sector) | |
322 | { | |
323 | FPWV *addr; | |
324 | FPWV *lock_conf_addr; | |
325 | ulong start; | |
326 | unsigned char ret; | |
327 | ||
328 | /* | |
329 | * first, wait for the WSM to be finished. The rationale for | |
330 | * waiting for the WSM to become idle for at most | |
6d0f6bcf | 331 | * CONFIG_SYS_FLASH_ERASE_TOUT is as follows. The WSM can be busy |
010162eb WD |
332 | * because of: (1) erase, (2) program or (3) lock bit |
333 | * configuration. So we just wait for the longest timeout of | |
334 | * the (1)-(3), i.e. the erase timeout. | |
335 | */ | |
336 | ||
337 | /* wait at least 35ns (W12) before issuing Read Status Register */ | |
338 | udelay(1); | |
339 | addr = (FPWV *) info->start[sector]; | |
340 | *addr = (FPW) INTEL_STATUS; | |
341 | ||
342 | start = get_timer (0); | |
343 | while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) { | |
6d0f6bcf | 344 | if (get_timer (start) > CONFIG_SYS_FLASH_ERASE_TOUT) { |
010162eb WD |
345 | *addr = (FPW) INTEL_RESET; /* restore read mode */ |
346 | printf("WSM busy too long, can't get prot status\n"); | |
347 | return 1; | |
348 | } | |
349 | } | |
095b8a37 | 350 | |
010162eb WD |
351 | /* issue the Read Identifier Codes command */ |
352 | *addr = (FPW) INTEL_READID; | |
353 | ||
354 | /* wait at least 35ns (W12) before reading */ | |
355 | udelay(1); | |
356 | ||
357 | /* Intel example code uses offset of 2 for 16 bit flash */ | |
358 | lock_conf_addr = (FPWV *) info->start[sector] + 2; | |
359 | ret = (*lock_conf_addr & (FPW) INTEL_PROTECT) ? 1 : 0; | |
360 | ||
361 | /* put flash back in read mode */ | |
362 | *addr = (FPW) INTEL_RESET; | |
363 | ||
364 | return ret; | |
365 | } | |
366 | ||
efa329cb WD |
367 | /*----------------------------------------------------------------------- |
368 | */ | |
369 | ||
370 | int flash_erase (flash_info_t *info, int s_first, int s_last) | |
371 | { | |
372 | int flag, prot, sect; | |
373 | ulong type, start, last; | |
374 | int rcode = 0; | |
375 | ||
376 | if ((s_first < 0) || (s_first > s_last)) { | |
377 | if (info->flash_id == FLASH_UNKNOWN) { | |
378 | printf ("- missing\n"); | |
379 | } else { | |
380 | printf ("- no sectors to erase\n"); | |
381 | } | |
382 | return 1; | |
383 | } | |
384 | ||
385 | type = (info->flash_id & FLASH_VENDMASK); | |
386 | if ((type != FLASH_MAN_INTEL)) { | |
387 | printf ("Can't erase unknown flash type %08lx - aborted\n", | |
388 | info->flash_id); | |
389 | return 1; | |
390 | } | |
391 | ||
392 | prot = 0; | |
393 | for (sect = s_first; sect <= s_last; ++sect) { | |
394 | if (info->protect[sect]) { | |
395 | prot++; | |
396 | } | |
397 | } | |
398 | ||
399 | if (prot) { | |
400 | printf ("- Warning: %d protected sectors will not be erased!\n", | |
401 | prot); | |
402 | } else { | |
403 | printf ("\n"); | |
404 | } | |
405 | ||
406 | start = get_timer (0); | |
407 | last = start; | |
408 | ||
409 | /* Disable interrupts which might cause a timeout here */ | |
410 | flag = disable_interrupts (); | |
411 | ||
412 | /* Start erase on unprotected sectors */ | |
413 | for (sect = s_first; sect <= s_last; sect++) { | |
414 | if (info->protect[sect] == 0) { /* not protected */ | |
415 | FPWV *addr = (FPWV *) (info->start[sect]); | |
416 | FPW status; | |
417 | ||
418 | printf ("Erasing sector %2d ... ", sect); | |
419 | ||
420 | /* arm simple, non interrupt dependent timer */ | |
421 | start = get_timer(0); | |
422 | ||
423 | *addr = (FPW) 0x00500050; /* clear status register */ | |
424 | *addr = (FPW) 0x00200020; /* erase setup */ | |
425 | *addr = (FPW) 0x00D000D0; /* erase confirm */ | |
426 | ||
427 | while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) { | |
6d0f6bcf | 428 | if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT) { |
efa329cb WD |
429 | printf ("Timeout\n"); |
430 | *addr = (FPW) 0x00B000B0; /* suspend erase */ | |
431 | *addr = (FPW) 0x00FF00FF; /* reset to read mode */ | |
432 | rcode = 1; | |
433 | break; | |
434 | } | |
435 | } | |
436 | ||
437 | *addr = 0x00500050; /* clear status register cmd. */ | |
438 | *addr = 0x00FF00FF; /* resest to read mode */ | |
439 | ||
440 | printf (" done\n"); | |
441 | } | |
442 | } | |
443 | return rcode; | |
444 | } | |
445 | ||
446 | /*----------------------------------------------------------------------- | |
447 | * Copy memory to flash, returns: | |
448 | * 0 - OK | |
449 | * 1 - write timeout | |
450 | * 2 - Flash not erased | |
451 | * 4 - Flash not identified | |
452 | */ | |
453 | ||
454 | int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
455 | { | |
456 | ulong cp, wp; | |
457 | FPW data; | |
458 | int count, i, l, rc, port_width; | |
459 | ||
460 | if (info->flash_id == FLASH_UNKNOWN) { | |
461 | return 4; | |
462 | } | |
463 | /* get lower word aligned address */ | |
464 | #ifdef FLASH_PORT_WIDTH16 | |
465 | wp = (addr & ~1); | |
466 | port_width = 2; | |
467 | #else | |
468 | wp = (addr & ~3); | |
469 | port_width = 4; | |
470 | #endif | |
471 | ||
472 | /* | |
473 | * handle unaligned start bytes | |
474 | */ | |
475 | if ((l = addr - wp) != 0) { | |
476 | data = 0; | |
477 | for (i = 0, cp = wp; i < l; ++i, ++cp) { | |
478 | data = (data << 8) | (*(uchar *) cp); | |
479 | } | |
480 | for (; i < port_width && cnt > 0; ++i) { | |
481 | data = (data << 8) | *src++; | |
482 | --cnt; | |
483 | ++cp; | |
484 | } | |
485 | for (; cnt == 0 && i < port_width; ++i, ++cp) { | |
486 | data = (data << 8) | (*(uchar *) cp); | |
487 | } | |
488 | ||
489 | if ((rc = write_data (info, wp, SWAP (data))) != 0) { | |
490 | return (rc); | |
491 | } | |
492 | wp += port_width; | |
493 | } | |
494 | ||
495 | /* | |
496 | * handle word aligned part | |
497 | */ | |
498 | count = 0; | |
499 | while (cnt >= port_width) { | |
500 | data = 0; | |
501 | for (i = 0; i < port_width; ++i) { | |
502 | data = (data << 8) | *src++; | |
503 | } | |
504 | if ((rc = write_data (info, wp, SWAP (data))) != 0) { | |
505 | return (rc); | |
506 | } | |
507 | wp += port_width; | |
508 | cnt -= port_width; | |
509 | if (count++ > 0x800) { | |
510 | spin_wheel (); | |
511 | count = 0; | |
512 | } | |
513 | } | |
514 | ||
515 | if (cnt == 0) { | |
516 | return (0); | |
517 | } | |
518 | ||
519 | /* | |
520 | * handle unaligned tail bytes | |
521 | */ | |
522 | data = 0; | |
523 | for (i = 0, cp = wp; i < port_width && cnt > 0; ++i, ++cp) { | |
524 | data = (data << 8) | *src++; | |
525 | --cnt; | |
526 | } | |
527 | for (; i < port_width; ++i, ++cp) { | |
528 | data = (data << 8) | (*(uchar *) cp); | |
529 | } | |
530 | ||
531 | return (write_data (info, wp, SWAP (data))); | |
532 | } | |
533 | ||
534 | /*----------------------------------------------------------------------- | |
535 | * Write a word or halfword to Flash, returns: | |
536 | * 0 - OK | |
537 | * 1 - write timeout | |
538 | * 2 - Flash not erased | |
539 | */ | |
540 | static int write_data (flash_info_t *info, ulong dest, FPW data) | |
541 | { | |
542 | FPWV *addr = (FPWV *) dest; | |
543 | ulong status; | |
544 | ulong start; | |
545 | int flag; | |
546 | ||
547 | /* Check if Flash is (sufficiently) erased */ | |
548 | if ((*addr & data) != data) { | |
549 | printf ("not erased at %08lx (%lx)\n", (ulong) addr, *addr); | |
550 | return (2); | |
551 | } | |
552 | /* Disable interrupts which might cause a timeout here */ | |
553 | flag = disable_interrupts (); | |
554 | ||
555 | *addr = (FPW) 0x00400040; /* write setup */ | |
556 | *addr = data; | |
557 | ||
558 | /* arm simple, non interrupt dependent timer */ | |
559 | start = get_timer(0); | |
560 | ||
561 | /* wait while polling the status register */ | |
562 | while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) { | |
6d0f6bcf | 563 | if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
efa329cb WD |
564 | *addr = (FPW) 0x00FF00FF; /* restore read mode */ |
565 | return (1); | |
566 | } | |
567 | } | |
568 | ||
569 | *addr = (FPW) 0x00FF00FF; /* restore read mode */ | |
570 | ||
571 | return (0); | |
572 | } | |
573 | ||
574 | void inline spin_wheel (void) | |
575 | { | |
576 | static int p = 0; | |
577 | static char w[] = "\\/-"; | |
578 | ||
579 | printf ("\010%c", w[p]); | |
580 | (++p == 3) ? (p = 0) : 0; | |
581 | } | |
582 | ||
583 | /*----------------------------------------------------------------------- | |
584 | * Set/Clear sector's lock bit, returns: | |
585 | * 0 - OK | |
586 | * 1 - Error (timeout, voltage problems, etc.) | |
587 | */ | |
010162eb | 588 | int flash_real_protect (flash_info_t *info, long sector, int prot) |
efa329cb WD |
589 | { |
590 | ulong start; | |
591 | int i; | |
592 | int rc = 0; | |
593 | vu_long *addr = (vu_long *)(info->start[sector]); | |
594 | int flag = disable_interrupts(); | |
595 | ||
596 | *addr = INTEL_CLEAR; /* Clear status register */ | |
597 | if (prot) { /* Set sector lock bit */ | |
598 | *addr = INTEL_LOCKBIT; /* Sector lock bit */ | |
599 | *addr = INTEL_PROTECT; /* set */ | |
600 | } | |
601 | else { /* Clear sector lock bit */ | |
602 | *addr = INTEL_LOCKBIT; /* All sectors lock bits */ | |
603 | *addr = INTEL_CONFIRM; /* clear */ | |
604 | } | |
605 | ||
606 | start = get_timer(0); | |
607 | ||
608 | while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) { | |
6d0f6bcf | 609 | if (get_timer(start) > CONFIG_SYS_FLASH_UNLOCK_TOUT) { |
efa329cb WD |
610 | printf("Flash lock bit operation timed out\n"); |
611 | rc = 1; | |
612 | break; | |
613 | } | |
614 | } | |
615 | ||
616 | if (*addr != INTEL_OK) { | |
617 | printf("Flash lock bit operation failed at %08X, CSR=%08X\n", | |
618 | (uint)addr, (uint)*addr); | |
619 | rc = 1; | |
620 | } | |
621 | ||
622 | if (!rc) | |
623 | info->protect[sector] = prot; | |
624 | ||
625 | /* | |
626 | * Clear lock bit command clears all sectors lock bits, so | |
627 | * we have to restore lock bits of protected sectors. | |
010162eb WD |
628 | * WARNING: code below re-locks sectors only for one bank (info). |
629 | * This causes problems on boards where several banks share | |
630 | * the same chip, as sectors in othere banks will be unlocked | |
631 | * but not re-locked. It works fine on pm520 though, as there | |
632 | * is only one chip and one bank. | |
efa329cb WD |
633 | */ |
634 | if (!prot) | |
635 | { | |
636 | for (i = 0; i < info->sector_count; i++) | |
637 | { | |
638 | if (info->protect[i]) | |
639 | { | |
640 | start = get_timer(0); | |
641 | addr = (vu_long *)(info->start[i]); | |
642 | *addr = INTEL_LOCKBIT; /* Sector lock bit */ | |
643 | *addr = INTEL_PROTECT; /* set */ | |
644 | while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) | |
645 | { | |
6d0f6bcf | 646 | if (get_timer(start) > CONFIG_SYS_FLASH_UNLOCK_TOUT) |
efa329cb WD |
647 | { |
648 | printf("Flash lock bit operation timed out\n"); | |
649 | rc = 1; | |
650 | break; | |
651 | } | |
652 | } | |
653 | } | |
654 | } | |
010162eb WD |
655 | /* |
656 | * get the s/w sector protection status in sync with the h/w, | |
657 | * in case something went wrong during the re-locking. | |
658 | */ | |
659 | flash_sync_real_protect(info); /* resets flash to read mode */ | |
efa329cb WD |
660 | } |
661 | ||
662 | if (flag) | |
663 | enable_interrupts(); | |
664 | ||
665 | *addr = INTEL_RESET; /* Reset to read array mode */ | |
666 | ||
667 | return rc; | |
668 | } |