diff options
author | drath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60> | 2007-05-29 11:23:42 +0000 |
---|---|---|
committer | drath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60> | 2007-05-29 11:23:42 +0000 |
commit | 237e894805dd757cc24029af1b4b1e824c51712b (patch) | |
tree | abe2187fa53c3ba2e51201df0a60a6e10af6cc0f /src/flash | |
parent | e8af4de0a7d224e1aa28e72f0de1ddf0bec5beb8 (diff) | |
download | openocd_libswd-237e894805dd757cc24029af1b4b1e824c51712b.tar.gz openocd_libswd-237e894805dd757cc24029af1b4b1e824c51712b.tar.bz2 openocd_libswd-237e894805dd757cc24029af1b4b1e824c51712b.tar.xz openocd_libswd-237e894805dd757cc24029af1b4b1e824c51712b.zip |
- split fileio handling into fileio part and image handling
- 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-e2dbd0fdcd60
Diffstat (limited to 'src/flash')
-rw-r--r-- | src/flash/Makefile.am | 4 | ||||
-rw-r--r-- | src/flash/cfi.c | 410 | ||||
-rw-r--r-- | src/flash/cfi.h | 18 | ||||
-rw-r--r-- | src/flash/flash.c | 28 | ||||
-rw-r--r-- | src/flash/nand.c | 58 | ||||
-rw-r--r-- | src/flash/non_cfi.c | 175 | ||||
-rw-r--r-- | src/flash/non_cfi.h | 41 |
7 files changed, 535 insertions, 199 deletions
diff --git a/src/flash/Makefile.am b/src/flash/Makefile.am index 6368f626..8f99e05e 100644 --- a/src/flash/Makefile.am +++ b/src/flash/Makefile.am @@ -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 diff --git a/src/flash/cfi.c b/src/flash/cfi.c index 83a8120a..69494b5f 100644 --- a/src/flash/cfi.c +++ b/src/flash/cfi.c @@ -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++) { diff --git a/src/flash/cfi.h b/src/flash/cfi.h index fa53f0d8..b4e3ab22 100644 --- a/src/flash/cfi.h +++ b/src/flash/cfi.h @@ -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 diff --git a/src/flash/flash.c b/src/flash/flash.c index f5c83f80..6af29825 100644 --- a/src/flash/flash.c +++ b/src/flash/flash.c @@ -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; } diff --git a/src/flash/nand.c b/src/flash/nand.c index e0dfa22f..38a70749 100644 --- a/src/flash/nand.c +++ b/src/flash/nand.c @@ -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 diff --git a/src/flash/non_cfi.c b/src/flash/non_cfi.c new file mode 100644 index 00000000..3a74ff92 --- /dev/null +++ b/src/flash/non_cfi.c @@ -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); + } +} + diff --git a/src/flash/non_cfi.h b/src/flash/non_cfi.h new file mode 100644 index 00000000..e91b2098 --- /dev/null +++ b/src/flash/non_cfi.h @@ -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 */ + |