]>
Commit | Line | Data |
---|---|---|
15647dc7 WD |
1 | /* |
2 | * board/eva/flash.c | |
3 | * | |
4 | * (C) Copyright 2002 | |
5 | * Sangmoon Kim, Etin Systems, dogoil@etinsys.com. | |
6 | * | |
1a459660 | 7 | * SPDX-License-Identifier: GPL-2.0+ |
15647dc7 WD |
8 | */ |
9 | ||
10 | #include <common.h> | |
11 | #include <asm/processor.h> | |
12 | #include <asm/pci_io.h> | |
13 | #include <mpc824x.h> | |
d35ae5a9 | 14 | #include <asm/mmu.h> |
15647dc7 WD |
15 | |
16 | int (*do_flash_erase)(flash_info_t*, uint32_t, uint32_t); | |
17 | int (*write_dword)(flash_info_t*, ulong, uint64_t); | |
18 | ||
19 | typedef uint64_t cfi_word; | |
20 | ||
21 | #define cfi_read(flash, addr) *((volatile cfi_word*)(flash->start[0] + addr)) | |
22 | ||
23 | #define cfi_write(flash, val, addr) \ | |
24 | move64((cfi_word*)&val, \ | |
25 | (cfi_word*)(flash->start[0] + addr)) | |
26 | ||
27 | #define CMD(x) ((((cfi_word)x)<<48)|(((cfi_word)x)<<32)|(((cfi_word)x)<<16)|(((cfi_word)x))) | |
28 | ||
29 | static void write32(unsigned long addr, uint32_t value) | |
30 | { | |
31 | *(volatile uint32_t*)(addr) = value; | |
32 | asm volatile("sync"); | |
33 | } | |
34 | ||
35 | static uint32_t read32(unsigned long addr) | |
36 | { | |
37 | uint32_t value; | |
38 | value = *(volatile uint32_t*)addr; | |
39 | asm volatile("sync"); | |
40 | return value; | |
41 | } | |
42 | ||
43 | static cfi_word cfi_cmd(flash_info_t *flash, uint8_t cmd, uint32_t addr) | |
44 | { | |
45 | uint32_t base = flash->start[0]; | |
46 | uint32_t val=(cmd << 16) | cmd; | |
47 | addr <<= 3; | |
48 | write32(base + addr, val); | |
49 | return addr; | |
50 | } | |
51 | ||
52 | static uint16_t cfi_read_query(flash_info_t *flash, uint32_t addr) | |
53 | { | |
54 | uint32_t base = flash->start[0]; | |
55 | addr <<= 3; | |
56 | return (uint16_t)read32(base + addr); | |
57 | } | |
58 | ||
6d0f6bcf | 59 | flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */ |
15647dc7 WD |
60 | |
61 | static void move64(uint64_t *src, uint64_t *dest) | |
62 | { | |
63 | asm volatile("lfd 0, 0(3)\n\t" /* fpr0 = *scr */ | |
64 | "stfd 0, 0(4)" /* *dest = fpr0 */ | |
65 | : : : "fr0" ); /* Clobbers fr0 */ | |
66 | return; | |
67 | } | |
68 | ||
69 | static int cfi_write_dword(flash_info_t *flash, ulong dest, cfi_word data) | |
70 | { | |
71 | unsigned long start; | |
72 | cfi_word status = 0; | |
73 | ||
74 | status = cfi_read(flash, dest); | |
75 | data &= status; | |
76 | ||
77 | cfi_cmd(flash, 0x40, 0); | |
78 | cfi_write(flash, data, dest); | |
79 | ||
80 | udelay(10); | |
81 | start = get_timer (0); | |
82 | for(;;) { | |
83 | status = cfi_read(flash, dest); | |
84 | status &= CMD(0x80); | |
85 | if(status == CMD(0x80)) | |
86 | break; | |
6d0f6bcf | 87 | if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) { |
15647dc7 WD |
88 | cfi_cmd(flash, 0xff, 0); |
89 | return 1; | |
90 | } | |
91 | udelay(1); | |
92 | } | |
93 | cfi_cmd(flash, 0xff, 0); | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
98 | static int jedec_write_dword (flash_info_t *flash, ulong dest, cfi_word data) | |
99 | { | |
100 | ulong start; | |
101 | cfi_word status = 0; | |
102 | ||
103 | status = cfi_read(flash, dest); | |
104 | if(status != CMD(0xffff)) return 2; | |
105 | ||
106 | cfi_cmd(flash, 0xaa, 0x555); | |
107 | cfi_cmd(flash, 0x55, 0x2aa); | |
108 | cfi_cmd(flash, 0xa0, 0x555); | |
109 | ||
110 | cfi_write(flash, data, dest); | |
111 | ||
112 | udelay(10); | |
113 | start = get_timer (0); | |
114 | status = ~data; | |
115 | while(status != data) { | |
6d0f6bcf | 116 | if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) |
15647dc7 WD |
117 | return 1; |
118 | status = cfi_read(flash, dest); | |
119 | udelay(1); | |
120 | } | |
121 | return 0; | |
122 | } | |
123 | ||
124 | static __inline__ unsigned long get_msr(void) | |
125 | { | |
126 | unsigned long msr; | |
127 | __asm__ __volatile__ ("mfmsr %0" : "=r" (msr) :); | |
128 | return msr; | |
129 | } | |
130 | ||
131 | static __inline__ void set_msr(unsigned long msr) | |
132 | { | |
133 | __asm__ __volatile__ ("mtmsr %0" : : "r" (msr)); | |
134 | } | |
135 | ||
136 | int write_buff (flash_info_t *flash, uchar *src, ulong addr, ulong cnt) | |
137 | { | |
138 | ulong wp; | |
139 | int i, s, l, rc; | |
140 | cfi_word data; | |
141 | uint8_t *t = (uint8_t*)&data; | |
142 | unsigned long base = flash->start[0]; | |
143 | uint32_t msr; | |
144 | ||
145 | if (flash->flash_id == FLASH_UNKNOWN) | |
146 | return 4; | |
147 | ||
148 | if (cnt == 0) | |
149 | return 0; | |
150 | ||
151 | addr -= base; | |
152 | ||
153 | msr = get_msr(); | |
154 | set_msr(msr|MSR_FP); | |
155 | ||
156 | wp = (addr & ~7); /* get lower word aligned address */ | |
157 | ||
158 | if((addr-wp) != 0) { | |
159 | data = cfi_read(flash, wp); | |
160 | s = addr & 7; | |
161 | l = ( cnt < (8-s) ) ? cnt : (8-s); | |
162 | for(i = 0; i < l; i++) | |
163 | t[s+i] = *src++; | |
164 | if ((rc = write_dword(flash, wp, data)) != 0) | |
165 | goto DONE; | |
166 | wp += 8; | |
167 | cnt -= l; | |
168 | } | |
169 | ||
170 | while (cnt >= 8) { | |
171 | for (i = 0; i < 8; i++) | |
172 | t[i] = *src++; | |
173 | if ((rc = write_dword(flash, wp, data)) != 0) | |
174 | goto DONE; | |
175 | wp += 8; | |
176 | cnt -= 8; | |
177 | } | |
178 | ||
179 | if (cnt == 0) { | |
180 | rc = 0; | |
181 | goto DONE; | |
182 | } | |
183 | ||
184 | data = cfi_read(flash, wp); | |
185 | for(i = 0; i < cnt; i++) | |
186 | t[i] = *src++; | |
187 | rc = write_dword(flash, wp, data); | |
188 | DONE: | |
189 | set_msr(msr); | |
190 | return rc; | |
191 | } | |
192 | ||
193 | static int cfi_erase_oneblock(flash_info_t *flash, uint32_t sect) | |
194 | { | |
195 | int sa; | |
196 | int flag; | |
197 | ulong start, last, now; | |
198 | cfi_word status; | |
199 | ||
200 | flag = disable_interrupts(); | |
201 | ||
202 | sa = (flash->start[sect] - flash->start[0]); | |
203 | write32(flash->start[sect], 0x00200020); | |
204 | write32(flash->start[sect], 0x00d000d0); | |
205 | ||
206 | if (flag) | |
207 | enable_interrupts(); | |
208 | ||
209 | udelay(1000); | |
210 | start = get_timer (0); | |
211 | last = start; | |
212 | ||
213 | for (;;) { | |
214 | status = cfi_read(flash, sa); | |
215 | status &= CMD(0x80); | |
216 | if (status == CMD(0x80)) | |
217 | break; | |
6d0f6bcf | 218 | if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) { |
15647dc7 WD |
219 | cfi_cmd(flash, 0xff, 0); |
220 | printf ("Timeout\n"); | |
221 | return ERR_TIMOUT; | |
222 | } | |
223 | ||
224 | if ((now - last) > 1000) { | |
225 | serial_putc ('.'); | |
226 | last = now; | |
227 | } | |
228 | udelay(10); | |
229 | } | |
230 | cfi_cmd(flash, 0xff, 0); | |
231 | return ERR_OK; | |
232 | } | |
233 | ||
234 | static int cfi_erase(flash_info_t *flash, uint32_t s_first, uint32_t s_last) | |
235 | { | |
236 | int sect; | |
237 | int rc = ERR_OK; | |
238 | ||
239 | for (sect = s_first; sect <= s_last; sect++) { | |
240 | if (flash->protect[sect] == 0) { | |
241 | rc = cfi_erase_oneblock(flash, sect); | |
242 | if (rc != ERR_OK) break; | |
243 | } | |
244 | } | |
245 | printf (" done\n"); | |
246 | return rc; | |
247 | } | |
248 | ||
249 | static int jedec_erase(flash_info_t *flash, uint32_t s_first, uint32_t s_last) | |
250 | { | |
251 | int sect; | |
252 | cfi_word status; | |
253 | int sa = -1; | |
254 | int flag; | |
255 | ulong start, last, now; | |
256 | ||
257 | flag = disable_interrupts(); | |
258 | ||
259 | cfi_cmd(flash, 0xaa, 0x555); | |
260 | cfi_cmd(flash, 0x55, 0x2aa); | |
261 | cfi_cmd(flash, 0x80, 0x555); | |
262 | cfi_cmd(flash, 0xaa, 0x555); | |
263 | cfi_cmd(flash, 0x55, 0x2aa); | |
264 | for ( sect = s_first; sect <= s_last; sect++) { | |
265 | if (flash->protect[sect] == 0) { | |
266 | sa = flash->start[sect] - flash->start[0]; | |
267 | write32(flash->start[sect], 0x00300030); | |
268 | } | |
269 | } | |
270 | if (flag) | |
271 | enable_interrupts(); | |
272 | ||
273 | if (sa < 0) | |
274 | goto DONE; | |
275 | ||
276 | udelay (1000); | |
277 | start = get_timer (0); | |
278 | last = start; | |
279 | for(;;) { | |
280 | status = cfi_read(flash, sa); | |
281 | if (status == CMD(0xffff)) | |
282 | break; | |
283 | ||
6d0f6bcf | 284 | if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) { |
15647dc7 WD |
285 | printf ("Timeout\n"); |
286 | return ERR_TIMOUT; | |
287 | } | |
288 | ||
289 | if ((now - last) > 1000) { | |
290 | serial_putc ('.'); | |
291 | last = now; | |
292 | } | |
293 | udelay(10); | |
294 | } | |
295 | DONE: | |
296 | cfi_cmd(flash, 0xf0, 0); | |
297 | ||
298 | printf (" done\n"); | |
299 | ||
300 | return ERR_OK; | |
301 | } | |
302 | ||
303 | int flash_erase (flash_info_t *flash, int s_first, int s_last) | |
304 | { | |
305 | int sect; | |
306 | int prot; | |
307 | ||
308 | if ((s_first < 0) || (s_first > s_last)) { | |
309 | if (flash->flash_id == FLASH_UNKNOWN) | |
310 | printf ("- missing\n"); | |
311 | else | |
312 | printf ("- no sectors to erase\n"); | |
313 | return ERR_NOT_ERASED; | |
314 | } | |
315 | if (flash->flash_id == FLASH_UNKNOWN) { | |
316 | printf ("Can't erase unknown flash type - aborted\n"); | |
317 | return ERR_NOT_ERASED; | |
318 | } | |
319 | ||
320 | prot = 0; | |
321 | for (sect = s_first; sect <= s_last; sect++) | |
322 | if (flash->protect[sect]) prot++; | |
323 | ||
324 | if (prot) | |
325 | printf ("- Warning: %d protected sectors will not be erased!\n", | |
93e14596 | 326 | prot); |
15647dc7 WD |
327 | else |
328 | printf ("\n"); | |
329 | ||
330 | return do_flash_erase(flash, s_first, s_last); | |
331 | } | |
332 | ||
333 | struct jedec_flash_info { | |
334 | const uint16_t mfr_id; | |
335 | const uint16_t dev_id; | |
336 | const char *name; | |
337 | const int DevSize; | |
338 | const int InterfaceDesc; | |
339 | const int NumEraseRegions; | |
340 | const ulong regions[4]; | |
341 | }; | |
342 | ||
343 | #define ERASEINFO(size,blocks) (size<<8)|(blocks-1) | |
344 | ||
345 | #define SIZE_1MiB 20 | |
346 | #define SIZE_2MiB 21 | |
347 | #define SIZE_4MiB 22 | |
348 | ||
349 | static const struct jedec_flash_info jedec_table[] = { | |
350 | { | |
351 | mfr_id: (uint16_t)AMD_MANUFACT, | |
352 | dev_id: (uint16_t)AMD_ID_LV800T, | |
353 | name: "AMD AM29LV800T", | |
354 | DevSize: SIZE_1MiB, | |
355 | NumEraseRegions: 4, | |
356 | regions: {ERASEINFO(0x10000,15), | |
357 | ERASEINFO(0x08000,1), | |
358 | ERASEINFO(0x02000,2), | |
359 | ERASEINFO(0x04000,1) | |
360 | } | |
361 | }, { | |
362 | mfr_id: (uint16_t)AMD_MANUFACT, | |
363 | dev_id: (uint16_t)AMD_ID_LV800B, | |
364 | name: "AMD AM29LV800B", | |
365 | DevSize: SIZE_1MiB, | |
366 | NumEraseRegions: 4, | |
367 | regions: {ERASEINFO(0x10000,15), | |
93e14596 | 368 | ERASEINFO(0x08000,1), |
15647dc7 WD |
369 | ERASEINFO(0x02000,2), |
370 | ERASEINFO(0x04000,1) | |
371 | } | |
372 | }, { | |
373 | mfr_id: (uint16_t)AMD_MANUFACT, | |
374 | dev_id: (uint16_t)AMD_ID_LV160T, | |
375 | name: "AMD AM29LV160T", | |
376 | DevSize: SIZE_2MiB, | |
377 | NumEraseRegions: 4, | |
378 | regions: {ERASEINFO(0x10000,31), | |
93e14596 | 379 | ERASEINFO(0x08000,1), |
15647dc7 WD |
380 | ERASEINFO(0x02000,2), |
381 | ERASEINFO(0x04000,1) | |
382 | } | |
383 | }, { | |
384 | mfr_id: (uint16_t)AMD_MANUFACT, | |
385 | dev_id: (uint16_t)AMD_ID_LV160B, | |
386 | name: "AMD AM29LV160B", | |
387 | DevSize: SIZE_2MiB, | |
388 | NumEraseRegions: 4, | |
389 | regions: {ERASEINFO(0x04000,1), | |
93e14596 | 390 | ERASEINFO(0x02000,2), |
15647dc7 WD |
391 | ERASEINFO(0x08000,1), |
392 | ERASEINFO(0x10000,31) | |
393 | } | |
394 | }, { | |
395 | mfr_id: (uint16_t)AMD_MANUFACT, | |
396 | dev_id: (uint16_t)AMD_ID_LV320T, | |
397 | name: "AMD AM29LV320T", | |
398 | DevSize: SIZE_4MiB, | |
399 | NumEraseRegions: 2, | |
400 | regions: {ERASEINFO(0x10000,63), | |
93e14596 | 401 | ERASEINFO(0x02000,8) |
15647dc7 WD |
402 | } |
403 | ||
404 | }, { | |
405 | mfr_id: (uint16_t)AMD_MANUFACT, | |
406 | dev_id: (uint16_t)AMD_ID_LV320B, | |
407 | name: "AMD AM29LV320B", | |
408 | DevSize: SIZE_4MiB, | |
409 | NumEraseRegions: 2, | |
410 | regions: {ERASEINFO(0x02000,8), | |
93e14596 | 411 | ERASEINFO(0x10000,63) |
15647dc7 WD |
412 | } |
413 | } | |
414 | }; | |
415 | ||
416 | static ulong cfi_init(uint32_t base, flash_info_t *flash) | |
417 | { | |
418 | int sector; | |
419 | int block; | |
420 | int block_count; | |
421 | int offset = 0; | |
422 | int reverse = 0; | |
423 | int primary; | |
424 | int mfr_id; | |
425 | int dev_id; | |
426 | ||
427 | flash->start[0] = base; | |
428 | cfi_cmd(flash, 0xF0, 0); | |
429 | cfi_cmd(flash, 0x98, 0); | |
430 | if ( !( cfi_read_query(flash, 0x10) == 'Q' && | |
431 | cfi_read_query(flash, 0x11) == 'R' && | |
432 | cfi_read_query(flash, 0x12) == 'Y' )) { | |
433 | cfi_cmd(flash, 0xff, 0); | |
434 | return 0; | |
435 | } | |
436 | ||
437 | flash->size = 1 << cfi_read_query(flash, 0x27); | |
438 | flash->size *= 4; | |
439 | block_count = cfi_read_query(flash, 0x2c); | |
440 | primary = cfi_read_query(flash, 0x15); | |
441 | if ( cfi_read_query(flash, primary + 4) == 0x30) | |
442 | reverse = (cfi_read_query(flash, 0x1) & 0x01); | |
443 | else | |
444 | reverse = (cfi_read_query(flash, primary+15) == 3); | |
445 | ||
446 | flash->sector_count = 0; | |
447 | ||
448 | for ( block = reverse ? block_count - 1 : 0; | |
449 | reverse ? block >= 0 : block < block_count; | |
450 | reverse ? block-- : block ++) { | |
451 | int sector_size = | |
452 | (cfi_read_query(flash, 0x2d + block*4+2) | | |
453 | (cfi_read_query(flash, 0x2d + block*4+3) << 8)) << 8; | |
454 | int sector_count = | |
455 | (cfi_read_query(flash, 0x2d + block*4+0) | | |
456 | (cfi_read_query(flash, 0x2d + block*4+1) << 8)) + 1; | |
457 | for(sector = 0; sector < sector_count; sector++) { | |
458 | flash->start[flash->sector_count++] = base + offset; | |
459 | offset += sector_size * 4; | |
460 | } | |
461 | } | |
462 | mfr_id = cfi_read_query(flash, 0x00); | |
463 | dev_id = cfi_read_query(flash, 0x01); | |
464 | ||
465 | cfi_cmd(flash, 0xff, 0); | |
466 | ||
467 | flash->flash_id = (mfr_id << 16) | dev_id; | |
468 | ||
469 | for (sector = 0; sector < flash->sector_count; sector++) { | |
470 | write32(flash->start[sector], 0x00600060); | |
471 | write32(flash->start[sector], 0x00d000d0); | |
472 | } | |
473 | cfi_cmd(flash, 0xff, 0); | |
474 | ||
475 | for (sector = 0; sector < flash->sector_count; sector++) | |
476 | flash->protect[sector] = 0; | |
477 | ||
478 | do_flash_erase = cfi_erase; | |
479 | write_dword = cfi_write_dword; | |
480 | ||
481 | return flash->size; | |
482 | } | |
483 | ||
484 | static ulong jedec_init(unsigned long base, flash_info_t *flash) | |
485 | { | |
486 | int i; | |
487 | int block, block_count; | |
488 | int sector, offset; | |
489 | int mfr_id, dev_id; | |
490 | flash->start[0] = base; | |
491 | cfi_cmd(flash, 0xF0, 0x000); | |
492 | cfi_cmd(flash, 0xAA, 0x555); | |
493 | cfi_cmd(flash, 0x55, 0x2AA); | |
494 | cfi_cmd(flash, 0x90, 0x555); | |
495 | mfr_id = cfi_read_query(flash, 0x000); | |
496 | dev_id = cfi_read_query(flash, 0x0001); | |
497 | cfi_cmd(flash, 0xf0, 0x000); | |
498 | ||
499 | for(i=0; i<sizeof(jedec_table)/sizeof(struct jedec_flash_info); i++) { | |
500 | if((jedec_table[i].mfr_id == mfr_id) && | |
501 | (jedec_table[i].dev_id == dev_id)) { | |
502 | ||
503 | flash->flash_id = (mfr_id << 16) | dev_id; | |
504 | flash->size = 1 << jedec_table[0].DevSize; | |
505 | flash->size *= 4; | |
506 | block_count = jedec_table[i].NumEraseRegions; | |
507 | offset = 0; | |
508 | flash->sector_count = 0; | |
509 | for (block = 0; block < block_count; block++) { | |
510 | int sector_size = jedec_table[i].regions[block]; | |
511 | int sector_count = (sector_size & 0xff) + 1; | |
512 | sector_size >>= 8; | |
513 | for (sector=0; sector<sector_count; sector++) { | |
514 | flash->start[flash->sector_count++] = | |
515 | base + offset; | |
516 | offset += sector_size * 4; | |
517 | } | |
518 | } | |
519 | break; | |
520 | } | |
521 | } | |
522 | ||
523 | for (sector = 0; sector < flash->sector_count; sector++) | |
524 | flash->protect[sector] = 0; | |
525 | ||
526 | do_flash_erase = jedec_erase; | |
527 | write_dword = jedec_write_dword; | |
528 | ||
529 | return flash->size; | |
530 | } | |
531 | ||
532 | inline void mtibat1u(unsigned int x) | |
533 | { | |
534 | __asm__ __volatile__ ("mtspr 530, %0" :: "r" (x)); | |
535 | } | |
536 | ||
537 | inline void mtibat1l(unsigned int x) | |
538 | { | |
539 | __asm__ __volatile__ ("mtspr 531, %0" :: "r" (x)); | |
540 | } | |
541 | ||
542 | inline void mtdbat1u(unsigned int x) | |
543 | { | |
544 | __asm__ __volatile__ ("mtspr 538, %0" :: "r" (x)); | |
545 | } | |
546 | ||
547 | inline void mtdbat1l(unsigned int x) | |
548 | { | |
549 | __asm__ __volatile__ ("mtspr 539, %0" :: "r" (x)); | |
550 | } | |
551 | ||
552 | unsigned long flash_init (void) | |
553 | { | |
554 | unsigned long size = 0; | |
555 | int i; | |
556 | unsigned int msr; | |
557 | ||
558 | /* BAT1 */ | |
559 | CONFIG_WRITE_WORD(ERCR3, 0x0C00000C); | |
560 | CONFIG_WRITE_WORD(ERCR4, 0x0800000C); | |
561 | msr = get_msr(); | |
562 | set_msr(msr & ~(MSR_IR | MSR_DR)); | |
563 | mtibat1l(0x70000000 | BATL_PP_10 | BATL_CACHEINHIBIT); | |
564 | mtibat1u(0x70000000 | BATU_BL_256M | BATU_VS | BATU_VP); | |
565 | mtdbat1l(0x70000000 | BATL_PP_10 | BATL_CACHEINHIBIT); | |
566 | mtdbat1u(0x70000000 | BATU_BL_256M | BATU_VS | BATU_VP); | |
567 | set_msr(msr); | |
568 | ||
6d0f6bcf | 569 | for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) |
15647dc7 WD |
570 | flash_info[i].flash_id = FLASH_UNKNOWN; |
571 | size = cfi_init(FLASH_BASE0_PRELIM, &flash_info[0]); | |
572 | if (!size) | |
573 | size = jedec_init(FLASH_BASE0_PRELIM, &flash_info[0]); | |
574 | ||
575 | if (flash_info[0].flash_id == FLASH_UNKNOWN) | |
576 | printf ("# Unknown FLASH on Bank 1 - Size = 0x%08lx = %ld MB\n", | |
577 | size, size<<20); | |
578 | ||
579 | return size; | |
580 | } | |
581 | ||
582 | void flash_print_info (flash_info_t *flash) | |
583 | { | |
584 | int i; | |
585 | int k; | |
586 | int size; | |
587 | int erased; | |
588 | volatile unsigned long *p; | |
589 | ||
590 | if (flash->flash_id == FLASH_UNKNOWN) { | |
591 | printf ("missing or unknown FLASH type\n"); | |
592 | flash_init(); | |
593 | } | |
594 | ||
595 | if (flash->flash_id == FLASH_UNKNOWN) { | |
596 | printf ("missing or unknown FLASH type\n"); | |
597 | return; | |
598 | } | |
599 | ||
600 | switch (((flash->flash_id) >> 16) & 0xff) { | |
601 | case 0x01: | |
602 | printf ("AMD "); | |
603 | break; | |
604 | case 0x04: | |
605 | printf("FUJITSU "); | |
606 | break; | |
607 | case 0x20: | |
608 | printf("STM "); | |
609 | break; | |
610 | case 0xBF: | |
611 | printf("SST "); | |
612 | break; | |
613 | case 0x89: | |
614 | case 0xB0: | |
615 | printf("INTEL "); | |
616 | break; | |
617 | default: | |
618 | printf ("Unknown Vendor "); | |
619 | break; | |
620 | } | |
621 | ||
622 | switch ((flash->flash_id) & 0xffff) { | |
623 | case (uint16_t)AMD_ID_LV800T: | |
624 | printf ("AM29LV800T\n"); | |
625 | break; | |
626 | case (uint16_t)AMD_ID_LV800B: | |
627 | printf ("AM29LV800B\n"); | |
628 | break; | |
629 | case (uint16_t)AMD_ID_LV160T: | |
630 | printf ("AM29LV160T\n"); | |
631 | break; | |
632 | case (uint16_t)AMD_ID_LV160B: | |
633 | printf ("AM29LV160B\n"); | |
634 | break; | |
635 | case (uint16_t)AMD_ID_LV320T: | |
636 | printf ("AM29LV320T\n"); | |
637 | break; | |
638 | case (uint16_t)AMD_ID_LV320B: | |
639 | printf ("AM29LV320B\n"); | |
640 | break; | |
641 | case (uint16_t)INTEL_ID_28F800C3T: | |
642 | printf ("28F800C3T\n"); | |
643 | break; | |
644 | case (uint16_t)INTEL_ID_28F800C3B: | |
645 | printf ("28F800C3B\n"); | |
646 | break; | |
647 | case (uint16_t)INTEL_ID_28F160C3T: | |
648 | printf ("28F160C3T\n"); | |
649 | break; | |
650 | case (uint16_t)INTEL_ID_28F160C3B: | |
651 | printf ("28F160C3B\n"); | |
652 | break; | |
653 | case (uint16_t)INTEL_ID_28F320C3T: | |
654 | printf ("28F320C3T\n"); | |
655 | break; | |
656 | case (uint16_t)INTEL_ID_28F320C3B: | |
657 | printf ("28F320C3B\n"); | |
658 | break; | |
659 | case (uint16_t)INTEL_ID_28F640C3T: | |
660 | printf ("28F640C3T\n"); | |
661 | break; | |
662 | case (uint16_t)INTEL_ID_28F640C3B: | |
663 | printf ("28F640C3B\n"); | |
664 | break; | |
665 | default: | |
666 | printf ("Unknown Chip Type\n"); | |
667 | break; | |
668 | } | |
669 | ||
670 | if (flash->size >= (1 << 20)) { | |
671 | printf (" Size: %ld MB in %d Sectors\n", | |
672 | flash->size >> 20, flash->sector_count); | |
673 | } else { | |
674 | printf (" Size: %ld kB in %d Sectors\n", | |
675 | flash->size >> 10, flash->sector_count); | |
676 | } | |
677 | ||
678 | printf (" Sector Start Addresses:"); | |
679 | for (i = 0; i < flash->sector_count; ++i) { | |
680 | /* Check if whole sector is erased*/ | |
681 | if (i != (flash->sector_count-1)) | |
682 | size = flash->start[i+1] - flash->start[i]; | |
683 | else | |
684 | size = flash->start[0] + flash->size - flash->start[i]; | |
685 | ||
686 | erased = 1; | |
687 | p = (volatile unsigned long *)flash->start[i]; | |
688 | size = size >> 2; /* divide by 4 for longword access */ | |
689 | for (k=0; k<size; k++) { | |
690 | if (*p++ != 0xffffffff) { | |
691 | erased = 0; | |
692 | break; | |
693 | } | |
694 | } | |
695 | ||
696 | if ((i % 5) == 0) | |
697 | printf ("\n "); | |
698 | ||
699 | printf (" %08lX%s%s", | |
700 | flash->start[i], | |
701 | erased ? " E" : " ", | |
702 | flash->protect[i] ? "RO " : " "); | |
703 | } | |
704 | printf ("\n"); | |
705 | } |