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

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)