===================================================================
@@ -22,6 +22,7 @@
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
+#include <unistd.h>
#include "flash.h"
#include "chipdrivers.h"
#include "programmer.h"
@@ -45,6 +46,8 @@
#define sp_flush_incoming(...) 0
#endif
+static int buspirate_interface_version;
+
static int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt)
{
int i, ret = 0;
@@ -130,7 +133,13 @@
return ret;
free(dev);
- /* This is the brute force version, but it should work. */
+ /* This is the brute force version, but it should work.
+ * It is guaranteed to fail if a previous flashrom run was aborted
+ * during a write with the new SPI commands in firmware v4.6 because
+ * that firmware may wait for up to 4096 bytes of input before
+ * responding to 0x00 again. The obvious workaround may cause startup
+ * penalties of more than one second.
+ */
for (i = 0; i < 19; i++) {
/* Enter raw bitbang mode */
buf[0] = 0x00;
@@ -141,6 +150,20 @@
/* Read any response and discard it. */
sp_flush_incoming();
}
+ /* 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
+ * ocassional 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 */
buf[0] = 0x00;
ret = buspirate_sendrecv(buf, 1, 5);
@@ -148,6 +171,8 @@
return ret;
if (memcmp(buf, "BBIO", 4)) {
msg_perr("Entering raw bitbang mode failed!\n");
+ msg_pdbg("Got %02x%02x%02x%02x%02x\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4]);
return 1;
}
msg_pdbg("Raw bitbang mode version %c\n", buf[4]);
@@ -159,8 +184,12 @@
/* Enter raw SPI mode */
buf[0] = 0x01;
ret = buspirate_sendrecv(buf, 1, 4);
+ if (ret)
+ return ret;
if (memcmp(buf, "SPI", 3)) {
msg_perr("Entering raw SPI mode failed!\n");
+ msg_pdbg("Got %02x%02x%02x%02x\n",
+ buf[0], buf[1], buf[2], buf[3]);
return 1;
}
msg_pdbg("Raw SPI mode version %c\n", buf[3]);
@@ -210,6 +239,34 @@
return 1;
}
+ /* Test combined SPI write/read, length 0. */
+ buf[0] = 0x04;
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+ buf[4] = 0;
+ ret = buspirate_sendrecv(buf, 5, 1);
+ if (ret)
+ return 1;
+ if (buf[0] != 0x01) {
+ msg_pdbg("SPI command set v2 not available, using old commands "
+ "present in firmware vX.Y or later\n");
+
+ /* FIXME: Check the error code? */
+ /* We sent 4 bytes of 0x00, so we expect 4 BBIO1 responses. */
+ buspirate_sendrecv(buf, 0, 4 * 5);
+
+ /* Enter raw SPI mode again. */
+ buf[0] = 0x01;
+ /* FIXME: Check the error code? */
+ buspirate_sendrecv(buf, 1, 4);
+
+ buspirate_interface_version = 1;
+ } else {
+ msg_pdbg("Using SPI command set v2.\n");
+ buspirate_interface_version = 2;
+ }
+
buses_supported = CHIP_BUSTYPE_SPI;
spi_controller = SPI_CONTROLLER_BUSPIRATE;
@@ -251,12 +308,56 @@
return 0;
}
-int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+int buspirate_spi_send_command_v2(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr)
{
static unsigned char *buf = NULL;
int i = 0, ret = 0;
+ if (writecnt > 4096 || readcnt > 4096 || (readcnt + writecnt) > 4096)
+ return SPI_INVALID_LENGTH;
+
+ /* 5 bytes extra for command, writelen, readlen.
+ * 1 byte extra for Ack/Nack.
+ */
+ buf = realloc(buf, max(writecnt + 5, readcnt + 1));
+ if (!buf) {
+ msg_perr("Out of memory!\n");
+ exit(1); // -1
+ }
+
+ /* Combined SPI write/read. */
+ buf[i++] = 0x04;
+ buf[i++] = (writecnt >> 8) & 0xff;
+ buf[i++] = writecnt & 0xff;
+ buf[i++] = (readcnt >> 8) & 0xff;
+ buf[i++] = readcnt & 0xff;
+ memcpy(buf + i, writearr, writecnt);
+
+ ret = buspirate_sendrecv(buf, i + writecnt, 1 + readcnt);
+
+ if (ret) {
+ msg_perr("Bus Pirate communication error!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ if (buf[0] != 0x01) {
+ msg_perr("Protocol error while sending SPI write/read!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ /* Skip Ack. */
+ memcpy(readarr, buf + 1, readcnt);
+
+ return ret;
+}
+
+int buspirate_spi_send_command_v1(unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
+{
+ static unsigned char *buf = NULL;
+ int i = 0, ret = 0;
+
if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
return SPI_INVALID_LENGTH;
@@ -307,6 +408,17 @@
return ret;
}
+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
+{
+ switch (buspirate_interface_version) {
+ case 2:
+ return buspirate_spi_send_command_v2(writecnt, readcnt, writearr, readarr);
+ default:
+ return buspirate_spi_send_command_v1(writecnt, readcnt, writearr, readarr);
+ }
+}
+
int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
{
return spi_read_chunked(flash, buf, start, len, 12);
===================================================================
@@ -200,8 +200,10 @@
#else
tmp = write(sp_fd, buf, writecnt);
#endif
- if (tmp == -1)
+ if (tmp == -1) {
+ msg_perr("Serial port write error!\n");
return 1;
+ }
if (!tmp)
msg_pdbg("Empty write\n");
writecnt -= tmp;
@@ -221,8 +223,10 @@
#else
tmp = read(sp_fd, buf, readcnt);
#endif
- if (tmp == -1)
+ if (tmp == -1) {
+ msg_perr("Serial port read error!\n");
return 1;
+ }
if (!tmp)
msg_pdbg("Empty read\n");
readcnt -= tmp;