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,