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: */
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 "",
};
/* 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)
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 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,
},