5 * Sangmoon Kim, Etin Systems, dogoil@etinsys.com.
7 * SPDX-License-Identifier: GPL-2.0+
11 #include <asm/processor.h>
12 #include <asm/pci_io.h>
16 int (*do_flash_erase
)(flash_info_t
*, uint32_t, uint32_t);
17 int (*write_dword
)(flash_info_t
*, ulong
, uint64_t);
19 typedef uint64_t cfi_word
;
21 #define cfi_read(flash, addr) *((volatile cfi_word*)(flash->start[0] + addr))
23 #define cfi_write(flash, val, addr) \
24 move64((cfi_word*)&val, \
25 (cfi_word*)(flash->start[0] + addr))
27 #define CMD(x) ((((cfi_word)x)<<48)|(((cfi_word)x)<<32)|(((cfi_word)x)<<16)|(((cfi_word)x)))
29 static void write32(unsigned long addr
, uint32_t value
)
31 *(volatile uint32_t*)(addr
) = value
;
35 static uint32_t read32(unsigned long addr
)
38 value
= *(volatile uint32_t*)addr
;
43 static cfi_word
cfi_cmd(flash_info_t
*flash
, uint8_t cmd
, uint32_t addr
)
45 uint32_t base
= flash
->start
[0];
46 uint32_t val
=(cmd
<< 16) | cmd
;
48 write32(base
+ addr
, val
);
52 static uint16_t cfi_read_query(flash_info_t
*flash
, uint32_t addr
)
54 uint32_t base
= flash
->start
[0];
56 return (uint16_t)read32(base
+ addr
);
59 flash_info_t flash_info
[CONFIG_SYS_MAX_FLASH_BANKS
]; /* info for FLASH chips */
61 static void move64(uint64_t *src
, uint64_t *dest
)
63 asm volatile("lfd 0, 0(3)\n\t" /* fpr0 = *scr */
64 "stfd 0, 0(4)" /* *dest = fpr0 */
65 : : : "fr0" ); /* Clobbers fr0 */
69 static int cfi_write_dword(flash_info_t
*flash
, ulong dest
, cfi_word data
)
74 status
= cfi_read(flash
, dest
);
77 cfi_cmd(flash
, 0x40, 0);
78 cfi_write(flash
, data
, dest
);
81 start
= get_timer (0);
83 status
= cfi_read(flash
, dest
);
85 if(status
== CMD(0x80))
87 if (get_timer(start
) > CONFIG_SYS_FLASH_WRITE_TOUT
) {
88 cfi_cmd(flash
, 0xff, 0);
93 cfi_cmd(flash
, 0xff, 0);
98 static int jedec_write_dword (flash_info_t
*flash
, ulong dest
, cfi_word data
)
103 status
= cfi_read(flash
, dest
);
104 if(status
!= CMD(0xffff)) return 2;
106 cfi_cmd(flash
, 0xaa, 0x555);
107 cfi_cmd(flash
, 0x55, 0x2aa);
108 cfi_cmd(flash
, 0xa0, 0x555);
110 cfi_write(flash
, data
, dest
);
113 start
= get_timer (0);
115 while(status
!= data
) {
116 if (get_timer(start
) > CONFIG_SYS_FLASH_WRITE_TOUT
)
118 status
= cfi_read(flash
, dest
);
124 static __inline__
unsigned long get_msr(void)
127 __asm__
__volatile__ ("mfmsr %0" : "=r" (msr
) :);
131 static __inline__
void set_msr(unsigned long msr
)
133 __asm__
__volatile__ ("mtmsr %0" : : "r" (msr
));
136 int write_buff (flash_info_t
*flash
, uchar
*src
, ulong addr
, ulong cnt
)
141 uint8_t *t
= (uint8_t*)&data
;
142 unsigned long base
= flash
->start
[0];
145 if (flash
->flash_id
== FLASH_UNKNOWN
)
156 wp
= (addr
& ~7); /* get lower word aligned address */
159 data
= cfi_read(flash
, wp
);
161 l
= ( cnt
< (8-s
) ) ? cnt
: (8-s
);
162 for(i
= 0; i
< l
; i
++)
164 if ((rc
= write_dword(flash
, wp
, data
)) != 0)
171 for (i
= 0; i
< 8; i
++)
173 if ((rc
= write_dword(flash
, wp
, data
)) != 0)
184 data
= cfi_read(flash
, wp
);
185 for(i
= 0; i
< cnt
; i
++)
187 rc
= write_dword(flash
, wp
, data
);
193 static int cfi_erase_oneblock(flash_info_t
*flash
, uint32_t sect
)
197 ulong start
, last
, now
;
200 flag
= disable_interrupts();
202 sa
= (flash
->start
[sect
] - flash
->start
[0]);
203 write32(flash
->start
[sect
], 0x00200020);
204 write32(flash
->start
[sect
], 0x00d000d0);
210 start
= get_timer (0);
214 status
= cfi_read(flash
, sa
);
216 if (status
== CMD(0x80))
218 if ((now
= get_timer(start
)) > CONFIG_SYS_FLASH_ERASE_TOUT
) {
219 cfi_cmd(flash
, 0xff, 0);
220 printf ("Timeout\n");
224 if ((now
- last
) > 1000) {
230 cfi_cmd(flash
, 0xff, 0);
234 static int cfi_erase(flash_info_t
*flash
, uint32_t s_first
, uint32_t s_last
)
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;
249 static int jedec_erase(flash_info_t
*flash
, uint32_t s_first
, uint32_t s_last
)
255 ulong start
, last
, now
;
257 flag
= disable_interrupts();
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);
277 start
= get_timer (0);
280 status
= cfi_read(flash
, sa
);
281 if (status
== CMD(0xffff))
284 if ((now
= get_timer(start
)) > CONFIG_SYS_FLASH_ERASE_TOUT
) {
285 printf ("Timeout\n");
289 if ((now
- last
) > 1000) {
296 cfi_cmd(flash
, 0xf0, 0);
303 int flash_erase (flash_info_t
*flash
, int s_first
, int s_last
)
308 if ((s_first
< 0) || (s_first
> s_last
)) {
309 if (flash
->flash_id
== FLASH_UNKNOWN
)
310 printf ("- missing\n");
312 printf ("- no sectors to erase\n");
313 return ERR_NOT_ERASED
;
315 if (flash
->flash_id
== FLASH_UNKNOWN
) {
316 printf ("Can't erase unknown flash type - aborted\n");
317 return ERR_NOT_ERASED
;
321 for (sect
= s_first
; sect
<= s_last
; sect
++)
322 if (flash
->protect
[sect
]) prot
++;
325 printf ("- Warning: %d protected sectors will not be erased!\n",
330 return do_flash_erase(flash
, s_first
, s_last
);
333 struct jedec_flash_info
{
334 const uint16_t mfr_id
;
335 const uint16_t dev_id
;
338 const int InterfaceDesc
;
339 const int NumEraseRegions
;
340 const ulong regions
[4];
343 #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
349 static const struct jedec_flash_info jedec_table
[] = {
351 mfr_id
: (uint16_t)AMD_MANUFACT
,
352 dev_id
: (uint16_t)AMD_ID_LV800T
,
353 name
: "AMD AM29LV800T",
356 regions
: {ERASEINFO(0x10000,15),
357 ERASEINFO(0x08000,1),
358 ERASEINFO(0x02000,2),
362 mfr_id
: (uint16_t)AMD_MANUFACT
,
363 dev_id
: (uint16_t)AMD_ID_LV800B
,
364 name
: "AMD AM29LV800B",
367 regions
: {ERASEINFO(0x10000,15),
368 ERASEINFO(0x08000,1),
369 ERASEINFO(0x02000,2),
373 mfr_id
: (uint16_t)AMD_MANUFACT
,
374 dev_id
: (uint16_t)AMD_ID_LV160T
,
375 name
: "AMD AM29LV160T",
378 regions
: {ERASEINFO(0x10000,31),
379 ERASEINFO(0x08000,1),
380 ERASEINFO(0x02000,2),
384 mfr_id
: (uint16_t)AMD_MANUFACT
,
385 dev_id
: (uint16_t)AMD_ID_LV160B
,
386 name
: "AMD AM29LV160B",
389 regions
: {ERASEINFO(0x04000,1),
390 ERASEINFO(0x02000,2),
391 ERASEINFO(0x08000,1),
392 ERASEINFO(0x10000,31)
395 mfr_id
: (uint16_t)AMD_MANUFACT
,
396 dev_id
: (uint16_t)AMD_ID_LV320T
,
397 name
: "AMD AM29LV320T",
400 regions
: {ERASEINFO(0x10000,63),
405 mfr_id
: (uint16_t)AMD_MANUFACT
,
406 dev_id
: (uint16_t)AMD_ID_LV320B
,
407 name
: "AMD AM29LV320B",
410 regions
: {ERASEINFO(0x02000,8),
411 ERASEINFO(0x10000,63)
416 static ulong
cfi_init(uint32_t base
, flash_info_t
*flash
)
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);
437 flash
->size
= 1 << cfi_read_query(flash
, 0x27);
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);
444 reverse
= (cfi_read_query(flash
, primary
+15) == 3);
446 flash
->sector_count
= 0;
448 for ( block
= reverse
? block_count
- 1 : 0;
449 reverse
? block
>= 0 : block
< block_count
;
450 reverse
? block
-- : block
++) {
452 (cfi_read_query(flash
, 0x2d + block
*4+2) |
453 (cfi_read_query(flash
, 0x2d + block
*4+3) << 8)) << 8;
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;
462 mfr_id
= cfi_read_query(flash
, 0x00);
463 dev_id
= cfi_read_query(flash
, 0x01);
465 cfi_cmd(flash
, 0xff, 0);
467 flash
->flash_id
= (mfr_id
<< 16) | dev_id
;
469 for (sector
= 0; sector
< flash
->sector_count
; sector
++) {
470 write32(flash
->start
[sector
], 0x00600060);
471 write32(flash
->start
[sector
], 0x00d000d0);
473 cfi_cmd(flash
, 0xff, 0);
475 for (sector
= 0; sector
< flash
->sector_count
; sector
++)
476 flash
->protect
[sector
] = 0;
478 do_flash_erase
= cfi_erase
;
479 write_dword
= cfi_write_dword
;
484 static ulong
jedec_init(unsigned long base
, flash_info_t
*flash
)
487 int block
, block_count
;
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);
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
)) {
503 flash
->flash_id
= (mfr_id
<< 16) | dev_id
;
504 flash
->size
= 1 << jedec_table
[0].DevSize
;
506 block_count
= jedec_table
[i
].NumEraseRegions
;
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;
513 for (sector
=0; sector
<sector_count
; sector
++) {
514 flash
->start
[flash
->sector_count
++] =
516 offset
+= sector_size
* 4;
523 for (sector
= 0; sector
< flash
->sector_count
; sector
++)
524 flash
->protect
[sector
] = 0;
526 do_flash_erase
= jedec_erase
;
527 write_dword
= jedec_write_dword
;
532 inline void mtibat1u(unsigned int x
)
534 __asm__
__volatile__ ("mtspr 530, %0" :: "r" (x
));
537 inline void mtibat1l(unsigned int x
)
539 __asm__
__volatile__ ("mtspr 531, %0" :: "r" (x
));
542 inline void mtdbat1u(unsigned int x
)
544 __asm__
__volatile__ ("mtspr 538, %0" :: "r" (x
));
547 inline void mtdbat1l(unsigned int x
)
549 __asm__
__volatile__ ("mtspr 539, %0" :: "r" (x
));
552 unsigned long flash_init (void)
554 unsigned long size
= 0;
559 CONFIG_WRITE_WORD(ERCR3
, 0x0C00000C);
560 CONFIG_WRITE_WORD(ERCR4
, 0x0800000C);
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
);
569 for (i
= 0; i
< CONFIG_SYS_MAX_FLASH_BANKS
; i
++)
570 flash_info
[i
].flash_id
= FLASH_UNKNOWN
;
571 size
= cfi_init(FLASH_BASE0_PRELIM
, &flash_info
[0]);
573 size
= jedec_init(FLASH_BASE0_PRELIM
, &flash_info
[0]);
575 if (flash_info
[0].flash_id
== FLASH_UNKNOWN
)
576 printf ("# Unknown FLASH on Bank 1 - Size = 0x%08lx = %ld MB\n",
582 void flash_print_info (flash_info_t
*flash
)
588 volatile unsigned long *p
;
590 if (flash
->flash_id
== FLASH_UNKNOWN
) {
591 printf ("missing or unknown FLASH type\n");
595 if (flash
->flash_id
== FLASH_UNKNOWN
) {
596 printf ("missing or unknown FLASH type\n");
600 switch (((flash
->flash_id
) >> 16) & 0xff) {
618 printf ("Unknown Vendor ");
622 switch ((flash
->flash_id
) & 0xffff) {
623 case (uint16_t)AMD_ID_LV800T
:
624 printf ("AM29LV800T\n");
626 case (uint16_t)AMD_ID_LV800B
:
627 printf ("AM29LV800B\n");
629 case (uint16_t)AMD_ID_LV160T
:
630 printf ("AM29LV160T\n");
632 case (uint16_t)AMD_ID_LV160B
:
633 printf ("AM29LV160B\n");
635 case (uint16_t)AMD_ID_LV320T
:
636 printf ("AM29LV320T\n");
638 case (uint16_t)AMD_ID_LV320B
:
639 printf ("AM29LV320B\n");
641 case (uint16_t)INTEL_ID_28F800C3T
:
642 printf ("28F800C3T\n");
644 case (uint16_t)INTEL_ID_28F800C3B
:
645 printf ("28F800C3B\n");
647 case (uint16_t)INTEL_ID_28F160C3T
:
648 printf ("28F160C3T\n");
650 case (uint16_t)INTEL_ID_28F160C3B
:
651 printf ("28F160C3B\n");
653 case (uint16_t)INTEL_ID_28F320C3T
:
654 printf ("28F320C3T\n");
656 case (uint16_t)INTEL_ID_28F320C3B
:
657 printf ("28F320C3B\n");
659 case (uint16_t)INTEL_ID_28F640C3T
:
660 printf ("28F640C3T\n");
662 case (uint16_t)INTEL_ID_28F640C3B
:
663 printf ("28F640C3B\n");
666 printf ("Unknown Chip Type\n");
670 if (flash
->size
>= (1 << 20)) {
671 printf (" Size: %ld MB in %d Sectors\n",
672 flash
->size
>> 20, flash
->sector_count
);
674 printf (" Size: %ld kB in %d Sectors\n",
675 flash
->size
>> 10, flash
->sector_count
);
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
];
684 size
= flash
->start
[0] + flash
->size
- flash
->start
[i
];
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) {
699 printf (" %08lX%s%s",
702 flash
->protect
[i
] ? "RO " : " ");