From fb750ab14bb050c90f9e182333e57e7526735725 Mon Sep 17 00:00:00 2001 From: Ryan QIAN Date: Mon, 27 Jan 2025 11:38:15 +0800 Subject: [PATCH] target/riscv: make sure target is halted when reset_halt is set - some MCU will need certain period of time to be halted after ndmreset is issued, so in deassert_reset, it needs to make sure MCU is halted before clearing DM_DMCONTROL_HALTREQ. Change-Id: I6d7ef7b9b33aff65cb996968fb28cd62e3e1fb16 Signed-off-by: Ryan QIAN --- src/target/riscv/riscv-013.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 91f8d330a..bbc47d24c 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2924,22 +2924,50 @@ static int deassert_reset(struct target *target) riscv_scan_set_delay(&info->learned_delays, RISCV_DELAY_BASE, orig_base_delay); - /* Ack reset and clear DM_DMCONTROL_HALTREQ if previously set */ + /* Ack reset with DM_DMCONTROL_HALTREQ for those MCUs which need a + * period of time to be halted after reset is released */ control = 0; control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); control = set_field(control, DM_DMCONTROL_ACKHAVERESET, 1); + control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_dmcontrol_hartsel(control, info->index); result = dm_write(target, DM_DMCONTROL, control); if (result != ERROR_OK) return result; if (target->reset_halt) { + /* Wait for all harts to halt for those MCUs mentioned above */ + time_t halt_start = time(NULL); + do { + result = dmstatus_read(target, &dmstatus, true); + if (result != ERROR_OK) + return result; + + if (time(NULL) - halt_start > riscv_get_command_timeout_sec()) { + LOG_TARGET_ERROR(target, "Hart didn't halt after reset in %ds; " + "dmstatus=0x%x (anyhalted=%s, allhalted=%s); " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_get_command_timeout_sec(), dmstatus, + get_field(dmstatus, DM_DMSTATUS_ANYHALTED) ? "true" : "false", + get_field(dmstatus, DM_DMSTATUS_ALLHALTED) ? "true" : "false"); + return ERROR_TIMEOUT_REACHED; + } + } while (!get_field(dmstatus, DM_DMSTATUS_ALLHALTED)); target->state = TARGET_HALTED; target->debug_reason = DBG_REASON_DBGRQ; } else { target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } + + /* clear DM_DMCONTROL_HALTREQ */ + control = 0; + control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); + control = set_dmcontrol_hartsel(control, info->index); + result = dm_write(target, DM_DMCONTROL, control); + if (result != ERROR_OK) + return result; + info->dcsr_ebreak_is_set = dcsr_ebreak_config_equals_reset_value(target); return ERROR_OK; }