From: Tomas Vanek Date: Tue, 20 Sep 2022 16:55:51 +0000 (+0200) Subject: target/adi_v5_swd: fix SWD multidrop X-Git-Url: https://git.gag.com/?p=fw%2Fopenocd;a=commitdiff_plain;h=b2f6b231177240af6693340e4e00d16c1e512692 target/adi_v5_swd: fix SWD multidrop Implementation of ADI v6 introduced banking of DP reg 0. The accompanying change preventing DP SELECT write before DP IDR read during connect was added to swd_connect_single() only. Unchanged swd_connect_multidrop() / swd_multidrop_select_inner() was broken as it emited DP SELECT and put DP to protocol error state. Copy dap->select handling to swd_multidrop_select_inner(). Fixes: 72fb88613f02 (adiv6: add low level swd transport) Change-Id: I514cd6d9ae2ba97ce3657b459df22638c278a0b1 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/7213 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Jonathan Bell --- diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 979c643e9..bd85eb217 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -177,6 +177,19 @@ static int swd_multidrop_select_inner(struct adiv5_dap *dap, uint32_t *dpidr_ptr assert(dap_is_multidrop(dap)); swd_send_sequence(dap, LINE_RESET); + /* From ARM IHI 0074C ADIv6.0, chapter B4.3.3 "Connection and line reset + * sequence": + * - line reset sets DP_SELECT_DPBANK to zero; + * - read of DP_DPIDR takes the connection out of reset; + * - write of DP_TARGETSEL keeps the connection in reset; + * - other accesses return protocol error (SWDIO not driven by target). + * + * Read DP_DPIDR to get out of reset. Initialize dap->select to zero to + * skip the write to DP_SELECT, avoiding the protocol error. Set again + * dap->select to DP_SELECT_INVALID because the rest of the register is + * unknown after line reset. + */ + dap->select = 0; retval = swd_queue_dp_write_inner(dap, DP_TARGETSEL, dap->multidrop_targetsel); if (retval != ERROR_OK) @@ -196,6 +209,8 @@ static int swd_multidrop_select_inner(struct adiv5_dap *dap, uint32_t *dpidr_ptr return retval; } + dap->select = DP_SELECT_INVALID; + retval = swd_queue_dp_read_inner(dap, DP_DLPIDR, &dlpidr); if (retval != ERROR_OK) return retval; @@ -342,6 +357,7 @@ static int swd_connect_single(struct adiv5_dap *dap) dap->switch_through_dormant = !dap->switch_through_dormant; } while (timeval_ms() < timeout); + dap->select = DP_SELECT_INVALID; if (retval != ERROR_OK) {