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