flashrom 

flashrom Svn Source Tree

Root/trunk/pickit2_spi.c

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

Archive Download this file

Revision: HEAD