aarch64: add support for "reset halt"
[openocd.git] / src / target / aarch64.c
index d111a05687730464f06b362dc97469c344af9d60..e45803040baac5897ef6ee03724be78ecf899ac9 100644 (file)
@@ -1677,22 +1677,102 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b
  * Cortex-A8 Reset functions
  */
 
+static int aarch64_enable_reset_catch(struct target *target, bool enable)
+{
+       struct armv8_common *armv8 = target_to_armv8(target);
+       uint32_t edecr;
+       int retval;
+
+       retval = mem_ap_read_atomic_u32(armv8->debug_ap,
+                       armv8->debug_base + CPUV8_DBG_EDECR, &edecr);
+       LOG_DEBUG("EDECR = 0x%08" PRIx32 ", enable=%d", edecr, enable);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (enable)
+               edecr |= ECR_RCE;
+       else
+               edecr &= ~ECR_RCE;
+
+       return mem_ap_write_atomic_u32(armv8->debug_ap,
+                       armv8->debug_base + CPUV8_DBG_EDECR, edecr);
+}
+
+static int aarch64_clear_reset_catch(struct target *target)
+{
+       struct armv8_common *armv8 = target_to_armv8(target);
+       uint32_t edesr;
+       int retval;
+       bool was_triggered;
+
+       /* check if Reset Catch debug event triggered as expected */
+       retval = mem_ap_read_atomic_u32(armv8->debug_ap,
+               armv8->debug_base + CPUV8_DBG_EDESR, &edesr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       was_triggered = !!(edesr & ESR_RC);
+       LOG_DEBUG("Reset Catch debug event %s",
+                       was_triggered ? "triggered" : "NOT triggered!");
+
+       if (was_triggered) {
+               /* clear pending Reset Catch debug event */
+               edesr &= ~ESR_RC;
+               retval = mem_ap_write_atomic_u32(armv8->debug_ap,
+                       armv8->debug_base + CPUV8_DBG_EDESR, edesr);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
 static int aarch64_assert_reset(struct target *target)
 {
        struct armv8_common *armv8 = target_to_armv8(target);
+       enum reset_types reset_config = jtag_get_reset_config();
+       int retval;
 
        LOG_DEBUG(" ");
 
-       /* FIXME when halt is requested, make it work somehow... */
-
        /* Issue some kind of warm reset. */
        if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT))
                target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
-       else if (jtag_get_reset_config() & RESET_HAS_SRST) {
+       else if (reset_config & RESET_HAS_SRST) {
+               bool srst_asserted = false;
+
+               if (target->reset_halt) {
+                       if (target_was_examined(target)) {
+
+                               if (reset_config & RESET_SRST_NO_GATING) {
+                                       /*
+                                        * SRST needs to be asserted *before* Reset Catch
+                                        * debug event can be set up.
+                                        */
+                                       adapter_assert_reset();
+                                       srst_asserted = true;
+
+                                       /* make sure to clear all sticky errors */
+                                       mem_ap_write_atomic_u32(armv8->debug_ap,
+                                                       armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE);
+                               }
+
+                               /* set up Reset Catch debug event to halt the CPU after reset */
+                               retval = aarch64_enable_reset_catch(target, true);
+                               if (retval != ERROR_OK)
+                                       LOG_WARNING("%s: Error enabling Reset Catch debug event; the CPU will not halt immediately after reset!",
+                                                       target_name(target));
+                       } else {
+                               LOG_WARNING("%s: Target not examined, will not halt immediately after reset!",
+                                               target_name(target));
+                       }
+               }
+
                /* REVISIT handle "pulls" cases, if there's
                 * hardware that needs them to work.
                 */
-               adapter_assert_reset();
+               if (!srst_asserted)
+                       adapter_assert_reset();
        } else {
                LOG_ERROR("%s: how to reset?", target_name(target));
                return ERROR_FAIL;
@@ -1721,23 +1801,37 @@ static int aarch64_deassert_reset(struct target *target)
        if (!target_was_examined(target))
                return ERROR_OK;
 
-       retval = aarch64_poll(target);
+       retval = aarch64_init_debug_access(target);
        if (retval != ERROR_OK)
                return retval;
 
-       retval = aarch64_init_debug_access(target);
+       retval = aarch64_poll(target);
        if (retval != ERROR_OK)
                return retval;
 
        if (target->reset_halt) {
+               /* clear pending Reset Catch debug event */
+               retval = aarch64_clear_reset_catch(target);
+               if (retval != ERROR_OK)
+                       LOG_WARNING("%s: Clearing Reset Catch debug event failed",
+                                       target_name(target));
+
+               /* disable Reset Catch debug event */
+               retval = aarch64_enable_reset_catch(target, false);
+               if (retval != ERROR_OK)
+                       LOG_WARNING("%s: Disabling Reset Catch debug event failed",
+                                       target_name(target));
+
                if (target->state != TARGET_HALTED) {
                        LOG_WARNING("%s: ran after reset and before halt ...",
                                target_name(target));
                        retval = target_halt(target);
+                       if (retval != ERROR_OK)
+                               return retval;
                }
        }
 
-       return retval;
+       return ERROR_OK;
 }
 
 static int aarch64_write_cpu_memory_slow(struct target *target,

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)