1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * altera-jtag.c |
4 | * |
5 | * altera FPGA driver |
6 | * |
7 | * Copyright (C) Altera Corporation 1998-2001 |
8 | * Copyright (C) 2010 NetUP Inc. |
9 | * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru> |
10 | */ |
11 | |
12 | #include <linux/delay.h> |
13 | #include <linux/firmware.h> |
14 | #include <linux/slab.h> |
15 | #include <misc/altera.h> |
16 | #include "altera-exprt.h" |
17 | #include "altera-jtag.h" |
18 | |
19 | #define alt_jtag_io(a, b, c)\ |
20 | astate->config->jtag_io(astate->config->dev, a, b, c); |
21 | |
22 | #define alt_malloc(a) kzalloc(a, GFP_KERNEL); |
23 | |
24 | /* |
25 | * This structure shows, for each JTAG state, which state is reached after |
26 | * a single TCK clock cycle with TMS high or TMS low, respectively. This |
27 | * describes all possible state transitions in the JTAG state machine. |
28 | */ |
29 | struct altera_jtag_machine { |
30 | enum altera_jtag_state tms_high; |
31 | enum altera_jtag_state tms_low; |
32 | }; |
33 | |
34 | static const struct altera_jtag_machine altera_transitions[] = { |
35 | /* RESET */ { RESET, IDLE }, |
36 | /* IDLE */ { DRSELECT, IDLE }, |
37 | /* DRSELECT */ { IRSELECT, DRCAPTURE }, |
38 | /* DRCAPTURE */ { DREXIT1, DRSHIFT }, |
39 | /* DRSHIFT */ { DREXIT1, DRSHIFT }, |
40 | /* DREXIT1 */ { DRUPDATE, DRPAUSE }, |
41 | /* DRPAUSE */ { DREXIT2, DRPAUSE }, |
42 | /* DREXIT2 */ { DRUPDATE, DRSHIFT }, |
43 | /* DRUPDATE */ { DRSELECT, IDLE }, |
44 | /* IRSELECT */ { RESET, IRCAPTURE }, |
45 | /* IRCAPTURE */ { IREXIT1, IRSHIFT }, |
46 | /* IRSHIFT */ { IREXIT1, IRSHIFT }, |
47 | /* IREXIT1 */ { IRUPDATE, IRPAUSE }, |
48 | /* IRPAUSE */ { IREXIT2, IRPAUSE }, |
49 | /* IREXIT2 */ { IRUPDATE, IRSHIFT }, |
50 | /* IRUPDATE */ { DRSELECT, IDLE } |
51 | }; |
52 | |
53 | /* |
54 | * This table contains the TMS value to be used to take the NEXT STEP on |
55 | * the path to the desired state. The array index is the current state, |
56 | * and the bit position is the desired endstate. To find out which state |
57 | * is used as the intermediate state, look up the TMS value in the |
58 | * altera_transitions[] table. |
59 | */ |
60 | static const u16 altera_jtag_path_map[16] = { |
61 | /* RST RTI SDRS CDR SDR E1DR PDR E2DR */ |
62 | 0x0001, 0xFFFD, 0xFE01, 0xFFE7, 0xFFEF, 0xFF0F, 0xFFBF, 0xFFFF, |
63 | /* UDR SIRS CIR SIR E1IR PIR E2IR UIR */ |
64 | 0xFEFD, 0x0001, 0xF3FF, 0xF7FF, 0x87FF, 0xDFFF, 0xFFFF, 0x7FFD |
65 | }; |
66 | |
67 | /* Flag bits for alt_jtag_io() function */ |
68 | #define TMS_HIGH 1 |
69 | #define TMS_LOW 0 |
70 | #define TDI_HIGH 1 |
71 | #define TDI_LOW 0 |
72 | #define READ_TDO 1 |
73 | #define IGNORE_TDO 0 |
74 | |
75 | int altera_jinit(struct altera_state *astate) |
76 | { |
77 | struct altera_jtag *js = &astate->js; |
78 | |
79 | /* initial JTAG state is unknown */ |
80 | js->jtag_state = ILLEGAL_JTAG_STATE; |
81 | |
82 | /* initialize to default state */ |
83 | js->drstop_state = IDLE; |
84 | js->irstop_state = IDLE; |
85 | js->dr_pre = 0; |
86 | js->dr_post = 0; |
87 | js->ir_pre = 0; |
88 | js->ir_post = 0; |
89 | js->dr_length = 0; |
90 | js->ir_length = 0; |
91 | |
92 | js->dr_pre_data = NULL; |
93 | js->dr_post_data = NULL; |
94 | js->ir_pre_data = NULL; |
95 | js->ir_post_data = NULL; |
96 | js->dr_buffer = NULL; |
97 | js->ir_buffer = NULL; |
98 | |
99 | return 0; |
100 | } |
101 | |
102 | int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state) |
103 | { |
104 | js->drstop_state = state; |
105 | |
106 | return 0; |
107 | } |
108 | |
109 | int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state) |
110 | { |
111 | js->irstop_state = state; |
112 | |
113 | return 0; |
114 | } |
115 | |
116 | int altera_set_dr_pre(struct altera_jtag *js, |
117 | u32 count, u32 start_index, |
118 | u8 *preamble_data) |
119 | { |
120 | int status = 0; |
121 | u32 i; |
122 | u32 j; |
123 | |
124 | if (count > js->dr_pre) { |
125 | kfree(objp: js->dr_pre_data); |
126 | js->dr_pre_data = (u8 *)alt_malloc((count + 7) >> 3); |
127 | if (js->dr_pre_data == NULL) |
128 | status = -ENOMEM; |
129 | else |
130 | js->dr_pre = count; |
131 | } else |
132 | js->dr_pre = count; |
133 | |
134 | if (status == 0) { |
135 | for (i = 0; i < count; ++i) { |
136 | j = i + start_index; |
137 | |
138 | if (preamble_data == NULL) |
139 | js->dr_pre_data[i >> 3] |= (1 << (i & 7)); |
140 | else { |
141 | if (preamble_data[j >> 3] & (1 << (j & 7))) |
142 | js->dr_pre_data[i >> 3] |= |
143 | (1 << (i & 7)); |
144 | else |
145 | js->dr_pre_data[i >> 3] &= |
146 | ~(u32)(1 << (i & 7)); |
147 | |
148 | } |
149 | } |
150 | } |
151 | |
152 | return status; |
153 | } |
154 | |
155 | int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, |
156 | u8 *preamble_data) |
157 | { |
158 | int status = 0; |
159 | u32 i; |
160 | u32 j; |
161 | |
162 | if (count > js->ir_pre) { |
163 | kfree(objp: js->ir_pre_data); |
164 | js->ir_pre_data = (u8 *)alt_malloc((count + 7) >> 3); |
165 | if (js->ir_pre_data == NULL) |
166 | status = -ENOMEM; |
167 | else |
168 | js->ir_pre = count; |
169 | |
170 | } else |
171 | js->ir_pre = count; |
172 | |
173 | if (status == 0) { |
174 | for (i = 0; i < count; ++i) { |
175 | j = i + start_index; |
176 | if (preamble_data == NULL) |
177 | js->ir_pre_data[i >> 3] |= (1 << (i & 7)); |
178 | else { |
179 | if (preamble_data[j >> 3] & (1 << (j & 7))) |
180 | js->ir_pre_data[i >> 3] |= |
181 | (1 << (i & 7)); |
182 | else |
183 | js->ir_pre_data[i >> 3] &= |
184 | ~(u32)(1 << (i & 7)); |
185 | |
186 | } |
187 | } |
188 | } |
189 | |
190 | return status; |
191 | } |
192 | |
193 | int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, |
194 | u8 *postamble_data) |
195 | { |
196 | int status = 0; |
197 | u32 i; |
198 | u32 j; |
199 | |
200 | if (count > js->dr_post) { |
201 | kfree(objp: js->dr_post_data); |
202 | js->dr_post_data = (u8 *)alt_malloc((count + 7) >> 3); |
203 | |
204 | if (js->dr_post_data == NULL) |
205 | status = -ENOMEM; |
206 | else |
207 | js->dr_post = count; |
208 | |
209 | } else |
210 | js->dr_post = count; |
211 | |
212 | if (status == 0) { |
213 | for (i = 0; i < count; ++i) { |
214 | j = i + start_index; |
215 | |
216 | if (postamble_data == NULL) |
217 | js->dr_post_data[i >> 3] |= (1 << (i & 7)); |
218 | else { |
219 | if (postamble_data[j >> 3] & (1 << (j & 7))) |
220 | js->dr_post_data[i >> 3] |= |
221 | (1 << (i & 7)); |
222 | else |
223 | js->dr_post_data[i >> 3] &= |
224 | ~(u32)(1 << (i & 7)); |
225 | |
226 | } |
227 | } |
228 | } |
229 | |
230 | return status; |
231 | } |
232 | |
233 | int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, |
234 | u8 *postamble_data) |
235 | { |
236 | int status = 0; |
237 | u32 i; |
238 | u32 j; |
239 | |
240 | if (count > js->ir_post) { |
241 | kfree(objp: js->ir_post_data); |
242 | js->ir_post_data = (u8 *)alt_malloc((count + 7) >> 3); |
243 | if (js->ir_post_data == NULL) |
244 | status = -ENOMEM; |
245 | else |
246 | js->ir_post = count; |
247 | |
248 | } else |
249 | js->ir_post = count; |
250 | |
251 | if (status != 0) |
252 | return status; |
253 | |
254 | for (i = 0; i < count; ++i) { |
255 | j = i + start_index; |
256 | |
257 | if (postamble_data == NULL) |
258 | js->ir_post_data[i >> 3] |= (1 << (i & 7)); |
259 | else { |
260 | if (postamble_data[j >> 3] & (1 << (j & 7))) |
261 | js->ir_post_data[i >> 3] |= (1 << (i & 7)); |
262 | else |
263 | js->ir_post_data[i >> 3] &= |
264 | ~(u32)(1 << (i & 7)); |
265 | |
266 | } |
267 | } |
268 | |
269 | return status; |
270 | } |
271 | |
272 | static void altera_jreset_idle(struct altera_state *astate) |
273 | { |
274 | struct altera_jtag *js = &astate->js; |
275 | int i; |
276 | /* Go to Test Logic Reset (no matter what the starting state may be) */ |
277 | for (i = 0; i < 5; ++i) |
278 | alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); |
279 | |
280 | /* Now step to Run Test / Idle */ |
281 | alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); |
282 | js->jtag_state = IDLE; |
283 | } |
284 | |
285 | int altera_goto_jstate(struct altera_state *astate, |
286 | enum altera_jtag_state state) |
287 | { |
288 | struct altera_jtag *js = &astate->js; |
289 | int tms; |
290 | int count = 0; |
291 | int status = 0; |
292 | |
293 | if (js->jtag_state == ILLEGAL_JTAG_STATE) |
294 | /* initialize JTAG chain to known state */ |
295 | altera_jreset_idle(astate); |
296 | |
297 | if (js->jtag_state == state) { |
298 | /* |
299 | * We are already in the desired state. |
300 | * If it is a stable state, loop here. |
301 | * Otherwise do nothing (no clock cycles). |
302 | */ |
303 | if ((state == IDLE) || (state == DRSHIFT) || |
304 | (state == DRPAUSE) || (state == IRSHIFT) || |
305 | (state == IRPAUSE)) { |
306 | alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); |
307 | } else if (state == RESET) |
308 | alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); |
309 | |
310 | } else { |
311 | while ((js->jtag_state != state) && (count < 9)) { |
312 | /* Get TMS value to take a step toward desired state */ |
313 | tms = (altera_jtag_path_map[js->jtag_state] & |
314 | (1 << state)) |
315 | ? TMS_HIGH : TMS_LOW; |
316 | |
317 | /* Take a step */ |
318 | alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); |
319 | |
320 | if (tms) |
321 | js->jtag_state = |
322 | altera_transitions[js->jtag_state].tms_high; |
323 | else |
324 | js->jtag_state = |
325 | altera_transitions[js->jtag_state].tms_low; |
326 | |
327 | ++count; |
328 | } |
329 | } |
330 | |
331 | if (js->jtag_state != state) |
332 | status = -EREMOTEIO; |
333 | |
334 | return status; |
335 | } |
336 | |
337 | int altera_wait_cycles(struct altera_state *astate, |
338 | s32 cycles, |
339 | enum altera_jtag_state wait_state) |
340 | { |
341 | struct altera_jtag *js = &astate->js; |
342 | int tms; |
343 | s32 count; |
344 | int status = 0; |
345 | |
346 | if (js->jtag_state != wait_state) |
347 | status = altera_goto_jstate(astate, state: wait_state); |
348 | |
349 | if (status == 0) { |
350 | /* |
351 | * Set TMS high to loop in RESET state |
352 | * Set TMS low to loop in any other stable state |
353 | */ |
354 | tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW; |
355 | |
356 | for (count = 0L; count < cycles; count++) |
357 | alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); |
358 | |
359 | } |
360 | |
361 | return status; |
362 | } |
363 | |
364 | int altera_wait_msecs(struct altera_state *astate, |
365 | s32 microseconds, enum altera_jtag_state wait_state) |
366 | /* |
367 | * Causes JTAG hardware to sit in the specified stable |
368 | * state for the specified duration of real time. If |
369 | * no JTAG operations have been performed yet, then only |
370 | * a delay is performed. This permits the WAIT USECS |
371 | * statement to be used in VECTOR programs without causing |
372 | * any JTAG operations. |
373 | * Returns 0 for success, else appropriate error code. |
374 | */ |
375 | { |
376 | struct altera_jtag *js = &astate->js; |
377 | int status = 0; |
378 | |
379 | if ((js->jtag_state != ILLEGAL_JTAG_STATE) && |
380 | (js->jtag_state != wait_state)) |
381 | status = altera_goto_jstate(astate, state: wait_state); |
382 | |
383 | if (status == 0) |
384 | /* Wait for specified time interval */ |
385 | udelay(microseconds); |
386 | |
387 | return status; |
388 | } |
389 | |
390 | static void altera_concatenate_data(u8 *buffer, |
391 | u8 *preamble_data, |
392 | u32 preamble_count, |
393 | u8 *target_data, |
394 | u32 start_index, |
395 | u32 target_count, |
396 | u8 *postamble_data, |
397 | u32 postamble_count) |
398 | /* |
399 | * Copies preamble data, target data, and postamble data |
400 | * into one buffer for IR or DR scans. |
401 | */ |
402 | { |
403 | u32 i, j, k; |
404 | |
405 | for (i = 0L; i < preamble_count; ++i) { |
406 | if (preamble_data[i >> 3L] & (1L << (i & 7L))) |
407 | buffer[i >> 3L] |= (1L << (i & 7L)); |
408 | else |
409 | buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); |
410 | |
411 | } |
412 | |
413 | j = start_index; |
414 | k = preamble_count + target_count; |
415 | for (; i < k; ++i, ++j) { |
416 | if (target_data[j >> 3L] & (1L << (j & 7L))) |
417 | buffer[i >> 3L] |= (1L << (i & 7L)); |
418 | else |
419 | buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); |
420 | |
421 | } |
422 | |
423 | j = 0L; |
424 | k = preamble_count + target_count + postamble_count; |
425 | for (; i < k; ++i, ++j) { |
426 | if (postamble_data[j >> 3L] & (1L << (j & 7L))) |
427 | buffer[i >> 3L] |= (1L << (i & 7L)); |
428 | else |
429 | buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); |
430 | |
431 | } |
432 | } |
433 | |
434 | static int alt_jtag_drscan(struct altera_state *astate, |
435 | int start_state, |
436 | int count, |
437 | u8 *tdi, |
438 | u8 *tdo) |
439 | { |
440 | int i = 0; |
441 | int tdo_bit = 0; |
442 | int status = 1; |
443 | |
444 | /* First go to DRSHIFT state */ |
445 | switch (start_state) { |
446 | case 0: /* IDLE */ |
447 | alt_jtag_io(1, 0, 0); /* DRSELECT */ |
448 | alt_jtag_io(0, 0, 0); /* DRCAPTURE */ |
449 | alt_jtag_io(0, 0, 0); /* DRSHIFT */ |
450 | break; |
451 | |
452 | case 1: /* DRPAUSE */ |
453 | alt_jtag_io(1, 0, 0); /* DREXIT2 */ |
454 | alt_jtag_io(1, 0, 0); /* DRUPDATE */ |
455 | alt_jtag_io(1, 0, 0); /* DRSELECT */ |
456 | alt_jtag_io(0, 0, 0); /* DRCAPTURE */ |
457 | alt_jtag_io(0, 0, 0); /* DRSHIFT */ |
458 | break; |
459 | |
460 | case 2: /* IRPAUSE */ |
461 | alt_jtag_io(1, 0, 0); /* IREXIT2 */ |
462 | alt_jtag_io(1, 0, 0); /* IRUPDATE */ |
463 | alt_jtag_io(1, 0, 0); /* DRSELECT */ |
464 | alt_jtag_io(0, 0, 0); /* DRCAPTURE */ |
465 | alt_jtag_io(0, 0, 0); /* DRSHIFT */ |
466 | break; |
467 | |
468 | default: |
469 | status = 0; |
470 | } |
471 | |
472 | if (status) { |
473 | /* loop in the SHIFT-DR state */ |
474 | for (i = 0; i < count; i++) { |
475 | tdo_bit = alt_jtag_io( |
476 | (i == count - 1), |
477 | tdi[i >> 3] & (1 << (i & 7)), |
478 | (tdo != NULL)); |
479 | |
480 | if (tdo != NULL) { |
481 | if (tdo_bit) |
482 | tdo[i >> 3] |= (1 << (i & 7)); |
483 | else |
484 | tdo[i >> 3] &= ~(u32)(1 << (i & 7)); |
485 | |
486 | } |
487 | } |
488 | |
489 | alt_jtag_io(0, 0, 0); /* DRPAUSE */ |
490 | } |
491 | |
492 | return status; |
493 | } |
494 | |
495 | static int alt_jtag_irscan(struct altera_state *astate, |
496 | int start_state, |
497 | int count, |
498 | u8 *tdi, |
499 | u8 *tdo) |
500 | { |
501 | int i = 0; |
502 | int tdo_bit = 0; |
503 | int status = 1; |
504 | |
505 | /* First go to IRSHIFT state */ |
506 | switch (start_state) { |
507 | case 0: /* IDLE */ |
508 | alt_jtag_io(1, 0, 0); /* DRSELECT */ |
509 | alt_jtag_io(1, 0, 0); /* IRSELECT */ |
510 | alt_jtag_io(0, 0, 0); /* IRCAPTURE */ |
511 | alt_jtag_io(0, 0, 0); /* IRSHIFT */ |
512 | break; |
513 | |
514 | case 1: /* DRPAUSE */ |
515 | alt_jtag_io(1, 0, 0); /* DREXIT2 */ |
516 | alt_jtag_io(1, 0, 0); /* DRUPDATE */ |
517 | alt_jtag_io(1, 0, 0); /* DRSELECT */ |
518 | alt_jtag_io(1, 0, 0); /* IRSELECT */ |
519 | alt_jtag_io(0, 0, 0); /* IRCAPTURE */ |
520 | alt_jtag_io(0, 0, 0); /* IRSHIFT */ |
521 | break; |
522 | |
523 | case 2: /* IRPAUSE */ |
524 | alt_jtag_io(1, 0, 0); /* IREXIT2 */ |
525 | alt_jtag_io(1, 0, 0); /* IRUPDATE */ |
526 | alt_jtag_io(1, 0, 0); /* DRSELECT */ |
527 | alt_jtag_io(1, 0, 0); /* IRSELECT */ |
528 | alt_jtag_io(0, 0, 0); /* IRCAPTURE */ |
529 | alt_jtag_io(0, 0, 0); /* IRSHIFT */ |
530 | break; |
531 | |
532 | default: |
533 | status = 0; |
534 | } |
535 | |
536 | if (status) { |
537 | /* loop in the SHIFT-IR state */ |
538 | for (i = 0; i < count; i++) { |
539 | tdo_bit = alt_jtag_io( |
540 | (i == count - 1), |
541 | tdi[i >> 3] & (1 << (i & 7)), |
542 | (tdo != NULL)); |
543 | if (tdo != NULL) { |
544 | if (tdo_bit) |
545 | tdo[i >> 3] |= (1 << (i & 7)); |
546 | else |
547 | tdo[i >> 3] &= ~(u32)(1 << (i & 7)); |
548 | |
549 | } |
550 | } |
551 | |
552 | alt_jtag_io(0, 0, 0); /* IRPAUSE */ |
553 | } |
554 | |
555 | return status; |
556 | } |
557 | |
558 | static void (u8 *buffer, |
559 | u8 *target_data, |
560 | u32 start_index, |
561 | u32 preamble_count, |
562 | u32 target_count) |
563 | /* |
564 | * Copies target data from scan buffer, filtering out |
565 | * preamble and postamble data. |
566 | */ |
567 | { |
568 | u32 i; |
569 | u32 j; |
570 | u32 k; |
571 | |
572 | j = preamble_count; |
573 | k = start_index + target_count; |
574 | for (i = start_index; i < k; ++i, ++j) { |
575 | if (buffer[j >> 3] & (1 << (j & 7))) |
576 | target_data[i >> 3] |= (1 << (i & 7)); |
577 | else |
578 | target_data[i >> 3] &= ~(u32)(1 << (i & 7)); |
579 | |
580 | } |
581 | } |
582 | |
583 | int altera_irscan(struct altera_state *astate, |
584 | u32 count, |
585 | u8 *tdi_data, |
586 | u32 start_index) |
587 | /* Shifts data into instruction register */ |
588 | { |
589 | struct altera_jtag *js = &astate->js; |
590 | int start_code = 0; |
591 | u32 alloc_chars = 0; |
592 | u32 shift_count = js->ir_pre + count + js->ir_post; |
593 | int status = 0; |
594 | enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; |
595 | |
596 | switch (js->jtag_state) { |
597 | case ILLEGAL_JTAG_STATE: |
598 | case RESET: |
599 | case IDLE: |
600 | start_code = 0; |
601 | start_state = IDLE; |
602 | break; |
603 | |
604 | case DRSELECT: |
605 | case DRCAPTURE: |
606 | case DRSHIFT: |
607 | case DREXIT1: |
608 | case DRPAUSE: |
609 | case DREXIT2: |
610 | case DRUPDATE: |
611 | start_code = 1; |
612 | start_state = DRPAUSE; |
613 | break; |
614 | |
615 | case IRSELECT: |
616 | case IRCAPTURE: |
617 | case IRSHIFT: |
618 | case IREXIT1: |
619 | case IRPAUSE: |
620 | case IREXIT2: |
621 | case IRUPDATE: |
622 | start_code = 2; |
623 | start_state = IRPAUSE; |
624 | break; |
625 | |
626 | default: |
627 | status = -EREMOTEIO; |
628 | break; |
629 | } |
630 | |
631 | if (status == 0) |
632 | if (js->jtag_state != start_state) |
633 | status = altera_goto_jstate(astate, state: start_state); |
634 | |
635 | if (status == 0) { |
636 | if (shift_count > js->ir_length) { |
637 | alloc_chars = (shift_count + 7) >> 3; |
638 | kfree(objp: js->ir_buffer); |
639 | js->ir_buffer = (u8 *)alt_malloc(alloc_chars); |
640 | if (js->ir_buffer == NULL) |
641 | status = -ENOMEM; |
642 | else |
643 | js->ir_length = alloc_chars * 8; |
644 | |
645 | } |
646 | } |
647 | |
648 | if (status == 0) { |
649 | /* |
650 | * Copy preamble data, IR data, |
651 | * and postamble data into a buffer |
652 | */ |
653 | altera_concatenate_data(buffer: js->ir_buffer, |
654 | preamble_data: js->ir_pre_data, |
655 | preamble_count: js->ir_pre, |
656 | target_data: tdi_data, |
657 | start_index, |
658 | target_count: count, |
659 | postamble_data: js->ir_post_data, |
660 | postamble_count: js->ir_post); |
661 | /* Do the IRSCAN */ |
662 | alt_jtag_irscan(astate, |
663 | start_state: start_code, |
664 | count: shift_count, |
665 | tdi: js->ir_buffer, |
666 | NULL); |
667 | |
668 | /* alt_jtag_irscan() always ends in IRPAUSE state */ |
669 | js->jtag_state = IRPAUSE; |
670 | } |
671 | |
672 | if (status == 0) |
673 | if (js->irstop_state != IRPAUSE) |
674 | status = altera_goto_jstate(astate, state: js->irstop_state); |
675 | |
676 | |
677 | return status; |
678 | } |
679 | |
680 | int altera_swap_ir(struct altera_state *astate, |
681 | u32 count, |
682 | u8 *in_data, |
683 | u32 in_index, |
684 | u8 *out_data, |
685 | u32 out_index) |
686 | /* Shifts data into instruction register, capturing output data */ |
687 | { |
688 | struct altera_jtag *js = &astate->js; |
689 | int start_code = 0; |
690 | u32 alloc_chars = 0; |
691 | u32 shift_count = js->ir_pre + count + js->ir_post; |
692 | int status = 0; |
693 | enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; |
694 | |
695 | switch (js->jtag_state) { |
696 | case ILLEGAL_JTAG_STATE: |
697 | case RESET: |
698 | case IDLE: |
699 | start_code = 0; |
700 | start_state = IDLE; |
701 | break; |
702 | |
703 | case DRSELECT: |
704 | case DRCAPTURE: |
705 | case DRSHIFT: |
706 | case DREXIT1: |
707 | case DRPAUSE: |
708 | case DREXIT2: |
709 | case DRUPDATE: |
710 | start_code = 1; |
711 | start_state = DRPAUSE; |
712 | break; |
713 | |
714 | case IRSELECT: |
715 | case IRCAPTURE: |
716 | case IRSHIFT: |
717 | case IREXIT1: |
718 | case IRPAUSE: |
719 | case IREXIT2: |
720 | case IRUPDATE: |
721 | start_code = 2; |
722 | start_state = IRPAUSE; |
723 | break; |
724 | |
725 | default: |
726 | status = -EREMOTEIO; |
727 | break; |
728 | } |
729 | |
730 | if (status == 0) |
731 | if (js->jtag_state != start_state) |
732 | status = altera_goto_jstate(astate, state: start_state); |
733 | |
734 | if (status == 0) { |
735 | if (shift_count > js->ir_length) { |
736 | alloc_chars = (shift_count + 7) >> 3; |
737 | kfree(objp: js->ir_buffer); |
738 | js->ir_buffer = (u8 *)alt_malloc(alloc_chars); |
739 | if (js->ir_buffer == NULL) |
740 | status = -ENOMEM; |
741 | else |
742 | js->ir_length = alloc_chars * 8; |
743 | |
744 | } |
745 | } |
746 | |
747 | if (status == 0) { |
748 | /* |
749 | * Copy preamble data, IR data, |
750 | * and postamble data into a buffer |
751 | */ |
752 | altera_concatenate_data(buffer: js->ir_buffer, |
753 | preamble_data: js->ir_pre_data, |
754 | preamble_count: js->ir_pre, |
755 | target_data: in_data, |
756 | start_index: in_index, |
757 | target_count: count, |
758 | postamble_data: js->ir_post_data, |
759 | postamble_count: js->ir_post); |
760 | |
761 | /* Do the IRSCAN */ |
762 | alt_jtag_irscan(astate, |
763 | start_state: start_code, |
764 | count: shift_count, |
765 | tdi: js->ir_buffer, |
766 | tdo: js->ir_buffer); |
767 | |
768 | /* alt_jtag_irscan() always ends in IRPAUSE state */ |
769 | js->jtag_state = IRPAUSE; |
770 | } |
771 | |
772 | if (status == 0) |
773 | if (js->irstop_state != IRPAUSE) |
774 | status = altera_goto_jstate(astate, state: js->irstop_state); |
775 | |
776 | |
777 | if (status == 0) |
778 | /* Now extract the returned data from the buffer */ |
779 | altera_extract_target_data(buffer: js->ir_buffer, |
780 | target_data: out_data, start_index: out_index, |
781 | preamble_count: js->ir_pre, target_count: count); |
782 | |
783 | return status; |
784 | } |
785 | |
786 | int altera_drscan(struct altera_state *astate, |
787 | u32 count, |
788 | u8 *tdi_data, |
789 | u32 start_index) |
790 | /* Shifts data into data register (ignoring output data) */ |
791 | { |
792 | struct altera_jtag *js = &astate->js; |
793 | int start_code = 0; |
794 | u32 alloc_chars = 0; |
795 | u32 shift_count = js->dr_pre + count + js->dr_post; |
796 | int status = 0; |
797 | enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; |
798 | |
799 | switch (js->jtag_state) { |
800 | case ILLEGAL_JTAG_STATE: |
801 | case RESET: |
802 | case IDLE: |
803 | start_code = 0; |
804 | start_state = IDLE; |
805 | break; |
806 | |
807 | case DRSELECT: |
808 | case DRCAPTURE: |
809 | case DRSHIFT: |
810 | case DREXIT1: |
811 | case DRPAUSE: |
812 | case DREXIT2: |
813 | case DRUPDATE: |
814 | start_code = 1; |
815 | start_state = DRPAUSE; |
816 | break; |
817 | |
818 | case IRSELECT: |
819 | case IRCAPTURE: |
820 | case IRSHIFT: |
821 | case IREXIT1: |
822 | case IRPAUSE: |
823 | case IREXIT2: |
824 | case IRUPDATE: |
825 | start_code = 2; |
826 | start_state = IRPAUSE; |
827 | break; |
828 | |
829 | default: |
830 | status = -EREMOTEIO; |
831 | break; |
832 | } |
833 | |
834 | if (status == 0) |
835 | if (js->jtag_state != start_state) |
836 | status = altera_goto_jstate(astate, state: start_state); |
837 | |
838 | if (status == 0) { |
839 | if (shift_count > js->dr_length) { |
840 | alloc_chars = (shift_count + 7) >> 3; |
841 | kfree(objp: js->dr_buffer); |
842 | js->dr_buffer = (u8 *)alt_malloc(alloc_chars); |
843 | if (js->dr_buffer == NULL) |
844 | status = -ENOMEM; |
845 | else |
846 | js->dr_length = alloc_chars * 8; |
847 | |
848 | } |
849 | } |
850 | |
851 | if (status == 0) { |
852 | /* |
853 | * Copy preamble data, DR data, |
854 | * and postamble data into a buffer |
855 | */ |
856 | altera_concatenate_data(buffer: js->dr_buffer, |
857 | preamble_data: js->dr_pre_data, |
858 | preamble_count: js->dr_pre, |
859 | target_data: tdi_data, |
860 | start_index, |
861 | target_count: count, |
862 | postamble_data: js->dr_post_data, |
863 | postamble_count: js->dr_post); |
864 | /* Do the DRSCAN */ |
865 | alt_jtag_drscan(astate, start_state: start_code, count: shift_count, |
866 | tdi: js->dr_buffer, NULL); |
867 | /* alt_jtag_drscan() always ends in DRPAUSE state */ |
868 | js->jtag_state = DRPAUSE; |
869 | } |
870 | |
871 | if (status == 0) |
872 | if (js->drstop_state != DRPAUSE) |
873 | status = altera_goto_jstate(astate, state: js->drstop_state); |
874 | |
875 | return status; |
876 | } |
877 | |
878 | int altera_swap_dr(struct altera_state *astate, u32 count, |
879 | u8 *in_data, u32 in_index, |
880 | u8 *out_data, u32 out_index) |
881 | /* Shifts data into data register, capturing output data */ |
882 | { |
883 | struct altera_jtag *js = &astate->js; |
884 | int start_code = 0; |
885 | u32 alloc_chars = 0; |
886 | u32 shift_count = js->dr_pre + count + js->dr_post; |
887 | int status = 0; |
888 | enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; |
889 | |
890 | switch (js->jtag_state) { |
891 | case ILLEGAL_JTAG_STATE: |
892 | case RESET: |
893 | case IDLE: |
894 | start_code = 0; |
895 | start_state = IDLE; |
896 | break; |
897 | |
898 | case DRSELECT: |
899 | case DRCAPTURE: |
900 | case DRSHIFT: |
901 | case DREXIT1: |
902 | case DRPAUSE: |
903 | case DREXIT2: |
904 | case DRUPDATE: |
905 | start_code = 1; |
906 | start_state = DRPAUSE; |
907 | break; |
908 | |
909 | case IRSELECT: |
910 | case IRCAPTURE: |
911 | case IRSHIFT: |
912 | case IREXIT1: |
913 | case IRPAUSE: |
914 | case IREXIT2: |
915 | case IRUPDATE: |
916 | start_code = 2; |
917 | start_state = IRPAUSE; |
918 | break; |
919 | |
920 | default: |
921 | status = -EREMOTEIO; |
922 | break; |
923 | } |
924 | |
925 | if (status == 0) |
926 | if (js->jtag_state != start_state) |
927 | status = altera_goto_jstate(astate, state: start_state); |
928 | |
929 | if (status == 0) { |
930 | if (shift_count > js->dr_length) { |
931 | alloc_chars = (shift_count + 7) >> 3; |
932 | kfree(objp: js->dr_buffer); |
933 | js->dr_buffer = (u8 *)alt_malloc(alloc_chars); |
934 | |
935 | if (js->dr_buffer == NULL) |
936 | status = -ENOMEM; |
937 | else |
938 | js->dr_length = alloc_chars * 8; |
939 | |
940 | } |
941 | } |
942 | |
943 | if (status == 0) { |
944 | /* |
945 | * Copy preamble data, DR data, |
946 | * and postamble data into a buffer |
947 | */ |
948 | altera_concatenate_data(buffer: js->dr_buffer, |
949 | preamble_data: js->dr_pre_data, |
950 | preamble_count: js->dr_pre, |
951 | target_data: in_data, |
952 | start_index: in_index, |
953 | target_count: count, |
954 | postamble_data: js->dr_post_data, |
955 | postamble_count: js->dr_post); |
956 | |
957 | /* Do the DRSCAN */ |
958 | alt_jtag_drscan(astate, |
959 | start_state: start_code, |
960 | count: shift_count, |
961 | tdi: js->dr_buffer, |
962 | tdo: js->dr_buffer); |
963 | |
964 | /* alt_jtag_drscan() always ends in DRPAUSE state */ |
965 | js->jtag_state = DRPAUSE; |
966 | } |
967 | |
968 | if (status == 0) |
969 | if (js->drstop_state != DRPAUSE) |
970 | status = altera_goto_jstate(astate, state: js->drstop_state); |
971 | |
972 | if (status == 0) |
973 | /* Now extract the returned data from the buffer */ |
974 | altera_extract_target_data(buffer: js->dr_buffer, |
975 | target_data: out_data, |
976 | start_index: out_index, |
977 | preamble_count: js->dr_pre, |
978 | target_count: count); |
979 | |
980 | return status; |
981 | } |
982 | |
983 | void altera_free_buffers(struct altera_state *astate) |
984 | { |
985 | struct altera_jtag *js = &astate->js; |
986 | /* If the JTAG interface was used, reset it to TLR */ |
987 | if (js->jtag_state != ILLEGAL_JTAG_STATE) |
988 | altera_jreset_idle(astate); |
989 | |
990 | kfree(objp: js->dr_pre_data); |
991 | js->dr_pre_data = NULL; |
992 | |
993 | kfree(objp: js->dr_post_data); |
994 | js->dr_post_data = NULL; |
995 | |
996 | kfree(objp: js->dr_buffer); |
997 | js->dr_buffer = NULL; |
998 | |
999 | kfree(objp: js->ir_pre_data); |
1000 | js->ir_pre_data = NULL; |
1001 | |
1002 | kfree(objp: js->ir_post_data); |
1003 | js->ir_post_data = NULL; |
1004 | |
1005 | kfree(objp: js->ir_buffer); |
1006 | js->ir_buffer = NULL; |
1007 | } |
1008 | |