summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--buspirate_spi.c199
1 files changed, 134 insertions, 65 deletions
diff --git a/buspirate_spi.c b/buspirate_spi.c
index a488fc3..d00277e 100644
--- a/buspirate_spi.c
+++ b/buspirate_spi.c
@@ -84,7 +84,8 @@ static int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt,
msg_perr("Zero length command!\n");
return 1;
}
- msg_pspew("Sending");
+ if (writecnt)
+ msg_pspew("Sending");
for (i = 0; i < writecnt; i++)
msg_pspew(" 0x%02x", buf[i]);
#ifdef FAKE_COMMUNICATION
@@ -104,18 +105,31 @@ static int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt,
if (ret)
return ret;
#endif
- msg_pspew(", receiving");
+ if (readcnt)
+ msg_pspew(", receiving");
for (i = 0; i < readcnt; i++)
msg_pspew(" 0x%02x", buf[i]);
msg_pspew("\n");
return 0;
}
-static int buspirate_spi_send_command(struct flashctx *flash,
- unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr);
+static int buspirate_wait_for_string(unsigned char *buf, char *key)
+{
+ unsigned int keylen = strlen(key);
+ int ret;
+
+ ret = buspirate_sendrecv(buf, 0, keylen);
+ while (!ret) {
+ if (!memcmp(buf, key, keylen))
+ return 0;
+ memmove(buf, buf + 1, keylen - 1);
+ ret = buspirate_sendrecv(buf + keylen - 1, 0, 1);
+ }
+ return ret;
+}
+
+static int buspirate_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr);
static const struct spi_programmer spi_programmer_buspirate = {
.type = SPI_CONTROLLER_BUSPIRATE,
@@ -147,17 +161,15 @@ static int buspirate_spi_shutdown(void *data)
/* Exit raw SPI mode (enter raw bitbang mode) */
bp_commbuf[0] = 0x00;
- ret = buspirate_sendrecv(bp_commbuf, 1, 5);
- if (ret)
+ if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
goto out_shutdown;
- if (memcmp(bp_commbuf, "BBIO", 4)) {
- msg_perr("Entering raw bitbang mode failed!\n");
- ret = 1;
+ if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
goto out_shutdown;
- }
- msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[4]);
- if (bp_commbuf[4] != '1') {
- msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[4]);
+ if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
+ goto out_shutdown;
+ msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[0]);
+ if (bp_commbuf[0] != '1') {
+ msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[0]);
ret = 1;
goto out_shutdown;
}
@@ -182,18 +194,26 @@ out_shutdown:
return ret;
}
+#define BP_FWVERSION(a,b) ((a) << 8 | (b))
+
int buspirate_spi_init(void)
{
char *dev = NULL;
char *speed = NULL;
+ char *tmp;
+ unsigned int fw_version_major = 0;
+ unsigned int fw_version_minor = 0;
int spispeed = 0x7;
int ret = 0;
int i;
dev = extract_programmer_param("dev");
- if (!dev || !strlen(dev)) {
- msg_perr("No serial device given. Use flashrom -p "
- "buspirate_spi:dev=/dev/ttyUSB0\n");
+ if (dev && !strlen(dev)) {
+ free(dev);
+ dev = NULL;
+ }
+ if (!dev) {
+ msg_perr("No serial device given. Use flashrom -p buspirate_spi:dev=/dev/ttyUSB0\n");
return 1;
}
@@ -210,9 +230,6 @@ int buspirate_spi_init(void)
}
free(speed);
- /* This works because speeds numbering starts at 0 and is contiguous. */
- msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed].name);
-
/* Default buffer size is 19: 16 bytes data, 3 bytes control. */
#define DEFAULT_BUFSIZE (16 + 3)
bp_commbuf = malloc(DEFAULT_BUFSIZE);
@@ -236,64 +253,116 @@ int buspirate_spi_init(void)
return 1;
/* This is the brute force version, but it should work. */
- for (i = 0; i < 19; i++) {
+ for (i = 0; i < 20; i++) {
/* Enter raw bitbang mode */
bp_commbuf[0] = 0x00;
/* Send the command, don't read the response. */
ret = buspirate_sendrecv(bp_commbuf, 1, 0);
if (ret)
return ret;
- /* Read any response and discard it. */
- sp_flush_incoming();
+ /* The old way to handle responses from a Bus Pirate already in BBIO mode was to flush any
+ * response which came in over serial. Unfortunately that does not work reliably on Linux
+ * with FTDI USB-serial.
+ */
+ //sp_flush_incoming();
+ /* The Bus Pirate can't handle UART input buffer overflow in BBIO mode, and sending a sequence
+ * of 0x00 too fast apparently triggers such an UART input buffer overflow.
+ */
+ usleep(10000);
+ }
+ /* We know that 20 commands of \0 should elicit at least one BBIO1 response. */
+ if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
+ return ret;
+
+ /* Reset the Bus Pirate. */
+ bp_commbuf[0] = 0x0f;
+ /* Send the command, don't read the response. */
+ if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
+ return ret;
+ if ((ret = buspirate_wait_for_string(bp_commbuf, "irate ")))
+ return ret;
+ /* Read the hardware version string. Last byte of the buffer is reserved for \0. */
+ for (i = 0; i < DEFAULT_BUFSIZE - 1; i++) {
+ if ((ret = buspirate_sendrecv(bp_commbuf + i, 0, 1)))
+ return ret;
+ if (strchr("\r\n\t ", bp_commbuf[i]))
+ break;
}
- /* USB is slow. The Bus Pirate is even slower. Apparently the flush
- * action above is too fast or too early. Some stuff still remains in
- * the pipe after the flush above, and one additional flush is not
- * sufficient either. Use a 1.5 ms delay inside the loop to make
- * mostly sure that at least one USB frame had time to arrive.
- * Looping only 5 times is not sufficient and causes the
- * occasional failure.
- * Folding the delay into the loop above is not reliable either.
- */
- for (i = 0; i < 10; i++) {
- usleep(1500);
- /* Read any response and discard it. */
- sp_flush_incoming();
+ bp_commbuf[i] = '\0';
+ msg_pdbg("Detected Bus Pirate hardware %s\n", bp_commbuf);
+
+ if ((ret = buspirate_wait_for_string(bp_commbuf, "irmware ")))
+ return ret;
+ /* Read the firmware version string. Last byte of the buffer is reserved for \0. */
+ for (i = 0; i < DEFAULT_BUFSIZE - 1; i++) {
+ if ((ret = buspirate_sendrecv(bp_commbuf + i, 0, 1)))
+ return ret;
+ if (strchr("\r\n\t ", bp_commbuf[i]))
+ break;
}
- /* Enter raw bitbang mode */
- bp_commbuf[0] = 0x00;
- ret = buspirate_sendrecv(bp_commbuf, 1, 5);
- if (ret)
+ bp_commbuf[i] = '\0';
+ msg_pdbg("Detected Bus Pirate firmware ");
+ if (bp_commbuf[0] != 'v')
+ msg_pdbg("(unknown version number format)");
+ else if (!strchr("0123456789", bp_commbuf[1]))
+ msg_pdbg("(unknown version number format)");
+ else {
+ fw_version_major = strtoul((char *)bp_commbuf + 1, &tmp, 10);
+ while ((*tmp != '\0') && !strchr("0123456789", *tmp))
+ tmp++;
+ fw_version_minor = strtoul(tmp, NULL, 10);
+ msg_pdbg("%u.%u", fw_version_major, fw_version_minor);
+ }
+ msg_pdbg2(" (\"%s\")", bp_commbuf);
+ msg_pdbg("\n");
+
+ if ((ret = buspirate_wait_for_string(bp_commbuf, "HiZ>")))
return ret;
- if (memcmp(bp_commbuf, "BBIO", 4)) {
- msg_perr("Entering raw bitbang mode failed!\n");
- msg_pdbg("Got %02x%02x%02x%02x%02x\n",
- bp_commbuf[0], bp_commbuf[1], bp_commbuf[2],
- bp_commbuf[3], bp_commbuf[4]);
- return 1;
+
+ /* Tell the user about missing SPI binary mode in firmware 2.3 and older. */
+ if (BP_FWVERSION(fw_version_major, fw_version_minor) < BP_FWVERSION(2, 4)) {
+ msg_pinfo("Bus Pirate firmware 2.3 and older does not support binary SPI access.\n");
+ msg_pinfo("Please upgrade to the latest firmware (at least 2.4).\n");
+ return SPI_PROGRAMMER_ERROR;
+ }
+
+ /* Workaround for broken speed settings in firmware 6.1 and older. */
+ if (BP_FWVERSION(fw_version_major, fw_version_minor) < BP_FWVERSION(6, 2))
+ if (spispeed > 0x4) {
+ msg_perr("Bus Pirate firmware 6.1 and older does not support SPI speeds above 2 MHz. "
+ "Limiting speed to 2 MHz.\n");
+ msg_pinfo("It is recommended to upgrade to firmware 6.2 or newer.\n");
+ spispeed = 0x4;
+ }
+
+ /* This works because speeds numbering starts at 0 and is contiguous. */
+ msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed].name);
+
+ /* Enter raw bitbang mode */
+ for (i = 0; i < 20; i++) {
+ bp_commbuf[0] = 0x00;
+ if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
+ return ret;
}
- msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[4]);
- if (bp_commbuf[4] != '1') {
- msg_perr("Can't handle raw bitbang mode version %c!\n",
- bp_commbuf[4]);
+ if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
+ return ret;
+ if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
+ return ret;
+ msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[0]);
+ if (bp_commbuf[0] != '1') {
+ msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[0]);
return 1;
}
/* Enter raw SPI mode */
bp_commbuf[0] = 0x01;
- ret = buspirate_sendrecv(bp_commbuf, 1, 4);
- if (ret)
+ ret = buspirate_sendrecv(bp_commbuf, 1, 0);
+ if ((ret = buspirate_wait_for_string(bp_commbuf, "SPI")))
return ret;
- if (memcmp(bp_commbuf, "SPI", 3)) {
- msg_perr("Entering raw SPI mode failed!\n");
- msg_pdbg("Got %02x%02x%02x%02x\n",
- bp_commbuf[0], bp_commbuf[1], bp_commbuf[2],
- bp_commbuf[3]);
- return 1;
- }
- msg_pdbg("Raw SPI mode version %c\n", bp_commbuf[3]);
- if (bp_commbuf[3] != '1') {
- msg_perr("Can't handle raw SPI mode version %c!\n",
- bp_commbuf[3]);
+ if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
+ return ret;
+ msg_pdbg("Raw SPI mode version %c\n", bp_commbuf[0]);
+ if (bp_commbuf[0] != '1') {
+ msg_perr("Can't handle raw SPI mode version %c!\n", bp_commbuf[0]);
return 1;
}
OpenPOWER on IntegriCloud