1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2010 Carl-Daniel Hailfinger
5  * Copyright (C) 2014 Justin Chevrier
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of the License.
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  * Connections are as follows:
19  *
20  *      +------+-----+----------+
21  *      | SPI  | Pin | PICkit2  |
22  *      +------+-----+----------+
23  *      | /CS  | 1   | VPP/MCLR |
24  *      | VCC  | 2   | VDD      |
25  *      | GND  | 3   | GND      |
26  *      | MISO | 4   | PGD      |
27  *      | SCLK | 5   | PDC      |
28  *      | MOSI | 6   | AUX      |
29  *      +------+-----+----------+
30  *
31  * Inspiration and some specifics of the interface came via the AVRDude
32  * PICkit2 code: https://github.com/steve-m/avrdude/blob/master/pickit2.c
33  */
34 
35 #include "platform.h"
36 
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <limits.h>
41 #include <errno.h>
42 #include <libusb.h>
43 
44 #include "flash.h"
45 #include "chipdrivers.h"
46 #include "programmer.h"
47 #include "spi.h"
48 
49 const struct dev_entry devs_pickit2_spi[] = {
50 	{0x04D8, 0x0033, OK, "Microchip", "PICkit 2"},
51 
52 	{0}
53 };
54 
55 static libusb_device_handle *pickit2_handle;
56 
57 /* Default USB transaction timeout in ms */
58 #define DFLT_TIMEOUT            10000
59 
60 #define CMD_LENGTH              64
61 #define ENDPOINT_OUT            0x01
62 #define ENDPOINT_IN             0x81
63 
64 #define CMD_GET_VERSION         0x76
65 #define CMD_SET_VDD             0xA0
66 #define CMD_SET_VPP             0xA1
67 #define CMD_READ_VDD_VPP        0xA3
68 #define CMD_EXEC_SCRIPT         0xA6
69 #define CMD_CLR_DLOAD_BUFF      0xA7
70 #define CMD_DOWNLOAD_DATA       0xA8
71 #define CMD_CLR_ULOAD_BUFF      0xA9
72 #define CMD_UPLOAD_DATA         0xAA
73 #define CMD_END_OF_BUFFER       0xAD
74 
75 #define SCR_SPI_READ_BUF        0xC5
76 #define SCR_SPI_WRITE_BUF       0xC6
77 #define SCR_SET_AUX             0xCF
78 #define SCR_LOOP                0xE9
79 #define SCR_SET_ICSP_CLK_PERIOD 0xEA
80 #define SCR_SET_PINS            0xF3
81 #define SCR_BUSY_LED_OFF        0xF4
82 #define SCR_BUSY_LED_ON         0xF5
83 #define SCR_MCLR_GND_OFF        0xF6
84 #define SCR_MCLR_GND_ON         0xF7
85 #define SCR_VPP_PWM_OFF         0xF8
86 #define SCR_VPP_PWM_ON          0xF9
87 #define SCR_VPP_OFF             0xFA
88 #define SCR_VPP_ON              0xFB
89 #define SCR_VDD_OFF             0xFE
90 #define SCR_VDD_ON              0xFF
91 
pickit2_get_firmware_version(void)92 static int pickit2_get_firmware_version(void)
93 {
94 	int ret;
95 	uint8_t command[CMD_LENGTH] = {CMD_GET_VERSION, CMD_END_OF_BUFFER};
96 	int transferred;
97 
98 	ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
99 
100 	if (ret != 0) {
101 		msg_perr("Command Get Firmware Version failed!\n");
102 		return 1;
103 	}
104 
105 	ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_IN, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
106 
107 	if (ret != 0) {
108 		msg_perr("Command Get Firmware Version failed!\n");
109 		return 1;
110 	}
111 
112 	msg_pdbg("PICkit2 Firmware Version: %d.%d\n", (int)command[0], (int)command[1]);
113 	return 0;
114 }
115 
pickit2_set_spi_voltage(int millivolt)116 static int pickit2_set_spi_voltage(int millivolt)
117 {
118 	double voltage_selector;
119 	switch (millivolt) {
120 	case 0:
121 		/* Admittedly this one is an assumption. */
122 		voltage_selector = 0;
123 		break;
124 	case 1800:
125 		voltage_selector = 1.8;
126 		break;
127 	case 2500:
128 		voltage_selector = 2.5;
129 		break;
130 	case 3500:
131 		voltage_selector = 3.5;
132 		break;
133 	default:
134 		msg_perr("Unknown voltage %i mV! Aborting.\n", millivolt);
135 		return 1;
136 	}
137 	msg_pdbg("Setting SPI voltage to %u.%03u V\n", millivolt / 1000,
138 		 millivolt % 1000);
139 
140 	uint8_t command[CMD_LENGTH] = {
141 		CMD_SET_VDD,
142 		voltage_selector * 2048 + 672,
143 		(voltage_selector * 2048 + 672) / 256,
144 		voltage_selector * 36,
145 		CMD_SET_VPP,
146 		0x40,
147 		voltage_selector * 18.61,
148 		voltage_selector * 13,
149 		CMD_END_OF_BUFFER
150 	};
151 	int transferred;
152 	int ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
153 
154 	if (ret != 0) {
155 		msg_perr("Command Set Voltage failed!\n");
156 		return 1;
157 	}
158 
159 	return 0;
160 }
161 
162 struct pickit2_spispeeds {
163 	const char *const name;
164 	const int speed;
165 };
166 
167 static const struct pickit2_spispeeds spispeeds[] = {
168 	{ "1M",		0x1 },
169 	{ "500k",	0x2 },
170 	{ "333k",	0x3 },
171 	{ "250k",	0x4 },
172 	{ NULL,		0x0 },
173 };
174 
pickit2_set_spi_speed(unsigned int spispeed_idx)175 static int pickit2_set_spi_speed(unsigned int spispeed_idx)
176 {
177 	msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed_idx].name);
178 
179 	uint8_t command[CMD_LENGTH] = {
180 		CMD_EXEC_SCRIPT,
181 		2,
182 		SCR_SET_ICSP_CLK_PERIOD,
183 		spispeed_idx,
184 		CMD_END_OF_BUFFER
185 	};
186 
187 	int transferred;
188 	int ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
189 
190 	if (ret != 0) {
191 		msg_perr("Command Set SPI Speed failed!\n");
192 		return 1;
193 	}
194 
195 	return 0;
196 }
197 
pickit2_spi_send_command(struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)198 static int pickit2_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
199 				     const unsigned char *writearr, unsigned char *readarr)
200 {
201 
202 	/* Maximum number of bytes per transaction (including command overhead) is 64. Lets play it safe
203 	 * and always assume the worst case scenario of 20 bytes command overhead.
204 	 */
205 	if (writecnt + readcnt + 20 > CMD_LENGTH) {
206 		msg_perr("\nTotal packetsize (%i) is greater than 64 supported, aborting.\n",
207 			 writecnt + readcnt + 20);
208 		return 1;
209 	}
210 
211 	uint8_t buf[CMD_LENGTH] = {CMD_DOWNLOAD_DATA, writecnt};
212 	unsigned int i = 2;
213 	for (; i < writecnt + 2; i++) {
214 		buf[i] = writearr[i - 2];
215 	}
216 
217 	buf[i++] = CMD_CLR_ULOAD_BUFF;
218 	buf[i++] = CMD_EXEC_SCRIPT;
219 
220 	/* Determine script length based on number of bytes to be read or written */
221 	if (writecnt == 1 && readcnt == 1)
222 		buf[i++] = 7;
223 	else if (writecnt == 1 || readcnt == 1)
224 		buf[i++] = 10;
225 	else
226 		buf[i++] = 13;
227 
228 	/* Assert CS# */
229 	buf[i++] = SCR_VPP_OFF;
230 	buf[i++] = SCR_MCLR_GND_ON;
231 
232 	buf[i++] = SCR_SPI_WRITE_BUF;
233 
234 	if (writecnt > 1) {
235 		buf[i++] = SCR_LOOP;
236 		buf[i++] = 1; /* Loop back one instruction */
237 		buf[i++] = writecnt - 1; /* Number of times to loop */
238 	}
239 
240 	if (readcnt)
241 		buf[i++] = SCR_SPI_READ_BUF;
242 
243 	if (readcnt > 1) {
244 		buf[i++] = SCR_LOOP;
245 		buf[i++] = 1; /* Loop back one instruction */
246 		buf[i++] = readcnt - 1; /* Number of times to loop */
247 	}
248 
249 	/* De-assert CS# */
250 	buf[i++] = SCR_MCLR_GND_OFF;
251 	buf[i++] = SCR_VPP_PWM_ON;
252 	buf[i++] = SCR_VPP_ON;
253 
254 	buf[i++] = CMD_UPLOAD_DATA;
255 	buf[i++] = CMD_END_OF_BUFFER;
256 
257 	int transferred;
258 	int ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, buf, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
259 
260 	if (ret != 0) {
261 		msg_perr("Send SPI failed!\n");
262 		return 1;
263 	}
264 
265 	if (readcnt) {
266 		int length = 0;
267 		ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_IN, buf, CMD_LENGTH, &length, DFLT_TIMEOUT);
268 
269 		if (length == 0 || ret != 0) {
270 			msg_perr("Receive SPI failed\n");
271 			return 1;
272 		}
273 
274 		/* First byte indicates number of bytes transferred from upload buffer */
275 		if (buf[0] != readcnt) {
276 			msg_perr("Unexpected number of bytes transferred, expected %i, got %i!\n",
277 				 readcnt, ret);
278 			return 1;
279 		}
280 
281 		/* Actual data starts at byte number two */
282 		memcpy(readarr, &buf[1], readcnt);
283 	}
284 
285 	return 0;
286 }
287 
288 /* Copied from dediprog.c */
289 /* Might be useful for other USB devices as well. static for now. */
parse_voltage(char * voltage)290 static int parse_voltage(char *voltage)
291 {
292 	char *tmp = NULL;
293 	int i;
294 	int millivolt = 0, fraction = 0;
295 
296 	if (!voltage || !strlen(voltage)) {
297 		msg_perr("Empty voltage= specified.\n");
298 		return -1;
299 	}
300 	millivolt = (int)strtol(voltage, &tmp, 0);
301 	voltage = tmp;
302 	/* Handle "," and "." as decimal point. Everything after it is assumed
303 	 * to be in decimal notation.
304 	 */
305 	if ((*voltage == '.') || (*voltage == ',')) {
306 		voltage++;
307 		for (i = 0; i < 3; i++) {
308 			fraction *= 10;
309 			/* Don't advance if the current character is invalid,
310 			 * but continue multiplying.
311 			 */
312 			if ((*voltage < '0') || (*voltage > '9'))
313 				continue;
314 			fraction += *voltage - '0';
315 			voltage++;
316 		}
317 		/* Throw away remaining digits. */
318 		voltage += strspn(voltage, "0123456789");
319 	}
320 	/* The remaining string must be empty or "mV" or "V". */
321 	tolower_string(voltage);
322 
323 	/* No unit or "V". */
324 	if ((*voltage == '\0') || !strncmp(voltage, "v", 1)) {
325 		millivolt *= 1000;
326 		millivolt += fraction;
327 	} else if (!strncmp(voltage, "mv", 2) ||
328 		   !strncmp(voltage, "millivolt", 9)) {
329 		/* No adjustment. fraction is discarded. */
330 	} else {
331 		/* Garbage at the end of the string. */
332 		msg_perr("Garbage voltage= specified.\n");
333 		return -1;
334 	}
335 	return millivolt;
336 }
337 
338 static const struct spi_master spi_master_pickit2 = {
339 	.max_data_read	= 40,
340 	.max_data_write	= 40,
341 	.command	= pickit2_spi_send_command,
342 	.multicommand	= default_spi_send_multicommand,
343 	.read		= default_spi_read,
344 	.write_256	= default_spi_write_256,
345 	.write_aai	= default_spi_write_aai,
346 };
347 
pickit2_shutdown(void * data)348 static int pickit2_shutdown(void *data)
349 {
350 	/* Set all pins to float and turn voltages off */
351 	uint8_t command[CMD_LENGTH] = {
352 		CMD_EXEC_SCRIPT,
353 		8,
354 		SCR_SET_PINS,
355 		3, /* Bit-0=1(PDC In), Bit-1=1(PGD In), Bit-2=0(PDC LL), Bit-3=0(PGD LL) */
356 		SCR_SET_AUX,
357 		1, /* Bit-0=1(Aux In), Bit-1=0(Aux LL) */
358 		SCR_MCLR_GND_OFF,
359 		SCR_VPP_OFF,
360 		SCR_VDD_OFF,
361 		SCR_BUSY_LED_OFF,
362 		CMD_END_OF_BUFFER
363 	};
364 
365 	int transferred;
366 	int ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
367 
368 	if (ret != 0) {
369 		msg_perr("Command Shutdown failed!\n");
370 		ret = 1;
371 	}
372 	if (libusb_release_interface(pickit2_handle, 0) != 0) {
373 		msg_perr("Could not release USB interface!\n");
374 		ret = 1;
375 	}
376 	libusb_close(pickit2_handle);
377 	libusb_exit(NULL);
378 	return ret;
379 }
380 
pickit2_spi_init(void)381 int pickit2_spi_init(void)
382 {
383 	uint8_t buf[CMD_LENGTH] = {
384 		CMD_EXEC_SCRIPT,
385 		10,			/* Script length */
386 		SCR_SET_PINS,
387 		2, /* Bit-0=0(PDC Out), Bit-1=1(PGD In), Bit-2=0(PDC LL), Bit-3=0(PGD LL) */
388 		SCR_SET_AUX,
389 		0, /* Bit-0=0(Aux Out), Bit-1=0(Aux LL) */
390 		SCR_VDD_ON,
391 		SCR_MCLR_GND_OFF,	/* Let CS# float */
392 		SCR_VPP_PWM_ON,
393 		SCR_VPP_ON,		/* Pull CS# high */
394 		SCR_BUSY_LED_ON,
395 		CMD_CLR_DLOAD_BUFF,
396 		CMD_CLR_ULOAD_BUFF,
397 		CMD_END_OF_BUFFER
398 	};
399 
400 
401 	int spispeed_idx = 0;
402 	char *spispeed = extract_programmer_param("spispeed");
403 	if (spispeed != NULL) {
404 		int i = 0;
405 		for (; spispeeds[i].name; i++) {
406 			if (strcasecmp(spispeeds[i].name, spispeed) == 0) {
407 				spispeed_idx = i;
408 				break;
409 			}
410 		}
411 		if (spispeeds[i].name == NULL) {
412 			msg_perr("Error: Invalid 'spispeed' value.\n");
413 			free(spispeed);
414 			return 1;
415 		}
416 		free(spispeed);
417 	}
418 
419 	int millivolt = 3500;
420 	char *voltage = extract_programmer_param("voltage");
421 	if (voltage != NULL) {
422 		millivolt = parse_voltage(voltage);
423 		free(voltage);
424 		if (millivolt < 0)
425 			return 1;
426 	}
427 
428 	if (libusb_init(NULL) < 0) {
429 		msg_perr("Couldn't initialize libusb!\n");
430 		return -1;
431 	}
432 
433 #if LIBUSB_API_VERSION < 0x01000106
434 	libusb_set_debug(NULL, 3);
435 #else
436 	libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
437 #endif
438 
439 	const uint16_t vid = devs_pickit2_spi[0].vendor_id;
440 	const uint16_t pid = devs_pickit2_spi[0].device_id;
441 	pickit2_handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
442 	if (pickit2_handle == NULL) {
443 		msg_perr("Could not open device PICkit2!\n");
444 		libusb_exit(NULL);
445 		return 1;
446 	}
447 
448 	if (libusb_set_configuration(pickit2_handle, 1) != 0) {
449 		msg_perr("Could not set USB device configuration.\n");
450 		libusb_close(pickit2_handle);
451 		libusb_exit(NULL);
452 		return 1;
453 	}
454 	if (libusb_claim_interface(pickit2_handle, 0) != 0) {
455 		msg_perr("Could not claim USB device interface\n");
456 		libusb_close(pickit2_handle);
457 		libusb_exit(NULL);
458 		return 1;
459 	}
460 
461 	if (register_shutdown(pickit2_shutdown, NULL) != 0) {
462 		return 1;
463 	}
464 
465 	if (pickit2_get_firmware_version()) {
466 		return 1;
467 	}
468 
469 	/* Command Set SPI Speed */
470 	if (pickit2_set_spi_speed(spispeed_idx)) {
471 		return 1;
472 	}
473 
474 	/* Command Set SPI Voltage */
475 	msg_pdbg("Setting voltage to %i mV.\n", millivolt);
476 	if (pickit2_set_spi_voltage(millivolt) != 0) {
477 		return 1;
478 	}
479 
480 	/* Perform basic setup.
481 	 * Configure pin directions and logic levels, turn Vdd on, turn busy LED on and clear buffers. */
482 	int transferred;
483 	if (libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, buf, CMD_LENGTH, &transferred, DFLT_TIMEOUT) != 0) {
484 		msg_perr("Command Setup failed!\n");
485 		return 1;
486 	}
487 
488 	register_spi_master(&spi_master_pickit2);
489 
490 	return 0;
491 }
492