restructure multi-byte flash programming support

git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1392 b68d4a1b-bc3d-0410-92ed-d4ac073336b7
master
Arnim Läuger 16 years ago
parent 7f81a9258c
commit b91de62b6f

@ -1,3 +1,11 @@
2008-12-03 Arnim Laeuger <arniml@users.sourceforge.net>
* 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 <arniml@users.sourceforge.net>
* include/flash/intel.h, src/flash/intel.c:

@ -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])
])

@ -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;

@ -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,
};

@ -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,
};

@ -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);

@ -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,
};

Loading…
Cancel
Save