OpenOCD
rshim.c
Go to the documentation of this file.
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. */
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 {
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 
180 
181  do {
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 
213 
214  do {
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) {
284  *data = ap_csw;
285  break;
286 
288  *data = 0;
289  break;
290 
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 
306  addr = (ap_tar & ~0xf) + (reg & 0x0C);
307  ap_addr_2_tile(&tile, &addr);
308  rc = coresight_read(tile, addr, data);
309  break;
310 
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) {
348  return ERROR_FAIL;
349  }
350 
351  switch (reg) {
353  ap_csw = data;
354  break;
355 
357  ap_tar = data;
358  ap_tar_inc = 0;
359  break;
360 
365  addr = (ap_tar & ~0xf) + (reg & 0x0C);
366  ap_addr_2_tile(&tile, &addr);
367  rc = coresight_write(tile, addr, data);
368  break;
369 
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. */
402 
403  return retval;
404 }
405 
406 static int rshim_connect(struct adiv5_dap *dap)
407 {
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  */
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");
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  },
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",
464  .usage = "",
465  },
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 = {
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 
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 };
This defines formats and data structures used to talk to ADIv5 entities.
#define ADIV5_MEM_AP_REG_DRW
Definition: arm_adi_v5.h:118
#define ADIV5_MEM_AP_REG_BD3
Definition: arm_adi_v5.h:122
#define CSW_ADDRINC_MASK
Definition: arm_adi_v5.h:164
#define ADIV5_MEM_AP_REG_BD2
Definition: arm_adi_v5.h:121
#define ADIV5_MEM_AP_REG_CFG
Definition: arm_adi_v5.h:125
#define ADIV5_MEM_AP_REG_BD1
Definition: arm_adi_v5.h:120
#define DP_SELECT
Definition: arm_adi_v5.h:57
#define ADIV5_MEM_AP_REG_BASE
Definition: arm_adi_v5.h:126
#define ADIV5_MEM_AP_REG_CSW
Definition: arm_adi_v5.h:115
#define DP_CTRL_STAT
Definition: arm_adi_v5.h:50
#define CDBGPWRUPACK
Definition: arm_adi_v5.h:94
#define DP_DPIDR
Definition: arm_adi_v5.h:45
#define CSYSPWRUPACK
Definition: arm_adi_v5.h:96
#define DP_SELECT_APSEL
Definition: arm_adi_v5.h:100
#define ADIV5_AP_REG_IDR
Definition: arm_adi_v5.h:155
static bool is_adiv6(const struct adiv5_dap *dap)
Check if DAP is ADIv6.
Definition: arm_adi_v5.h:479
#define ADIV5_MEM_AP_REG_TAR
Definition: arm_adi_v5.h:116
#define DP_SELECT_APBANK
Definition: arm_adi_v5.h:101
#define ADIV5_MEM_AP_REG_BD0
Definition: arm_adi_v5.h:119
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:473
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly.
Definition: command.h:140
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:155
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:385
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:150
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:247
@ COMMAND_CONFIG
Definition: command.h:41
@ COMMAND_ANY
Definition: command.h:42
struct esp_usb_jtag __attribute__
Definition: armv8.c:804
#define ERROR_FAIL
Definition: log.h:161
#define LOG_ERROR(expr ...)
Definition: log.h:123
#define LOG_INFO(expr ...)
Definition: log.h:117
#define ERROR_OK
Definition: log.h:155
#define ADDR
Definition: mrvlqspi.c:59
uint32_t addr
Definition: nuttx.c:65
static uint32_t ap_tar
Definition: rshim.c:80
static uint32_t ap_sel
Definition: rshim.c:77
#define RSH_CS_SET_FIELD(reg, field, value)
Definition: rshim.c:56
static int rshim_ap_q_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data)
Definition: rshim.c:332
static int rshim_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data)
Definition: rshim.c:268
static int rshim_dap_retval
Definition: rshim.c:92
static int rshim_dap_reset(int req_trst, int req_srst)
Definition: rshim.c:479
#define RSH_CORESIGHT_CTL
Definition: rshim.c:39
static int rshim_dap_khz(int khz, int *jtag_speed)
Definition: rshim.c:489
static int rshim_connect(struct adiv5_dap *dap)
Definition: rshim.c:406
#define APB_AP_IDR
Definition: rshim.c:36
static int rshim_dev_read(int chan, int addr, uint64_t *value)
Definition: rshim.c:98
#define RSH_CS_ROM_BASE
Definition: rshim.c:27
static int rshim_fd
Definition: rshim.c:89
static uint32_t dp_id_code
Definition: rshim.c:76
static int rshim_dap_speed(int speed)
Definition: rshim.c:484
static int rshim_dap_speed_div(int speed, int *khz)
Definition: rshim.c:495
static int rshim_dp_q_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data)
Definition: rshim.c:227
static uint32_t ap_drw
Definition: rshim.c:79
static int(* rshim_write)(int chan, int addr, uint64_t value)
Definition: rshim.c:84
static int rshim_dp_q_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data)
Definition: rshim.c:249
#define RSH_CS_GET_FIELD(reg, field)
Definition: rshim.c:52
static const struct dap_ops rshim_dap_ops
Definition: rshim.c:502
static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata)
Definition: rshim.c:159
static int(* rshim_read)(int chan, int addr, uint64_t *value)
Definition: rshim.c:83
COMMAND_HANDLER(rshim_dap_device_command)
Definition: rshim.c:435
static const struct command_registration rshim_dap_subcommand_handlers[]
Definition: rshim.c:447
struct adapter_driver rshim_dap_adapter_driver
Definition: rshim.c:515
static int rshim_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
Definition: rshim.c:391
#define RSH_CS_TILE_BASE
Definition: rshim.c:28
static uint32_t dp_ctrl_stat
Definition: rshim.c:75
static const struct command_registration rshim_dap_command_handlers[]
Definition: rshim.c:458
#define RSH_MMIO_CHANNEL_RSHIM
Definition: rshim.c:24
static int rshim_dp_run(struct adiv5_dap *dap)
Definition: rshim.c:396
static int rshim_dap_init(void)
Definition: rshim.c:469
static int rshim_dap_quit(void)
Definition: rshim.c:474
static void ap_addr_2_tile(int *tile, uint32_t *addr)
Definition: rshim.c:141
#define RSH_CS_TILE_SIZE
Definition: rshim.c:29
static void rshim_disconnect(struct adiv5_dap *dap)
Definition: rshim.c:427
static int rshim_dev_write(int chan, int addr, uint64_t value)
Definition: rshim.c:120
static char * rshim_dev_path
Definition: rshim.c:96
static uint32_t ap_csw
Definition: rshim.c:78
static uint32_t ap_bank
Definition: rshim.c:77
#define RSHIM_DEV_PATH_DEFAULT
Definition: rshim.c:95
static const char *const rshim_dap_transport[]
Definition: rshim.c:513
static uint32_t ap_tar_inc
Definition: rshim.c:80
static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value)
Definition: rshim.c:193
Represents a driver for a debugging interface.
Definition: interface.h:207
const char *const name
The name of the interface driver.
Definition: interface.h:209
This represents an ARM Debug Interface (v5) Access Port (AP).
Definition: arm_adi_v5.h:243
uint64_t ap_num
ADIv5: Number of this AP (0~255) ADIv6: Base address of this AP (4k aligned) TODO: to be more coheren...
Definition: arm_adi_v5.h:254
struct adiv5_dap * dap
DAP this AP belongs to.
Definition: arm_adi_v5.h:247
This represents an ARM Debug Interface (v5) Debug Access Port (DAP).
Definition: arm_adi_v5.h:320
const char * name
Definition: command.h:229
const char * usage
a string listing the options and arguments, required or optional
Definition: command.h:235
Transport-neutral representation of queued DAP transactions, supporting both JTAG and SWD transports.
Definition: arm_adi_v5.h:408
int(* connect)(struct adiv5_dap *dap)
connect operation for SWD
Definition: arm_adi_v5.h:410
Definition: register.h:111
#define NULL
Definition: usb.h:16