- reworked etm/etb into a generic etm part with trace capture drivers (currently only etb supported) - added XScale debug handler binary to repository - added Thumb disassembling (thanks to Vincent Palatin for this patch) - added support for non-CFI compatible flashes to cfi driver (currently only SST39VFxxx devices supported) This checkin is experimental, not suitable for general use git-svn-id: svn://svn.berlios.de/openocd/trunk@155 b42882b7-edfa-0310-969c-e2dbd0fdcd60tags/v0.1.0
@@ -1,5 +1,5 @@ | |||
INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target $(all_includes) | |||
METASOURCES = AUTO | |||
noinst_LIBRARIES = libflash.a | |||
libflash_a_SOURCES = flash.c lpc2000.c cfi.c at91sam7.c str7x.c str9x.c nand.c lpc3180_nand_controller.c | |||
noinst_HEADERS = flash.h lpc2000.h cfi.h at91sam7.h str7x.h str9x.h nand.h lpc3180_nand_controller.h | |||
libflash_a_SOURCES = flash.c lpc2000.c cfi.c non_cfi.c at91sam7.c str7x.c str9x.c nand.c lpc3180_nand_controller.c | |||
noinst_HEADERS = flash.h lpc2000.h cfi.h non_cfi.h at91sam7.h str7x.h str9x.h nand.h lpc3180_nand_controller.h |
@@ -66,17 +66,33 @@ flash_driver_t cfi_flash = | |||
.info = cfi_info | |||
}; | |||
cfi_unlock_addresses_t cfi_unlock_addresses[] = | |||
{ | |||
[CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa }, | |||
[CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa }, | |||
}; | |||
/* CFI fixups foward declarations */ | |||
void cfi_fixup_non_cfi(flash_bank_t *flash, void *param); | |||
void cfi_fixup_0002_erase_regions(flash_bank_t *flash, void *param); | |||
void cfi_fixup_0002_unlock_addresses(flash_bank_t *flash, void *param); | |||
void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *flash, void *param); | |||
/* fixup after identifying JEDEC manufactuer and ID */ | |||
cfi_fixup_t cfi_jedec_fixups[] = { | |||
{CFI_MFR_SST, 0x00D4, cfi_fixup_non_cfi, NULL}, | |||
{CFI_MFR_SST, 0x00D5, cfi_fixup_non_cfi, NULL}, | |||
{CFI_MFR_SST, 0x00D6, cfi_fixup_non_cfi, NULL}, | |||
{CFI_MFR_SST, 0x00D7, cfi_fixup_non_cfi, NULL}, | |||
{0, 0, NULL, NULL} | |||
}; | |||
/* fixup after reading cmdset 0002 primary query table */ | |||
cfi_fixup_t cfi_0002_fixups[] = { | |||
{CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, | |||
{CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, | |||
{CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, | |||
{CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, | |||
{CFI_MFR_ATMEL, 0x00C8, cfi_fixup_atmel_reversed_erase_regions, NULL}, | |||
{CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL}, | |||
{0, 0, NULL, NULL} | |||
@@ -421,6 +437,11 @@ int cfi_read_spansion_pri_ext(flash_bank_t *bank) | |||
DEBUG("WP# protection 0x%x", pri_ext->TopBottom); | |||
/* default values for implementation specific workarounds */ | |||
pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; | |||
pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; | |||
pri_ext->_reversed_geometry = 0; | |||
return ERROR_OK; | |||
} | |||
@@ -594,7 +615,9 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char ** | |||
cfi_info = malloc(sizeof(cfi_flash_bank_t)); | |||
bank->driver_priv = cfi_info; | |||
cfi_info->x16_as_x8 = 1; | |||
cfi_info->x16_as_x8 = 0; | |||
cfi_info->jedec_probe = 0; | |||
cfi_info->not_cfi = 0; | |||
cfi_info->target = get_target_by_num(strtoul(args[5], NULL, 0)); | |||
if (!cfi_info->target) | |||
@@ -605,9 +628,13 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char ** | |||
for (i = 6; i < argc; i++) | |||
{ | |||
if (strcmp(args[i], "x16_as_x8") != 0) | |||
if (strcmp(args[i], "x16_as_x8") == 0) | |||
{ | |||
cfi_info->x16_as_x8 = 0; | |||
cfi_info->x16_as_x8 = 1; | |||
} | |||
else if (strcmp(args[i], "jedec_probe") == 0) | |||
{ | |||
cfi_info->jedec_probe = 1; | |||
} | |||
} | |||
@@ -665,19 +692,19 @@ int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last) | |||
for (i = first; i <= last; i++) | |||
{ | |||
cfi_command(bank, 0xaa, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); | |||
cfi_command(bank, 0x55, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); | |||
cfi_command(bank, 0x80, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); | |||
cfi_command(bank, 0xaa, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); | |||
cfi_command(bank, 0x55, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); | |||
cfi_command(bank, 0x30, command); | |||
target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); | |||
@@ -891,9 +918,10 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 | |||
armv4_5_algorithm_t armv4_5_info; | |||
working_area_t *source; | |||
u32 buffer_size = 32768; | |||
u8 write_command[CFI_MAX_BUS_WIDTH]; | |||
u8 busy_pattern[CFI_MAX_BUS_WIDTH]; | |||
u8 error_pattern[CFI_MAX_BUS_WIDTH]; | |||
u8 write_command_buf[CFI_MAX_BUS_WIDTH]; | |||
u8 busy_pattern_buf[CFI_MAX_BUS_WIDTH]; | |||
u8 error_pattern_buf[CFI_MAX_BUS_WIDTH]; | |||
u32 write_command_val, busy_pattern_val, error_pattern_val; | |||
int retval; | |||
/* algorithm register usage: | |||
@@ -906,7 +934,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 | |||
* r6: error test pattern | |||
*/ | |||
u32 word_32_code[] = { | |||
static const u32 word_32_code[] = { | |||
0xe4904004, /* loop: ldr r4, [r0], #4 */ | |||
0xe5813000, /* str r3, [r1] */ | |||
0xe5814000, /* str r4, [r1] */ | |||
@@ -923,7 +951,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 | |||
0xeafffffe, /* done: b -2 */ | |||
}; | |||
u32 word_16_code[] = { | |||
static const u32 word_16_code[] = { | |||
0xe0d040b2, /* loop: ldrh r4, [r0], #2 */ | |||
0xe1c130b0, /* strh r3, [r1] */ | |||
0xe1c140b0, /* strh r4, [r1] */ | |||
@@ -940,7 +968,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 | |||
0xeafffffe, /* done: b -2 */ | |||
}; | |||
u32 word_8_code[] = { | |||
static const u32 word_8_code[] = { | |||
0xe4d04001, /* loop: ldrb r4, [r0], #1 */ | |||
0xe5c13000, /* strb r3, [r1] */ | |||
0xe5c14000, /* strb r4, [r1] */ | |||
@@ -966,29 +994,37 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 | |||
/* flash write code */ | |||
if (!cfi_info->write_algorithm) | |||
{ | |||
u8 write_code_buf[14 * 4]; | |||
int i; | |||
if (target_alloc_working_area(target, 4 * 14, &cfi_info->write_algorithm) != ERROR_OK) | |||
{ | |||
WARNING("no working area available, can't do block memory writes"); | |||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; | |||
}; | |||
/* write algorithm code to working area */ | |||
if (bank->bus_width == 1) | |||
{ | |||
target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_8_code); | |||
for (i = 0; i < 14; i++) | |||
target_buffer_set_u32(target, write_code_buf + (i*4), word_8_code[i]); | |||
} | |||
else if (bank->bus_width == 2) | |||
{ | |||
target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_16_code); | |||
for (i = 0; i < 14; i++) | |||
target_buffer_set_u32(target, write_code_buf + (i*4), word_16_code[i]); | |||
} | |||
else if (bank->bus_width == 4) | |||
{ | |||
target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_32_code); | |||
for (i = 0; i < 14; i++) | |||
target_buffer_set_u32(target, write_code_buf + (i*4), word_32_code[i]); | |||
} | |||
else | |||
{ | |||
return ERROR_FLASH_OPERATION_FAILED; | |||
} | |||
target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, write_code_buf); | |||
} | |||
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) | |||
@@ -1013,10 +1049,30 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 | |||
init_reg_param(®_params[5], "r5", 32, PARAM_OUT); | |||
init_reg_param(®_params[6], "r6", 32, PARAM_OUT); | |||
cfi_command(bank, 0x40, write_command); | |||
cfi_command(bank, 0x80, busy_pattern); | |||
cfi_command(bank, 0x7e, error_pattern); | |||
/* prepare command and status register patterns */ | |||
cfi_command(bank, 0x40, write_command_buf); | |||
cfi_command(bank, 0x80, busy_pattern_buf); | |||
cfi_command(bank, 0x7e, error_pattern_buf); | |||
if (bank->bus_width == 1) | |||
{ | |||
write_command_val = write_command_buf[0]; | |||
busy_pattern_val = busy_pattern_buf[0]; | |||
error_pattern_val = error_pattern_buf[0]; | |||
} | |||
else if (bank->bus_width == 2) | |||
{ | |||
write_command_val = target_buffer_get_u16(target, write_command_buf); | |||
busy_pattern_val = target_buffer_get_u16(target, busy_pattern_buf); | |||
error_pattern_val = target_buffer_get_u16(target, error_pattern_buf); | |||
} | |||
else if (bank->bus_width == 4) | |||
{ | |||
write_command_val = target_buffer_get_u32(target, write_command_buf); | |||
busy_pattern_val = target_buffer_get_u32(target, busy_pattern_buf); | |||
error_pattern_val = target_buffer_get_u32(target, error_pattern_buf); | |||
} | |||
while (count > 0) | |||
{ | |||
u32 thisrun_count = (count > buffer_size) ? buffer_size : count; | |||
@@ -1026,11 +1082,9 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 | |||
buf_set_u32(reg_params[0].value, 0, 32, source->address); | |||
buf_set_u32(reg_params[1].value, 0, 32, address); | |||
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); | |||
buf_set_u32(reg_params[3].value, 0, 32, target_buffer_get_u32(target, write_command)); | |||
buf_set_u32(reg_params[5].value, 0, 32, target_buffer_get_u32(target, busy_pattern)); | |||
buf_set_u32(reg_params[6].value, 0, 32, target_buffer_get_u32(target, error_pattern)); | |||
buf_set_u32(reg_params[5].value, 0, 32, buf_get_u32(busy_pattern, 0, 32)); | |||
buf_set_u32(reg_params[6].value, 0, 32, buf_get_u32(error_pattern, 0, 32)); | |||
buf_set_u32(reg_params[3].value, 0, 32, write_command_val); | |||
buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val); | |||
buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val); | |||
if ((retval = target->type->run_algorithm(target, 0, NULL, 7, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (13 * 4), 10000, &armv4_5_info)) != ERROR_OK) | |||
{ | |||
@@ -1038,7 +1092,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 | |||
return ERROR_FLASH_OPERATION_FAILED; | |||
} | |||
if (buf_get_u32(reg_params[4].value, 0, 32) & target_buffer_get_u32(target, error_pattern)) | |||
if (buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val) | |||
{ | |||
/* read status register (outputs debug inforation) */ | |||
cfi_intel_wait_status_busy(bank, 100); | |||
@@ -1078,8 +1132,6 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, | |||
int i; | |||
int retval; | |||
int exit_code = ERROR_OK; | |||
int code_size; | |||
void *code_p; | |||
/* input parameters - */ | |||
/* R0 = source address */ | |||
@@ -1095,8 +1147,8 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, | |||
/* unlock registers - */ | |||
/* R8 = unlock1_addr */ | |||
/* R9 = unlock1_cmd */ | |||
/* R10 = unlock1_addr */ | |||
/* R11 = unlock1_cmd */ | |||
/* R10 = unlock2_addr */ | |||
/* R11 = unlock2_cmd */ | |||
u32 word_32_code[] = { | |||
/* 00008100 <sp_32_code>: */ | |||
@@ -1207,36 +1259,47 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, | |||
/* flash write code */ | |||
if (!cfi_info->write_algorithm) | |||
{ | |||
/* write algorithm code to working area */ | |||
u8 *code_p; | |||
/* convert bus-width dependent algorithm code to correct endiannes */ | |||
if (bank->bus_width == 1) | |||
{ | |||
code_size = sizeof(word_8_code); | |||
code_p = word_8_code; | |||
code_p = malloc(24 * 4); | |||
for (i = 0; i < 24; i++) | |||
target_buffer_set_u32(target, code_p + (i*4), word_8_code[i]); | |||
} | |||
else if (bank->bus_width == 2) | |||
{ | |||
code_size = sizeof(word_16_code); | |||
code_p = word_16_code; | |||
} | |||
code_p = malloc(24 * 4); | |||
for (i = 0; i < 24; i++) | |||
target_buffer_set_u32(target, code_p + (i*4), word_16_code[i]); | |||
} | |||
else if (bank->bus_width == 4) | |||
{ | |||
code_size = sizeof(word_32_code); | |||
code_p = word_32_code; | |||
code_p = malloc(24 * 4); | |||
for (i = 0; i < 24; i++) | |||
target_buffer_set_u32(target, code_p + (i*4), word_32_code[i]); | |||
} | |||
else | |||
{ | |||
return ERROR_FLASH_OPERATION_FAILED; | |||
} | |||
if (target_alloc_working_area(target, code_size, | |||
&cfi_info->write_algorithm) != ERROR_OK) | |||
/* allocate working area */ | |||
if (target_alloc_working_area(target, 24 * 4, | |||
&cfi_info->write_algorithm) != ERROR_OK) | |||
{ | |||
WARNING("no working area available, can't do block memory writes"); | |||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; | |||
} | |||
target_write_buffer(target, cfi_info->write_algorithm->address, | |||
code_size, code_p); | |||
/* write algorithm code to working area */ | |||
target_write_buffer(target, cfi_info->write_algorithm->address, 24 * 4, code_p); | |||
free(code_p); | |||
} | |||
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) | |||
@@ -1277,14 +1340,14 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, | |||
buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32)); | |||
cfi_command(bank, 0x80, write_command); | |||
buf_set_u32(reg_params[4].value, 0, 32, buf_get_u32(write_command, 0, 32)); | |||
buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, 0x555)); | |||
buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1)); | |||
buf_set_u32(reg_params[7].value, 0, 32, 0xaa); | |||
buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, 0xaaa)); | |||
buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2)); | |||
buf_set_u32(reg_params[9].value, 0, 32, 0x55); | |||
retval = target->type->run_algorithm(target, 0, NULL, 10, reg_params, | |||
cfi_info->write_algorithm->address, | |||
cfi_info->write_algorithm->address + (code_size - 4), | |||
cfi_info->write_algorithm->address + ((24 * 4) - 4), | |||
10000, &armv4_5_info); | |||
status = buf_get_u32(reg_params[5].value, 0, 32); | |||
@@ -1301,6 +1364,8 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, | |||
count -= thisrun_count; | |||
} | |||
target_free_working_area(target, source); | |||
destroy_reg_param(®_params[0]); | |||
destroy_reg_param(®_params[1]); | |||
destroy_reg_param(®_params[2]); | |||
@@ -1347,13 +1412,13 @@ int cfi_spansion_write_word(struct flash_bank_s *bank, u8 *word, u32 address) | |||
u8 command[8]; | |||
cfi_command(bank, 0xaa, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); | |||
cfi_command(bank, 0x55, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); | |||
cfi_command(bank, 0xa0, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); | |||
target->type->write_memory(target, address, bank->bus_width, 1, word); | |||
@@ -1554,6 +1619,16 @@ void cfi_fixup_0002_erase_regions(flash_bank_t *bank, void *param) | |||
} | |||
} | |||
void cfi_fixup_0002_unlock_addresses(flash_bank_t *bank, void *param) | |||
{ | |||
cfi_flash_bank_t *cfi_info = bank->driver_priv; | |||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; | |||
cfi_unlock_addresses_t *unlock_addresses = param; | |||
pri_ext->_unlock1 = unlock_addresses->unlock1; | |||
pri_ext->_unlock2 = unlock_addresses->unlock2; | |||
} | |||
int cfi_probe(struct flash_bank_s *bank) | |||
{ | |||
cfi_flash_bank_t *cfi_info = bank->driver_priv; | |||
@@ -1563,14 +1638,25 @@ int cfi_probe(struct flash_bank_s *bank) | |||
int i; | |||
int sector = 0; | |||
u32 offset = 0; | |||
u32 unlock1 = 0x555; | |||
u32 unlock2 = 0x2aa; | |||
/* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses, | |||
* while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa | |||
*/ | |||
if (cfi_info->jedec_probe) | |||
{ | |||
unlock1 = 0x5555; | |||
unlock2 = 0x2aaa; | |||
} | |||
/* switch to read identifier codes mode ("AUTOSELECT") */ | |||
cfi_command(bank, 0xaa, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command); | |||
cfi_command(bank, 0x55, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, unlock2), bank->bus_width, 1, command); | |||
cfi_command(bank, 0x90, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command); | |||
if (bank->chip_width == 1) | |||
{ | |||
@@ -1594,105 +1680,132 @@ int cfi_probe(struct flash_bank_s *bank) | |||
cfi_fixup(bank, cfi_jedec_fixups); | |||
/* enter CFI query mode | |||
* according to JEDEC Standard No. 68.01, | |||
* a single bus sequence with address = 0x55, data = 0x98 should put | |||
* the device into CFI query mode. | |||
* | |||
* SST flashes clearly violate this, and we will consider them incompatbile for now | |||
/* query only if this is a CFI compatible flash, | |||
* otherwise the relevant info has already been filled in | |||
*/ | |||
cfi_command(bank, 0x98, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); | |||
cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10); | |||
cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11); | |||
cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12); | |||
DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]); | |||
if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y')) | |||
if (cfi_info->not_cfi == 0) | |||
{ | |||
/* enter CFI query mode | |||
* according to JEDEC Standard No. 68.01, | |||
* a single bus sequence with address = 0x55, data = 0x98 should put | |||
* the device into CFI query mode. | |||
* | |||
* SST flashes clearly violate this, and we will consider them incompatbile for now | |||
*/ | |||
cfi_command(bank, 0x98, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); | |||
cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10); | |||
cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11); | |||
cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12); | |||
DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]); | |||
if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y')) | |||
{ | |||
cfi_command(bank, 0xf0, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); | |||
cfi_command(bank, 0xff, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); | |||
return ERROR_FLASH_BANK_INVALID; | |||
} | |||
cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13); | |||
cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15); | |||
cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17); | |||
cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19); | |||
DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); | |||
cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b); | |||
cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c); | |||
cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d); | |||
cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e); | |||
cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f); | |||
cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20); | |||
cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21); | |||
cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22); | |||
cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23); | |||
cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24); | |||
cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25); | |||
cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26); | |||
DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x", | |||
(cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, | |||
(cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, | |||
(cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, | |||
(cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); | |||
DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ, | |||
1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); | |||
DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ), | |||
(1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), | |||
(1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), | |||
(1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); | |||
cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27); | |||
cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28); | |||
cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a); | |||
cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c); | |||
DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size)); | |||
if (((1 << cfi_info->dev_size) * bank->bus_width / bank->chip_width) != bank->size) | |||
{ | |||
WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size); | |||
} | |||
if (cfi_info->num_erase_regions) | |||
{ | |||
cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions); | |||
for (i = 0; i < cfi_info->num_erase_regions; i++) | |||
{ | |||
cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i)); | |||
DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256); | |||
} | |||
} | |||
else | |||
{ | |||
cfi_info->erase_region_info = NULL; | |||
} | |||
/* We need to read the primary algorithm extended query table before calculating | |||
* the sector layout to be able to apply fixups | |||
*/ | |||
switch(cfi_info->pri_id) | |||
{ | |||
/* Intel command set (standard and extended) */ | |||
case 0x0001: | |||
case 0x0003: | |||
cfi_read_intel_pri_ext(bank); | |||
break; | |||
/* AMD/Spansion, Atmel, ... command set */ | |||
case 0x0002: | |||
cfi_read_0002_pri_ext(bank); | |||
break; | |||
default: | |||
ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); | |||
break; | |||
} | |||
/* return to read array mode | |||
* we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command | |||
*/ | |||
cfi_command(bank, 0xf0, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); | |||
cfi_command(bank, 0xff, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); | |||
return ERROR_FLASH_BANK_INVALID; | |||
} | |||
cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13); | |||
cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15); | |||
cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17); | |||
cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19); | |||
DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); | |||
cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b); | |||
cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c); | |||
cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d); | |||
cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e); | |||
cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f); | |||
cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20); | |||
cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21); | |||
cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22); | |||
cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23); | |||
cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24); | |||
cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25); | |||
cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26); | |||
DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x", | |||
(cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, | |||
(cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, | |||
(cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, | |||
(cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); | |||
DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ, | |||
1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); | |||
DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ), | |||
(1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), | |||
(1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), | |||
(1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); | |||
cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27); | |||
cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28); | |||
cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a); | |||
cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c); | |||
DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size)); | |||
if (((1 << cfi_info->dev_size) * bank->bus_width / bank->chip_width) != bank->size) | |||
{ | |||
WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size); | |||
} | |||
if (cfi_info->num_erase_regions) | |||
{ | |||
cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions); | |||
for (i = 0; i < cfi_info->num_erase_regions; i++) | |||
{ | |||
cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i)); | |||
DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256); | |||
num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1; | |||
} | |||
} | |||
else | |||
{ | |||
cfi_info->erase_region_info = NULL; | |||
} | |||
/* We need to read the primary algorithm extended query table before calculating | |||
* the sector layout to be able to apply fixups | |||
*/ | |||
/* apply fixups depending on the primary command set */ | |||
switch(cfi_info->pri_id) | |||
{ | |||
/* Intel command set (standard and extended) */ | |||
case 0x0001: | |||
case 0x0003: | |||
cfi_read_intel_pri_ext(bank); | |||
cfi_fixup(bank, cfi_0001_fixups); | |||
break; | |||
/* AMD/Spansion, Atmel, ... command set */ | |||
case 0x0002: | |||
cfi_read_0002_pri_ext(bank); | |||
case 0x0002: | |||
cfi_fixup(bank, cfi_0002_fixups); | |||
break; | |||
default: | |||
@@ -1713,6 +1826,11 @@ int cfi_probe(struct flash_bank_s *bank) | |||
} | |||
else | |||
{ | |||
for (i = 0; i < cfi_info->num_erase_regions; i++) | |||
{ | |||
num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1; | |||
} | |||
bank->num_sectors = num_sectors; | |||
bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors); | |||
@@ -1731,14 +1849,6 @@ int cfi_probe(struct flash_bank_s *bank) | |||
} | |||
} | |||
/* return to read array mode | |||
* we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command | |||
*/ | |||
cfi_command(bank, 0xf0, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); | |||
cfi_command(bank, 0xff, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); | |||
return ERROR_OK; | |||
} | |||
@@ -1893,13 +2003,13 @@ int cfi_spansion_protect_check(struct flash_bank_s *bank) | |||
int i; | |||
cfi_command(bank, 0xaa, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); | |||
cfi_command(bank, 0x55, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); | |||
cfi_command(bank, 0x90, command); | |||
target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command); | |||
target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); | |||
for (i = 0; i < bank->num_sectors; i++) | |||
{ | |||
@@ -30,10 +30,12 @@ typedef struct cfi_flash_bank_s | |||
working_area_t *erase_check_algorithm; | |||
int x16_as_x8; | |||
int jedec_probe; | |||
int not_cfi; | |||
u16 manufacturer; | |||
u16 device_id; | |||
char qry[3]; | |||
/* identification string */ | |||
@@ -108,6 +110,8 @@ typedef struct cfi_spansion_pri_ext_s | |||
u8 VppMax; | |||
u8 TopBottom; | |||
int _reversed_geometry; | |||
u32 _unlock1; | |||
u32 _unlock2; | |||
} cfi_spansion_pri_ext_t; | |||
/* Atmel primary extended query table as defined for and used by | |||
@@ -124,6 +128,17 @@ typedef struct cfi_atmel_pri_ext_s | |||
u8 page_mode; | |||
} cfi_atmel_pri_ext_t; | |||
enum { | |||
CFI_UNLOCK_555_2AA, | |||
CFI_UNLOCK_5555_2AAA, | |||
}; | |||
typedef struct cfi_unlock_addresses_s | |||
{ | |||
u32 unlock1; | |||
u32 unlock2; | |||
} cfi_unlock_addresses_t; | |||
typedef struct cfi_fixup_s | |||
{ | |||
u16 mfr; | |||
@@ -135,6 +150,7 @@ typedef struct cfi_fixup_s | |||
#define CFI_MFR_AMD 0x0001 | |||
#define CFI_MFR_ATMEL 0x001F | |||
#define CFI_MFR_ST 0x0020 /* STMicroelectronics */ | |||
#define CFI_MFR_SST 0x00BF | |||
#define CFI_MFR_ANY 0xffff | |||
#define CFI_ID_ANY 0xffff | |||
@@ -35,6 +35,7 @@ | |||
#include <errno.h> | |||
#include <fileio.h> | |||
#include <image.h> | |||
/* command handlers */ | |||
int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); | |||
@@ -493,9 +494,7 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha | |||
u8 *buffer; | |||
u32 buf_cnt; | |||
fileio_t file; | |||
fileio_image_t image_info; | |||
enum fileio_sec_type sec_type; | |||
image_t image; | |||
duration_t duration; | |||
char *duration_text; | |||
@@ -511,7 +510,12 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha | |||
duration_start_measure(&duration); | |||
fileio_identify_image_type(&sec_type, (argc == 4) ? args[3] : NULL); | |||
identify_image_type(&image.type, (argc == 4) ? args[3] : NULL); | |||
image.base_address_set = 1; | |||
image.base_address = strtoul(args[1], NULL, 0); | |||
image.start_address_set = 0; | |||
offset = strtoul(args[2], NULL, 0); | |||
p = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); | |||
@@ -521,20 +525,16 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha | |||
return ERROR_OK; | |||
} | |||
image_info.base_address = strtoul(args[2], NULL, 0); | |||
image_info.has_start_address = 0; | |||
if (fileio_open(&file, args[1], FILEIO_READ, | |||
FILEIO_IMAGE, &image_info, sec_type) != ERROR_OK) | |||
if (image_open(&image, args[1], FILEIO_READ) != ERROR_OK) | |||
{ | |||
command_print(cmd_ctx, "flash write error: %s", file.error_str); | |||
command_print(cmd_ctx, "flash write error: %s", image.error_str); | |||
return ERROR_OK; | |||
} | |||
binary_size = file.size; | |||
binary_size = image.size; | |||
buffer = malloc(binary_size); | |||
fileio_read(&file, binary_size, buffer, &buf_cnt); | |||
image_read(&image, binary_size, buffer, &buf_cnt); | |||
if ((retval = p->driver->write(p, buffer, offset, buf_cnt)) != ERROR_OK) | |||
{ | |||
@@ -571,12 +571,12 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha | |||
{ | |||
duration_stop_measure(&duration, &duration_text); | |||
command_print(cmd_ctx, "wrote file %s to flash bank %i at offset 0x%8.8x in %s", | |||
file.url, strtoul(args[0], NULL, 0), offset, duration_text); | |||
args[1], strtoul(args[0], NULL, 0), offset, duration_text); | |||
free(duration_text); | |||
} | |||
free(buffer); | |||
fileio_close(&file); | |||
image_close(&image); | |||
return ERROR_OK; | |||
} |
@@ -38,6 +38,7 @@ | |||
#include "flash.h" | |||
#include "time_support.h" | |||
#include "fileio.h" | |||
#include "image.h" | |||
int nand_register_commands(struct command_context_s *cmd_ctx); | |||
int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); | |||
@@ -1163,10 +1164,8 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
u32 buf_cnt; | |||
enum oob_formats oob_format = NAND_OOB_NONE; | |||
fileio_t file; | |||
fileio_image_t image_info; | |||
int sec_type_identified = 0; | |||
enum fileio_sec_type sec_type; | |||
image_t image; | |||
int image_type_identified = 0; | |||
duration_t duration; | |||
char *duration_text; | |||
@@ -1201,9 +1200,9 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY; | |||
else | |||
{ | |||
if (fileio_identify_image_type(&sec_type, args[i]) == ERROR_OK) | |||
if (identify_image_type(&image.type, args[i]) == ERROR_OK) | |||
{ | |||
sec_type_identified = 1; | |||
image_type_identified = 1; | |||
} | |||
else | |||
{ | |||
@@ -1214,27 +1213,27 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
} | |||
/* if no image type option was encountered, set the default */ | |||
if (!sec_type_identified) | |||
if (!image_type_identified) | |||
{ | |||
fileio_identify_image_type(&sec_type, NULL); | |||
sec_type_identified = 1; | |||
identify_image_type(&image.type, NULL); | |||
image_type_identified = 1; | |||
} | |||
image_info.base_address = strtoul(args[2], NULL, 0); | |||
image_info.has_start_address = 0; | |||
image.base_address_set = 1; | |||
image.base_address = strtoul(args[2], NULL, 0); | |||
image.start_address_set = 0; | |||
if (fileio_open(&file, args[1], FILEIO_READ, | |||
FILEIO_IMAGE, &image_info, sec_type) != ERROR_OK) | |||
if (image_open(&image, args[1], FILEIO_READ) != ERROR_OK) | |||
{ | |||
command_print(cmd_ctx, "flash write error: %s", file.error_str); | |||
command_print(cmd_ctx, "flash write error: %s", image.error_str); | |||
return ERROR_OK; | |||
} | |||
/* the offset might have been overwritten by the image base address */ | |||
offset = image_info.base_address; | |||
offset = image.base_address; | |||
buf_cnt = binary_size = file.size; | |||
buf_cnt = binary_size = image.size; | |||
if (!(oob_format & NAND_OOB_ONLY)) | |||
{ | |||
@@ -1263,7 +1262,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
if (page) | |||
{ | |||
fileio_read(&file, page_size, page, &size_read); | |||
image_read(&image, page_size, page, &size_read); | |||
buf_cnt -= size_read; | |||
if (size_read < page_size) | |||
{ | |||
@@ -1273,7 +1272,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
if (oob) | |||
{ | |||
fileio_read(&file, oob_size, oob, &size_read); | |||
image_read(&image, oob_size, oob, &size_read); | |||
buf_cnt -= size_read; | |||
if (size_read < oob_size) | |||
{ | |||
@@ -1284,7 +1283,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
if (nand_write_page(p, offset / p->page_size, page, page_size, oob, oob_size) != ERROR_OK) | |||
{ | |||
command_print(cmd_ctx, "failed writing file %s to NAND flash %s at offset 0x%8.8x", | |||
file.url, args[0], offset); | |||
args[1], args[0], offset); | |||
return ERROR_OK; | |||
} | |||
offset += page_size; | |||
@@ -1292,7 +1291,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
duration_stop_measure(&duration, &duration_text); | |||
command_print(cmd_ctx, "wrote file %s to NAND flash %s at offset 0x%8.8x in %s", | |||
file.url, args[0], image_info.base_address, duration_text); | |||
args[1], args[0], image.base_address, duration_text); | |||
free(duration_text); | |||
} | |||
else | |||
@@ -1318,8 +1317,7 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
{ | |||
if (p->device) | |||
{ | |||
fileio_t file; | |||
fileio_image_t image_info; | |||
fileio_t fileio; | |||
duration_t duration; | |||
char *duration_text; | |||
int retval; | |||
@@ -1367,14 +1365,10 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
oob_size = 64; | |||
oob = malloc(oob_size); | |||
} | |||
image_info.base_address = address; | |||
image_info.has_start_address = 0; | |||
if (fileio_open(&file, args[1], FILEIO_WRITE, | |||
FILEIO_IMAGE, &image_info, FILEIO_PLAIN) != ERROR_OK) | |||
if (fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) | |||
{ | |||
command_print(cmd_ctx, "dump_image error: %s", file.error_str); | |||
command_print(cmd_ctx, "dump_image error: %s", fileio.error_str); | |||
return ERROR_OK; | |||
} | |||
@@ -1391,13 +1385,13 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
if (page) | |||
{ | |||
fileio_write(&file, page_size, page, &size_written); | |||
fileio_write(&fileio, page_size, page, &size_written); | |||
bytes_done += page_size; | |||
} | |||
if (oob) | |||
{ | |||
fileio_write(&file, oob_size, oob, &size_written); | |||
fileio_write(&fileio, oob_size, oob, &size_written); | |||
bytes_done += oob_size; | |||
} | |||
@@ -1411,10 +1405,10 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
if (oob) | |||
free(oob); | |||
fileio_close(&file); | |||
fileio_close(&fileio); | |||
duration_stop_measure(&duration, &duration_text); | |||
command_print(cmd_ctx, "dumped %lli byte in %s", file.size, duration_text); | |||
command_print(cmd_ctx, "dumped %lli byte in %s", fileio.size, duration_text); | |||
free(duration_text); | |||
} | |||
else | |||
@@ -0,0 +1,175 @@ | |||
/*************************************************************************** | |||
* Copyright (C) 2007 by Dominic Rath * | |||
* Dominic.Rath@gmx.de * | |||
* * | |||
* This program is free software; you can redistribute it and/or modify * | |||
* it under the terms of the GNU General Public License as published by * | |||
* the Free Software Foundation; either version 2 of the License, or * | |||
* (at your option) any later version. * | |||
* * | |||
* This program is distributed in the hope that it will be useful, * | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||
* GNU General Public License for more details. * | |||
* * | |||
* You should have received a copy of the GNU General Public License * | |||
* along with this program; if not, write to the * | |||
* Free Software Foundation, Inc., * | |||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||
***************************************************************************/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#include <stdlib.h> | |||
#include "log.h" | |||
#include "flash.h" | |||
#include "cfi.h" | |||
#include "non_cfi.h" | |||
/* non-CFI compatible flashes */ | |||
non_cfi_t non_cfi_flashes[] = { | |||
{ | |||
.mfr = CFI_MFR_SST, | |||
.id = 0xd4, | |||
.pri_id = 0x02, | |||
.dev_size = 0x10, | |||
.interface_desc = 0x0, | |||
.max_buf_write_size = 0x0, | |||
.num_erase_regions = 1, | |||
.erase_region_info = | |||
{ | |||
0x0010000f, | |||
0x00000000 | |||
} | |||
}, | |||
{ | |||
.mfr = CFI_MFR_SST, | |||
.id = 0xd5, | |||
.pri_id = 0x02, | |||
.dev_size = 0x11, | |||
.interface_desc = 0x0, | |||
.max_buf_write_size = 0x0, | |||
.num_erase_regions = 1, | |||
.erase_region_info = | |||
{ | |||
0x0010001f, | |||
0x00000000 | |||
} | |||
}, | |||
{ | |||
.mfr = CFI_MFR_SST, | |||
.id = 0xd6, | |||
.pri_id = 0x02, | |||
.dev_size = 0x12, | |||
.interface_desc = 0x0, | |||
.max_buf_write_size = 0x0, | |||
.num_erase_regions = 1, | |||
.erase_region_info = | |||
{ | |||
0x0010003f, | |||
0x00000000 | |||
} | |||
}, | |||
{ | |||
.mfr = CFI_MFR_SST, | |||
.id = 0xd7, | |||
.pri_id = 0x02, | |||
.dev_size = 0x13, | |||
.interface_desc = 0x0, | |||
.max_buf_write_size = 0x0, | |||
.num_erase_regions = 1, | |||
.erase_region_info = | |||
{ | |||
0x0010007f, | |||
0x00000000 | |||
} | |||
}, | |||
{ | |||
.mfr = 0, | |||
.id = 0, | |||
} | |||
}; | |||
void cfi_fixup_non_cfi(flash_bank_t *bank, void *param) | |||
{ | |||
cfi_flash_bank_t *cfi_info = bank->driver_priv; | |||
non_cfi_t *non_cfi = non_cfi_flashes; | |||
while (non_cfi->mfr) | |||
{ | |||
if ((cfi_info->manufacturer == non_cfi->mfr) | |||
&& (cfi_info->device_id == non_cfi->id)) | |||
{ | |||
break; | |||
} | |||
non_cfi++; | |||
} | |||
cfi_info->not_cfi = 1; | |||
/* fill in defaults for non-critical data */ | |||
cfi_info->vcc_min = 0x0; | |||
cfi_info->vcc_max = 0x0; | |||
cfi_info->vpp_min = 0x0; | |||
cfi_info->vpp_max = 0x0; | |||
cfi_info->word_write_timeout_typ = 0x0; | |||
cfi_info->buf_write_timeout_typ = 0x0; | |||
cfi_info->block_erase_timeout_typ = 0x0; | |||
cfi_info->chip_erase_timeout_typ = 0x0; | |||
cfi_info->word_write_timeout_max = 0x0; | |||
cfi_info->buf_write_timeout_max = 0x0; | |||
cfi_info->block_erase_timeout_max = 0x0; | |||
cfi_info->chip_erase_timeout_max = 0x0; | |||
cfi_info->qry[0] = 'Q'; | |||
cfi_info->qry[1] = 'R'; | |||
cfi_info->qry[2] = 'Y'; | |||
cfi_info->pri_id = non_cfi->pri_id; | |||
cfi_info->pri_addr = 0x0; | |||
cfi_info->alt_id = 0x0; | |||
cfi_info->alt_addr = 0x0; | |||
cfi_info->alt_ext = NULL; | |||
cfi_info->interface_desc = non_cfi->interface_desc; | |||
cfi_info->max_buf_write_size = non_cfi->max_buf_write_size; | |||
cfi_info->num_erase_regions = non_cfi->num_erase_regions; | |||
cfi_info->erase_region_info = non_cfi->erase_region_info; | |||
if (cfi_info->pri_id == 0x2) | |||
{ | |||
cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t)); | |||
pri_ext->pri[0] = 'P'; | |||
pri_ext->pri[1] = 'R'; | |||
pri_ext->pri[2] = 'I'; | |||
pri_ext->major_version = '1'; | |||
pri_ext->minor_version = '0'; | |||
pri_ext->SiliconRevision = 0x0; | |||
pri_ext->EraseSuspend = 0x0; | |||
pri_ext->EraseSuspend = 0x0; | |||
pri_ext->BlkProt = 0x0; | |||
pri_ext->TmpBlkUnprotect = 0x0; | |||
pri_ext->BlkProtUnprot = 0x0; | |||
pri_ext->SimultaneousOps = 0x0; | |||
pri_ext->BurstMode = 0x0; | |||
pri_ext->PageMode = 0x0; | |||
pri_ext->VppMin = 0x0; | |||
pri_ext->VppMax = 0x0; | |||
pri_ext->TopBottom = 0x0; | |||
pri_ext->_reversed_geometry = 0; | |||
cfi_info->pri_ext = pri_ext; | |||
} else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3)) | |||
{ | |||
ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported"); | |||
exit(-1); | |||
} | |||
} | |||
@@ -0,0 +1,41 @@ | |||
/*************************************************************************** | |||
* Copyright (C) 2007 by Dominic Rath * | |||
* Dominic.Rath@gmx.de * | |||
* * | |||
* This program is free software; you can redistribute it and/or modify * | |||
* it under the terms of the GNU General Public License as published by * | |||
* the Free Software Foundation; either version 2 of the License, or * | |||
* (at your option) any later version. * | |||
* * | |||
* This program is distributed in the hope that it will be useful, * | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||
* GNU General Public License for more details. * | |||
* * | |||
* You should have received a copy of the GNU General Public License * | |||
* along with this program; if not, write to the * | |||
* Free Software Foundation, Inc., * | |||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||
***************************************************************************/ | |||
#ifndef NON_CFI_H | |||
#define NON_CFI_H | |||
#include "types.h" | |||
typedef struct non_cfi_s | |||
{ | |||
u16 mfr; | |||
u16 id; | |||
u16 pri_id; | |||
u8 dev_size; | |||
u16 interface_desc; | |||
u16 max_buf_write_size; | |||
u8 num_erase_regions; | |||
u32 erase_region_info[6]; | |||
} non_cfi_t; | |||
extern non_cfi_t non_cfi_flashes[]; | |||
extern void cfi_fixup_non_cfi(flash_bank_t *bank, void *param); | |||
#endif /* NON_CFI_H */ | |||
@@ -98,7 +98,7 @@ int fileio_open_local(fileio_t *fileio) | |||
} | |||
} | |||
if (fileio->pri_type == FILEIO_IMAGE) | |||
if (fileio->type == FILEIO_BINARY) | |||
strcat(access, "b"); | |||
if (!(fileio_local->file = fopen(fileio->url, access))) | |||
@@ -120,126 +120,7 @@ int fileio_open_local(fileio_t *fileio) | |||
return ERROR_OK; | |||
} | |||
//#ifdef FILEIO_BUFFER_COMPLETE_IHEX | |||
int fileio_ihex_buffer_complete(fileio_t *fileio) | |||
{ | |||
fileio_image_t *image = fileio->pri_type_private; | |||
fileio_ihex_t *ihex = fileio->sec_type_private; | |||
u32 raw_bytes_read, raw_bytes; | |||
int retval; | |||
u32 full_address = image->base_address; | |||
char *buffer = malloc(ihex->raw_size); | |||
u32 cooked_bytes = 0x0; | |||
ihex->raw_size = fileio->size; | |||
ihex->buffer = malloc(ihex->raw_size >> 1); | |||
if ((retval = fileio_dispatch_read(fileio, ihex->raw_size, (u8*)buffer, &raw_bytes_read)) != ERROR_OK) | |||
{ | |||
free(buffer); | |||
ERROR("failed buffering IHEX file, read failed"); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
if (raw_bytes_read != ihex->raw_size) | |||
{ | |||
free(buffer); | |||
ERROR("failed buffering complete IHEX file, only partially read"); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
raw_bytes = 0x0; | |||
while (raw_bytes < raw_bytes_read) | |||
{ | |||
u32 count; | |||
u32 address; | |||
u32 record_type; | |||
u32 checksum; | |||
if (sscanf(&buffer[raw_bytes], ":%2x%4x%2x", &count, &address, &record_type) != 3) | |||
{ | |||
snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "invalid IHEX record"); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
raw_bytes += 9; | |||
if (record_type == 0) | |||
{ | |||
if ((full_address & 0xffff) != address) | |||
{ | |||
free(buffer); | |||
ERROR("can't handle non-linear IHEX file"); | |||
snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't handle non-linear IHEX file"); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
while (count-- > 0) | |||
{ | |||
sscanf(&buffer[raw_bytes], "%2hhx", &ihex->buffer[cooked_bytes]); | |||
raw_bytes += 2; | |||
cooked_bytes += 1; | |||
full_address++; | |||
} | |||
} | |||
else if (record_type == 1) | |||
{ | |||
free(buffer); | |||
fileio->size = cooked_bytes; | |||
return ERROR_OK; | |||
} | |||
else if (record_type == 4) | |||
{ | |||
u16 upper_address; | |||
sscanf(&buffer[raw_bytes], "%4hx", &upper_address); | |||
raw_bytes += 4; | |||
if ((full_address >> 16) != upper_address) | |||
{ | |||
free(buffer); | |||
ERROR("can't handle non-linear IHEX file"); | |||
snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't handle non-linear IHEX file"); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
} | |||
else if (record_type == 5) | |||
{ | |||
u32 start_address; | |||
sscanf(&buffer[raw_bytes], "%8x", &start_address); | |||
raw_bytes += 8; | |||
image->has_start_address = 1; | |||
image->start_address = be_to_h_u32((u8*)&start_address); | |||
} | |||
else | |||
{ | |||
free(buffer); | |||
ERROR("unhandled IHEX record type: %i", record_type); | |||
snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "unhandled IHEX record type: %i", record_type); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
sscanf(&buffer[raw_bytes], "%2x", &checksum); | |||
raw_bytes += 2; | |||
/* consume new-line character(s) */ | |||
if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r')) | |||
raw_bytes++; | |||
if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r')) | |||
raw_bytes++; | |||
} | |||
free(buffer); | |||
ERROR("premature end of IHEX file, no end-of-file record found"); | |||
snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "premature end of IHEX file, no end-of-file record found"); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
//#endif | |||
int fileio_open(fileio_t *fileio, char *url, enum fileio_access access, | |||
enum fileio_pri_type pri_type, void *pri_info, enum fileio_sec_type sec_type) | |||
int fileio_open(fileio_t *fileio, char *url, enum fileio_access access, enum fileio_type type) | |||
{ | |||
int retval = ERROR_OK; | |||
char *resource_identifier = NULL; | |||
@@ -261,9 +142,8 @@ int fileio_open(fileio_t *fileio, char *url, enum fileio_access access, | |||
fileio->location = FILEIO_LOCAL; | |||
} | |||
fileio->type = type; | |||
fileio->access = access; | |||
fileio->pri_type = pri_type; | |||
fileio->sec_type = sec_type; | |||
fileio->url = strdup(url); | |||
switch (fileio->location) | |||
@@ -279,50 +159,6 @@ int fileio_open(fileio_t *fileio, char *url, enum fileio_access access, | |||
if (retval != ERROR_OK) | |||
return retval; | |||
if (fileio->pri_type == FILEIO_TEXT) | |||
{ | |||
/* do nothing for now */ | |||
return ERROR_OK; | |||
} | |||
else if (fileio->pri_type == FILEIO_IMAGE) | |||
{ | |||
fileio_image_t *image = malloc(sizeof(fileio_image_t)); | |||
fileio_image_t *image_info = pri_info; | |||
fileio->pri_type_private = image; | |||
*image = *image_info; | |||
if (fileio->sec_type == FILEIO_PLAIN) | |||
{ | |||
fileio->sec_type_private = NULL; | |||
} | |||
else if (fileio->sec_type == FILEIO_IHEX) | |||
{ | |||
fileio_ihex_t *fileio_ihex; | |||
if (fileio->access != FILEIO_READ) | |||
{ | |||
ERROR("can't write/append to a IHEX file"); | |||
snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't write/append to a IHEX file"); | |||
fileio_close(fileio); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
fileio_ihex = malloc(sizeof(fileio_ihex_t)); | |||
fileio->sec_type_private = fileio_ihex; | |||
fileio_ihex->position = 0; | |||
fileio_ihex->raw_size = fileio->size; | |||
#ifdef FILEIO_BUFFER_COMPLETE_IHEX | |||
if (fileio_ihex_buffer_complete(fileio) != ERROR_OK) | |||
{ | |||
fileio_close(fileio); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
#endif | |||
} | |||
} | |||
return ERROR_OK; | |||
} | |||
@@ -369,29 +205,6 @@ int fileio_close(fileio_t *fileio) | |||
free(fileio->url); | |||
if (fileio->pri_type == FILEIO_TEXT) | |||
{ | |||
/* do nothing for now */ | |||
} | |||
else if (fileio->pri_type == FILEIO_IMAGE) | |||
{ | |||
if (fileio->sec_type == FILEIO_PLAIN) | |||
{ | |||
/* nothing special to do for plain binary */ | |||
} | |||
else if (fileio->sec_type == FILEIO_IHEX) | |||
{ | |||
fileio_ihex_t *fileio_ihex = fileio->sec_type_private; | |||
if (fileio_ihex->buffer) | |||
free(fileio_ihex->buffer); | |||
free(fileio->sec_type_private); | |||
} | |||
free(fileio->pri_type_private); | |||
} | |||
return ERROR_OK; | |||
} | |||
@@ -432,7 +245,7 @@ int fileio_local_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read) | |||
return ERROR_OK; | |||
} | |||
int fileio_dispatch_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read) | |||
int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read) | |||
{ | |||
switch (fileio->location) | |||
{ | |||
@@ -445,38 +258,6 @@ int fileio_dispatch_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read) | |||
} | |||
} | |||
int fileio_read_ihex(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read) | |||
{ | |||
fileio_ihex_t *fileio_ihex = fileio->sec_type_private; | |||
if ((fileio_ihex->position + size) > fileio->size) | |||
{ | |||
/* don't read past the end of the file */ | |||
size = (fileio->size - fileio_ihex->position); | |||
} | |||
#ifdef FILEIO_BUFFER_COMPLETE_IHEX | |||
memcpy(buffer, fileio_ihex->buffer + fileio_ihex->position, size); | |||
*size_read = size; | |||
#endif | |||
return ERROR_OK; | |||
} | |||
int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read) | |||
{ | |||
if (fileio->sec_type == FILEIO_PLAIN) | |||
{ | |||
return fileio_dispatch_read(fileio, size, buffer, size_read); | |||
} | |||
else if (fileio->sec_type == FILEIO_IHEX) | |||
{ | |||
return fileio_read_ihex(fileio, size, buffer, size_read); | |||
} | |||
return ERROR_OK; | |||
} | |||
int fileio_local_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written) | |||
{ | |||
fileio_local_t *fileio_local = fileio->location_private; | |||
@@ -486,7 +267,7 @@ int fileio_local_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written | |||
return ERROR_OK; | |||
} | |||
int fileio_dispatch_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written) | |||
int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written) | |||
{ | |||
switch (fileio->location) | |||
{ | |||
@@ -499,48 +280,3 @@ int fileio_dispatch_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_writ | |||
return ERROR_OK; | |||
} | |||
int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written) | |||
{ | |||
int retval = ERROR_FILEIO_OPERATION_NOT_SUPPORTED; | |||
if (fileio->sec_type == FILEIO_PLAIN) | |||
{ | |||
retval = fileio_dispatch_write(fileio, size, buffer, size_written); | |||
} | |||
else if (fileio->sec_type == FILEIO_IHEX) | |||
{ | |||
return ERROR_FILEIO_OPERATION_NOT_SUPPORTED; | |||
} | |||
if (retval != ERROR_OK) | |||
return retval; | |||
fileio->size += size; | |||
return ERROR_OK; | |||
} | |||
int fileio_identify_image_type(enum fileio_sec_type *sec_type, char *type_string) | |||
{ | |||
if (type_string) | |||
{ | |||
if (!strcmp(type_string, "bin")) | |||
{ | |||
*sec_type = FILEIO_PLAIN; | |||
} | |||
else if (!strcmp(type_string, "ihex")) | |||
{ | |||
*sec_type = FILEIO_IHEX; | |||
} | |||
else | |||
{ | |||
return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN; | |||
} | |||
} | |||
else | |||
{ | |||
*sec_type = FILEIO_PLAIN; | |||
} | |||
return ERROR_OK; | |||
} |
@@ -22,28 +22,20 @@ | |||
#define FILEIO_MAX_ERROR_STRING (128) | |||
/* make buffering of complete intel-hex format files optional | |||
* to account for resource-limited hosts | |||
*/ | |||
#define FILEIO_BUFFER_COMPLETE_IHEX | |||
#include "types.h" | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <stdlib.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <errno.h> | |||
#include <ctype.h> | |||
enum fileio_pri_type | |||
{ | |||
FILEIO_TEXT = 0x1, | |||
FILEIO_IMAGE = 0x2, | |||
}; | |||
enum fileio_sec_type | |||
enum fileio_type | |||
{ | |||
FILEIO_PLAIN = 0x10, | |||
FILEIO_IHEX = 0x20, | |||
/* | |||
* Possible future enhancements: | |||
* FILEIO_ELF, | |||
* FILEIO_SRECORD, | |||
*/ | |||
FILEIO_TEXT, | |||
FILEIO_BINARY, | |||
}; | |||
enum fileio_location | |||
@@ -73,48 +65,23 @@ typedef struct fileio_s | |||
char *url; | |||
char error_str[FILEIO_MAX_ERROR_STRING]; | |||
long long size; | |||
enum fileio_pri_type pri_type; | |||
enum fileio_sec_type sec_type; | |||
enum fileio_type type; | |||
enum fileio_location location; | |||
enum fileio_access access; | |||
void *location_private; | |||
void *pri_type_private; | |||
void *sec_type_private; | |||
} fileio_t; | |||
typedef struct fileio_text_s | |||
{ | |||
} fileio_text_t; | |||
typedef struct fileio_image_s | |||
{ | |||
u32 base_address; | |||
int has_start_address; | |||
u32 start_address; | |||
} fileio_image_t; | |||
typedef struct fileio_local_s | |||
{ | |||
FILE *file; | |||
struct stat file_stat; | |||
} fileio_local_t; | |||
typedef struct fileio_ihex_s | |||
{ | |||
u32 position; | |||
u32 raw_size; | |||
#ifdef FILEIO_BUFFER_COMPLETE_IHEX | |||
u8 *buffer; | |||
#endif | |||
} fileio_ihex_t; | |||
extern int fileio_identify_image_type(enum fileio_sec_type *sec_type, char *type_string); | |||
extern int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written); | |||
extern int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read); | |||
extern int fileio_seek(fileio_t *fileio, u32 position); | |||
extern int fileio_close(fileio_t *fileio); | |||
extern int fileio_open(fileio_t *fileio, char *url, enum fileio_access access, | |||
enum fileio_pri_type pri_type, void *pri_info, enum fileio_sec_type sec_type); | |||
extern int fileio_open(fileio_t *fileio, char *url, enum fileio_access access, enum fileio_type type); | |||
#define ERROR_FILEIO_LOCATION_UNKNOWN (-1200) | |||
#define ERROR_FILEIO_NOT_FOUND (-1201) | |||
@@ -1282,6 +1282,7 @@ int jtag_examine_chain() | |||
{ | |||
ERROR("number of discovered devices in JTAG chain (%i) doesn't match configuration (%i)", | |||
device_count, jtag_num_devices); | |||
ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)"); | |||
exit(-1); | |||
} | |||
@@ -18,7 +18,7 @@ | |||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||
***************************************************************************/ | |||
#define OPENOCD_VERSION "Open On-Chip Debugger (2007-04-26 16:40 CEST)" | |||
#define OPENOCD_VERSION "Open On-Chip Debugger (2007-05-29 13:15 CEST)" | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
@@ -3,7 +3,7 @@ METASOURCES = AUTO | |||
noinst_LIBRARIES = libtarget.a | |||
libtarget_a_SOURCES = target.c register.c breakpoints.c armv4_5.c embeddedice.c etm.c arm7tdmi.c arm9tdmi.c \ | |||
arm_jtag.c arm7_9_common.c algorithm.c arm920t.c arm720t.c armv4_5_mmu.c armv4_5_cache.c arm_disassembler.c \ | |||
arm966e.c arm926ejs.c etb.c xscale.c arm_simulator.c | |||
arm966e.c arm926ejs.c etb.c xscale.c arm_simulator.c image.c | |||
noinst_HEADERS = target.h register.h armv4_5.h embeddedice.h etm.h arm7tdmi.h arm9tdmi.h \ | |||
arm_jtag.h arm7_9_common.h arm920t.h arm720t.h armv4_5_mmu.h armv4_5_cache.h breakpoints.h algorithm.h \ | |||
arm_disassembler.h arm966e.h arm926ejs.h etb.h xscale.h arm_simulator.h | |||
arm_disassembler.h arm966e.h arm926ejs.h etb.h xscale.h arm_simulator.h image.h |
@@ -2096,8 +2096,6 @@ int arm7_9_register_commands(struct command_context_s *cmd_ctx) | |||
arm7_9_cmd = register_command(cmd_ctx, NULL, "arm7_9", NULL, COMMAND_ANY, "arm7/9 specific commands"); | |||
register_command(cmd_ctx, arm7_9_cmd, "etm", handle_arm7_9_etm_command, COMMAND_CONFIG, NULL); | |||
register_command(cmd_ctx, arm7_9_cmd, "write_xpsr", handle_arm7_9_write_xpsr_command, COMMAND_EXEC, "write program status register <value> <not cpsr|spsr>"); | |||
register_command(cmd_ctx, arm7_9_cmd, "write_xpsr_im8", handle_arm7_9_write_xpsr_im8_command, COMMAND_EXEC, "write program status register <8bit immediate> <rotate> <not cpsr|spsr>"); | |||
@@ -2115,7 +2113,8 @@ int arm7_9_register_commands(struct command_context_s *cmd_ctx) | |||
COMMAND_ANY, "use DCC downloads for larger memory writes <enable|disable>"); | |||
armv4_5_register_commands(cmd_ctx); | |||
etb_register_commands(cmd_ctx, arm7_9_cmd); | |||
etm_register_commands(cmd_ctx); | |||
return ERROR_OK; | |||
} | |||
@@ -2425,83 +2424,6 @@ int handle_arm7_9_dcc_downloads_command(struct command_context_s *cmd_ctx, char | |||
return ERROR_OK; | |||
} | |||
int handle_arm7_9_etm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) | |||
{ | |||
target_t *target; | |||
armv4_5_common_t *armv4_5; | |||
arm7_9_common_t *arm7_9; | |||
if (argc != 1) | |||
{ | |||
ERROR("incomplete 'arm7_9 etm <target>' command"); | |||
exit(-1); | |||
} | |||
target = get_target_by_num(strtoul(args[0], NULL, 0)); | |||
if (!target) | |||
{ | |||
ERROR("target number '%s' not defined", args[0]); | |||
exit(-1); | |||
} | |||
if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) | |||
{ | |||
command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); | |||
return ERROR_OK; | |||
} | |||
arm7_9->has_etm = 1; | |||
return ERROR_OK; | |||
} | |||
int handle_arm7_9_etb_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) | |||
{ | |||
target_t *target; | |||
jtag_device_t *jtag_device; | |||
armv4_5_common_t *armv4_5; | |||
arm7_9_common_t *arm7_9; | |||
if (argc != 2) | |||
{ | |||
ERROR("incomplete 'arm7_9 etb <target> <chain_pos>' command"); | |||
exit(-1); | |||
} | |||
target = get_target_by_num(strtoul(args[0], NULL, 0)); | |||
if (!target) | |||
{ | |||
ERROR("target number '%s' not defined", args[0]); | |||
exit(-1); | |||
} | |||
if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) | |||
{ | |||
command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); | |||
return ERROR_OK; | |||
} | |||
jtag_device = jtag_get_device(strtoul(args[1], NULL, 0)); | |||
if (!jtag_device) | |||
{ | |||
ERROR("jtag device number '%s' not defined", args[1]); | |||
exit(-1); | |||
} | |||
arm7_9->etb = malloc(sizeof(etb_t)); | |||
arm7_9->etb->chain_pos = strtoul(args[1], NULL, 0); | |||
arm7_9->etb->cur_scan_chain = -1; | |||
arm7_9->etb->reg_cache = NULL; | |||
arm7_9->etb->RAM_width = 0; | |||
arm7_9->etb->RAM_depth = 0; | |||
return ERROR_OK; | |||
} | |||
int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9) | |||
{ | |||
armv4_5_common_t *armv4_5 = &arm7_9->armv4_5_common; | |||
@@ -2515,8 +2437,7 @@ int arm7_9_init_arch_info(target_t *target, arm7_9_common_t *arm7_9) | |||
arm7_9->force_hw_bkpts = 0; | |||
arm7_9->use_dbgrq = 0; | |||
arm7_9->has_etm = 0; | |||
arm7_9->etb = NULL; | |||
arm7_9->etm_ctx = NULL; | |||
arm7_9->has_single_step = 0; | |||
arm7_9->has_monitor_mode = 0; | |||
arm7_9->has_vector_catch = 0; | |||
@@ -25,7 +25,7 @@ | |||
#include "breakpoints.h" | |||
#include "target.h" | |||
#include "etb.h" | |||
#include "etm.h" | |||
#define ARM7_9_COMMON_MAGIC 0x0a790a79 | |||
@@ -35,7 +35,6 @@ typedef struct arm7_9_common_s | |||
arm_jtag_t jtag_info; | |||
reg_cache_t *eice_cache; | |||
reg_cache_t *etm_cache; | |||
u32 arm_bkpt; | |||
u16 thumb_bkpt; | |||
@@ -48,8 +47,8 @@ typedef struct arm7_9_common_s | |||
int dbgreq_adjust_pc; | |||
int use_dbgrq; | |||
int has_etm; | |||
etb_t *etb; | |||
etm_context_t *etm_ctx; | |||
int has_single_step; | |||
int has_monitor_mode; | |||
int has_vector_catch; | |||
@@ -744,10 +744,10 @@ void arm7tdmi_build_reg_cache(target_t *target) | |||
(*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); | |||
arm7_9->eice_cache = (*cache_p)->next; | |||
if (arm7_9->has_etm) | |||
if (arm7_9->etm_ctx) | |||
{ | |||
(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0); | |||
arm7_9->etm_cache = (*cache_p)->next->next; | |||
(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); | |||
arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; | |||
} | |||
} | |||
@@ -874,16 +874,10 @@ void arm9tdmi_build_reg_cache(target_t *target) | |||
(*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); | |||
arm7_9->eice_cache = (*cache_p)->next; | |||
if (arm7_9->has_etm) | |||
if (arm7_9->etm_ctx) | |||
{ | |||
(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, 0); | |||
arm7_9->etm_cache = (*cache_p)->next->next; | |||
} | |||
if (arm7_9->etb) | |||
{ | |||
(*cache_p)->next->next->next = etb_build_reg_cache(arm7_9->etb); | |||
arm7_9->etb->reg_cache = (*cache_p)->next->next->next; | |||
(*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); | |||
arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; | |||
} | |||
} | |||
@@ -343,7 +343,10 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) | |||
if (!I) /* #+-<offset_12> */ | |||
{ | |||
u32 offset_12 = (opcode & 0xfff); | |||
snprintf(offset, 32, "#%s0x%x", (U) ? "" : "-", offset_12); | |||
if (offset_12) | |||
snprintf(offset, 32, ", #%s0x%x", (U) ? "" : "-", offset_12); | |||
else | |||
snprintf(offset, 32, ""); | |||
instruction->info.load_store.offset_mode = 0; | |||
instruction->info.load_store.offset.offset = offset_12; | |||
@@ -376,26 +379,26 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) | |||
if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */ | |||
{ | |||
snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm); | |||
snprintf(offset, 32, ", %sr%i", (U) ? "" : "-", Rm); | |||
} | |||
else /* +-<Rm>, <Shift>, #<shift_imm> */ | |||
{ | |||
switch (shift) | |||
{ | |||
case 0x0: /* LSL */ | |||
snprintf(offset, 32, "%sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm); | |||
snprintf(offset, 32, ", %sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm); | |||
break; | |||
case 0x1: /* LSR */ | |||
snprintf(offset, 32, "%sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm); | |||
snprintf(offset, 32, ", %sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm); | |||
break; | |||
case 0x2: /* ASR */ | |||
snprintf(offset, 32, "%sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm); | |||
snprintf(offset, 32, ", %sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm); | |||
break; | |||
case 0x3: /* ROR */ | |||
snprintf(offset, 32, "%sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm); | |||
snprintf(offset, 32, ", %sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm); | |||
break; | |||
case 0x4: /* RRX */ | |||
snprintf(offset, 32, "%sr%i, RRX", (U) ? "" : "-", Rm); | |||
snprintf(offset, 32, ", %sr%i, RRX", (U) ? "" : "-", Rm); | |||
break; | |||
} | |||
} | |||
@@ -405,7 +408,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) | |||
{ | |||
if (W == 0) /* offset */ | |||
{ | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]", | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]", | |||
address, opcode, operation, COND(opcode), suffix, | |||
Rd, Rn, offset); | |||
@@ -413,7 +416,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) | |||
} | |||
else /* pre-indexed */ | |||
{ | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!", | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]!", | |||
address, opcode, operation, COND(opcode), suffix, | |||
Rd, Rn, offset); | |||
@@ -422,7 +425,7 @@ int evaluate_load_store(u32 opcode, u32 address, arm_instruction_t *instruction) | |||
} | |||
else /* post-indexed */ | |||
{ | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s", | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i]%s", | |||
address, opcode, operation, COND(opcode), suffix, | |||
Rd, Rn, offset); | |||
@@ -1157,7 +1160,10 @@ int evaluate_data_proc(u32 opcode, u32 address, arm_instruction_t *instruction) | |||
} | |||
else if ((op == 0xd) || (op == 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */ | |||
{ | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s", | |||
if (opcode==0xe1a00000) /* print MOV r0,r0 as NOP */ | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\tNOP",address, opcode); | |||
else | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s", | |||
address, opcode, mnemonic, COND(opcode), | |||
(S) ? "S" : "", Rd, shifter_operand); | |||
} | |||
@@ -1315,3 +1321,762 @@ int arm_evaluate_opcode(u32 opcode, u32 address, arm_instruction_t *instruction) | |||
return -1; | |||
} | |||
int evaluate_b_bl_blx_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) | |||
{ | |||
u32 offset = opcode & 0x7ff; | |||
u32 opc = (opcode >> 11) & 0x3; | |||
u32 target_address; | |||
char *mnemonic = NULL; | |||
/* sign extend 11-bit offset */ | |||
if (((opc==0) || (opc==2)) && (offset & 0x00000400)) | |||
offset = 0xfffff800 | offset; | |||
target_address = address + 4 + (offset<<1); | |||
switch(opc) | |||
{ | |||
/* unconditional branch */ | |||
case 0: | |||
instruction->type = ARM_B; | |||
mnemonic = "B"; | |||
break; | |||
/* BLX suffix */ | |||
case 1: | |||
instruction->type = ARM_BLX; | |||
mnemonic = "BLX"; | |||
break; | |||
/* BL/BLX prefix */ | |||
case 2: | |||
instruction->type = ARM_UNKNOWN_INSTUCTION; | |||
mnemonic = "prefix"; | |||
target_address = offset<<12; | |||
break; | |||
/* BL suffix */ | |||
case 3: | |||
instruction->type = ARM_BL; | |||
mnemonic = "BL"; | |||
break; | |||
} | |||
/* TODO: deals correctly with dual opcodes BL/BLX ... */ | |||
snprintf(instruction->text, 128, "0x%8.8x\t0x%4.4x\t%s 0x%8.8x", address, opcode,mnemonic, target_address); | |||
instruction->info.b_bl_bx_blx.reg_operand = -1; | |||
instruction->info.b_bl_bx_blx.target_address = target_address; | |||
return ERROR_OK; | |||
} | |||
int evaluate_add_sub_thumb(u16 opcode, u32 address, arm_instruction_t *instruction) | |||
{ | |||
u8 Rd = (opcode >> 0) & 0x7; | |||
u8 Rn = (opcode >> 3) & 0x7; | |||
u8 Rm_imm = (opcode >> 6) & 0x7; | |||
u32 opc = opcode & (1<<9); | |||
u32 reg_imm = opcode & (1<<10); | |||
char *mnemonic; | |||
if (opc) | |||
{ | |||
instruction->type = ARM_SUB; | |||
mnemonic = "SUBS"; | |||
} | |||
else | |||