blob: 26579588dd951bc4fec46e39f7f3d1c8a569a910 [file] [log] [blame]
wdenk9f837932003-10-09 19:00:25 +00001/*
2 * board/eva/flash.c
3 *
4 * (C) Copyright 2002
5 * Sangmoon Kim, Etin Systems, dogoil@etinsys.com.
6 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
wdenk9f837932003-10-09 19:00:25 +00008 */
9
10#include <common.h>
11#include <asm/processor.h>
12#include <asm/pci_io.h>
13#include <mpc824x.h>
Becky Brucedad8c912009-02-03 18:10:51 -060014#include <asm/mmu.h>
wdenk9f837932003-10-09 19:00:25 +000015
16int (*do_flash_erase)(flash_info_t*, uint32_t, uint32_t);
17int (*write_dword)(flash_info_t*, ulong, uint64_t);
18
19typedef 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
29static void write32(unsigned long addr, uint32_t value)
30{
31 *(volatile uint32_t*)(addr) = value;
32 asm volatile("sync");
33}
34
35static 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
43static 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
52static 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
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020059flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenk9f837932003-10-09 19:00:25 +000060
61static 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
69static 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;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020087 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenk9f837932003-10-09 19:00:25 +000088 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
98static 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) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200116 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT)
wdenk9f837932003-10-09 19:00:25 +0000117 return 1;
118 status = cfi_read(flash, dest);
119 udelay(1);
120 }
121 return 0;
122}
123
124static __inline__ unsigned long get_msr(void)
125{
126 unsigned long msr;
127 __asm__ __volatile__ ("mfmsr %0" : "=r" (msr) :);
128 return msr;
129}
130
131static __inline__ void set_msr(unsigned long msr)
132{
133 __asm__ __volatile__ ("mtmsr %0" : : "r" (msr));
134}
135
136int 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);
188DONE:
189 set_msr(msr);
190 return rc;
191}
192
193static 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;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200218 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenk9f837932003-10-09 19:00:25 +0000219 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
234static 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
249static 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
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200284 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenk9f837932003-10-09 19:00:25 +0000285 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 }
295DONE:
296 cfi_cmd(flash, 0xf0, 0);
297
298 printf (" done\n");
299
300 return ERR_OK;
301}
302
303int 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",
Wolfgang Denkec7fbf52013-10-04 17:43:24 +0200326 prot);
wdenk9f837932003-10-09 19:00:25 +0000327 else
328 printf ("\n");
329
330 return do_flash_erase(flash, s_first, s_last);
331}
332
333struct 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
349static 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),
Wolfgang Denkec7fbf52013-10-04 17:43:24 +0200368 ERASEINFO(0x08000,1),
wdenk9f837932003-10-09 19:00:25 +0000369 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),
Wolfgang Denkec7fbf52013-10-04 17:43:24 +0200379 ERASEINFO(0x08000,1),
wdenk9f837932003-10-09 19:00:25 +0000380 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),
Wolfgang Denkec7fbf52013-10-04 17:43:24 +0200390 ERASEINFO(0x02000,2),
wdenk9f837932003-10-09 19:00:25 +0000391 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),
Wolfgang Denkec7fbf52013-10-04 17:43:24 +0200401 ERASEINFO(0x02000,8)
wdenk9f837932003-10-09 19:00:25 +0000402 }
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),
Wolfgang Denkec7fbf52013-10-04 17:43:24 +0200411 ERASEINFO(0x10000,63)
wdenk9f837932003-10-09 19:00:25 +0000412 }
413 }
414};
415
416static 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
484static 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
532inline void mtibat1u(unsigned int x)
533{
534 __asm__ __volatile__ ("mtspr 530, %0" :: "r" (x));
535}
536
537inline void mtibat1l(unsigned int x)
538{
539 __asm__ __volatile__ ("mtspr 531, %0" :: "r" (x));
540}
541
542inline void mtdbat1u(unsigned int x)
543{
544 __asm__ __volatile__ ("mtspr 538, %0" :: "r" (x));
545}
546
547inline void mtdbat1l(unsigned int x)
548{
549 __asm__ __volatile__ ("mtspr 539, %0" :: "r" (x));
550}
551
552unsigned 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
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200569 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++)
wdenk9f837932003-10-09 19:00:25 +0000570 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
582void 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}