Add OpenULINK firmware
[fw/openocd] / src / jtag / drivers / OpenULINK / src / jtag.c
1 /***************************************************************************
2  *   Copyright (C) 2011 by Martin Schmoelzer                               *
3  *   <martin.schmoelzer@student.tuwien.ac.at>                              *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "jtag.h"
22
23 #include "io.h"
24 #include "msgtypes.h"
25 #include "common.h"
26
27 #include <stdbool.h>
28
29 /** Delay value for SCAN operations with less than maximum TCK frequency */
30 u8 delay_scan = 0;
31
32 /** Delay value for CLOCK_TCK operations */
33 u8 delay_tck = 0;
34
35 /** Delay value for CLOCK_TMS operations with less than maximum frequency */
36 u8 delay_tms = 0;
37
38 /**
39  * Perform JTAG SCAN-IN operation at maximum TCK frequency.
40  *
41  * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and
42  * stored in the EP2 IN buffer.
43  *
44  * @param out_offset offset in OUT2BUF where payload data starts
45  */
46 void jtag_scan_in(u8 out_offset, u8 in_offset)
47 {
48   u8 scan_size_bytes, bits_last_byte;
49   u8 tms_count_start, tms_count_end;
50   u8 tms_sequence_start, tms_sequence_end;
51   u8 tdo_data, i, j;
52
53   u8 outb_buffer;
54
55   /* Get parameters from OUT2BUF */
56   scan_size_bytes = OUT2BUF[out_offset];
57   bits_last_byte = OUT2BUF[out_offset + 1];
58   tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
59   tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
60   tms_sequence_start = OUT2BUF[out_offset + 3];
61   tms_sequence_end = OUT2BUF[out_offset + 4];
62
63   if (tms_count_start > 0) {
64     jtag_clock_tms(tms_count_start, tms_sequence_start);
65   }
66
67   outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS);
68
69   /* Shift all bytes except the last byte */
70   for (i = 0; i < scan_size_bytes - 1; i++) {
71     tdo_data = 0;
72
73     for (j = 0; j < 8; j++) {
74       OUTB = outb_buffer; /* TCK changes here */
75       OUTB = (outb_buffer | PIN_TCK);
76       tdo_data = tdo_data >> 1;
77
78       if (GET_TDO()) {
79         tdo_data |= 0x80;
80       }
81     }
82
83     /* Copy TDO data to IN2BUF */
84     IN2BUF[i + in_offset] = tdo_data;
85   }
86
87   tdo_data = 0;
88
89   /* Shift the last byte */
90   for (j = 0; j < bits_last_byte; j++) {
91     /* Assert TMS signal if requested and this is the last bit */
92     if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
93       outb_buffer |= PIN_TMS;
94       tms_count_end--;
95       tms_sequence_end = tms_sequence_end >> 1;
96     }
97
98     OUTB = outb_buffer; /* TCK change here */
99     OUTB = (outb_buffer | PIN_TCK);
100     tdo_data = tdo_data >> 1;
101
102     if (GET_TDO()) {
103       tdo_data |= 0x80;
104     }
105   }
106   tdo_data = tdo_data >> (8 - bits_last_byte);
107
108   /* Copy TDO data to IN2BUF */
109   IN2BUF[i + in_offset] = tdo_data;
110
111   /* Move to correct end state */
112   if (tms_count_end > 0) {
113     jtag_clock_tms(tms_count_end, tms_sequence_end);
114   }
115 }
116
117 /**
118  * Perform JTAG SCAN-OUT operation at maximum TCK frequency.
119  *
120  * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
121  * data is not sampled.
122  * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state.
123  *
124  * @param out_offset offset in OUT2BUF where payload data starts
125  */
126 void jtag_scan_out(u8 out_offset)
127 {
128   u8 scan_size_bytes, bits_last_byte;
129   u8 tms_count_start, tms_count_end;
130   u8 tms_sequence_start, tms_sequence_end;
131   u8 tdi_data, i, j;
132
133   u8 outb_buffer;
134
135   /* Get parameters from OUT2BUF */
136   scan_size_bytes = OUT2BUF[out_offset];
137   bits_last_byte = OUT2BUF[out_offset + 1];
138   tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
139   tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
140   tms_sequence_start = OUT2BUF[out_offset + 3];
141   tms_sequence_end = OUT2BUF[out_offset + 4];
142   
143   if (tms_count_start > 0) {
144     jtag_clock_tms(tms_count_start, tms_sequence_start);
145   }
146
147   outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);
148
149   /* Shift all bytes except the last byte */
150   for (i = 0; i < scan_size_bytes - 1; i++) {
151     tdi_data = OUT2BUF[i + out_offset + 5];
152
153     for (j = 0; j < 8; j++) {
154       if (tdi_data & 0x01) {
155         outb_buffer |= PIN_TDI;
156       }
157       else {
158         outb_buffer &= ~PIN_TDI;
159       }
160
161       OUTB = outb_buffer; /* TDI and TCK change here */
162       tdi_data = tdi_data >> 1;
163       OUTB = (outb_buffer | PIN_TCK);
164     }
165   }
166
167   tdi_data = OUT2BUF[i + out_offset + 5];
168
169   /* Shift the last byte */
170   for (j = 0; j < bits_last_byte; j++) {
171     if (tdi_data & 0x01) {
172       outb_buffer |= PIN_TDI;
173     }
174     else {
175       outb_buffer &= ~PIN_TDI;
176     }
177
178     /* Assert TMS signal if requested and this is the last bit */
179     if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
180       outb_buffer |= PIN_TMS;
181       tms_count_end--;
182       tms_sequence_end = tms_sequence_end >> 1;
183     }
184
185     OUTB = outb_buffer; /* TDI and TCK change here */
186     tdi_data = tdi_data >> 1;
187     OUTB = (outb_buffer | PIN_TCK);
188   }
189
190   /* Move to correct end state */
191   if (tms_count_end > 0) {
192     jtag_clock_tms(tms_count_end, tms_sequence_end);
193   }
194 }
195
196 /**
197  * Perform bidirectional JTAG SCAN operation at maximum TCK frequency.
198  *
199  * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
200  * data is sampled and stored in the EP2 IN buffer.
201  * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state.
202  *
203  * @param out_offset offset in OUT2BUF where payload data starts
204  */
205 void jtag_scan_io(u8 out_offset, u8 in_offset)
206 {
207   u8 scan_size_bytes, bits_last_byte;
208   u8 tms_count_start, tms_count_end;
209   u8 tms_sequence_start, tms_sequence_end;
210   u8 tdi_data, tdo_data, i, j;
211
212   u8 outb_buffer;
213
214   /* Get parameters from OUT2BUF */
215   scan_size_bytes = OUT2BUF[out_offset];
216   bits_last_byte = OUT2BUF[out_offset + 1];
217   tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
218   tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
219   tms_sequence_start = OUT2BUF[out_offset + 3];
220   tms_sequence_end = OUT2BUF[out_offset + 4];
221   
222   if (tms_count_start > 0) {
223     jtag_clock_tms(tms_count_start, tms_sequence_start);
224   }
225
226   outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);
227
228   /* Shift all bytes except the last byte */
229   for (i = 0; i < scan_size_bytes - 1; i++) {
230     tdi_data = OUT2BUF[i + out_offset + 5];
231     tdo_data = 0;
232
233     for (j = 0; j < 8; j++) {
234       if (tdi_data & 0x01) {
235         outb_buffer |= PIN_TDI;
236       }
237       else {
238         outb_buffer &= ~PIN_TDI;
239       }
240
241       OUTB = outb_buffer; /* TDI and TCK change here */
242       tdi_data = tdi_data >> 1;
243       OUTB = (outb_buffer | PIN_TCK);
244       tdo_data = tdo_data >> 1;
245
246       if (GET_TDO()) {
247         tdo_data |= 0x80;
248       }
249     }
250
251     /* Copy TDO data to IN2BUF */
252     IN2BUF[i + in_offset] = tdo_data;
253   }
254
255   tdi_data = OUT2BUF[i + out_offset + 5];
256   tdo_data = 0;
257
258   /* Shift the last byte */
259   for (j = 0; j < bits_last_byte; j++) {
260     if (tdi_data & 0x01) {
261       outb_buffer |= PIN_TDI;
262     }
263     else {
264       outb_buffer &= ~PIN_TDI;
265     }
266
267     /* Assert TMS signal if requested and this is the last bit */
268     if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
269       outb_buffer |= PIN_TMS;
270       tms_count_end--;
271       tms_sequence_end = tms_sequence_end >> 1;
272     }
273
274     OUTB = outb_buffer; /* TDI and TCK change here */
275     tdi_data = tdi_data >> 1;
276     OUTB = (outb_buffer | PIN_TCK);
277     tdo_data = tdo_data >> 1;
278
279     if (GET_TDO()) {
280       tdo_data |= 0x80;
281     }
282   }
283   tdo_data = tdo_data >> (8 - bits_last_byte);
284
285   /* Copy TDO data to IN2BUF */
286   IN2BUF[i + in_offset] = tdo_data;
287   
288   /* Move to correct end state */
289   if (tms_count_end > 0) {
290     jtag_clock_tms(tms_count_end, tms_sequence_end);
291   }
292 }
293
294 /**
295  * Generate TCK clock cycles.
296  *
297  * @param count number of TCK clock cyclces to generate.
298  */
299 void jtag_clock_tck(u16 count)
300 {
301   u16 i;
302   u8 j;
303
304   for ( i = 0; i < count; i++ ) {
305     SET_TCK_LOW();
306     for(j = 0; j < delay_tck; j++);
307
308     SET_TCK_HIGH();
309     for(j = 0; j < delay_tck; j++);
310   }
311 }
312
313 /**
314  * Perform TAP-FSM state transitions at maximum TCK frequency.
315  *
316  * @param count the number of state transitions to perform.
317  * @param sequence the TMS pin levels for each state transition, starting with
318  *  the least-significant bit.
319  */
320 void jtag_clock_tms(u8 count, u8 sequence)
321 {
322   volatile u8 outb_buffer;
323   u8 i;
324
325   outb_buffer = OUTB & ~(PIN_TCK);
326
327   for ( i = 0; i < count; i++ ) {
328     /* Set TMS pin according to sequence parameter */
329     if ( sequence & 0x1 ) {
330       outb_buffer |= PIN_TMS;
331     }
332     else {
333       outb_buffer &= ~PIN_TMS;
334     }
335
336     OUTB = outb_buffer;
337     sequence = sequence >> 1;
338     OUTB = outb_buffer | PIN_TCK;
339   }
340 }
341
342 /**
343  * Perform TAP-FSM state transitions at less than maximum TCK frequency.
344  *
345  * @param count the number of state transitions to perform.
346  * @param sequence the TMS pin levels for each state transition, starting with
347  *  the least-significant bit.
348  */
349 void jtag_slow_clock_tms(u8 count, u8 sequence)
350 {
351
352 }
353
354 /**
355  * Get current JTAG signal states.
356  *
357  * @return a 16-bit integer where the most-significant byte contains the state
358  *  of the JTAG input signals and the least-significant byte cotains the state
359  *  of the JTAG output signals.
360  */
361 u16 jtag_get_signals(void)
362 {
363   u8 input_signal_state, output_signal_state;
364
365   input_signal_state = 0;
366   output_signal_state = 0;
367
368   /* Get states of input pins */
369   if (GET_TDO()) {
370     input_signal_state |= SIGNAL_TDO;
371   }
372   if (GET_BRKOUT()) {
373     input_signal_state |= SIGNAL_BRKOUT;
374   }
375   if (GET_TRAP()) {
376     input_signal_state |= SIGNAL_TRAP;
377   }
378   if (GET_RTCK()) {
379     /* Using RTCK this way would be extremely slow,
380      * implemented only for the sake of completeness */
381     input_signal_state |= SIGNAL_RTCK;
382   }
383
384   /* Get states of output pins */
385   output_signal_state = PINSB & MASK_PORTB_DIRECTION_OUT;
386
387   return ((u16)input_signal_state << 8) | ((u16)output_signal_state);
388 }
389
390 /**
391  * Set state of JTAG output signals.
392  *
393  * @param low signals which should be de-asserted.
394  * @param high signals which should be asserted.
395  */
396 void jtag_set_signals(u8 low, u8 high)
397 {
398   OUTB &= ~(low & MASK_PORTB_DIRECTION_OUT);
399   OUTB |= (high & MASK_PORTB_DIRECTION_OUT);
400 }
401
402 /**
403  * Configure TCK delay parameters.
404  *
405  * @param scan number of delay cycles in shift operations.
406  * @param tck number of delay cycles in clock_tck operations.
407  * @param tms number of delay cycles in clock_tms operations.
408  */
409 void jtag_configure_tck_delay(u8 scan, u8 tck, u8 tms)
410 {
411   delay_scan = scan;
412   delay_tck = tck;
413   delay_tms = tms;
414 }