jtag/drivers: add debugging support for Mellanox BlueField SoC
[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 switch (reg) {
286 case MEM_AP_REG_CSW:
287 *data = ap_csw;
288 break;
289
290 case MEM_AP_REG_CFG:
291 *data = 0;
292 break;
293
294 case MEM_AP_REG_BASE:
295 *data = RSH_CS_ROM_BASE;
296 break;
297
298 case AP_REG_IDR:
299 if (ap->ap_num == 0)
300 *data = APB_AP_IDR;
301 else
302 *data = 0;
303 break;
304
305 case MEM_AP_REG_BD0:
306 case MEM_AP_REG_BD1:
307 case MEM_AP_REG_BD2:
308 case MEM_AP_REG_BD3:
309 addr = (ap_tar & ~0xf) + (reg & 0x0C);
310 ap_addr_2_tile(&tile, &addr);
311 rc = coresight_read(tile, addr, data);
312 break;
313
314 case MEM_AP_REG_DRW:
315 addr = (ap_tar & ~0x3) + ap_tar_inc;
316 ap_addr_2_tile(&tile, &addr);
317 rc = coresight_read(tile, addr, data);
318 if (!rc && (ap_csw & CSW_ADDRINC_MASK))
319 ap_tar_inc += (ap_csw & 0x03) * 2;
320 break;
321
322 default:
323 LOG_INFO("Unknown command");
324 rc = ERROR_FAIL;
325 break;
326 }
327
328 /* Track the last error code. */
329 if (rc != ERROR_OK)
330 rshim_dap_retval = rc;
331
332 return rc;
333 }
334
335 static int rshim_ap_q_write(struct adiv5_ap *ap, unsigned int reg,
336 uint32_t data)
337 {
338 int rc = ERROR_OK, tile;
339 uint32_t addr;
340
341 if (ap_bank != 0) {
342 rshim_dap_retval = ERROR_FAIL;
343 return ERROR_FAIL;
344 }
345
346 switch (reg) {
347 case MEM_AP_REG_CSW:
348 ap_csw = data;
349 break;
350
351 case MEM_AP_REG_TAR:
352 ap_tar = data;
353 ap_tar_inc = 0;
354 break;
355
356 case MEM_AP_REG_BD0:
357 case MEM_AP_REG_BD1:
358 case MEM_AP_REG_BD2:
359 case MEM_AP_REG_BD3:
360 addr = (ap_tar & ~0xf) + (reg & 0x0C);
361 ap_addr_2_tile(&tile, &addr);
362 rc = coresight_write(tile, addr, data);
363 break;
364
365 case MEM_AP_REG_DRW:
366 ap_drw = data;
367 addr = (ap_tar & ~0x3) + ap_tar_inc;
368 ap_addr_2_tile(&tile, &addr);
369 rc = coresight_write(tile, addr, data);
370 if (!rc && (ap_csw & CSW_ADDRINC_MASK))
371 ap_tar_inc += (ap_csw & 0x03) * 2;
372 break;
373
374 default:
375 rc = EINVAL;
376 break;
377 }
378
379 /* Track the last error code. */
380 if (rc != ERROR_OK)
381 rshim_dap_retval = rc;
382
383 return rc;
384 }
385
386 static int rshim_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
387 {
388 return ERROR_OK;
389 }
390
391 static int rshim_dp_run(struct adiv5_dap *dap)
392 {
393 int retval = rshim_dap_retval;
394
395 /* Clear the error code. */
396 rshim_dap_retval = ERROR_OK;
397
398 return retval;
399 }
400
401 static int rshim_connect(struct adiv5_dap *dap)
402 {
403 char *path = rshim_dev_path ? rshim_dev_path : RSHIM_DEV_PATH_DEFAULT;
404
405 rshim_fd = open(path, O_RDWR | O_SYNC);
406 if (rshim_fd == -1) {
407 LOG_ERROR("Unable to open %s\n", path);
408 return ERROR_FAIL;
409 }
410
411 /*
412 * Set read/write operation via the device file. Funtion pointers
413 * are used here so more ways like remote accessing via socket could
414 * be added later.
415 */
416 rshim_read = rshim_dev_read;
417 rshim_write = rshim_dev_write;
418
419 return ERROR_OK;
420 }
421
422 static void rshim_disconnect(struct adiv5_dap *dap)
423 {
424 if (rshim_fd != -1) {
425 close(rshim_fd);
426 rshim_fd = -1;
427 }
428 }
429
430 COMMAND_HANDLER(rshim_dap_device_command)
431 {
432 if (CMD_ARGC != 1) {
433 command_print(CMD, "Too many arguments");
434 return ERROR_COMMAND_SYNTAX_ERROR;
435 }
436
437 free(rshim_dev_path);
438 rshim_dev_path = strdup(CMD_ARGV[0]);
439 return ERROR_OK;
440 }
441
442 static const struct command_registration rshim_dap_subcommand_handlers[] = {
443 {
444 .name = "device",
445 .handler = rshim_dap_device_command,
446 .mode = COMMAND_CONFIG,
447 .help = "set the rshim device",
448 .usage = "</dev/rshim<N>/rshim>",
449 },
450 COMMAND_REGISTRATION_DONE
451 };
452
453 static const struct command_registration rshim_dap_command_handlers[] = {
454 {
455 .name = "rshim",
456 .mode = COMMAND_ANY,
457 .help = "perform rshim management",
458 .chain = rshim_dap_subcommand_handlers,
459 .usage = "",
460 },
461 COMMAND_REGISTRATION_DONE
462 };
463
464 static int rshim_dap_init(void)
465 {
466 return ERROR_OK;
467 }
468
469 static int rshim_dap_quit(void)
470 {
471 return ERROR_OK;
472 }
473
474 static int rshim_dap_reset(int req_trst, int req_srst)
475 {
476 return ERROR_OK;
477 }
478
479 static int rshim_dap_speed(int speed)
480 {
481 return ERROR_OK;
482 }
483
484 static int rshim_dap_khz(int khz, int *jtag_speed)
485 {
486 *jtag_speed = khz;
487 return ERROR_OK;
488 }
489
490 static int rshim_dap_speed_div(int speed, int *khz)
491 {
492 *khz = speed;
493 return ERROR_OK;
494 }
495
496 /* DAP operations. */
497 static const struct dap_ops rshim_dap_ops = {
498 .connect = rshim_connect,
499 .queue_dp_read = rshim_dp_q_read,
500 .queue_dp_write = rshim_dp_q_write,
501 .queue_ap_read = rshim_ap_q_read,
502 .queue_ap_write = rshim_ap_q_write,
503 .queue_ap_abort = rshim_ap_q_abort,
504 .run = rshim_dp_run,
505 .quit = rshim_disconnect,
506 };
507
508 static const char *const rshim_dap_transport[] = { "dapdirect_swd", NULL };
509
510 struct adapter_driver rshim_dap_adapter_driver = {
511 .name = "rshim",
512 .transports = rshim_dap_transport,
513 .commands = rshim_dap_command_handlers,
514
515 .init = rshim_dap_init,
516 .quit = rshim_dap_quit,
517 .reset = rshim_dap_reset,
518 .speed = rshim_dap_speed,
519 .khz = rshim_dap_khz,
520 .speed_div = rshim_dap_speed_div,
521
522 .dap_swd_ops = &rshim_dap_ops,
523 };

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)