Hello all: I have noticed some issues on CFI flash driver related to chip and bus width affecting read and writes.
The system I'm dealing with is based on a Vitesse switch chip which embeds an ARM926ejs processor. It additionally provides RAM and flash controller. In this case we are using an spansion S29GL128 16MB flash chip, using a 8bit width data bus layout, so on each read/write cycle we can only retrieve 1byte at once. The flash chip data bus width is 16bit. I declare the flash like this: flash bank cfi 0x80000000 0x1000000 1 2 0 => 1st problem (writing): This clashes somehow with the current CFI driver operations as designed now. I have discovered that when the connected flash is 8 bit, only byte writes will be performed correctly so even this call: target->type->write_memory(target, address, 4, 1, value_buf) will succeed, the operation isn't carried out correctly. I got to workaround the problem for just cfi flash probe. See attached cfi- write-width.diff What I do there is using chip width instead of bus width for each write. This works in my case but I'm not sure it's the general way to go. This effect expands to larger write operations, for instance in target_write_u32 (cfi.c:1220) you would need to repeat a byte write operation 4 times. => 2nd problem (reading) But writing is not the only problem. In reading, when chip width is 8bit whereas bus width is 16bit, single byte operation could be acceptable, whereas this is no longer valid for halfword or word operations, 16bit and 32bit, respectively. When you call, for example cfi_query_u16, expected return is 0xAABB, where 0xAA is the MSB and 0xBB is the LSB. Current return is always 0xBBBB. Similar problem for cfi_query_u32 The solution is iterating the necessary times for a 1byte read and then aggregate each iteration result properly. See attached cfi-read_iteration.diff I guess the x16_as_x8 option defined but not used should be aimed at handling this, but this is unimplemented currently. I would like to write a patch addressing this issues, but I thought that I'd rather bring the topic to the list so I can directly go for a ultimate solution and not workarounds as I'm using right now. Comments are welcome. Regards, -- Raúl Sánchez Siles Departamento de Montaje INFOGLOBAL, S. A. * C/ Virgilio, 2. Ciudad de la Imagen. 28223 Pozuelo de Alarcón (Madrid), España * T: +34 91 506 40 00 * F: +34 91 506 40 01
Index: flash/cfi.c =================================================================== --- flash/cfi.c (revisión: 1782) +++ flash/cfi.c (copia de trabajo) @@ -203,8 +203,11 @@ { target_t *target = bank->target; u8 data[CFI_MAX_BUS_WIDTH * 2]; + u8 i; - target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data); + for(i=0;i<2;i++) + target->type->read_memory(target, flash_address(bank, sector, offset+i), bank->bus_width, 1, + &data[i*bank->bus_width] ); if (bank->target->endianness == TARGET_LITTLE_ENDIAN) return data[0] | data[bank->bus_width] << 8; @@ -216,8 +219,11 @@ { target_t *target = bank->target; u8 data[CFI_MAX_BUS_WIDTH * 4]; + u8 i; - target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data); + for(i=0;i<4;i++) + target->type->read_memory(target, flash_address(bank, sector, offset+i), bank->bus_width, 1, + &data[i*bank->bus_width] ); if (bank->target->endianness == TARGET_LITTLE_ENDIAN) return data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24;
Index: flash/cfi.c =================================================================== --- flash/cfi.c (revisión: 1782) +++ flash/cfi.c (copia de trabajo) @@ -2111,17 +2117,17 @@ /* switch to read identifier codes mode ("AUTOSELECT") */ cfi_command(bank, 0xaa, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->chip_width, 1, command)) != ERROR_OK) { return retval; } cfi_command(bank, 0x55, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, unlock2), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, unlock2), bank->chip_width, 1, command)) != ERROR_OK) { return retval; } cfi_command(bank, 0x90, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->chip_width, 1, command)) != ERROR_OK) { return retval; } @@ -2155,12 +2161,12 @@ LOG_INFO("Flash Manufacturer/Device: 0x%04x 0x%04x", cfi_info->manufacturer, cfi_info->device_id); /* switch back to read array mode */ cfi_command(bank, 0xf0, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x00), bank->chip_width, 1, command)) != ERROR_OK) { return retval; } cfi_command(bank, 0xff, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x00), bank->chip_width, 1, command)) != ERROR_OK) { return retval; } @@ -2181,7 +2187,7 @@ * SST flashes clearly violate this, and we will consider them incompatbile for now */ cfi_command(bank, 0x98, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->chip_width, 1, command)) != ERROR_OK) { return retval; } @@ -2195,12 +2201,12 @@ if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y')) { cfi_command(bank, 0xf0, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->chip_width, 1, command)) != ERROR_OK) { return retval; } cfi_command(bank, 0xff, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->chip_width, 1, command)) != ERROR_OK) { return retval; } @@ -2285,12 +2291,12 @@ * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command */ cfi_command(bank, 0xf0, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->chip_width, 1, command)) != ERROR_OK) { return retval; } cfi_command(bank, 0xff, command); - if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK) + if((retval = target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->chip_width, 1, command)) != ERROR_OK) { return retval; }
_______________________________________________ Openocd-development mailing list Openocd-development@lists.berlios.de https://lists.berlios.de/mailman/listinfo/openocd-development