blob: 7daa8b713e2f4fc5d2b6d11f947ef2cdc5800981 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/* rswd.c
2 *
3 * Copyright 2011-2015 Brian Swetland <swetland@frotz.net>
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <reg.h>
19#include <debug.h>
20#include <string.h>
21#include <stdlib.h>
22#include <printf.h>
23
24#include <platform.h>
25
26#include "swd.h"
27#include "rswdp.h"
28
29void usb_xmit(void *data, unsigned len);
30int usb_recv(void *data, unsigned len);
31
32unsigned swdp_trace = 0;
33
34// indicates host knows about v1.0 protocol features
35unsigned host_version = 0;
36
37static u8 optable[16] = {
38 [OP_RD | OP_DP | OP_X0] = RD_IDCODE,
39 [OP_RD | OP_DP | OP_X4] = RD_DPCTRL,
40 [OP_RD | OP_DP | OP_X8] = RD_RESEND,
41 [OP_RD | OP_DP | OP_XC] = RD_BUFFER,
42 [OP_WR | OP_DP | OP_X0] = WR_ABORT,
43 [OP_WR | OP_DP | OP_X4] = WR_DPCTRL,
44 [OP_WR | OP_DP | OP_X8] = WR_SELECT,
45 [OP_WR | OP_DP | OP_XC] = WR_BUFFER,
46 [OP_RD | OP_AP | OP_X0] = RD_AP0,
47 [OP_RD | OP_AP | OP_X4] = RD_AP1,
48 [OP_RD | OP_AP | OP_X8] = RD_AP2,
49 [OP_RD | OP_AP | OP_XC] = RD_AP3,
50 [OP_WR | OP_AP | OP_X0] = WR_AP0,
51 [OP_WR | OP_AP | OP_X4] = WR_AP1,
52 [OP_WR | OP_AP | OP_X8] = WR_AP2,
53 [OP_WR | OP_AP | OP_XC] = WR_AP3,
54};
55
56static const char *board_str = TARGET;
57static const char *build_str = "fw v0.91 (" __DATE__ ", " __TIME__ ")";
58
59static void _reboot(void) {
60 platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET);
61}
62
63#define MODE_SWD 0
64#define MODE_JTAG 1
65static unsigned mode = MODE_SWD;
66
67/* TODO bounds checking -- we trust the host far too much */
68void process_txn(u32 txnid, u32 *rx, int rxc, u32 *tx) {
69 unsigned msg, op, n;
70 unsigned txc = 1;
71 unsigned count = 0;
72 unsigned status = 0;
73 void (*func)(void) = 0;
74
75 tx[0] = txnid;
76
77 while (rxc-- > 0) {
78 count++;
79 msg = *rx++;
80 op = RSWD_MSG_OP(msg);
81 n = RSWD_MSG_ARG(msg);
82#if CONFIG_MDEBUG_TRACE
83 printf("> %02x %02x %04x <\n", RSWD_MSG_CMD(msg), op, n);
84#endif
85 switch (RSWD_MSG_CMD(msg)) {
86 case CMD_NULL:
87 continue;
88 case CMD_SWD_WRITE:
89 while (n-- > 0) {
90 rxc--;
91 status = swd_write(optable[op], *rx++);
92 if (status) {
93 goto done;
94 }
95 }
96 continue;
97 case CMD_SWD_READ:
98 tx[txc++] = RSWD_MSG(CMD_SWD_DATA, 0, n);
99 while (n-- > 0) {
100 status = swd_read(optable[op], tx + txc);
101 if (status) {
102 txc++;
103 while (n-- > 0)
104 tx[txc++] = 0xfefefefe;
105 goto done;
106 }
107 txc++;
108 }
109 continue;
110 case CMD_SWD_DISCARD:
111 while (n-- > 0) {
112 u32 tmp;
113 status = swd_read(optable[op], &tmp);
114 if (status) {
115 goto done;
116 }
117 }
118 continue;
119 case CMD_ATTACH:
120 if (mode != MODE_SWD) {
121 mode = MODE_SWD;
122 swd_init();
123 }
124 swd_reset();
125 continue;
126 case CMD_JTAG_IO:
127 if (mode != MODE_JTAG) {
128 mode = MODE_JTAG;
129 jtag_init();
130 }
131 tx[txc++] = RSWD_MSG(CMD_JTAG_DATA, 0, n);
132 while (n > 0) {
133 unsigned xfer = (n > 32) ? 32 : n;
134 jtag_io(xfer, rx[0], rx[1], tx + txc);
135 rx += 2;
136 rxc -= 2;
137 txc += 1;
138 n -= xfer;
139 }
140 continue;
141 case CMD_JTAG_VRFY:
142 if (mode != MODE_JTAG) {
143 mode = MODE_JTAG;
144 jtag_init();
145 }
146 // (n/32) x 4 words: TMS, TDI, DATA, MASK
147 while (n > 0) {
148 unsigned xfer = (n > 32) ? 32 : n;
149 jtag_io(xfer, rx[0], rx[1], tx + txc);
150 if ((tx[txc] & rx[3]) != rx[2]) {
151 status = ERR_BAD_MATCH;
152 goto done;
153 }
154 rx += 4;
155 rxc -= 4;
156 n -= xfer;
157 }
158 continue;
159 case CMD_JTAG_TX: {
160 unsigned tms = (op & 1) ? 0xFFFFFFFF : 0;
161 if (mode != MODE_JTAG) {
162 mode = MODE_JTAG;
163 jtag_init();
164 }
165 while (n > 0) {
166 unsigned xfer = (n > 32) ? 32 : n;
167 jtag_io(xfer, tms, rx[0], rx);
168 rx++;
169 rxc--;
170 n -= xfer;
171 }
172 continue;
173 }
174 case CMD_JTAG_RX: {
175 unsigned tms = (op & 1) ? 0xFFFFFFFF : 0;
176 unsigned tdi = (op & 2) ? 0xFFFFFFFF : 0;
177 if (mode != MODE_JTAG) {
178 mode = MODE_JTAG;
179 jtag_init();
180 }
181 tx[txc++] = RSWD_MSG(CMD_JTAG_DATA, 0, n);
182 while (n > 0) {
183 unsigned xfer = (n > 32) ? 32 : n;
184 jtag_io(xfer, tms, tdi, tx + txc);
185 txc++;
186 n -= xfer;
187 }
188 continue;
189 }
190 case CMD_RESET:
191 swd_hw_reset(n);
192 continue;
193 case CMD_DOWNLOAD: {
194 //u32 *addr = (void*) *rx++;
195 rxc--;
196 while (n) {
197 //*addr++ = *rx++;
198 rx++;
199 rxc--;
200 }
201 continue;
202 }
203 case CMD_EXECUTE:
204 //func = (void*) *rx++;
205 rxc--;
206 continue;
207 case CMD_TRACE:
208 swdp_trace = op;
209 continue;
210 case CMD_BOOTLOADER:
211 func = _reboot;
212 continue;
213 case CMD_SET_CLOCK:
214 n = swd_set_clock(n);
215 printf("swdp clock is now %d KHz\n", n);
216 if (host_version >= RSWD_VERSION_1_0) {
217 tx[txc++] = RSWD_MSG(CMD_CLOCK_KHZ, 0, n);
218 }
219 continue;
220 case CMD_SWO_CLOCK:
221 n = swo_set_clock(n);
222 printf("swo clock is now %d KHz\n", n);
223 continue;
224 case CMD_VERSION:
225 host_version = n;
226 tx[txc++] = RSWD_MSG(CMD_VERSION, 0, RSWD_VERSION);
227
228 n = strlen(board_str);
229 memcpy(tx + txc + 1, board_str, n + 1);
230 n = (n + 4) / 4;
231 tx[txc++] = RSWD_MSG(CMD_BOARD_STR, 0, n);
232 txc += n;
233
234 n = strlen(build_str);
235 memcpy(tx + txc + 1, build_str, n + 1);
236 n = (n + 4) / 4;
237 tx[txc++] = RSWD_MSG(CMD_BUILD_STR, 0, n);
238 txc += n;
239
240 tx[txc++] = RSWD_MSG(CMD_RX_MAXDATA, 0, 8192);
241 txc += n;
242 continue;
243 default:
244 printf("unknown command %02x\n", RSWD_MSG_CMD(msg));
245 status = 1;
246 goto done;
247 }
248 }
249
250done:
251 tx[txc++] = RSWD_MSG(CMD_STATUS, status, count);
252
253 /* if we're about to send an even multiple of the packet size
254 * (64), add a NULL op on the end to create a short packet at
255 * the end.
256 */
257 if ((txc & 0xf) == 0)
258 tx[txc++] = RSWD_MSG(CMD_NULL, 0, 0);
259
260#if CONFIG_MDEBUG_TRACE
261 printf("[ send %d words ]\n", txc);
262 for (n = 0; n < txc; n+=4) {
263 printx("%08x %08x %08x %08x\n",
264 tx[n], tx[n+1], tx[n+2], tx[n+3]);
265 }
266#endif
267 usb_xmit(tx, txc * 4);
268
269 if (func) {
270 for (n = 0; n < 1000000; n++) asm("nop");
271 func();
272 for (;;) ;
273 }
274}
275
276// io buffers in AHB SRAM
277static u32 *rxbuffer = (void*) 0x20001000;
278static u32 *txbuffer[2] = {(void*) 0x20003000, (void*) 0x20005000 };
279
280#include <kernel/thread.h>
281
282void handle_rswd(void) {
283 int rxc;
284 int toggle = 0;
285
286#if CONFIG_MDEBUG_TRACE
287 printf("[ rswdp agent v0.9 ]\n");
288 printf("[ built " __DATE__ " " __TIME__ " ]\n");
289#endif
290
291 for (;;) {
292 rxc = usb_recv(rxbuffer, 8192);
293
294#if CONFIG_MDEBUG_TRACE
295 int n;
296 printx("[ recv %d words ]\n", rxc/4);
297 for (n = 0; n < (rxc/4); n+=4) {
298 printx("%08x %08x %08x %08x\n",
299 rxbuffer[n], rxbuffer[n+1],
300 rxbuffer[n+2], rxbuffer[n+3]);
301 }
302#endif
303
304 if ((rxc < 4) || (rxc & 3)) {
305 printf("error, runt frame, or strange frame... %d\n", rxc);
306 continue;
307 }
308
309 rxc = rxc / 4;
310
311 if ((rxbuffer[0] & 0xFFFF0000) != 0xAA770000) {
312 printf("invalid frame %x\n", rxbuffer[0]);
313 continue;
314 }
315
316 process_txn(rxbuffer[0], rxbuffer + 1, rxc - 1, txbuffer[toggle]);
317 toggle ^= 1;
318 }
319}