diff --git a/jtag/ChangeLog b/jtag/ChangeLog index bb21eb27..e97082a2 100644 --- a/jtag/ChangeLog +++ b/jtag/ChangeLog @@ -1,3 +1,11 @@ +2008-12-03 Arnim Laeuger + + * include/flash.h, src/flash/amd_flash.c, src/flash/amd.c, + src/flash/intel.c, src/flash/flash.c, configure.ac: + restructure multi-byte flash programming support + flashmem no longer needs to know about the capabilities of + the flash chip to handle multi-byte programming + 2008-12-02 Arnim Laeuger * include/flash/intel.h, src/flash/intel.c: diff --git a/jtag/configure.ac b/jtag/configure.ac index 7e464ca3..a6fc0f48 100644 --- a/jtag/configure.ac +++ b/jtag/configure.ac @@ -565,9 +565,9 @@ AS_IF([test "x$dmalloc" = xyes], [ # Enable flash multi-byte write mode? AC_ARG_ENABLE(flash_multi_byte, [AS_HELP_STRING([--enable-flash_multi_byte], [Enable flash multi-byte write mode])], -[multi_byte=$enableval], [multi_byte=yes]) -AS_IF([test "x$multi_byte" = xyes], [ - AC_DEFINE(MULTI_BYTE, 1, [define for flash multi-byte write mode]) +[flash_multi_byte=$enableval], [flash_multi_byte=yes]) +AS_IF([test "x$flash_multi_byte" = xyes], [ + AC_DEFINE(FLASH_MULTI_BYTE, 1, [define for flash multi-byte write mode]) ]) diff --git a/jtag/include/flash.h b/jtag/include/flash.h index 70fd6ebe..54100daf 100644 --- a/jtag/include/flash.h +++ b/jtag/include/flash.h @@ -68,8 +68,7 @@ typedef struct { void (*print_info)( cfi_array_t *cfi_array ); int (*erase_block)( cfi_array_t *cfi_array, uint32_t adr ); int (*unlock_block)( cfi_array_t *cfi_array, uint32_t adr ); - int (*program)( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); - int (*program_buffer)( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ); + int (*program)( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ); void (*readarray)( cfi_array_t *cfi_array ); } flash_driver_t; diff --git a/jtag/src/flash/amd.c b/jtag/src/flash/amd.c index b985397e..d76d4430 100644 --- a/jtag/src/flash/amd.c +++ b/jtag/src/flash/amd.c @@ -27,6 +27,8 @@ * September 20, 2002 Rev B, 22366b8.pdf * [2] Advanced Micro Devices, "Am29LV642D", * August 14, 2001 Rev A, 25022.pdf + * [3] Spansion, "S29GL-N MirrorBit Flash Family" + * October 13, 2006 Rev B, Amendment 3 * */ @@ -47,7 +49,10 @@ static int dbg = 0; static int amd_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr ); static int amd_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr ); -static int amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int amd_flash_program_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int amd_flash_program_buffer( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ); +static int amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ); +static int amd_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ); static void amd_flash_read_array( cfi_array_t *cfi_array ); /* The code below assumes a connection of the flash chip address LSB (A0) @@ -393,7 +398,7 @@ amd_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr ) } static int -amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) +amd_flash_program_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) { int status; bus_t *bus = cfi_array->bus; @@ -416,6 +421,9 @@ amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) static int amd_program_buffer_status( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) { + /* NOTE: Status polling according to [3], Figure 1. + The current method for status polling is not compatible with 32 bit (2x16) configurations + since it only checks the DQ7 bit of the lower chip. */ bus_t *bus = cfi_array->bus; int timeout; const uint32_t dq7mask = (1 << 7); @@ -445,33 +453,102 @@ amd_program_buffer_status( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) static int amd_flash_program_buffer( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ) { + /* NOTE: Write buffer programming operation according to [3], Figure 1. */ int status; bus_t *bus = cfi_array->bus; + cfi_chip_t *cfi_chip = cfi_array->cfi_chips[0]; int o = amd_flash_address_shift( cfi_array ); - int idx; - uint32_t sa = adr; + int wb_bytes = cfi_chip->cfi.device_geometry.max_bytes_write; + int chip_width = cfi_chip->width; + int offset = 0; if (dbg) printf("\nflash_program_buffer 0x%08X, count 0x%08X\n", adr, count); - bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa ); - bus_write( bus, cfi_array->address + (0x02aa << o), 0x00550055 ); - bus_write( bus, adr, 0x00250025 ); - bus_write( bus, sa, count-1 ); + while (count > 0) { + int wcount, idx; + uint32_t sa = adr; + + /* determine length of next multi-byte write */ + wcount = wb_bytes - (adr % wb_bytes); + wcount /= chip_width; + if (wcount > count) + wcount = count; + + bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa ); + bus_write( bus, cfi_array->address + (0x02aa << o), 0x00550055 ); + bus_write( bus, adr, 0x00250025 ); + bus_write( bus, sa, wcount-1 ); + + /* write payload to write buffer */ + for (idx = 0; idx < wcount; idx++) { + bus_write( bus, adr, buffer[offset + idx] ); + adr += cfi_array->bus_width; + } + offset += wcount; - /* write payload to write buffer */ - for (idx = 0; idx < count; idx++) { - bus_write( bus, adr, buffer[idx] ); - adr += cfi_array->bus_width; + /* program buffer to flash */ + bus_write( bus, sa, 0x00290029 ); + + status = amd_program_buffer_status( cfi_array, adr - cfi_array->bus_width, buffer[offset - 1] ); + /* amd_flash_read_array(ps); */ + if (status != 1) + return 1; + + count -= wcount; } - /* program buffer to flash */ - bus_write( bus, sa, 0x00290029 ); + return 0; +} - status = amd_program_buffer_status( cfi_array, adr - cfi_array->bus_width, buffer[idx - 1] ); - /* amd_flash_read_array(ps); */ +static int +amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ) +{ + cfi_query_structure_t *cfi = &(cfi_array->cfi_chips[0]->cfi); + int max_bytes_write = cfi->device_geometry.max_bytes_write; + +#ifndef FLASH_MULTI_BYTE + max_bytes_write = 0; +#endif + + /* multi-byte writes supported? */ + if (max_bytes_write > 0) + return amd_flash_program_buffer( cfi_array, adr, buffer, count ); + + else { + /* unroll buffer to single writes */ + int idx; + + for (idx = 0; idx < count; idx++) { + int status = amd_flash_program_single( cfi_array, adr, buffer[idx] ); + if (status) + return status; + adr += cfi_array->bus_width; + } + } - return !status; + return 0; +} + +static int +amd_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ) +{ + /* Single byte programming is forced for 32 bit (2x16) flash configuration. + a) lack of testing capbilities for 2x16 multi-byte write operation + b) amd_flash_program_buffer() is not 2x16 compatible at the moment + due to insufficiency of amd_program_buffer_status() + Closing these issues will obsolete amd_flash_program32(). */ + int idx; + + /* unroll buffer to single writes */ + for (idx = 0; idx < count; idx++) { + int status = amd_flash_program_single( cfi_array, adr, buffer[idx] ); + if (status) + return status; + adr += cfi_array->bus_width; + } + + return 0; } static void @@ -489,8 +566,7 @@ flash_driver_t amd_32_flash_driver = { amd_flash_print_info, amd_flash_erase_block, amd_flash_unlock_block, - amd_flash_program, - NULL, + amd_flash_program32, amd_flash_read_array, }; @@ -503,7 +579,6 @@ flash_driver_t amd_16_flash_driver = { amd_flash_erase_block, amd_flash_unlock_block, amd_flash_program, - amd_flash_program_buffer, amd_flash_read_array, }; @@ -516,6 +591,5 @@ flash_driver_t amd_8_flash_driver = { amd_flash_erase_block, amd_flash_unlock_block, amd_flash_program, - amd_flash_program_buffer, amd_flash_read_array, }; diff --git a/jtag/src/flash/amd_flash.c b/jtag/src/flash/amd_flash.c index 2606c4f5..65ce01f1 100644 --- a/jtag/src/flash/amd_flash.c +++ b/jtag/src/flash/amd_flash.c @@ -80,7 +80,8 @@ static int amd_29xx040_status( bus_t *bus, uint32_t adr, unsigned short data ); static void amd_29xx040_print_info( cfi_array_t *cfi_array ); static void amd_29xx040_read_array( cfi_array_t *cfi_array ); static int amd_29xx040_erase_block( cfi_array_t *cfi_array, uint32_t adr ); -static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int amd_29xx040_program_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ); static int amd_29xx040_unlock_block( cfi_array_t *cfi_array, uint32_t adr ); int amd_detect(bus_t *bus, uint32_t adr, cfi_array_t **cfi_array ) @@ -302,7 +303,7 @@ static int amd_29xx040_erase_block( cfi_array_t *cfi_array, uint32_t adr ) return FLASH_ERASE_ERROR; } -static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) +static int amd_29xx040_program_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) { int status; bus_t *bus = cfi_array->bus; @@ -334,6 +335,21 @@ static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t d return !status; } +static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ) +{ + int idx; + + /* unroll buffer to single writes */ + for (idx = 0; idx < count; idx++) { + int status = amd_29xx040_program_single( cfi_array, adr, buffer[idx] ); + if (status) + return status; + adr += cfi_array->bus_width; + } + + return 0; +} + static int amd_29xx040_unlock_block( cfi_array_t *cfi_array, uint32_t adr ) { printf( "flash_unlock_block 0x%08X IGNORE\n", adr ); @@ -350,6 +366,5 @@ flash_driver_t amd_29xx040_flash_driver = { amd_29xx040_erase_block, amd_29xx040_unlock_block, amd_29xx040_program, - NULL, amd_29xx040_read_array, }; diff --git a/jtag/src/flash/flash.c b/jtag/src/flash/flash.c index 4647c972..8f4241f5 100644 --- a/jtag/src/flash/flash.c +++ b/jtag/src/flash/flash.c @@ -161,7 +161,7 @@ flashmsbin( bus_t *bus, FILE *f ) printf( "\r" ); fflush(stdout); fread( &data, sizeof data, 1, f ); - if (flash_driver->program( cfi_array, a, data )) { + if (flash_driver->program( cfi_array, a, &data, 1 )) { printf( _("\nflash error\n") ); return; } @@ -250,9 +250,10 @@ flashmem( bus_t *bus, FILE *f, uint32_t addr ) int neb; int bus_width; int chip_width; - uint32_t *write_buffer = NULL; - uint32_t write_buffer_adr = 0; - int write_buffer_count, cfi_max_entries; +#define BSIZE (1 << 12) + uint32_t write_buffer[BSIZE]; + int write_buffer_count; + uint32_t write_buffer_adr; set_flash_driver(); if (!cfi_array || !flash_driver) { @@ -267,20 +268,6 @@ flashmem( bus_t *bus, FILE *f, uint32_t addr ) for (i = 0, neb = 0; i < cfi->device_geometry.number_of_erase_regions; i++) neb += cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks; - /* prepare multi-byte write */ -#ifdef MULTI_BYTE - cfi_max_entries = flash_driver->program_buffer ? cfi->device_geometry.max_bytes_write / flash_driver->bus_width : 0; -#else - cfi_max_entries = 0; -#endif - if (cfi_max_entries > 0) { - write_buffer = (uint32_t *)calloc( cfi_max_entries, sizeof( uint32_t ) ); - if (!write_buffer) { - printf( _("Out of memory!\n") ); - return; - } - } - erased = malloc( neb * sizeof *erased ); if (!erased) { printf( _("Out of memory!\n") ); @@ -291,14 +278,15 @@ flashmem( bus_t *bus, FILE *f, uint32_t addr ) printf( _("program:\n") ); adr = addr; - write_buffer_count = 0; while (!feof( f )) { uint32_t data; -#define BSIZE 4096 uint8_t b[BSIZE]; int bc = 0, bn = 0, btr = BSIZE; int block_no = find_block( cfi, adr - cfi_array->address, bus_width, chip_width, &btr); + write_buffer_count = 0; + write_buffer_adr = adr; + if(btr > BSIZE) btr = BSIZE; bn = fread( b, 1, btr, f ); @@ -311,7 +299,7 @@ flashmem( bus_t *bus, FILE *f, uint32_t addr ) for (bc = 0; bc < bn; bc += flash_driver->bus_width) { int j; - if ((adr & 0xFF) == 0) { + if ((adr & (BSIZE-1)) == 0) { printf( _("addr: 0x%08X"), adr ); printf( "\r" ); fflush( stdout ); @@ -324,45 +312,18 @@ flashmem( bus_t *bus, FILE *f, uint32_t addr ) else data |= b[bc + j] << (j * 8); - if (cfi_max_entries > 0) { - /* handle multi-byte writes via write buffer */ - if (write_buffer_count == 0) - write_buffer_adr = adr; /* note address of first entry that goes into write buffer */ - write_buffer[write_buffer_count++] = data; - - if ((write_buffer_count == cfi_max_entries) || - ((adr + flash_driver->bus_width) % (cfi_max_entries * flash_driver->bus_width) == 0)) { - /* program buffer to flash conditions matched: - a) write buffer is full (cfi_max_bytes_write bytes entered) - b) next adr will leave current page */ - if (flash_driver->program_buffer( cfi_array, write_buffer_adr, write_buffer, write_buffer_count )) { - printf( _("\nflash error\n") ); - return; - } - write_buffer_count = 0; - } + /* store data in write buffer, will be programmed to flash later */ + write_buffer[write_buffer_count++] = data; - } else { - /* single word write */ - if (flash_driver->program( cfi_array, adr, data )) { - printf( _("\nflash error\n") ); - return; - } - } adr += flash_driver->bus_width; } - } - /* flush partly filled write buffer */ - if (cfi_max_entries > 0) { - if (write_buffer_count > 0) { - if (flash_driver->program_buffer( cfi_array, write_buffer_adr, write_buffer, write_buffer_count )) { - free( write_buffer ); + if (write_buffer_count > 0) + if (flash_driver->program( cfi_array, write_buffer_adr, write_buffer, write_buffer_count )) { printf( _("\nflash error\n") ); return; } - } - free( write_buffer ); + } printf( _("addr: 0x%08X\n"), adr - flash_driver->bus_width); diff --git a/jtag/src/flash/intel.c b/jtag/src/flash/intel.c index 10802855..b87a3675 100644 --- a/jtag/src/flash/intel.c +++ b/jtag/src/flash/intel.c @@ -30,6 +30,8 @@ * Application Note 646", April 2000, Order Number: 292204-004 * [4] Advanced Micro Devices, "Common Flash Memory Interface Publication 100 Vendor & Device * ID Code Assignments", December 1, 2001, Volume Number: 96.1 + * [5] Micron Technology, Inc. "Q-Flash Memory MT28F123J3, MT28F640J3, MT28F320J3", + * MT28F640J3.fm - Rev. N 3/05 EN * */ @@ -48,10 +50,13 @@ static int intel_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr ); static int intel_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr ); -static int intel_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int intel_flash_program_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int intel_flash_program_buffer( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ); +static int intel_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ); static int intel_flash_erase_block32( cfi_array_t *cfi_array, uint32_t adr ); static int intel_flash_unlock_block32( cfi_array_t *cfi_array, uint32_t adr ); -static int intel_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int intel_flash_program32_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int intel_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ); /* autodetect, we can handle this chip */ static int @@ -267,7 +272,7 @@ intel_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr ) } static int -intel_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) +intel_flash_program_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) { uint16_t sr; bus_t *bus = cfi_array->bus; @@ -288,36 +293,83 @@ intel_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) static int intel_flash_program_buffer( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ) { + /* NOTE: Write-to-buffer programming operation according to [5], Figure 9 */ uint16_t sr; bus_t *bus = cfi_array->bus; - int idx; - uint32_t block_adr = adr; - - /* issue command WRITE_TO_BUFFER */ - bus_write( bus, cfi_array->address, CFI_INTEL_CMD_CLEAR_STATUS_REGISTER ); - bus_write( bus, adr, CFI_INTEL_CMD_WRITE_TO_BUFFER ); - /* poll XSR7 == 1 */ - while (!((sr = bus_read( bus, cfi_array->address ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ - - /* write count value (number of upcoming writes - 1) */ - bus_write( bus, adr, count-1 ); - - /* write payload to buffer */ - for (idx = 0; idx < count; idx++) { - bus_write( bus, adr, buffer[idx] ); - adr += cfi_array->bus_width; + cfi_chip_t *cfi_chip = cfi_array->cfi_chips[0]; + int wb_bytes = cfi_chip->cfi.device_geometry.max_bytes_write; + int chip_width = cfi_chip->width; + int offset = 0; + + while (count > 0) { + int wcount, idx; + uint32_t block_adr = adr; + + /* determine length of next multi-byte write */ + wcount = wb_bytes - (adr % wb_bytes); + wcount /= chip_width; + if (wcount > count) + wcount = count; + + /* issue command WRITE_TO_BUFFER */ + bus_write( bus, cfi_array->address, CFI_INTEL_CMD_CLEAR_STATUS_REGISTER ); + bus_write( bus, adr, CFI_INTEL_CMD_WRITE_TO_BUFFER ); + /* poll XSR7 == 1 */ + while (!((sr = bus_read( bus, cfi_array->address ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ + + /* write count value (number of upcoming writes - 1) */ + bus_write( bus, adr, wcount-1 ); + + /* write payload to buffer */ + for (idx = 0; idx < wcount; idx++) { + bus_write( bus, adr, buffer[offset + idx] ); + adr += cfi_array->bus_width; + } + offset += wcount; + + /* issue command WRITE_CONFIRM */ + bus_write( bus, block_adr, CFI_INTEL_CMD_WRITE_CONFIRM ); + + count -= wcount; } - /* issued command WRITE_CONFIRM */ - bus_write( bus, block_adr, CFI_INTEL_CMD_WRITE_CONFIRM ); - /* poll SR7 == 1 */ while (!((sr = bus_read( bus, cfi_array->address ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ if (sr != CFI_INTEL_SR_READY) { printf( _("flash: unknown error while programming\n") ); return FLASH_ERROR_UNKNOWN; - } else - return 0; + } + + return 0; +} + +static int +intel_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ) +{ + cfi_query_structure_t *cfi = &(cfi_array->cfi_chips[0]->cfi); + int max_bytes_write = cfi->device_geometry.max_bytes_write; + +#ifndef FLASH_MULTI_BYTE + max_bytes_write = 0; +#endif + + /* multi-byte writes supported? */ + if (max_bytes_write > 0) + return intel_flash_program_buffer( cfi_array, adr, buffer, count ); + + else { + /* unroll buffer to single writes */ + int idx; + + for (idx = 0; idx < count; idx++) { + int status = intel_flash_program_single( cfi_array, adr, buffer[idx] ); + if (status) + return status; + adr += cfi_array->bus_width; + } + } + + return 0; } static int @@ -359,7 +411,7 @@ intel_flash_unlock_block32( cfi_array_t *cfi_array, uint32_t adr ) } static int -intel_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) +intel_flash_program32_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) { uint32_t sr; bus_t *bus = cfi_array->bus; @@ -377,6 +429,26 @@ intel_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) return 0; } +static int +intel_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ) +{ + /* Single byte programming is forced for 32 bit (2x16) flash configuration. + a) lack of testing capbilities for 2x16 multi-byte write operation + b) no implementation of intel_flash_program32_buffer() available + Closing these issues will enable multi-byte for 2x16 as well. */ + int idx; + + /* unroll buffer to single writes */ + for (idx = 0; idx < count; idx++) { + int status = intel_flash_program32_single( cfi_array, adr, buffer[idx] ); + if (status) + return status; + adr += cfi_array->bus_width; + } + + return 0; +} + static void intel_flash_readarray32( cfi_array_t *cfi_array ) { @@ -400,7 +472,6 @@ flash_driver_t intel_32_flash_driver = { intel_flash_erase_block32, intel_flash_unlock_block32, intel_flash_program32, - NULL, intel_flash_readarray32, }; @@ -413,7 +484,6 @@ flash_driver_t intel_16_flash_driver = { intel_flash_erase_block, intel_flash_unlock_block, intel_flash_program, - intel_flash_program_buffer, intel_flash_readarray, }; @@ -426,6 +496,5 @@ flash_driver_t intel_8_flash_driver = { intel_flash_erase_block, intel_flash_unlock_block, intel_flash_program, - intel_flash_program_buffer, intel_flash_readarray, };