flash.c 15 KB

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