#include <mpc8260.h>
#include <asm/processor.h>
+#undef DEBUG_FLASH
/*
* This file implements a Common Flash Interface (CFI) driver for ppcboot.
* The width of the port and the width of the chips are determined at initialization.
#define FLASH_CMD_PROTECT_SET 0x01
#define FLASH_CMD_PROTECT_CLEAR 0xD0
#define FLASH_CMD_CLEAR_STATUS 0x50
+#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
+#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
#define FLASH_STATUS_DONE 0x80
#define FLASH_STATUS_ESS 0x40
#define FLASH_OFFSET_CFI 0x55
#define FLASH_OFFSET_CFI_RESP 0x10
#define FLASH_OFFSET_WTOUT 0x1F
+#define FLASH_OFFSET_WBTOUT 0x20
#define FLASH_OFFSET_ETOUT 0x21
+#define FLASH_OFFSET_CETOUT 0x22
#define FLASH_OFFSET_WMAX_TOUT 0x23
+#define FLASH_OFFSET_WBMAX_TOUT 0x24
#define FLASH_OFFSET_EMAX_TOUT 0x25
+#define FLASH_OFFSET_CEMAX_TOUT 0x26
#define FLASH_OFFSET_SIZE 0x27
+#define FLASH_OFFSET_INTERFACE 0x28
+#define FLASH_OFFSET_BUFFER_SIZE 0x2A
#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
#define FLASH_OFFSET_ERASE_REGIONS 0x2D
#define FLASH_OFFSET_PROTECT 0x02
+#define FLASH_OFFSET_USER_PROTECTION 0x85
+#define FLASH_OFFSET_INTEL_PROTECTION 0x81
#define FLASH_MAN_CFI 0x01000000
static int flash_isset(flash_info_t * info, int sect, uchar offset, uchar cmd);
static int flash_detect_cfi(flash_info_t * info);
static ulong flash_get_size (ulong base, int banknum);
-static void flash_status_display(flash_info_t * info, int sect);
static int flash_write_cfiword (flash_info_t *info, ulong dest, cfiword_t cword);
-
+static int flash_full_status_check(flash_info_t * info, ulong sector, ulong tout, char * prompt);
+#ifdef CFG_FLASH_USE_BUFFER_WRITE
+static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, int len);
+#endif
/*-----------------------------------------------------------------------
* create an address based on the offset and the port width
*/
return (cp[info->portwidth - 1]);
}
+/*-----------------------------------------------------------------------
+ * read a short word by swapping for ppc format.
+ */
+ushort flash_read_ushort(flash_info_t * info, int sect, uchar offset)
+{
+ uchar * addr;
+
+ addr = flash_make_addr(info, sect, offset);
+ return ((addr[(2*info->portwidth) - 1] << 8) | addr[info->portwidth - 1]);
+
+}
+
/*-----------------------------------------------------------------------
* read a long word by picking the least significant byte of each maiximum
* port size word. Swap for ppc format.
}
/* Monitor protection ON by default */
-#if (CFG_MONITOR_BASE > CFG_FLASH_BASE)
- (void)flash_protect(FLAG_PROTECT_SET,
- CFG_MONITOR_BASE,
- CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
- &flash_info[0]);
+#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
+ for(i=0; flash_info[0].start[i] < CFG_MONITOR_BASE+CFG_MONITOR_LEN-1; i++)
+ (void)flash_real_protect(&flash_info[0], i, 1);
#endif
return (size);
flash_write_cmd(info, sect, 0, FLASH_CMD_CLEAR_STATUS);
flash_write_cmd(info, sect, 0, FLASH_CMD_BLOCK_ERASE);
flash_write_cmd(info, sect, 0, FLASH_CMD_ERASE_CONFIRM);
-
- while(!flash_isset(info, sect, 0, FLASH_STATUS_DONE));
- if(!flash_isequal(info,sect, 0, FLASH_STATUS_DONE)) {
- flash_status_display(info, sect);
+
+ if(flash_full_status_check(info, sect, info->erase_blk_tout, "erase")) {
rcode = 1;
} else
printf(".");
}
- flash_write_cmd(info, sect, 0, FLASH_CMD_RESET);
- flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
-
}
-
printf (" done\n");
return rcode;
}
(info->portwidth << 3 ), (info->chipwidth << 3 ));
printf (" Size: %ld MB in %d Sectors\n",
info->size >> 20, info->sector_count);
- printf(" Erase timeout %ld ms, write timeout %ld ms\n",
- info->erase_blk_tout, info->write_tout);
-
+ printf(" Erase timeout %ld ms, write timeout %ld ms, buffer write timeout %ld ms, buffer size %d\n",
+ info->erase_blk_tout, info->write_tout, info->buffer_write_tout, info->buffer_size);
+
printf (" Sector Start Addresses:");
for (i=0; i<info->sector_count; ++i) {
if ((i % 5) == 0)
- printf ("\n ");
- printf (" %08lX%s",
+ printf ("\n");
+ printf (" %08lX%5s",
info->start[i],
- info->protect[i] ? " (RO)" : " "
+ info->protect[i] ? " (RO)" : " "
);
}
printf ("\n");
flash_add_byte(info, &cword, (*(uchar *)cp));
if((rc = flash_write_cfiword(info, wp, cword)) != 0)
return rc;
- wp += info->portwidth;
+ wp = cp;
}
+#ifdef CFG_FLASH_USE_BUFFER_WRITE
+ while(cnt >= info->portwidth) {
+ i = info->buffer_size > cnt? cnt: info->buffer_size;
+ if((rc = flash_write_cfibuffer(info, wp, src,i)) != ERR_OK)
+ return rc;
+ wp += i;
+ src += i;
+ cnt -=i;
+ }
+#else
/* handle the aligned part */
while(cnt >= info->portwidth) {
cword.l = 0;
wp += info->portwidth;
cnt -= info->portwidth;
}
-
+#endif /* CFG_FLASH_USE_BUFFER_WRITE */
if (cnt == 0) {
return (0);
}
*/
int flash_real_protect(flash_info_t *info, long sector, int prot)
{
- ulong start;
+ int retcode = 0;
flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS);
flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT);
else
flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
+ if((retcode = flash_full_status_check(info, sector, info->erase_blk_tout,
+ prot?"protect":"unprotect")) == 0) {
+
+ info->protect[sector] = prot;
+ /* Intel's unprotect unprotects all locking */
+ if(prot == 0) {
+ int i;
+ for(i = 0 ; i<info->sector_count; i++) {
+ if(info->protect[i])
+ flash_real_protect(info, i, 1);
+ }
+ }
+ }
+
+ return retcode;
+}
+/*-----------------------------------------------------------------------
+ * wait for XSR.7 to be set. Time out with an error if it does not.
+ * This routine does not set the flash to read-array mode.
+ */
+static int flash_status_check(flash_info_t * info, ulong sector, ulong tout, char * prompt)
+{
+ ulong start;
+
/* Wait for command completion */
start = get_timer (0);
while(!flash_isset(info, sector, 0, FLASH_STATUS_DONE)) {
if (get_timer(start) > info->erase_blk_tout) {
- printf("Flash %sprotect timeout at address %lx\n", prot?"":"un", info->start[sector]);
+ printf("Flash %s timeout at address %lx\n", prompt, info->start[sector]);
flash_write_cmd(info, sector, 0, FLASH_CMD_RESET);
- return 1;
+ return ERR_TIMOUT;
}
}
- if(!flash_isequal(info,sector, 0, FLASH_STATUS_DONE)) {
- printf("\nFlash %sprotect error at address %lx\n", prot?"":"un",info->start[sector]);
- flash_status_display(info, 0);
- flash_write_cmd(info, sector, 0, FLASH_CMD_RESET);
- return 1;
- }
- flash_write_cmd(info, sector, 0, FLASH_CMD_RESET);
- info->protect[sector] = prot;
- /* Intel's unprotect unprotects all locking */
- if(prot == 0) {
- int i;
- for(i = 0 ; i<info->sector_count; i++) {
- if(info->protect[i])
- flash_real_protect(info, i, 1);
+ return ERR_OK;
+}
+/*-----------------------------------------------------------------------
+ * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check.
+ * This routine sets the flash to read-array mode.
+ */
+static int flash_full_status_check(flash_info_t * info, ulong sector, ulong tout, char * prompt)
+{
+ int retcode;
+ retcode = flash_status_check(info, sector, tout, prompt);
+ if((retcode == ERR_OK) && !flash_isequal(info,sector, 0, FLASH_STATUS_DONE)) {
+ retcode = ERR_INVAL;
+ printf("Flash %s error at address %lx\n", prompt,info->start[sector]);
+ if(flash_isset(info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)){
+ printf("Command Sequence Error.\n");
+ } else if(flash_isset(info, sector, 0, FLASH_STATUS_ECLBS)){
+ printf("Block Erase Error.\n");
+ retcode = ERR_NOT_ERASED;
+ } else if (flash_isset(info, sector, 0, FLASH_STATUS_PSLBS)) {
+ printf("Locking Error\n");
}
+ if(flash_isset(info, sector, 0, FLASH_STATUS_DPS)){
+ printf("Block locked.\n");
+ retcode = ERR_PROTECTED;
+ }
+ if(flash_isset(info, sector, 0, FLASH_STATUS_VPENS))
+ printf("Vpp Low Error.\n");
}
-
- return 0;
+ flash_write_cmd(info, sector, 0, FLASH_CMD_RESET);
+ return retcode;
}
-
/*-----------------------------------------------------------------------
*/
static void flash_add_byte(flash_info_t *info, cfiword_t * cword, uchar c)
info->sector_count = sect_cnt;
/* multiply the size by the number of chips */
- info->size = (2 << flash_read_uchar(info, FLASH_OFFSET_SIZE)) * size_ratio;
+ info->size = (1 << flash_read_uchar(info, FLASH_OFFSET_SIZE)) * size_ratio;
+ info->buffer_size = (1 << flash_read_ushort(info, 0, FLASH_OFFSET_BUFFER_SIZE));
tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_ETOUT);
info->erase_blk_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_EMAX_TOUT)));
+ tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WBTOUT);
+ info->buffer_write_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_WBMAX_TOUT)));
tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WTOUT);
info->write_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_WMAX_TOUT)))/ 1000;
info->flash_id = FLASH_MAN_CFI;
}
-/*-----------------------------------------------------------------------
- */
-static void flash_status_display(flash_info_t * info, int sect)
-{
- if(flash_isset(info, sect, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS))
- printf("Command Sequence Error.\n");
- if(flash_isset(info, sect, 0, FLASH_STATUS_ECLBS))
- printf("Block Erase Error.\n");
- if(flash_isset(info, sect, 0, FLASH_STATUS_DPS))
- printf("Block locked.\n");
- if(flash_isset(info, sect, 0, FLASH_STATUS_VPENS))
- printf("Vpp Low Error.\n");
-}
-
/*-----------------------------------------------------------------------
*/
static int flash_write_cfiword (flash_info_t *info, ulong dest, cfiword_t cword)
cfiptr_t ctladdr;
cfiptr_t cptr;
int flag;
- ulong start;
-
ctladdr.cp = flash_make_addr(info, 0, 0);
cptr.cp = (uchar *)dest;
if(flag)
enable_interrupts();
- /* data polling for D7 */
- start = get_timer (0);
+ return flash_full_status_check(info, 0, info->write_tout, "write");
+}
- while(!flash_isset(info, 0, 0, FLASH_STATUS_DONE)) {
- if (get_timer(start) > info->write_tout) {
- printf("Write timeout at address %lx\n", (unsigned long)dest);
- flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
- return (1);
- }
- }
+#ifdef CFG_FLASH_USE_BUFFER_WRITE
- if(!flash_isequal(info,0, 0, FLASH_STATUS_DONE)) {
- printf("\nFlash write error at address %lx\n",(unsigned long)dest);
- flash_status_display(info, 0);
- flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
- return 2;
+/* loop through the sectors from the highest address
+ * when the passed address is greater or equal to the sector address
+ * we have a match
+ */
+static int find_sector(flash_info_t *info, ulong addr)
+{
+ int sector;
+ for(sector = info->sector_count - 1; sector >= 0; sector--) {
+ if(addr >= info->start[sector])
+ break;
}
- flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
- return 0;
+ return sector;
}
+
+static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, int len)
+{
+
+ int sector;
+ int cnt;
+ int retcode;
+ volatile cfiptr_t src;
+ volatile cfiptr_t dst;
+
+ src.cp = cp;
+ dst.cp = (uchar *)dest;
+ sector = find_sector(info, dest);
+ flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS);
+ flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
+ if((retcode = flash_status_check(info, sector, info->buffer_write_tout,
+ "write to buffer")) == ERR_OK) {
+ switch(info->portwidth) {
+ case FLASH_CFI_8BIT:
+ cnt = len;
+ break;
+ case FLASH_CFI_16BIT:
+ cnt = len >> 1;
+ break;
+ case FLASH_CFI_32BIT:
+ cnt = len >> 2;
+ break;
+ default:
+ return ERR_INVAL;
+ break;
+ }
+ flash_write_cmd(info, sector, 0, (uchar)cnt-1);
+ while(cnt-- > 0) {
+ switch(info->portwidth) {
+ case FLASH_CFI_8BIT:
+ *dst.cp++ = *src.cp++;
+ break;
+ case FLASH_CFI_16BIT:
+ *dst.wp++ = *src.wp++;
+ break;
+ case FLASH_CFI_32BIT:
+ *dst.lp++ = *src.lp++;
+ break;
+ default:
+ return ERR_INVAL;
+ break;
+ }
+ }
+ flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_BUFFER_CONFIRM);
+ retcode = flash_full_status_check(info, sector, info->buffer_write_tout,
+ "buffer write");
+ }
+ flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS);
+ return retcode;
+}
+#endif /* CFG_USE_FLASH_BUFFER_WRITE */