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

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)