jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / jtag / drivers / imx_gpio.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2017 by Grzegorz Kostka, kostka.grzegorz@gmail.com *
5 * *
6 * Based on bcm2835gpio.c *
7 ***************************************************************************/
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include <jtag/interface.h>
14 #include <transport/transport.h>
15 #include "bitbang.h"
16
17 #include <sys/mman.h>
18
19 #define IMX_GPIO_BASE 0x0209c000
20 #define IMX_GPIO_SIZE 0x00004000
21 #define IMX_GPIO_REGS_COUNT 8
22
23 static uint32_t imx_gpio_peri_base = IMX_GPIO_BASE;
24
25 struct imx_gpio_regs {
26 uint32_t dr;
27 uint32_t gdir;
28 uint32_t psr;
29 uint32_t icr1;
30 uint32_t icr2;
31 uint32_t imr;
32 uint32_t isr;
33 uint32_t edge_sel;
34 } __attribute__((aligned(IMX_GPIO_SIZE)));
35
36 static int dev_mem_fd;
37 static volatile struct imx_gpio_regs *pio_base;
38
39 /* GPIO setup functions */
40 static inline bool gpio_mode_get(int g)
41 {
42 return pio_base[g / 32].gdir >> (g & 0x1F) & 1;
43 }
44
45 static inline void gpio_mode_input_set(int g)
46 {
47 pio_base[g / 32].gdir &= ~(1u << (g & 0x1F));
48 }
49
50 static inline void gpio_mode_output_set(int g)
51 {
52 pio_base[g / 32].gdir |= (1u << (g & 0x1F));
53 }
54
55 static inline void gpio_mode_set(int g, int m)
56 {
57 (m) ? gpio_mode_output_set(g) : gpio_mode_input_set(g);
58 }
59
60 static inline void gpio_set(int g)
61 {
62 pio_base[g / 32].dr |= (1u << (g & 0x1F));
63 }
64
65 static inline void gpio_clear(int g)
66 {
67 pio_base[g / 32].dr &= ~(1u << (g & 0x1F));
68 }
69
70 static inline bool gpio_level(int g)
71 {
72 return pio_base[g / 32].dr >> (g & 0x1F) & 1;
73 }
74
75 static bb_value_t imx_gpio_read(void);
76 static int imx_gpio_write(int tck, int tms, int tdi);
77
78 static int imx_gpio_swdio_read(void);
79 static void imx_gpio_swdio_drive(bool is_output);
80 static int imx_gpio_swd_write(int swclk, int swdio);
81
82 static int imx_gpio_init(void);
83 static int imx_gpio_quit(void);
84
85 static struct bitbang_interface imx_gpio_bitbang = {
86 .read = imx_gpio_read,
87 .write = imx_gpio_write,
88 .swdio_read = imx_gpio_swdio_read,
89 .swdio_drive = imx_gpio_swdio_drive,
90 .swd_write = imx_gpio_swd_write,
91 .blink = NULL
92 };
93
94 /* GPIO numbers for each signal. Negative values are invalid */
95 static int tck_gpio = -1;
96 static int tck_gpio_mode;
97 static int tms_gpio = -1;
98 static int tms_gpio_mode;
99 static int tdi_gpio = -1;
100 static int tdi_gpio_mode;
101 static int tdo_gpio = -1;
102 static int tdo_gpio_mode;
103 static int trst_gpio = -1;
104 static int trst_gpio_mode;
105 static int srst_gpio = -1;
106 static int srst_gpio_mode;
107 static int swclk_gpio = -1;
108 static int swclk_gpio_mode;
109 static int swdio_gpio = -1;
110 static int swdio_gpio_mode;
111
112 /* Transition delay coefficients. Tuned for IMX6UL 528MHz. Adjusted
113 * experimentally for:10kHz, 100Khz, 500KHz. Speeds above 800Khz are impossible
114 * to reach via memory mapped method (at least for IMX6UL@528MHz).
115 * Measured mmap raw GPIO toggling speed on IMX6UL@528MHz: 1.3MHz.
116 */
117 static int speed_coeff = 50000;
118 static int speed_offset = 100;
119 static unsigned int jtag_delay;
120
121 static bb_value_t imx_gpio_read(void)
122 {
123 return gpio_level(tdo_gpio) ? BB_HIGH : BB_LOW;
124 }
125
126 static int imx_gpio_write(int tck, int tms, int tdi)
127 {
128 tms ? gpio_set(tms_gpio) : gpio_clear(tms_gpio);
129 tdi ? gpio_set(tdi_gpio) : gpio_clear(tdi_gpio);
130 tck ? gpio_set(tck_gpio) : gpio_clear(tck_gpio);
131
132 for (unsigned int i = 0; i < jtag_delay; i++)
133 asm volatile ("");
134
135 return ERROR_OK;
136 }
137
138 static int imx_gpio_swd_write(int swclk, int swdio)
139 {
140 swdio ? gpio_set(swdio_gpio) : gpio_clear(swdio_gpio);
141 swclk ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio);
142
143 for (unsigned int i = 0; i < jtag_delay; i++)
144 asm volatile ("");
145
146 return ERROR_OK;
147 }
148
149 /* (1) assert or (0) deassert reset lines */
150 static int imx_gpio_reset(int trst, int srst)
151 {
152 if (trst_gpio != -1)
153 trst ? gpio_clear(trst_gpio) : gpio_set(trst_gpio);
154
155 if (srst_gpio != -1)
156 srst ? gpio_clear(srst_gpio) : gpio_set(srst_gpio);
157
158 return ERROR_OK;
159 }
160
161 static void imx_gpio_swdio_drive(bool is_output)
162 {
163 if (is_output)
164 gpio_mode_output_set(swdio_gpio);
165 else
166 gpio_mode_input_set(swdio_gpio);
167 }
168
169 static int imx_gpio_swdio_read(void)
170 {
171 return gpio_level(swdio_gpio);
172 }
173
174 static int imx_gpio_khz(int khz, int *jtag_speed)
175 {
176 if (!khz) {
177 LOG_DEBUG("RCLK not supported");
178 return ERROR_FAIL;
179 }
180 *jtag_speed = speed_coeff/khz - speed_offset;
181 if (*jtag_speed < 0)
182 *jtag_speed = 0;
183 return ERROR_OK;
184 }
185
186 static int imx_gpio_speed_div(int speed, int *khz)
187 {
188 *khz = speed_coeff/(speed + speed_offset);
189 return ERROR_OK;
190 }
191
192 static int imx_gpio_speed(int speed)
193 {
194 jtag_delay = speed;
195 return ERROR_OK;
196 }
197
198 static int is_gpio_valid(int gpio)
199 {
200 return gpio >= 0 && gpio < 32 * IMX_GPIO_REGS_COUNT;
201 }
202
203 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionums)
204 {
205 if (CMD_ARGC == 4) {
206 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
207 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
208 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
209 COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
210 } else if (CMD_ARGC != 0) {
211 return ERROR_COMMAND_SYNTAX_ERROR;
212 }
213
214 command_print(CMD,
215 "imx_gpio GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d",
216 tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
217
218 return ERROR_OK;
219 }
220
221 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tck)
222 {
223 if (CMD_ARGC == 1)
224 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
225
226 command_print(CMD, "imx_gpio GPIO config: tck = %d", tck_gpio);
227 return ERROR_OK;
228 }
229
230 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tms)
231 {
232 if (CMD_ARGC == 1)
233 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
234
235 command_print(CMD, "imx_gpio GPIO config: tms = %d", tms_gpio);
236 return ERROR_OK;
237 }
238
239 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdo)
240 {
241 if (CMD_ARGC == 1)
242 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
243
244 command_print(CMD, "imx_gpio GPIO config: tdo = %d", tdo_gpio);
245 return ERROR_OK;
246 }
247
248 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdi)
249 {
250 if (CMD_ARGC == 1)
251 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
252
253 command_print(CMD, "imx_gpio GPIO config: tdi = %d", tdi_gpio);
254 return ERROR_OK;
255 }
256
257 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_srst)
258 {
259 if (CMD_ARGC == 1)
260 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
261
262 command_print(CMD, "imx_gpio GPIO config: srst = %d", srst_gpio);
263 return ERROR_OK;
264 }
265
266 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_trst)
267 {
268 if (CMD_ARGC == 1)
269 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
270
271 command_print(CMD, "imx_gpio GPIO config: trst = %d", trst_gpio);
272 return ERROR_OK;
273 }
274
275 COMMAND_HANDLER(imx_gpio_handle_swd_gpionums)
276 {
277 if (CMD_ARGC == 2) {
278 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
279 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
280 } else if (CMD_ARGC != 0) {
281 return ERROR_COMMAND_SYNTAX_ERROR;
282 }
283
284 command_print(CMD,
285 "imx_gpio GPIO nums: swclk = %d, swdio = %d",
286 swclk_gpio, swdio_gpio);
287
288 return ERROR_OK;
289 }
290
291 COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swclk)
292 {
293 if (CMD_ARGC == 1)
294 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
295
296 command_print(CMD, "imx_gpio num: swclk = %d", swclk_gpio);
297 return ERROR_OK;
298 }
299
300 COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swdio)
301 {
302 if (CMD_ARGC == 1)
303 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
304
305 command_print(CMD, "imx_gpio num: swdio = %d", swdio_gpio);
306 return ERROR_OK;
307 }
308
309 COMMAND_HANDLER(imx_gpio_handle_speed_coeffs)
310 {
311 if (CMD_ARGC == 2) {
312 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
313 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
314 }
315
316 command_print(CMD, "imx_gpio: speed_coeffs = %d, speed_offset = %d",
317 speed_coeff, speed_offset);
318 return ERROR_OK;
319 }
320
321 COMMAND_HANDLER(imx_gpio_handle_peripheral_base)
322 {
323 if (CMD_ARGC == 1)
324 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], imx_gpio_peri_base);
325
326 command_print(CMD, "imx_gpio: peripheral_base = 0x%08x",
327 imx_gpio_peri_base);
328 return ERROR_OK;
329 }
330
331 static const struct command_registration imx_gpio_command_handlers[] = {
332 {
333 .name = "imx_gpio_jtag_nums",
334 .handler = &imx_gpio_handle_jtag_gpionums,
335 .mode = COMMAND_CONFIG,
336 .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
337 .usage = "[tck tms tdi tdo]",
338 },
339 {
340 .name = "imx_gpio_tck_num",
341 .handler = &imx_gpio_handle_jtag_gpionum_tck,
342 .mode = COMMAND_CONFIG,
343 .help = "gpio number for tck.",
344 .usage = "[tck]",
345 },
346 {
347 .name = "imx_gpio_tms_num",
348 .handler = &imx_gpio_handle_jtag_gpionum_tms,
349 .mode = COMMAND_CONFIG,
350 .help = "gpio number for tms.",
351 .usage = "[tms]",
352 },
353 {
354 .name = "imx_gpio_tdo_num",
355 .handler = &imx_gpio_handle_jtag_gpionum_tdo,
356 .mode = COMMAND_CONFIG,
357 .help = "gpio number for tdo.",
358 .usage = "[tdo]",
359 },
360 {
361 .name = "imx_gpio_tdi_num",
362 .handler = &imx_gpio_handle_jtag_gpionum_tdi,
363 .mode = COMMAND_CONFIG,
364 .help = "gpio number for tdi.",
365 .usage = "[tdi]",
366 },
367 {
368 .name = "imx_gpio_swd_nums",
369 .handler = &imx_gpio_handle_swd_gpionums,
370 .mode = COMMAND_CONFIG,
371 .help = "gpio numbers for swclk, swdio. (in that order)",
372 .usage = "[swclk swdio]",
373 },
374 {
375 .name = "imx_gpio_swclk_num",
376 .handler = &imx_gpio_handle_swd_gpionum_swclk,
377 .mode = COMMAND_CONFIG,
378 .help = "gpio number for swclk.",
379 .usage = "[swclk]",
380 },
381 {
382 .name = "imx_gpio_swdio_num",
383 .handler = &imx_gpio_handle_swd_gpionum_swdio,
384 .mode = COMMAND_CONFIG,
385 .help = "gpio number for swdio.",
386 .usage = "[swdio]",
387 },
388 {
389 .name = "imx_gpio_srst_num",
390 .handler = &imx_gpio_handle_jtag_gpionum_srst,
391 .mode = COMMAND_CONFIG,
392 .help = "gpio number for srst.",
393 .usage = "[srst]",
394 },
395 {
396 .name = "imx_gpio_trst_num",
397 .handler = &imx_gpio_handle_jtag_gpionum_trst,
398 .mode = COMMAND_CONFIG,
399 .help = "gpio number for trst.",
400 .usage = "[trst]",
401 },
402 {
403 .name = "imx_gpio_speed_coeffs",
404 .handler = &imx_gpio_handle_speed_coeffs,
405 .mode = COMMAND_CONFIG,
406 .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
407 .usage = "[SPEED_COEFF SPEED_OFFSET]",
408 },
409 {
410 .name = "imx_gpio_peripheral_base",
411 .handler = &imx_gpio_handle_peripheral_base,
412 .mode = COMMAND_CONFIG,
413 .help = "peripheral base to access GPIOs (0x0209c000 for most IMX).",
414 .usage = "[base]",
415 },
416
417 COMMAND_REGISTRATION_DONE
418 };
419
420 static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL };
421
422 static struct jtag_interface imx_gpio_interface = {
423 .supported = DEBUG_CAP_TMS_SEQ,
424 .execute_queue = bitbang_execute_queue,
425 };
426
427 struct adapter_driver imx_gpio_adapter_driver = {
428 .name = "imx_gpio",
429 .transports = imx_gpio_transports,
430 .commands = imx_gpio_command_handlers,
431
432 .init = imx_gpio_init,
433 .quit = imx_gpio_quit,
434 .reset = imx_gpio_reset,
435 .speed = imx_gpio_speed,
436 .khz = imx_gpio_khz,
437 .speed_div = imx_gpio_speed_div,
438
439 .jtag_ops = &imx_gpio_interface,
440 .swd_ops = &bitbang_swd,
441 };
442
443 static bool imx_gpio_jtag_mode_possible(void)
444 {
445 if (!is_gpio_valid(tck_gpio))
446 return 0;
447 if (!is_gpio_valid(tms_gpio))
448 return 0;
449 if (!is_gpio_valid(tdi_gpio))
450 return 0;
451 if (!is_gpio_valid(tdo_gpio))
452 return 0;
453 return 1;
454 }
455
456 static bool imx_gpio_swd_mode_possible(void)
457 {
458 if (!is_gpio_valid(swclk_gpio))
459 return 0;
460 if (!is_gpio_valid(swdio_gpio))
461 return 0;
462 return 1;
463 }
464
465 static int imx_gpio_init(void)
466 {
467 bitbang_interface = &imx_gpio_bitbang;
468
469 LOG_INFO("imx_gpio GPIO JTAG/SWD bitbang driver");
470
471 if (transport_is_jtag() && !imx_gpio_jtag_mode_possible()) {
472 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
473 return ERROR_JTAG_INIT_FAILED;
474 }
475
476 if (transport_is_swd() && !imx_gpio_swd_mode_possible()) {
477 LOG_ERROR("Require swclk and swdio gpio for SWD mode");
478 return ERROR_JTAG_INIT_FAILED;
479 }
480
481 dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
482 if (dev_mem_fd < 0) {
483 LOG_ERROR("open: %s", strerror(errno));
484 return ERROR_JTAG_INIT_FAILED;
485 }
486
487 LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u",
488 (unsigned int) sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE);
489 pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE,
490 PROT_READ | PROT_WRITE,
491 MAP_SHARED, dev_mem_fd, imx_gpio_peri_base);
492
493 if (pio_base == MAP_FAILED) {
494 LOG_ERROR("mmap: %s", strerror(errno));
495 close(dev_mem_fd);
496 return ERROR_JTAG_INIT_FAILED;
497 }
498
499 /*
500 * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
501 * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
502 */
503 if (transport_is_jtag()) {
504 tdo_gpio_mode = gpio_mode_get(tdo_gpio);
505 tdi_gpio_mode = gpio_mode_get(tdi_gpio);
506 tck_gpio_mode = gpio_mode_get(tck_gpio);
507 tms_gpio_mode = gpio_mode_get(tms_gpio);
508
509 gpio_clear(tdi_gpio);
510 gpio_clear(tck_gpio);
511 gpio_set(tms_gpio);
512
513 gpio_mode_input_set(tdo_gpio);
514 gpio_mode_output_set(tdi_gpio);
515 gpio_mode_output_set(tck_gpio);
516 gpio_mode_output_set(tms_gpio);
517
518 if (trst_gpio != -1) {
519 trst_gpio_mode = gpio_mode_get(trst_gpio);
520 gpio_set(trst_gpio);
521 gpio_mode_output_set(trst_gpio);
522 }
523 }
524
525 if (transport_is_swd()) {
526 swclk_gpio_mode = gpio_mode_get(swclk_gpio);
527 swdio_gpio_mode = gpio_mode_get(swdio_gpio);
528
529 gpio_clear(swdio_gpio);
530 gpio_clear(swclk_gpio);
531 gpio_mode_output_set(swclk_gpio);
532 gpio_mode_output_set(swdio_gpio);
533 }
534
535 if (srst_gpio != -1) {
536 srst_gpio_mode = gpio_mode_get(srst_gpio);
537 gpio_set(srst_gpio);
538 gpio_mode_output_set(srst_gpio);
539 }
540
541 LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d "
542 "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode,
543 tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode);
544
545 return ERROR_OK;
546 }
547
548 static int imx_gpio_quit(void)
549 {
550 if (transport_is_jtag()) {
551 gpio_mode_set(tdo_gpio, tdo_gpio_mode);
552 gpio_mode_set(tdi_gpio, tdi_gpio_mode);
553 gpio_mode_set(tck_gpio, tck_gpio_mode);
554 gpio_mode_set(tms_gpio, tms_gpio_mode);
555
556 if (trst_gpio != -1)
557 gpio_mode_set(trst_gpio, trst_gpio_mode);
558 }
559
560 if (transport_is_swd()) {
561 gpio_mode_set(swclk_gpio, swclk_gpio_mode);
562 gpio_mode_set(swdio_gpio, swdio_gpio_mode);
563 }
564
565 if (srst_gpio != -1)
566 gpio_mode_set(srst_gpio, srst_gpio_mode);
567
568 return ERROR_OK;
569 }

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)