diff --git a/src/cmd/reset.c b/src/cmd/reset.c index efce080..5ed914b 100644 --- a/src/cmd/reset.c +++ b/src/cmd/reset.c @@ -20,7 +20,6 @@ int cmd_reset(const char *name __unused, int argc, char *argv[]) { struct host _host, *host = &_host; struct soc _soc, *soc = &_soc; - int64_t wait = 0; struct ahb *ahb; struct clk *clk; struct wdt *wdt; @@ -83,11 +82,8 @@ int cmd_reset(const char *name __unused, int argc, char *argv[]) /* wdt_perform_reset ungates the ARM if required */ logi("Performing SoC reset\n"); - if ((wait = wdt_perform_reset(wdt)) > 0) - usleep(wait); - - /* Cleanup */ - if (wait < 0) { + rc = wdt_perform_reset(wdt); + if (rc < 0) { clk_enable_arm: if ((cleanup = clk_enable(clk, clk_arm)) < 0) { errno = -cleanup; diff --git a/src/cmd/write.c b/src/cmd/write.c index a876d57..a9428cd 100644 --- a/src/cmd/write.c +++ b/src/cmd/write.c @@ -163,7 +163,6 @@ int cmd_write(const char *name __unused, int argc, char *argv[]) if (rc == 0) { if (!ahb->drv->local) { struct wdt *wdt; - int64_t wait; logi("Performing SoC reset\n"); if (!(wdt = wdt_get_by_name(soc, "wdt2"))) { @@ -171,14 +170,9 @@ int cmd_write(const char *name __unused, int argc, char *argv[]) goto cleanup_soc; } - wait = wdt_perform_reset(wdt); - - if (wait < 0) { - rc = wait; + rc = wdt_perform_reset(wdt); + if (rc < 0) goto cleanup_soc; - } - - usleep(wait); } } else { logi("Deconfiguring VUART host Tx discard\n"); diff --git a/src/soc/wdt.c b/src/soc/wdt.c index 9abc60a..367199e 100644 --- a/src/soc/wdt.c +++ b/src/soc/wdt.c @@ -9,6 +9,7 @@ #include #include #include +#include /* Registers */ #define WDT_RELOAD 0x04 @@ -119,7 +120,7 @@ static int64_t wdt_usecs_to_ticks(struct wdt *ctx, uint32_t usecs) return usecs; } -int64_t wdt_perform_reset(struct wdt *ctx) +int wdt_perform_reset(struct wdt *ctx) { uint32_t mode; int64_t wait; @@ -159,6 +160,22 @@ int64_t wdt_perform_reset(struct wdt *ctx) if ((rc = wdt_writel(ctx, WDT_CTRL, mode)) < 0) return rc; + if ((rc = ahb_release_bridge(ctx->soc->ahb)) < 0) + return rc; + + /* + * Allow a little extra time for reset to occur (we're timing this + * asynchronously after all) before we try to reinitialize the bridge + */ + wait += 1000000; + logd("Waiting %"PRId64" microseconds for watchdog timer to expire\n", wait); + usleep(wait); + + if ((rc = ahb_reinit_bridge(ctx->soc->ahb)) < 0) { + loge("Failed to reinitialize bridge after reset: %d\n", rc); + return rc; + } + /* The ARM clock gate is sticky on reset?! Ensure it's clear */ if ((rc = clk_enable(ctx->clk, clk_arm)) < 0) return rc; @@ -167,7 +184,7 @@ int64_t wdt_perform_reset(struct wdt *ctx) if (rc < 0) return rc; - return wait; + return 0; } static const struct soc_device_id wdt_match[] = { diff --git a/src/soc/wdt.h b/src/soc/wdt.h index b6d8b57..cec8301 100644 --- a/src/soc/wdt.h +++ b/src/soc/wdt.h @@ -12,7 +12,7 @@ int wdt_prevent_reset(struct soc *soc); struct wdt; int wdt_init(struct wdt *ctx, struct soc *soc, const char *name); -int64_t wdt_perform_reset(struct wdt *ctx); +int wdt_perform_reset(struct wdt *ctx); void wdt_destroy(struct wdt *ctx); struct wdt *wdt_get_by_name(struct soc *soc, const char *name);