[flashrom] Add PICkit2 as an SPI programmer

Justin Chevrier jchevrier at gmail.com
Tue Jun 3 03:47:00 CEST 2014


On Mon, Jun 2, 2014 at 9:43 PM, Justin Chevrier <jchevrier at gmail.com> wrote:
> Hi Stefan,
>
> Attached is a second revision of my patch. Hopefully it addresses
> everything you pointed out previously! Keep me posted if more work
> needs to be done.
>
> I have attached a log of a write as well.
>
> Thanks again,
>
> Justin
>
> On Fri, May 30, 2014 at 8:27 PM, Stefan Tauner
> <stefan.tauner at alumni.tuwien.ac.at> wrote:
>> On Thu, 1 May 2014 13:39:44 -0400
>> Justin Chevrier <jchevrier at gmail.com> wrote:
>>
>>> Very sorry for not replying to your email (thanks for the review by the way).
>>>
>>> I do have a newer patch that fixes most if not all of the points you
>>> made, but I've been slacking in going over it one last time and
>>> getting it sent in. I had someone contact me directly around December
>>> and they successfully used this updated patch on their hardware.
>>>
>>> I'll see if I can get the patch brushed up and sent in shortly.
>>>
>>> Thanks for the reminder (ugh, can't believe it's been over one year).
>>
>> Hi Justin,
>>
>> this is just a friendly ping. I am planning to do a stable release in
>> the not too distant future (next few weeks) and would like to include
>> your module if it gets ready by then.
>>
>> --
>> Kind regards/Mit freundlichen Grüßen, Stefan Tauner

Ugh, sorry for the top post and the flashrom.8 junk in the patch.

New version attached.

Justin
-------------- next part --------------
Index: Makefile
===================================================================
--- Makefile	(revision 1817)
+++ Makefile	(working copy)
@@ -137,7 +137,7 @@
 else
 override CONFIG_PONY_SPI = no
 endif
-# Dediprog and FT2232 are not supported under DOS (missing USB support).
+# Dediprog, FT2232 and PICkit2 are not supported under DOS (missing USB support).
 ifeq ($(CONFIG_DEDIPROG), yes)
 UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes
 else
@@ -153,7 +153,12 @@
 else
 override CONFIG_USBBLASTER_SPI = no
 endif
