Index: devs/flash/intel/strata/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/ChangeLog,v retrieving revision 1.18 diff -u -5 -p -r1.18 ChangeLog --- devs/flash/intel/strata/current/ChangeLog 11 Sep 2003 13:21:39 -0000 1.18 +++ devs/flash/intel/strata/current/ChangeLog 14 Oct 2003 14:36:26 -0000 @@ -1,5 +1,23 @@ +2003-10-03 Patrick Doyle + + * src/flash_erase_block.c (flash_erase_block): + * src/flash_lock_block.c (flash_lock_block): + * src/flash_program_buf.c (flash_program_buf): + * src/flash_query.c (flash_query): + * src/flash_unlock_block.c (flash_unlock_block): + * src/strata.c: + * src/strata.h: Added additional support for dynamically adapting + to device parameters based on the CFI. The driver now locks, + unlocks, and erases boot/parameter blocks whose sizes are + submultiples of the main block size of the device, based on + information derived from the CFI. + Write buffering is now enabled dynamically based on the CFI + (instead of as a compile time option). + Cleaned up and renamed several parameters in "strata.h" to be more + self-documenting. + 2003-09-11 Jani Monoses * src/flash_erase_block.c (flash_erase_block): * src/flash_program_buf.c (flash_program_buf): Fix bootblock handling in erase. Fix erase and word-program for Synchronous Strata and later Index: devs/flash/intel/strata/current/src/flash_erase_block.c =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/src/flash_erase_block.c,v retrieving revision 1.7 diff -u -5 -p -r1.7 flash_erase_block.c --- devs/flash/intel/strata/current/src/flash_erase_block.c 11 Sep 2003 13:21:39 -0000 1.7 +++ devs/flash/intel/strata/current/src/flash_erase_block.c 14 Oct 2003 14:36:26 -0000 @@ -50,59 +50,19 @@ // //========================================================================== #include "strata.h" -#include -#include - int flash_erase_block(volatile flash_t *block, unsigned int block_size) __attribute__ ((section (".2ram.flash_erase_block"))); int flash_erase_block(volatile flash_t *block, unsigned int block_size) { - volatile flash_t *ROM; - flash_t stat = 0; - int timeout = 50000; - int len, block_len, erase_block_size; - volatile flash_t *eb; - - // Get base address and map addresses to virtual addresses - ROM = FLASH_P2V(CYGNUM_FLASH_BASE_MASK & (unsigned int)block); - eb = block = FLASH_P2V(block); - block_len = block_size; - -#ifdef CYGOPT_FLASH_IS_BOOTBLOCK -#define BLOCKSIZE (0x10000*CYGNUM_FLASH_DEVICES) -#define ERASE_BLOCKSIZE (0x2000*CYGNUM_FLASH_DEVICES) - if ((eb - ROM) < BLOCKSIZE/(sizeof eb[0])) { - erase_block_size = ERASE_BLOCKSIZE; - } else { - erase_block_size = block_size; - } -#else - erase_block_size = block_size; -#endif - - // Clear any error conditions - ROM[0] = FLASH_Clear_Status; - - // Erase block - while (block_len > 0) { - eb[0] = FLASH_Block_Erase; - eb[0] = FLASH_Confirm; - - timeout = 5000000; - while(((stat = eb[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { - if (--timeout == 0) break; - } - - block_len -= erase_block_size; - eb = FLASH_P2V((unsigned int)eb + erase_block_size); - } - - // Restore ROM to "normal" mode - ROM[0] = FLASH_Reset; + int len; + flash_t stat = flash_block_op(block, + block_size, + FLASH_Block_Erase, + FLASH_Confirm); // If an error was reported, see if the block erased anyway if (stat & FLASH_ErrorMask ) { len = block_size; while (len > 0) { Index: devs/flash/intel/strata/current/src/flash_lock_block.c =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/src/flash_lock_block.c,v retrieving revision 1.5 diff -u -5 -p -r1.5 flash_lock_block.c --- devs/flash/intel/strata/current/src/flash_lock_block.c 10 Sep 2003 20:52:53 -0000 1.5 +++ devs/flash/intel/strata/current/src/flash_lock_block.c 14 Oct 2003 14:36:26 -0000 @@ -49,36 +49,21 @@ //####DESCRIPTIONEND#### // //========================================================================== #include "strata.h" +#include +#define _FLASH_PRIVATE_ +#include int flash_lock_block(volatile flash_t *block) __attribute__ ((section (".2ram.flash_lock_block"))); int flash_lock_block(volatile flash_t *block) { - volatile flash_t *ROM; - flash_t stat; - int timeout = 5000000; - - // Get base address and map addresses to virtual addresses - ROM = FLASH_P2V(CYGNUM_FLASH_BASE_MASK & (unsigned int)block); - block = FLASH_P2V(block); - - // Clear any error conditions - ROM[0] = FLASH_Clear_Status; - - // Set lock bit - block[0] = FLASH_Set_Lock; - block[0] = FLASH_Set_Lock_Confirm; // Confirmation - while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { - if (--timeout == 0) break; - } - - // Restore ROM to "normal" mode - ROM[0] = FLASH_Reset; - - return stat; + return(flash_block_op(block, + flash_info.block_size, + FLASH_Set_Lock, + FLASH_Set_Lock_Confirm)); } Index: devs/flash/intel/strata/current/src/flash_program_buf.c =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/src/flash_program_buf.c,v retrieving revision 1.9 diff -u -5 -p -r1.9 flash_program_buf.c --- devs/flash/intel/strata/current/src/flash_program_buf.c 11 Sep 2003 13:21:39 -0000 1.9 +++ devs/flash/intel/strata/current/src/flash_program_buf.c 14 Oct 2003 14:36:26 -0000 @@ -70,59 +70,61 @@ flash_program_buf(volatile flash_t *addr #ifdef FLASH_Write_Buffer int i, wc; #endif // Get base address and map addresses to virtual addresses - ROM = FLASH_P2V( CYGNUM_FLASH_BASE_MASK & (unsigned int)addr ); + ROM = FLASH_P2V( block_mask & (unsigned int)addr ); BA = addr = FLASH_P2V(addr); // Clear any error conditions ROM[0] = FLASH_Clear_Status; #ifdef FLASH_Write_Buffer - // Write any big chunks first - while (len >= buffer_size) { - wc = buffer_size; - if (wc > len) wc = len; - len -= wc; - // convert 'wc' in bytes to 'wc' in 'flash_t' - wc = wc / sizeof(flash_t); // Word count - *BA = FLASH_Write_Buffer; - timeout = 5000000; - while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { - if (--timeout == 0) { - goto bad; - } + if (buffer_size > 1) { + // Write any big chunks first + while (len >= buffer_size) { + wc = buffer_size; + if (wc > len) wc = len; + len -= wc; + // convert 'wc' in bytes to 'wc' in 'flash_t' + wc = wc / sizeof(flash_t); // Word count *BA = FLASH_Write_Buffer; - } - *BA = FLASHWORD(wc-1); // Count is 0..N-1 - for (i = 0; i < wc; i++) { + timeout = 5000000; + while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { + if (--timeout == 0) { + goto bad; + } + *BA = FLASH_Write_Buffer; + } + *BA = FLASHWORD(wc-1); // Count is 0..N-1 + for (i = 0; i < wc; i++) { #ifdef CYGHWR_FLASH_WRITE_ELEM - CYGHWR_FLASH_WRITE_ELEM(addr+i, data+i); + CYGHWR_FLASH_WRITE_ELEM(addr+i, data+i); #else - *(addr+i) = *(data+i); + *(addr+i) = *(data+i); #endif - } - *BA = FLASH_Confirm; + } + *BA = FLASH_Confirm; - ROM[0] = FLASH_Read_Status; - timeout = 5000000; - while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { - if (--timeout == 0) { - goto bad; + ROM[0] = FLASH_Read_Status; + timeout = 5000000; + while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { + if (--timeout == 0) { + goto bad; + } } - } - // Jump out if there was an error - if (stat & FLASH_ErrorMask) { - goto bad; - } - // And verify the data - also increments the pointers. - *BA = FLASH_Reset; - for (i = 0; i < wc; i++) { - if ( *addr++ != *data++ ) { - stat = FLASH_ErrorNotVerified; + // Jump out if there was an error + if (stat & FLASH_ErrorMask) { goto bad; + } + // And verify the data - also increments the pointers. + *BA = FLASH_Reset; + for (i = 0; i < wc; i++) { + if ( *addr++ != *data++ ) { + stat = FLASH_ErrorNotVerified; + goto bad; + } } } } #endif Index: devs/flash/intel/strata/current/src/flash_query.c =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/src/flash_query.c,v retrieving revision 1.6 diff -u -5 -p -r1.6 flash_query.c --- devs/flash/intel/strata/current/src/flash_query.c 10 Sep 2003 20:52:53 -0000 1.6 +++ devs/flash/intel/strata/current/src/flash_query.c 14 Oct 2003 14:36:26 -0000 @@ -62,38 +62,45 @@ int flash_query(unsigned char *data) __attribute__ ((section (".2ram.flash_query"))); int flash_query(unsigned char *data) { + register int i; volatile flash_t *ROM; - int i, cnt; + int len, cnt; - // Get base address and map addresses to virtual addresses - ROM = FLASH_P2V( CYGNUM_FLASH_BASE ); -#ifdef CYGOPT_FLASH_IS_BOOTBLOCK - // BootBlock flash does not support full Read_Query - we have do a - // table oriented thing above, after getting just two bytes of results: - ROM[0] = FLASH_Read_ID; - i = 2; + for (i = 0; i < CYGNUM_FLASH_SERIES; i++) { + + // Get base address and map addresses to virtual addresses + ROM = FLASH_P2V( CYGNUM_FLASH_BASE + i * CYGNUM_FLASH_SIZE); +#ifdef CYGOPT_FLASH_NO_CFI + // BootBlock flash does not support full Read_Query - we have do a + // table oriented thing above, after getting just two bytes of results: + ROM[0] = FLASH_Read_ID; + len = 2; + // We only query the 1st device + i = CYGNUM_FLASH_SERIES - 1; #else - // StrataFlash supports the full Read_Query op: - ROM[0] = FLASH_Read_Query; - i = sizeof(struct FLASH_query); -#endif // Not CYGOPT_FLASH_IS_BOOTBLOCK + // flash supports the full Read_Query op: + ROM[0] = FLASH_Read_Query; + len = sizeof(struct FLASH_query); +#endif // Not CYGOPT_FLASH_NO_CFI + + for (cnt = CNT; cnt > 0; cnt--) ; - for (cnt = CNT; cnt > 0; cnt--) ; - for ( /* i */; i > 0; i-- ) { - // It is very deliberate that data is chars NOT flash_t: - // The info comes out in bytes regardless of device. - *data++ = (unsigned char) (*ROM++); -#ifndef CYGOPT_FLASH_IS_BOOTBLOCK + for ( /* len */; len > 0; len-- ) { + // It is very deliberate that data is chars NOT flash_t: + // The info comes out in bytes regardless of device. + *data++ = (unsigned char) (*ROM++); +#ifndef CYGOPT_FLASH_NO_CFI # if 8 == CYGNUM_FLASH_WIDTH - // strata flash with 'byte-enable' contains the configuration data - // at even addresses - ++ROM; + // strata flash with 'byte-enable' contains the configuration data + // at even addresses + ++ROM; # endif #endif + } + ROM[0] = FLASH_Reset; } - ROM[0] = FLASH_Reset; return 0; } Index: devs/flash/intel/strata/current/src/flash_unlock_block.c =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/src/flash_unlock_block.c,v retrieving revision 1.6 diff -u -5 -p -r1.6 flash_unlock_block.c --- devs/flash/intel/strata/current/src/flash_unlock_block.c 10 Sep 2003 20:52:53 -0000 1.6 +++ devs/flash/intel/strata/current/src/flash_unlock_block.c 14 Oct 2003 14:36:26 -0000 @@ -67,33 +67,25 @@ int flash_unlock_block(volatile flash_t *block, int block_size, int blocks) __attribute__ ((section (".2ram.flash_unlock_block"))); int flash_unlock_block(volatile flash_t *block, int block_size, int blocks) { +#ifndef CYGOPT_FLASH_UNLOCKS_SINGLE_BLOCKS volatile flash_t *ROM; - flash_t stat; int timeout = 5000000; -#ifndef CYGOPT_FLASH_IS_SYNCHRONOUS int i; volatile flash_t *bp, *bpv; unsigned char is_locked[MAX_FLASH_BLOCKS]; #endif + flash_t stat = 0; - // Get base address and map addresses to virtual addresses - ROM = FLASH_P2V( CYGNUM_FLASH_BASE_MASK & (unsigned int)block ); - block = FLASH_P2V(block); +#ifdef CYGOPT_FLASH_UNLOCKS_SINGLE_BLOCKS + stat = flash_block_op(block, + block_size, + FLASH_Clear_Locks, + FLASH_Clear_Locks_Confirm); - // Clear any error conditions - ROM[0] = FLASH_Clear_Status; - -#ifdef CYGOPT_FLASH_IS_SYNCHRONOUS - // Clear lock bit - block[0] = FLASH_Clear_Locks; - block[0] = FLASH_Clear_Locks_Confirm; // Confirmation - while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { - if (--timeout == 0) break; - } #else // Get current block lock state. This needs to access each block on // the device so currently locked blocks can be re-locked. bp = ROM; for (i = 0; i < blocks; i++) { @@ -119,24 +111,18 @@ flash_unlock_block(volatile flash_t *blo if (--timeout == 0) break; } // Restore the lock state bp = ROM; - for (i = 0; i < blocks; i++) { - bpv = FLASH_P2V( bp ); + for (i = 0; i < blocks; i++) { if (is_locked[i]) { - *bpv = FLASH_Set_Lock; - *bpv = FLASH_Set_Lock_Confirm; // Confirmation - timeout = 5000000; - while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { - if (--timeout == 0) break; - } + flash_lock_block(bp); } bp += block_size / sizeof(*bp); } -#endif // CYGOPT_FLASH_IS_SYNCHRONOUS // Restore ROM to "normal" mode - ROM[0] = FLASH_Reset; + block[0] = FLASH_Reset; +#endif // CYGOPT_FLASH_UNLOCKS_SINGLE_BLOCKS return stat; } Index: devs/flash/intel/strata/current/src/strata.c =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/src/strata.c,v retrieving revision 1.8 diff -u -5 -p -r1.8 strata.c --- devs/flash/intel/strata/current/src/strata.c 2 May 2003 16:35:23 -0000 1.8 +++ devs/flash/intel/strata/current/src/strata.c 14 Oct 2003 14:36:27 -0000 @@ -62,22 +62,37 @@ #define _si(p) ((p[1]<<8)|p[0]) extern void diag_dump_buf(void *buf, CYG_ADDRWORD len); extern int strncmp(const char *s1, const char *s2, size_t len); -extern void *memcpy( void *, const void *, size_t ); + +#ifndef CYGOPT_FLASH_SYNTHETIC_CFI +#define CYGOPT_FLASH_SYNTHETIC_CFI {0} +#endif + +struct FLASH_parsed_CFI flash_cfi = CYGOPT_FLASH_SYNTHETIC_CFI; + +#ifndef CYGOPT_FLASH_NO_CFI +static int +flash_parse_CFI(const struct FLASH_query *qp, + struct FLASH_parsed_CFI *cfi); +#endif int flash_hwr_init(void) { - struct FLASH_query data, *qp; - int num_regions, region_size, buffer_size; + struct FLASH_query data[CYGNUM_FLASH_SERIES], *qp; + struct FLASH_parsed_CFI *cfi = &flash_cfi; + + int num_blocks, block_size; - flash_dev_query(&data); - qp = &data; - if ( (qp->manuf_code == FLASH_Intel_code) + flash_dev_query(data); + qp = &data[0]; +#ifdef CYGOPT_FLASH_NO_CFI + if ( #ifdef CYGOPT_FLASH_IS_BOOTBLOCK + (qp->manuf_code == FLASH_Intel_code) // device types go as follows: 0x90 for 16-bits, 0xD0 for 8-bits, // plus 0 or 1 for -T (Top Boot) or -B (Bottom Boot) // [FIXME: whatever that means :FIXME] // [I think it means the boot blocks are top/bottom of addr space] // plus the following size codes: @@ -91,67 +106,149 @@ flash_hwr_init(void) && 0 #error Only understand 16 and 8-bit bootblock flash types #endif ) { int lookup[] = { 16, 8, 4, 32, 64 }; -#define BLOCKSIZE (0x10000) - region_size = BLOCKSIZE; - num_regions = qp->device_code & 0x0F; - num_regions >>= 1; - if ( num_regions > 4 ) + unsigned total_size; + +#define BLOCKSIZE (0x10000) +#define ERASE_BLOCKSIZE (0x2000) + + total_size = qp->device_code & 0x0F; + total_size >>= 1; + if ( total_size > 4 ) goto flash_type_unknown; - num_regions = lookup[num_regions]; - num_regions *= 1024 * 1024; // to bits - num_regions /= 8; // to bytes - num_regions /= BLOCKSIZE; // to blocks - buffer_size = 0; -#else // CYGOPT_FLASH_IS_BOOTBLOCK - && (strncmp(qp->id, "QRY", 3) == 0)) { - num_regions = _si(qp->num_regions)+1; - region_size = _si(qp->region_size)*256; - if (_si(qp->buffer_size)) { - buffer_size = CYGNUM_FLASH_DEVICES << _si(qp->buffer_size); + total_size = lookup[total_size]; + total_size *= 1024 * 1024; // to bits + total_size /= 8; // to bytes + num_blocks = CYGNUM_FLASH_SERIES * (total_size / BLOCKSIZE); + // to blocks + + cfi->manuf_code = qp->manuf_code; + cfi->device_code = qp->device_code; + cfi->write_buffer_size = 0; + cfi->num_regions = 2; + cfi->max_block_size = BLOCKSIZE; + if (qp->device_code & 0x01) { + // Bottom Boot + cfi->region[0].num_blocks = BLOCKSIZE / ERASE_BLOCKSIZE; + cfi->region[0].total_size = BLOCKSIZE; + cfi->region[0].block_size = ERASE_BLOCKSIZE; + cfi->region[1].num_blocks = num_blocks - 1; + cfi->region[1].total_size = total_size - BLOCKSIZE; + cfi->region[1].block_size = BLOCKSIZE; } else { - buffer_size = 0; + // Top Boot + cfi->region[0].num_blocks = num_blocks - 1; + cfi->region[0].total_size = total_size - BLOCKSIZE; + cfi->region[0].block_size = BLOCKSIZE; + cfi->region[1].num_blocks = BLOCKSIZE / ERASE_BLOCKSIZE; + cfi->region[1].total_size = BLOCKSIZE; + cfi->region[1].block_size = ERASE_BLOCKSIZE; } -#endif // Not CYGOPT_FLASH_IS_BOOTBLOCK +#else // CYGOPT_FLASH_IS_BOOTBLOCK + // If 'CYGOPT_FLASH_IS_BOOTBLOCK' is not defined, then we + // assume/require that the user fill in + // 'CYGOPT_FLASH_SYNTHETIC_CFI' correctly. If not, we go to + // 'flash_type_unknown'. + (qp->manuf_code != cfi->manuf_code) || + (qp->device_code != cfi->device_code)) { + goto flash_type_unknown; +#endif // FLASH_IS_BOOTBLOCK + } +#else // CYGOPT_FLASH_NO_CFI + if (flash_parse_CFI(data, cfi) != 0) { + goto flash_type_unknown; + } +#endif // CYGOPT_FLASH_NO_CFI + if (cfi->num_regions <= 1) { + // num_regions should never be zero, but what the heck + num_blocks = cfi->region[0].num_blocks; + block_size = cfi->region[0].block_size; + } else { + register int i; - flash_info.block_size = region_size*CYGNUM_FLASH_DEVICES; - flash_info.buffer_size = buffer_size; - flash_info.blocks = num_regions; - flash_info.start = (void *)CYGNUM_FLASH_BASE; - flash_info.end = (void *)(CYGNUM_FLASH_BASE + - (num_regions*region_size*CYGNUM_FLASH_DEVICES)); -#ifdef CYGNUM_FLASH_BASE_MASK - // Then this gives us a maximum size for the (visible) device. - // This is to cope with oversize devices fitted, with some high - // address lines ignored. - if ( ((unsigned int)flash_info.start & CYGNUM_FLASH_BASE_MASK) != - (((unsigned int)flash_info.end - 1) & CYGNUM_FLASH_BASE_MASK ) ) { - // then the size of the device appears to span >1 device-worth! - unsigned int x; - x = (~(CYGNUM_FLASH_BASE_MASK)) + 1; // expected device size - x += (unsigned int)flash_info.start; - if ( x < (unsigned int)flash_info.end ) { // 2nd sanity check - (*flash_info.pf)("\nFLASH: Oversized device! End addr %p changed to %p\n", - flash_info.end, (void *)x ); - flash_info.end = (void *)x; - // Also adjust the block count else unlock crashes! - x = ((cyg_uint8 *)flash_info.end - (cyg_uint8 *)flash_info.start) - / flash_info.block_size; - flash_info.blocks = x; + // Collapse the smaller region(s) into a larger region + // We only know how to do this if the smaller block + // length(s) is/are a multiple of the maximum block size, + // which is what we report to the higher layer. + num_blocks = 0; + block_size = cfi->max_block_size; + + for (i = 0; i < cfi->num_regions; i++) { + if (cfi->region[i].block_size == block_size) { + num_blocks += cfi->region[i].num_blocks; + } else if (cfi->region[i].total_size == block_size) { + // Collapse all of these blocks into a single larger + // block. + num_blocks++; + } else { + /* I'm not sure how to collapse this -- the total size + * of the smaller region is not exactly equal to the + * size of the largest block. Most likely, the + * total size would be a multiple of the the since of + * the larger region, which we might be able to live + * with. Let's see if this is ever a problem and deal + * with it then.. + */ + goto flash_type_unknown; } } + } + + flash_info.block_size = block_size*CYGNUM_FLASH_INTERLEAVE; + flash_info.buffer_size = cfi->write_buffer_size; + flash_info.blocks = num_blocks; + flash_info.start = (void *)CYGNUM_FLASH_BASE; + flash_info.end = (void *)(CYGNUM_FLASH_BASE + + (num_blocks*block_size*CYGNUM_FLASH_INTERLEAVE)); +#ifdef CYGNUM_FLASH_BASE_MASK + // Then this gives us a maximum size for the (visible) device. + // This is to cope with oversize devices fitted, with some high + // address lines ignored. + if ( ((unsigned int)flash_info.start & CYGNUM_FLASH_BASE_MASK) != + (((unsigned int)flash_info.end - 1) & CYGNUM_FLASH_BASE_MASK ) ) { + // then the size of the device appears to span >1 device-worth! + unsigned int x; + x = (~(CYGNUM_FLASH_BASE_MASK)) + 1; // expected device size + x += (unsigned int)flash_info.start; + if ( x < (unsigned int)flash_info.end ) { // 2nd sanity check + (*flash_info.pf)("\nFLASH: Oversized device! End addr %p changed to %p\n", + flash_info.end, (void *)x ); + flash_info.end = (void *)x; + // Also adjust the block count else unlock crashes! + x = ((cyg_uint8 *)flash_info.end - (cyg_uint8 *)flash_info.start) + / flash_info.block_size; + flash_info.blocks = x; + } + } #endif // CYGNUM_FLASH_BASE_MASK - return FLASH_ERR_OK; +#if 0 + { + register int i; + // Dump the CFI + flash_info.pf("CFI dump:\n"); + flash_info.pf("manuf_code = 0x%02x, device_code = 0x%02x, write buffer size = %d\n", + cfi->manuf_code, + cfi->device_code, + cfi->write_buffer_size); + flash_info.pf("%d erase block regions:\n", cfi->num_regions); + for (i = 0; i < cfi->num_regions; i++) { + flash_info.pf("num_blocks = %3d, block_size = 0x%08X, total_size = 0x%08X\n", + cfi->region[i].num_blocks, + cfi->region[i].block_size, + cfi->region[i].total_size); + } + flash_info.pf("Max block size = 0x%08X\n", cfi->max_block_size); } -#ifdef CYGOPT_FLASH_IS_BOOTBLOCK - flash_type_unknown: #endif + return FLASH_ERR_OK; + + flash_type_unknown: (*flash_info.pf)("Can't identify FLASH, sorry, man %x, dev %x, id [%4s] \n", - qp->manuf_code, qp->device_code, qp->id ); + qp->manuf_code, qp->device_code, qp->id ); diag_dump_buf(qp, sizeof(data)); return FLASH_ERR_HWR; } // Map a hardware status to a package error @@ -181,6 +278,201 @@ flash_code_overlaps(void *start, void *e ((unsigned long)&_stext < (unsigned long)end)) || (((unsigned long)&_etext >= (unsigned long)start) && ((unsigned long)&_etext < (unsigned long)end))); } +#ifndef CYGOPT_FLASH_NO_CFI +static int +flash_parse_CFI(const struct FLASH_query *qp, + struct FLASH_parsed_CFI *cfi) +{ + register int i; + + if (strncmp(qp->id, "QRY", 3) != 0) { + return(-1); + } + + cfi->num_regions = qp->num_erase_block_regions; + if (cfi->num_regions == 0) { + // no erase blocking -- the device erases in bulk + cfi->num_regions = 1; + cfi->region[0].num_blocks = 1; + cfi->region[0].block_size = 1 << qp->device_size; + cfi->max_block_size = cfi->region[0].block_size; + } else { + int total_size = 0; + int max_block_size = 0; + + for (i = 0; i < cfi->num_regions; i++) { + cfi->region[i].num_blocks = _si(qp->regions[i].num)+1; + cfi->region[i].block_size = _si(qp->regions[i].size)*256; + total_size += cfi->region[i].num_blocks * cfi->region[i].block_size; + if (cfi->region[i].block_size > max_block_size) { + max_block_size = cfi->region[i].block_size; + } + } + cfi->max_block_size = max_block_size; + + // Just so that we can assume that the number of regions and the size + // of the device match up, we verify it here. + if (total_size != (1 << qp->device_size)) { + return(-1); + } + } + + cfi->manuf_code = qp->manuf_code; + cfi->device_code = qp->device_code; + + if (_si(qp->buffer_size)) { + cfi->write_buffer_size = CYGNUM_FLASH_INTERLEAVE << _si(qp->buffer_size); + } else { + // no write buffering + cfi->write_buffer_size = 0; + } +#if 0 + diag_dump_buf(qp, sizeof(*qp)); +#endif + +#if CYGNUM_FLASH_SERIES > 1 + for (i = 1; i < CYGNUM_FLASH_SERIES; i++) { + int max_block_size = cfi->max_block_size; + int idx = cfi->num_regions; + + // We allow some flexibility in mixing and matching devices in + // series, but with some restrictions -- the write buffer + // sizes must match. Someday we might decide to require that + // the timing parameters reported in the CFI should match as + // well, but, for now, we will assume that the board designer + // has taken that into account. + // On the plus side, we all mixing and matching of top and bottom + // boot devices. + + // Point to the next query block + ++qp; + if (strncmp(qp->id, "QRY", 3) != 0) { + // Oops, not CFI + return(-1); + } + if (_si(qp->buffer_size)) { + if ((CYGNUM_FLASH_INTERLEAVE << _si(qp->buffer_size)) != cfi->write_buffer_size) { + // As I said, the write buffers must match -- I suppose we + // could just as easily choose the smaller one. Perhaps + // somebody will add code to do that someday. + return(-1); + } + } else { + if (cfi->write_buffer_size != 0) { + return(-1); + } + } + + // Append the erase block regions from this device + if (qp->num_erase_block_regions == 0) { + // no erase blocking -- the device erases in bulk + cfi->region[idx].num_blocks = 1; + cfi->region[idx].block_size = 1 << qp->device_size; + if ((1 << qp->device_size) > max_block_size) { + max_block_size = 1 << qp->device_size; + } + cfi->num_regions++; + } else { + register int j; + int total_size = 0; + + for (j = 0; j < qp->num_erase_block_regions; j++) { + cfi->region[idx].num_blocks = _si(qp->regions[j].num)+1; + cfi->region[idx].block_size = _si(qp->regions[j].size)*256; + + total_size += + cfi->region[idx].num_blocks * cfi->region[idx].block_size; + + if (cfi->region[idx].block_size > max_block_size) { + max_block_size = cfi->region[idx].block_size; + } + idx++; + cfi->num_regions++; + } + + // Just so that we can assume that the number of regions + // and the size of the device match up, we verify it here. + if (total_size != (1 << qp->device_size)) { + return(-1); + } + } + cfi->max_block_size = max_block_size; + } +#endif // CYGNUM_FLASH_SERIES > 1 + + for (i = 0; i < cfi->num_regions; i++) { + cfi->region[i].total_size = + cfi->region[i].num_blocks * cfi->region[i].block_size; + } + + return 0; +} +#endif // !CYGOPT_FLASH_NO_CFI +int flash_block_op(volatile flash_t *block, unsigned int block_size, flash_t opcode, flash_t confirm) + __attribute__ ((section (".2ram.flash_block_op"))); +int flash_block_op(volatile flash_t *block, + unsigned int block_size, + flash_t opcode, + flash_t confirm) +{ + // This is a general purpose routine shared by 'flash_unlock_block()', + // 'flash_erase_block()', and 'flash_lock_block()'. It handles all + // of the messyness required to deal with bootblock type devices that + // have variable sized "erase partitions". + + volatile flash_t *ROM; + const struct FLASH_parsed_CFI *cfi = &flash_cfi; + flash_t stat = 0; + int timeout = 50000; + int block_len, sub_block_size; + volatile flash_t *op_block; + int region_idx = 0; + int flash_offset; + + // Get base address and map addresses to virtual addresses + ROM = FLASH_P2V(CYGNUM_FLASH_BASE_MASK & (unsigned int)block); + + region_idx = 0; + flash_offset = (unsigned)block - (unsigned)ROM; + while (flash_offset >= cfi->region[region_idx].total_size) { + flash_offset -= cfi->region[region_idx].total_size; + if (++region_idx == cfi->num_regions) { + // Huh -- how could this happen? + return(-1); + } + } + + op_block = block = FLASH_P2V(block); + block_len = block_size; + + // Clear any error conditions + op_block[0] = FLASH_Clear_Status; + + // Erase block + while (block_len > 0) { + op_block[0] = opcode; + op_block[0] = confirm; + + timeout = 5000000; + while(((stat = op_block[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { + if (--timeout == 0) break; + } + + sub_block_size = cfi->region[region_idx].block_size; + if (flash_offset > cfi->region[region_idx].total_size) { + region_idx++; + } + + block_len -= sub_block_size; + flash_offset += sub_block_size; + op_block = FLASH_P2V((unsigned int)op_block + sub_block_size); + } + + // Restore ROM to "normal" mode + block[0] = FLASH_Reset; + + return stat; +} // EOF strata.c Index: devs/flash/intel/strata/current/src/strata.h =================================================================== RCS file: /cvs/ecos/ecos/packages/devs/flash/intel/strata/current/src/strata.h,v retrieving revision 1.5 diff -u -5 -p -r1.5 strata.h --- devs/flash/intel/strata/current/src/strata.h 12 Apr 2003 02:47:46 -0000 1.5 +++ devs/flash/intel/strata/current/src/strata.h 14 Oct 2003 14:36:27 -0000 @@ -41,11 +41,11 @@ //####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas, hmt -// Contributors: gthomas +// Contributors: gthomas, wpd, jani // Date: 2001-02-14 // Purpose: // Description: // //####DESCRIPTIONEND#### @@ -59,42 +59,120 @@ // ------------------------------------------------------------------------ // // It is expected that the above include defined all the properties of the // device we want to drive: the choices this module supports include: // +// The following table may be of historical value. The current incarnation +// of the driver is not limited to these specific devices. +// // Buffered Read Block // write query locking -// 28FxxxB3 - Bootblock - no no no -// 28FxxxC3 - StrataFlash - no yes yes -// 28FxxxJ3 - Advanced StrataFlash - yes yes yes +// 28FxxxB3 - Advanced Bootblock - no no no +// 28FxxxC3 - Advanced+ Bootblock - no yes yes +// 28FxxxJ3 - StrataFlash - yes yes yes // 28FxxxK3 - Synchronous StrataFlash - yes yes yes +// 28FxxxW3 - Wireless Flash - no yes yes +// 28FxxxL3 - Wireless StrataFlash - no yes yes // -// These options are controlled by defining or not, in that include file, -// these symbols (not CDL options, just symbols - though they could be CDL -// in future) -// CYGOPT_FLASH_IS_BOOTBLOCK - for xxxB3 devices. -// CYGOPT_FLASH_IS_NOT_ADVANCED - for xxxC3 devices. -// CYGOPT_FLASH_IS_SYNCHRONOUS - for xxxK3 devices. -// none of the above - for xxxJ3 devices. -// (Advanced seems to be usual these days hence the sense of that opt) +// Various options in this driver are controlled by defining or not, +// in that include file, these symbols (not CDL options, just symbols +// - though they could be CDL in future) +// +// CYGOPT_FLASH_NO_CFI +// - define this if the device does not support the +// "Common Flash Interface". If this is defined, you +// must define CYGOPT_FLASH_SYNTHETIC_CFI to contain the +// information that is parsed from the CFI. See the +// definition of 'struct FLASH_parsed_CFI' at the end of +// this file. Alternatively, you may define the +// CYGOPT_FLASH_IS_BOOTBLOCK symbol if your device matches +// the narrow set of parameters encompassed by the xxxB3 +// devices. +// +// CYGOPT_FLASH_SYNTHETIC_CFI +// - This should contain the static CFI information for a +// device that does not support the CFI. (Are there any +// such devices? -- perhaps). +// +// CYGOPT_FLASH_IS_BOOTBLOCK +// - Define this symbol for xxxB3 devices, which this driver +// continues to support. +// +// CYGOPT_FLASH_UNLOCKS_SINGLE_BLOCKS +// - Define this symbol if the device unlocks individual +// blocks in response to the 'FLASH_Clear_Locks' (0x60) +// Most modern devices should will probably require this. +// The xxxJ3 and xxxB3 devices do not require this. // // Other properties are controlled by these symbols: -// CYGNUM_FLASH_DEVICES number of devices across the databus +// CYGNUM_FLASH_INTERLEAVE number of devices across the databus +// CYGNUM_FLASH_SERIES number of devices that occupy +// consecutive (virtual) addresses +// CYGNUM_FLASH_SIZE When 'CYGNUM_FLASH_SERIES' is > 1, +// this specifies the size (in +// bytes) of each device in +// series. (This should be fixed +// someday so that +// 'flash_query()' determines the +// size automatically based on +// the CFI read from the device.) // CYGNUM_FLASH_WIDTH number of bits in each device // CYGNUM_FLASH_BLANK 1 if blank is allones, 0 if 0 // CYGNUM_FLASH_BASE base address // CYGNUM_FLASH_BASE_MASK a mask to get base address from any // // for example, a 32-bit memory could be made from 1x32bit, 2x16bit or // 4x8bit devices; usually 16bit ones are chosen in practice, so we would -// have CYGNUM_FLASH_DEVICES = 2, and CYGNUM_FLASH_WIDTH = 16. Both +// have CYGNUM_FLASH_INTERLEAVE = 2, and CYGNUM_FLASH_WIDTH = 16. Both // devices would be handled simulataneously, via 32bit bus operations. // Some CPUs can handle a single 16bit device as 32bit memory "by magic". -// In that case, CYGNUM_FLASH_DEVICES = 1 and CYGNUM_FLASH_WIDTH = 16, and +// In that case, CYGNUM_FLASH_INTERLEAVE = 1 and CYGNUM_FLASH_WIDTH = 16, and // the device is managed using only 16bit bus operations. +// +// +// Obsolete Properties: +// CYGOPT_FLASH_IS_NOT_ADVANCED +// - This used to control whether the 'FLASH_Write_Buffer' +// command was defined (and, hence, used). Now, write +// buffering is used only if the device indicates that it +// supports write buffering via the CFI. +// +// CYGOPT_FLASH_IS_SYNCHRONOUS +// - This used to force 'flash_unlock_block()' to assume that +// the 'FLASH_Clear_Locks' command cleared all of the locks. +// This has been renamed to be 'CYGOPT_FLASH_UNLOCKS_ALL_BLOCKS'. +// + +#ifdef CYGNUM_FLASH_DEVICES +# warning "Definition of CYGNUM_FLASH_DEVICES in strata driver is deprecated" +# define CYGNUM_FLASH_INTERLEAVE CYGNUM_FLASH_DEVICES +#endif + +#ifndef CYGNUM_FLASH_INTERLEAVE +# define CYGNUM_FLASH_INTERLEAVE 1 +#endif + +#ifndef CYGNUM_FLASH_SERIES +# define CYGNUM_FLASH_SERIES 1 +#endif + +#ifndef CYGNUM_FLASH_SIZE +# if CYGNUM_FLASH_SERIES > 1 +# error "Must define CYGNUM_FLASH_SIZE as well as CYGNUM_FLASH_SERIES" +# else +# define CYGNUM_FLASH_SIZE 0 +# endif +#endif + +#ifdef CYGOPT_FLASH_IS_BOOTBLOCK +// The only time this should be defined is on platforms that use the +// xxxB3 part, which does not support CFI +# ifndef CYGOPT_FLASH_NO_CFI +# define CYGOPT_FLASH_NO_CFI +# endif +#endif -#define CYGNUM_FLASH_INTERLEAVE CYGNUM_FLASH_DEVICES #define _FLASH_PRIVATE_ #include #define flash_t flash_data_t // ------------------------------------------------------------------------ @@ -115,31 +193,21 @@ // // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ #define FLASH_Read_ID FLASHWORD( 0x90 ) -#ifndef CYGOPT_FLASH_IS_BOOTBLOCK -#define FLASH_Read_Query FLASHWORD( 0x98 ) // Strata only -#endif +#define FLASH_Read_Query FLASHWORD( 0x98 ) #define FLASH_Read_Status FLASHWORD( 0x70 ) #define FLASH_Clear_Status FLASHWORD( 0x50 ) #define FLASH_Status_Ready FLASHWORD( 0x80 ) -#ifdef CYGOPT_FLASH_IS_BOOTBLOCK -#define FLASH_Program FLASHWORD( 0x40 ) // BootBlock only -#else -#define FLASH_Program FLASHWORD( 0x10 ) -#endif +#define FLASH_Program FLASHWORD( 0x40 ) #define FLASH_Block_Erase FLASHWORD( 0x20 ) -#ifndef CYGOPT_FLASH_IS_BOOTBLOCK -#ifndef CYGOPT_FLASH_IS_NOT_ADVANCED -#define FLASH_Write_Buffer FLASHWORD( 0xE8 ) // *Advanced* Strata only -#endif // flash is advanced ie. has Write Buffer command -#define FLASH_Set_Lock FLASHWORD( 0x60 ) // Strata only -#define FLASH_Set_Lock_Confirm FLASHWORD( 0x01 ) // Strata only -#define FLASH_Clear_Locks FLASHWORD( 0x60 ) // Strata only -#define FLASH_Clear_Locks_Confirm FLASHWORD( 0xD0 ) // Strata only -#endif +#define FLASH_Write_Buffer FLASHWORD( 0xE8 ) +#define FLASH_Set_Lock FLASHWORD( 0x60 ) +#define FLASH_Set_Lock_Confirm FLASHWORD( 0x01 ) +#define FLASH_Clear_Locks FLASHWORD( 0x60 ) +#define FLASH_Clear_Locks_Confirm FLASHWORD( 0xD0 ) #define FLASH_Confirm FLASHWORD( 0xD0 ) //#define FLASH_Configure FLASHWORD( 0xB8 ) //#define FLASH_Configure_ReadyWait FLASHWORD( 0x00 ) //#define FLASH_Configure_PulseOnErase FLASHWORD( 0x01 ) //#define FLASH_Configure_PulseOnProgram FLASHWORD( 0x02 ) @@ -156,22 +224,46 @@ // ------------------------------------------------------------------------ #define FLASH_Intel_code 0x89 // NOT mapped to 16+16 // Extended query information +#define MAX_NUM_ERASE_BLOCK_REGIONS 3 struct FLASH_query { unsigned char manuf_code; // FLASH_Intel_code unsigned char device_code; unsigned char _unused0[14]; unsigned char id[3]; // Q R Y unsigned char _unused1[20]; unsigned char device_size; unsigned char device_interface[2]; unsigned char buffer_size[2]; - unsigned char is_block_oriented; - unsigned char num_regions[2]; - unsigned char region_size[2]; + unsigned char num_erase_block_regions; + struct { + unsigned char num[2]; + unsigned char size[2]; + } __attribute__((packed)) regions[MAX_NUM_ERASE_BLOCK_REGIONS]; }; +#define FLASH_MAX_REGIONS (MAX_NUM_ERASE_BLOCK_REGIONS * CYGNUM_FLASH_SERIES) + +struct FLASH_parsed_CFI { + int manuf_code; + int device_code; + unsigned write_buffer_size; // 0 => no write buffer + unsigned num_regions; + struct region { + unsigned num_blocks; + unsigned total_size; + unsigned block_size; + } region[FLASH_MAX_REGIONS]; + unsigned max_block_size; +}; + +extern struct FLASH_parsed_CFI flash_cfi; + +extern int flash_block_op(volatile flash_t *block, + unsigned int block_size, + flash_t opcode, + flash_t confirm); #endif // CYGONCE_DEVS_FLASH_INTEL_STRATA_FLASH_H // ------------------------------------------------------------------------ // EOF strata.h