stellaris: recover_command use usleep rather than sleep
[fw/openocd] / src / flash / nor / stellaris.c
index 51fe677cd75a8c9acb1836c7cfa0a28b9b40eedd..c9c800ea2d43010c71ab5518a3daaf32e38c58fc 100644 (file)
@@ -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 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,
        },