1 /* SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2019 Google, LLC.
4 * Author: Moritz Fischer <moritzf@google.com>
15 #include <linux/pci.h>
17 #include <jtag/interface.h>
19 #include <jtag/commands.h>
20 #include <helper/replacements.h>
21 #include <helper/bits.h>
23 /* Available only from kernel v4.10 */
24 #ifndef PCI_CFG_SPACE_EXP_SIZE
25 #define PCI_CFG_SPACE_EXP_SIZE 4096
28 #define PCIE_EXT_CAP_LST 0x100
30 #define XLNX_XVC_EXT_CAP 0x00
31 #define XLNX_XVC_VSEC_HDR 0x04
32 #define XLNX_XVC_LEN_REG 0x0C
33 #define XLNX_XVC_TMS_REG 0x10
34 #define XLNX_XVC_TDx_REG 0x14
36 #define XLNX_XVC_CAP_SIZE 0x20
37 #define XLNX_XVC_VSEC_ID 0x8
38 #define XLNX_XVC_MAX_BITS 0x20
40 struct xlnx_pcie_xvc
{
46 static struct xlnx_pcie_xvc xlnx_pcie_xvc_state
;
47 static struct xlnx_pcie_xvc
*xlnx_pcie_xvc
= &xlnx_pcie_xvc_state
;
49 static int xlnx_pcie_xvc_read_reg(const int offset
, uint32_t *val
)
54 /* Note: This should be ok endianess-wise because by going
55 * through sysfs the kernel does the conversion in the config
56 * space accessor functions
58 err
= pread(xlnx_pcie_xvc
->fd
, &res
, sizeof(res
),
59 xlnx_pcie_xvc
->offset
+ offset
);
60 if (err
!= sizeof(res
)) {
61 LOG_ERROR("Failed to read offset %x", offset
);
62 return ERROR_JTAG_DEVICE_ERROR
;
71 static int xlnx_pcie_xvc_write_reg(const int offset
, const uint32_t val
)
75 /* Note: This should be ok endianess-wise because by going
76 * through sysfs the kernel does the conversion in the config
77 * space accessor functions
79 err
= pwrite(xlnx_pcie_xvc
->fd
, &val
, sizeof(val
),
80 xlnx_pcie_xvc
->offset
+ offset
);
81 if (err
!= sizeof(val
)) {
82 LOG_ERROR("Failed to write offset: %x with value: %x",
84 return ERROR_JTAG_DEVICE_ERROR
;
90 static int xlnx_pcie_xvc_transact(size_t num_bits
, uint32_t tms
, uint32_t tdi
,
95 err
= xlnx_pcie_xvc_write_reg(XLNX_XVC_LEN_REG
, num_bits
);
99 err
= xlnx_pcie_xvc_write_reg(XLNX_XVC_TMS_REG
, tms
);
103 err
= xlnx_pcie_xvc_write_reg(XLNX_XVC_TDx_REG
, tdi
);
107 err
= xlnx_pcie_xvc_read_reg(XLNX_XVC_TDx_REG
, tdo
);
112 LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: %x",
113 num_bits
, tms
, tdi
, *tdo
);
115 LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: <null>",
120 int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command
*cmd
)
122 int tms
= tap_get_state() == TAP_RESET
? 1 : 0;
123 size_t left
= cmd
->cmd
.stableclocks
->num_cycles
;
127 LOG_DEBUG("stableclocks %i cycles", cmd
->cmd
.runtest
->num_cycles
);
130 write
= MIN(XLNX_XVC_MAX_BITS
, left
);
131 err
= xlnx_pcie_xvc_transact(write
, tms
, 0, NULL
);
140 static int xlnx_pcie_xvc_execute_statemove(size_t skip
)
142 uint8_t tms_scan
= tap_get_tms_path(tap_get_state(),
143 tap_get_end_state());
144 int tms_count
= tap_get_tms_path_len(tap_get_state(),
145 tap_get_end_state());
148 LOG_DEBUG("statemove starting at (skip: %zu) %s end in %s", skip
,
149 tap_state_name(tap_get_state()),
150 tap_state_name(tap_get_end_state()));
153 err
= xlnx_pcie_xvc_transact(tms_count
- skip
, tms_scan
>> skip
, 0, NULL
);
157 tap_set_state(tap_get_end_state());
162 static int xlnx_pcie_xvc_execute_runtest(struct jtag_command
*cmd
)
166 LOG_DEBUG("runtest %i cycles, end in %i",
167 cmd
->cmd
.runtest
->num_cycles
,
168 cmd
->cmd
.runtest
->end_state
);
170 tap_state_t tmp_state
= tap_get_end_state();
172 if (tap_get_state() != TAP_IDLE
) {
173 tap_set_end_state(TAP_IDLE
);
174 err
= xlnx_pcie_xvc_execute_statemove(0);
179 size_t left
= cmd
->cmd
.runtest
->num_cycles
;
183 write
= MIN(XLNX_XVC_MAX_BITS
, left
);
184 err
= xlnx_pcie_xvc_transact(write
, 0, 0, NULL
);
190 tap_set_end_state(tmp_state
);
191 if (tap_get_state() != tap_get_end_state())
192 err
= xlnx_pcie_xvc_execute_statemove(0);
197 static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command
*cmd
)
199 size_t num_states
= cmd
->cmd
.pathmove
->num_states
;
200 tap_state_t
*path
= cmd
->cmd
.pathmove
->path
;
204 LOG_DEBUG("pathmove: %i states, end in %i",
205 cmd
->cmd
.pathmove
->num_states
,
206 cmd
->cmd
.pathmove
->path
[cmd
->cmd
.pathmove
->num_states
- 1]);
208 for (i
= 0; i
< num_states
; i
++) {
209 if (path
[i
] == tap_state_transition(tap_get_state(), false)) {
210 err
= xlnx_pcie_xvc_transact(1, 1, 0, NULL
);
211 } else if (path
[i
] == tap_state_transition(tap_get_state(), true)) {
212 err
= xlnx_pcie_xvc_transact(1, 0, 0, NULL
);
214 LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.",
215 tap_state_name(tap_get_state()),
216 tap_state_name(path
[i
]));
217 err
= ERROR_JTAG_QUEUE_FAILED
;
221 tap_set_state(path
[i
]);
224 tap_set_end_state(tap_get_state());
229 static int xlnx_pcie_xvc_execute_scan(struct jtag_command
*cmd
)
231 enum scan_type type
= jtag_scan_type(cmd
->cmd
.scan
);
232 tap_state_t saved_end_state
= cmd
->cmd
.scan
->end_state
;
233 bool ir_scan
= cmd
->cmd
.scan
->ir_scan
;
234 uint32_t tdi
, tms
, tdo
;
235 uint8_t *buf
, *rd_ptr
;
240 scan_size
= jtag_build_buffer(cmd
->cmd
.scan
, &buf
);
242 LOG_DEBUG("%s scan type %d %d bits; starts in %s end in %s",
243 (cmd
->cmd
.scan
->ir_scan
) ? "IR" : "DR", type
, scan_size
,
244 tap_state_name(tap_get_state()),
245 tap_state_name(cmd
->cmd
.scan
->end_state
));
247 /* If we're in TAP_DR_SHIFT state but need to do a IR_SCAN or
248 * vice-versa, do a statemove to corresponding other state, then restore
251 if (ir_scan
&& tap_get_state() != TAP_IRSHIFT
) {
252 tap_set_end_state(TAP_IRSHIFT
);
253 err
= xlnx_pcie_xvc_execute_statemove(0);
256 tap_set_end_state(saved_end_state
);
257 } else if (!ir_scan
&& (tap_get_state() != TAP_DRSHIFT
)) {
258 tap_set_end_state(TAP_DRSHIFT
);
259 err
= xlnx_pcie_xvc_execute_statemove(0);
262 tap_set_end_state(saved_end_state
);
267 write
= MIN(XLNX_XVC_MAX_BITS
, left
);
268 /* the last TMS should be a 1, to leave the state */
269 tms
= left
<= XLNX_XVC_MAX_BITS
? BIT(write
- 1) : 0;
270 tdi
= (type
!= SCAN_IN
) ? buf_get_u32(rd_ptr
, 0, write
) : 0;
271 err
= xlnx_pcie_xvc_transact(write
, tms
, tdi
, type
!= SCAN_OUT
?
276 if (type
!= SCAN_OUT
)
277 buf_set_u32(rd_ptr
, 0, write
, tdo
);
278 rd_ptr
+= sizeof(uint32_t);
281 err
= jtag_read_buffer(buf
, cmd
->cmd
.scan
);
285 if (tap_get_state() != tap_get_end_state())
286 err
= xlnx_pcie_xvc_execute_statemove(1);
296 static void xlnx_pcie_xvc_execute_reset(struct jtag_command
*cmd
)
298 LOG_DEBUG("reset trst: %i srst: %i", cmd
->cmd
.reset
->trst
,
299 cmd
->cmd
.reset
->srst
);
302 static void xlnx_pcie_xvc_execute_sleep(struct jtag_command
*cmd
)
304 LOG_DEBUG("sleep %" PRIi32
"", cmd
->cmd
.sleep
->us
);
305 usleep(cmd
->cmd
.sleep
->us
);
308 static int xlnx_pcie_xvc_execute_tms(struct jtag_command
*cmd
)
310 const size_t num_bits
= cmd
->cmd
.tms
->num_bits
;
311 const uint8_t *bits
= cmd
->cmd
.tms
->bits
;
316 LOG_DEBUG("execute tms %zu", num_bits
);
320 write
= MIN(XLNX_XVC_MAX_BITS
, left
);
321 tms
= buf_get_u32(bits
, 0, write
);
322 err
= xlnx_pcie_xvc_transact(write
, tms
, 0, NULL
);
332 static int xlnx_pcie_xvc_execute_command(struct jtag_command
*cmd
)
334 LOG_DEBUG("%s: cmd->type: %u", __func__
, cmd
->type
);
336 case JTAG_STABLECLOCKS
:
337 return xlnx_pcie_xvc_execute_stableclocks(cmd
);
339 return xlnx_pcie_xvc_execute_runtest(cmd
);
341 tap_set_end_state(cmd
->cmd
.statemove
->end_state
);
342 return xlnx_pcie_xvc_execute_statemove(0);
344 return xlnx_pcie_xvc_execute_pathmove(cmd
);
346 return xlnx_pcie_xvc_execute_scan(cmd
);
348 xlnx_pcie_xvc_execute_reset(cmd
);
351 xlnx_pcie_xvc_execute_sleep(cmd
);
354 return xlnx_pcie_xvc_execute_tms(cmd
);
356 LOG_ERROR("BUG: Unknown JTAG command type encountered.");
357 return ERROR_JTAG_QUEUE_FAILED
;
363 static int xlnx_pcie_xvc_execute_queue(void)
365 struct jtag_command
*cmd
= jtag_command_queue
;
369 ret
= xlnx_pcie_xvc_execute_command(cmd
);
381 static int xlnx_pcie_xvc_init(void)
383 char filename
[PATH_MAX
];
387 snprintf(filename
, PATH_MAX
, "/sys/bus/pci/devices/%s/config",
388 xlnx_pcie_xvc
->device
);
389 xlnx_pcie_xvc
->fd
= open(filename
, O_RDWR
| O_SYNC
);
390 if (xlnx_pcie_xvc
->fd
< 0) {
391 LOG_ERROR("Failed to open device: %s", filename
);
392 return ERROR_JTAG_INIT_FAILED
;
395 LOG_INFO("Scanning PCIe device %s's for Xilinx XVC/PCIe ...",
396 xlnx_pcie_xvc
->device
);
397 /* Parse the PCIe extended capability list and try to find
398 * vendor specific header */
399 xlnx_pcie_xvc
->offset
= PCIE_EXT_CAP_LST
;
400 while (xlnx_pcie_xvc
->offset
<= PCI_CFG_SPACE_EXP_SIZE
- sizeof(cap
) &&
401 xlnx_pcie_xvc
->offset
>= PCIE_EXT_CAP_LST
) {
402 err
= xlnx_pcie_xvc_read_reg(XLNX_XVC_EXT_CAP
, &cap
);
405 LOG_DEBUG("Checking capability at 0x%x; id=0x%04x version=0x%x next=0x%x",
406 xlnx_pcie_xvc
->offset
,
408 PCI_EXT_CAP_VER(cap
),
409 PCI_EXT_CAP_NEXT(cap
));
410 if (PCI_EXT_CAP_ID(cap
) == PCI_EXT_CAP_ID_VNDR
) {
411 err
= xlnx_pcie_xvc_read_reg(XLNX_XVC_VSEC_HDR
, &vh
);
414 LOG_DEBUG("Checking possible match at 0x%x; id: 0x%x; rev: 0x%x; length: 0x%x",
415 xlnx_pcie_xvc
->offset
,
416 PCI_VNDR_HEADER_ID(vh
),
417 PCI_VNDR_HEADER_REV(vh
),
418 PCI_VNDR_HEADER_LEN(vh
));
419 if ((PCI_VNDR_HEADER_ID(vh
) == XLNX_XVC_VSEC_ID
) &&
420 (PCI_VNDR_HEADER_LEN(vh
) == XLNX_XVC_CAP_SIZE
))
423 xlnx_pcie_xvc
->offset
= PCI_EXT_CAP_NEXT(cap
);
425 if ((xlnx_pcie_xvc
->offset
> PCI_CFG_SPACE_EXP_SIZE
- XLNX_XVC_CAP_SIZE
) ||
426 xlnx_pcie_xvc
->offset
< PCIE_EXT_CAP_LST
) {
427 close(xlnx_pcie_xvc
->fd
);
428 return ERROR_JTAG_INIT_FAILED
;
431 LOG_INFO("Found Xilinx XVC/PCIe capability at offset: 0x%x", xlnx_pcie_xvc
->offset
);
436 static int xlnx_pcie_xvc_quit(void)
440 err
= close(xlnx_pcie_xvc
->fd
);
447 COMMAND_HANDLER(xlnx_pcie_xvc_handle_config_command
)
450 return ERROR_COMMAND_SYNTAX_ERROR
;
452 /* we can't really free this in a safe manner, so at least
453 * limit the memory we're leaking by freeing the old one first
454 * before allocating a new one ...
456 if (xlnx_pcie_xvc
->device
)
457 free(xlnx_pcie_xvc
->device
);
459 xlnx_pcie_xvc
->device
= strdup(CMD_ARGV
[0]);
463 static const struct command_registration xlnx_pcie_xvc_command_handlers
[] = {
465 .name
= "xlnx_pcie_xvc_config",
466 .handler
= xlnx_pcie_xvc_handle_config_command
,
467 .mode
= COMMAND_CONFIG
,
468 .help
= "Configure XVC/PCIe JTAG adapter",
471 COMMAND_REGISTRATION_DONE
474 static struct jtag_interface xlnx_pcie_xvc_interface
= {
475 .execute_queue
= &xlnx_pcie_xvc_execute_queue
,
478 struct adapter_driver xlnx_pcie_xvc_adapter_driver
= {
479 .name
= "xlnx_pcie_xvc",
480 .transports
= jtag_only
,
481 .commands
= xlnx_pcie_xvc_command_handlers
,
483 .init
= &xlnx_pcie_xvc_init
,
484 .quit
= &xlnx_pcie_xvc_quit
,
486 .jtag_ops
= &xlnx_pcie_xvc_interface
,
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)