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

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)