1 // SPDX-License-Identifier: Apache-2.0
2 /*
3 * Copyright (C) 2020 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
4 */
5
6 #include <libusb.h>
7 #include <stdio.h>
8 #include <string.h>
9
10 #include <iostream>
11 #include <map>
12 #include <vector>
13 #include <string>
14
15 #include "display.hpp"
16 #include "ch552_jtag.hpp"
17 #include "ftdipp_mpsse.hpp"
18
19 using namespace std;
20
21 #define DEBUG 0
22
23 #ifdef DEBUG
24 #define display(...) \
25 do { \
26 if (_verbose) fprintf(stdout, __VA_ARGS__); \
27 }while(0)
28 #else
29 #define display(...) do {}while(0)
30 #endif
31
CH552_jtag(const FTDIpp_MPSSE::mpsse_bit_config & cable,string dev,const string & serial,uint32_t clkHZ,uint8_t verbose)32 CH552_jtag::CH552_jtag(const FTDIpp_MPSSE::mpsse_bit_config &cable,
33 string dev, const string &serial, uint32_t clkHZ, uint8_t verbose):
34 FTDIpp_MPSSE(cable, dev, serial, clkHZ, verbose), _to_read(0)
35 {
36 init_internal(cable);
37 }
38
~CH552_jtag()39 CH552_jtag::~CH552_jtag()
40 {
41 int read;
42 /* Before shutdown, we must wait until everything is shifted out
43 * Do this by temporary enabling loopback mode, write something
44 * and wait until we can read it back
45 */
46 static unsigned char tbuf[16] = { SET_BITS_LOW, 0xff, 0x00,
47 SET_BITS_HIGH, 0xff, 0x00,
48 LOOPBACK_START,
49 static_cast<unsigned char>(MPSSE_DO_READ |
50 MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB),
51 0x04, 0x00,
52 0xaa, 0x55, 0x00, 0xff, 0xaa,
53 LOOPBACK_END
54 };
55 mpsse_store(tbuf, 16);
56 read = mpsse_read(tbuf, 5);
57 if (read != 5)
58 fprintf(stderr,
59 "Loopback failed, expect problems on later runs %d\n", read);
60 }
61
init_internal(const FTDIpp_MPSSE::mpsse_bit_config & cable)62 void CH552_jtag::init_internal(const FTDIpp_MPSSE::mpsse_bit_config &cable)
63 {
64 display("iProduct : %s\n", _iproduct);
65
66 display("%x\n", cable.bit_low_val);
67 display("%x\n", cable.bit_low_dir);
68 display("%x\n", cable.bit_high_val);
69 display("%x\n", cable.bit_high_dir);
70
71 init(5, 0xfb, BITMODE_MPSSE);
72 ftdi_set_event_char(_ftdi, 0, 0);
73 ftdi_set_error_char(_ftdi, 0, 0);
74 ftdi_set_latency_timer(_ftdi, 5);
75 #if (FTDI_VERSION < 105)
76 ftdi_usb_purge_rx_buffer(_ftdi);
77 ftdi_usb_purge_tx_buffer(_ftdi);
78 #else
79 ftdi_tciflush(_ftdi);
80 ftdi_tcoflush(_ftdi);
81 #endif
82 }
83
setClkFreq(uint32_t clkHZ)84 int CH552_jtag::setClkFreq(uint32_t clkHZ) {
85
86 int ret = FTDIpp_MPSSE::setClkFreq(clkHZ);
87 return ret;
88 }
89
writeTMS(uint8_t * tms,uint32_t len,bool flush_buffer)90 int CH552_jtag::writeTMS(uint8_t *tms, uint32_t len, bool flush_buffer)
91 {
92 (void) flush_buffer;
93 display("%s %d %d\n", __func__, len, (len/8)+1);
94
95 if (len == 0)
96 return 0;
97
98 uint32_t xfer = len;
99 uint32_t iter = (_buffer_size -8) / 4;
100 iter = (_buffer_size / 3);
101 uint32_t offset = 0, pos = 0;
102 flush_buffer = true;
103
104 uint8_t buf[3]= {static_cast<unsigned char>(MPSSE_WRITE_TMS | MPSSE_LSB |
105 MPSSE_BITMODE | MPSSE_WRITE_NEG|
106 MPSSE_DO_READ),
107 0, 0};
108 while (xfer > 0) {
109 int bit_to_send = (xfer > 6) ? 6 : xfer;
110 buf[1] = bit_to_send-1;
111 buf[2] = 0x80;
112
113 for (int i = 0; i < bit_to_send; i++, offset++) {
114 buf[2] |=
115 (((tms[offset >> 3] & (1 << (offset & 0x07))) ? 1 : 0) << i);
116 }
117 pos+=3;
118 _to_read++;
119
120 mpsse_store(buf, 3);
121 if (pos >= iter) {
122 uint8_t tmp[_to_read];
123 pos = 0;
124 if (-1 == mpsse_read(tmp, _to_read))
125 printError("writeTMS: Fail to read/write");
126 _to_read = 0;
127 }
128 xfer -= bit_to_send;
129 }
130
131 if (flush_buffer) {
132 if (_to_read > 0) {
133 uint8_t tmp[_to_read];
134 if (mpsse_read(tmp, _to_read) == -1)
135 printError("writeTMS: fail to flush");
136 _to_read = 0;
137 }
138 if (_num > 0)
139 if (mpsse_write() == -1)
140 printError("writeTMS: fail to flush in write mode");
141 }
142
143 return len;
144 }
145
toggleClk(uint8_t tms,uint8_t tdi,uint32_t clk_len)146 int CH552_jtag::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len)
147 {
148 (void) tdi;
149
150 int byteLen = (clk_len+7)/8;
151 uint8_t buf_tms[byteLen];
152
153 memset(buf_tms, (tms) ? 0xff : 0x00, byteLen);
154 return writeTMS(buf_tms, clk_len, false);
155 }
156
flush()157 int CH552_jtag::flush()
158 {
159 int ret;
160 if (_to_read == 0) {
161 ret = mpsse_write();
162 if (ret == -1)
163 printError("flush: fails to write");
164 } else {
165 uint8_t tmp[_to_read];
166 ret = mpsse_read(tmp, _to_read);
167 if (ret == -1)
168 printError("flush: fails to read/write");
169 _to_read = 0;
170 }
171 return ret;
172 }
173
writeTDI(uint8_t * tdi,uint8_t * tdo,uint32_t len,bool last)174 int CH552_jtag::writeTDI(uint8_t *tdi, uint8_t *tdo, uint32_t len, bool last)
175 {
176 bool rd_mode = (tdo) ? true : false;
177 /* 3 possible case :
178 * - n * 8bits to send -> use byte command
179 * - less than 8bits -> use bit command
180 * - last bit to send -> sent in conjunction with TMS
181 */
182 int tx_buff_size = mpsse_get_buffer_size();
183 int real_len = (last) ? len - 1 : len; // if its a buffer in a big send send len
184 // else supress last bit -> with TMS
185 int nb_byte = real_len >> 3; // number of byte to send
186 int nb_bit = (real_len & 0x07); // residual bits
187 int xfer = tx_buff_size - 7; // 2 byte for opcode and size 2 time
188 unsigned char *rx_ptr = (unsigned char *)tdo;
189 unsigned char *tx_ptr = (unsigned char *)tdi;
190 unsigned char tx_buf[3] = {(unsigned char)(MPSSE_LSB |
191 ((tdi) ? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) |
192 ((rd_mode) ? (MPSSE_DO_READ) : 0)),
193 static_cast<unsigned char>((xfer - 1) & 0xff), // low
194 static_cast<unsigned char>((((xfer - 1) >> 8) & 0xff))}; // high
195 unsigned char def_cmd = tx_buf[0];
196 unsigned char rd_cmd = def_cmd | (MPSSE_DO_READ);
197 /* read (and write) 1Byte */
198 uint8_t oneshot_buf[3] = {rd_cmd, 0, 0};
199
200 if (_to_read != 0) {
201 uint8_t tmp_[_to_read];
202 if (mpsse_read(tmp_, _to_read) == -1)
203 printError("writeTDI: fails to flush read");
204 _to_read = 0;
205 }
206
207 display("%s len : %d %d %d %d\n", __func__, len, real_len, nb_byte,
208 nb_bit);
209
210 if (_num != 0 && ((nb_byte + _num + 3) > _buffer_size))
211 if (mpsse_write() == -1)
212 printError("writeTDI: fails to flush write");
213
214 if ((nb_byte * 8) + nb_bit != real_len) {
215 printf("pas cool\n");
216 throw std::exception();
217 }
218
219 /* first case: 1 full byte (and maybe up to 7bit) to send
220 * direct write (and read)
221 */
222 if (nb_byte == 1) {
223 uint8_t tmp_;
224 mpsse_store(oneshot_buf, 3);
225 if (tdi) {
226 mpsse_store(tx_ptr, 1);
227 tx_ptr++;
228 }
229 if (mpsse_read(&tmp_, 1) == -1)
230 printError("writeTDI: fails to read/write with nb_byte == 1");
231 if (rd_mode) {
232 *rx_ptr = tmp_;
233 rx_ptr++;
234 }
235 nb_byte--;
236 }
237
238 while (nb_byte != 0) {
239 uint8_t tmp_;
240 int xfer_len = (nb_byte > xfer) ? xfer : nb_byte;
241 if (!rd_mode) {
242 xfer_len--;
243 }
244 if (xfer_len != 0) {
245 tx_buf[0] = def_cmd;
246 tx_buf[1] = (((xfer_len - 1) ) & 0xff); // low
247 tx_buf[2] = (((xfer_len - 1) >> 8) & 0xff); // high
248 mpsse_store(tx_buf, 3);
249 if (tdi) {
250 mpsse_store(tx_ptr, xfer_len);
251 tx_ptr += xfer_len;
252 }
253 if (rd_mode) {
254 if (mpsse_read(rx_ptr, xfer_len) == -1)
255 printError("writeTDI: fails to read with nb_byte > 1");
256 rx_ptr += xfer_len;
257 } else {
258 mpsse_store(oneshot_buf, 3);
259 if (tdi) {
260 mpsse_store(tx_ptr, 1);
261 tx_ptr++;
262 }
263 if (mpsse_read(&tmp_, 1) == -1)
264 printError("writeTDI: fails to read/write with nb_byte > 1");
265 }
266 } else {
267 tx_buf[0] = rd_cmd;
268 tx_buf[1] = 0;
269 tx_buf[2] = 0;
270 mpsse_store(tx_buf, 3);
271 if (tdi) {
272 mpsse_store(tx_ptr, 1);
273 tx_ptr++;
274 }
275 if (mpsse_read(&tmp_, 1) == -1)
276 printError("writeTDI: fails to read/write with nb_byte == 0");
277 if (rd_mode) {
278 *rx_ptr = tmp_;
279 rx_ptr++;
280 }
281 }
282 if (!rd_mode)
283 xfer_len++;
284 nb_byte -= xfer_len;
285 }
286
287 unsigned char last_bit = (tdi) ? *tx_ptr : 0;
288
289 /* next: serie of bit to send: inconditionnaly write AND read
290 */
291 if (nb_bit != 0) {
292 display("%s read/write %d bit\n", __func__, nb_bit);
293 tx_buf[0] = rd_cmd | MPSSE_BITMODE;
294 tx_buf[1] = nb_bit - 1;
295 mpsse_store(tx_buf, 2);
296 if (tdi) {
297 display("%s last_bit %x size %d\n", __func__, last_bit, nb_bit-1);
298 mpsse_store(last_bit);
299 }
300 uint8_t tmp_;
301 if (mpsse_read(&tmp_, 1) == -1)
302 printError("writeTDI: fails to read/write serie of bits");
303 if (rd_mode) {
304 *rx_ptr = tmp_;
305 /* realign we have read nb_bit
306 * since LSB add bit by the left and shift
307 * we need to complete shift
308 */
309 *rx_ptr >>= (8 - nb_bit);
310 display("%s %x\n", __func__, *rx_ptr);
311 }
312 }
313
314 /* display : must be dropped */
315 if (_verbose && tdo) {
316 display("\n");
317 for (int i = (len / 8) - 1; i >= 0; i--)
318 display("%x ", (unsigned char)tdo[i]);
319 display("\n");
320 }
321
322 if (last == 1) {
323 last_bit = (tdi)? (*tx_ptr & (1 << nb_bit)) : 0;
324
325 display("%s move to EXIT1_xx and send last bit %x\n", __func__, (last_bit?0x81:0x01));
326 /* write the last bit in conjunction with TMS */
327 tx_buf[0] = MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG |
328 (MPSSE_DO_READ);
329 tx_buf[1] = 0x0; // send 1bit
330 tx_buf[2] = ((last_bit) ? 0x81 : 0x01); // we know in TMS tdi is bit 7
331 // and to move to EXIT_XR TMS = 1
332 mpsse_store(tx_buf, 3);
333 uint8_t c;
334 if (mpsse_read(&c, 1) == -1)
335 printError("writeTDI: fails to read/write last transaction");
336 if (rd_mode) {
337 /* in this case for 1 one it's always bit 7 */
338 *rx_ptr |= ((c & 0x80) << (7 - nb_bit));
339 }
340 }
341
342 return 0;
343 }
344