jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / jtag / drivers / amt_jtagaccel.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2005 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <jtag/adapter.h>
13 #include <jtag/interface.h>
14
15 #if PARPORT_USE_PPDEV == 1
16 #include <linux/parport.h>
17 #include <linux/ppdev.h>
18 #include <sys/ioctl.h>
19 #else /* not PARPORT_USE_PPDEV */
20 #ifndef _WIN32
21 #include <sys/io.h>
22 #endif
23 #endif
24
25 #if PARPORT_USE_GIVEIO == 1
26 #if IS_CYGWIN == 1
27 #include <windows.h>
28 #endif
29 #endif
30
31 /**
32 * @file
33 * Support the Amontec Chameleon POD with JTAG Accelerator support.
34 * This is a parallel port JTAG adapter with a CPLD between the
35 * parallel port and the JTAG connection. VHDL code running in the
36 * CPLD significantly accelerates JTAG operations compared to the
37 * bitbanging "Wiggler" style of most parallel port adapters.
38 */
39
40 /* configuration */
41 static uint16_t amt_jtagaccel_port;
42
43 /* interface variables
44 */
45 static uint8_t aw_control_rst;
46 static uint8_t aw_control_fsm = 0x10;
47 static uint8_t aw_control_baudrate = 0x20;
48
49 static int rtck_enabled;
50
51 #if PARPORT_USE_PPDEV == 1
52 static int device_handle;
53
54 static const int addr_mode = IEEE1284_MODE_EPP | IEEE1284_ADDR;
55
56 /* FIXME do something sane when these ioctl/read/write calls fail. */
57
58 #define AMT_AW(val) \
59 do { \
60 int __retval; \
61 \
62 __retval = ioctl(device_handle, PPSETMODE, &addr_mode); \
63 assert(__retval >= 0); \
64 __retval = write(device_handle, &val, 1); \
65 assert(__retval >= 0); \
66 } while (0)
67 #define AMT_AR(val) \
68 do { \
69 int __retval; \
70 \
71 __retval = ioctl(device_handle, PPSETMODE, &addr_mode); \
72 assert(__retval >= 0); \
73 __retval = read(device_handle, &val, 1); \
74 assert(__retval >= 0); \
75 } while (0)
76
77 static const int data_mode = IEEE1284_MODE_EPP | IEEE1284_DATA;
78
79 #define AMT_DW(val) \
80 do { \
81 int __retval; \
82 \
83 __retval = ioctl(device_handle, PPSETMODE, &data_mode); \
84 assert(__retval >= 0); \
85 __retval = write(device_handle, &val, 1); \
86 assert(__retval >= 0); \
87 } while (0)
88 #define AMT_DR(val) \
89 do { \
90 int __retval; \
91 \
92 __retval = ioctl(device_handle, PPSETMODE, &data_mode); \
93 assert(__retval >= 0); \
94 __retval = read(device_handle, &val, 1); \
95 assert(__retval >= 0); \
96 } while (0)
97
98 #else
99
100 #define AMT_AW(val) do { outb(val, amt_jtagaccel_port + 3); } while (0)
101 #define AMT_AR(val) do { val = inb(amt_jtagaccel_port + 3); } while (0)
102 #define AMT_DW(val) do { outb(val, amt_jtagaccel_port + 4); } while (0)
103 #define AMT_DR(val) do { val = inb(amt_jtagaccel_port + 4); } while (0)
104
105 #endif /* PARPORT_USE_PPDEV */
106
107 /* tap_move[i][j]: tap movement command to go from state i to state j
108 * 0: Test-Logic-Reset
109 * 1: Run-Test/Idle
110 * 2: Shift-DR
111 * 3: Pause-DR
112 * 4: Shift-IR
113 * 5: Pause-IR
114 */
115 static const uint8_t amt_jtagaccel_tap_move[6][6][2] = {
116 /* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */
117 { {0x1f, 0x00}, {0x0f, 0x00}, {0x05, 0x00}, {0x0a, 0x00}, {0x06, 0x00}, {0x96, 0x00} }, /* RESET */
118 { {0x1f, 0x00}, {0x00, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x0b, 0x00} }, /* IDLE */
119 { {0x1f, 0x00}, {0x0d, 0x00}, {0x00, 0x00}, {0x01, 0x00}, {0x8f, 0x09}, {0x8f, 0x01} }, /* DRSHIFT */
120 { {0x1f, 0x00}, {0x0c, 0x00}, {0x08, 0x00}, {0x00, 0x00}, {0x8f, 0x09}, {0x8f, 0x01} }, /* DRPAUSE */
121 { {0x1f, 0x00}, {0x0d, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x00, 0x00}, {0x01, 0x00} }, /* IRSHIFT */
122 { {0x1f, 0x00}, {0x0c, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x08, 0x00}, {0x00, 0x00} }, /* IRPAUSE */
123 };
124
125 static void amt_jtagaccel_reset(int trst, int srst)
126 {
127 if (trst == 1)
128 aw_control_rst |= 0x4;
129 else if (trst == 0)
130 aw_control_rst &= ~0x4;
131
132 if (srst == 1)
133 aw_control_rst |= 0x1;
134 else if (srst == 0)
135 aw_control_rst &= ~0x1;
136
137 AMT_AW(aw_control_rst);
138 }
139
140 static int amt_jtagaccel_speed(int speed)
141 {
142 aw_control_baudrate &= 0xf0;
143 aw_control_baudrate |= speed & 0x0f;
144 AMT_AW(aw_control_baudrate);
145
146 return ERROR_OK;
147 }
148
149 static void amt_jtagaccel_end_state(tap_state_t state)
150 {
151 if (tap_is_state_stable(state))
152 tap_set_end_state(state);
153 else {
154 LOG_ERROR("BUG: %i is not a valid end state", state);
155 exit(-1);
156 }
157 }
158
159 static void amt_wait_scan_busy(void)
160 {
161 int timeout = 4096;
162 uint8_t ar_status;
163
164 AMT_AR(ar_status);
165 while (((ar_status) & 0x80) && (timeout-- > 0))
166 AMT_AR(ar_status);
167
168 if (ar_status & 0x80) {
169 LOG_ERROR(
170 "amt_jtagaccel timed out while waiting for end of scan, rtck was %s, last AR_STATUS: 0x%2.2x",
171 (rtck_enabled) ? "enabled" : "disabled",
172 ar_status);
173 exit(-1);
174 }
175 }
176
177 static void amt_jtagaccel_state_move(void)
178 {
179 uint8_t aw_scan_tms_5;
180 uint8_t tms_scan[2];
181
182 tap_state_t cur_state = tap_get_state();
183 tap_state_t end_state = tap_get_end_state();
184
185 tms_scan[0] = amt_jtagaccel_tap_move[tap_move_ndx(cur_state)][tap_move_ndx(end_state)][0];
186 tms_scan[1] = amt_jtagaccel_tap_move[tap_move_ndx(cur_state)][tap_move_ndx(end_state)][1];
187
188 aw_scan_tms_5 = 0x40 | (tms_scan[0] & 0x1f);
189 AMT_AW(aw_scan_tms_5);
190 int jtag_speed = 0;
191 int retval = adapter_get_speed(&jtag_speed);
192 assert(retval == ERROR_OK);
193 if (jtag_speed > 3 || rtck_enabled)
194 amt_wait_scan_busy();
195
196 if (tms_scan[0] & 0x80) {
197 aw_scan_tms_5 = 0x40 | (tms_scan[1] & 0x1f);
198 AMT_AW(aw_scan_tms_5);
199 if (jtag_speed > 3 || rtck_enabled)
200 amt_wait_scan_busy();
201 }
202
203 tap_set_state(end_state);
204 }
205
206 static void amt_jtagaccel_runtest(int num_cycles)
207 {
208 int i = 0;
209 uint8_t aw_scan_tms_5;
210 uint8_t aw_scan_tms_1to4;
211
212 tap_state_t saved_end_state = tap_get_end_state();
213
214 /* only do a state_move when we're not already in IDLE */
215 if (tap_get_state() != TAP_IDLE) {
216 amt_jtagaccel_end_state(TAP_IDLE);
217 amt_jtagaccel_state_move();
218 }
219
220 while (num_cycles - i >= 5) {
221 aw_scan_tms_5 = 0x40;
222 AMT_AW(aw_scan_tms_5);
223 i += 5;
224 }
225
226 if (num_cycles - i > 0) {
227 aw_scan_tms_1to4 = 0x80 | ((num_cycles - i - 1) & 0x3) << 4;
228 AMT_AW(aw_scan_tms_1to4);
229 }
230
231 amt_jtagaccel_end_state(saved_end_state);
232 if (tap_get_state() != tap_get_end_state())
233 amt_jtagaccel_state_move();
234 }
235
236 static void amt_jtagaccel_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size)
237 {
238 int bits_left = scan_size;
239 int bit_count = 0;
240 tap_state_t saved_end_state = tap_get_end_state();
241 uint8_t aw_tdi_option;
242 uint8_t dw_tdi_scan;
243 uint8_t dr_tdo;
244 uint8_t aw_tms_scan;
245 uint8_t tms_scan[2];
246 int jtag_speed_var;
247 int retval = adapter_get_speed(&jtag_speed_var);
248 assert(retval == ERROR_OK);
249
250 if (ir_scan)
251 amt_jtagaccel_end_state(TAP_IRSHIFT);
252 else
253 amt_jtagaccel_end_state(TAP_DRSHIFT);
254
255 /* Only move if we're not already there */
256 if (tap_get_state() != tap_get_end_state())
257 amt_jtagaccel_state_move();
258
259 amt_jtagaccel_end_state(saved_end_state);
260
261 /* handle unaligned bits at the beginning */
262 if ((scan_size - 1) % 8) {
263 aw_tdi_option = 0x30 | (((scan_size - 1) % 8) - 1);
264 AMT_AW(aw_tdi_option);
265
266 dw_tdi_scan = buf_get_u32(buffer, bit_count, (scan_size - 1) % 8) & 0xff;
267 AMT_DW(dw_tdi_scan);
268 if (jtag_speed_var > 3 || rtck_enabled)
269 amt_wait_scan_busy();
270
271 if ((type == SCAN_IN) || (type == SCAN_IO)) {
272 AMT_DR(dr_tdo);
273 dr_tdo = dr_tdo >> (8 - ((scan_size - 1) % 8));
274 buf_set_u32(buffer, bit_count, (scan_size - 1) % 8, dr_tdo);
275 }
276
277 bit_count += (scan_size - 1) % 8;
278 bits_left -= (scan_size - 1) % 8;
279 }
280
281 while (bits_left - 1 >= 8) {
282 dw_tdi_scan = buf_get_u32(buffer, bit_count, 8) & 0xff;
283 AMT_DW(dw_tdi_scan);
284 if (jtag_speed_var > 3 || rtck_enabled)
285 amt_wait_scan_busy();
286
287 if ((type == SCAN_IN) || (type == SCAN_IO)) {
288 AMT_DR(dr_tdo);
289 buf_set_u32(buffer, bit_count, 8, dr_tdo);
290 }
291
292 bit_count += 8;
293 bits_left -= 8;
294 }
295
296 tms_scan[0] =
297 amt_jtagaccel_tap_move[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())][0];
298 tms_scan[1] =
299 amt_jtagaccel_tap_move[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())][1];
300 aw_tms_scan = 0x40 | (tms_scan[0] & 0x1f) | (buf_get_u32(buffer, bit_count, 1) << 5);
301 AMT_AW(aw_tms_scan);
302 if (jtag_speed_var > 3 || rtck_enabled)
303 amt_wait_scan_busy();
304
305 if ((type == SCAN_IN) || (type == SCAN_IO)) {
306 AMT_DR(dr_tdo);
307 dr_tdo = dr_tdo >> 7;
308 buf_set_u32(buffer, bit_count, 1, dr_tdo);
309 }
310
311 if (tms_scan[0] & 0x80) {
312 aw_tms_scan = 0x40 | (tms_scan[1] & 0x1f);
313 AMT_AW(aw_tms_scan);
314 if (jtag_speed_var > 3 || rtck_enabled)
315 amt_wait_scan_busy();
316 }
317 tap_set_state(tap_get_end_state());
318 }
319
320 static int amt_jtagaccel_execute_queue(struct jtag_command *cmd_queue)
321 {
322 struct jtag_command *cmd = cmd_queue; /* currently processed command */
323 int scan_size;
324 enum scan_type type;
325 uint8_t *buffer;
326 int retval;
327
328 /* return ERROR_OK, unless a jtag_read_buffer returns a failed check
329 * that wasn't handled by a caller-provided error handler
330 */
331 retval = ERROR_OK;
332
333 while (cmd) {
334 switch (cmd->type) {
335 case JTAG_RESET:
336 LOG_DEBUG_IO("reset trst: %i srst %i",
337 cmd->cmd.reset->trst,
338 cmd->cmd.reset->srst);
339 if (cmd->cmd.reset->trst == 1)
340 tap_set_state(TAP_RESET);
341 amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
342 break;
343 case JTAG_RUNTEST:
344 LOG_DEBUG_IO("runtest %i cycles, end in %i",
345 cmd->cmd.runtest->num_cycles,
346 cmd->cmd.runtest->end_state);
347 amt_jtagaccel_end_state(cmd->cmd.runtest->end_state);
348 amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles);
349 break;
350 case JTAG_TLR_RESET:
351 LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state);
352 amt_jtagaccel_end_state(cmd->cmd.statemove->end_state);
353 amt_jtagaccel_state_move();
354 break;
355 case JTAG_SCAN:
356 LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state);
357 amt_jtagaccel_end_state(cmd->cmd.scan->end_state);
358 scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
359 type = jtag_scan_type(cmd->cmd.scan);
360 amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
361 if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
362 retval = ERROR_JTAG_QUEUE_FAILED;
363 free(buffer);
364 break;
365 case JTAG_SLEEP:
366 LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us);
367 jtag_sleep(cmd->cmd.sleep->us);
368 break;
369 default:
370 LOG_ERROR("BUG: unknown JTAG command type encountered");
371 exit(-1);
372 }
373 cmd = cmd->next;
374 }
375
376 return retval;
377 }
378
379 #if PARPORT_USE_GIVEIO == 1
380 int amt_jtagaccel_get_giveio_access(void)
381 {
382 HANDLE h;
383 OSVERSIONINFO version;
384
385 version.dwOSVersionInfoSize = sizeof(version);
386 if (!GetVersionEx(&version)) {
387 errno = EINVAL;
388 return -1;
389 }
390 if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
391 return 0;
392
393 h = CreateFile("\\\\.\\giveio",
394 GENERIC_READ,
395 0,
396 NULL,
397 OPEN_EXISTING,
398 FILE_ATTRIBUTE_NORMAL,
399 NULL);
400 if (h == INVALID_HANDLE_VALUE) {
401 errno = ENODEV;
402 return -1;
403 }
404
405 CloseHandle(h);
406
407 return 0;
408 }
409 #endif
410
411 static int amt_jtagaccel_init(void)
412 {
413 #if PARPORT_USE_PPDEV == 1
414 char buffer[256];
415 int i = 0;
416 uint8_t control_port;
417 #else
418 uint8_t status_port;
419 #endif
420 uint8_t ar_status;
421
422 #if PARPORT_USE_PPDEV == 1
423 if (device_handle > 0) {
424 LOG_ERROR("device is already opened");
425 return ERROR_JTAG_INIT_FAILED;
426 }
427
428 snprintf(buffer, 256, "/dev/parport%d", amt_jtagaccel_port);
429 device_handle = open(buffer, O_RDWR);
430
431 if (device_handle < 0) {
432 LOG_ERROR(
433 "cannot open device. check it exists and that user read and write rights are set");
434 return ERROR_JTAG_INIT_FAILED;
435 }
436
437 i = ioctl(device_handle, PPCLAIM);
438 if (i < 0) {
439 LOG_ERROR("cannot claim device");
440 return ERROR_JTAG_INIT_FAILED;
441 }
442
443 i = IEEE1284_MODE_EPP;
444 i = ioctl(device_handle, PPSETMODE, &i);
445 if (i < 0) {
446 LOG_ERROR(" cannot set compatible mode to device");
447 return ERROR_JTAG_INIT_FAILED;
448 }
449
450 control_port = 0x00;
451 i = ioctl(device_handle, PPWCONTROL, &control_port);
452
453 control_port = 0x04;
454 i = ioctl(device_handle, PPWCONTROL, &control_port);
455
456 #else
457 if (amt_jtagaccel_port == 0) {
458 amt_jtagaccel_port = 0x378;
459 LOG_WARNING("No parport port specified, using default '0x378' (LPT1)");
460 }
461
462 #if PARPORT_USE_GIVEIO == 1
463 if (amt_jtagaccel_get_giveio_access() != 0) {
464 #else /* PARPORT_USE_GIVEIO */
465 if (ioperm(amt_jtagaccel_port, 5, 1) != 0) {
466 #endif /* PARPORT_USE_GIVEIO */
467 LOG_ERROR("missing privileges for direct i/o");
468 return ERROR_JTAG_INIT_FAILED;
469 }
470
471 /* prepare epp port
472 * clear timeout */
473 status_port = inb(amt_jtagaccel_port + 1);
474 outb(status_port | 0x1, amt_jtagaccel_port + 1);
475
476 /* reset epp port */
477 outb(0x00, amt_jtagaccel_port + 2);
478 outb(0x04, amt_jtagaccel_port + 2);
479 #endif
480
481 if (rtck_enabled) {
482 /* set RTCK enable bit */
483 aw_control_fsm |= 0x02;
484 }
485
486 /* enable JTAG port */
487 aw_control_fsm |= 0x04;
488 AMT_AW(aw_control_fsm);
489
490 enum reset_types jtag_reset_config = jtag_get_reset_config();
491 if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
492 aw_control_rst &= ~0x8;
493 else
494 aw_control_rst |= 0x8;
495
496 if (jtag_reset_config & RESET_SRST_PUSH_PULL)
497 aw_control_rst &= ~0x2;
498 else
499 aw_control_rst |= 0x2;
500
501 amt_jtagaccel_reset(0, 0);
502
503 /* read status register */
504 AMT_AR(ar_status);
505 LOG_DEBUG("AR_STATUS: 0x%2.2x", ar_status);
506
507 return ERROR_OK;
508 }
509
510 static int amt_jtagaccel_quit(void)
511 {
512
513 return ERROR_OK;
514 }
515
516 COMMAND_HANDLER(amt_jtagaccel_handle_parport_port_command)
517 {
518 if (CMD_ARGC == 1) {
519 /* only if the port wasn't overwritten by cmdline */
520 if (amt_jtagaccel_port == 0) {
521 uint16_t port;
522 COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
523 amt_jtagaccel_port = port;
524 } else {
525 LOG_ERROR("The parport port was already configured!");
526 return ERROR_FAIL;
527 }
528 }
529
530 command_print(CMD, "parport port = %u", amt_jtagaccel_port);
531
532 return ERROR_OK;
533 }
534
535 COMMAND_HANDLER(amt_jtagaccel_handle_rtck_command)
536 {
537 if (CMD_ARGC == 0) {
538 command_print(CMD,
539 "amt_jtagaccel RTCK feature %s",
540 (rtck_enabled) ? "enabled" : "disabled");
541 return ERROR_OK;
542 } else {
543 if (strcmp(CMD_ARGV[0], "enabled") == 0)
544 rtck_enabled = 1;
545 else
546 rtck_enabled = 0;
547 }
548
549 return ERROR_OK;
550 }
551
552 static const struct command_registration amtjtagaccel_command_handlers[] = {
553 {
554 .name = "parport_port",
555 .handler = &amt_jtagaccel_handle_parport_port_command,
556 .mode = COMMAND_CONFIG,
557 .help = "configure or display the parallel port to use",
558 .usage = "[port_num]",
559 },
560 {
561 /**
562 * @todo Remove this "rtck" command; just use the standard
563 * mechanism to enable/disable adaptive clocking. First
564 * implement the standard mechanism and deprecate "rtck";
565 * after a year or so, it'll be safe to remove this.
566 */
567 .name = "rtck",
568 .handler = &amt_jtagaccel_handle_rtck_command,
569 .mode = COMMAND_CONFIG,
570 .help = "configure or display RTCK support",
571 .usage = "[enable|disable]",
572 },
573 COMMAND_REGISTRATION_DONE
574 };
575
576 static struct jtag_interface amt_jtagaccel_interface = {
577 .execute_queue = amt_jtagaccel_execute_queue,
578 };
579
580 struct adapter_driver amt_jtagaccel_adapter_driver = {
581 .name = "amt_jtagaccel",
582 .transports = jtag_only,
583 .commands = amtjtagaccel_command_handlers,
584
585 .init = amt_jtagaccel_init,
586 .quit = amt_jtagaccel_quit,
587 .speed = amt_jtagaccel_speed,
588
589 .jtag_ops = &amt_jtagaccel_interface,
590 };

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)