jtag/presto: switch to command 'adapter serial'
[openocd.git] / src / jtag / drivers / presto.c
1 /***************************************************************************
2 * Copyright (C) 2007 by Pavel Chromy *
3 * chromy@asix.cz *
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 /**
20 * @file
21 * Holds driver for PRESTO programmer from ASIX.
22 * http://tools.asix.net/prg_presto.htm
23 */
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #if IS_CYGWIN == 1
29 #include "windows.h"
30 #endif
31
32 #include <jtag/adapter.h>
33 #include <jtag/interface.h>
34 #include <helper/time_support.h>
35 #include "bitq.h"
36
37 /* PRESTO access library includes */
38 #include "libftdi_helper.h"
39
40 /* -------------------------------------------------------------------------- */
41
42 #define FT_DEVICE_NAME_LEN 64
43 #define FT_DEVICE_SERNUM_LEN 64
44
45 #define PRESTO_VID_PID 0x0403f1a0
46 #define PRESTO_VID (0x0403)
47 #define PRESTO_PID (0xf1a0)
48
49 #define BUFFER_SIZE (64*62)
50
51 struct presto {
52 struct ftdi_context ftdic;
53 int retval;
54
55 char serial[FT_DEVICE_SERNUM_LEN];
56
57 uint8_t buff_out[BUFFER_SIZE];
58 int buff_out_pos;
59
60 uint8_t buff_in[BUFFER_SIZE];
61 int buff_in_exp;/* expected in buffer length */
62 int buff_in_len;/* length of data received */
63 int buff_in_pos;
64
65 unsigned long total_out;
66 unsigned long total_in;
67
68 int jtag_tms; /* last tms state */
69 int jtag_tck; /* last tck state */
70 int jtag_rst; /* last trst state */
71
72 int jtag_tdi_data;
73 int jtag_tdi_count;
74
75 int jtag_speed;
76 };
77
78 static struct presto presto_state;
79 static struct presto *presto = &presto_state;
80
81 static uint8_t presto_init_seq[] = {
82 0x80, 0xA0, 0xA8, 0xB0, 0xC0, 0xE0
83 };
84
85 static int presto_write(uint8_t *buf, uint32_t size)
86 {
87 uint32_t ftbytes;
88 presto->retval = ftdi_write_data(&presto->ftdic, buf, size);
89 if (presto->retval < 0) {
90 LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&presto->ftdic));
91 return ERROR_JTAG_DEVICE_ERROR;
92 }
93 ftbytes = presto->retval;
94
95 if (ftbytes != size) {
96 LOG_ERROR("couldn't write the requested number of bytes to PRESTO (%u < %u)",
97 (unsigned)ftbytes, (unsigned)size);
98 return ERROR_JTAG_DEVICE_ERROR;
99 }
100
101 return ERROR_OK;
102 }
103
104 static int presto_read(uint8_t *buf, uint32_t size)
105 {
106 uint32_t ftbytes = 0;
107
108 struct timeval timeout, now;
109 gettimeofday(&timeout, NULL);
110 timeval_add_time(&timeout, 1, 0); /* one second timeout */
111
112 while (ftbytes < size) {
113 presto->retval = ftdi_read_data(&presto->ftdic, buf + ftbytes, size - ftbytes);
114 if (presto->retval < 0) {
115 LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(&presto->ftdic));
116 return ERROR_JTAG_DEVICE_ERROR;
117 }
118 ftbytes += presto->retval;
119
120 gettimeofday(&now, NULL);
121 if (timeval_compare(&now, &timeout) > 0)
122 break;
123 }
124
125 if (ftbytes != size) {
126 /* this is just a warning, there might have been timeout when detecting PRESTO,
127 *which is not fatal */
128 LOG_WARNING("couldn't read the requested number of bytes from PRESTO (%u < %u)",
129 (unsigned)ftbytes, (unsigned)size);
130 return ERROR_JTAG_DEVICE_ERROR;
131 }
132
133 return ERROR_OK;
134 }
135
136 static int presto_open_libftdi(const char *req_serial)
137 {
138 uint8_t presto_data;
139
140 LOG_DEBUG("searching for PRESTO using libftdi");
141
142 /* initialize FTDI context structure */
143 if (ftdi_init(&presto->ftdic) < 0) {
144 LOG_ERROR("unable to init libftdi: %s", presto->ftdic.error_str);
145 return ERROR_JTAG_DEVICE_ERROR;
146 }
147
148 /* context, vendor id, product id */
149 if (ftdi_usb_open_desc(&presto->ftdic, PRESTO_VID, PRESTO_PID, NULL, req_serial) < 0) {
150 LOG_ERROR("unable to open PRESTO: %s", presto->ftdic.error_str);
151 return ERROR_JTAG_DEVICE_ERROR;
152 }
153
154 if (ftdi_usb_reset(&presto->ftdic) < 0) {
155 LOG_ERROR("unable to reset PRESTO device");
156 return ERROR_JTAG_DEVICE_ERROR;
157 }
158
159 if (ftdi_set_latency_timer(&presto->ftdic, 1) < 0) {
160 LOG_ERROR("unable to set latency timer");
161 return ERROR_JTAG_DEVICE_ERROR;
162 }
163
164 if (ftdi_tcioflush(&presto->ftdic) < 0) {
165 LOG_ERROR("unable to flush PRESTO buffers");
166 return ERROR_JTAG_DEVICE_ERROR;
167 }
168
169 presto_data = 0xD0;
170 if (presto_write(&presto_data, 1) != ERROR_OK) {
171 LOG_ERROR("error writing to PRESTO");
172 return ERROR_JTAG_DEVICE_ERROR;
173 }
174
175 if (presto_read(&presto_data, 1) != ERROR_OK) {
176 LOG_DEBUG("no response from PRESTO, retrying");
177
178 if (ftdi_tcioflush(&presto->ftdic) < 0)
179 return ERROR_JTAG_DEVICE_ERROR;
180
181 presto_data = 0xD0;
182 if (presto_write(&presto_data, 1) != ERROR_OK)
183 return ERROR_JTAG_DEVICE_ERROR;
184
185 if (presto_read(&presto_data, 1) != ERROR_OK) {
186 LOG_ERROR("no response from PRESTO, giving up");
187 return ERROR_JTAG_DEVICE_ERROR;
188 }
189 }
190
191 if (presto_write(presto_init_seq, sizeof(presto_init_seq)) != ERROR_OK) {
192 LOG_ERROR("error writing PRESTO init sequence");
193 return ERROR_JTAG_DEVICE_ERROR;
194 }
195
196 return ERROR_OK;
197 }
198
199 static int presto_open(const char *req_serial)
200 {
201 presto->buff_out_pos = 0;
202 presto->buff_in_pos = 0;
203 presto->buff_in_len = 0;
204 presto->buff_in_exp = 0;
205
206 presto->total_out = 0;
207 presto->total_in = 0;
208
209 presto->jtag_tms = 0;
210 presto->jtag_tck = 0;
211 presto->jtag_rst = 0;
212 presto->jtag_tdi_data = 0;
213 presto->jtag_tdi_count = 0;
214
215 presto->jtag_speed = 0;
216
217 return presto_open_libftdi(req_serial);
218 }
219
220 static int presto_close(void)
221 {
222
223 int result = ERROR_OK;
224
225 presto->retval = ftdi_write_data(&presto->ftdic, presto_init_seq, sizeof(presto_init_seq));
226 if (presto->retval != sizeof(presto_init_seq))
227 result = ERROR_JTAG_DEVICE_ERROR;
228
229 presto->retval = ftdi_set_latency_timer(&presto->ftdic, 16);
230 if (presto->retval < 0)
231 result = ERROR_JTAG_DEVICE_ERROR;
232
233 presto->retval = ftdi_usb_close(&presto->ftdic);
234 if (presto->retval < 0)
235 result = ERROR_JTAG_DEVICE_ERROR;
236 else
237 ftdi_deinit(&presto->ftdic);
238
239 return result;
240 }
241
242 static int presto_flush(void)
243 {
244 if (presto->buff_out_pos == 0)
245 return ERROR_OK;
246
247 if (presto->retval < 0) {
248 LOG_DEBUG("error in previous communication, canceling I/O operation");
249 return ERROR_JTAG_DEVICE_ERROR;
250 }
251
252 if (presto_write(presto->buff_out, presto->buff_out_pos) != ERROR_OK) {
253 presto->buff_out_pos = 0;
254 return ERROR_JTAG_DEVICE_ERROR;
255 }
256
257 presto->total_out += presto->buff_out_pos;
258 presto->buff_out_pos = 0;
259
260 if (presto->buff_in_exp == 0)
261 return ERROR_OK;
262
263 presto->buff_in_pos = 0;
264 presto->buff_in_len = 0;
265
266 if (presto_read(presto->buff_in, presto->buff_in_exp) != ERROR_OK) {
267 presto->buff_in_exp = 0;
268 return ERROR_JTAG_DEVICE_ERROR;
269 }
270
271 presto->total_in += presto->buff_in_exp;
272 presto->buff_in_len = presto->buff_in_exp;
273 presto->buff_in_exp = 0;
274
275 return ERROR_OK;
276 }
277
278 static int presto_sendbyte(int data)
279 {
280 if (data == EOF)
281 return presto_flush();
282
283 if (presto->buff_out_pos < BUFFER_SIZE) {
284 presto->buff_out[presto->buff_out_pos++] = (uint8_t)data;
285 if (((data & 0xC0) == 0x40) || ((data & 0xD0) == 0xD0))
286 presto->buff_in_exp++;
287 } else
288 return ERROR_JTAG_DEVICE_ERROR;
289
290 /* libftdi does not do background read, be sure that USB IN buffer does not overflow (128
291 *bytes only!) */
292 if (presto->buff_out_pos >= BUFFER_SIZE || presto->buff_in_exp == 128)
293 return presto_flush();
294
295 return ERROR_OK;
296 }
297
298 #if 0
299 static int presto_getbyte(void)
300 {
301 if (presto->buff_in_pos < presto->buff_in_len)
302 return presto->buff_in[presto->buff_in_pos++];
303
304 if (presto->buff_in_exp == 0)
305 return -1;
306
307 if (presto_flush() != ERROR_OK)
308 return -1;
309
310 if (presto->buff_in_pos < presto->buff_in_len)
311 return presto->buff_in[presto->buff_in_pos++];
312
313 return -1;
314 }
315 #endif
316
317 /* -------------------------------------------------------------------------- */
318
319 static int presto_tdi_flush(void)
320 {
321 if (presto->jtag_tdi_count == 0)
322 return 0;
323
324 if (presto->jtag_tck == 0) {
325 LOG_ERROR("BUG: unexpected TAP condition, TCK low");
326 return -1;
327 }
328
329 presto->jtag_tdi_data |= (presto->jtag_tdi_count - 1) << 4;
330 presto_sendbyte(presto->jtag_tdi_data);
331 presto->jtag_tdi_count = 0;
332 presto->jtag_tdi_data = 0;
333
334 return 0;
335 }
336
337 static int presto_tck_idle(void)
338 {
339 if (presto->jtag_tck == 1) {
340 presto_sendbyte(0xCA);
341 presto->jtag_tck = 0;
342 }
343
344 return 0;
345 }
346
347 /* -------------------------------------------------------------------------- */
348
349 static int presto_bitq_out(int tms, int tdi, int tdo_req)
350 {
351 int i;
352 unsigned char cmd;
353
354 if (presto->jtag_tck == 0)
355 presto_sendbyte(0xA4); /* LED indicator - JTAG active */
356 else if (presto->jtag_speed == 0 && !tdo_req && tms == presto->jtag_tms) {
357 presto->jtag_tdi_data |= (tdi != 0) << presto->jtag_tdi_count;
358
359 if (++presto->jtag_tdi_count == 4)
360 presto_tdi_flush();
361
362 return 0;
363 }
364
365 presto_tdi_flush();
366
367 cmd = tdi ? 0xCB : 0xCA;
368 presto_sendbyte(cmd);
369
370 if (tms != presto->jtag_tms) {
371 presto_sendbyte((tms ? 0xEC : 0xE8) | (presto->jtag_rst ? 0x02 : 0));
372 presto->jtag_tms = tms;
373 }
374
375 /* delay with TCK low */
376 for (i = presto->jtag_speed; i > 1; i--)
377 presto_sendbyte(cmd);
378
379 cmd |= 0x04;
380 presto_sendbyte(cmd | (tdo_req ? 0x10 : 0));
381
382 /* delay with TCK high */
383 for (i = presto->jtag_speed; i > 1; i--)
384 presto_sendbyte(cmd);
385
386 presto->jtag_tck = 1;
387
388 return 0;
389 }
390
391 static int presto_bitq_flush(void)
392 {
393 presto_tdi_flush();
394 presto_tck_idle();
395
396 presto_sendbyte(0xA0); /* LED indicator - JTAG idle */
397
398 return presto_flush();
399 }
400
401 static int presto_bitq_in_rdy(void)
402 {
403 if (presto->buff_in_pos >= presto->buff_in_len)
404 return 0;
405 return presto->buff_in_len-presto->buff_in_pos;
406 }
407
408 static int presto_bitq_in(void)
409 {
410 if (presto->buff_in_pos >= presto->buff_in_len)
411 return -1;
412 if (presto->buff_in[presto->buff_in_pos++]&0x08)
413 return 1;
414 return 0;
415 }
416
417 static int presto_bitq_sleep(unsigned long us)
418 {
419 long waits;
420
421 presto_tdi_flush();
422 presto_tck_idle();
423
424 if (us > 100000) {
425 presto_bitq_flush();
426 jtag_sleep(us);
427 return 0;
428 }
429
430 waits = us / 170 + 2;
431 while (waits--)
432 presto_sendbyte(0x80);
433
434 return 0;
435 }
436
437 static int presto_bitq_reset(int trst, int srst)
438 {
439 presto_tdi_flush();
440 presto_tck_idle();
441
442 /* add a delay after possible TCK transition */
443 presto_sendbyte(0x80);
444 presto_sendbyte(0x80);
445
446 presto->jtag_rst = trst || srst;
447 presto_sendbyte((presto->jtag_rst ? 0xEA : 0xE8) | (presto->jtag_tms ? 0x04 : 0));
448
449 return 0;
450 }
451
452 static struct bitq_interface presto_bitq = {
453 .out = &presto_bitq_out,
454 .flush = &presto_bitq_flush,
455 .sleep = &presto_bitq_sleep,
456 .reset = &presto_bitq_reset,
457 .in_rdy = &presto_bitq_in_rdy,
458 .in = &presto_bitq_in,
459 };
460
461 /* -------------------------------------------------------------------------- */
462
463 static int presto_adapter_khz(int khz, int *jtag_speed)
464 {
465 if (khz < 0) {
466 *jtag_speed = 0;
467 return ERROR_COMMAND_SYNTAX_ERROR;
468 }
469
470 if (khz >= 3000)
471 *jtag_speed = 0;
472 else
473 *jtag_speed = (1000 + khz-1)/khz;
474
475 return 0;
476 }
477
478 static int presto_jtag_speed_div(int speed, int *khz)
479 {
480 if ((speed < 0) || (speed > 1000)) {
481 *khz = 0;
482 return ERROR_COMMAND_SYNTAX_ERROR;
483 }
484
485 if (speed == 0)
486 *khz = 3000;
487 else
488 *khz = 1000/speed;
489
490 return 0;
491 }
492
493 static int presto_jtag_speed(int speed)
494 {
495 int khz;
496
497 if (presto_jtag_speed_div(speed, &khz))
498 return ERROR_COMMAND_SYNTAX_ERROR;
499
500 presto->jtag_speed = speed;
501
502 if (khz%1000 == 0)
503 LOG_INFO("setting speed to %d, max. TCK freq. is %d MHz", speed, khz/1000);
504 else
505 LOG_INFO("setting speed to %d, max. TCK freq. is %d kHz", speed, khz);
506
507 return 0;
508 }
509
510 static int presto_jtag_init(void)
511 {
512 const char *presto_serial = adapter_get_required_serial();
513
514 if (presto_open(presto_serial) != ERROR_OK) {
515 presto_close();
516 if (presto_serial)
517 LOG_ERROR("Cannot open PRESTO, serial number '%s'", presto_serial);
518 else
519 LOG_ERROR("Cannot open PRESTO");
520 return ERROR_JTAG_INIT_FAILED;
521 }
522 LOG_INFO("PRESTO open, serial number '%s'", presto->serial);
523
524 bitq_interface = &presto_bitq;
525 return ERROR_OK;
526 }
527
528 static int presto_jtag_quit(void)
529 {
530 bitq_cleanup();
531 presto_close();
532 LOG_INFO("PRESTO closed");
533 return ERROR_OK;
534 }
535
536 static struct jtag_interface presto_interface = {
537 .execute_queue = bitq_execute_queue,
538 };
539
540 struct adapter_driver presto_adapter_driver = {
541 .name = "presto",
542 .transports = jtag_only,
543
544 .init = presto_jtag_init,
545 .quit = presto_jtag_quit,
546 .speed = presto_jtag_speed,
547 .khz = presto_adapter_khz,
548 .speed_div = presto_jtag_speed_div,
549
550 .jtag_ops = &presto_interface,
551 };

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)