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