jtag/drivers/bcm2835gpio: fix bcm2835_peri_base output format
[openocd.git] / src / jtag / drivers / am335xgpio.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2022 by Steve Marple, stevemarple@googlemail.com *
5 * *
6 * Based on bcm2835gpio.c and linuxgpiod.c *
7 ***************************************************************************/
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include <jtag/adapter.h>
14 #include <jtag/interface.h>
15 #include <transport/transport.h>
16 #include "bitbang.h"
17
18 #include <sys/mman.h>
19
20 /* GPIO register base addresses. Values taken from "AM335x and AMIC110 Sitara
21 * Processors Technical Reference Manual", Chapter 2 Memory Map.
22 */
23 #define AM335XGPIO_NUM_GPIO_PER_CHIP 32
24 #define AM335XGPIO_NUM_GPIO_CHIPS 4
25 #define AM335XGPIO_GPIO0_HW_ADDR 0x44E07000
26 #define AM335XGPIO_GPIO1_HW_ADDR 0x4804C000
27 #define AM335XGPIO_GPIO2_HW_ADDR 0x481AC000
28 #define AM335XGPIO_GPIO3_HW_ADDR 0x481AE000
29
30 /* 32-bit offsets from GPIO chip base address. Values taken from "AM335x and
31 * AMIC110 Sitara Processors Technical Reference Manual", Chapter 25
32 * General-Purpose Input/Output.
33 */
34 #define AM335XGPIO_GPIO_OE_OFFSET (0x134 / 4)
35 #define AM335XGPIO_GPIO_DATAIN_OFFSET (0x138 / 4)
36 #define AM335XGPIO_GPIO_DATAOUT_OFFSET (0x13C / 4) /* DATAOUT register uses 0 for output, 1 for input */
37 #define AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET (0x190 / 4)
38 #define AM335XGPIO_GPIO_SETDATAOUT_OFFSET (0x194 / 4)
39
40 #define AM335XGPIO_READ_REG(chip_num, offset) \
41 (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)))
42
43 #define AM335XGPIO_WRITE_REG(chip_num, offset, value) \
44 (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) = (value))
45
46 #define AM335XGPIO_SET_REG_BITS(chip_num, offset, bit_mask) \
47 (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) |= (bit_mask))
48
49 #define AM335XGPIO_CLEAR_REG_BITS(chip_num, offset, bit_mask) \
50 (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) &= ~(bit_mask))
51
52 #define AM335XGPIO_SET_INPUT(gpio_config) \
53 AM335XGPIO_SET_REG_BITS((gpio_config)->chip_num, AM335XGPIO_GPIO_OE_OFFSET, BIT((gpio_config)->gpio_num))
54 #define AM335XGPIO_SET_OUTPUT(gpio_config) \
55 AM335XGPIO_CLEAR_REG_BITS((gpio_config)->chip_num, AM335XGPIO_GPIO_OE_OFFSET, BIT((gpio_config)->gpio_num))
56 #define AM335XGPIO_SET_HIGH(gpio_config) \
57 AM335XGPIO_WRITE_REG((gpio_config)->chip_num, AM335XGPIO_GPIO_SETDATAOUT_OFFSET, BIT((gpio_config)->gpio_num))
58 #define AM335XGPIO_SET_LOW(gpio_config) \
59 AM335XGPIO_WRITE_REG((gpio_config)->chip_num, AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET, BIT((gpio_config)->gpio_num))
60
61 enum amx335gpio_initial_gpio_mode {
62 AM335XGPIO_GPIO_MODE_INPUT,
63 AM335XGPIO_GPIO_MODE_OUTPUT_LOW,
64 AM335XGPIO_GPIO_MODE_OUTPUT_HIGH,
65 };
66
67 static const uint32_t am335xgpio_gpio_chip_hw_addr[AM335XGPIO_NUM_GPIO_CHIPS] = {
68 AM335XGPIO_GPIO0_HW_ADDR,
69 AM335XGPIO_GPIO1_HW_ADDR,
70 AM335XGPIO_GPIO2_HW_ADDR,
71 AM335XGPIO_GPIO3_HW_ADDR,
72 };
73
74 /* Memory-mapped address pointers */
75 static volatile uint32_t *am335xgpio_gpio_chip_mmap_addr[AM335XGPIO_NUM_GPIO_CHIPS];
76
77 static int dev_mem_fd;
78 static enum amx335gpio_initial_gpio_mode initial_gpio_mode[ADAPTER_GPIO_IDX_NUM];
79
80 /* Transition delay coefficients */
81 static int speed_coeff = 600000;
82 static int speed_offset = 575;
83 static unsigned int jtag_delay;
84
85 static const struct adapter_gpio_config *adapter_gpio_config;
86
87 static bool is_gpio_config_valid(const struct adapter_gpio_config *gpio_config)
88 {
89 return gpio_config->chip_num >= 0
90 && gpio_config->chip_num < AM335XGPIO_NUM_GPIO_CHIPS
91 && gpio_config->gpio_num >= 0
92 && gpio_config->gpio_num < AM335XGPIO_NUM_GPIO_PER_CHIP;
93 }
94
95 static int get_gpio_value(const struct adapter_gpio_config *gpio_config)
96 {
97 unsigned int shift = gpio_config->gpio_num;
98 uint32_t value = AM335XGPIO_READ_REG(gpio_config->chip_num, AM335XGPIO_GPIO_DATAIN_OFFSET);
99 value = (value >> shift) & 1;
100 return value ^ (gpio_config->active_low ? 1 : 0);
101 }
102
103 static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value)
104 {
105 value = value ^ (gpio_config->active_low ? 1 : 0);
106 switch (gpio_config->drive) {
107 case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL:
108 if (value)
109 AM335XGPIO_SET_HIGH(gpio_config);
110 else
111 AM335XGPIO_SET_LOW(gpio_config);
112 /* For performance reasons assume the GPIO is already set as an output
113 * and therefore the call can be omitted here.
114 */
115 break;
116 case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN:
117 if (value) {
118 AM335XGPIO_SET_INPUT(gpio_config);
119 } else {
120 AM335XGPIO_SET_LOW(gpio_config);
121 AM335XGPIO_SET_OUTPUT(gpio_config);
122 }
123 break;
124 case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE:
125 if (value) {
126 AM335XGPIO_SET_HIGH(gpio_config);
127 AM335XGPIO_SET_OUTPUT(gpio_config);
128 } else {
129 AM335XGPIO_SET_INPUT(gpio_config);
130 }
131 break;
132 }
133 }
134
135 static enum amx335gpio_initial_gpio_mode get_gpio_mode(const struct adapter_gpio_config *gpio_config)
136 {
137 if (AM335XGPIO_READ_REG(gpio_config->chip_num, AM335XGPIO_GPIO_OE_OFFSET) & BIT(gpio_config->gpio_num))
138 return AM335XGPIO_GPIO_MODE_INPUT;
139
140 /* Return output level too so that pin mode can be fully restored */
141 if (AM335XGPIO_READ_REG(gpio_config->chip_num, AM335XGPIO_GPIO_DATAOUT_OFFSET) & BIT(gpio_config->gpio_num))
142 return AM335XGPIO_GPIO_MODE_OUTPUT_HIGH;
143 return AM335XGPIO_GPIO_MODE_OUTPUT_LOW;
144 }
145
146 static const char *get_gpio_mode_name(enum amx335gpio_initial_gpio_mode gpio_mode)
147 {
148 switch (gpio_mode) {
149 case AM335XGPIO_GPIO_MODE_INPUT:
150 return "input";
151 case AM335XGPIO_GPIO_MODE_OUTPUT_LOW:
152 return "output (low)";
153 case AM335XGPIO_GPIO_MODE_OUTPUT_HIGH:
154 return "output (high)";
155 }
156 return "unknown";
157 }
158
159 static void initialize_gpio(enum adapter_gpio_config_index idx)
160 {
161 if (!is_gpio_config_valid(&adapter_gpio_config[idx]))
162 return;
163
164 initial_gpio_mode[idx] = get_gpio_mode(&adapter_gpio_config[idx]);
165 LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %s",
166 adapter_gpio_get_name(idx), adapter_gpio_config[idx].chip_num, adapter_gpio_config[idx].gpio_num,
167 get_gpio_mode_name(initial_gpio_mode[idx]));
168
169 if (adapter_gpio_config[idx].pull != ADAPTER_GPIO_PULL_NONE) {
170 LOG_WARNING("am335xgpio does not support pull-up or pull-down settings (signal %s)",
171 adapter_gpio_get_name(idx));
172 }
173
174 switch (adapter_gpio_config[idx].init_state) {
175 case ADAPTER_GPIO_INIT_STATE_INACTIVE:
176 set_gpio_value(&adapter_gpio_config[idx], 0);
177 break;
178 case ADAPTER_GPIO_INIT_STATE_ACTIVE:
179 set_gpio_value(&adapter_gpio_config[idx], 1);
180 break;
181 case ADAPTER_GPIO_INIT_STATE_INPUT:
182 AM335XGPIO_SET_INPUT(&adapter_gpio_config[idx]);
183 break;
184 }
185
186 /* Direction for non push-pull is already set by set_gpio_value() */
187 if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL
188 && adapter_gpio_config[idx].init_state != ADAPTER_GPIO_INIT_STATE_INPUT)
189 AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[idx]);
190 }
191
192 static void restore_gpio(enum adapter_gpio_config_index idx)
193 {
194 if (is_gpio_config_valid(&adapter_gpio_config[idx])) {
195 switch (initial_gpio_mode[idx]) {
196 case AM335XGPIO_GPIO_MODE_INPUT:
197 AM335XGPIO_SET_INPUT(&adapter_gpio_config[idx]);
198 break;
199 case AM335XGPIO_GPIO_MODE_OUTPUT_LOW:
200 AM335XGPIO_SET_LOW(&adapter_gpio_config[idx]);
201 AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[idx]);
202 break;
203 case AM335XGPIO_GPIO_MODE_OUTPUT_HIGH:
204 AM335XGPIO_SET_HIGH(&adapter_gpio_config[idx]);
205 AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[idx]);
206 break;
207 }
208 }
209 }
210
211 static bb_value_t am335xgpio_read(void)
212 {
213 return get_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDO]) ? BB_HIGH : BB_LOW;
214 }
215
216 static int am335xgpio_write(int tck, int tms, int tdi)
217 {
218 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDI], tdi);
219 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TMS], tms);
220 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TCK], tck); /* Write clock last */
221
222 for (unsigned int i = 0; i < jtag_delay; ++i)
223 asm volatile ("");
224
225 return ERROR_OK;
226 }
227
228 static int am335xgpio_swd_write(int swclk, int swdio)
229 {
230 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio);
231 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */
232
233 for (unsigned int i = 0; i < jtag_delay; ++i)
234 asm volatile ("");
235
236 return ERROR_OK;
237 }
238
239 /* (1) assert or (0) deassert reset lines */
240 static int am335xgpio_reset(int trst, int srst)
241 {
242 /* As the "adapter reset_config" command keeps the srst and trst gpio drive
243 * mode settings in sync we can use our standard set_gpio_value() function
244 * that honours drive mode and active low.
245 */
246 if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST]))
247 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST], srst);
248
249 if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST]))
250 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST], trst);
251
252 LOG_DEBUG("am335xgpio_reset(%d, %d), trst_gpio: %d %d, srst_gpio: %d %d",
253 trst, srst,
254 adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num,
255 adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num);
256 return ERROR_OK;
257 }
258
259 static void am335xgpio_swdio_drive(bool is_output)
260 {
261 if (is_output) {
262 if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR]))
263 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 1);
264 AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]);
265 } else {
266 AM335XGPIO_SET_INPUT(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]);
267 if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR]))
268 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0);
269 }
270 }
271
272 static int am335xgpio_swdio_read(void)
273 {
274 return get_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]);
275 }
276
277 static int am335xgpio_blink(int on)
278 {
279 if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED]))
280 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED], on);
281
282 return ERROR_OK;
283 }
284
285 static struct bitbang_interface am335xgpio_bitbang = {
286 .read = am335xgpio_read,
287 .write = am335xgpio_write,
288 .swdio_read = am335xgpio_swdio_read,
289 .swdio_drive = am335xgpio_swdio_drive,
290 .swd_write = am335xgpio_swd_write,
291 .blink = am335xgpio_blink
292 };
293
294 static int am335xgpio_khz(int khz, int *jtag_speed)
295 {
296 if (!khz) {
297 LOG_DEBUG("RCLK not supported");
298 return ERROR_FAIL;
299 }
300 *jtag_speed = speed_coeff / khz - speed_offset;
301 if (*jtag_speed < 0)
302 *jtag_speed = 0;
303 return ERROR_OK;
304 }
305
306 static int am335xgpio_speed_div(int speed, int *khz)
307 {
308 *khz = speed_coeff / (speed + speed_offset);
309 return ERROR_OK;
310 }
311
312 static int am335xgpio_speed(int speed)
313 {
314 jtag_delay = speed;
315 return ERROR_OK;
316 }
317
318 COMMAND_HANDLER(am335xgpio_handle_speed_coeffs)
319 {
320 if (CMD_ARGC == 2) {
321 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
322 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
323 }
324
325 command_print(CMD, "AM335x GPIO config: speed_coeffs = %d, speed_offset = %d",
326 speed_coeff, speed_offset);
327 return ERROR_OK;
328 }
329
330 static const struct command_registration am335xgpio_subcommand_handlers[] = {
331 {
332 .name = "speed_coeffs",
333 .handler = am335xgpio_handle_speed_coeffs,
334 .mode = COMMAND_CONFIG,
335 .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
336 .usage = "[SPEED_COEFF SPEED_OFFSET]",
337 },
338 COMMAND_REGISTRATION_DONE
339 };
340
341 static const struct command_registration am335xgpio_command_handlers[] = {
342 {
343 .name = "am335xgpio",
344 .mode = COMMAND_ANY,
345 .help = "perform am335xgpio management",
346 .chain = am335xgpio_subcommand_handlers,
347 .usage = "",
348 },
349 COMMAND_REGISTRATION_DONE
350 };
351
352 static const char * const am335xgpio_transports[] = { "jtag", "swd", NULL };
353
354 static struct jtag_interface am335xgpio_interface = {
355 .supported = DEBUG_CAP_TMS_SEQ,
356 .execute_queue = bitbang_execute_queue,
357 };
358
359 static bool am335xgpio_jtag_mode_possible(void)
360 {
361 if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TCK]))
362 return false;
363 if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TMS]))
364 return false;
365 if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDI]))
366 return false;
367 if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDO]))
368 return false;
369 return true;
370 }
371
372 static bool am335xgpio_swd_mode_possible(void)
373 {
374 if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK]))
375 return false;
376 if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]))
377 return false;
378 return true;
379 }
380
381 static void am335xgpio_munmap(void)
382 {
383 for (unsigned int i = 0; i < AM335XGPIO_NUM_GPIO_CHIPS && am335xgpio_gpio_chip_mmap_addr[i] != MAP_FAILED; ++i)
384 if (munmap((void *)am335xgpio_gpio_chip_mmap_addr[i], sysconf(_SC_PAGE_SIZE)) < 0)
385 LOG_ERROR("Cannot unmap GPIO memory for chip %d: %s", i, strerror(errno));
386 }
387
388 static int am335xgpio_init(void)
389 {
390 LOG_INFO("AM335x GPIO JTAG/SWD bitbang driver");
391
392 bitbang_interface = &am335xgpio_bitbang;
393 adapter_gpio_config = adapter_gpio_get_config();
394
395 if (transport_is_jtag() && !am335xgpio_jtag_mode_possible()) {
396 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
397 return ERROR_JTAG_INIT_FAILED;
398 }
399
400 if (transport_is_swd() && !am335xgpio_swd_mode_possible()) {
401 LOG_ERROR("Require swclk and swdio gpio for SWD mode");
402 return ERROR_JTAG_INIT_FAILED;
403 }
404
405 dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
406 if (dev_mem_fd < 0) {
407 LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
408 dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
409 }
410 if (dev_mem_fd < 0) {
411 LOG_ERROR("open: %s", strerror(errno));
412 return ERROR_JTAG_INIT_FAILED;
413 }
414
415 for (unsigned int i = 0; i < AM335XGPIO_NUM_GPIO_CHIPS; ++i) {
416 am335xgpio_gpio_chip_mmap_addr[i] = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
417 MAP_SHARED, dev_mem_fd, am335xgpio_gpio_chip_hw_addr[i]);
418
419 if (am335xgpio_gpio_chip_mmap_addr[i] == MAP_FAILED) {
420 LOG_ERROR("mmap: %s", strerror(errno));
421 am335xgpio_munmap();
422 close(dev_mem_fd);
423 return ERROR_JTAG_INIT_FAILED;
424 }
425 }
426 close(dev_mem_fd);
427
428 /* Configure JTAG/SWD signals. Default directions and initial states are handled
429 * by adapter.c and "adapter gpio" command.
430 */
431 if (transport_is_jtag()) {
432 initialize_gpio(ADAPTER_GPIO_IDX_TDO);
433 initialize_gpio(ADAPTER_GPIO_IDX_TDI);
434 initialize_gpio(ADAPTER_GPIO_IDX_TMS);
435 initialize_gpio(ADAPTER_GPIO_IDX_TCK);
436 initialize_gpio(ADAPTER_GPIO_IDX_TRST);
437 }
438
439 if (transport_is_swd()) {
440 /* swdio and its buffer should be initialized in the order that prevents
441 * two outputs from being connected together. This will occur if the
442 * swdio GPIO of the AM335x is configured as an output while its
443 * external buffer is configured to send the swdio signal from the
444 * target to the AM335x.
445 */
446 if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) {
447 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO);
448 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
449 } else {
450 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
451 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO);
452 }
453
454 initialize_gpio(ADAPTER_GPIO_IDX_SWCLK);
455 }
456
457 initialize_gpio(ADAPTER_GPIO_IDX_SRST);
458 initialize_gpio(ADAPTER_GPIO_IDX_LED);
459
460 return ERROR_OK;
461 }
462
463 static int am335xgpio_quit(void)
464 {
465 if (transport_is_jtag()) {
466 restore_gpio(ADAPTER_GPIO_IDX_TDO);
467 restore_gpio(ADAPTER_GPIO_IDX_TDI);
468 restore_gpio(ADAPTER_GPIO_IDX_TMS);
469 restore_gpio(ADAPTER_GPIO_IDX_TCK);
470 restore_gpio(ADAPTER_GPIO_IDX_TRST);
471 }
472
473 if (transport_is_swd()) {
474 /* Restore swdio/swdio_dir to their initial modes, even if that means
475 * connecting two outputs. Begin by making swdio an input so that the
476 * current and final states of swdio and swdio_dir do not have to be
477 * considered to calculate the safe restoration order.
478 */
479 AM335XGPIO_SET_INPUT(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]);
480 restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
481 restore_gpio(ADAPTER_GPIO_IDX_SWDIO);
482
483 restore_gpio(ADAPTER_GPIO_IDX_SWCLK);
484 }
485
486 restore_gpio(ADAPTER_GPIO_IDX_SRST);
487 restore_gpio(ADAPTER_GPIO_IDX_LED);
488
489 am335xgpio_munmap();
490
491 return ERROR_OK;
492 }
493
494 struct adapter_driver am335xgpio_adapter_driver = {
495 .name = "am335xgpio",
496 .transports = am335xgpio_transports,
497 .commands = am335xgpio_command_handlers,
498
499 .init = am335xgpio_init,
500 .quit = am335xgpio_quit,
501 .reset = am335xgpio_reset,
502 .speed = am335xgpio_speed,
503 .khz = am335xgpio_khz,
504 .speed_div = am335xgpio_speed_div,
505
506 .jtag_ops = &am335xgpio_interface,
507 .swd_ops = &bitbang_swd,
508 };

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)