openocd: fix incorrect doxygen comments
[openocd.git] / src / jtag / drivers / bcm2835gpio.c
1 /***************************************************************************
2 * Copyright (C) 2013 by Paul Fertser, fercerpav@gmail.com *
3 * *
4 * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au *
5 * Based on at91rm9200.c (c) Anders Larsen *
6 * and RPi GPIO examples by Gert van Loo & Dom *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
20 ***************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <jtag/interface.h>
27 #include <transport/transport.h>
28 #include "bitbang.h"
29
30 #include <sys/mman.h>
31
32 uint32_t bcm2835_peri_base = 0x20000000;
33 #define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */
34
35 #define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000)
36 #define BCM2835_PADS_GPIO_0_27_OFFSET (0x2c / 4)
37
38 /* GPIO setup macros */
39 #define MODE_GPIO(g) (*(pio_base+((g)/10))>>(((g)%10)*3) & 7)
40 #define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0)
41 #define SET_MODE_GPIO(g, m) do { /* clear the mode bits first, then set as necessary */ \
42 INP_GPIO(g); \
43 *(pio_base+((g)/10)) |= ((m)<<(((g)%10)*3)); } while (0)
44 #define OUT_GPIO(g) SET_MODE_GPIO(g, 1)
45
46 #define GPIO_SET (*(pio_base+7)) /* sets bits which are 1, ignores bits which are 0 */
47 #define GPIO_CLR (*(pio_base+10)) /* clears bits which are 1, ignores bits which are 0 */
48 #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */
49
50 static int dev_mem_fd;
51 static volatile uint32_t *pio_base;
52
53 static bb_value_t bcm2835gpio_read(void);
54 static int bcm2835gpio_write(int tck, int tms, int tdi);
55
56 static int bcm2835_swdio_read(void);
57 static void bcm2835_swdio_drive(bool is_output);
58 static int bcm2835gpio_swd_write(int swclk, int swdio);
59
60 static int bcm2835gpio_init(void);
61 static int bcm2835gpio_quit(void);
62
63 static struct bitbang_interface bcm2835gpio_bitbang = {
64 .read = bcm2835gpio_read,
65 .write = bcm2835gpio_write,
66 .swdio_read = bcm2835_swdio_read,
67 .swdio_drive = bcm2835_swdio_drive,
68 .swd_write = bcm2835gpio_swd_write,
69 .blink = NULL
70 };
71
72 /* GPIO numbers for each signal. Negative values are invalid */
73 static int tck_gpio = -1;
74 static int tck_gpio_mode;
75 static int tms_gpio = -1;
76 static int tms_gpio_mode;
77 static int tdi_gpio = -1;
78 static int tdi_gpio_mode;
79 static int tdo_gpio = -1;
80 static int tdo_gpio_mode;
81 static int trst_gpio = -1;
82 static int trst_gpio_mode;
83 static int srst_gpio = -1;
84 static int srst_gpio_mode;
85 static int swclk_gpio = -1;
86 static int swclk_gpio_mode;
87 static int swdio_gpio = -1;
88 static int swdio_gpio_mode;
89
90 /* Transition delay coefficients */
91 static int speed_coeff = 113714;
92 static int speed_offset = 28;
93 static unsigned int jtag_delay;
94
95 static bb_value_t bcm2835gpio_read(void)
96 {
97 return (GPIO_LEV & 1<<tdo_gpio) ? BB_HIGH : BB_LOW;
98 }
99
100 static int bcm2835gpio_write(int tck, int tms, int tdi)
101 {
102 uint32_t set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio;
103 uint32_t clear = !tck<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio;
104
105 GPIO_SET = set;
106 GPIO_CLR = clear;
107
108 for (unsigned int i = 0; i < jtag_delay; i++)
109 asm volatile ("");
110
111 return ERROR_OK;
112 }
113
114 static int bcm2835gpio_swd_write(int swclk, int swdio)
115 {
116 uint32_t set = swclk << swclk_gpio | swdio << swdio_gpio;
117 uint32_t clear = !swclk << swclk_gpio | !swdio << swdio_gpio;
118
119 GPIO_SET = set;
120 GPIO_CLR = clear;
121
122 for (unsigned int i = 0; i < jtag_delay; i++)
123 asm volatile ("");
124
125 return ERROR_OK;
126 }
127
128 /* (1) assert or (0) deassert reset lines */
129 static int bcm2835gpio_reset(int trst, int srst)
130 {
131 uint32_t set = 0;
132 uint32_t clear = 0;
133
134 if (trst_gpio > 0) {
135 set |= !trst<<trst_gpio;
136 clear |= trst<<trst_gpio;
137 }
138
139 if (srst_gpio > 0) {
140 set |= !srst<<srst_gpio;
141 clear |= srst<<srst_gpio;
142 }
143
144 GPIO_SET = set;
145 GPIO_CLR = clear;
146
147 return ERROR_OK;
148 }
149
150 static void bcm2835_swdio_drive(bool is_output)
151 {
152 if (is_output)
153 OUT_GPIO(swdio_gpio);
154 else
155 INP_GPIO(swdio_gpio);
156 }
157
158 static int bcm2835_swdio_read(void)
159 {
160 return !!(GPIO_LEV & 1 << swdio_gpio);
161 }
162
163 static int bcm2835gpio_khz(int khz, int *jtag_speed)
164 {
165 if (!khz) {
166 LOG_DEBUG("RCLK not supported");
167 return ERROR_FAIL;
168 }
169 *jtag_speed = speed_coeff/khz - speed_offset;
170 if (*jtag_speed < 0)
171 *jtag_speed = 0;
172 return ERROR_OK;
173 }
174
175 static int bcm2835gpio_speed_div(int speed, int *khz)
176 {
177 *khz = speed_coeff/(speed + speed_offset);
178 return ERROR_OK;
179 }
180
181 static int bcm2835gpio_speed(int speed)
182 {
183 jtag_delay = speed;
184 return ERROR_OK;
185 }
186
187 static int is_gpio_valid(int gpio)
188 {
189 return gpio >= 0 && gpio <= 53;
190 }
191
192 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums)
193 {
194 if (CMD_ARGC == 4) {
195 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
196 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
197 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
198 COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
199 } else if (CMD_ARGC != 0) {
200 return ERROR_COMMAND_SYNTAX_ERROR;
201 }
202
203 command_print(CMD,
204 "BCM2835 GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d",
205 tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
206
207 return ERROR_OK;
208 }
209
210 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tck)
211 {
212 if (CMD_ARGC == 1)
213 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
214
215 command_print(CMD, "BCM2835 GPIO config: tck = %d", tck_gpio);
216 return ERROR_OK;
217 }
218
219 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tms)
220 {
221 if (CMD_ARGC == 1)
222 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
223
224 command_print(CMD, "BCM2835 GPIO config: tms = %d", tms_gpio);
225 return ERROR_OK;
226 }
227
228 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdo)
229 {
230 if (CMD_ARGC == 1)
231 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
232
233 command_print(CMD, "BCM2835 GPIO config: tdo = %d", tdo_gpio);
234 return ERROR_OK;
235 }
236
237 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdi)
238 {
239 if (CMD_ARGC == 1)
240 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
241
242 command_print(CMD, "BCM2835 GPIO config: tdi = %d", tdi_gpio);
243 return ERROR_OK;
244 }
245
246 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_srst)
247 {
248 if (CMD_ARGC == 1)
249 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
250
251 command_print(CMD, "BCM2835 GPIO config: srst = %d", srst_gpio);
252 return ERROR_OK;
253 }
254
255 COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_trst)
256 {
257 if (CMD_ARGC == 1)
258 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
259
260 command_print(CMD, "BCM2835 GPIO config: trst = %d", trst_gpio);
261 return ERROR_OK;
262 }
263
264 COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionums)
265 {
266 if (CMD_ARGC == 2) {
267 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
268 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
269 } else if (CMD_ARGC != 0) {
270 return ERROR_COMMAND_SYNTAX_ERROR;
271 }
272
273 command_print(CMD,
274 "BCM2835 GPIO nums: swclk = %d, swdio = %d",
275 swclk_gpio, swdio_gpio);
276
277 return ERROR_OK;
278 }
279
280 COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swclk)
281 {
282 if (CMD_ARGC == 1)
283 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
284
285 command_print(CMD, "BCM2835 num: swclk = %d", swclk_gpio);
286 return ERROR_OK;
287 }
288
289 COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swdio)
290 {
291 if (CMD_ARGC == 1)
292 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
293
294 command_print(CMD, "BCM2835 num: swdio = %d", swdio_gpio);
295 return ERROR_OK;
296 }
297
298 COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs)
299 {
300 if (CMD_ARGC == 2) {
301 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
302 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
303 }
304
305 command_print(CMD, "BCM2835 GPIO: speed_coeffs = %d, speed_offset = %d",
306 speed_coeff, speed_offset);
307 return ERROR_OK;
308 }
309
310 COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base)
311 {
312 if (CMD_ARGC == 1)
313 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bcm2835_peri_base);
314
315 command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08x",
316 bcm2835_peri_base);
317 return ERROR_OK;
318 }
319
320 static const struct command_registration bcm2835gpio_command_handlers[] = {
321 {
322 .name = "bcm2835gpio_jtag_nums",
323 .handler = &bcm2835gpio_handle_jtag_gpionums,
324 .mode = COMMAND_CONFIG,
325 .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
326 .usage = "[tck tms tdi tdo]",
327 },
328 {
329 .name = "bcm2835gpio_tck_num",
330 .handler = &bcm2835gpio_handle_jtag_gpionum_tck,
331 .mode = COMMAND_CONFIG,
332 .help = "gpio number for tck.",
333 .usage = "[tck]",
334 },
335 {
336 .name = "bcm2835gpio_tms_num",
337 .handler = &bcm2835gpio_handle_jtag_gpionum_tms,
338 .mode = COMMAND_CONFIG,
339 .help = "gpio number for tms.",
340 .usage = "[tms]",
341 },
342 {
343 .name = "bcm2835gpio_tdo_num",
344 .handler = &bcm2835gpio_handle_jtag_gpionum_tdo,
345 .mode = COMMAND_CONFIG,
346 .help = "gpio number for tdo.",
347 .usage = "[tdo]",
348 },
349 {
350 .name = "bcm2835gpio_tdi_num",
351 .handler = &bcm2835gpio_handle_jtag_gpionum_tdi,
352 .mode = COMMAND_CONFIG,
353 .help = "gpio number for tdi.",
354 .usage = "[tdi]",
355 },
356 {
357 .name = "bcm2835gpio_swd_nums",
358 .handler = &bcm2835gpio_handle_swd_gpionums,
359 .mode = COMMAND_CONFIG,
360 .help = "gpio numbers for swclk, swdio. (in that order)",
361 .usage = "[swclk swdio]",
362 },
363 {
364 .name = "bcm2835gpio_swclk_num",
365 .handler = &bcm2835gpio_handle_swd_gpionum_swclk,
366 .mode = COMMAND_CONFIG,
367 .help = "gpio number for swclk.",
368 .usage = "[swclk]",
369 },
370 {
371 .name = "bcm2835gpio_swdio_num",
372 .handler = &bcm2835gpio_handle_swd_gpionum_swdio,
373 .mode = COMMAND_CONFIG,
374 .help = "gpio number for swdio.",
375 .usage = "[swdio]",
376 },
377 {
378 .name = "bcm2835gpio_srst_num",
379 .handler = &bcm2835gpio_handle_jtag_gpionum_srst,
380 .mode = COMMAND_CONFIG,
381 .help = "gpio number for srst.",
382 .usage = "[srst]",
383 },
384 {
385 .name = "bcm2835gpio_trst_num",
386 .handler = &bcm2835gpio_handle_jtag_gpionum_trst,
387 .mode = COMMAND_CONFIG,
388 .help = "gpio number for trst.",
389 .usage = "[trst]",
390 },
391 {
392 .name = "bcm2835gpio_speed_coeffs",
393 .handler = &bcm2835gpio_handle_speed_coeffs,
394 .mode = COMMAND_CONFIG,
395 .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
396 .usage = "[SPEED_COEFF SPEED_OFFSET]",
397 },
398 {
399 .name = "bcm2835gpio_peripheral_base",
400 .handler = &bcm2835gpio_handle_peripheral_base,
401 .mode = COMMAND_CONFIG,
402 .help = "peripheral base to access GPIOs (RPi1 0x20000000, RPi2 0x3F000000).",
403 .usage = "[base]",
404 },
405
406 COMMAND_REGISTRATION_DONE
407 };
408
409 static const char * const bcm2835_transports[] = { "jtag", "swd", NULL };
410
411 static struct jtag_interface bcm2835gpio_interface = {
412 .supported = DEBUG_CAP_TMS_SEQ,
413 .execute_queue = bitbang_execute_queue,
414 };
415
416 struct adapter_driver bcm2835gpio_adapter_driver = {
417 .name = "bcm2835gpio",
418 .transports = bcm2835_transports,
419 .commands = bcm2835gpio_command_handlers,
420
421 .init = bcm2835gpio_init,
422 .quit = bcm2835gpio_quit,
423 .reset = bcm2835gpio_reset,
424 .speed = bcm2835gpio_speed,
425 .khz = bcm2835gpio_khz,
426 .speed_div = bcm2835gpio_speed_div,
427
428 .jtag_ops = &bcm2835gpio_interface,
429 .swd_ops = &bitbang_swd,
430 };
431
432 static bool bcm2835gpio_jtag_mode_possible(void)
433 {
434 if (!is_gpio_valid(tck_gpio))
435 return 0;
436 if (!is_gpio_valid(tms_gpio))
437 return 0;
438 if (!is_gpio_valid(tdi_gpio))
439 return 0;
440 if (!is_gpio_valid(tdo_gpio))
441 return 0;
442 return 1;
443 }
444
445 static bool bcm2835gpio_swd_mode_possible(void)
446 {
447 if (!is_gpio_valid(swclk_gpio))
448 return 0;
449 if (!is_gpio_valid(swdio_gpio))
450 return 0;
451 return 1;
452 }
453
454 static int bcm2835gpio_init(void)
455 {
456 bitbang_interface = &bcm2835gpio_bitbang;
457
458 LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver");
459
460 if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) {
461 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
462 return ERROR_JTAG_INIT_FAILED;
463 }
464
465 if (transport_is_swd() && !bcm2835gpio_swd_mode_possible()) {
466 LOG_ERROR("Require swclk and swdio gpio for SWD mode");
467 return ERROR_JTAG_INIT_FAILED;
468 }
469
470 dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
471 if (dev_mem_fd < 0) {
472 LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
473 dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
474 }
475 if (dev_mem_fd < 0) {
476 LOG_ERROR("open: %s", strerror(errno));
477 return ERROR_JTAG_INIT_FAILED;
478 }
479
480 pio_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
481 MAP_SHARED, dev_mem_fd, BCM2835_GPIO_BASE);
482
483 if (pio_base == MAP_FAILED) {
484 LOG_ERROR("mmap: %s", strerror(errno));
485 close(dev_mem_fd);
486 return ERROR_JTAG_INIT_FAILED;
487 }
488
489 static volatile uint32_t *pads_base;
490 pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
491 MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27);
492
493 if (pads_base == MAP_FAILED) {
494 LOG_ERROR("mmap: %s", strerror(errno));
495 close(dev_mem_fd);
496 return ERROR_JTAG_INIT_FAILED;
497 }
498
499 /* set 4mA drive strength, slew rate limited, hysteresis on */
500 pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
501
502 /*
503 * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
504 * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
505 */
506 if (transport_is_jtag()) {
507 tdo_gpio_mode = MODE_GPIO(tdo_gpio);
508 tdi_gpio_mode = MODE_GPIO(tdi_gpio);
509 tck_gpio_mode = MODE_GPIO(tck_gpio);
510 tms_gpio_mode = MODE_GPIO(tms_gpio);
511
512 INP_GPIO(tdo_gpio);
513
514 GPIO_CLR = 1<<tdi_gpio | 1<<tck_gpio;
515 GPIO_SET = 1<<tms_gpio;
516
517 OUT_GPIO(tdi_gpio);
518 OUT_GPIO(tck_gpio);
519 OUT_GPIO(tms_gpio);
520
521 if (trst_gpio != -1) {
522 trst_gpio_mode = MODE_GPIO(trst_gpio);
523 GPIO_SET = 1 << trst_gpio;
524 OUT_GPIO(trst_gpio);
525 }
526 }
527
528 if (transport_is_swd()) {
529 swclk_gpio_mode = MODE_GPIO(swclk_gpio);
530 swdio_gpio_mode = MODE_GPIO(swdio_gpio);
531
532 GPIO_CLR = 1<<swdio_gpio | 1<<swclk_gpio;
533
534 OUT_GPIO(swclk_gpio);
535 OUT_GPIO(swdio_gpio);
536 }
537
538 if (srst_gpio != -1) {
539 srst_gpio_mode = MODE_GPIO(srst_gpio);
540 GPIO_SET = 1 << srst_gpio;
541 OUT_GPIO(srst_gpio);
542 }
543
544 LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d "
545 "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode,
546 tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode);
547
548 return ERROR_OK;
549 }
550
551 static int bcm2835gpio_quit(void)
552 {
553 if (transport_is_jtag()) {
554 SET_MODE_GPIO(tdo_gpio, tdo_gpio_mode);
555 SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode);
556 SET_MODE_GPIO(tck_gpio, tck_gpio_mode);
557 SET_MODE_GPIO(tms_gpio, tms_gpio_mode);
558 if (trst_gpio != -1)
559 SET_MODE_GPIO(trst_gpio, trst_gpio_mode);
560 }
561
562 if (transport_is_swd()) {
563 SET_MODE_GPIO(swclk_gpio, swclk_gpio_mode);
564 SET_MODE_GPIO(swdio_gpio, swdio_gpio_mode);
565 }
566
567 if (srst_gpio != -1)
568 SET_MODE_GPIO(srst_gpio, srst_gpio_mode);
569
570 return ERROR_OK;
571 }

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)