1 /***************************************************************************
2 * Copyright (C) 2017 by Grzegorz Kostka, kostka.grzegorz@gmail.com *
4 * Based on bcm2835gpio.c *
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. *
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. *
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 ***************************************************************************/
24 #include <jtag/interface.h>
29 #define IMX_GPIO_BASE 0x0209c000
30 #define IMX_GPIO_SIZE 0x00004000
31 #define IMX_GPIO_REGS_COUNT 8
33 static uint32_t imx_gpio_peri_base
= IMX_GPIO_BASE
;
35 struct imx_gpio_regs
{
44 } __attribute__((aligned(IMX_GPIO_SIZE
)));
46 static int dev_mem_fd
;
47 static volatile struct imx_gpio_regs
*pio_base
;
49 /* GPIO setup functions */
50 static inline bool gpio_mode_get(int g
)
52 return pio_base
[g
/ 32].gdir
>> (g
& 0x1F) & 1;
55 static inline void gpio_mode_input_set(int g
)
57 pio_base
[g
/ 32].gdir
&= ~(1u << (g
& 0x1F));
60 static inline void gpio_mode_output_set(int g
)
62 pio_base
[g
/ 32].gdir
|= (1u << (g
& 0x1F));
65 static inline void gpio_mode_set(int g
, int m
)
67 (m
) ? gpio_mode_output_set(g
) : gpio_mode_input_set(g
);
70 static inline void gpio_set(int g
)
72 pio_base
[g
/ 32].dr
|= (1u << (g
& 0x1F));
75 static inline void gpio_clear(int g
)
77 pio_base
[g
/ 32].dr
&= ~(1u << (g
& 0x1F));
80 static inline bool gpio_level(int g
)
82 return pio_base
[g
/ 32].dr
>> (g
& 0x1F) & 1;
85 static bb_value_t
imx_gpio_read(void);
86 static int imx_gpio_write(int tck
, int tms
, int tdi
);
88 static int imx_gpio_swdio_read(void);
89 static void imx_gpio_swdio_drive(bool is_output
);
91 static int imx_gpio_init(void);
92 static int imx_gpio_quit(void);
94 static struct bitbang_interface imx_gpio_bitbang
= {
95 .read
= imx_gpio_read
,
96 .write
= imx_gpio_write
,
97 .swdio_read
= imx_gpio_swdio_read
,
98 .swdio_drive
= imx_gpio_swdio_drive
,
102 /* GPIO numbers for each signal. Negative values are invalid */
103 static int tck_gpio
= -1;
104 static int tck_gpio_mode
;
105 static int tms_gpio
= -1;
106 static int tms_gpio_mode
;
107 static int tdi_gpio
= -1;
108 static int tdi_gpio_mode
;
109 static int tdo_gpio
= -1;
110 static int tdo_gpio_mode
;
111 static int trst_gpio
= -1;
112 static int trst_gpio_mode
;
113 static int srst_gpio
= -1;
114 static int srst_gpio_mode
;
115 static int swclk_gpio
= -1;
116 static int swclk_gpio_mode
;
117 static int swdio_gpio
= -1;
118 static int swdio_gpio_mode
;
120 /* Transition delay coefficients. Tuned for IMX6UL 528MHz. Adjusted
121 * experimentally for:10kHz, 100Khz, 500KHz. Speeds above 800Khz are impossible
122 * to reach via memory mapped method (at least for IMX6UL@528MHz).
123 * Measured mmap raw GPIO toggling speed on IMX6UL@528MHz: 1.3MHz.
125 static int speed_coeff
= 50000;
126 static int speed_offset
= 100;
127 static unsigned int jtag_delay
;
129 static bb_value_t
imx_gpio_read(void)
131 return gpio_level(tdo_gpio
) ? BB_HIGH
: BB_LOW
;
134 static int imx_gpio_write(int tck
, int tms
, int tdi
)
136 tms
? gpio_set(tms_gpio
) : gpio_clear(tms_gpio
);
137 tdi
? gpio_set(tdi_gpio
) : gpio_clear(tdi_gpio
);
138 tck
? gpio_set(tck_gpio
) : gpio_clear(tck_gpio
);
140 for (unsigned int i
= 0; i
< jtag_delay
; i
++)
146 static int imx_gpio_swd_write(int tck
, int tms
, int tdi
)
148 tdi
? gpio_set(swdio_gpio
) : gpio_clear(swdio_gpio
);
149 tck
? gpio_set(swclk_gpio
) : gpio_clear(swclk_gpio
);
151 for (unsigned int i
= 0; i
< jtag_delay
; i
++)
157 /* (1) assert or (0) deassert reset lines */
158 static int imx_gpio_reset(int trst
, int srst
)
161 trst
? gpio_clear(trst_gpio
) : gpio_set(trst_gpio
);
164 srst
? gpio_clear(srst_gpio
) : gpio_set(srst_gpio
);
169 static void imx_gpio_swdio_drive(bool is_output
)
172 gpio_mode_output_set(swdio_gpio
);
174 gpio_mode_input_set(swdio_gpio
);
177 static int imx_gpio_swdio_read(void)
179 return gpio_level(swdio_gpio
);
182 static int imx_gpio_khz(int khz
, int *jtag_speed
)
185 LOG_DEBUG("RCLK not supported");
188 *jtag_speed
= speed_coeff
/khz
- speed_offset
;
194 static int imx_gpio_speed_div(int speed
, int *khz
)
196 *khz
= speed_coeff
/(speed
+ speed_offset
);
200 static int imx_gpio_speed(int speed
)
206 static int is_gpio_valid(int gpio
)
208 return gpio
>= 0 && gpio
< 32 * IMX_GPIO_REGS_COUNT
;
211 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionums
)
214 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], tck_gpio
);
215 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], tms_gpio
);
216 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[2], tdi_gpio
);
217 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[3], tdo_gpio
);
218 } else if (CMD_ARGC
!= 0) {
219 return ERROR_COMMAND_SYNTAX_ERROR
;
223 "imx_gpio GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d",
224 tck_gpio
, tms_gpio
, tdi_gpio
, tdo_gpio
);
229 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tck
)
232 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], tck_gpio
);
234 command_print(CMD
, "imx_gpio GPIO config: tck = %d", tck_gpio
);
238 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tms
)
241 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], tms_gpio
);
243 command_print(CMD
, "imx_gpio GPIO config: tms = %d", tms_gpio
);
247 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdo
)
250 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], tdo_gpio
);
252 command_print(CMD
, "imx_gpio GPIO config: tdo = %d", tdo_gpio
);
256 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_tdi
)
259 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], tdi_gpio
);
261 command_print(CMD
, "imx_gpio GPIO config: tdi = %d", tdi_gpio
);
265 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_srst
)
268 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], srst_gpio
);
270 command_print(CMD
, "imx_gpio GPIO config: srst = %d", srst_gpio
);
274 COMMAND_HANDLER(imx_gpio_handle_jtag_gpionum_trst
)
277 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], trst_gpio
);
279 command_print(CMD
, "imx_gpio GPIO config: trst = %d", trst_gpio
);
283 COMMAND_HANDLER(imx_gpio_handle_swd_gpionums
)
286 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], swclk_gpio
);
287 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], swdio_gpio
);
288 } else if (CMD_ARGC
!= 0) {
289 return ERROR_COMMAND_SYNTAX_ERROR
;
293 "imx_gpio GPIO nums: swclk = %d, swdio = %d",
294 swclk_gpio
, swdio_gpio
);
299 COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swclk
)
302 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], swclk_gpio
);
304 command_print(CMD
, "imx_gpio num: swclk = %d", swclk_gpio
);
308 COMMAND_HANDLER(imx_gpio_handle_swd_gpionum_swdio
)
311 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], swdio_gpio
);
313 command_print(CMD
, "imx_gpio num: swdio = %d", swdio_gpio
);
317 COMMAND_HANDLER(imx_gpio_handle_speed_coeffs
)
320 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], speed_coeff
);
321 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[1], speed_offset
);
324 command_print(CMD
, "imx_gpio: speed_coeffs = %d, speed_offset = %d",
325 speed_coeff
, speed_offset
);
329 COMMAND_HANDLER(imx_gpio_handle_peripheral_base
)
332 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], imx_gpio_peri_base
);
334 command_print(CMD
, "imx_gpio: peripheral_base = 0x%08x",
339 static const struct command_registration imx_gpio_command_handlers
[] = {
341 .name
= "imx_gpio_jtag_nums",
342 .handler
= &imx_gpio_handle_jtag_gpionums
,
343 .mode
= COMMAND_CONFIG
,
344 .help
= "gpio numbers for tck, tms, tdi, tdo. (in that order)",
345 .usage
= "[tck tms tdi tdo]",
348 .name
= "imx_gpio_tck_num",
349 .handler
= &imx_gpio_handle_jtag_gpionum_tck
,
350 .mode
= COMMAND_CONFIG
,
351 .help
= "gpio number for tck.",
355 .name
= "imx_gpio_tms_num",
356 .handler
= &imx_gpio_handle_jtag_gpionum_tms
,
357 .mode
= COMMAND_CONFIG
,
358 .help
= "gpio number for tms.",
362 .name
= "imx_gpio_tdo_num",
363 .handler
= &imx_gpio_handle_jtag_gpionum_tdo
,
364 .mode
= COMMAND_CONFIG
,
365 .help
= "gpio number for tdo.",
369 .name
= "imx_gpio_tdi_num",
370 .handler
= &imx_gpio_handle_jtag_gpionum_tdi
,
371 .mode
= COMMAND_CONFIG
,
372 .help
= "gpio number for tdi.",
376 .name
= "imx_gpio_swd_nums",
377 .handler
= &imx_gpio_handle_swd_gpionums
,
378 .mode
= COMMAND_CONFIG
,
379 .help
= "gpio numbers for swclk, swdio. (in that order)",
380 .usage
= "[swclk swdio]",
383 .name
= "imx_gpio_swclk_num",
384 .handler
= &imx_gpio_handle_swd_gpionum_swclk
,
385 .mode
= COMMAND_CONFIG
,
386 .help
= "gpio number for swclk.",
390 .name
= "imx_gpio_swdio_num",
391 .handler
= &imx_gpio_handle_swd_gpionum_swdio
,
392 .mode
= COMMAND_CONFIG
,
393 .help
= "gpio number for swdio.",
397 .name
= "imx_gpio_srst_num",
398 .handler
= &imx_gpio_handle_jtag_gpionum_srst
,
399 .mode
= COMMAND_CONFIG
,
400 .help
= "gpio number for srst.",
404 .name
= "imx_gpio_trst_num",
405 .handler
= &imx_gpio_handle_jtag_gpionum_trst
,
406 .mode
= COMMAND_CONFIG
,
407 .help
= "gpio number for trst.",
411 .name
= "imx_gpio_speed_coeffs",
412 .handler
= &imx_gpio_handle_speed_coeffs
,
413 .mode
= COMMAND_CONFIG
,
414 .help
= "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
415 .usage
= "[SPEED_COEFF SPEED_OFFSET]",
418 .name
= "imx_gpio_peripheral_base",
419 .handler
= &imx_gpio_handle_peripheral_base
,
420 .mode
= COMMAND_CONFIG
,
421 .help
= "peripheral base to access GPIOs (0x0209c000 for most IMX).",
425 COMMAND_REGISTRATION_DONE
428 static const char * const imx_gpio_transports
[] = { "jtag", "swd", NULL
};
430 struct jtag_interface imx_gpio_interface
= {
432 .supported
= DEBUG_CAP_TMS_SEQ
,
433 .execute_queue
= bitbang_execute_queue
,
434 .transports
= imx_gpio_transports
,
436 .speed
= imx_gpio_speed
,
438 .speed_div
= imx_gpio_speed_div
,
439 .commands
= imx_gpio_command_handlers
,
440 .init
= imx_gpio_init
,
441 .quit
= imx_gpio_quit
,
442 .reset
= imx_gpio_reset
,
445 static bool imx_gpio_jtag_mode_possible(void)
447 if (!is_gpio_valid(tck_gpio
))
449 if (!is_gpio_valid(tms_gpio
))
451 if (!is_gpio_valid(tdi_gpio
))
453 if (!is_gpio_valid(tdo_gpio
))
458 static bool imx_gpio_swd_mode_possible(void)
460 if (!is_gpio_valid(swclk_gpio
))
462 if (!is_gpio_valid(swdio_gpio
))
467 static int imx_gpio_init(void)
469 bitbang_interface
= &imx_gpio_bitbang
;
471 LOG_INFO("imx_gpio GPIO JTAG/SWD bitbang driver");
473 if (imx_gpio_jtag_mode_possible()) {
474 if (imx_gpio_swd_mode_possible())
475 LOG_INFO("JTAG and SWD modes enabled");
477 LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)");
478 } else if (imx_gpio_swd_mode_possible()) {
479 LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)");
481 LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode and/or swclk and swdio gpio for SWD mode");
482 return ERROR_JTAG_INIT_FAILED
;
485 dev_mem_fd
= open("/dev/mem", O_RDWR
| O_SYNC
);
486 if (dev_mem_fd
< 0) {
488 return ERROR_JTAG_INIT_FAILED
;
492 LOG_INFO("imx_gpio mmap: pagesize: %u, regionsize: %u",
493 (unsigned int) sysconf(_SC_PAGE_SIZE
), IMX_GPIO_REGS_COUNT
* IMX_GPIO_SIZE
);
494 pio_base
= mmap(NULL
, IMX_GPIO_REGS_COUNT
* IMX_GPIO_SIZE
,
495 PROT_READ
| PROT_WRITE
,
496 MAP_SHARED
, dev_mem_fd
, imx_gpio_peri_base
);
498 if (pio_base
== MAP_FAILED
) {
501 return ERROR_JTAG_INIT_FAILED
;
505 * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
506 * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
508 if (imx_gpio_jtag_mode_possible()) {
509 tdo_gpio_mode
= gpio_mode_get(tdo_gpio
);
510 tdi_gpio_mode
= gpio_mode_get(tdi_gpio
);
511 tck_gpio_mode
= gpio_mode_get(tck_gpio
);
512 tms_gpio_mode
= gpio_mode_get(tms_gpio
);
514 gpio_clear(tdi_gpio
);
515 gpio_clear(tck_gpio
);
518 gpio_mode_input_set(tdo_gpio
);
519 gpio_mode_output_set(tdi_gpio
);
520 gpio_mode_output_set(tck_gpio
);
521 gpio_mode_output_set(tms_gpio
);
523 if (imx_gpio_swd_mode_possible()) {
524 swclk_gpio_mode
= gpio_mode_get(swclk_gpio
);
525 swdio_gpio_mode
= gpio_mode_get(swdio_gpio
);
527 gpio_clear(swdio_gpio
);
528 gpio_clear(swclk_gpio
);
529 gpio_mode_output_set(swclk_gpio
);
530 gpio_mode_output_set(swdio_gpio
);
532 if (trst_gpio
!= -1) {
533 trst_gpio_mode
= gpio_mode_get(trst_gpio
);
535 gpio_mode_output_set(trst_gpio
);
537 if (srst_gpio
!= -1) {
538 srst_gpio_mode
= gpio_mode_get(srst_gpio
);
540 gpio_mode_output_set(srst_gpio
);
543 LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d "
544 "tdo %d trst %d srst %d", tck_gpio_mode
, tms_gpio_mode
,
545 tdi_gpio_mode
, tdo_gpio_mode
, trst_gpio_mode
, srst_gpio_mode
);
548 imx_gpio_bitbang
.write
= imx_gpio_swd_write
;
549 bitbang_switch_to_swd();
555 static int imx_gpio_quit(void)
557 if (imx_gpio_jtag_mode_possible()) {
558 gpio_mode_set(tdo_gpio
, tdo_gpio_mode
);
559 gpio_mode_set(tdi_gpio
, tdi_gpio_mode
);
560 gpio_mode_set(tck_gpio
, tck_gpio_mode
);
561 gpio_mode_set(tms_gpio
, tms_gpio_mode
);
563 if (imx_gpio_swd_mode_possible()) {
564 gpio_mode_set(swclk_gpio
, swclk_gpio_mode
);
565 gpio_mode_set(swdio_gpio
, swdio_gpio_mode
);
568 gpio_mode_set(trst_gpio
, trst_gpio_mode
);
570 gpio_mode_set(srst_gpio
, srst_gpio_mode
);
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)