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

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)