• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2021-2022 Jean THOMAS <virgule@jeanthomas.me>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 /*
18  * Driver for the DirtyJTAG project.
19  * See https://github.com/jeanthom/dirtyjtag for more info.
20  *
21  *  SPI-JTAG Pin Mapping
22  * |=========|==========|
23  * | SPI pin | JTAG pin |
24  * |=========|==========|
25  * | #CS     | TMS      |
26  * | #WP     | SRST     |
27  * | #HOLD   | TRST     |
28  * | MISO    | TDO      |
29  * | MOSI    | TDI      |
30  * | CLK     | TCK      |
31  * |=========|==========|
32  */
33 
34 #include <assert.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <libusb.h>
39 #include "programmer.h"
40 
41 struct dirtyjtag_spi_data {
42 	struct libusb_context *libusb_ctx;
43 	struct libusb_device_handle *libusb_handle;
44 };
45 
46 static const struct dev_entry devs_dirtyjtag_spi[] = {
47 	{ 0x1209, 0xc0ca, OK, "DirtyJTAG", "JTAG probe" },
48 	{ 0 },
49 };
50 
51 static const char dirtyjtag_write_endpoint = 0x01;
52 static const char dirtyjtag_read_endpoint = 0x82;
53 static const int dirtyjtag_timeout = 100 * 10; /* 100 ms */
54 
55 enum dirtyjtag_command_identifier {
56 	CMD_STOP = 0x00,
57 	CMD_INFO = 0x01,
58 	CMD_FREQ = 0x02,
59 	CMD_XFER = 0x03,
60 	CMD_SETSIG = 0x04,
61 	CMD_GETSIG = 0x05,
62 	CMD_CLK = 0x06
63 };
64 
65 enum dirtyjtag_signal_identifier {
66 	SIG_TCK = 1 << 1,
67 	SIG_TDI = 1 << 2,
68 	SIG_TDO = 1 << 3,
69 	SIG_TMS = 1 << 4,
70 	SIG_TRST = 1 << 5,
71 	SIG_SRST = 1 << 6
72 };
73 
dirtyjtag_send(struct dirtyjtag_spi_data * djtag_data,uint8_t * data,size_t len)74 static int dirtyjtag_send(struct dirtyjtag_spi_data *djtag_data, uint8_t *data, size_t len)
75 {
76 	int transferred;
77 	int ret = libusb_bulk_transfer(djtag_data->libusb_handle,
78 		dirtyjtag_write_endpoint,
79 		data,
80 		len,
81 		&transferred,
82 		dirtyjtag_timeout);
83 	if (ret != 0) {
84 		msg_perr("%s: failed to send query command\n", __func__);
85 		return -1;
86 	}
87 	if (transferred != (int)len) {
88 		msg_perr("%s: failed to send whole packet\n", __func__);
89 		return -1;
90 	}
91 
92 	return 0;
93 }
94 
dirtyjtag_receive(struct dirtyjtag_spi_data * djtag_data,uint8_t * data,size_t buffer_len,int expected)95 static int dirtyjtag_receive(struct dirtyjtag_spi_data *djtag_data, uint8_t *data, size_t buffer_len, int expected)
96 {
97 	int transferred;
98 	int ret = libusb_bulk_transfer(djtag_data->libusb_handle,
99 		dirtyjtag_read_endpoint,
100 		data,
101 		buffer_len,
102 		&transferred,
103 		dirtyjtag_timeout);
104 	if (ret != 0) {
105 		msg_perr("%s: Failed to read SPI commands\n", __func__);
106 		return -1;
107 	}
108 
109 	if (expected != -1 && transferred != expected) {
110 		msg_perr("%s: failed to meet expected\n", __func__);
111 		return -1;
112 	}
113 
114 	return transferred;
115 }
116 
dirtyjtag_spi_shutdown(void * data)117 static int dirtyjtag_spi_shutdown(void *data)
118 {
119 	struct dirtyjtag_spi_data *djtag_data = (struct dirtyjtag_spi_data*)data;
120 	libusb_release_interface(djtag_data->libusb_handle, 0);
121 	libusb_attach_kernel_driver(djtag_data->libusb_handle, 0);
122 	libusb_close(djtag_data->libusb_handle);
123 	libusb_exit(djtag_data->libusb_ctx);
124 	free(data);
125 	return 0;
126 }
127 
dirtyjtag_djtag1_spi_send_command(struct dirtyjtag_spi_data * context,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)128 static int dirtyjtag_djtag1_spi_send_command(struct dirtyjtag_spi_data *context,
129 					     unsigned int writecnt, unsigned int readcnt,
130 					     const unsigned char *writearr, unsigned char *readarr)
131 {
132 	const size_t max_xfer_size = 30; // max transfer size in DJTAG1
133 	size_t len = writecnt + readcnt;
134 	size_t num_xfer = (len + max_xfer_size - 1 ) / max_xfer_size; // ceil(len/max_xfer_size)
135 
136 	uint8_t *rxtx_buffer = malloc(max_xfer_size * num_xfer);
137 	if (!rxtx_buffer) {
138 		msg_perr("%s: Failed rxtx_buffer allocation\n", __func__);
139 		return -1;
140 	}
141 
142 	memcpy(rxtx_buffer, writearr, writecnt);
143 	for (size_t i = 0; i < num_xfer; i++) {
144 		const size_t xfer_offset = i * max_xfer_size;
145 		size_t txn_size = max_xfer_size;
146 		if (i == num_xfer-1 && len % max_xfer_size != 0)
147 			txn_size = len % max_xfer_size;
148 
149 		uint8_t transfer_buffer[32] = {
150 			CMD_XFER,
151 			txn_size * 8
152 		};
153 		memcpy(transfer_buffer + 2, rxtx_buffer + xfer_offset, txn_size);
154 
155 		if (dirtyjtag_send(context, transfer_buffer, sizeof(transfer_buffer)))
156 			goto cleanup_fail;
157 
158 		if (dirtyjtag_receive(context, transfer_buffer, sizeof(transfer_buffer), 32) < 0)
159 			goto cleanup_fail;
160 
161 		memcpy(rxtx_buffer + xfer_offset, transfer_buffer, txn_size);
162 	}
163 	memcpy(readarr, rxtx_buffer + writecnt, readcnt);
164 
165 	free(rxtx_buffer);
166 
167 	uint8_t tms_reset_buffer[] = {
168 		CMD_SETSIG,
169 		SIG_TMS,
170 		SIG_TMS,
171 
172 		CMD_STOP,
173 	};
174 	dirtyjtag_send(context, tms_reset_buffer, sizeof(tms_reset_buffer));
175 
176 	return 0;
177 
178 cleanup_fail:
179 	free(rxtx_buffer);
180 	return -1;
181 }
182 
dirtyjtag_spi_spi_send_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)183 static int dirtyjtag_spi_spi_send_command(const struct flashctx *flash,
184 					  unsigned int writecnt, unsigned int readcnt,
185 					  const unsigned char *writearr, unsigned char *readarr)
186 {
187 	struct dirtyjtag_spi_data *djtag_data = flash->mst->spi.data;
188 	return dirtyjtag_djtag1_spi_send_command(djtag_data, writecnt, readcnt, writearr, readarr);
189 }
190 
191 static const struct spi_master spi_master_dirtyjtag_spi = {
192 	.features	= SPI_MASTER_4BA,
193 	.max_data_read	= MAX_DATA_READ_UNLIMITED,
194 	.max_data_write	= MAX_DATA_WRITE_UNLIMITED,
195 	.command	= dirtyjtag_spi_spi_send_command,
196 	.read		= default_spi_read,
197 	.write_256	= default_spi_write_256,
198 	.write_aai	= default_spi_write_aai,
199 	.shutdown	= dirtyjtag_spi_shutdown,
200 };
201 
dirtyjtag_spi_init(const struct programmer_cfg * cfg)202 static int dirtyjtag_spi_init(const struct programmer_cfg *cfg)
203 {
204 	struct libusb_device_handle *handle = NULL;
205 	struct dirtyjtag_spi_data *djtag_data = NULL;
206 
207 	djtag_data = calloc(1, sizeof(struct dirtyjtag_spi_data));
208 	if (djtag_data == NULL) {
209 		msg_perr("%s: failed to allocate internal driver data structure\n", __func__);
210 		return -1;
211 	}
212 
213 	int ret = libusb_init(&djtag_data->libusb_ctx);
214 	if (ret < 0) {
215 		msg_perr("%s: couldn't initialize libusb!\n", __func__);
216 		goto cleanup_djtag_struct;
217 	}
218 
219 #if LIBUSB_API_VERSION < 0x01000106
220 	libusb_set_debug(djtag_data->libusb_ctx, 3);
221 #else
222 	libusb_set_option(djtag_data->libusb_ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
223 #endif
224 
225 	uint16_t vid = devs_dirtyjtag_spi[0].vendor_id;
226 	uint16_t pid = devs_dirtyjtag_spi[0].device_id;
227 	handle = libusb_open_device_with_vid_pid(djtag_data->libusb_ctx, vid, pid);
228 	if (handle == NULL) {
229 		msg_perr("%s: couldn't open device %04x:%04x.\n", __func__, vid, pid);
230 		goto cleanup_libusb_ctx;
231 	}
232 
233 	ret = libusb_detach_kernel_driver(handle, 0);
234 	if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) {
235 		msg_pwarn("Cannot detach the existing USB driver. Claiming the interface may fail. %s\n",
236 			libusb_error_name(ret));
237 	}
238 
239 	ret = libusb_claim_interface(handle, 0);
240 	if (ret != 0) {
241 		msg_perr("%s: failed to claim interface 0: '%s'\n", __func__, libusb_error_name(ret));
242 		goto cleanup_libusb_handle;
243 	}
244 
245 	djtag_data->libusb_handle = handle;
246 
247 	unsigned long int freq = 100;
248 	char *tmp = extract_programmer_param_str(cfg, "spispeed");
249 	if (tmp) {
250 		char *units = tmp;
251 
252 		errno = 0;
253 		freq = strtoul(tmp, &units, 0);
254 		if (errno) {
255 			msg_perr("Invalid frequency \"%s\", %s\n", tmp, strerror(errno));
256 			free(tmp);
257 			goto cleanup_libusb_handle;
258 		}
259 
260 		if (!strcasecmp(units, "hz")) {
261 			freq /= 1000;
262 		} else if (!strcasecmp(units, "khz")) {
263 			/* Do nothing, already in the right unit */
264 		} else if (!strcasecmp(units, "mhz")) {
265 			freq *= 1000;
266 		} else {
267 			msg_perr("Invalid unit: %s, use hz, khz or mhz\n", units);
268 			free(tmp);
269 			goto cleanup_libusb_handle;
270 		}
271 
272 		if (freq > UINT16_MAX) {
273 			msg_perr("%s: Frequency set above DJTAG1 limits (%d kHz)", __func__, UINT16_MAX);
274 			free(tmp);
275 			goto cleanup_libusb_handle;
276 		}
277 
278 		msg_pinfo("%s: programmer speed set to %lu kHz\n", __func__, freq);
279 	}
280 	free(tmp);
281 
282 	uint8_t commands[] = {
283 		CMD_SETSIG, /* Set TDI/TCK to low, SRST/TRST/TMS to high */
284 		SIG_TDI | SIG_TMS | SIG_TCK | SIG_SRST | SIG_TRST,
285 		SIG_SRST | SIG_TRST | SIG_TMS,
286 
287 		CMD_FREQ, /* Set frequency */
288 		(freq >> 8) & 0xff,
289 		freq & 0xff,
290 
291 		CMD_STOP,
292 	};
293 	ret = dirtyjtag_send(djtag_data, commands, sizeof(commands));
294 	if (ret != 0) {
295 		msg_perr("%s: failed to configure DirtyJTAG into initialized state\n", __func__);
296 		goto cleanup_libusb_handle;
297 	}
298 
299 	return register_spi_master(&spi_master_dirtyjtag_spi, (void*)djtag_data);
300 
301 cleanup_libusb_handle:
302 	libusb_attach_kernel_driver(handle, 0);
303 	libusb_close(handle);
304 
305 cleanup_libusb_ctx:
306 	libusb_exit(djtag_data->libusb_ctx);
307 
308 cleanup_djtag_struct:
309 	free(djtag_data);
310 	return -1;
311 }
312 
313 const struct programmer_entry programmer_dirtyjtag_spi = {
314 	.name			= "dirtyjtag_spi",
315 	.type			= USB,
316 	.devs.dev		= devs_dirtyjtag_spi,
317 	.init			= dirtyjtag_spi_init,
318 };
319