adiv6: add low level jtag transport
[openocd.git] / src / jtag / drivers / rshim.c
1 /*
2 * Copyright (c) 2020, Mellanox Technologies Ltd. - All Rights Reserved
3 * Liming Sun <lsun@mellanox.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <helper/types.h>
24 #include <helper/system.h>
25 #include <helper/time_support.h>
26 #include <helper/list.h>
27 #include <jtag/interface.h>
28 #ifdef HAVE_SYS_IOCTL_H
29 #include <sys/ioctl.h>
30 #endif
31 #include <target/arm_adi_v5.h>
32 #include <transport/transport.h>
33
34 /* Rshim channel where the CoreSight register resides. */
35 #define RSH_MMIO_CHANNEL_RSHIM 0x1
36
37 /* APB and tile address translation. */
38 #define RSH_CS_ROM_BASE 0x80000000
39 #define RSH_CS_TILE_BASE 0x44000000
40 #define RSH_CS_TILE_SIZE 0x04000000
41
42 /*
43 * APB-AP Identification Register
44 * The default value is defined in "CoreSight on-chip trace and debug
45 * (Revision: r1p0)", Section 3.16.5 APB-AP register summary.
46 */
47 #define APB_AP_IDR 0x44770002
48
49 /* CoreSight register definition. */
50 #define RSH_CORESIGHT_CTL 0x0e00
51 #define RSH_CORESIGHT_CTL_GO_SHIFT 0
52 #define RSH_CORESIGHT_CTL_GO_MASK 0x1ULL
53 #define RSH_CORESIGHT_CTL_ACTION_SHIFT 1
54 #define RSH_CORESIGHT_CTL_ACTION_MASK 0x2ULL
55 #define RSH_CORESIGHT_CTL_ADDR_SHIFT 2
56 #define RSH_CORESIGHT_CTL_ADDR_MASK 0x7ffffffcULL
57 #define RSH_CORESIGHT_CTL_ERR_SHIFT 31
58 #define RSH_CORESIGHT_CTL_ERR_MASK 0x80000000ULL
59 #define RSH_CORESIGHT_CTL_DATA_SHIFT 32
60 #define RSH_CORESIGHT_CTL_DATA_MASK 0xffffffff00000000ULL
61
62 /* Util macros to access the CoreSight register. */
63 #define RSH_CS_GET_FIELD(reg, field) \
64 (((uint64_t)(reg) & RSH_CORESIGHT_CTL_##field##_MASK) >> \
65 RSH_CORESIGHT_CTL_##field##_SHIFT)
66
67 #define RSH_CS_SET_FIELD(reg, field, value) \
68 (reg) = (((reg) & ~RSH_CORESIGHT_CTL_##field##_MASK) | \
69 (((uint64_t)(value) << RSH_CORESIGHT_CTL_##field##_SHIFT) & \
70 RSH_CORESIGHT_CTL_##field##_MASK))
71
72 #ifdef HAVE_SYS_IOCTL_H
73 /* Message used to program rshim via ioctl(). */
74 typedef struct {
75 uint32_t addr;
76 uint64_t data;
77 } __attribute__((packed)) rshim_ioctl_msg;
78
79 enum {
80 RSH_IOC_READ = _IOWR('R', 0, rshim_ioctl_msg),
81 RSH_IOC_WRITE = _IOWR('R', 1, rshim_ioctl_msg),
82 };
83 #endif
84
85 /* Use local variable stub for DP/AP registers. */
86 static uint32_t dp_ctrl_stat;
87 static uint32_t dp_id_code;
88 static uint32_t ap_sel, ap_bank;
89 static uint32_t ap_csw;
90 static uint32_t ap_drw;
91 static uint32_t ap_tar, ap_tar_inc;
92
93 /* Static functions to read/write via rshim/coresight. */
94 static int (*rshim_read)(int chan, int addr, uint64_t *value);
95 static int (*rshim_write)(int chan, int addr, uint64_t value);
96 static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata);
97 static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value);
98
99 /* RShim file handler. */
100 static int rshim_fd = -1;
101
102 /* DAP error code. */
103 static int rshim_dap_retval = ERROR_OK;
104
105 /* Default rshim device. */
106 #define RSHIM_DEV_PATH_DEFAULT "/dev/rshim0/rshim"
107 static char *rshim_dev_path;
108
109 static int rshim_dev_read(int chan, int addr, uint64_t *value)
110 {
111 int rc;
112
113 addr = (addr & 0xFFFF) | (1 << 16);
114 rc = pread(rshim_fd, value, sizeof(*value), addr);
115
116 #ifdef HAVE_SYS_IOCTL_H
117 if (rc < 0 && errno == ENOSYS) {
118 rshim_ioctl_msg msg;
119
120 msg.addr = addr;
121 msg.data = 0;
122 rc = ioctl(rshim_fd, RSH_IOC_READ, &msg);
123 if (!rc)
124 *value = msg.data;
125 }
126 #endif
127
128 return rc;
129 }
130
131 static int rshim_dev_write(int chan, int addr, uint64_t value)
132 {
133 int rc;
134
135 addr = (addr & 0xFFFF) | (1 << 16);
136 rc = pwrite(rshim_fd, &value, sizeof(value), addr);
137
138 #ifdef HAVE_SYS_IOCTL_H
139 if (rc < 0 && errno == ENOSYS) {
140 rshim_ioctl_msg msg;
141
142 msg.addr = addr;
143 msg.data = value;
144 rc = ioctl(rshim_fd, RSH_IOC_WRITE, &msg);
145 }
146 #endif
147
148 return rc;
149 }
150
151 /* Convert AP address to tile local address. */
152 static void ap_addr_2_tile(int *tile, uint32_t *addr)
153 {
154 *addr -= RSH_CS_ROM_BASE;
155
156 if (*addr < RSH_CS_TILE_BASE) {
157 *tile = 0;
158 } else {
159 *addr -= RSH_CS_TILE_BASE;
160 *tile = *addr / RSH_CS_TILE_SIZE + 1;
161 *addr = *addr % RSH_CS_TILE_SIZE;
162 }
163 }
164
165 /*
166 * Write 4 bytes on the APB bus.
167 * tile = 0: access the root CS_ROM table
168 * > 0: access the ROM table of cluster (tile - 1)
169 */
170 static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata)
171 {
172 uint64_t ctl = 0;
173 int rc;
174
175 if (!rshim_read || !rshim_write)
176 return ERROR_FAIL;
177
178 /*
179 * ADDR[28] - must be set to 1 due to coresight ip.
180 * ADDR[27:24] - linear tile id
181 */
182 addr = (addr >> 2) | (tile << 24);
183 if (tile)
184 addr |= (1 << 28);
185 RSH_CS_SET_FIELD(ctl, ADDR, addr);
186 RSH_CS_SET_FIELD(ctl, ACTION, 0); /* write */
187 RSH_CS_SET_FIELD(ctl, DATA, wdata);
188 RSH_CS_SET_FIELD(ctl, GO, 1); /* start */
189
190 rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl);
191
192 do {
193 rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM,
194 RSH_CORESIGHT_CTL, &ctl);
195 if (rc < 0) {
196 LOG_ERROR("Failed to read rshim.\n");
197 return rc;
198 }
199 } while (RSH_CS_GET_FIELD(ctl, GO));
200
201 return ERROR_OK;
202 }
203
204 static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value)
205 {
206 uint64_t ctl = 0;
207 int rc;
208
209 if (!rshim_read || !rshim_write)
210 return ERROR_FAIL;
211
212 /*
213 * ADDR[28] - must be set to 1 due to coresight ip.
214 * ADDR[27:24] - linear tile id
215 */
216 addr = (addr >> 2) | (tile << 24);
217 if (tile)
218 addr |= (1 << 28);
219 RSH_CS_SET_FIELD(ctl, ADDR, addr);
220 RSH_CS_SET_FIELD(ctl, ACTION, 1); /* read */
221 RSH_CS_SET_FIELD(ctl, GO, 1); /* start */
222
223 rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl);
224
225 do {
226 rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM,
227 RSH_CORESIGHT_CTL, &ctl);
228 if (rc < 0) {
229 LOG_ERROR("Failed to write rshim.\n");
230 return rc;
231 }
232 } while (RSH_CS_GET_FIELD(ctl, GO));
233
234 *value = RSH_CS_GET_FIELD(ctl, DATA);
235 return ERROR_OK;
236 }
237
238 static int rshim_dp_q_read(struct adiv5_dap *dap, unsigned int reg,
239 uint32_t *data)
240 {
241 if (!data)
242 return ERROR_OK;
243
244 switch (reg) {
245 case DP_DPIDR:
246 *data = dp_id_code;
247 break;
248
249 case DP_CTRL_STAT:
250 *data = CDBGPWRUPACK | CSYSPWRUPACK;
251 break;
252
253 default:
254 break;
255 }
256
257 return ERROR_OK;
258 }
259
260 static int rshim_dp_q_write(struct adiv5_dap *dap, unsigned int reg,
261 uint32_t data)
262 {
263 switch (reg) {
264 case DP_CTRL_STAT:
265 dp_ctrl_stat = data;
266 break;
267 case DP_SELECT:
268 ap_sel = (data & DP_SELECT_APSEL) >> 24;
269 ap_bank = (data & DP_SELECT_APBANK) >> 4;
270 break;
271 default:
272 LOG_INFO("Unknown command");
273 break;
274 }
275
276 return ERROR_OK;
277 }
278
279 static int rshim_ap_q_read(struct adiv5_ap *ap, unsigned int reg,
280 uint32_t *data)
281 {
282 uint32_t addr;
283 int rc = ERROR_OK, tile;
284
285 if (is_adiv6(ap->dap)) {
286 static bool error_flagged;
287 if (!error_flagged)
288 LOG_ERROR("ADIv6 dap not supported by rshim dap-direct mode");
289 error_flagged = true;
290 return ERROR_FAIL;
291 }
292
293 switch (reg) {
294 case ADIV5_MEM_AP_REG_CSW:
295 *data = ap_csw;
296 break;
297
298 case ADIV5_MEM_AP_REG_CFG:
299 *data = 0;
300 break;
301
302 case ADIV5_MEM_AP_REG_BASE:
303 *data = RSH_CS_ROM_BASE;
304 break;
305
306 case ADIV5_AP_REG_IDR:
307 if (ap->ap_num == 0)
308 *data = APB_AP_IDR;
309 else
310 *data = 0;
311 break;
312
313 case ADIV5_MEM_AP_REG_BD0:
314 case ADIV5_MEM_AP_REG_BD1:
315 case ADIV5_MEM_AP_REG_BD2:
316 case ADIV5_MEM_AP_REG_BD3:
317 addr = (ap_tar & ~0xf) + (reg & 0x0C);
318 ap_addr_2_tile(&tile, &addr);
319 rc = coresight_read(tile, addr, data);
320 break;
321
322 case ADIV5_MEM_AP_REG_DRW:
323 addr = (ap_tar & ~0x3) + ap_tar_inc;
324 ap_addr_2_tile(&tile, &addr);
325 rc = coresight_read(tile, addr, data);
326 if (!rc && (ap_csw & CSW_ADDRINC_MASK))
327 ap_tar_inc += (ap_csw & 0x03) * 2;
328 break;
329
330 default:
331 LOG_INFO("Unknown command");
332 rc = ERROR_FAIL;
333 break;
334 }
335
336 /* Track the last error code. */
337 if (rc != ERROR_OK)
338 rshim_dap_retval = rc;
339
340 return rc;
341 }
342
343 static int rshim_ap_q_write(struct adiv5_ap *ap, unsigned int reg,
344 uint32_t data)
345 {
346 int rc = ERROR_OK, tile;
347 uint32_t addr;
348
349 if (is_adiv6(ap->dap)) {
350 static bool error_flagged;
351 if (!error_flagged)
352 LOG_ERROR("ADIv6 dap not supported by rshim dap-direct mode");
353 error_flagged = true;
354 return ERROR_FAIL;
355 }
356
357 if (ap_bank != 0) {
358 rshim_dap_retval = ERROR_FAIL;
359 return ERROR_FAIL;
360 }
361
362 switch (reg) {
363 case ADIV5_MEM_AP_REG_CSW:
364 ap_csw = data;
365 break;
366
367 case ADIV5_MEM_AP_REG_TAR:
368 ap_tar = data;
369 ap_tar_inc = 0;
370 break;
371
372 case ADIV5_MEM_AP_REG_BD0:
373 case ADIV5_MEM_AP_REG_BD1:
374 case ADIV5_MEM_AP_REG_BD2:
375 case ADIV5_MEM_AP_REG_BD3:
376 addr = (ap_tar & ~0xf) + (reg & 0x0C);
377 ap_addr_2_tile(&tile, &addr);
378 rc = coresight_write(tile, addr, data);
379 break;
380
381 case ADIV5_MEM_AP_REG_DRW:
382 ap_drw = data;
383 addr = (ap_tar & ~0x3) + ap_tar_inc;
384 ap_addr_2_tile(&tile, &addr);
385 rc = coresight_write(tile, addr, data);
386 if (!rc && (ap_csw & CSW_ADDRINC_MASK))
387 ap_tar_inc += (ap_csw & 0x03) * 2;
388 break;
389
390 default:
391 rc = EINVAL;
392 break;
393 }
394
395 /* Track the last error code. */
396 if (rc != ERROR_OK)
397 rshim_dap_retval = rc;
398
399 return rc;
400 }
401
402 static int rshim_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
403 {
404 return ERROR_OK;
405 }
406
407 static int rshim_dp_run(struct adiv5_dap *dap)
408 {
409 int retval = rshim_dap_retval;
410
411 /* Clear the error code. */
412 rshim_dap_retval = ERROR_OK;
413
414 return retval;
415 }
416
417 static int rshim_connect(struct adiv5_dap *dap)
418 {
419 char *path = rshim_dev_path ? rshim_dev_path : RSHIM_DEV_PATH_DEFAULT;
420
421 rshim_fd = open(path, O_RDWR | O_SYNC);
422 if (rshim_fd == -1) {
423 LOG_ERROR("Unable to open %s\n", path);
424 return ERROR_FAIL;
425 }
426
427 /*
428 * Set read/write operation via the device file. Function pointers
429 * are used here so more ways like remote accessing via socket could
430 * be added later.
431 */
432 rshim_read = rshim_dev_read;
433 rshim_write = rshim_dev_write;
434
435 return ERROR_OK;
436 }
437
438 static void rshim_disconnect(struct adiv5_dap *dap)
439 {
440 if (rshim_fd != -1) {
441 close(rshim_fd);
442 rshim_fd = -1;
443 }
444 }
445
446 COMMAND_HANDLER(rshim_dap_device_command)
447 {
448 if (CMD_ARGC != 1) {
449 command_print(CMD, "Too many arguments");
450 return ERROR_COMMAND_SYNTAX_ERROR;
451 }
452
453 free(rshim_dev_path);
454 rshim_dev_path = strdup(CMD_ARGV[0]);
455 return ERROR_OK;
456 }
457
458 static const struct command_registration rshim_dap_subcommand_handlers[] = {
459 {
460 .name = "device",
461 .handler = rshim_dap_device_command,
462 .mode = COMMAND_CONFIG,
463 .help = "set the rshim device",
464 .usage = "</dev/rshim<N>/rshim>",
465 },
466 COMMAND_REGISTRATION_DONE
467 };
468
469 static const struct command_registration rshim_dap_command_handlers[] = {
470 {
471 .name = "rshim",
472 .mode = COMMAND_ANY,
473 .help = "perform rshim management",
474 .chain = rshim_dap_subcommand_handlers,
475 .usage = "",
476 },
477 COMMAND_REGISTRATION_DONE
478 };
479
480 static int rshim_dap_init(void)
481 {
482 return ERROR_OK;
483 }
484
485 static int rshim_dap_quit(void)
486 {
487 return ERROR_OK;
488 }
489
490 static int rshim_dap_reset(int req_trst, int req_srst)
491 {
492 return ERROR_OK;
493 }
494
495 static int rshim_dap_speed(int speed)
496 {
497 return ERROR_OK;
498 }
499
500 static int rshim_dap_khz(int khz, int *jtag_speed)
501 {
502 *jtag_speed = khz;
503 return ERROR_OK;
504 }
505
506 static int rshim_dap_speed_div(int speed, int *khz)
507 {
508 *khz = speed;
509 return ERROR_OK;
510 }
511
512 /* DAP operations. */
513 static const struct dap_ops rshim_dap_ops = {
514 .connect = rshim_connect,
515 .queue_dp_read = rshim_dp_q_read,
516 .queue_dp_write = rshim_dp_q_write,
517 .queue_ap_read = rshim_ap_q_read,
518 .queue_ap_write = rshim_ap_q_write,
519 .queue_ap_abort = rshim_ap_q_abort,
520 .run = rshim_dp_run,
521 .quit = rshim_disconnect,
522 };
523
524 static const char *const rshim_dap_transport[] = { "dapdirect_swd", NULL };
525
526 struct adapter_driver rshim_dap_adapter_driver = {
527 .name = "rshim",
528 .transports = rshim_dap_transport,
529 .commands = rshim_dap_command_handlers,
530
531 .init = rshim_dap_init,
532 .quit = rshim_dap_quit,
533 .reset = rshim_dap_reset,
534 .speed = rshim_dap_speed,
535 .khz = rshim_dap_khz,
536 .speed_div = rshim_dap_speed_div,
537
538 .dap_swd_ops = &rshim_dap_ops,
539 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)