X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fcfi.c;h=b8b7eb5409d176839c8d3c2423e41fae4324b87a;hp=fb3d4cc884d032e554804b7544f64d8432a12497;hb=5ed126c4f90948fbf53d186dc4ef49018fb5ecfc;hpb=fbf5bec7f3ea9f4a9584099a12e71681cb55ce35;ds=sidebyside diff --git a/src/flash/cfi.c b/src/flash/cfi.c index fb3d4cc884..b8b7eb5409 100644 --- a/src/flash/cfi.c +++ b/src/flash/cfi.c @@ -88,6 +88,12 @@ void cfi_command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf) cfi_flash_bank_t *cfi_info = bank->driver_priv; int i; + /* clear whole buffer, to ensure bits that exceed the bus_width + * are set to zero + */ + for (i = 0; i < CFI_MAX_BUS_WIDTH; i++) + cmd_buf[i] = 0; + if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN) { for (i = bank->bus_width; i > 0; i--) @@ -206,10 +212,17 @@ u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout) DEBUG("status: 0x%x", status); usleep(1000); } - - DEBUG("status: 0x%x", status); - if (status != 0x80) + /* mask out bit 0 (reserved) */ + status = status & 0xfe; + + DEBUG("status: 0x%x", status); + + if ((status & 0x80) != 0x80) + { + ERROR("timeout while waiting for WSM to become ready"); + } + else if (status != 0x80) { ERROR("status register: 0x%x", status); if (status & 0x2) @@ -316,7 +329,7 @@ int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size) int cfi_register_commands(struct command_context_s *cmd_ctx) { - command_t *cfi_cmd = register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL); + /*command_t *cfi_cmd = */register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL); /* register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC, "print part id of cfi flash bank "); @@ -349,9 +362,11 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char ** cfi_info->target = get_target_by_num(strtoul(args[5], NULL, 0)); if (!cfi_info->target) { - ERROR("no target '%i' configured", args[5]); + ERROR("no target '%s' configured", args[5]); exit(-1); } + + cfi_info->write_algorithm = NULL; /* bank wasn't probed yet */ cfi_info->qry[0] = -1; @@ -362,7 +377,6 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char ** int cfi_intel_erase(struct flash_bank_s *bank, int first, int last) { cfi_flash_bank_t *cfi_info = bank->driver_priv; - cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; target_t *target = cfi_info->target; u8 command[8]; int i; @@ -432,8 +446,12 @@ int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last) cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; target_t *target = cfi_info->target; u8 command[8]; + int retry = 0; int i; + /* if the device supports neither legacy lock/unlock (bit 3) nor + * instant individual block locking (bit 5). + */ if (!(pri_ext->feature_support & 0x28)) return ERROR_FLASH_OPERATION_FAILED; @@ -442,21 +460,53 @@ int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last) for (i = first; i <= last; i++) { cfi_command(bank, 0x60, command); + DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command)); target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); if (set) { cfi_command(bank, 0x01, command); + DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command)); target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); bank->sectors[i].is_protected = 1; } else { cfi_command(bank, 0xd0, command); + DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command)); target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); bank->sectors[i].is_protected = 0; } - - cfi_intel_wait_status_busy(bank, 100); + + /* instant individual block locking doesn't require reading of the status register */ + if (!(pri_ext->feature_support & 0x20)) + { + /* Clear lock bits operation may take up to 1.4s */ + cfi_intel_wait_status_busy(bank, 1400); + } + else + { + u8 block_status; + /* read block lock bit, to verify status */ + cfi_command(bank, 0x90, command); + target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); + block_status = cfi_get_u8(bank, i, 0x2); + + if ((block_status & 0x1) != set) + { + ERROR("couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status); + cfi_command(bank, 0x70, command); + target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); + cfi_intel_wait_status_busy(bank, 10); + + if (retry > 10) + return ERROR_FLASH_OPERATION_FAILED; + else + { + i--; + retry++; + } + } + } } /* if the device doesn't support individual block lock bits set/clear, @@ -542,29 +592,40 @@ void cfi_add_byte(struct flash_bank_s *bank, u8 *word, u8 byte) int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u32 count) { cfi_flash_bank_t *cfi_info = bank->driver_priv; - cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; target_t *target = cfi_info->target; - reg_param_t reg_params[5]; + reg_param_t reg_params[7]; armv4_5_algorithm_t armv4_5_info; working_area_t *source; u32 buffer_size = 32768; u8 write_command[CFI_MAX_BUS_WIDTH]; - int i; + u8 busy_pattern[CFI_MAX_BUS_WIDTH]; + u8 error_pattern[CFI_MAX_BUS_WIDTH]; int retval; + /* algorithm register usage: + * r0: source address (in RAM) + * r1: target address (in Flash) + * r2: count + * r3: flash write command + * r4: status byte (returned to host) + * r5: busy test pattern + * r6: error test pattern + */ + u32 word_32_code[] = { 0xe4904004, /* loop: ldr r4, [r0], #4 */ 0xe5813000, /* str r3, [r1] */ 0xe5814000, /* str r4, [r1] */ - 0xe5914000, /* busy ldr r4, [r1] */ - 0xe3140080, /* tst r4, #0x80 */ - 0x0afffffc, /* beq busy */ - 0xe314007f, /* tst r4, #0x7f */ + 0xe5914000, /* busy: ldr r4, [r1] */ + 0xe0047005, /* and r7, r4, r5 */ + 0xe1570005, /* cmp r7, r5 */ + 0x1afffffb, /* bne busy */ + 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811004, /* add r1, r1 #4 */ - 0xeafffff3, /* b loop */ + 0xeafffff2, /* b loop */ 0xeafffffe, /* done: b -2 */ }; @@ -573,14 +634,15 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 0xe1c130b0, /* strh r3, [r1] */ 0xe1c140b0, /* strh r4, [r1] */ 0xe1d140b0, /* busy ldrh r4, [r1] */ - 0xe3140080, /* tst r4, #0x80 */ - 0x0afffffc, /* beq busy */ - 0xe314007f, /* tst r4, #0x7f */ + 0xe0047005, /* and r7, r4, r5 */ + 0xe1570005, /* cmp r7, r5 */ + 0x1afffffb, /* bne busy */ + 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811002, /* add r1, r1 #2 */ - 0xeafffff3, /* b loop */ + 0xeafffff2, /* b loop */ 0xeafffffe, /* done: b -2 */ }; @@ -589,14 +651,15 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 0xe5c13000, /* strb r3, [r1] */ 0xe5c14000, /* strb r4, [r1] */ 0xe5d14000, /* busy ldrb r4, [r1] */ - 0xe3140080, /* tst r4, #0x80 */ - 0x0afffffc, /* beq busy */ - 0xe314007f, /* tst r4, #0x7f */ + 0xe0047005, /* and r7, r4, r5 */ + 0xe1570005, /* cmp r7, r5 */ + 0x1afffffb, /* bne busy */ + 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811001, /* add r1, r1 #1 */ - 0xeafffff3, /* b loop */ + 0xeafffff2, /* b loop */ 0xeafffffe, /* done: b -2 */ }; @@ -609,7 +672,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 /* flash write code */ if (!cfi_info->write_algorithm) { - if (target_alloc_working_area(target, 4 * 13, &cfi_info->write_algorithm) != ERROR_OK) + 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; @@ -618,15 +681,15 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 /* write algorithm code to working area */ if (bank->bus_width == 1) { - target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_8_code); + target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_8_code); } else if (bank->bus_width == 2) { - target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_16_code); + target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_16_code); } else if (bank->bus_width == 4) { - target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_32_code); + target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_32_code); } else { @@ -653,6 +716,12 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_IN); + 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); while (count > 0) { @@ -663,16 +732,17 @@ 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); - cfi_command(bank, 0x40, write_command); - buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32)); + 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)); - if ((retval = target->type->run_algorithm(target, 0, NULL, 5, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (12 * 4), 10000, &armv4_5_info)) != ERROR_OK) + 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) { cfi_intel_clear_status_register(bank); return ERROR_FLASH_OPERATION_FAILED; } - if (buf_get_u32(reg_params[4].value, 0, 32) != 0x80) + if (buf_get_u32(reg_params[4].value, 0, 32) & target_buffer_get_u32(target, error_pattern)) { /* read status register (outputs debug inforation) */ cfi_intel_wait_status_busy(bank, 100); @@ -685,19 +755,22 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 count -= thisrun_count; } + target_free_working_area(target, source); + destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); - + destroy_reg_param(®_params[5]); + destroy_reg_param(®_params[6]); + return ERROR_OK; } int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address) { cfi_flash_bank_t *cfi_info = bank->driver_priv; - cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; target_t *target = cfi_info->target; u8 command[8]; @@ -722,7 +795,6 @@ int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address) int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address) { cfi_flash_bank_t *cfi_info = bank->driver_priv; - target_t *target = cfi_info->target; switch(cfi_info->pri_id) { @@ -808,6 +880,7 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) break; default: ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + retval = ERROR_FLASH_OPERATION_FAILED; break; } if (retval != ERROR_OK) @@ -882,6 +955,8 @@ int cfi_probe(struct flash_bank_s *bank) 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); @@ -928,9 +1003,9 @@ int cfi_probe(struct flash_bank_s *bank) 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, cfi_info->max_buf_write_size); + 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->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); } @@ -959,7 +1034,7 @@ int cfi_probe(struct flash_bank_s *bank) for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) { bank->sectors[sector].offset = offset; - bank->sectors[sector].size = (cfi_info->erase_region_info[i] >> 16) * 256; + bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) * bank->bus_width / bank->chip_width; offset += bank->sectors[sector].size; bank->sectors[sector].is_erased = -1; bank->sectors[sector].is_protected = -1; @@ -1003,11 +1078,11 @@ int cfi_erase_check(struct flash_bank_s *bank) { u32 erase_check_code[] = { - 0xe4d03001, - 0xe0022003, - 0xe2511001, - 0x1afffffb, - 0xeafffffe + 0xe4d03001, /* ldrb r3, [r0], #1 */ + 0xe0022003, /* and r2, r2, r3 */ + 0xe2511001, /* subs r1, r1, #1 */ + 0x1afffffb, /* b -4 */ + 0xeafffffe /* b 0 */ }; /* make sure we have a working area */ @@ -1017,8 +1092,13 @@ int cfi_erase_check(struct flash_bank_s *bank) } else { + u8 erase_check_code_buf[5 * 4]; + + for (i = 0; i < 5; i++) + target_buffer_set_u32(target, erase_check_code_buf + (i*4), erase_check_code[i]); + /* write algorithm code to working area */ - target->type->write_memory(target, cfi_info->erase_check_algorithm->address, 4, 5, (u8*)erase_check_code); + target->type->write_memory(target, cfi_info->erase_check_algorithm->address, 4, 5, erase_check_code_buf); } } @@ -1103,7 +1183,7 @@ int cfi_intel_protect_check(struct flash_bank_s *bank) cfi_flash_bank_t *cfi_info = bank->driver_priv; cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; target_t *target = cfi_info->target; - u8 command[8]; + u8 command[CFI_MAX_BUS_WIDTH]; int i; /* check if block lock bits are supported on this device */ @@ -1132,7 +1212,6 @@ int cfi_intel_protect_check(struct flash_bank_s *bank) int cfi_protect_check(struct flash_bank_s *bank) { cfi_flash_bank_t *cfi_info = bank->driver_priv; - target_t *target = cfi_info->target; if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED;