commit b078c7fe3ea33d4a06ca81d3c2e5db3ae2e98815
parent 45ce633fd004850c01d325609e58d730f0383d3a
Author: Brian Swetland <swetland@frotz.net>
Date: Mon, 1 Feb 2021 17:52:54 -0800
mdebug: initial rpi rp2040/pico support
- new lpclink ii firmware binary
https://github.com/littlekernel/lk
6e3edb87de03ab8f00fa45902ff89a1909e79927
- warn about pre 1.3 firmware (which will no longer work)
- new attach argument for multidrop selection:
swd: plain swd, no multidrop (default)
pico0: multidrop, select rp2040 cpu0
pico1: multidrop, select rp2040 cpu1
picor: multidrop, select rp2040 rescue dp
(resets both CPUs and parks them in ROM)
- new --pico commandline argument to ensure we start in attach pico0
mode and avoid trying to do a single-drop attach which confuses
the rp2040
- some code to dump outbound RSWD packets (disabled)
Diffstat:
7 files changed, 145 insertions(+), 13 deletions(-)
diff --git a/firmware/lpclink2-mdebug.bin b/firmware/lpclink2-mdebug.bin
Binary files differ.
diff --git a/include/protocol/rswdp.h b/include/protocol/rswdp.h
@@ -60,6 +60,12 @@
#define CMD_JTAG_IO 0x0C /* op=0, arg=bitcount, data x (count/32) * 2 */
/* tms, tdi word pairs per 32bits */
+/* ATTACH ops */
+#define ATTACH_SWD_RESET 0
+#define ATTACH_JTAG_TO_SWD 1
+#define ATTACH_DORMANT_TO_SWD 2
+#define ATTACH_SWD_TO_DORMANT 3
+
/* valid: target to host */
#define CMD_STATUS 0x10 /* op=errorcode, arg=commands since last TXN_START */
#define CMD_SWD_DATA 0x11 /* op=0 arg=count, payload: data x count */
diff --git a/tools/debugger-commands.c b/tools/debugger-commands.c
@@ -84,7 +84,20 @@ int do_exit(int argc, param *argv) {
int do_attach(int argc, param *argv) {
if (argc > 0) {
- if (!strcmp(argv[0].s, "swd")) {
+ if (!strcmp(argv[0].s, "pico0")) {
+ swdp_targetsel(0x01002927, 1);
+ ACTIVE_TRANSPORT = &SWDP_TRANSPORT;
+ } else if (!strcmp(argv[0].s, "pico1")) {
+ swdp_targetsel(0x11002927, 1);
+ ACTIVE_TRANSPORT = &SWDP_TRANSPORT;
+ } else if (!strcmp(argv[0].s, "picor")) {
+ swdp_targetsel(0xF1002927, 1);
+ ACTIVE_TRANSPORT = &SWDP_TRANSPORT;
+ } else if (!strcmp(argv[0].s, "swd")) {
+ swdp_targetsel(0, 0);
+ ACTIVE_TRANSPORT = &SWDP_TRANSPORT;
+ } else if (!strcmp(argv[0].s, "swdx")) {
+ swdp_targetsel(0xffffffff, 1);
ACTIVE_TRANSPORT = &SWDP_TRANSPORT;
} else if (!strcmp(argv[0].s, "jtag")) {
ACTIVE_TRANSPORT = &JTAG_TRANSPORT;
@@ -95,6 +108,19 @@ int do_attach(int argc, param *argv) {
return swdp_reset();
}
+int debug_target(const char* name) {
+ if (!strcmp(name,"pico")) {
+ xprintf(XDATA, "target: RPxxxx MCUs\n");
+ xprintf(XDATA, "target: use 'attach pico0', 'attach pico1' to change cores\n");
+ xprintf(XDATA, "target: use 'attach picor' to enter rescue (reset-stop-in-rom)\n");
+ swdp_targetsel(0x01002927, 1);
+ return 0;
+ } else {
+ xprintf(XDATA, "target: unknown target '%s'\n", name);
+ return -1;
+ }
+}
+
static u32 lastregs[19];
int do_regs(int argc, param *argv) {
diff --git a/tools/debugger.c b/tools/debugger.c
@@ -72,6 +72,7 @@ int main(int argc, char **argv) {
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"script", 1, 0, 'f'},
+ {"pico", 0, 0, 'p'},
{0, 0, 0, 0},
};
@@ -86,6 +87,9 @@ int main(int argc, char **argv) {
case 'h':
usage(argc, argv);
break;
+ case 'p':
+ debug_target("pico");
+ break;
default:
usage(argc, argv);
break;
diff --git a/tools/debugger.h b/tools/debugger.h
@@ -131,5 +131,7 @@ extern debug_transport DUMMY_TRANSPORT;
extern debug_transport SWDP_TRANSPORT;
extern debug_transport JTAG_TRANSPORT;
+int debug_target(const char* name);
+
#endif
diff --git a/tools/rswdp.c b/tools/rswdp.c
@@ -171,6 +171,9 @@ done:
xprintf(XSWD, "usb: protocol: %d.%d\n", version >> 8, version & 0xff);
xprintf(XSWD, "usb: max data: %d byte rx buffer\n", maxdata);
+ if (version < 0x0103) {
+ xprintf(XSWD, "usb: WARNING, FIRMWARE OUT OF DATE\n");
+ }
swd_version = version;
swd_maxwords = maxdata / 4;
}
@@ -237,7 +240,7 @@ static int process_reply(struct txn *t, u32 *data, int count) {
return 0;
}
case CMD_CLOCK_KHZ:
- xprintf(XSWD,"mdebug: SWD clock: %d KHz\n", n);
+ xprintf(XSWD,"mdebug: %s clock: %d KHz\n", op ? "SWO" : "SWD", n);
continue;
default:
xprintf(XSWD,"unknown command 0x%02x\n", RSWD_MSG_CMD(msg));
@@ -247,6 +250,61 @@ static int process_reply(struct txn *t, u32 *data, int count) {
return 0;
}
+#define TRACE_RSWD_XMIT 0
+#if TRACE_RSWD_XMIT
+static const char* opstr(unsigned op) {
+ switch (op) {
+ case OP_RD|OP_DP|OP_X0: return "RD DP x0 (DPIDR)";
+ case OP_RD|OP_DP|OP_X4: return "RD DP x4 (DPCTRL)";
+ case OP_RD|OP_DP|OP_X8: return "RD DP x8 (RESEND)";
+ case OP_RD|OP_DP|OP_XC: return "RD DP xC";
+ case OP_WR|OP_DP|OP_X0: return "WR DP x0 (ABORT)";
+ case OP_WR|OP_DP|OP_X4: return "WR DP x4 (DPCTRL)";
+ case OP_WR|OP_DP|OP_X8: return "WR DP x8 (SELECT)";
+ case OP_WR|OP_DP|OP_XC: return "WR DP xC (TARGETSEL)";
+ case OP_RD|OP_AP|OP_X0: return "RD AP x0";
+ case OP_RD|OP_AP|OP_X4: return "RD AP x4";
+ case OP_RD|OP_AP|OP_X8: return "RD AP x8";
+ case OP_RD|OP_AP|OP_XC: return "RD AP xC";
+ case OP_WR|OP_AP|OP_X0: return "WR AP x0";
+ case OP_WR|OP_AP|OP_X4: return "WR AP x4";
+ case OP_WR|OP_AP|OP_X8: return "WR AP x8";
+ case OP_WR|OP_AP|OP_XC: return "WR AP xC";
+ default: return "???";
+ }
+}
+
+static void q_dump(u32* tx, unsigned count) {
+ while (count-- > 0) {
+ unsigned cmd = RSWD_MSG_CMD(*tx);
+ unsigned op = RSWD_MSG_OP(*tx);
+ unsigned arg = RSWD_MSG_ARG(*tx);
+ switch (cmd) {
+ case CMD_SWD_WRITE:
+ xprintf(XSWD, "CMD_SWD_WRITE %s 0x%08x n=%u\n", opstr(op), tx[1], arg);
+ while (arg > 0) { arg--; tx++; count--; }
+ break;
+ case CMD_SWD_READ:
+ xprintf(XSWD, "CMD_SWD_READ %s n=%u\n", opstr(op), arg);
+ break;
+ case CMD_SWD_DISCARD:
+ xprintf(XSWD, "CMD_SWD_DISCARD %s n=%u\n", opstr(op), arg);
+ break;
+ case CMD_ATTACH:
+ xprintf(XSWD, "CMD_ATTACH\n");
+ break;
+ case CMD_RESET:
+ xprintf(XSWD, "CMD_RESET n=%u\n", arg);
+ break;
+ default:
+ xprintf(XSWD, "CMD_%02x\n", cmd);
+ }
+ tx++;
+ }
+ xprintf(XSWD, "---\n");
+}
+#endif
+
static int q_exec(struct txn *t) {
unsigned data[MAXWORDS];
unsigned seq;
@@ -265,6 +323,10 @@ static int q_exec(struct txn *t) {
if (((t->txc % 16) == 0) && (t->txc != swd_maxwords))
t->tx[t->txc++] = RSWD_MSG(CMD_NULL, 0, 0);
+#if TRACE_RSWD_XMIT
+ q_dump(t->tx + 1, t->txc - 1);
+#endif
+
pthread_mutex_lock(&swd_lock);
seq = sequence++;
id = RSWD_TXN_START(seq);
@@ -755,41 +817,71 @@ int swdp_bootloader(void) {
return q_exec(&t);
}
+static uint32_t targetsel_val = 0;
+static unsigned targetsel_on = 0;
+
+void swdp_targetsel(uint32_t val, unsigned on) {
+ targetsel_val = val;
+ targetsel_on = on;
+}
+
static int _swdp_reset(void) {
struct txn t;
u32 n, idcode;
swd_error = 0;
q_init(&t);
- t.tx[t.txc++] = RSWD_MSG(CMD_ATTACH, 0, 0);
+ t.tx[t.txc++] = RSWD_MSG(CMD_ATTACH, ATTACH_JTAG_TO_SWD, 0);
+ t.tx[t.txc++] = RSWD_MSG(CMD_ATTACH, ATTACH_DORMANT_TO_SWD, 0);
+ t.tx[t.txc++] = RSWD_MSG(CMD_ATTACH, ATTACH_SWD_RESET, 0);
+
+ if (targetsel_on) {
+ t.tx[t.txc++] = SWD_WR(DP_BUFFER, 1);
+ t.tx[t.txc++] = targetsel_val;
+ }
+
t.tx[t.txc++] = SWD_RD(DP_IDCODE, 1);
t.rx[t.rxc++] = &idcode;
if (q_exec(&t)) {
xprintf(XSWD, "attach: IDCODE: ????????\n");
} else {
- xprintf(XSWD, "attach: IDCODE: %08x\n", idcode);
+ xprintf(XSWD, "attach: IDCODE: %08x\n");
}
swd_error = 0;
q_init(&t);
+
/* clear any stale errors */
t.tx[t.txc++] = SWD_WR(DP_ABORT, 1);
t.tx[t.txc++] = 0x1E;
- /* power up */
- t.tx[t.txc++] = SWD_WR(DP_DPCTRL, 1);
- t.tx[t.txc++] = (1 << 28) | (1 << 30);
- t.tx[t.txc++] = SWD_RD(DP_DPCTRL, 1);
- t.rx[t.rxc++] = &n;
+ if (targetsel_on && (targetsel_val == 0xf1002927)) {
+ // for pico recovery dap, only valid action is clear
+ // debug power bits to put the chip in to recovery mode
+ t.tx[t.txc++] = SWD_WR(DP_DPCTRL, 1);
+ t.tx[t.txc++] = 0;
+ t.tx[t.txc++] = SWD_RD(DP_DPCTRL, 1);
+ t.rx[t.rxc++] = &n;
+ } else{
+ /* power up */
+ t.tx[t.txc++] = SWD_WR(DP_DPCTRL, 1);
+ t.tx[t.txc++] = (1 << 28) | (1 << 30);
+ t.tx[t.txc++] = SWD_RD(DP_DPCTRL, 1);
+ t.rx[t.rxc++] = &n;
+
+ /* configure for 32bit IO */
+ q_ap_write(&t, AHB_CSW,
+ AHB_CSW_MDEBUG | AHB_CSW_PRIV |
+ AHB_CSW_PRIV | AHB_CSW_DBG_EN | AHB_CSW_32BIT);
+ }
- /* configure for 32bit IO */
- q_ap_write(&t, AHB_CSW,
- AHB_CSW_MDEBUG | AHB_CSW_PRIV |
- AHB_CSW_PRIV | AHB_CSW_DBG_EN | AHB_CSW_32BIT);
+ //u32 base;
+ //q_ap_read(&t, 0xF8, &base);
if (q_exec(&t))
return -1;
xprintf(XSWD, "attach: DPCTRL: %08x\n", n);
+ //xprintf(XSWD, "attach: BASE: %08x\n", base);
return 0;
}
diff --git a/tools/rswdp.h b/tools/rswdp.h
@@ -55,6 +55,8 @@ int swdp_watchpoint_wr(unsigned n, u32 addr);
int swdp_watchpoint_rw(unsigned n, u32 addr);
int swdp_watchpoint_disable(unsigned n);
+void swdp_targetsel(u32 val, unsigned on);
+
/* these are now provided by the transport layer */
//int swdp_reset(void);
//int swdp_error(void);