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

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)