diff options
Diffstat (limited to 'src/flash/cfi.c')
-rw-r--r-- | src/flash/cfi.c | 410 |
1 files changed, 260 insertions, 150 deletions
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++) { |