1 /***************************************************************************
2 * Copyright (C) 2017 by Texas Instruments, Inc. *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 ***************************************************************************/
22 #include <transport/transport.h>
24 #include <jtag/interface.h>
25 #include <jtag/commands.h>
29 /* XDS110 USB serial number length */
30 #define XDS110_SERIAL_LEN 8
32 /* XDS110 stand-alone probe voltage supply limits */
33 #define XDS110_MIN_VOLTAGE 1800
34 #define XDS110_MAX_VOLTAGE 3600
36 /* XDS110 stand-alone probe hardware ID */
37 #define XDS110_STAND_ALONE_ID 0x21
39 /* Firmware version that introduced OpenOCD support via block accesses */
40 #define OCD_FIRMWARE_VERSION 0x02030011
41 #define OCD_FIRMWARE_UPGRADE \
42 "XDS110: upgrade to version 2.3.0.11+ for improved support"
44 /* Firmware version that introduced improved TCK performance */
45 #define FAST_TCK_FIRMWARE_VERSION 0x03000000
47 /* Firmware version that introduced 10 MHz and 12 MHz TCK support */
48 #define FAST_TCK_PLUS_FIRMWARE_VERSION 0x03000003
50 /***************************************************************************
51 * USB Connection Buffer Definitions *
52 ***************************************************************************/
54 /* Max USB packet size for up to USB 3.0 */
55 #define MAX_PACKET 1024
58 * Maximum data payload that can be handled in a single call
59 * Limitation is the size of the buffers in the XDS110 firmware
61 #define MAX_DATA_BLOCK 4096
63 #ifndef USB_PAYLOAD_SIZE
64 /* Largest data block plus parameters */
65 #define USB_PAYLOAD_SIZE (MAX_DATA_BLOCK + 60)
67 #define MAX_RESULT_QUEUE (MAX_DATA_BLOCK / 4)
69 /***************************************************************************
70 * XDS110 Firmware API Definitions *
71 ***************************************************************************/
74 * Default values controlling how the host communicates commands
75 * with XDS110 firmware (automatic retry count and wait timeout)
77 #define DEFAULT_ATTEMPTS (1)
78 #define DEFAULT_TIMEOUT (4000)
80 /* XDS110 API error codes */
82 #define SC_ERR_XDS110_FAIL -261
83 #define SC_ERR_SWD_WAIT -613
84 #define SC_ERR_SWD_FAULT -614
85 #define SC_ERR_SWD_PROTOCOL -615
86 #define SC_ERR_SWD_PARITY -616
87 #define SC_ERR_SWD_DEVICE_ID -617
89 /* TCK frequency limits */
90 #define XDS110_MIN_TCK_SPEED 100 /* kHz */
91 #define XDS110_MAX_SLOW_TCK_SPEED 2500 /* kHz */
92 #define XDS110_MAX_FAST_TCK_SPEED 14000 /* kHz */
93 #define XDS110_DEFAULT_TCK_SPEED 2500 /* kHz */
95 /* Fixed TCK delay values for "Fast" TCK frequencies */
96 #define FAST_TCK_DELAY_14000_KHZ 0
97 #define FAST_TCK_DELAY_10000_KHZ 0xfffffffd
98 #define FAST_TCK_DELAY_12000_KHZ 0xfffffffe
99 #define FAST_TCK_DELAY_8500_KHZ 1
100 #define FAST_TCK_DELAY_5500_KHZ 2
101 /* For TCK frequencies below 5500 kHz, use calculated delay */
103 /* Scan mode on connect */
106 /* XDS110 API JTAG state definitions */
107 #define XDS_JTAG_STATE_RESET 1
108 #define XDS_JTAG_STATE_IDLE 2
109 #define XDS_JTAG_STATE_SHIFT_DR 3
110 #define XDS_JTAG_STATE_SHIFT_IR 4
111 #define XDS_JTAG_STATE_PAUSE_DR 5
112 #define XDS_JTAG_STATE_PAUSE_IR 6
113 #define XDS_JTAG_STATE_EXIT1_DR 8
114 #define XDS_JTAG_STATE_EXIT1_IR 9
115 #define XDS_JTAG_STATE_EXIT2_DR 10
116 #define XDS_JTAG_STATE_EXIT2_IR 11
117 #define XDS_JTAG_STATE_SELECT_DR 12
118 #define XDS_JTAG_STATE_SELECT_IR 13
119 #define XDS_JTAG_STATE_UPDATE_DR 14
120 #define XDS_JTAG_STATE_UPDATE_IR 15
121 #define XDS_JTAG_STATE_CAPTURE_DR 16
122 #define XDS_JTAG_STATE_CAPTURE_IR 17
124 /* XDS110 API JTAG transit definitions */
125 #define XDS_JTAG_TRANSIT_QUICKEST 1
126 #define XDS_JTAG_TRANSIT_VIA_CAPTURE 2
127 #define XDS_JTAG_TRANSIT_VIA_IDLE 3
129 /* DAP register definitions as used by XDS110 APIs */
131 #define DAP_AP 0 /* DAP AP register type */
132 #define DAP_DP 1 /* DAP DP register type */
134 #define DAP_DP_IDCODE 0x0 /* DAP DP IDCODE register (read only) */
135 #define DAP_DP_ABORT 0x0 /* DAP DP ABORT register (write only) */
136 #define DAP_DP_STAT 0x4 /* DAP DP STAT register (for read only) */
137 #define DAP_DP_CTRL 0x4 /* DAP DP CTRL register (for write only) */
138 #define DAP_DP_ADDR 0x8 /* DAP DP SELECT register (legacy name) */
139 #define DAP_DP_RESEND 0x8 /* DAP DP RESEND register (read only) */
140 #define DAP_DP_SELECT 0x8 /* DAP DP SELECT register (write only) */
141 #define DAP_DP_RDBUFF 0xc /* DAP DP RDBUFF Read Buffer register */
143 #define DAP_AP_CSW 0x00 /* DAP AP Control Status Word */
144 #define DAP_AP_TAR 0x04 /* DAP AP Transfer Address */
145 #define DAP_AP_DRW 0x0C /* DAP AP Data Read/Write */
146 #define DAP_AP_BD0 0x10 /* DAP AP Banked Data 0 */
147 #define DAP_AP_BD1 0x14 /* DAP AP Banked Data 1 */
148 #define DAP_AP_BD2 0x18 /* DAP AP Banked Data 2 */
149 #define DAP_AP_BD3 0x1C /* DAP AP Banked Data 3 */
150 #define DAP_AP_RTBL 0xF8 /* DAP AP Debug ROM Table */
151 #define DAP_AP_IDR 0xFC /* DAP AP Identification Register */
153 /* Command packet definitions */
155 #define XDS_OUT_LEN 1 /* command (byte) */
156 #define XDS_IN_LEN 4 /* error code (int) */
158 /* XDS API Commands */
159 #define XDS_CONNECT 0x01 /* Connect JTAG connection */
160 #define XDS_DISCONNECT 0x02 /* Disconnect JTAG connection */
161 #define XDS_VERSION 0x03 /* Get firmware version and hardware ID */
162 #define XDS_SET_TCK 0x04 /* Set TCK delay (to set TCK frequency) */
163 #define XDS_SET_TRST 0x05 /* Assert or deassert nTRST signal */
164 #define XDS_CYCLE_TCK 0x07 /* Toggle TCK for a number of cycles */
165 #define XDS_GOTO_STATE 0x09 /* Go to requested JTAG state */
166 #define XDS_JTAG_SCAN 0x0c /* Send and receive JTAG scan */
167 #define XDS_SET_SRST 0x0e /* Assert or deassert nSRST signal */
168 #define CMAPI_CONNECT 0x0f /* CMAPI connect */
169 #define CMAPI_DISCONNECT 0x10 /* CMAPI disconnect */
170 #define CMAPI_ACQUIRE 0x11 /* CMAPI acquire */
171 #define CMAPI_RELEASE 0x12 /* CMAPI release */
172 #define CMAPI_REG_READ 0x15 /* CMAPI DAP register read */
173 #define CMAPI_REG_WRITE 0x16 /* CMAPI DAP register write */
174 #define SWD_CONNECT 0x17 /* Switch from JTAG to SWD connection */
175 #define SWD_DISCONNECT 0x18 /* Switch from SWD to JTAG connection */
176 #define CJTAG_CONNECT 0x2b /* Switch from JTAG to cJTAG connection */
177 #define CJTAG_DISCONNECT 0x2c /* Switch from cJTAG to JTAG connection */
178 #define XDS_SET_SUPPLY 0x32 /* Set up stand-alone probe upply voltage */
179 #define OCD_DAP_REQUEST 0x3a /* Handle block of DAP requests */
180 #define OCD_SCAN_REQUEST 0x3b /* Handle block of JTAG scan requests */
181 #define OCD_PATHMOVE 0x3c /* Handle PATHMOVE to navigate JTAG states */
183 #define CMD_IR_SCAN 1
184 #define CMD_DR_SCAN 2
185 #define CMD_RUNTEST 3
186 #define CMD_STABLECLOCKS 4
188 /* Array to convert from OpenOCD tap_state_t to XDS JTAG state */
189 const uint32_t xds_jtag_state
[] = {
190 XDS_JTAG_STATE_EXIT2_DR
, /* TAP_DREXIT2 = 0x0 */
191 XDS_JTAG_STATE_EXIT1_DR
, /* TAP_DREXIT1 = 0x1 */
192 XDS_JTAG_STATE_SHIFT_DR
, /* TAP_DRSHIFT = 0x2 */
193 XDS_JTAG_STATE_PAUSE_DR
, /* TAP_DRPAUSE = 0x3 */
194 XDS_JTAG_STATE_SELECT_IR
, /* TAP_IRSELECT = 0x4 */
195 XDS_JTAG_STATE_UPDATE_DR
, /* TAP_DRUPDATE = 0x5 */
196 XDS_JTAG_STATE_CAPTURE_DR
, /* TAP_DRCAPTURE = 0x6 */
197 XDS_JTAG_STATE_SELECT_DR
, /* TAP_DRSELECT = 0x7 */
198 XDS_JTAG_STATE_EXIT2_IR
, /* TAP_IREXIT2 = 0x8 */
199 XDS_JTAG_STATE_EXIT1_IR
, /* TAP_IREXIT1 = 0x9 */
200 XDS_JTAG_STATE_SHIFT_IR
, /* TAP_IRSHIFT = 0xa */
201 XDS_JTAG_STATE_PAUSE_IR
, /* TAP_IRPAUSE = 0xb */
202 XDS_JTAG_STATE_IDLE
, /* TAP_IDLE = 0xc */
203 XDS_JTAG_STATE_UPDATE_IR
, /* TAP_IRUPDATE = 0xd */
204 XDS_JTAG_STATE_CAPTURE_IR
, /* TAP_IRCAPTURE = 0xe */
205 XDS_JTAG_STATE_RESET
, /* TAP_RESET = 0xf */
215 /* USB connection handles and data buffers */
217 libusb_device_handle
*dev
;
218 unsigned char read_payload
[USB_PAYLOAD_SIZE
];
219 unsigned char write_packet
[3];
220 unsigned char write_payload
[USB_PAYLOAD_SIZE
];
224 /* Debug interface */
227 uint8_t endpoint_out
;
230 bool is_cmapi_connected
;
231 bool is_cmapi_acquired
;
234 /* DAP register caches */
238 /* TCK speed and delay count*/
240 uint32_t delay_count
;
241 /* XDS110 serial number */
242 char serial
[XDS110_SERIAL_LEN
+ 1];
243 /* XDS110 voltage supply setting */
245 /* XDS110 firmware and hardware version */
248 /* Transaction queues */
249 unsigned char txn_requests
[MAX_DATA_BLOCK
];
250 uint32_t *txn_dap_results
[MAX_DATA_BLOCK
/ 4];
251 struct scan_result txn_scan_results
[MAX_DATA_BLOCK
/ 4];
252 uint32_t txn_request_size
;
253 uint32_t txn_result_size
;
254 uint32_t txn_result_count
;
257 static struct xds110_info xds110
= {
265 .is_connected
= false,
266 .is_cmapi_connected
= false,
267 .is_cmapi_acquired
= false,
268 .is_swd_mode
= false,
269 .is_ap_dirty
= false,
270 .speed
= XDS110_DEFAULT_TCK_SPEED
,
276 .txn_request_size
= 0,
277 .txn_result_size
= 0,
278 .txn_result_count
= 0
281 static inline void xds110_set_u32(uint8_t *buffer
, uint32_t value
)
283 buffer
[3] = (value
>> 24) & 0xff;
284 buffer
[2] = (value
>> 16) & 0xff;
285 buffer
[1] = (value
>> 8) & 0xff;
286 buffer
[0] = (value
>> 0) & 0xff;
289 static inline void xds110_set_u16(uint8_t *buffer
, uint16_t value
)
291 buffer
[1] = (value
>> 8) & 0xff;
292 buffer
[0] = (value
>> 0) & 0xff;
295 static inline uint32_t xds110_get_u32(uint8_t *buffer
)
297 uint32_t value
= (((uint32_t)buffer
[3]) << 24) |
298 (((uint32_t)buffer
[2]) << 16) |
299 (((uint32_t)buffer
[1]) << 8) |
300 (((uint32_t)buffer
[0]) << 0);
304 static inline uint16_t xds110_get_u16(uint8_t *buffer
)
306 uint16_t value
= (((uint32_t)buffer
[1]) << 8) |
307 (((uint32_t)buffer
[0]) << 0);
311 /***************************************************************************
312 * usb connection routines *
314 * The following functions handle connecting, reading, and writing to *
315 * the XDS110 over USB using the libusb library. *
316 ***************************************************************************/
318 static bool usb_connect(void)
320 libusb_context
*ctx
= NULL
;
321 libusb_device
**list
= NULL
;
322 libusb_device_handle
*dev
= NULL
;
324 struct libusb_device_descriptor desc
;
326 /* The vid/pids of possible XDS110 configurations */
327 uint16_t vids
[] = { 0x0451, 0x0451, 0x1cbe };
328 uint16_t pids
[] = { 0xbef3, 0xbef4, 0x02a5 };
329 /* Corresponding interface and endpoint numbers for configurations */
330 uint8_t interfaces
[] = { 2, 2, 0 };
331 uint8_t endpoints_in
[] = { 3, 3, 1 };
332 uint8_t endpoints_out
[] = { 2, 2, 1 };
341 /* Initialize libusb context */
342 result
= libusb_init(&ctx
);
345 /* Get list of USB devices attached to system */
346 count
= libusb_get_device_list(ctx
, &list
);
354 /* Scan through list of devices for any XDS110s */
355 for (i
= 0; i
< count
; i
++) {
356 /* Check for device vid/pid match */
357 libusb_get_device_descriptor(list
[i
], &desc
);
359 for (device
= 0; device
< sizeof(vids
)/sizeof(vids
[0]); device
++) {
360 if (desc
.idVendor
== vids
[device
] &&
361 desc
.idProduct
== pids
[device
]) {
367 result
= libusb_open(list
[i
], &dev
);
369 const int max_data
= 256;
370 unsigned char data
[max_data
+ 1];
373 /* May be the requested device if serial number matches */
374 if (0 == xds110
.serial
[0]) {
375 /* No serial number given; match first XDS110 found */
379 /* Get the device's serial number string */
380 result
= libusb_get_string_descriptor_ascii(dev
,
381 desc
.iSerialNumber
, data
, max_data
);
383 0 == strcmp((char *)data
, (char *)xds110
.serial
)) {
389 /* If we fall though to here, we don't want this device */
398 * We can fall through the for() loop with two possible exit conditions:
399 * 1) found the right XDS110, and that device is open
400 * 2) didn't find the XDS110, and no devices are currently open
404 /* Free the device list, we're done with it */
405 libusb_free_device_list(list
, 1);
409 /* Save the vid/pid of the device we're using */
410 xds110
.vid
= vids
[device
];
411 xds110
.pid
= pids
[device
];
413 /* Save the debug interface and endpoints for the device */
414 xds110
.interface
= interfaces
[device
];
415 xds110
.endpoint_in
= endpoints_in
[device
] | LIBUSB_ENDPOINT_IN
;
416 xds110
.endpoint_out
= endpoints_out
[device
] | LIBUSB_ENDPOINT_OUT
;
418 /* Save the context and device handles */
422 /* Set libusb to auto detach kernel */
423 (void)libusb_set_auto_detach_kernel_driver(dev
, 1);
425 /* Claim the debug interface on the XDS110 */
426 result
= libusb_claim_interface(dev
, xds110
.interface
);
428 /* Couldn't find an XDS110, flag the error */
432 /* On an error, clean up what we can */
435 /* Release the debug and data interface on the XDS110 */
436 (void)libusb_release_interface(dev
, xds110
.interface
);
445 /* Log the results */
447 LOG_INFO("XDS110: connected");
449 LOG_ERROR("XDS110: failed to connect");
451 return (0 == result
) ? true : false;
454 static void usb_disconnect(void)
456 if (NULL
!= xds110
.dev
) {
457 /* Release the debug and data interface on the XDS110 */
458 (void)libusb_release_interface(xds110
.dev
, xds110
.interface
);
459 libusb_close(xds110
.dev
);
462 if (NULL
!= xds110
.ctx
) {
463 libusb_exit(xds110
.ctx
);
467 LOG_INFO("XDS110: disconnected");
470 static bool usb_read(unsigned char *buffer
, int size
, int *bytes_read
,
475 if (NULL
== xds110
.dev
|| NULL
== buffer
|| NULL
== bytes_read
)
478 /* Force a non-zero timeout to prevent blocking */
480 timeout
= DEFAULT_TIMEOUT
;
482 result
= libusb_bulk_transfer(xds110
.dev
, xds110
.endpoint_in
, buffer
, size
,
483 bytes_read
, timeout
);
485 return (0 == result
) ? true : false;
488 static bool usb_write(unsigned char *buffer
, int size
, int *written
)
490 int bytes_written
= 0;
491 int result
= LIBUSB_SUCCESS
;
494 if (NULL
== xds110
.dev
|| NULL
== buffer
)
497 result
= libusb_bulk_transfer(xds110
.dev
, xds110
.endpoint_out
, buffer
,
498 size
, &bytes_written
, 0);
500 while (LIBUSB_ERROR_PIPE
== result
&& retries
< 3) {
501 /* Try clearing the pipe stall and retry transfer */
502 libusb_clear_halt(xds110
.dev
, xds110
.endpoint_out
);
503 result
= libusb_bulk_transfer(xds110
.dev
, xds110
.endpoint_out
, buffer
,
504 size
, &bytes_written
, 0);
509 *written
= bytes_written
;
511 return (0 == result
&& size
== bytes_written
) ? true : false;
514 static bool usb_get_response(uint32_t *total_bytes_read
, uint32_t timeout
)
516 static unsigned char buffer
[MAX_PACKET
];
525 success
= usb_read(buffer
, sizeof(buffer
), &bytes_read
, timeout
);
528 * Validate that this appears to be a good response packet
529 * First check it contains enough data for header and error
530 * code, plus the first character is the start character
532 if (bytes_read
>= 7 && '*' == buffer
[0]) {
533 /* Extract the payload size */
534 size
= xds110_get_u16(&buffer
[1]);
535 /* Sanity test on payload size */
536 if (USB_PAYLOAD_SIZE
>= size
&& 4 <= size
) {
537 /* Check we didn't get more data than expected */
538 if ((bytes_read
- 3) <= size
) {
539 /* Packet appears to be valid, move on */
546 * Somehow received an invalid packet, retry till we
547 * time out or a valid response packet is received
551 /* Abort now if we didn't receive a valid response */
553 if (NULL
!= total_bytes_read
)
554 *total_bytes_read
= 0;
558 /* Build the return payload into xds110.read_payload */
560 /* Copy over payload data from received buffer (skipping header) */
563 memcpy((void *)&xds110
.read_payload
[count
], (void *)&buffer
[3], bytes_read
);
566 * Drop timeout to just 1/2 second. Once the XDS110 starts sending
567 * a response, the remaining packets should arrive in short order
570 timeout
= 500; /* ms */
572 /* If there's more data to retrieve, get it now */
573 while ((count
< size
) && success
) {
574 success
= usb_read(buffer
, sizeof(buffer
), &bytes_read
, timeout
);
576 if ((count
+ bytes_read
) > size
) {
577 /* Read too much data, not a valid packet, abort */
580 /* Copy this data over to xds110.read_payload */
581 memcpy((void *)&xds110
.read_payload
[count
], (void *)buffer
,
590 if (NULL
!= total_bytes_read
)
591 *total_bytes_read
= count
;
596 static bool usb_send_command(uint16_t size
)
601 /* Check the packet length */
602 if (size
> USB_PAYLOAD_SIZE
)
605 /* Place the start character into the packet buffer */
606 xds110
.write_packet
[0] = '*';
608 /* Place the payload size into the packet buffer */
609 xds110_set_u16(&xds110
.write_packet
[1], size
);
611 /* Adjust size to include header */
614 /* Send the data via the USB connection */
615 success
= usb_write(xds110
.write_packet
, (int)size
, &written
);
617 /* Check if the correct number of bytes was written */
618 if (written
!= (int)size
)
624 /***************************************************************************
625 * XDS110 firmware API routines *
627 * The following functions handle calling into the XDS110 firmware to *
628 * perform requested debug actions. *
629 ***************************************************************************/
631 static bool xds_execute(uint32_t out_length
, uint32_t in_length
,
632 uint32_t attempts
, uint32_t timeout
)
637 uint32_t bytes_read
= 0;
639 if (NULL
== xds110
.dev
)
642 while (!done
&& attempts
> 0) {
645 /* Send command to XDS110 */
646 success
= usb_send_command(out_length
);
649 /* Get response from XDS110 */
650 success
= usb_get_response(&bytes_read
, timeout
);
654 /* Check for valid response from XDS code handling */
655 if (bytes_read
!= in_length
) {
656 /* Unexpected amount of data returned */
658 LOG_DEBUG("XDS110: command 0x%02x return %d bytes, expected %d",
659 xds110
.write_payload
[0], bytes_read
, in_length
);
661 /* Extract error code from return packet */
662 error
= (int)xds110_get_u32(&xds110
.read_payload
[0]);
664 if (SC_ERR_NONE
!= error
)
665 LOG_DEBUG("XDS110: command 0x%02x returned error %d",
666 xds110
.write_payload
[0], error
);
672 error
= SC_ERR_XDS110_FAIL
;
680 static bool xds_connect(void)
684 xds110
.write_payload
[0] = XDS_CONNECT
;
686 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
692 static bool xds_disconnect(void)
696 xds110
.write_payload
[0] = XDS_DISCONNECT
;
698 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
704 static bool xds_version(uint32_t *firmware_id
, uint16_t *hardware_id
)
706 uint8_t *fw_id_pntr
= &xds110
.read_payload
[XDS_IN_LEN
+ 0]; /* 32-bits */
707 uint8_t *hw_id_pntr
= &xds110
.read_payload
[XDS_IN_LEN
+ 4]; /* 16-bits */
711 xds110
.write_payload
[0] = XDS_VERSION
;
713 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
+ 6, DEFAULT_ATTEMPTS
,
717 if (NULL
!= firmware_id
)
718 *firmware_id
= xds110_get_u32(fw_id_pntr
);
719 if (NULL
!= hardware_id
)
720 *hardware_id
= xds110_get_u16(hw_id_pntr
);
726 static bool xds_set_tck_delay(uint32_t delay
)
728 uint8_t *delay_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 32-bits */
732 xds110
.write_payload
[0] = XDS_SET_TCK
;
734 xds110_set_u32(delay_pntr
, delay
);
736 success
= xds_execute(XDS_OUT_LEN
+ 4, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
742 static bool xds_set_trst(uint8_t trst
)
744 uint8_t *trst_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 8-bits */
748 xds110
.write_payload
[0] = XDS_SET_TRST
;
752 success
= xds_execute(XDS_OUT_LEN
+ 1, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
758 static bool xds_cycle_tck(uint32_t count
)
760 uint8_t *count_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 32-bits */
764 xds110
.write_payload
[0] = XDS_CYCLE_TCK
;
766 xds110_set_u32(count_pntr
, count
);
768 success
= xds_execute(XDS_OUT_LEN
+ 4, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
774 static bool xds_goto_state(uint32_t state
)
776 uint8_t *state_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 32-bits */
777 uint8_t *transit_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+4]; /* 32-bits */
781 xds110
.write_payload
[0] = XDS_GOTO_STATE
;
783 xds110_set_u32(state_pntr
, state
);
784 xds110_set_u32(transit_pntr
, XDS_JTAG_TRANSIT_QUICKEST
);
786 success
= xds_execute(XDS_OUT_LEN
+8, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
792 static bool xds_jtag_scan(uint32_t shift_state
, uint16_t shift_bits
,
793 uint32_t end_state
, uint8_t *data_out
, uint8_t *data_in
)
795 uint8_t *bits_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 16-bits */
796 uint8_t *path_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 2]; /* 8-bits */
797 uint8_t *trans1_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 3]; /* 8-bits */
798 uint8_t *end_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 4]; /* 8-bits */
799 uint8_t *trans2_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 5]; /* 8-bits */
800 uint8_t *pre_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 6]; /* 16-bits */
801 uint8_t *pos_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 8]; /* 16-bits */
802 uint8_t *delay_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 10]; /* 16-bits */
803 uint8_t *rep_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 12]; /* 16-bits */
804 uint8_t *out_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 14]; /* 16-bits */
805 uint8_t *in_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 16]; /* 16-bits */
806 uint8_t *data_out_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 18];
807 uint8_t *data_in_pntr
= &xds110
.read_payload
[XDS_IN_LEN
+0];
809 uint16_t total_bytes
= DIV_ROUND_UP(shift_bits
, 8);
813 xds110
.write_payload
[0] = XDS_JTAG_SCAN
;
815 xds110_set_u16(bits_pntr
, shift_bits
); /* bits to scan */
816 *path_pntr
= (uint8_t)(shift_state
& 0xff); /* IR vs DR path */
817 *trans1_pntr
= (uint8_t)XDS_JTAG_TRANSIT_QUICKEST
; /* start state route */
818 *end_pntr
= (uint8_t)(end_state
& 0xff); /* JTAG state after scan */
819 *trans2_pntr
= (uint8_t)XDS_JTAG_TRANSIT_QUICKEST
; /* end state route */
820 xds110_set_u16(pre_pntr
, 0); /* number of preamble bits */
821 xds110_set_u16(pos_pntr
, 0); /* number of postamble bits */
822 xds110_set_u16(delay_pntr
, 0); /* number of extra TCKs after scan */
823 xds110_set_u16(rep_pntr
, 1); /* number of repetitions */
824 xds110_set_u16(out_pntr
, total_bytes
); /* out buffer offset (if repeats) */
825 xds110_set_u16(in_pntr
, total_bytes
); /* in buffer offset (if repeats) */
827 memcpy((void *)data_out_pntr
, (void *)data_out
, total_bytes
);
829 success
= xds_execute(XDS_OUT_LEN
+ 18 + total_bytes
,
830 XDS_IN_LEN
+ total_bytes
, DEFAULT_ATTEMPTS
, DEFAULT_TIMEOUT
);
833 memcpy((void *)data_in
, (void *)data_in_pntr
, total_bytes
);
838 static bool xds_set_srst(uint8_t srst
)
840 uint8_t *srst_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 8-bits */
844 xds110
.write_payload
[0] = XDS_SET_SRST
;
848 success
= xds_execute(XDS_OUT_LEN
+ 1, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
854 static bool cmapi_connect(uint32_t *idcode
)
856 uint8_t *idcode_pntr
= &xds110
.read_payload
[XDS_IN_LEN
+ 0]; /* 32-bits */
860 xds110
.write_payload
[0] = CMAPI_CONNECT
;
862 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
+4, DEFAULT_ATTEMPTS
,
867 *idcode
= xds110_get_u32(idcode_pntr
);
873 static bool cmapi_disconnect(void)
877 xds110
.write_payload
[0] = CMAPI_DISCONNECT
;
879 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
885 static bool cmapi_acquire(void)
889 xds110
.write_payload
[0] = CMAPI_ACQUIRE
;
891 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
897 static bool cmapi_release(void)
901 xds110
.write_payload
[0] = CMAPI_RELEASE
;
903 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
909 static bool cmapi_read_dap_reg(uint32_t type
, uint32_t ap_num
,
910 uint32_t address
, uint32_t *value
)
912 uint8_t *type_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 8-bits */
913 uint8_t *ap_num_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 1]; /* 8-bits */
914 uint8_t *address_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 2]; /* 8-bits */
915 uint8_t *value_pntr
= &xds110
.read_payload
[XDS_IN_LEN
+ 0]; /* 32-bits */
919 xds110
.write_payload
[0] = CMAPI_REG_READ
;
921 *type_pntr
= (uint8_t)(type
& 0xff);
922 *ap_num_pntr
= (uint8_t)(ap_num
& 0xff);
923 *address_pntr
= (uint8_t)(address
& 0xff);
925 success
= xds_execute(XDS_OUT_LEN
+ 3, XDS_IN_LEN
+ 4, DEFAULT_ATTEMPTS
,
930 *value
= xds110_get_u32(value_pntr
);
936 static bool cmapi_write_dap_reg(uint32_t type
, uint32_t ap_num
,
937 uint32_t address
, uint32_t *value
)
939 uint8_t *type_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 8-bits */
940 uint8_t *ap_num_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 1]; /* 8-bits */
941 uint8_t *address_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 2]; /* 8-bits */
942 uint8_t *value_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 3]; /* 32-bits */
949 xds110
.write_payload
[0] = CMAPI_REG_WRITE
;
951 *type_pntr
= (uint8_t)(type
& 0xff);
952 *ap_num_pntr
= (uint8_t)(ap_num
& 0xff);
953 *address_pntr
= (uint8_t)(address
& 0xff);
954 xds110_set_u32(value_pntr
, *value
);
956 success
= xds_execute(XDS_OUT_LEN
+ 7, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
962 static bool swd_connect(void)
966 xds110
.write_payload
[0] = SWD_CONNECT
;
968 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
974 static bool swd_disconnect(void)
978 xds110
.write_payload
[0] = SWD_DISCONNECT
;
980 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
986 static bool cjtag_connect(uint32_t format
)
988 uint8_t *format_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 32-bits */
992 xds110
.write_payload
[0] = CJTAG_CONNECT
;
994 xds110_set_u32(format_pntr
, format
);
996 success
= xds_execute(XDS_OUT_LEN
+ 4, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
1002 static bool cjtag_disconnect(void)
1006 xds110
.write_payload
[0] = CJTAG_DISCONNECT
;
1008 success
= xds_execute(XDS_OUT_LEN
, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
1014 static bool xds_set_supply(uint32_t voltage
)
1016 uint8_t *volts_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 32-bits */
1017 uint8_t *source_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 4]; /* 8-bits */
1021 xds110
.write_payload
[0] = XDS_SET_SUPPLY
;
1023 xds110_set_u32(volts_pntr
, voltage
);
1024 *source_pntr
= (uint8_t)(0 != voltage
? 1 : 0);
1026 success
= xds_execute(XDS_OUT_LEN
+ 5, XDS_IN_LEN
, DEFAULT_ATTEMPTS
,
1032 static bool ocd_dap_request(uint8_t *dap_requests
, uint32_t request_size
,
1033 uint32_t *dap_results
, uint32_t result_count
)
1035 uint8_t *request_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0];
1036 uint8_t *result_pntr
= &xds110
.read_payload
[XDS_IN_LEN
+ 0];
1040 if (NULL
== dap_requests
|| NULL
== dap_results
)
1043 xds110
.write_payload
[0] = OCD_DAP_REQUEST
;
1045 memcpy((void *)request_pntr
, (void *)dap_requests
, request_size
);
1047 success
= xds_execute(XDS_OUT_LEN
+ request_size
,
1048 XDS_IN_LEN
+ (result_count
* 4), DEFAULT_ATTEMPTS
,
1051 if (success
&& (result_count
> 0))
1052 memcpy((void *)dap_results
, (void *)result_pntr
, result_count
* 4);
1057 static bool ocd_scan_request(uint8_t *scan_requests
, uint32_t request_size
,
1058 uint8_t *scan_results
, uint32_t result_size
)
1060 uint8_t *request_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0];
1061 uint8_t *result_pntr
= &xds110
.read_payload
[XDS_IN_LEN
+ 0];
1065 if (NULL
== scan_requests
|| NULL
== scan_results
)
1068 xds110
.write_payload
[0] = OCD_SCAN_REQUEST
;
1070 memcpy((void *)request_pntr
, (void *)scan_requests
, request_size
);
1072 success
= xds_execute(XDS_OUT_LEN
+ request_size
,
1073 XDS_IN_LEN
+ result_size
, DEFAULT_ATTEMPTS
,
1076 if (success
&& (result_size
> 0))
1077 memcpy((void *)scan_results
, (void *)result_pntr
, result_size
);
1082 static bool ocd_pathmove(uint32_t num_states
, uint8_t *path
)
1084 uint8_t *num_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 0]; /* 32-bits */
1085 uint8_t *path_pntr
= &xds110
.write_payload
[XDS_OUT_LEN
+ 4];
1092 xds110
.write_payload
[0] = OCD_PATHMOVE
;
1094 xds110_set_u32(num_pntr
, num_states
);
1096 memcpy((void *)path_pntr
, (void *)path
, num_states
);
1098 success
= xds_execute(XDS_OUT_LEN
+ 4 + num_states
, XDS_IN_LEN
,
1099 DEFAULT_ATTEMPTS
, DEFAULT_TIMEOUT
);
1104 /***************************************************************************
1105 * swd driver interface *
1107 * The following functions provide SWD support to OpenOCD. *
1108 ***************************************************************************/
1110 static int xds110_swd_init(void)
1112 xds110
.is_swd_mode
= true;
1116 static int xds110_swd_switch_seq(enum swd_special_seq seq
)
1123 LOG_ERROR("Sequence SWD line reset (%d) not supported", seq
);
1126 LOG_DEBUG("JTAG-to-SWD");
1127 xds110
.is_swd_mode
= false;
1128 xds110
.is_cmapi_connected
= false;
1129 xds110
.is_cmapi_acquired
= false;
1130 /* Run sequence to put target in SWD mode */
1131 success
= swd_connect();
1132 /* Re-iniitialize CMAPI API for DAP access */
1134 xds110
.is_swd_mode
= true;
1135 success
= cmapi_connect(&idcode
);
1137 xds110
.is_cmapi_connected
= true;
1138 success
= cmapi_acquire();
1143 LOG_DEBUG("SWD-to-JTAG");
1144 xds110
.is_swd_mode
= false;
1145 xds110
.is_cmapi_connected
= false;
1146 xds110
.is_cmapi_acquired
= false;
1147 /* Run sequence to put target in JTAG mode */
1148 success
= swd_disconnect();
1150 /* Re-initialize JTAG interface */
1151 success
= cjtag_connect(MODE_JTAG
);
1155 LOG_ERROR("Sequence %d not supported", seq
);
1165 static bool xds110_legacy_read_reg(uint8_t cmd
, uint32_t *value
)
1167 /* Make sure this is a read request */
1168 bool is_read_request
= (0 != (SWD_CMD_RnW
& cmd
));
1169 /* Determine whether this is a DP or AP register access */
1170 uint32_t type
= (0 != (SWD_CMD_APnDP
& cmd
)) ? DAP_AP
: DAP_DP
;
1171 /* Determine the AP number from cached SELECT value */
1172 uint32_t ap_num
= (xds110
.select
& 0xff000000) >> 24;
1173 /* Extract register address from command */
1174 uint32_t address
= ((cmd
& SWD_CMD_A32
) >> 1);
1175 /* Extract bank address from cached SELECT value */
1176 uint32_t bank
= (xds110
.select
& 0x000000f0);
1178 uint32_t reg_value
= 0;
1179 uint32_t temp_value
= 0;
1183 if (!is_read_request
)
1186 if (DAP_AP
== type
) {
1187 /* Add bank address to register address for CMAPI call */
1191 if (DAP_DP
== type
&& DAP_DP_RDBUFF
== address
&& xds110
.use_rdbuff
) {
1192 /* If RDBUFF is cached and this is a DP RDBUFF read, use the cache */
1193 reg_value
= xds110
.rdbuff
;
1195 } else if (DAP_AP
== type
&& DAP_AP_DRW
== address
&& xds110
.use_rdbuff
) {
1196 /* If RDBUFF is cached and this is an AP DRW read, use the cache, */
1197 /* but still call into the firmware to get the next read. */
1198 reg_value
= xds110
.rdbuff
;
1199 success
= cmapi_read_dap_reg(type
, ap_num
, address
, &temp_value
);
1201 success
= cmapi_read_dap_reg(type
, ap_num
, address
, &temp_value
);
1203 reg_value
= temp_value
;
1206 /* Mark that we have consumed or invalidated the RDBUFF cache */
1207 xds110
.use_rdbuff
= false;
1209 /* Handle result of read attempt */
1211 LOG_ERROR("XDS110: failed to read DAP register");
1212 else if (NULL
!= value
)
1215 if (success
&& DAP_AP
== type
) {
1217 * On a successful DAP AP read, we actually have the value from RDBUFF,
1218 * the firmware will have run the AP request and made the RDBUFF read
1220 xds110
.use_rdbuff
= true;
1221 xds110
.rdbuff
= temp_value
;
1227 static bool xds110_legacy_write_reg(uint8_t cmd
, uint32_t value
)
1229 /* Make sure this isn't a read request */
1230 bool is_read_request
= (0 != (SWD_CMD_RnW
& cmd
));
1231 /* Determine whether this is a DP or AP register access */
1232 uint32_t type
= (0 != (SWD_CMD_APnDP
& cmd
)) ? DAP_AP
: DAP_DP
;
1233 /* Determine the AP number from cached SELECT value */
1234 uint32_t ap_num
= (xds110
.select
& 0xff000000) >> 24;
1235 /* Extract register address from command */
1236 uint32_t address
= ((cmd
& SWD_CMD_A32
) >> 1);
1237 /* Extract bank address from cached SELECT value */
1238 uint32_t bank
= (xds110
.select
& 0x000000f0);
1242 if (is_read_request
)
1245 /* Invalidate the RDBUFF cache */
1246 xds110
.use_rdbuff
= false;
1248 if (DAP_AP
== type
) {
1249 /* Add bank address to register address for CMAPI call */
1251 /* Any write to an AP register invalidates the firmware's cache */
1252 xds110
.is_ap_dirty
= true;
1253 } else if (DAP_DP_SELECT
== address
) {
1254 /* Any write to the SELECT register invalidates the firmware's cache */
1255 xds110
.is_ap_dirty
= true;
1258 success
= cmapi_write_dap_reg(type
, ap_num
, address
, &value
);
1261 LOG_ERROR("XDS110: failed to write DAP register");
1264 * If the debugger wrote to SELECT, cache the value
1265 * to use to build the apNum and address values above
1267 if ((DAP_DP
== type
) && (DAP_DP_SELECT
== address
))
1268 xds110
.select
= value
;
1274 static int xds110_swd_run_queue(void)
1276 static uint32_t dap_results
[MAX_RESULT_QUEUE
];
1281 bool success
= true;
1283 if (0 == xds110
.txn_request_size
)
1286 /* Terminate request queue */
1287 xds110
.txn_requests
[xds110
.txn_request_size
++] = 0;
1289 if (xds110
.firmware
>= OCD_FIRMWARE_VERSION
) {
1290 /* XDS110 firmware has the API to directly handle the queue */
1291 success
= ocd_dap_request(xds110
.txn_requests
,
1292 xds110
.txn_request_size
, dap_results
, xds110
.txn_result_count
);
1294 /* Legacy firmware needs to handle queue via discrete DAP calls */
1297 while (xds110
.txn_requests
[request
] != 0) {
1298 cmd
= xds110
.txn_requests
[request
++];
1299 if (0 == (SWD_CMD_RnW
& cmd
)) {
1300 /* DAP register write command */
1301 value
= (uint32_t)(xds110
.txn_requests
[request
++]) << 0;
1302 value
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 8;
1303 value
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 16;
1304 value
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 24;
1306 success
= xds110_legacy_write_reg(cmd
, value
);
1308 /* DAP register read command */
1311 success
= xds110_legacy_read_reg(cmd
, &value
);
1312 dap_results
[result
++] = value
;
1317 /* Transfer results into caller's buffers */
1318 for (result
= 0; result
< xds110
.txn_result_count
; result
++)
1319 if (0 != xds110
.txn_dap_results
[result
])
1320 *xds110
.txn_dap_results
[result
] = dap_results
[result
];
1322 xds110
.txn_request_size
= 0;
1323 xds110
.txn_result_size
= 0;
1324 xds110
.txn_result_count
= 0;
1326 return (success
) ? ERROR_OK
: ERROR_FAIL
;
1329 static void xds110_swd_queue_cmd(uint8_t cmd
, uint32_t *value
)
1331 /* Check if this is a read or write request */
1332 bool is_read_request
= (0 != (SWD_CMD_RnW
& cmd
));
1333 /* Determine whether this is a DP or AP register access */
1334 uint32_t type
= (0 != (SWD_CMD_APnDP
& cmd
)) ? DAP_AP
: DAP_DP
;
1335 /* Extract register address from command */
1336 uint32_t address
= ((cmd
& SWD_CMD_A32
) >> 1);
1337 uint32_t request_size
= (is_read_request
) ? 1 : 5;
1339 /* Check if new request would be too large to fit */
1340 if (((xds110
.txn_request_size
+ request_size
+ 1) > MAX_DATA_BLOCK
) ||
1341 ((xds110
.txn_result_count
+ 1) > MAX_RESULT_QUEUE
))
1342 xds110_swd_run_queue();
1344 /* Set the START bit in cmd to ensure cmd is not zero */
1345 /* (a value of zero is used to terminate the buffer) */
1346 cmd
|= SWD_CMD_START
;
1348 /* Add request to queue; queue is built marshalled for XDS110 call */
1349 if (is_read_request
) {
1350 /* Queue read request, save pointer to pass back result */
1351 xds110
.txn_requests
[xds110
.txn_request_size
++] = cmd
;
1352 xds110
.txn_dap_results
[xds110
.txn_result_count
++] = value
;
1353 xds110
.txn_result_size
+= 4;
1355 /* Check for and prevent sticky overrun detection */
1356 if (DAP_DP
== type
&& DAP_DP_CTRL
== address
&&
1357 (*value
& CORUNDETECT
)) {
1358 LOG_DEBUG("XDS110: refusing to enable sticky overrun detection");
1359 *value
&= ~CORUNDETECT
;
1361 /* Queue write request, add value directly to queue buffer */
1362 xds110
.txn_requests
[xds110
.txn_request_size
++] = cmd
;
1363 xds110
.txn_requests
[xds110
.txn_request_size
++] = (*value
>> 0) & 0xff;
1364 xds110
.txn_requests
[xds110
.txn_request_size
++] = (*value
>> 8) & 0xff;
1365 xds110
.txn_requests
[xds110
.txn_request_size
++] = (*value
>> 16) & 0xff;
1366 xds110
.txn_requests
[xds110
.txn_request_size
++] = (*value
>> 24) & 0xff;
1370 static void xds110_swd_read_reg(uint8_t cmd
, uint32_t *value
,
1371 uint32_t ap_delay_clk
)
1373 xds110_swd_queue_cmd(cmd
, value
);
1375 static void xds110_swd_write_reg(uint8_t cmd
, uint32_t value
,
1376 uint32_t ap_delay_clk
)
1378 xds110_swd_queue_cmd(cmd
, &value
);
1381 /***************************************************************************
1384 * The following functions provide XDS110 interface to OpenOCD. *
1385 ***************************************************************************/
1387 static void xds110_show_info(void)
1389 uint32_t firmware
= xds110
.firmware
;
1391 LOG_INFO("XDS110: vid/pid = %04x/%04x", xds110
.vid
, xds110
.pid
);
1392 LOG_INFO("XDS110: firmware version = %d.%d.%d.%d",
1393 (((firmware
>> 28) & 0xf) * 10) + ((firmware
>> 24) & 0xf),
1394 (((firmware
>> 20) & 0xf) * 10) + ((firmware
>> 16) & 0xf),
1395 (((firmware
>> 12) & 0xf) * 10) + ((firmware
>> 8) & 0xf),
1396 (((firmware
>> 4) & 0xf) * 10) + ((firmware
>> 0) & 0xf));
1397 LOG_INFO("XDS110: hardware version = 0x%04x", xds110
.hardware
);
1398 if (0 != xds110
.serial
[0])
1399 LOG_INFO("XDS110: serial number = %s", xds110
.serial
);
1400 if (xds110
.is_swd_mode
) {
1401 LOG_INFO("XDS110: connected to target via SWD");
1402 LOG_INFO("XDS110: SWCLK set to %d kHz", xds110
.speed
);
1404 LOG_INFO("XDS110: connected to target via JTAG");
1405 LOG_INFO("XDS110: TCK set to %d kHz", xds110
.speed
);
1408 /* Alert user that there's a better firmware to use */
1409 if (firmware
< OCD_FIRMWARE_VERSION
) {
1410 LOG_WARNING("XDS110: the firmware is not optimized for OpenOCD");
1411 LOG_WARNING(OCD_FIRMWARE_UPGRADE
);
1415 static int xds110_quit(void)
1417 if (xds110
.is_cmapi_acquired
) {
1418 (void)cmapi_release();
1419 xds110
.is_cmapi_acquired
= false;
1421 if (xds110
.is_cmapi_connected
) {
1422 (void)cmapi_disconnect();
1423 xds110
.is_cmapi_connected
= false;
1425 if (xds110
.is_connected
) {
1426 if (xds110
.is_swd_mode
) {
1427 /* Switch out of SWD mode */
1428 (void)swd_disconnect();
1430 /* Switch out of cJTAG mode */
1431 (void)cjtag_disconnect();
1433 /* Tell firmware we're disconnecting */
1434 (void)xds_disconnect();
1435 xds110
.is_connected
= false;
1437 /* Close down the USB connection to the XDS110 debug probe */
1443 static int xds110_init(void)
1447 /* Establish USB connection to the XDS110 debug probe */
1448 success
= usb_connect();
1451 /* Send connect message to XDS110 firmware */
1452 success
= xds_connect();
1454 xds110
.is_connected
= true;
1461 /* Retrieve version IDs from firmware */
1462 /* Version numbers are stored in BCD format */
1463 success
= xds_version(&firmware
, &hardware
);
1465 /* Save the firmware and hardware version */
1466 xds110
.firmware
= firmware
;
1467 xds110
.hardware
= hardware
;
1472 /* Set supply voltage for stand-alone probes */
1473 if (XDS110_STAND_ALONE_ID
== xds110
.hardware
) {
1474 success
= xds_set_supply(xds110
.voltage
);
1475 /* Allow time for target device to power up */
1476 /* (CC32xx takes up to 1300 ms before debug is enabled) */
1478 } else if (0 != xds110
.voltage
) {
1479 /* Voltage supply not a feature of embedded probes */
1481 "XDS110: ignoring supply voltage, not supported on this probe");
1486 success
= xds_set_trst(0);
1488 success
= xds_cycle_tck(50);
1490 success
= xds_set_trst(1);
1492 success
= xds_cycle_tck(50);
1496 if (xds110
.is_swd_mode
) {
1497 /* Switch to SWD if needed */
1498 success
= swd_connect();
1500 success
= cjtag_connect(MODE_JTAG
);
1504 if (success
&& xds110
.is_swd_mode
) {
1507 /* Connect to CMAPI interface in XDS110 */
1508 success
= cmapi_connect(&idcode
);
1510 /* Acquire exclusive access to CMAPI interface */
1512 xds110
.is_cmapi_connected
= true;
1513 success
= cmapi_acquire();
1515 xds110
.is_cmapi_acquired
= true;
1525 return (success
) ? ERROR_OK
: ERROR_FAIL
;
1528 static void xds110_legacy_scan(uint32_t shift_state
, uint32_t total_bits
,
1529 uint32_t end_state
, uint8_t *data_out
, uint8_t *data_in
)
1531 (void)xds_jtag_scan(shift_state
, total_bits
, end_state
, data_out
, data_in
);
1534 static void xds110_legacy_runtest(uint32_t clocks
, uint32_t end_state
)
1536 xds_goto_state(XDS_JTAG_STATE_IDLE
);
1537 xds_cycle_tck(clocks
);
1538 xds_goto_state(end_state
);
1541 static void xds110_legacy_stableclocks(uint32_t clocks
)
1543 xds_cycle_tck(clocks
);
1546 static void xds110_flush(void)
1550 uint32_t shift_state
;
1557 uint8_t data_in
[MAX_DATA_BLOCK
];
1560 if (0 == xds110
.txn_request_size
)
1563 /* Terminate request queue */
1564 xds110
.txn_requests
[xds110
.txn_request_size
++] = 0;
1566 if (xds110
.firmware
>= OCD_FIRMWARE_VERSION
) {
1567 /* Updated firmware has the API to directly handle the queue */
1568 (void)ocd_scan_request(xds110
.txn_requests
, xds110
.txn_request_size
,
1569 data_in
, xds110
.txn_result_size
);
1571 /* Legacy firmware needs to handle queue via discrete JTAG calls */
1574 while (xds110
.txn_requests
[request
] != 0) {
1575 command
= xds110
.txn_requests
[request
++];
1579 if (command
== CMD_IR_SCAN
)
1580 shift_state
= XDS_JTAG_STATE_SHIFT_IR
;
1582 shift_state
= XDS_JTAG_STATE_SHIFT_DR
;
1583 end_state
= (uint32_t)(xds110
.txn_requests
[request
++]);
1584 bits
= (uint32_t)(xds110
.txn_requests
[request
++]) << 0;
1585 bits
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 8;
1586 data_out
= &xds110
.txn_requests
[request
];
1587 bytes
= DIV_ROUND_UP(bits
, 8);
1588 xds110_legacy_scan(shift_state
, bits
, end_state
, data_out
,
1594 clocks
= (uint32_t)(xds110
.txn_requests
[request
++]) << 0;
1595 clocks
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 8;
1596 clocks
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 16;
1597 clocks
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 24;
1598 end_state
= (uint32_t)xds110
.txn_requests
[request
++];
1599 xds110_legacy_runtest(clocks
, end_state
);
1601 case CMD_STABLECLOCKS
:
1602 clocks
= (uint32_t)(xds110
.txn_requests
[request
++]) << 0;
1603 clocks
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 8;
1604 clocks
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 16;
1605 clocks
|= (uint32_t)(xds110
.txn_requests
[request
++]) << 24;
1606 xds110_legacy_stableclocks(clocks
);
1609 LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered",
1617 /* Transfer results into caller's buffers from data_in buffer */
1618 bits
= 0; /* Bit offset into current scan result */
1619 data_pntr
= data_in
;
1620 for (result
= 0; result
< xds110
.txn_result_count
; result
++) {
1621 if (xds110
.txn_scan_results
[result
].first
) {
1623 bytes
= DIV_ROUND_UP(bits
, 8);
1628 if (xds110
.txn_scan_results
[result
].buffer
!= 0)
1629 bit_copy(xds110
.txn_scan_results
[result
].buffer
, 0, data_pntr
,
1630 bits
, xds110
.txn_scan_results
[result
].num_bits
);
1631 bits
+= xds110
.txn_scan_results
[result
].num_bits
;
1634 xds110
.txn_request_size
= 0;
1635 xds110
.txn_result_size
= 0;
1636 xds110
.txn_result_count
= 0;
1639 static int xds110_reset(int trst
, int srst
)
1643 int retval
= ERROR_OK
;
1647 /* Deassert nTRST (active low) */
1650 /* Assert nTRST (active low) */
1653 success
= xds_set_trst(value
);
1655 retval
= ERROR_FAIL
;
1660 /* Deassert nSRST (active low) */
1663 /* Assert nSRST (active low) */
1666 success
= xds_set_srst(value
);
1668 retval
= ERROR_FAIL
;
1670 /* Toggle TCK to trigger HIB on CC13x/CC26x devices */
1671 if (success
&& !xds110
.is_swd_mode
) {
1672 /* Toggle TCK for about 50 ms */
1673 success
= xds_cycle_tck(xds110
.speed
* 50);
1677 retval
= ERROR_FAIL
;
1683 static void xds110_execute_sleep(struct jtag_command
*cmd
)
1685 jtag_sleep(cmd
->cmd
.sleep
->us
);
1689 static void xds110_execute_tlr_reset(struct jtag_command
*cmd
)
1691 (void)xds_goto_state(XDS_JTAG_STATE_RESET
);
1696 static void xds110_execute_pathmove(struct jtag_command
*cmd
)
1699 uint32_t num_states
;
1702 num_states
= (uint32_t)cmd
->cmd
.pathmove
->num_states
;
1704 if (num_states
== 0)
1707 path
= (uint8_t *)malloc(num_states
* sizeof(uint8_t));
1709 LOG_ERROR("XDS110: unable to allocate memory");
1713 /* Convert requested path states into XDS API states */
1714 for (i
= 0; i
< num_states
; i
++)
1715 path
[i
] = (uint8_t)xds_jtag_state
[cmd
->cmd
.pathmove
->path
[i
]];
1717 if (xds110
.firmware
>= OCD_FIRMWARE_VERSION
) {
1718 /* Updated firmware fully supports pathmove */
1719 (void)ocd_pathmove(num_states
, path
);
1721 /* Notify user that legacy firmware simply cannot handle pathmove */
1722 LOG_ERROR("XDS110: the firmware does not support pathmove command");
1723 LOG_ERROR(OCD_FIRMWARE_UPGRADE
);
1724 /* If pathmove is required, then debug is not possible */
1733 static void xds110_queue_scan(struct jtag_command
*cmd
)
1737 uint32_t total_fields
;
1738 uint32_t total_bits
;
1739 uint32_t total_bytes
;
1743 /* Calculate the total number of bits to scan */
1746 for (i
= 0; i
< cmd
->cmd
.scan
->num_fields
; i
++) {
1748 total_bits
+= (uint32_t)cmd
->cmd
.scan
->fields
[i
].num_bits
;
1751 if (total_bits
== 0)
1754 total_bytes
= DIV_ROUND_UP(total_bits
, 8);
1756 /* Check if new request would be too large to fit */
1757 if (((xds110
.txn_request_size
+ 1 + total_bytes
+ sizeof(end_state
) + 1)
1758 > MAX_DATA_BLOCK
) || ((xds110
.txn_result_count
+ total_fields
) >
1762 /* Check if this single request is too large to fit */
1763 if ((1 + total_bytes
+ sizeof(end_state
) + 1) > MAX_DATA_BLOCK
) {
1764 LOG_ERROR("BUG: JTAG scan request is too large to handle (%d bits)",
1766 /* Failing to run this scan mucks up debug on this target */
1770 if (cmd
->cmd
.scan
->ir_scan
)
1771 xds110
.txn_requests
[xds110
.txn_request_size
++] = CMD_IR_SCAN
;
1773 xds110
.txn_requests
[xds110
.txn_request_size
++] = CMD_DR_SCAN
;
1775 end_state
= (uint8_t)xds_jtag_state
[cmd
->cmd
.scan
->end_state
];
1776 xds110
.txn_requests
[xds110
.txn_request_size
++] = end_state
;
1778 xds110
.txn_requests
[xds110
.txn_request_size
++] = (total_bits
>> 0) & 0xff;
1779 xds110
.txn_requests
[xds110
.txn_request_size
++] = (total_bits
>> 8) & 0xff;
1781 /* Build request data by flattening fields into single buffer */
1782 /* also populate the results array to return the results when run */
1784 buffer
= &xds110
.txn_requests
[xds110
.txn_request_size
];
1785 /* Clear data out buffer to default value of all zeros */
1786 memset((void *)buffer
, 0x00, total_bytes
);
1787 for (i
= 0; i
< cmd
->cmd
.scan
->num_fields
; i
++) {
1788 if (cmd
->cmd
.scan
->fields
[i
].out_value
!= 0) {
1789 /* Copy over data to scan out into request buffer */
1790 bit_copy(buffer
, offset
, cmd
->cmd
.scan
->fields
[i
].out_value
, 0,
1791 cmd
->cmd
.scan
->fields
[i
].num_bits
);
1793 offset
+= cmd
->cmd
.scan
->fields
[i
].num_bits
;
1794 xds110
.txn_scan_results
[xds110
.txn_result_count
].first
= (i
== 0);
1795 xds110
.txn_scan_results
[xds110
.txn_result_count
].num_bits
=
1796 cmd
->cmd
.scan
->fields
[i
].num_bits
;
1797 xds110
.txn_scan_results
[xds110
.txn_result_count
++].buffer
=
1798 cmd
->cmd
.scan
->fields
[i
].in_value
;
1800 xds110
.txn_request_size
+= total_bytes
;
1801 xds110
.txn_result_size
+= total_bytes
;
1806 static void xds110_queue_runtest(struct jtag_command
*cmd
)
1808 uint32_t clocks
= (uint32_t)cmd
->cmd
.stableclocks
->num_cycles
;
1809 uint8_t end_state
= (uint8_t)xds_jtag_state
[cmd
->cmd
.runtest
->end_state
];
1811 /* Check if new request would be too large to fit */
1812 if ((xds110
.txn_request_size
+ 1 + sizeof(clocks
) + sizeof(end_state
) + 1)
1816 /* Queue request and cycle count directly to queue buffer */
1817 xds110
.txn_requests
[xds110
.txn_request_size
++] = CMD_RUNTEST
;
1818 xds110
.txn_requests
[xds110
.txn_request_size
++] = (clocks
>> 0) & 0xff;
1819 xds110
.txn_requests
[xds110
.txn_request_size
++] = (clocks
>> 8) & 0xff;
1820 xds110
.txn_requests
[xds110
.txn_request_size
++] = (clocks
>> 16) & 0xff;
1821 xds110
.txn_requests
[xds110
.txn_request_size
++] = (clocks
>> 24) & 0xff;
1822 xds110
.txn_requests
[xds110
.txn_request_size
++] = end_state
;
1827 static void xds110_queue_stableclocks(struct jtag_command
*cmd
)
1829 uint32_t clocks
= (uint32_t)cmd
->cmd
.stableclocks
->num_cycles
;
1831 /* Check if new request would be too large to fit */
1832 if ((xds110
.txn_request_size
+ 1 + sizeof(clocks
) + 1) > MAX_DATA_BLOCK
)
1835 /* Queue request and cycle count directly to queue buffer */
1836 xds110
.txn_requests
[xds110
.txn_request_size
++] = CMD_STABLECLOCKS
;
1837 xds110
.txn_requests
[xds110
.txn_request_size
++] = (clocks
>> 0) & 0xff;
1838 xds110
.txn_requests
[xds110
.txn_request_size
++] = (clocks
>> 8) & 0xff;
1839 xds110
.txn_requests
[xds110
.txn_request_size
++] = (clocks
>> 16) & 0xff;
1840 xds110
.txn_requests
[xds110
.txn_request_size
++] = (clocks
>> 24) & 0xff;
1845 static void xds110_execute_command(struct jtag_command
*cmd
)
1847 switch (cmd
->type
) {
1850 xds110_execute_sleep(cmd
);
1852 case JTAG_TLR_RESET
:
1854 xds110_execute_tlr_reset(cmd
);
1858 xds110_execute_pathmove(cmd
);
1861 xds110_queue_scan(cmd
);
1864 xds110_queue_runtest(cmd
);
1866 case JTAG_STABLECLOCKS
:
1867 xds110_queue_stableclocks(cmd
);
1871 LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered",
1877 static int xds110_execute_queue(void)
1879 struct jtag_command
*cmd
= jtag_command_queue
;
1881 while (cmd
!= NULL
) {
1882 xds110_execute_command(cmd
);
1891 static int xds110_speed(int speed
)
1894 uint32_t delay_count
;
1898 LOG_INFO("XDS110: RTCK not supported");
1899 return ERROR_JTAG_NOT_IMPLEMENTED
;
1902 if (speed
< XDS110_MIN_TCK_SPEED
) {
1903 LOG_INFO("XDS110: increase speed request: %d kHz to %d kHz minimum",
1904 speed
, XDS110_MIN_TCK_SPEED
);
1905 speed
= XDS110_MIN_TCK_SPEED
;
1908 /* Older XDS110 firmware had inefficient scan routines and could only */
1909 /* achieve a peak TCK frequency of about 2500 kHz */
1910 if (xds110
.firmware
< FAST_TCK_FIRMWARE_VERSION
) {
1912 /* Check for request for top speed or higher */
1913 if (speed
>= XDS110_MAX_SLOW_TCK_SPEED
) {
1915 /* Inform user that speed was adjusted down to max possible */
1916 if (speed
> XDS110_MAX_SLOW_TCK_SPEED
) {
1918 "XDS110: reduce speed request: %d kHz to %d kHz maximum",
1919 speed
, XDS110_MAX_SLOW_TCK_SPEED
);
1920 speed
= XDS110_MAX_SLOW_TCK_SPEED
;
1926 const double XDS110_TCK_PULSE_INCREMENT
= 66.0;
1927 freq_to_use
= speed
* 1000; /* Hz */
1930 /* Calculate the delay count value */
1931 double one_giga
= 1000000000;
1932 /* Get the pulse duration for the max frequency supported in ns */
1933 double max_freq_pulse_duration
= one_giga
/
1934 (XDS110_MAX_SLOW_TCK_SPEED
* 1000);
1936 /* Convert frequency to pulse duration */
1937 double freq_to_pulse_width_in_ns
= one_giga
/ freq_to_use
;
1940 * Start with the pulse duration for the maximum frequency. Keep
1941 * decrementing time added by each count value till the requested
1942 * frequency pulse is less than the calculated value.
1944 double current_value
= max_freq_pulse_duration
;
1946 while (current_value
< freq_to_pulse_width_in_ns
) {
1947 current_value
+= XDS110_TCK_PULSE_INCREMENT
;
1952 * Determine which delay count yields the best match.
1953 * The one obtained above or one less.
1956 double diff_freq_1
= freq_to_use
-
1957 (one_giga
/ (max_freq_pulse_duration
+
1958 (XDS110_TCK_PULSE_INCREMENT
* delay_count
)));
1959 double diff_freq_2
= (one_giga
/ (max_freq_pulse_duration
+
1960 (XDS110_TCK_PULSE_INCREMENT
* (delay_count
- 1)))) -
1963 /* One less count value yields a better match */
1964 if (diff_freq_1
> diff_freq_2
)
1969 /* Newer firmware has reworked TCK routines that are much more efficient */
1970 /* and can now achieve a peak TCK frequency of 14000 kHz */
1973 if (speed
>= XDS110_MAX_FAST_TCK_SPEED
) {
1974 if (speed
> XDS110_MAX_FAST_TCK_SPEED
) {
1976 "XDS110: reduce speed request: %d kHz to %d kHz maximum",
1977 speed
, XDS110_MAX_FAST_TCK_SPEED
);
1978 speed
= XDS110_MAX_FAST_TCK_SPEED
;
1981 } else if (speed
>= 12000 && xds110
.firmware
>=
1982 FAST_TCK_PLUS_FIRMWARE_VERSION
) {
1983 delay_count
= FAST_TCK_DELAY_12000_KHZ
;
1984 } else if (speed
>= 10000 && xds110
.firmware
>=
1985 FAST_TCK_PLUS_FIRMWARE_VERSION
) {
1986 delay_count
= FAST_TCK_DELAY_10000_KHZ
;
1987 } else if (speed
>= 8500) {
1988 delay_count
= FAST_TCK_DELAY_8500_KHZ
;
1989 } else if (speed
>= 5500) {
1990 delay_count
= FAST_TCK_DELAY_5500_KHZ
;
1992 /* Calculate the delay count to set the frequency */
1993 /* Formula determined by measuring the waveform on Saeleae logic */
1994 /* analyzer using known values for delay count */
1995 const double m
= 17100000.0; /* slope */
1996 const double b
= -1.02; /* y-intercept */
1998 freq_to_use
= speed
* 1000; /* Hz */
1999 double period
= 1.0/freq_to_use
;
2000 double delay
= m
* period
+ b
;
2005 delay_count
= (uint32_t)delay
;
2009 /* Send the delay count to the XDS110 firmware */
2010 success
= xds_set_tck_delay(delay_count
);
2013 xds110
.delay_count
= delay_count
;
2014 xds110
.speed
= speed
;
2017 return (success
) ? ERROR_OK
: ERROR_FAIL
;
2020 static int xds110_speed_div(int speed
, int *khz
)
2026 static int xds110_khz(int khz
, int *jtag_speed
)
2032 COMMAND_HANDLER(xds110_handle_info_command
)
2038 COMMAND_HANDLER(xds110_handle_serial_command
)
2040 wchar_t serial
[XDS110_SERIAL_LEN
+ 1];
2042 xds110
.serial
[0] = 0;
2044 if (CMD_ARGC
== 1) {
2045 size_t len
= mbstowcs(0, CMD_ARGV
[0], 0);
2046 if (len
> XDS110_SERIAL_LEN
) {
2047 LOG_ERROR("XDS110: serial number is limited to %d characters",
2051 if ((size_t)-1 == mbstowcs(serial
, CMD_ARGV
[0], len
+ 1)) {
2052 LOG_ERROR("XDS110: unable to convert serial number");
2056 for (uint32_t i
= 0; i
< len
; i
++)
2057 xds110
.serial
[i
] = (char)serial
[i
];
2059 xds110
.serial
[len
] = 0;
2061 return ERROR_COMMAND_SYNTAX_ERROR
;
2066 COMMAND_HANDLER(xds110_handle_supply_voltage_command
)
2068 uint32_t voltage
= 0;
2070 if (CMD_ARGC
== 1) {
2071 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[0], voltage
);
2072 if (voltage
== 0 || (voltage
>= XDS110_MIN_VOLTAGE
&& voltage
2073 <= XDS110_MAX_VOLTAGE
)) {
2074 /* Requested voltage is in range */
2075 xds110
.voltage
= voltage
;
2077 LOG_ERROR("XDS110: voltage must be 0 or between %d and %d "
2078 "millivolts", XDS110_MIN_VOLTAGE
, XDS110_MAX_VOLTAGE
);
2081 xds110
.voltage
= voltage
;
2083 return ERROR_COMMAND_SYNTAX_ERROR
;
2088 static const struct command_registration xds110_subcommand_handlers
[] = {
2091 .handler
= &xds110_handle_info_command
,
2092 .mode
= COMMAND_EXEC
,
2093 .help
= "show XDS110 info",
2098 .handler
= &xds110_handle_serial_command
,
2099 .mode
= COMMAND_CONFIG
,
2100 .help
= "set the XDS110 probe serial number",
2101 .usage
= "serial_string",
2105 .handler
= &xds110_handle_supply_voltage_command
,
2106 .mode
= COMMAND_CONFIG
,
2107 .help
= "set the XDS110 probe supply voltage",
2108 .usage
= "voltage_in_millivolts",
2110 COMMAND_REGISTRATION_DONE
2113 static const struct command_registration xds110_command_handlers
[] = {
2116 .mode
= COMMAND_ANY
,
2117 .help
= "perform XDS110 management",
2119 .chain
= xds110_subcommand_handlers
,
2121 COMMAND_REGISTRATION_DONE
2124 static const struct swd_driver xds110_swd_driver
= {
2125 .init
= xds110_swd_init
,
2126 .switch_seq
= xds110_swd_switch_seq
,
2127 .read_reg
= xds110_swd_read_reg
,
2128 .write_reg
= xds110_swd_write_reg
,
2129 .run
= xds110_swd_run_queue
,
2132 static const char * const xds110_transport
[] = { "swd", "jtag", NULL
};
2134 static struct jtag_interface xds110_interface
= {
2135 .execute_queue
= xds110_execute_queue
,
2138 struct adapter_driver xds110_adapter_driver
= {
2140 .transports
= xds110_transport
,
2141 .commands
= xds110_command_handlers
,
2143 .init
= xds110_init
,
2144 .quit
= xds110_quit
,
2145 .reset
= xds110_reset
,
2146 .speed
= xds110_speed
,
2148 .speed_div
= xds110_speed_div
,
2150 .jtag_ops
= &xds110_interface
,
2151 .swd_ops
= &xds110_swd_driver
,
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)