jtag/drivers: add debugging support for Mellanox BlueField SoC
[fw/openocd] / 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 };