X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstellaris.c;h=0b7c45a31f45ba241d6df6e21c869d0315a3dae4;hb=f10ed95a5ce6be416bcb2ec20826c6e508e4b622;hp=51fe677cd75a8c9acb1836c7cfa0a28b9b40eedd;hpb=e40f6380638ed3f7780b78ceb1411f8b7059a073;p=openocd.git diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 51fe677cd7..0b7c45a31f 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -693,8 +693,8 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la if (!set) { - LOG_ERROR("Can't unprotect write-protected pages."); - /* except by the "recover locked device" procedure ... */ + LOG_ERROR("Hardware doesn't suppport page-level unprotect. " + "Try the 'recover' command."); return ERROR_INVALID_ARGUMENTS; } @@ -706,7 +706,7 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la || (last < first) || !(last & 1) || (last >= 2 * stellaris_info->num_lockbits)) { - LOG_ERROR("Can't protect unaligned or out-of-range sectors."); + LOG_ERROR("Can't protect unaligned or out-of-range pages."); return ERROR_FLASH_SECTOR_INVALID; } @@ -805,8 +805,7 @@ static const uint8_t stellaris_write_code[] = 0x04,0x36, /* adds r6, r6, #4 */ 0x96,0x42, /* cmp r6, r2 */ 0xF4,0xD1, /* bne mainloop */ - /* exit: */ - 0xFE,0xE7, /* b exit */ + 0x00,0xBE, /* bkpt #0 */ /* pFLASH_CTRL_BASE: */ 0x00,0xD0,0x0F,0x40, /* .word 0x400FD000 */ /* FLASHWRITECMD: */ @@ -826,10 +825,10 @@ static int stellaris_write_block(struct flash_bank *bank, int retval = ERROR_OK; /* power of two, and multiple of word size */ - static const unsigned buf_min = 32; + static const unsigned buf_min = 128; /* for small buffers it's faster not to download an algorithm */ - if (wcount < buf_min) + if (wcount * 4 < buf_min) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", @@ -843,11 +842,8 @@ static int stellaris_write_block(struct flash_bank *bank, }; /* plus a buffer big enough for this data */ - if (wcount < buffer_size) { - buffer_size = wcount; - buffer_size += buf_min - 1; - buffer_size &= ~(buf_min - 1); - } + if (wcount * 4 < buffer_size) + buffer_size = wcount * 4; /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) @@ -1173,19 +1169,85 @@ COMMAND_HANDLER(stellaris_handle_mass_erase_command) return ERROR_OK; } +/** + * Perform the Stellaris "Recovering a 'Locked' Device procedure. + * This performs a mass erase and then restores all nonvolatile registers + * (including USER_* registers and flash lock bits) to their defaults. + * Accordingly, flash can be reprogrammed, and JTAG can be used. + * + * NOTE that DustDevil parts (at least rev A0 silicon) have errata which + * can affect this operation if flash protection has been enabled. + */ +COMMAND_HANDLER(stellaris_handle_recover_command) +{ + struct flash_bank *bank; + int retval; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + /* REVISIT ... it may be worth sanity checking that the AP is + * inactive before we start. ARM documents that switching a DP's + * mode while it's active can cause fault modes that need a power + * cycle to recover. + */ + + /* assert SRST */ + if (!(jtag_get_reset_config() & RESET_HAS_SRST)) { + LOG_ERROR("Can't recover Stellaris flash without SRST"); + return ERROR_FAIL; + } + jtag_add_reset(0, 1); + + for (int i = 0; i < 5; i++) { + retval = dap_to_swd(bank->target); + if (retval != ERROR_OK) + goto done; + + retval = dap_to_jtag(bank->target); + if (retval != ERROR_OK) + goto done; + } + + /* de-assert SRST */ + jtag_add_reset(0, 0); + retval = jtag_execute_queue(); + + /* wait 400+ msec ... OK, "1+ second" is simpler */ + usleep(1000); + + /* USER INTERVENTION required for the power cycle + * Restarting OpenOCD is likely needed because of mode switching. + */ + LOG_INFO("USER ACTION: " + "power cycle Stellaris chip, then restart OpenOCD."); + +done: + return retval; +} + static const struct command_registration stellaris_exec_command_handlers[] = { { .name = "mass_erase", - .handler = &stellaris_handle_mass_erase_command, + .handler = stellaris_handle_mass_erase_command, .mode = COMMAND_EXEC, + .usage = "bank_id", .help = "erase entire device", }, + { + .name = "recover", + .handler = stellaris_handle_recover_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "recover (and erase) locked device", + }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stellaris_command_handlers[] = { { .name = "stellaris", - .mode = COMMAND_ANY, + .mode = COMMAND_EXEC, .help = "Stellaris flash command group", .chain = stellaris_exec_command_handlers, },