commit 437a6da3a57cc05d3964a0f1571e22d74424f56a
parent 050b143acadd580ca8491c5cc14e0813dbfe0e4c
Author: Brian Swetland <swetland@frotz.net>
Date: Tue, 28 Feb 2023 15:04:38 -0800
transport: complete swd attach sequence
This now handles SWJ-DPs in JTAG mode, DPv2s in Dormant State,
and supports DPv2 MultiDrop Target Selection.
Tested against SAMD21(CM0+), NRF52840(CM4), EFR32BG22(CM33),
RP2040(2xCM0+ Multidrop), LPC4370(2xCM4+CM0), and STM32F103(CM3)
Diffstat:
3 files changed, 91 insertions(+), 24 deletions(-)
diff --git a/src/transport.c b/src/transport.c
@@ -319,20 +319,62 @@ int dc_ap_wr(DC* dc, unsigned apaddr, uint32_t val) {
return dc_q_exec(dc);
}
-int dc_attach(DC* dc) {
- uint8_t io[23] = { DAP_SWD_Sequence, 3,
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 64 1s
- 0x10, 0x9E, 0xE7, // JTAG to SWD magic sequence
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, // 60 1s, 4 0s
- };
- if (dap_cmd(dc, io, 23, io, 2) < 0) {
- return -1;
- }
- if (io[1] != 0) {
- ERROR("dc_attach() failure 0x%02x\n", io[1]);
- return -1;
- }
- return 0;
+// SWD Attach Sequence:
+// 1. Send >50 1s and then the JTAG to SWD escape code
+// (in case this is a JTAG-SWD DAP in JTAG mode)
+// 2. Send >8 1s and then the Selection Alert Sequence
+// and then the SWD Activation Code
+// (in case this is a SWD v2 DAP in Dormant State)
+// 3. Send >50 1s and then 4 0s -- the Line Reset Sequence
+// 4. If multidrop, issue a write to DP.TARGETSEL, but
+// ignore the ACK response
+// 5. Issue a read from DP.IDR
+
+static uint8_t attach_cmd[54] = {
+ DAP_SWD_Sequence, 5,
+
+ // [--- 64 1s ----------------------------------]
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ // [JTAG2SWD] [- 16 1s ] [---------------------
+ 0x00, 0x9E, 0xE7, 0xFF, 0xFF, 0x92, 0xF3, 0x09, 0x62,
+ // ----- Selection Alert Sequence ---------------
+ 0x00, 0x95, 0x2D, 0x85, 0x86, 0xE9, 0xAF, 0xDD, 0xE3,
+ // ---------------------] [Act Code] [---------
+ 0x00, 0xA2, 0x0E, 0xBC, 0x19, 0xA0, 0xF1, 0xFF, 0xFF,
+ // ----- Line Reset Sequence -------]
+ 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F,
+
+ // WR DP TARGETSEL
+ 0x08, 0x99,
+ // 5 bits idle
+ 0x85,
+ // WR VALUE:32, PARTY:1, ZEROs:7
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+int dc_attach(DC* dc, unsigned flags, uint32_t tgt, uint32_t* idcode) {
+ uint8_t rsp[3];
+
+ if (flags & DC_MULTIDROP) {
+ // Copy and patch the attach sequence to include
+ // the DP.TARGETSEL write and insert the target
+ // id and parity
+ uint8_t cmd[54];
+ memcpy(cmd, attach_cmd, 54);
+ cmd[1] = 8;
+ memcpy(cmd + 49, &tgt, sizeof(tgt));
+ cmd[53] = __builtin_parity(tgt);
+ dap_cmd(dc, cmd, 54, rsp, 3);
+ } else {
+ // use the common part of the attach sequence, as-is
+ dap_cmd(dc, attach_cmd, 45, rsp, 2);
+ }
+
+ // Issue a bare DP.IDR read, as required after a line reset
+ // or line reset + target select
+ dc_q_init(dc);
+ dc_q_raw_rd(dc, XFER_DP | XFER_RD | XFER_00, idcode);
+ return dc_q_exec(dc);
}
static usb_handle* usb_connect(void) {
diff --git a/src/transport.h b/src/transport.h
@@ -33,5 +33,6 @@ int dc_ap_wr(dctx_t* dc, unsigned apaddr, uint32_t val);
int dc_create(dctx_t** dc);
// attempt to attach to the debug target
-int dc_attach(dctx_t* dc);
+int dc_attach(dctx_t* dc, unsigned flags, uint32_t tgt, uint32_t* idcode);
+#define DC_MULTIDROP 1
diff --git a/src/xdebug.c b/src/xdebug.c
@@ -11,26 +11,50 @@
#include "transport.h"
int main(int argc, char **argv) {
- uint32_t n;
+ uint32_t n = 0;
dctx_t* dc;
if (dc_create(&dc) < 0) {
return -1;
}
- dc_attach(dc);
-
- n = 0;
- dc_dp_rd(dc, DP_DPIDR, &n);
+ dc_attach(dc, 0, 0, &n);
printf("IDCODE %08x\n", n);
- dc_dp_rd(dc, DP_CS, &n);
- printf("CTRL/STAT %08x\n", n);
+ // If this is a RP2040, we need to connect in multidrop
+ // mode before doing anything else.
+ if (n == 0x0bc12477) {
+ dc_dp_rd(dc, DP_TARGETID, &n);
+ if (n == 0x01002927) { // RP2040
+ dc_attach(dc, DC_MULTIDROP, 0x01002927, &n);
+ }
+ }
+ // power up system & debug
+ dc_dp_rd(dc, DP_CS, &n);
+ printf("CTRL/STAT %08x\n", n);
dc_dp_wr(dc, DP_CS, DP_CS_CDBGPWRUPREQ | DP_CS_CSYSPWRUPREQ);
-
dc_dp_rd(dc, DP_CS, &n);
- printf("CTRL/STAT %08x\n", n);
+ printf("CTRL/STAT %08x\n", n);
+
+ // dump some info
+ dc_dp_rd(dc, DP_DPIDR, &n);
+ printf("DP.DPIDR %08x\n", n);
+ dc_dp_rd(dc, DP_TARGETID, &n);
+ printf("DP.TARGETID %08x\n", n);
+ dc_dp_rd(dc, DP_DLPIDR, &n);
+ printf("DP.DLPIDR %08x\n", n);
+ dc_ap_rd(dc, MAP_IDR, &n);
+ printf("MAP.IDR %08x\n", n);
+ dc_ap_rd(dc, MAP_CSW, &n);
+ printf("MAP.CSW %08x\n", n);
+ dc_ap_rd(dc, MAP_CFG, &n);
+ printf("MAP.CFG %08x\n", n);
+ dc_ap_rd(dc, MAP_CFG1, &n);
+ printf("MAP.CFG1 %08x\n", n);
+ dc_ap_rd(dc, MAP_BASE, &n);
+ printf("MAP.BASE %08x\n", n);
+
return 0;
}