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 #include <stdexcept>
15 
16 #include "display.hpp"
17 #include "ftdiJtagBitbang.hpp"
18 #include "ftdipp_mpsse.hpp"
19 
20 using namespace std;
21 
22 #define DEBUG 0
23 
24 #ifdef DEBUG
25 #define display(...) \
26 	do { \
27 		if (_verbose) fprintf(stdout, __VA_ARGS__); \
28 	}while(0)
29 #else
30 #define display(...) do {}while(0)
31 #endif
32 
FtdiJtagBitBang(const FTDIpp_MPSSE::mpsse_bit_config & cable,const jtag_pins_conf_t * pin_conf,string dev,const std::string & serial,uint32_t clkHZ,uint8_t verbose)33 FtdiJtagBitBang::FtdiJtagBitBang(const FTDIpp_MPSSE::mpsse_bit_config &cable,
34 			const jtag_pins_conf_t *pin_conf, string dev, const std::string &serial,
35 			uint32_t clkHZ, uint8_t verbose):
36 			FTDIpp_MPSSE(cable, dev, serial, clkHZ, verbose), _bitmode(0),
37 			_curr_tms(0), _rx_size(0)
38 {
39 	unsigned char *ptr;
40 
41 	_tck_pin = pin_conf->tck_pin;
42 	_tms_pin = pin_conf->tms_pin;
43 	_tdi_pin = pin_conf->tdi_pin;
44 	_tdo_pin = pin_conf->tdo_pin;
45 
46 	/* store FTDI TX Fifo size */
47 	if (_pid == 0x6001)  // FT232R
48 		_rx_size = 256;
49 	else if (_pid == 0x6015)  // FT231X
50 		_rx_size = 512;
51 	else
52 		_rx_size = _buffer_size;
53 
54 	/* RX Fifo size (rx: USB -> FTDI)
55 	 * is 128 or 256 Byte and MaxPacketSize ~= 64Byte
56 	 * but we let subsystem (libftdi, libusb, linux)
57 	 * sending with the correct size -> this reduce hierarchical calls
58 	 */
59 	_buffer_size = 4096;
60 
61 	/* _buffer_size has changed -> resize buffer */
62 	ptr = (unsigned char *)realloc(_buffer, sizeof(char) * _buffer_size);
63 	if (!ptr)
64 		throw std::runtime_error("_buffer realloc failed\n");
65 	_buffer = ptr;
66 
67 	setClkFreq(clkHZ);
68 
69 	init(1, _tck_pin | _tms_pin | _tdi_pin, BITMODE_BITBANG);
70 	setBitmode(BITMODE_BITBANG);
71 }
72 
~FtdiJtagBitBang()73 FtdiJtagBitBang::~FtdiJtagBitBang()
74 {
75 }
76 
setClkFreq(uint32_t clkHZ)77 int FtdiJtagBitBang::setClkFreq(uint32_t clkHZ)
78 {
79 	uint32_t user_clk = clkHZ;
80 	if (clkHZ > 3000000) {
81 		printWarn("Jtag probe limited to 3MHz");
82 		clkHZ = 3000000;
83 	}
84 	printInfo("Jtag frequency : requested " + std::to_string(user_clk) +
85 			"Hz -> real " + std::to_string(clkHZ) + "Hz");
86 	int ret = ftdi_set_baudrate(_ftdi, clkHZ);
87 	printf("ret %d\n", ret);
88 	return ret;
89 }
90 
setBitmode(uint8_t mode)91 int FtdiJtagBitBang::setBitmode(uint8_t mode)
92 {
93 	if (_bitmode == mode)
94 		return 0;
95 	_bitmode = mode;
96 
97 	int ret = ftdi_set_bitmode(_ftdi, _tck_pin | _tms_pin | _tdi_pin, _bitmode);
98 #if (FTDI_VERSION < 105)
99 	ftdi_usb_purge_rx_buffer(_ftdi);
100 	ftdi_usb_purge_tx_buffer(_ftdi);
101 #else
102 	ftdi_tcioflush(_ftdi);
103 #endif
104 	return ret;
105 }
106 
writeTMS(uint8_t * tms,uint32_t len,bool flush_buffer)107 int FtdiJtagBitBang::writeTMS(uint8_t *tms, uint32_t len, bool flush_buffer)
108 {
109 	int ret;
110 
111 	/* nothing to send
112 	 * but maybe need to flush internal buffer
113 	 */
114 	if (len == 0) {
115 		if (flush_buffer) {
116 			ret = flush();
117 			return ret;
118 		}
119 		return 0;
120 	}
121 
122 	/* check for at least one bit space in buffer */
123 	if (_num+2 > _buffer_size) {
124 		ret = flush();
125 		if (ret < 0)
126 			return ret;
127 	}
128 
129 	/* fill buffer to reduce USB transaction */
130 	for (uint32_t i = 0; i < len; i++) {
131 		_curr_tms = ((tms[i >> 3] & (1 << (i & 0x07)))? _tms_pin : 0);
132 		uint8_t val = _tdi_pin | _curr_tms;
133 		_buffer[_num++] = val;
134 		_buffer[_num++] = val | _tck_pin;
135 
136 		if (_num + 2 > _buffer_size) {
137 			ret = write(NULL, 0);
138 			if (ret < 0)
139 				return ret;
140 		}
141 	}
142 
143 	/* security check: try to flush buffer */
144 	if (flush_buffer) {
145 		ret = write(NULL, 0);
146 		if (ret < 0)
147 			return ret;
148 	}
149 
150 	return len;
151 }
152 
writeTDI(uint8_t * tx,uint8_t * rx,uint32_t len,bool end)153 int FtdiJtagBitBang::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
154 {
155 	uint32_t iter;
156 	uint32_t xfer_size = (rx) ? _rx_size : _buffer_size;
157 	if (len * 2 + 1 < xfer_size) {
158 		iter = len;
159 	} else {
160 		iter = xfer_size >> 1;  // two tx / bit
161 		iter = (iter / 8) * 8;
162 	}
163 
164 	uint8_t *rx_ptr = rx;
165 
166 	if (len == 0)
167 		return 0;
168 	if (rx)
169 		memset(rx, 0, len/8);
170 
171 	/* quick fix: use an empty buffer */
172 	if (_num != 0)
173 		flush();
174 
175 	for (uint32_t i = 0, pos = 0; i < len; i++) {
176 		/* keep tms or
177 		 * set tms high if it's last bit and end true */
178 		if (end && (i == len -1))
179 			_curr_tms = _tms_pin;
180 		uint8_t val = _curr_tms;
181 
182 		if (tx)
183 			val |= ((tx[i >> 3] & (1 << (i & 0x07)))? _tdi_pin : 0);
184 		_buffer[_num    ] = val;
185 		_buffer[_num + 1] = val | _tck_pin;
186 
187 		_num += 2;
188 
189 		pos++;
190 		/* flush buffer */
191 		if (pos == iter) {
192 			pos = 0;
193 			write((rx) ? rx_ptr : NULL, iter);
194 			if (rx)
195 				rx_ptr += (iter/8);
196 		}
197 	}
198 
199 	/* security check: try to flush buffer */
200 	if (_num != 0) {
201 		write((rx && _num > 1) ? rx_ptr : NULL, _num / 2);
202 	}
203 
204 	return len;
205 }
206 
toggleClk(uint8_t tms,uint8_t tdi,uint32_t clk_len)207 int FtdiJtagBitBang::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len)
208 {
209 	int xfer_len = clk_len;
210 
211 	int val = ((tms) ? _tms_pin : 0) | ((tdi) ? _tdi_pin : 0);
212 	while (xfer_len > 0) {
213 		if (_num + 2 > _buffer_size)
214 			if (write(NULL, 0) < 0)
215 				return -EXIT_FAILURE;
216 		_buffer[_num++] = val | _tck_pin;
217 		_buffer[_num++] = val;
218 
219 		xfer_len--;
220 	}
221 
222 	/* flush */
223 	write(NULL, 0);
224 
225 	return clk_len;
226 }
227 
flush()228 int FtdiJtagBitBang::flush()
229 {
230 	return write(NULL, 0);
231 }
232 
write(uint8_t * tdo,int nb_bit)233 int FtdiJtagBitBang::write(uint8_t *tdo, int nb_bit)
234 {
235 	int ret = 0;
236 	if (_num == 0)
237 		return 0;
238 
239 	setBitmode((tdo) ? BITMODE_SYNCBB : BITMODE_BITBANG);
240 
241 	ret = ftdi_write_data(_ftdi, _buffer, _num);
242 	if (ret != _num) {
243 		printf("problem %d written\n", ret);
244 		return ret;
245 	}
246 
247 	if (tdo) {
248 		ret = ftdi_read_data(_ftdi, _buffer, _num);
249 		if (ret != _num) {
250 			printf("problem %d read\n", ret);
251 			return ret;
252 		}
253 		/* need to reconstruct received word
254 		 * even bit are discarded since JTAG read in rising edge
255 		 * since jtag is LSB first we need to shift right content by 1
256 		 * and add 0x80 (1 << 7) or 0
257 		 * the buffer may contains some tms bit, so start with i
258 		 * equal to fill exactly nb_bit bits
259 		 * */
260 		for (int i = (_num-(nb_bit *2) + 1), offset=0; i < _num; i+=2, offset++) {
261 			tdo[offset >> 3] = (((_buffer[i] & _tdo_pin) ? 0x80 : 0x00) |
262 							(tdo[offset >> 3] >> 1));
263 		}
264 	}
265 	_num = 0;
266 	return ret;
267 }
268