openocd: fix SPDX tag format for files .c
[fw/openocd] / 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 };