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