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

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)