f33d10976246f1352131df3d630ae653190cb620
[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 int imx_gpio_read(void);
86 static void imx_gpio_write(int tck, int tms, int tdi);
87 static void 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 int imx_gpio_read(void)
132 {
133 return gpio_level(tdo_gpio);
134 }
135
136 static void 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
146 static void imx_gpio_swd_write(int tck, int tms, int tdi)
147 {
148 tdi ? gpio_set(swdio_gpio) : gpio_clear(swdio_gpio);
149 tck ? gpio_set(swclk_gpio) : gpio_clear(swclk_gpio);
150
151 for (unsigned int i = 0; i < jtag_delay; i++)
152 asm volatile ("");
153 }
154
155 /* (1) assert or (0) deassert reset lines */
156 static void imx_gpio_reset(int trst, int srst)
157 {
158 if (trst_gpio != -1)
159 trst ? gpio_set(trst_gpio) : gpio_clear(trst_gpio);
160
161 if (srst_gpio != -1)
162 srst ? gpio_set(srst_gpio) : gpio_clear(srst_gpio);
163 }
164
165 static void imx_gpio_swdio_drive(bool is_output)
166 {
167 if (is_output)
168 gpio_mode_output_set(swdio_gpio);
169 else
170 gpio_mode_input_set(swdio_gpio);
171 }
172
173 static int imx_gpio_swdio_read(void)
174 {
175 return gpio_level(swdio_gpio);
176 }
177
178 static int imx_gpio_khz(int khz, int *jtag_speed)
179 {
180 if (!khz) {
181 LOG_DEBUG("RCLK not supported");
182 return ERROR_FAIL;
183 }
184 *jtag_speed = speed_coeff/khz - speed_offset;
185 if (*jtag_speed < 0)
186 *jtag_speed = 0;
187 return ERROR_OK;
188 }
189
190 static int imx_gpio_speed_div(int speed, int *khz)
191 {
192 *khz = speed_coeff/(speed + speed_offset);
193 return ERROR_OK;
194 }
195
196 static int imx_gpio_speed(int speed)
197 {
198 jtag_delay = speed;
199 return ERROR_OK;
200 }
201
202 static int is_gpio_valid(int gpio)
203 {
204 return gpio >= 0 && gpio < 32 * IMX_GPIO_REGS_COUNT;
205 }
206
207 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionums)
208 {
209 if (CMD_ARGC == 4) {
210 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
211 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
212 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
213 COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
214 } else if (CMD_ARGC != 0) {
215 return ERROR_COMMAND_SYNTAX_ERROR;
216 }
217
218 command_print(CMD_CTX,
219 "imx_gpio GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d",
220 tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
221
222 return ERROR_OK;
223 }
224
225 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tck)
226 {
227 if (CMD_ARGC == 1)
228 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
229
230 command_print(CMD_CTX, "imx_gpio GPIO config: tck = %d", tck_gpio);
231 return ERROR_OK;
232 }
233
234 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tms)
235 {
236 if (CMD_ARGC == 1)
237 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
238
239 command_print(CMD_CTX, "imx_gpio GPIO config: tms = %d", tms_gpio);
240 return ERROR_OK;
241 }
242
243 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdo)
244 {
245 if (CMD_ARGC == 1)
246 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
247
248 command_print(CMD_CTX, "imx_gpio GPIO config: tdo = %d", tdo_gpio);
249 return ERROR_OK;
250 }
251
252 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdi)
253 {
254 if (CMD_ARGC == 1)
255 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
256
257 command_print(CMD_CTX, "imx_gpio GPIO config: tdi = %d", tdi_gpio);
258 return ERROR_OK;
259 }
260
261 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_srst)
262 {
263 if (CMD_ARGC == 1)
264 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
265
266 command_print(CMD_CTX, "imx_gpio GPIO config: srst = %d", srst_gpio);
267 return ERROR_OK;
268 }
269
270 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_trst)
271 {
272 if (CMD_ARGC == 1)
273 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
274
275 command_print(CMD_CTX, "imx_gpio GPIO config: trst = %d", trst_gpio);
276 return ERROR_OK;
277 }
278
279 COMMAND_HANDLER(imx_gpio_handle_swd_gpionums)
280 {
281 if (CMD_ARGC == 2) {
282 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
283 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
284 } else if (CMD_ARGC != 0) {
285 return ERROR_COMMAND_SYNTAX_ERROR;
286 }
287
288 command_print(CMD_CTX,
289 "imx_gpio GPIO nums: swclk = %d, swdio = %d",
290 swclk_gpio, swdio_gpio);
291
292 return ERROR_OK;
293 }
294
295 COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swclk)
296 {
297 if (CMD_ARGC == 1)
298 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
299
300 command_print(CMD_CTX, "imx_gpio num: swclk = %d", swclk_gpio);
301 return ERROR_OK;
302 }
303
304 COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swdio)
305 {
306 if (CMD_ARGC == 1)
307 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
308
309 command_print(CMD_CTX, "imx_gpio num: swdio = %d", swdio_gpio);
310 return ERROR_OK;
311 }
312
313 COMMAND_HANDLER(imx_gpio_handle_speed_coeffs)
314 {
315 if (CMD_ARGC == 2) {
316 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
317 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
318 }
319 return ERROR_OK;
320 }
321
322 COMMAND_HANDLER(imx_gpio_handle_peripheral_base)
323 {
324 if (CMD_ARGC == 1)
325 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], imx_gpio_peri_base);
326 return ERROR_OK;
327 }
328
329 static const struct command_registration imx_gpio_command_handlers[] = {
330 {
331 .name = "imx_gpio_jtag_nums",
332 .handler = &imx_gpio_handle_jtag_gpionums,
333 .mode = COMMAND_CONFIG,
334 .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
335 .usage = "(tck tms tdi tdo)* ",
336 },
337 {
338 .name = "imx_gpio_tck_num",
339 .handler = &imx_gpio_handle_jtag_gpionum_tck,
340 .mode = COMMAND_CONFIG,
341 .help = "gpio number for tck.",
342 },
343 {
344 .name = "imx_gpio_tms_num",
345 .handler = &imx_gpio_handle_jtag_gpionum_tms,
346 .mode = COMMAND_CONFIG,
347 .help = "gpio number for tms.",
348 },
349 {
350 .name = "imx_gpio_tdo_num",
351 .handler = &imx_gpio_handle_jtag_gpionum_tdo,
352 .mode = COMMAND_CONFIG,
353 .help = "gpio number for tdo.",
354 },
355 {
356 .name = "imx_gpio_tdi_num",
357 .handler = &imx_gpio_handle_jtag_gpionum_tdi,
358 .mode = COMMAND_CONFIG,
359 .help = "gpio number for tdi.",
360 },
361 {
362 .name = "imx_gpio_swd_nums",
363 .handler = &imx_gpio_handle_swd_gpionums,
364 .mode = COMMAND_CONFIG,
365 .help = "gpio numbers for swclk, swdio. (in that order)",
366 .usage = "(swclk swdio)* ",
367 },
368 {
369 .name = "imx_gpio_swclk_num",
370 .handler = &imx_gpio_handle_swd_gpionum_swclk,
371 .mode = COMMAND_CONFIG,
372 .help = "gpio number for swclk.",
373 },
374 {
375 .name = "imx_gpio_swdio_num",
376 .handler = &imx_gpio_handle_swd_gpionum_swdio,
377 .mode = COMMAND_CONFIG,
378 .help = "gpio number for swdio.",
379 },
380 {
381 .name = "imx_gpio_srst_num",
382 .handler = &imx_gpio_handle_jtag_gpionum_srst,
383 .mode = COMMAND_CONFIG,
384 .help = "gpio number for srst.",
385 },
386 {
387 .name = "imx_gpio_trst_num",
388 .handler = &imx_gpio_handle_jtag_gpionum_trst,
389 .mode = COMMAND_CONFIG,
390 .help = "gpio number for trst.",
391 },
392 {
393 .name = "imx_gpio_speed_coeffs",
394 .handler = &imx_gpio_handle_speed_coeffs,
395 .mode = COMMAND_CONFIG,
396 .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
397 },
398 {
399 .name = "imx_gpio_peripheral_base",
400 .handler = &imx_gpio_handle_peripheral_base,
401 .mode = COMMAND_CONFIG,
402 .help = "peripheral base to access GPIOs (0x0209c000 for most IMX).",
403 },
404
405 COMMAND_REGISTRATION_DONE
406 };
407
408 static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL };
409
410 struct jtag_interface imx_gpio_interface = {
411 .name = "imx_gpio",
412 .supported = DEBUG_CAP_TMS_SEQ,
413 .execute_queue = bitbang_execute_queue,
414 .transports = imx_gpio_transports,
415 .swd = &bitbang_swd,
416 .speed = imx_gpio_speed,
417 .khz = imx_gpio_khz,
418 .speed_div = imx_gpio_speed_div,
419 .commands = imx_gpio_command_handlers,
420 .init = imx_gpio_init,
421 .quit = imx_gpio_quit,
422 };
423
424 static bool imx_gpio_jtag_mode_possible(void)
425 {
426 if (!is_gpio_valid(tck_gpio))
427 return 0;
428 if (!is_gpio_valid(tms_gpio))
429 return 0;
430 if (!is_gpio_valid(tdi_gpio))
431 return 0;
432 if (!is_gpio_valid(tdo_gpio))
433 return 0;
434 return 1;
435 }
436
437 static bool imx_gpio_swd_mode_possible(void)
438 {
439 if (!is_gpio_valid(swclk_gpio))
440 return 0;
441 if (!is_gpio_valid(swdio_gpio))
442 return 0;
443 return 1;
444 }
445
446 static int imx_gpio_init(void)
447 {
448 bitbang_interface = &imx_gpio_bitbang;
449
450 LOG_INFO("imx_gpio GPIO JTAG/SWD bitbang driver");
451
452 if (imx_gpio_jtag_mode_possible()) {
453 if (imx_gpio_swd_mode_possible())
454 LOG_INFO("JTAG and SWD modes enabled");
455 else
456 LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)");
457 } else if (imx_gpio_swd_mode_possible()) {
458 LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)");
459 } else {
460 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode and/or swclk and swdio gpio for SWD mode");
461 return ERROR_JTAG_INIT_FAILED;
462 }
463
464 dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
465 if (dev_mem_fd < 0) {
466 perror("open");
467 return ERROR_JTAG_INIT_FAILED;
468 }
469
470
471 LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u",
472 sysconf(_SC_PAGE_SIZE), IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE);
473 pio_base = mmap(NULL, IMX_GPIO_REGS_COUNT * IMX_GPIO_SIZE,
474 PROT_READ | PROT_WRITE,
475 MAP_SHARED, dev_mem_fd, imx_gpio_peri_base);
476
477 if (pio_base == MAP_FAILED) {
478 perror("mmap");
479 close(dev_mem_fd);
480 return ERROR_JTAG_INIT_FAILED;
481 }
482
483 /*
484 * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
485 * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
486 */
487 if (imx_gpio_jtag_mode_possible()) {
488 tdo_gpio_mode = gpio_mode_get(tdo_gpio);
489 tdi_gpio_mode = gpio_mode_get(tdi_gpio);
490 tck_gpio_mode = gpio_mode_get(tck_gpio);
491 tms_gpio_mode = gpio_mode_get(tms_gpio);
492
493 gpio_clear(tdi_gpio);
494 gpio_clear(tck_gpio);
495 gpio_set(tms_gpio);
496
497 gpio_mode_input_set(tdo_gpio);
498 gpio_mode_output_set(tdi_gpio);
499 gpio_mode_output_set(tck_gpio);
500 gpio_mode_output_set(tms_gpio);
501 }
502 if (imx_gpio_swd_mode_possible()) {
503 swclk_gpio_mode = gpio_mode_get(swclk_gpio);
504 swdio_gpio_mode = gpio_mode_get(swdio_gpio);
505
506 gpio_clear(swdio_gpio);
507 gpio_clear(swclk_gpio);
508 gpio_mode_output_set(swclk_gpio);
509 gpio_mode_output_set(swdio_gpio);
510 }
511 if (trst_gpio != -1) {
512 trst_gpio_mode = gpio_mode_get(trst_gpio);
513 gpio_set(trst_gpio);
514 gpio_mode_output_set(trst_gpio);
515 }
516 if (srst_gpio != -1) {
517 srst_gpio_mode = gpio_mode_get(srst_gpio);
518 gpio_set(srst_gpio);
519 gpio_mode_output_set(srst_gpio);
520 }
521
522 LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d "
523 "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode,
524 tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode);
525
526 if (swd_mode) {
527 imx_gpio_bitbang.write = imx_gpio_swd_write;
528 bitbang_switch_to_swd();
529 }
530
531 return ERROR_OK;
532 }
533
534 static int imx_gpio_quit(void)
535 {
536 if (imx_gpio_jtag_mode_possible()) {
537 gpio_mode_set(tdo_gpio, tdo_gpio_mode);
538 gpio_mode_set(tdi_gpio, tdi_gpio_mode);
539 gpio_mode_set(tck_gpio, tck_gpio_mode);
540 gpio_mode_set(tms_gpio, tms_gpio_mode);
541 }
542 if (imx_gpio_swd_mode_possible()) {
543 gpio_mode_set(swclk_gpio, swclk_gpio_mode);
544 gpio_mode_set(swdio_gpio, swdio_gpio_mode);
545 }
546 if (trst_gpio != -1)
547 gpio_mode_set(trst_gpio, trst_gpio_mode);
548 if (srst_gpio != -1)
549 gpio_mode_set(srst_gpio, srst_gpio_mode);
550
551 return ERROR_OK;
552 }

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)