+ifeq ($(CONFIG_PICKIT2_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_PICKIT2_SPI=yes
+else
+override CONFIG_PICKIT2_SPI = no
 endif
+endif
 
 # FIXME: Should we check for Cygwin/MSVC as well?
 ifeq ($(TARGET_OS), MinGW)
@@ -271,7 +276,7 @@
 else
 override CONFIG_PONY_SPI = no
 endif
-# Dediprog and FT2232 are not supported with libpayload (missing libusb support)
+# Dediprog, FT2232 and PICkit2 are not supported with libpayload (missing libusb support)
 ifeq ($(CONFIG_DEDIPROG), yes)
 UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes
 else
@@ -287,7 +292,12 @@
 else
 override CONFIG_USBBLASTER_SPI = no
 endif
+ifeq ($(CONFIG_PICKIT2_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_PICKIT2_SPI=yes
+else
+override CONFIG_PICKIT2_SPI = no
 endif
+endif
 
 ifneq ($(TARGET_OS), Linux)
 ifeq ($(CONFIG_LINUX_SPI), yes)
@@ -408,6 +418,9 @@
 # Always enable Altera USB-Blaster dongles for now.
 CONFIG_USBBLASTER_SPI ?= yes
 
+# Always enable PICkit2 SPI dongles for now.
+CONFIG_PICKIT2_SPI ?= yes
+
 # Always enable dummy tracing for now.
 CONFIG_DUMMY ?= yes
 
@@ -583,6 +596,12 @@
 PROGRAMMER_OBJS += usbblaster_spi.o
 endif
 
+ifeq ($(CONFIG_PICKIT2_SPI), yes)
+FEATURE_CFLAGS += -D'CONFIG_PICKIT2_SPI=1'
+PROGRAMMER_OBJS += pickit2_spi.o
+NEED_USB := yes
+endif
+
 ifeq ($(NEED_FTDI), yes)
 FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb")
 FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'")
Index: flashrom.8.tmpl
===================================================================
--- flashrom.8.tmpl	(revision 1817)
+++ flashrom.8.tmpl	(working copy)
@@ -225,6 +225,8 @@
 .sp
 .BR "* usbblaster_spi" " (for SPI flash ROMs attached to an Altera USB-Blaster compatible cable)"
 .sp
+.BR "* pickit2_spi" " (for SPI flash ROMs accessible via Microchip PICkit2)"
+.sp
 Some programmers have optional or mandatory parameters which are described
 in detail in the
 .B PROGRAMMER SPECIFIC INFO
@@ -724,6 +726,34 @@
 .BR "http://dangerousprototypes.com/docs/Practical_guide_to_Bus_Pirate_pull-up_resistors " .
 Only the external supply voltage (Vpu) is supported as of this writing.
 .SS
+.BR "pickit2_spi " programmer
+.B voltage
+parameter specifies the voltage the PICkit2 should use. The default unit is
+Volt if no unit is specified. You can use
+.BR mV ", " milliVolt ", " V " or " Volt
+as unit specifier. Syntax is
+.sp
+.B "  flashrom \-p pickit2_spi:voltage=value"
+.sp
+where
+.B value
+can be
+.BR 0V ", " 1.8V ", " 2.5V ", " 3.5V
+or the equivalent in mV.
+.sp
+An optional
+.B spispeed
+parameter specifies the frequency of the SPI bus.
+Syntax is
+.sp
+.B "  flashrom \-p pickit2_spi:spispeed=frequency"
+.sp
+where
+.B frequency
+can be
+.BR 250k ", " 333k ", " 500k " or " 1M "
+(in Hz). The default is a frequency of 1 MHz.
+.SS
 .BR "dediprog " programmer
 An optional
 .B voltage
@@ -935,7 +965,7 @@
 .B buspirate_spi
 needs userspace access to a serial port.
 .sp
-.BR dediprog ", " ft2232_spi " and " usbblaster_spi
+.BR dediprog ", " ft2232_spi " and " usbblaster_spi and " pickit2_spi
 need access to the USB device via libusb.
 .sp
 .B dummy
@@ -945,7 +975,7 @@
 .BR gfxnvidia ", " drkaiser ", " satasii ", " satamv ", " atahpt" and " atavia
 have to be run as superuser/root, and need additional raw access permission.
 .sp
-.BR serprog ", " buspirate_spi ", " dediprog ", " usbblaster_spi " and " ft2232_spi
+.BR serprog ", " buspirate_spi ", " dediprog ", " usbblaster_spi " and " ft2232_spi and " pickit2_spi
 can be run as normal user on most operating systems if appropriate device
 permissions are set.
 .sp
Index: flashrom.c
===================================================================
--- flashrom.c	(revision 1817)
+++ flashrom.c	(working copy)
@@ -345,6 +345,19 @@
 	},
 #endif
 
+#if CONFIG_PICKIT2_SPI == 1
+	{
+		.name			= "pickit2_spi",
+		.type			= OTHER,
+					/* FIXME */
+		.devs.note		= "Microchip PICkit2\n",
+		.init			= pickit2_spi_init,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.delay			= internal_delay,
+	},
+#endif
+
 	{0}, /* This entry corresponds to PROGRAMMER_INVALID. */
 };
 
Index: pickit2_spi.c
===================================================================
--- pickit2_spi.c	(revision 0)
+++ pickit2_spi.c	(working copy)
@@ -0,0 +1,527 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010 Carl-Daniel Hailfinger
+ * Copyright (C) 2014 Justin Chevrier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Connections are as follows:
+ *
+ *      +------+-----+----------+
+ *      | SPI  | Pin | PICkit2  |
+ *      +------+-----+----------+
+ *      | /CS  | 1   | VPP/MCLR |
+ *      | VCC  | 2   | VDD      |
+ *      | GND  | 3   | GND      |
+ *      | MISO | 4   | PGD      |
+ *      | SCLK | 5   | PDC      |
+ *      | MOSI | 6   | AUX      |
+ *      +------+-----+----------+
+ *
+ * Inspiration and some specifics of the interface came via the AVRDude 
+ * PICkit2 code: https://github.com/steve-m/avrdude/blob/master/pickit2.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <usb.h>
+#include "flash.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+#include "spi.h"
+
+static usb_dev_handle *pickit2_handle;
+
+/* Default USB transaction timeout in ms */
+#define DEFAULT_TIMEOUT         10000
+
+#define CMD_LENGTH              64
+#define ENDPOINT_OUT            0x01
+#define ENDPOINT_IN             0x81
+
+#define PICKIT2_VID             0x04D8
+#define PICKIT2_PID             0x0033
+
+#define CMD_GET_VERSION         0x76
+#define CMD_SET_VDD             0xA0
+#define CMD_SET_VPP             0xA1
+#define CMD_READ_VDD_VPP        0xA3
+#define CMD_EXEC_SCRIPT         0xA6
+#define CMD_CLR_DLOAD_BUFF      0xA7
+#define CMD_DOWNLOAD_DATA       0xA8
+#define CMD_CLR_ULOAD_BUFF      0xA9
+#define CMD_UPLOAD_DATA         0xAA
+#define CMD_END_OF_BUFFER       0xAD
+
+#define SCR_SPI_READ_BUF        0xC5
+#define SCR_SPI_WRITE_BUF       0xC6
+#define SCR_SET_AUX             0xCF
+#define SCR_LOOP                0xE9
+#define SCR_SET_ICSP_CLK_PERIOD 0xEA
+#define SCR_SET_PINS            0xF3
+#define SCR_BUSY_LED_OFF        0xF4
+#define SCR_BUSY_LED_ON         0xF5
+#define SCR_MCLR_GND_OFF        0xF6
+#define SCR_MCLR_GND_ON         0xF7
+#define SCR_VPP_PWM_OFF         0xF8
+#define SCR_VPP_PWM_ON          0xF9
+#define SCR_VPP_OFF             0xFA
+#define SCR_VPP_ON              0xFB
+#define SCR_VDD_OFF             0xFE
+#define SCR_VDD_ON              0xFF
+
+/* Copied from dediprog.c */
+/* Might be useful for other USB devices as well. static for now. */
+/* device parameter allows user to specify one device of multiple installed */
+static struct usb_device *get_device_by_vid_pid(uint16_t vid, uint16_t pid, unsigned int device)
+{
+	struct usb_bus *bus;
+	struct usb_device *dev;
+
+	for (bus = usb_get_busses(); bus; bus = bus->next)
+		for (dev = bus->devices; dev; dev = dev->next)
+			if ((dev->descriptor.idVendor == vid) &&
+			    (dev->descriptor.idProduct == pid)) {
+				if (device == 0)
+					return dev;
+				device--;
+			}
+
+	return NULL;
+}
+
+static int pickit2_get_firmware_version(void)
+{
+	int ret;
+	uint8_t command[CMD_LENGTH] = {CMD_GET_VERSION, CMD_END_OF_BUFFER};
+
+	ret = usb_interrupt_write(pickit2_handle, ENDPOINT_OUT, (char *)command, CMD_LENGTH, DEFAULT_TIMEOUT);
+	ret = usb_interrupt_read(pickit2_handle, ENDPOINT_IN, (char *)command, CMD_LENGTH, DEFAULT_TIMEOUT);
+	
+	msg_pdbg("PICkit2 Firmware Version: %d.%d\n", (int)command[0], (int)command[1]);
+	if (ret != CMD_LENGTH) {
+		msg_perr("Command Get Firmware Version failed (%s)!\n",
+			 usb_strerror());
+		return 1;
+	}
+
+	return 0;
+}
+
+static int pickit2_set_spi_voltage(int millivolt)
+{
+	int ret;
+	double voltage_selector;
+
+	switch (millivolt) {
+	case 0:
+		/* Admittedly this one is an assumption. */
+		voltage_selector = 0;
+		break;
+	case 1800:
+		voltage_selector = 1.8;
+		break;
+	case 2500:
+		voltage_selector = 2.5;
+		break;
+	case 3500:
+		voltage_selector = 3.5;
+		break;
+	default:
+		msg_perr("Unknown voltage %i mV! Aborting.\n", millivolt);
+		return 1;
+	}
+	msg_pdbg("Setting SPI voltage to %u.%03u V\n", millivolt / 1000,
+		 millivolt % 1000);
+
+	uint8_t command[CMD_LENGTH] = {
+		CMD_SET_VDD,
+		voltage_selector * 2048 + 672,
+		(voltage_selector * 2048 + 672) / 256,
+		voltage_selector * 36,
+		CMD_SET_VPP,
+		0x40,
+		voltage_selector * 18.61,
+		voltage_selector * 13,
+		CMD_END_OF_BUFFER
+	};
+
+	ret = usb_interrupt_write(pickit2_handle, ENDPOINT_OUT, (char *)command, CMD_LENGTH, DEFAULT_TIMEOUT);
+
+	if (ret != CMD_LENGTH) {
+		msg_perr("Command Set Voltage failed (%s)!\n",
+			 usb_strerror());
+		return 1;
+	}
+
+	return 0;
+}
+
+
+struct pickit2_spispeeds {
+	const char *const name;
+	const int speed;
+};
+
+static const struct pickit2_spispeeds spispeeds[] = {
+	{ "1M",		0x1 },
+	{ "500k",	0x2 },
+	{ "333k",	0x3 },
+	{ "250k",	0x4 },
+	{ NULL,		0x0 },
+};
+
+static int pickit2_set_spi_speed(unsigned int spispeed_idx)
+{
+	int ret;
+
+	msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed_idx].name);
+
+	uint8_t command[CMD_LENGTH] = {
+		CMD_EXEC_SCRIPT,
+		2,
+		SCR_SET_ICSP_CLK_PERIOD,
+		spispeed_idx,
+		CMD_END_OF_BUFFER
+	};
+
+	ret = usb_interrupt_write(pickit2_handle, ENDPOINT_OUT, (char *)command, CMD_LENGTH, DEFAULT_TIMEOUT);
+
+	if (ret != CMD_LENGTH) {
+		msg_perr("Command Set SPI Speed failed (%s)!\n",
+			 usb_strerror());
+		return 1;
+	}
+
+	return 0;
+}
+
+static int pickit2_spi_send_command(struct flashctx *flash,
+				     unsigned int writecnt,
+				     unsigned int readcnt,
+				     const unsigned char *writearr,
+				     unsigned char *readarr)
+{
+	int ret, i;
+
+	uint8_t buf[CMD_LENGTH] = {CMD_DOWNLOAD_DATA, writecnt};
+
+	/* Maximum number of bytes per transaction (including command overhead) is 64. Lets play it safe
+	 * and always assume the worst case scenario of 20 bytes command overhead.
+	 */
+	msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
+	if (writecnt + readcnt + 20 > CMD_LENGTH) {
+		msg_perr("\nTotal packetsize (%i) is greater than 64 supported, aborting.\n", writecnt + readcnt + 20);
+		return 1;
+	}
+
+	for (i = 2; i < writecnt + 2; i++) {
+		buf[i] = writearr[i - 2];
+	}
+
+	buf[i++] = CMD_CLR_ULOAD_BUFF;
+	buf[i++] = CMD_EXEC_SCRIPT;
+
+	/* Determine script length based on number of bytes to be read or written */
+	if (writecnt == 1 && readcnt == 1)
+		buf[i++] = 7;
+	else if (writecnt == 1 || readcnt == 1)
+		buf[i++] = 10;
+	else
+		buf[i++] = 13;
+		
+	/* Assert CS# */
+	buf[i++] = SCR_VPP_OFF;
+	buf[i++] = SCR_MCLR_GND_ON;
+
+	buf[i++] = SCR_SPI_WRITE_BUF;
+
+	if (writecnt > 1) {
+		buf[i++] = SCR_LOOP;
+		buf[i++] = 1; /* Loop back one instruction */
+		buf[i++] = writecnt - 1; /* Number of times to loop */
+	}
+
+	if (readcnt)
+		buf[i++] = SCR_SPI_READ_BUF;
+
+	if (readcnt > 1) {
+		buf[i++] = SCR_LOOP;
+		buf[i++] = 1; /* Loop back one instruction */
+		buf[i++] = readcnt - 1; /* Number of times to loop */
+	}
+
+	/* De-assert CS# */
+	buf[i++] = SCR_MCLR_GND_OFF;
+	buf[i++] = SCR_VPP_PWM_ON;
+	buf[i++] = SCR_VPP_ON;
+
+	buf[i++] = CMD_UPLOAD_DATA;
+	buf[i++] = CMD_END_OF_BUFFER;
+
+	ret = usb_interrupt_write(pickit2_handle, ENDPOINT_OUT, (char *)buf, CMD_LENGTH, DEFAULT_TIMEOUT);
+
+	if (ret != CMD_LENGTH) {
+		msg_perr("Send SPI failed, expected %i, got %i %s!\n",
+			writecnt, ret, usb_strerror());
+			return 1;
+	}
+
+	if (readcnt) {
+		ret = usb_interrupt_read(pickit2_handle, ENDPOINT_IN, (char *)buf, CMD_LENGTH, DEFAULT_TIMEOUT);
+
+		if (ret != CMD_LENGTH) {
+			msg_perr("Receive SPI failed, expected %i, got %i %s!\n",
+				readcnt, ret, usb_strerror());
+			return 1;
+		}
+
+		/* First byte indicates number of bytes transferred from upload buffer */
+		if (buf[0] != readcnt) {
+			msg_perr("Unexpected number of bytes transferred, expected %i, got %i!\n",
+				 readcnt, ret);
+			return 1;
+		}
+		
+		/* Actual data starts at byte number two */
+		memcpy(readarr, &buf[1], readcnt);
+	}
+
+	return 0;
+}
+
+/* Copied from dediprog.c */
+/* Might be useful for other USB devices as well. static for now. */
+static int parse_voltage(char *voltage)
+{
+	char *tmp = NULL;
+	int i;
+	int millivolt = 0, fraction = 0;
+
+	if (!voltage || !strlen(voltage)) {
+		msg_perr("Empty voltage= specified.\n");
+		return -1;
+	}
+	millivolt = (int)strtol(voltage, &tmp, 0);
+	voltage = tmp;
+	/* Handle "," and "." as decimal point. Everything after it is assumed
+	 * to be in decimal notation.
+	 */
+	if ((*voltage == '.') || (*voltage == ',')) {
+		voltage++;
+		for (i = 0; i < 3; i++) {
+			fraction *= 10;
+			/* Don't advance if the current character is invalid,
+			 * but continue multiplying.
+			 */
+			if ((*voltage < '0') || (*voltage > '9'))
+				continue;
+			fraction += *voltage - '0';
+			voltage++;
+		}
+		/* Throw away remaining digits. */
+		voltage += strspn(voltage, "0123456789");
+	}
+	/* The remaining string must be empty or "mV" or "V". */
+	tolower_string(voltage);
+
+	/* No unit or "V". */
+	if ((*voltage == '\0') || !strncmp(voltage, "v", 1)) {
+		millivolt *= 1000;
+		millivolt += fraction;
+	} else if (!strncmp(voltage, "mv", 2) ||
+		   !strncmp(voltage, "milliv", 6)) {
+		/* No adjustment. fraction is discarded. */
+	} else {
+		/* Garbage at the end of the string. */
+		msg_perr("Garbage voltage= specified.\n");
+		return -1;
+	}
+	return millivolt;
+}
+
+static const struct spi_programmer spi_programmer_pickit2 = {
+	.type		= SPI_CONTROLLER_PICKIT2,
+	.max_data_read	= 40,
+	.max_data_write	= 40,
+	.command	= pickit2_spi_send_command,
+	.multicommand	= default_spi_send_multicommand,
+	.read		= default_spi_read,
+	.write_256	= default_spi_write_256,
+	.write_aai	= default_spi_write_aai,
+};
+
+static int pickit2_shutdown(void *data)
+{
+	int ret;
+	msg_pspew("%s\n", __func__);
+
+	/* Set all pins to float and turn voltages off */
+	uint8_t command[CMD_LENGTH] = {
+		CMD_EXEC_SCRIPT,
+		8,
+		SCR_SET_PINS,
+		/* Bit-0=1(PDC In), Bit-1=1(PGD In), Bit-2=0(PDC LL), Bit-3=0(PGD LL) */
+		3,
+		SCR_SET_AUX,
+		/* Bit-0=1(Aux In), Bit-1=0(Aux LL) */
+		1,
+		SCR_MCLR_GND_OFF,
+		SCR_VPP_OFF,
+		SCR_VDD_OFF,
+		SCR_BUSY_LED_OFF,
+		CMD_END_OF_BUFFER
+	};
+
+	ret = usb_interrupt_write(pickit2_handle, ENDPOINT_OUT, (char *)command, CMD_LENGTH, DEFAULT_TIMEOUT);
+
+	if (ret != CMD_LENGTH) {
+		msg_perr("Command Shutdown failed (%s)!\n",
+			 usb_strerror());
+		return 1;
+	}
+
+	if (usb_release_interface(pickit2_handle, 0)) {
+		msg_perr("Could not release USB interface!\n");
+		return 1;
+	}
+	if (usb_close(pickit2_handle)) {
+		msg_perr("Could not close USB device!\n");
+		return 1;
+	}
+	return 0;
+}
+
+int pickit2_spi_init(void)
+{
+	struct usb_device *dev;
+	char *voltage, *spispeed;
+	int spispeed_idx = 0;
+	int millivolt = 3500;
+	long usedevice = 0;
+	int i, ret;
+
+	uint8_t buf[CMD_LENGTH] = {
+		CMD_EXEC_SCRIPT,
+		10,			/* Script length */
+		SCR_SET_PINS,
+		/* Bit-0=0(PDC Out), Bit-1=1(PGD In), Bit-2=0(PDC LL), Bit-3=0(PGD LL) */
+		2,
+		SCR_SET_AUX,
+		/* Bit-0=0(Aux Out), Bit-1=0(Aux LL) */
+		0,
+		SCR_VDD_ON,
+		SCR_MCLR_GND_OFF,	/* Let CS# float */
+		SCR_VPP_PWM_ON,
+		SCR_VPP_ON,		/* Pull CS# high */
+		SCR_BUSY_LED_ON,
+		CMD_CLR_DLOAD_BUFF,
+		CMD_CLR_ULOAD_BUFF,
+		CMD_END_OF_BUFFER
+	};
+
+	msg_pspew("%s\n", __func__);
+
+	spispeed = extract_programmer_param("spispeed");
+	if (spispeed) {
+		for (i = 0; spispeeds[i].name; ++i) {
+			if (!strcasecmp(spispeeds[i].name, spispeed)) {
+				spispeed_idx = i;
+				break;
+			}
+		}
+		if (!spispeeds[i].name) {
+			msg_perr("Error: Invalid 'spispeed' value.\n");
+			free(spispeed);
+			return 1;
+		}
+		free(spispeed);
+	}
+	voltage = extract_programmer_param("voltage");
+	if (voltage) {
+		millivolt = parse_voltage(voltage);
+		free(voltage);
+		if (millivolt < 0)
+			return 1;
+		msg_pinfo("Setting voltage to %i mV\n", millivolt);
+	}
+
+	/* Here comes the USB stuff */
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+	dev = get_device_by_vid_pid(PICKIT2_VID, PICKIT2_PID, (unsigned int) usedevice);
+	if (!dev) {
+		msg_perr("Could not find a PICkit2 on USB!\n");
+		return 1;
+	}
+	msg_pdbg("Found USB device (%04x:%04x).\n",
+		 dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+	pickit2_handle = usb_open(dev);
+	ret = usb_set_configuration(pickit2_handle, 1);
+	if (ret < 0) {
+		msg_perr("Could not set USB device configuration: %i %s\n",
+			 ret, usb_strerror());
+		if (usb_close(pickit2_handle))
+			msg_perr("Could not close USB device!\n");
+		return 1;
+	}
+	ret = usb_claim_interface(pickit2_handle, 0);
+	if (ret < 0) {
+		msg_perr("Could not claim USB device interface %i: %i %s\n",
+			 0, ret, usb_strerror());
+		if (usb_close(pickit2_handle))
+			msg_perr("Could not close USB device!\n");
+		return 1;
+	}
+
+	if (register_shutdown(pickit2_shutdown, NULL))
+		return 1;
+
+	if (pickit2_get_firmware_version()) {
+		return 1;
+	}
+
+	/* Command Set SPI Speed */
+	if (pickit2_set_spi_speed(spispeed_idx)) {
+		return 1;
+	}
+
+	/* Command Set SPI Voltage */
+	if (pickit2_set_spi_voltage(millivolt)) {
+		return 1;
+	}
+
+	/* Perform basic setup */
+	/* Configure pins for correct directions and logic levels,
+	 * turn Vdd on, turn busy LED on and clear buffers
+	 */
+	ret = usb_interrupt_write(pickit2_handle, ENDPOINT_OUT, (char *)buf, CMD_LENGTH, DEFAULT_TIMEOUT);
+
+	if (ret != CMD_LENGTH) {
+		msg_perr("Command Setup failed (%s)!\n",
+			  usb_strerror());
+		return 1;
+	}
+
+	register_spi_programmer(&spi_programmer_pickit2);
+
+	return 0;
+}
Index: programmer.h
===================================================================
--- programmer.h	(revision 1817)
+++ programmer.h	(working copy)
@@ -96,6 +96,9 @@
 #if CONFIG_USBBLASTER_SPI == 1
 	PROGRAMMER_USBBLASTER_SPI,
 #endif
+#if CONFIG_PICKIT2_SPI == 1
+	PROGRAMMER_PICKIT2_SPI,
+#endif
 	PROGRAMMER_INVALID /* This must always be the last entry. */
 };
 
@@ -464,6 +467,11 @@
 extern const struct dev_entry devs_usbblasterspi[];
 #endif
 
+/* pickit2_spi.c */
+#if CONFIG_PICKIT2_SPI == 1
+int pickit2_spi_init(void);
+#endif
+
 /* rayer_spi.c */
 #if CONFIG_RAYER_SPI == 1
 int rayer_spi_init(void);
@@ -546,6 +554,9 @@
 #if CONFIG_USBBLASTER_SPI == 1
 	SPI_CONTROLLER_USBBLASTER,
 #endif
+#if CONFIG_PICKIT2_SPI == 1
+	SPI_CONTROLLER_PICKIT2,
+#endif
 };
 
 #define MAX_DATA_UNSPECIFIED 0


More information about the flashrom mailing list