This is a combination of two patches.
Patch 1:
Thanks to Johannes Sjölund for reporting that the Bus Pirate init could not deal with a Bus Pirate which is already in binary Bitbang mode. This is caused by a combination of the slowness of the Bus Pirate, the slowness of USB and a fast serial port flush routine which just flushes the buffer contents and does not wait until data arrival stops.
Make the Bus Pirate init more robust by running the flush command 10 times with 1.5 ms delay in between.
This code development was sponsored by Mattias Mattsson. Thanks! Tested a few dozen times, should work reliably.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Patch 2: Thanks to Ian Lesnet for adding a new SPI mode to the Bus Pirate which is specifically designed for flashrom. It has the potential to speed up reads and writes a lot. This patch implements flashrom support for the new SPI mode in a hopefully backward compatible way.
Not for merge. The Bus Pirate interface has not been finalized yet, and this patch should help testing if the interface works as designed. No significant speedups expected yet because the code still uses the old small block sizes.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-buspirate_newcommands/buspirate_spi.c =================================================================== --- flashrom-buspirate_newcommands/buspirate_spi.c (Revision 1130) +++ flashrom-buspirate_newcommands/buspirate_spi.c (Arbeitskopie) @@ -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); Index: flashrom-buspirate_newcommands/serial.c =================================================================== --- flashrom-buspirate_newcommands/serial.c (Revision 1130) +++ flashrom-buspirate_newcommands/serial.c (Arbeitskopie) @@ -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;