mdebug

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
Mfirmware/lpclink2-mdebug.bin | 0
Minclude/protocol/rswdp.h | 6++++++
Mtools/debugger-commands.c | 28+++++++++++++++++++++++++++-
Mtools/debugger.c | 4++++
Mtools/debugger.h | 2++
Mtools/rswdp.c | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mtools/rswdp.h | 2++
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);