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

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)