Bus Pirate init cleanup and fixes
The Bus Pirate firmware (at least v6.1 and earlier) 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. Wait 10 ms
after sending each 0x00 byte during init to give the Bus Pirate enough
time to handle the input. This fixes a Bus Pirate hang if the previous
flashrom run was aborted by the user.
The Bus Pirate firmware v6.1 and earlier use the wrong (too slow) SPI
speed if more than 2 MHz are requested. Automatically downgrade SPI
speed to 2 MHz for affected firmware versions.
Detect Bus Pirate hardware and firmware versions to allow quirk
handling.
The Bus Pirate init sequence has lots of open-coded sequences which wait
for a given string on the serial line. Refactor them into
buspirate_wait_for_string().
Corresponding to flashrom svn r1576.
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
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 @@
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 @@
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 @@
/* 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 @@
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 @@
}
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 @@
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);
}
- /* 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();
- }
- /* Enter raw bitbang mode */
- bp_commbuf[0] = 0x00;
- ret = buspirate_sendrecv(bp_commbuf, 1, 5);
- if (ret)
+ /* 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;
- 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;
+
+ /* 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;
}
- 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]);
+ 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;
+ }
+ 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;
+
+ /* 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;
+ }
+ 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;
}