From: wdenk Date: Fri, 7 Jun 2002 14:54:33 +0000 (+0000) Subject: * Patch by Brad Kemp, 31 May 2002: X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=df517fd60066169852145d9abbac17fb940aa5f5;p=users%2Frw%2Fppcboot.git * Patch by Brad Kemp, 31 May 2002: - use buffered IO for the ppmc8260 strataflash; gives about a 20x performance boost for flash writes --- diff --git a/CHANGELOG b/CHANGELOG index 9e92b49..5b063d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,7 +14,11 @@ Modifications for 1.1.6: ====================================================================== -* Patch by Stefan Roese: +* Patch by Brad Kemp, 31 May 2002: + - use buffered IO for the ppmc8260 strataflash; + gives about a 20x performance boost for flash writes + +* Patch by Stefan Roese, 29 May 2002: - PCI405 board added. - CPCI4052 fpga image changed. - First step to add PPC405GPr support. diff --git a/board/ppmc8260/strataflash.c b/board/ppmc8260/strataflash.c index dd9211f..dd84479 100644 --- a/board/ppmc8260/strataflash.c +++ b/board/ppmc8260/strataflash.c @@ -25,6 +25,7 @@ #include #include +#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. @@ -53,6 +54,8 @@ #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 @@ -67,13 +70,21 @@ #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 @@ -111,9 +122,11 @@ static int flash_isequal(flash_info_t * info, int sect, uchar offset, uchar cmd) 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 */ @@ -131,6 +144,18 @@ inline uchar flash_read_uchar(flash_info_t * info, uchar offset) 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. @@ -175,11 +200,9 @@ unsigned long flash_init (void) } /* 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); @@ -221,19 +244,13 @@ int flash_erase (flash_info_t *info, int s_first, int s_last) 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; } @@ -253,16 +270,16 @@ void flash_print_info (flash_info_t *info) (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; isector_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"); @@ -302,9 +319,19 @@ int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) 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; @@ -316,7 +343,7 @@ int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) wp += info->portwidth; cnt -= info->portwidth; } - +#endif /* CFG_FLASH_USE_BUFFER_WRITE */ if (cnt == 0) { return (0); } @@ -340,7 +367,7 @@ int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) */ 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); @@ -349,35 +376,70 @@ int flash_real_protect(flash_info_t *info, long sector, int prot) 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 ; isector_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 ; isector_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) @@ -549,9 +611,12 @@ static ulong flash_get_size (ulong base, int banknum) 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; @@ -562,20 +627,6 @@ static ulong flash_get_size (ulong base, int banknum) } -/*----------------------------------------------------------------------- - */ -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) @@ -584,8 +635,6 @@ 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; @@ -630,23 +679,77 @@ static int flash_write_cfiword (flash_info_t *info, ulong dest, cfiword_t cword) 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 */ diff --git a/include/config_ppmc8260.h b/include/config_ppmc8260.h index c5aa79c..c1b97fd 100644 --- a/include/config_ppmc8260.h +++ b/include/config_ppmc8260.h @@ -449,6 +449,7 @@ #define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */ #define CFG_FLASH_INCREMENT 0 /* there is only one bank */ #define CFG_FLASH_PROTECTION 1 /* use hardware protection */ +#define CFG_FLASH_USE_BUFFER_WRITE 1 /* use buffered writes (20x faster) */ #ifndef CFG_RAMBOOT diff --git a/include/flash.h b/include/flash.h index bac0b7a..32eda65 100644 --- a/include/flash.h +++ b/include/flash.h @@ -37,8 +37,11 @@ typedef struct { #ifdef CFG_FLASH_CFI uchar portwidth; /* the width of the port */ uchar chipwidth; /* the width of the chip */ + ushort buffer_size; /* # of bytes in write buffer */ ulong erase_blk_tout; /* maximum block erase timeout */ ulong write_tout; /* maximum write timeout */ + ulong buffer_write_tout; /* maximum buffer write timeout */ + #endif } flash_info_t;