jtag/drivers/bcm2835gpio: use rounding in delay math
[openocd.git] / src / jtag / drivers / bcm2835gpio.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2013 by Paul Fertser, fercerpav@gmail.com *
5 * *
6 * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au *
7 * Based on at91rm9200.c (c) Anders Larsen *
8 * and RPi GPIO examples by Gert van Loo & Dom *
9 ***************************************************************************/
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include <jtag/adapter.h>
16 #include <jtag/interface.h>
17 #include <transport/transport.h>
18 #include "bitbang.h"
19
20 #include <sys/mman.h>
21
22 uint32_t bcm2835_peri_base = 0x20000000;
23 #define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */
24
25 #define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000)
26 #define BCM2835_PADS_GPIO_0_27_OFFSET (0x2c / 4)
27
28 /* See "GPIO Function Select Registers (GPFSELn)" in "Broadcom BCM2835 ARM Peripherals" datasheet. */
29 #define BCM2835_GPIO_MODE_INPUT 0
30 #define BCM2835_GPIO_MODE_OUTPUT 1
31
32 /* GPIO setup macros */
33 #define MODE_GPIO(g) (*(pio_base+((g)/10))>>(((g)%10)*3) & 7)
34 #define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0)
35 #define SET_MODE_GPIO(g, m) do { /* clear the mode bits first, then set as necessary */ \
36 INP_GPIO(g); \
37 *(pio_base+((g)/10)) |= ((m)<<(((g)%10)*3)); } while (0)
38 #define OUT_GPIO(g) SET_MODE_GPIO(g, BCM2835_GPIO_MODE_OUTPUT)
39
40 #define GPIO_SET (*(pio_base+7)) /* sets bits which are 1, ignores bits which are 0 */
41 #define GPIO_CLR (*(pio_base+10)) /* clears bits which are 1, ignores bits which are 0 */
42 #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */
43
44 static int dev_mem_fd;
45 static volatile uint32_t *pio_base = MAP_FAILED;
46 static volatile uint32_t *pads_base = MAP_FAILED;
47
48 /* Transition delay coefficients */
49 static int speed_coeff = 113714;
50 static int speed_offset = 28;
51 static unsigned int jtag_delay;
52
53 static const struct adapter_gpio_config *adapter_gpio_config;
54 static struct initial_gpio_state {
55 unsigned int mode;
56 unsigned int output_level;
57 } initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
58 static uint32_t initial_drive_strength_etc;
59
60 static inline void bcm2835_gpio_synchronize(void)
61 {
62 /* Ensure that previous writes to GPIO registers are flushed out of
63 * the inner shareable domain to prevent pipelined writes to the
64 * same address being merged.
65 */
66 __sync_synchronize();
67 }
68
69 static bool is_gpio_config_valid(enum adapter_gpio_config_index idx)
70 {
71 /* Only chip 0 is supported, accept unset value (-1) too */
72 return adapter_gpio_config[idx].chip_num >= -1
73 && adapter_gpio_config[idx].chip_num <= 0
74 && adapter_gpio_config[idx].gpio_num >= 0
75 && adapter_gpio_config[idx].gpio_num <= 31;
76 }
77
78 static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value)
79 {
80 value = value ^ (gpio_config->active_low ? 1 : 0);
81 switch (gpio_config->drive) {
82 case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL:
83 if (value)
84 GPIO_SET = 1 << gpio_config->gpio_num;
85 else
86 GPIO_CLR = 1 << gpio_config->gpio_num;
87 /* For performance reasons assume the GPIO is already set as an output
88 * and therefore the call can be omitted here.
89 */
90 break;
91 case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN:
92 if (value) {
93 INP_GPIO(gpio_config->gpio_num);
94 } else {
95 GPIO_CLR = 1 << gpio_config->gpio_num;
96 OUT_GPIO(gpio_config->gpio_num);
97 }
98 break;
99 case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE:
100 if (value) {
101 GPIO_SET = 1 << gpio_config->gpio_num;
102 OUT_GPIO(gpio_config->gpio_num);
103 } else {
104 INP_GPIO(gpio_config->gpio_num);
105 }
106 break;
107 }
108 bcm2835_gpio_synchronize();
109 }
110
111 static void restore_gpio(enum adapter_gpio_config_index idx)
112 {
113 if (is_gpio_config_valid(idx)) {
114 SET_MODE_GPIO(adapter_gpio_config[idx].gpio_num, initial_gpio_state[idx].mode);
115 if (initial_gpio_state[idx].mode == BCM2835_GPIO_MODE_OUTPUT) {
116 if (initial_gpio_state[idx].output_level)
117 GPIO_SET = 1 << adapter_gpio_config[idx].gpio_num;
118 else
119 GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num;
120 }
121 }
122 bcm2835_gpio_synchronize();
123 }
124
125 static void initialize_gpio(enum adapter_gpio_config_index idx)
126 {
127 if (!is_gpio_config_valid(idx))
128 return;
129
130 initial_gpio_state[idx].mode = MODE_GPIO(adapter_gpio_config[idx].gpio_num);
131 unsigned int shift = adapter_gpio_config[idx].gpio_num;
132 initial_gpio_state[idx].output_level = (GPIO_LEV >> shift) & 1;
133 LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %d",
134 adapter_gpio_get_name(idx), adapter_gpio_config[idx].chip_num, adapter_gpio_config[idx].gpio_num,
135 initial_gpio_state[idx].mode);
136
137 if (adapter_gpio_config[idx].pull != ADAPTER_GPIO_PULL_NONE) {
138 LOG_WARNING("BCM2835 GPIO does not support pull-up or pull-down settings (signal %s)",
139 adapter_gpio_get_name(idx));
140 }
141
142 switch (adapter_gpio_config[idx].init_state) {
143 case ADAPTER_GPIO_INIT_STATE_INACTIVE:
144 set_gpio_value(&adapter_gpio_config[idx], 0);
145 break;
146 case ADAPTER_GPIO_INIT_STATE_ACTIVE:
147 set_gpio_value(&adapter_gpio_config[idx], 1);
148 break;
149 case ADAPTER_GPIO_INIT_STATE_INPUT:
150 INP_GPIO(adapter_gpio_config[idx].gpio_num);
151 break;
152 }
153
154 /* Direction for non push-pull is already set by set_gpio_value() */
155 if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL)
156 OUT_GPIO(adapter_gpio_config[idx].gpio_num);
157 bcm2835_gpio_synchronize();
158 }
159
160 static bb_value_t bcm2835gpio_read(void)
161 {
162 unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num;
163 uint32_t value = (GPIO_LEV >> shift) & 1;
164 return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].active_low ? BB_HIGH : BB_LOW);
165
166 }
167
168 static int bcm2835gpio_write(int tck, int tms, int tdi)
169 {
170 uint32_t set = tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num |
171 tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num |
172 tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num;
173 uint32_t clear = !tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num |
174 !tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num |
175 !tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num;
176
177 GPIO_SET = set;
178 GPIO_CLR = clear;
179 bcm2835_gpio_synchronize();
180
181 for (unsigned int i = 0; i < jtag_delay; i++)
182 asm volatile ("");
183
184 return ERROR_OK;
185 }
186
187 /* Requires push-pull drive mode for swclk and swdio */
188 static int bcm2835gpio_swd_write_fast(int swclk, int swdio)
189 {
190 swclk = swclk ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].active_low ? 1 : 0);
191 swdio = swdio ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0);
192
193 uint32_t set = swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num |
194 swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
195 uint32_t clear = !swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num |
196 !swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
197
198 GPIO_SET = set;
199 GPIO_CLR = clear;
200 bcm2835_gpio_synchronize();
201
202 for (unsigned int i = 0; i < jtag_delay; i++)
203 asm volatile ("");
204
205 return ERROR_OK;
206 }
207
208 /* Generic mode that works for open-drain/open-source drive modes, but slower */
209 static int bcm2835gpio_swd_write_generic(int swclk, int swdio)
210 {
211 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio);
212 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */
213
214 for (unsigned int i = 0; i < jtag_delay; ++i)
215 asm volatile ("");
216
217 return ERROR_OK;
218 }
219
220 /* (1) assert or (0) deassert reset lines */
221 static int bcm2835gpio_reset(int trst, int srst)
222 {
223 /* As the "adapter reset_config" command keeps the srst and trst gpio drive
224 * mode settings in sync we can use our standard set_gpio_value() function
225 * that honours drive mode and active low.
226 */
227 if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SRST))
228 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST], srst);
229
230 if (is_gpio_config_valid(ADAPTER_GPIO_IDX_TRST))
231 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST], trst);
232
233 LOG_DEBUG("BCM2835 GPIO: bcm2835gpio_reset(%d, %d), trst_gpio: %d %d, srst_gpio: %d %d",
234 trst, srst,
235 adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num,
236 adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num, adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num);
237 return ERROR_OK;
238 }
239
240 static void bcm2835_swdio_drive(bool is_output)
241 {
242 if (is_output) {
243 if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
244 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 1);
245 OUT_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
246 } else {
247 INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
248 if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
249 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0);
250 }
251 bcm2835_gpio_synchronize();
252 }
253
254 static int bcm2835_swdio_read(void)
255 {
256 unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
257 uint32_t value = (GPIO_LEV >> shift) & 1;
258 return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0);
259 }
260
261 static int bcm2835gpio_khz(int khz, int *jtag_speed)
262 {
263 if (!khz) {
264 LOG_DEBUG("BCM2835 GPIO: RCLK not supported");
265 return ERROR_FAIL;
266 }
267 *jtag_speed = DIV_ROUND_UP(speed_coeff, khz) - speed_offset;
268 LOG_DEBUG("jtag_delay %d", *jtag_speed);
269 if (*jtag_speed < 0)
270 *jtag_speed = 0;
271 return ERROR_OK;
272 }
273
274 static int bcm2835gpio_speed_div(int speed, int *khz)
275 {
276 int divisor = speed + speed_offset;
277 /* divide with roundig to the closest */
278 *khz = (speed_coeff + divisor / 2) / divisor;
279 return ERROR_OK;
280 }
281
282 static int bcm2835gpio_speed(int speed)
283 {
284 jtag_delay = speed;
285 return ERROR_OK;
286 }
287
288 COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs)
289 {
290 if (CMD_ARGC == 2) {
291 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
292 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
293 }
294
295 command_print(CMD, "BCM2835 GPIO: speed_coeffs = %d, speed_offset = %d",
296 speed_coeff, speed_offset);
297 return ERROR_OK;
298 }
299
300 COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base)
301 {
302 if (CMD_ARGC == 1)
303 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bcm2835_peri_base);
304
305 command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08x",
306 bcm2835_peri_base);
307 return ERROR_OK;
308 }
309
310 static const struct command_registration bcm2835gpio_subcommand_handlers[] = {
311 {
312 .name = "speed_coeffs",
313 .handler = &bcm2835gpio_handle_speed_coeffs,
314 .mode = COMMAND_CONFIG,
315 .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
316 .usage = "[SPEED_COEFF SPEED_OFFSET]",
317 },
318 {
319 .name = "peripheral_base",
320 .handler = &bcm2835gpio_handle_peripheral_base,
321 .mode = COMMAND_CONFIG,
322 .help = "peripheral base to access GPIOs (RPi1 0x20000000, RPi2 0x3F000000).",
323 .usage = "[base]",
324 },
325
326 COMMAND_REGISTRATION_DONE
327 };
328
329 static const struct command_registration bcm2835gpio_command_handlers[] = {
330 {
331 .name = "bcm2835gpio",
332 .mode = COMMAND_ANY,
333 .help = "perform bcm2835gpio management",
334 .chain = bcm2835gpio_subcommand_handlers,
335 .usage = "",
336 },
337 COMMAND_REGISTRATION_DONE
338 };
339
340 static bool bcm2835gpio_jtag_mode_possible(void)
341 {
342 if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TCK))
343 return false;
344 if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TMS))
345 return false;
346 if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDI))
347 return false;
348 if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDO))
349 return false;
350 return true;
351 }
352
353 static bool bcm2835gpio_swd_mode_possible(void)
354 {
355 if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWCLK))
356 return false;
357 if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO))
358 return false;
359 return true;
360 }
361
362 static void bcm2835gpio_munmap(void)
363 {
364 if (pio_base != MAP_FAILED) {
365 munmap((void *)pio_base, sysconf(_SC_PAGE_SIZE));
366 pio_base = MAP_FAILED;
367 }
368
369 if (pads_base != MAP_FAILED) {
370 munmap((void *)pads_base, sysconf(_SC_PAGE_SIZE));
371 pads_base = MAP_FAILED;
372 }
373 }
374
375 static int bcm2835gpio_blink(int on)
376 {
377 if (is_gpio_config_valid(ADAPTER_GPIO_IDX_LED))
378 set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED], on);
379
380 return ERROR_OK;
381 }
382
383 static struct bitbang_interface bcm2835gpio_bitbang = {
384 .read = bcm2835gpio_read,
385 .write = bcm2835gpio_write,
386 .swdio_read = bcm2835_swdio_read,
387 .swdio_drive = bcm2835_swdio_drive,
388 .swd_write = bcm2835gpio_swd_write_generic,
389 .blink = bcm2835gpio_blink,
390 };
391
392 static int bcm2835gpio_init(void)
393 {
394 LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver");
395
396 bitbang_interface = &bcm2835gpio_bitbang;
397 adapter_gpio_config = adapter_gpio_get_config();
398
399 if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) {
400 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
401 return ERROR_JTAG_INIT_FAILED;
402 }
403
404 if (transport_is_swd() && !bcm2835gpio_swd_mode_possible()) {
405 LOG_ERROR("Require swclk and swdio gpio for SWD mode");
406 return ERROR_JTAG_INIT_FAILED;
407 }
408
409 dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
410 if (dev_mem_fd < 0) {
411 LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
412 dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
413 }
414 if (dev_mem_fd < 0) {
415 LOG_ERROR("open: %s", strerror(errno));
416 return ERROR_JTAG_INIT_FAILED;
417 }
418
419 pio_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
420 MAP_SHARED, dev_mem_fd, BCM2835_GPIO_BASE);
421
422 if (pio_base == MAP_FAILED) {
423 LOG_ERROR("mmap: %s", strerror(errno));
424 close(dev_mem_fd);
425 return ERROR_JTAG_INIT_FAILED;
426 }
427
428 pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
429 MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27);
430
431 if (pads_base == MAP_FAILED) {
432 LOG_ERROR("mmap: %s", strerror(errno));
433 bcm2835gpio_munmap();
434 close(dev_mem_fd);
435 return ERROR_JTAG_INIT_FAILED;
436 }
437
438 close(dev_mem_fd);
439
440 /* set 4mA drive strength, slew rate limited, hysteresis on */
441 initial_drive_strength_etc = pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] & 0x1f;
442 pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
443
444 /* Configure JTAG/SWD signals. Default directions and initial states are handled
445 * by adapter.c and "adapter gpio" command.
446 */
447 if (transport_is_jtag()) {
448 initialize_gpio(ADAPTER_GPIO_IDX_TDO);
449 initialize_gpio(ADAPTER_GPIO_IDX_TDI);
450 initialize_gpio(ADAPTER_GPIO_IDX_TMS);
451 initialize_gpio(ADAPTER_GPIO_IDX_TCK);
452 initialize_gpio(ADAPTER_GPIO_IDX_TRST);
453 }
454
455 if (transport_is_swd()) {
456 /* swdio and its buffer should be initialized in the order that prevents
457 * two outputs from being connected together. This will occur if the
458 * swdio GPIO of the AM335x is configured as an output while its
459 * external buffer is configured to send the swdio signal from the
460 * target to the AM335x.
461 */
462 if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) {
463 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO);
464 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
465 } else {
466 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
467 initialize_gpio(ADAPTER_GPIO_IDX_SWDIO);
468 }
469
470 initialize_gpio(ADAPTER_GPIO_IDX_SWCLK);
471
472 if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL &&
473 adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL) {
474 LOG_DEBUG("BCM2835 GPIO using fast mode for SWD write");
475 bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_fast;
476 } else {
477 LOG_DEBUG("BCM2835 GPIO using generic mode for SWD write");
478 bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_generic;
479 }
480 }
481
482 initialize_gpio(ADAPTER_GPIO_IDX_SRST);
483 initialize_gpio(ADAPTER_GPIO_IDX_LED);
484
485 return ERROR_OK;
486 }
487
488 static int bcm2835gpio_quit(void)
489 {
490 if (transport_is_jtag()) {
491 restore_gpio(ADAPTER_GPIO_IDX_TDO);
492 restore_gpio(ADAPTER_GPIO_IDX_TDI);
493 restore_gpio(ADAPTER_GPIO_IDX_TCK);
494 restore_gpio(ADAPTER_GPIO_IDX_TMS);
495 restore_gpio(ADAPTER_GPIO_IDX_TRST);
496 }
497
498 if (transport_is_swd()) {
499 /* Restore swdio/swdio_dir to their initial modes, even if that means
500 * connecting two outputs. Begin by making swdio an input so that the
501 * current and final states of swdio and swdio_dir do not have to be
502 * considered to calculate the safe restoration order.
503 */
504 INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
505 restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
506 restore_gpio(ADAPTER_GPIO_IDX_SWDIO);
507 restore_gpio(ADAPTER_GPIO_IDX_SWCLK);
508 }
509
510 restore_gpio(ADAPTER_GPIO_IDX_SRST);
511 restore_gpio(ADAPTER_GPIO_IDX_LED);
512
513 /* Restore drive strength. MSB is password ("5A") */
514 pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5A000000 | initial_drive_strength_etc;
515 bcm2835gpio_munmap();
516
517 return ERROR_OK;
518 }
519
520
521 static const char * const bcm2835_transports[] = { "jtag", "swd", NULL };
522
523 static struct jtag_interface bcm2835gpio_interface = {
524 .supported = DEBUG_CAP_TMS_SEQ,
525 .execute_queue = bitbang_execute_queue,
526 };
527 struct adapter_driver bcm2835gpio_adapter_driver = {
528 .name = "bcm2835gpio",
529 .transports = bcm2835_transports,
530 .commands = bcm2835gpio_command_handlers,
531
532 .init = bcm2835gpio_init,
533 .quit = bcm2835gpio_quit,
534 .reset = bcm2835gpio_reset,
535 .speed = bcm2835gpio_speed,
536 .khz = bcm2835gpio_khz,
537 .speed_div = bcm2835gpio_speed_div,
538
539 .jtag_ops = &bcm2835gpio_interface,
540 .swd_ops = &bitbang_swd,
541 };

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)