From 37d72e13f37f87b3928f850c8a0e5f0cf1c7df73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnim=20L=C3=A4uger?= Date: Tue, 2 Dec 2008 00:18:59 +0000 Subject: [PATCH] support multi-byte write mode for certain flash chips git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1390 b68d4a1b-bc3d-0410-92ed-d4ac073336b7 --- jtag/ChangeLog | 7 ++++ jtag/configure.ac | 9 +++++ jtag/include/flash.h | 1 + jtag/src/flash/amd.c | 78 ++++++++++++++++++++++++++++++++++---- jtag/src/flash/amd_flash.c | 1 + jtag/src/flash/flash.c | 56 ++++++++++++++++++++++++++- jtag/src/flash/intel.c | 3 ++ 7 files changed, 146 insertions(+), 9 deletions(-) diff --git a/jtag/ChangeLog b/jtag/ChangeLog index 556c6058..af4e4b3c 100644 --- a/jtag/ChangeLog +++ b/jtag/ChangeLog @@ -1,4 +1,11 @@ 2008-12-01 Arnim Laeuger + * include/flash.h, src/flash/amd_flash.c, src/flash/amd.c, + src/flash/intel.c, src/flash/flash.c, configure.ac: + support multi-byte write mode + chips must match the following criteria to qualify + - CFI data specifies multi-byte write mode supported + - handled by amd.c + - 8 or 16 bit interface * src/bus/prototype.c (prototype_bus_new): consider amode parameter properly when specified on the command line. pervious version didn't set ASHIFT in diff --git a/jtag/configure.ac b/jtag/configure.ac index d62b9852..7e464ca3 100644 --- a/jtag/configure.ac +++ b/jtag/configure.ac @@ -562,6 +562,15 @@ 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]) +]) + + AC_OUTPUT dnl diff --git a/jtag/include/flash.h b/jtag/include/flash.h index 2e65438c..70fd6ebe 100644 --- a/jtag/include/flash.h +++ b/jtag/include/flash.h @@ -69,6 +69,7 @@ typedef struct { 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 ); 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 9876c080..b985397e 100644 --- a/jtag/src/flash/amd.c +++ b/jtag/src/flash/amd.c @@ -275,7 +275,7 @@ amd_flash_print_info( cfi_array_t *cfi_array ) switch (mid) { case 0x0001: printf( "AMD" ); - printf( _("\n\tChip: ") ); + printf( _("\n\tChip: ") ); switch (cid) { case 0x0049: printf( "AM29LV160DB" ); @@ -294,7 +294,7 @@ amd_flash_print_info( cfi_array_t *cfi_array ) break; case 0x227E: /* 16-bit mode */ case 0x007E: /* 8-bit mode */ - printf( "S92GL" ); + printf( "S92GLxxxN" ); break; default: printf ( _("Unknown (ID 0x%04x)"), cid ); @@ -303,7 +303,7 @@ amd_flash_print_info( cfi_array_t *cfi_array ) break; case 0x001f: printf( "Atmel" ); - printf( _("\n\tChip: ") ); + printf( _("\n\tChip: ") ); switch (cid) { case 0x01d2: printf( "AT49BW642DT" ); @@ -318,7 +318,7 @@ amd_flash_print_info( cfi_array_t *cfi_array ) break; case 0x0020: printf( "ST/Samsung" ); - printf( _("\n\tChip: ") ); + printf( _("\n\tChip: ") ); switch (cid) { case 0x00ca: printf( "M29W320DT" ); @@ -336,7 +336,7 @@ amd_flash_print_info( cfi_array_t *cfi_array ) break; case 0x00C2: printf( "Macronix" ); - printf( _("\n\tChip: ") ); + printf( _("\n\tChip: ") ); switch (cid) { case 0x2249: printf( "MX29LV160B" ); @@ -413,6 +413,67 @@ amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) return !status; } +static int +amd_program_buffer_status( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) +{ + bus_t *bus = cfi_array->bus; + int timeout; + const uint32_t dq7mask = (1 << 7); + const uint32_t dq5mask = (1 << 5); + uint32_t bit7 = data & dq7mask; + uint32_t data1; + + for (timeout = 0; timeout < 7000; timeout++) { + data1 = bus_read( bus, adr ); + if (dbg) + printf( "amd_program_buffer_status %d: %04X (%04X) = %04X\n", timeout, data1, (data1 & dq7mask), bit7 ); + if ((data1 & dq7mask) == bit7) + return 1; + + if ((data1 & dq5mask) == dq5mask) + break; + usleep( 100 ); + } + + data1 = bus_read( bus, adr ); + if ((data1 & dq7mask) == bit7) + return 1; + + return 0; +} + +static int +amd_flash_program_buffer( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count ) +{ + int status; + bus_t *bus = cfi_array->bus; + int o = amd_flash_address_shift( cfi_array ); + int idx; + uint32_t sa = adr; + + 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 ); + + /* 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[idx - 1] ); + /* amd_flash_read_array(ps); */ + + return !status; +} + static void amd_flash_read_array( cfi_array_t *cfi_array ) { @@ -429,29 +490,32 @@ flash_driver_t amd_32_flash_driver = { amd_flash_erase_block, amd_flash_unlock_block, amd_flash_program, + NULL, amd_flash_read_array, }; flash_driver_t amd_16_flash_driver = { 2, /* buswidth */ N_("AMD/Fujitsu Standard Command Set"), - N_("supported: AMD 29LV800B; 1x16 Bit"), + N_("supported: AMD 29LV800B, S92GLxxxN; 1x16 Bit"), amd_flash_autodetect16, amd_flash_print_info, amd_flash_erase_block, amd_flash_unlock_block, amd_flash_program, + amd_flash_program_buffer, amd_flash_read_array, }; flash_driver_t amd_8_flash_driver = { 1, /* buswidth */ N_("AMD/Fujitsu Standard Command Set"), - N_("supported: AMD 29LV160, AMD 29LV065D, AMD 29LV040B; 1x8 Bit"), + N_("supported: AMD 29LV160, AMD 29LV065D, AMD 29LV040B, S92GLxxxN; 1x8 Bit"), amd_flash_autodetect8, amd_flash_print_info, 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 44083784..2606c4f5 100644 --- a/jtag/src/flash/amd_flash.c +++ b/jtag/src/flash/amd_flash.c @@ -350,5 +350,6 @@ 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 d752738d..4647c972 100644 --- a/jtag/src/flash/flash.c +++ b/jtag/src/flash/flash.c @@ -250,6 +250,9 @@ 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; set_flash_driver(); if (!cfi_array || !flash_driver) { @@ -264,6 +267,20 @@ 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") ); @@ -274,6 +291,7 @@ 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 @@ -306,13 +324,47 @@ flashmem( bus_t *bus, FILE *f, uint32_t addr ) else data |= b[bc + j] << (j * 8); - if (flash_driver->program( cfi_array, adr, data )) { + 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; + } + + } 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 ); printf( _("\nflash error\n") ); return; } - adr += flash_driver->bus_width; } + free( write_buffer ); } + printf( _("addr: 0x%08X\n"), adr - flash_driver->bus_width); flash_driver->readarray( cfi_array ); diff --git a/jtag/src/flash/intel.c b/jtag/src/flash/intel.c index b21df7ed..5cb8180b 100644 --- a/jtag/src/flash/intel.c +++ b/jtag/src/flash/intel.c @@ -362,6 +362,7 @@ flash_driver_t intel_32_flash_driver = { intel_flash_erase_block32, intel_flash_unlock_block32, intel_flash_program32, + NULL, intel_flash_readarray32, }; @@ -374,6 +375,7 @@ flash_driver_t intel_16_flash_driver = { intel_flash_erase_block, intel_flash_unlock_block, intel_flash_program, + NULL, intel_flash_readarray, }; @@ -386,5 +388,6 @@ flash_driver_t intel_8_flash_driver = { intel_flash_erase_block, intel_flash_unlock_block, intel_flash_program, + NULL, intel_flash_readarray, };