diff --git a/NEWS b/NEWS index b39b3a8f6..56c697ff5 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,12 @@ Boundary Scan: Target Layer: Flash Layer: + New "stellaris recover" command, implements the procedure + to recover locked devices (restoring non-volatile + state to the factory defaults, including erasing + the flash and its protection bits, and possibly + re-enabling hardware debugging). + Board, Target, and Interface Configuration Scripts: diff --git a/doc/openocd.texi b/doc/openocd.texi index 61e39b284..aa8bed1b1 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4497,6 +4497,21 @@ flash bank stellaris 0 0 0 0 $_TARGETNAME @end example @end deffn +@deffn Command {stellaris recover bank_id} +Performs the @emph{Recovering a "Locked" Device} procedure to +restore the flash specified by @var{bank_id} and its associated +nonvolatile registers to their factory default values (erased). +This is the only way to remove flash protection or re-enable +debugging if that capability has been disabled. + +Note that the final "power cycle the chip" step in this procedure +must be performed by hand, since OpenOCD can't do it. +@quotation Warning +if more than one Stellaris chip is connected, the procedure is +applied to all of them. +@end quotation +@end deffn + @deffn {Flash Driver} stm32x All members of the STM32 microcontroller family from ST Microelectronics include internal flash and use ARM Cortex M3 cores. diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 107b1c6d1..21a0cffd4 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -1170,13 +1170,79 @@ 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 */ + sleep(1); + + /* 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, .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 locked device", + }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stellaris_command_handlers[] = {