NCC clean newCell
[fleet.git] / misc / jtagkey.c
1 #include <stdio.h>
2 #include <ftdi.h>
3 #include <unistd.h>
4 #include <pthread.h>
5 #include <inttypes.h>
6 #include "usb-driver.h"
7 #include "config.h"
8 #include "jtagkey.h"
9 #include "jtagmon.h"
10
11 #define USBBUFSIZE 1048576
12 #define JTAG_SPEED 100000
13 #define BULK_LATENCY 2
14 #define OTHER_LATENCY 1
15
16 static struct ftdi_context ftdic;
17
18 static int jtagkey_latency(int latency) {
19         static int current = 0;
20         int ret;
21
22         if (current != latency) {
23                 DPRINTF("switching latency\n");
24                 if ((ret = ftdi_set_latency_timer(&ftdic, latency))  != 0) {
25                         fprintf(stderr, "unable to set latency timer: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
26                         return ret;
27                 }
28                 
29                 current = latency;
30         }
31
32         return ret;
33 }
34
35 static int jtagkey_init(unsigned short vid, unsigned short pid) {
36         int ret = 0;
37         unsigned char c;
38
39         if ((ret = ftdi_init(&ftdic)) != 0) {
40                 fprintf(stderr, "unable to initialise libftdi: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
41                 return ret;
42         }
43         
44         if ((ret = ftdi_usb_open(&ftdic, vid, pid)) != 0) {
45                 fprintf(stderr, "unable to open ftdi device: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
46                 return ret;
47         }
48
49         if ((ret = ftdi_usb_reset(&ftdic)) != 0) {
50                 fprintf(stderr, "unable reset device: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
51                 return ret;
52         }
53
54         if ((ret = ftdi_set_interface(&ftdic, INTERFACE_A)) != 0) {
55                 fprintf(stderr, "unable to set interface: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
56                 return ret;
57         }
58
59         if ((ret = ftdi_write_data_set_chunksize(&ftdic, USBBUFSIZE))  != 0) {
60                 fprintf(stderr, "unable to set write chunksize: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
61                 return ret;
62         }
63
64         if ((ret = ftdi_read_data_set_chunksize(&ftdic, USBBUFSIZE))  != 0) {
65                 fprintf(stderr, "unable to set read chunksize: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
66                 return ret;
67         }
68
69         if ((ret = jtagkey_latency(OTHER_LATENCY)) != 0)
70                 return ret;
71
72         c = 0x00;
73         ftdi_write_data(&ftdic, &c, 1);
74
75         if ((ret = ftdi_set_bitmode(&ftdic, JTAGKEY_TCK|JTAGKEY_TDI|JTAGKEY_TMS|JTAGKEY_OEn, BITMODE_SYNCBB))  != 0) {
76                 fprintf(stderr, "unable to enable bitbang mode: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
77                 return ret;
78         }
79
80         if ((ret = ftdi_set_baudrate(&ftdic, JTAG_SPEED))  != 0) {
81                 fprintf(stderr, "unable to set baudrate: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
82                 return ret;
83         }
84
85         if ((ret = ftdi_usb_purge_buffers(&ftdic))  != 0) {
86                 fprintf(stderr, "unable to purge buffers: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
87                 return ret;
88         }
89
90         return ret;
91 }
92
93 int jtagkey_open(int num) {
94         int ret;
95
96         ret = jtagkey_init(config_usb_vid(num), config_usb_pid(num));
97
98         if (ret >= 0)
99                 ret = 0xff;
100
101         return ret;
102 }
103
104 void jtagkey_close(int handle) {
105         if (handle == 0xff) {
106                 ftdi_disable_bitbang(&ftdic);
107                 ftdi_usb_close(&ftdic);
108                 ftdi_deinit(&ftdic);
109         }
110 }
111
112 #ifdef DEBUG
113 static void jtagkey_state(unsigned char data) {
114         fprintf(stderr,"Pins high: ");
115
116         if (data & JTAGKEY_TCK)
117                 fprintf(stderr,"TCK ");
118
119         if (data & JTAGKEY_TDI)
120                 fprintf(stderr,"TDI ");
121
122         if (data & JTAGKEY_TDO)
123                 fprintf(stderr,"TDO ");
124
125         if (data & JTAGKEY_TMS)
126                 fprintf(stderr,"TMS ");
127
128         if (data & JTAGKEY_VREF)
129                 fprintf(stderr,"VREF ");
130         
131         fprintf(stderr,"\n");
132 }
133 #endif
134
135 struct jtagkey_reader_arg {
136         int             num;
137         unsigned char   *buf;
138 };
139
140 static void *jtagkey_reader(void *thread_arg) {
141         struct jtagkey_reader_arg *arg = (struct jtagkey_reader_arg*)thread_arg;
142         int i;
143
144         i = 0;
145         DPRINTF("reader for %d bytes\n", arg->num);
146         while (i < arg->num) {
147                 i += ftdi_read_data(&ftdic, arg->buf + i, arg->num - i);
148         }
149         
150         pthread_exit(NULL);
151 }
152
153 /* TODO: Interpret JTAG commands and transfer in MPSSE mode */
154 int jtagkey_transfer(WD_TRANSFER *tr, int fd, unsigned int request, int ppbase, int ecpbase, int num) {
155         int ret = 0;
156         int i;
157         int nread = 0;
158         unsigned long port;
159         unsigned char val;
160         static unsigned char last_data = 0;
161         static unsigned char last_write = 0x00;
162         static unsigned char writebuf[USBBUFSIZE], *writepos = writebuf;
163         static unsigned char readbuf[USBBUFSIZE], *readpos;
164         unsigned char data, prev_data, last_cyc_write;
165         struct jtagkey_reader_arg targ;
166         pthread_t reader_thread;
167
168         /* Count reads */
169         for (i = 0; i < num; i++)
170                 if (tr[i].cmdTrans == PP_READ)
171                         nread++;
172
173         /* Write combining */
174         if ((writepos-writebuf > sizeof(writebuf)-num) || (nread && writepos-writebuf)) {
175                 unsigned char *pos = writebuf;
176                 int len;
177
178                 DPRINTF("writing %d bytes due to %d following reads in %d chunks or full buffer\n", writepos-writebuf, nread, num);
179                 jtagkey_latency(BULK_LATENCY);
180
181                 targ.num = writepos-pos;
182                 targ.buf = readbuf;
183                 pthread_create(&reader_thread, NULL, &jtagkey_reader, &targ);
184
185                 while (pos < writepos) {
186                         len = writepos-pos;
187
188                         if (len > USBBUFSIZE)
189                                 len = USBBUFSIZE;
190
191                         DPRINTF("combined write of %d/%d\n",len,writepos-pos);
192                         ftdi_write_data(&ftdic, pos, len);
193                         pos += len;
194                 }
195                 pthread_join(reader_thread, NULL);
196
197                 writepos = writebuf;
198         }
199
200         last_cyc_write = last_write;
201
202         for (i = 0; i < num; i++) {
203                 DPRINTF("dwPort: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
204                                 (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
205                                 tr[i].fAutoinc, tr[i].dwOptions);
206
207                 port = (unsigned long)tr[i].dwPort;
208                 val = tr[i].Data.Byte;
209
210 #ifdef DEBUG
211                 if (tr[i].cmdTrans == 13)
212                         DPRINTF("write byte: %d\n", val);
213
214                 if (tr[i].cmdTrans == 13)
215                         jtagmon(val & PP_TCK, val & PP_TMS, val & PP_TDI);
216 #endif
217
218                 /* Pad writebuf for read-commands in stream */
219                 *writepos = last_data;
220                 prev_data = last_data;
221
222                 if (port == ppbase + PP_DATA) {
223                         DPRINTF("data port\n");
224
225                         data = 0x00;
226                         switch(tr[i].cmdTrans) {
227                                 case PP_READ:
228                                         ret = 0; /* We don't support reading of the data port */
229                                         break;
230
231                                 case PP_WRITE:
232                                         if (val & PP_TDI) {
233                                                 data |= JTAGKEY_TDI;
234                                                 DPRINTF("TDI\n");
235                                         } else {
236                                                 DPRINTF("!TDI\n");
237                                         }
238                                         if (val & PP_TCK) {
239                                                 data |= JTAGKEY_TCK;
240                                                 DPRINTF("TCK\n");
241                                         } else {
242                                                 DPRINTF("!TCK\n");
243                                         }
244                                         if (val & PP_TMS) {
245                                                 data |= JTAGKEY_TMS;
246                                                 DPRINTF("TMS\n");
247                                         } else {
248                                                 DPRINTF("!TMS\n");
249                                         }
250                                         if (val & PP_CTRL) {
251                                                 data = JTAGKEY_OEn;
252                                                 DPRINTF("CTRL\n");
253                                         } else {
254                                                 DPRINTF("!CTRL\n");
255                                         }
256
257                                         if (val & PP_PROG) {
258                                                 DPRINTF("PROG\n");
259                                         } else {
260                                                 DPRINTF("!PROG\n");
261                                         }
262
263                                         *writepos = data;
264
265                                         last_data = data;
266                                         last_write = val;
267                                         break;
268
269                                 default:
270                                         fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans);
271                                         ret = -1;
272                                         break;
273                         }
274                 }
275
276                 if ((tr[i].cmdTrans == PP_READ) || (*writepos != prev_data) || (i == num-1))
277                         writepos++;
278         }
279
280         if (nread)
281         {
282                 DPRINTF("writing %d bytes\n", writepos-writebuf);
283
284                 *writepos = last_data;
285                 writepos++;
286
287                 jtagkey_latency(OTHER_LATENCY);
288
289                 targ.num = writepos-writebuf;
290                 targ.buf = readbuf;
291                 pthread_create(&reader_thread, NULL, &jtagkey_reader, &targ);
292                 ftdi_write_data(&ftdic, writebuf, writepos-writebuf);
293                 pthread_join(reader_thread, NULL);
294
295 #ifdef DEBUG
296                 DPRINTF("write: ");
297                 hexdump(writebuf, writepos-writebuf);
298                 DPRINTF("read: ");
299                 hexdump(readbuf, i);
300 #endif
301
302                 writepos = writebuf;
303         } else {
304                 return ret;
305         }
306
307         readpos = readbuf;
308         last_write = last_cyc_write;
309
310         for (i = 0; i < num; i++) {
311                 DPRINTF("dwPort: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
312                                 (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
313                                 tr[i].fAutoinc, tr[i].dwOptions);
314
315                 port = (unsigned long)tr[i].dwPort;
316                 val = tr[i].Data.Byte;
317
318                 if ((tr[i].cmdTrans != PP_READ) && (val == last_write) && (i != num-1))
319                         continue;
320
321                 readpos++;
322
323                 if (port == ppbase + PP_DATA) {
324                         if (tr[i].cmdTrans == PP_WRITE) {
325                                 last_write = val;
326                         }
327                 } else if (port == ppbase + PP_STATUS) {
328                         DPRINTF("status port (last write: 0x%x)\n", last_write);
329                         switch(tr[i].cmdTrans) {
330                                 case PP_READ:
331                                         data = *readpos;
332
333 #ifdef DEBUG
334                                         DPRINTF("READ: 0x%x\n", data);
335                                         jtagkey_state(data);
336 #endif
337
338                                         val = 0x00;
339                                         if ((data & JTAGKEY_TDO) && (last_write & PP_PROG))
340                                                 val |= PP_TDO;
341
342                                         if (~last_write & PP_PROG)
343                                                 val |= 0x08;
344
345                                         if (last_write & 0x40)
346                                                 val |= 0x20;
347                                         else
348                                                 val |= 0x80;
349                                         break;
350
351                                 case PP_WRITE:
352                                         ret = 0; /* Status Port is readonly */
353                                         break;
354
355                                 default:
356                                         fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans);
357                                         ret = -1;
358                                         break;
359                         }
360                 } else {
361                         ret = 0;
362                 }
363
364                 tr[i].Data.Byte = val;
365
366                 DPRINTF("dwPortReturn: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
367                                 (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
368                                 tr[i].fAutoinc, tr[i].dwOptions);
369 #ifdef DEBUG
370                 if (tr[i].cmdTrans == 10)
371                         DPRINTF("read byte: %d\n", tr[i].Data.Byte);
372 #endif
373         }
374
375         return ret;
376 }