Support bulk read on Dediprog SF100
Should result in native speed for plain read and erase.
Should result in a measurable speedup for writes due to a fast verify.
Packet size is 512 bytes. Depending on your USB hardware and the
Dediprog firmware version, this may not work at all. That said, it
worked on the hardware we tested.
Add lots of error checking where it was missing before.
Thanks to Richard A. Smith, Mathias Krause and David Hendricks for
testing multiple iterations of this patch.
Corresponding to flashrom svn r1234.
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Richard A. Smith <richard@laptop.org>
Acked-by: Mathias Krause <mathias.krause@secunet.com>
diff --git a/dediprog.c b/dediprog.c
index a7a1988..a6db17c 100644
--- a/dediprog.c
+++ b/dediprog.c
@@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000
static usb_dev_handle *dediprog_handle;
+static int dediprog_endpoint;
#if 0
/* Might be useful for other pieces of code as well. */
@@ -148,11 +149,93 @@
}
#endif
+/* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes.
+ * @start start address
+ * @len length
+ * @return 0 on success, 1 on failure
+ */
+static int dediprog_spi_bulk_read(struct flashchip *flash, uint8_t *buf,
+ int start, int len)
+{
+ int ret;
+ int i;
+ /* chunksize must be 512, other sizes will NOT work at all. */
+ const int chunksize = 0x200;
+ const int count = len / chunksize;
+ const char count_and_chunk[] = {count & 0xff,
+ (count >> 8) & 0xff,
+ chunksize & 0xff,
+ (chunksize >> 8) & 0xff};
+
+ if ((start % chunksize) || (len % chunksize)) {
+ msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug "
+ "at flashrom@flashrom.org\n", __func__, start, len);
+ return 1;
+ }
+
+ /* No idea if the hardware can handle empty reads, so chicken out. */
+ if (!len)
+ return 0;
+ /* Command Read SPI Bulk. No idea which read command is used on the
+ * SPI side.
+ */
+ ret = usb_control_msg(dediprog_handle, 0x42, 0x20, start % 0x10000,
+ start / 0x10000, (char *)count_and_chunk,
+ sizeof(count_and_chunk), DEFAULT_TIMEOUT);
+ if (ret != sizeof(count_and_chunk)) {
+ msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret,
+ usb_strerror());
+ return 1;
+ }
+
+ for (i = 0; i < count; i++) {
+ ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint,
+ (char *)buf + i * chunksize, chunksize,
+ DEFAULT_TIMEOUT);
+ if (ret != chunksize) {
+ msg_perr("SPI bulk read %i failed, expected %i, got %i "
+ "%s!\n", i, chunksize, ret, usb_strerror());
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
{
- msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len);
- /* Chosen read length is 16 bytes for now. */
- return spi_read_chunked(flash, buf, start, len, 16);
+ int ret;
+ /* chunksize must be 512, other sizes will NOT work at all. */
+ const int chunksize = 0x200;
+ int residue = start % chunksize ? chunksize - start % chunksize : 0;
+ int bulklen;
+
+ if (residue) {
+ msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n",
+ start, residue);
+ ret = spi_read_chunked(flash, buf, start, residue, 16);
+ if (ret)
+ return ret;
+ }
+
+ /* Round down. */
+ bulklen = (len - residue) / chunksize * chunksize;
+ ret = dediprog_spi_bulk_read(flash, buf + residue, start + residue,
+ bulklen);
+ if (ret)
+ return ret;
+
+ len -= residue + bulklen;
+ if (len) {
+ msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n",
+ start, len);
+ ret = spi_read_chunked(flash, buf + residue + bulklen,
+ start + residue + bulklen, len, 16);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt,
@@ -345,6 +428,7 @@
struct usb_device *dev;
char *voltage;
int millivolt = 3500;
+ int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +455,23 @@
dev->descriptor.idVendor,
dev->descriptor.idProduct);
dediprog_handle = usb_open(dev);
- usb_set_configuration(dediprog_handle, 1);
- usb_claim_interface(dediprog_handle, 0);
+ ret = usb_set_configuration(dediprog_handle, 1);
+ if (ret < 0) {
+ msg_perr("Could not set USB device configuration: %i %s\n",
+ ret, usb_strerror());
+ if (usb_close(dediprog_handle))
+ msg_perr("Could not close USB device!\n");
+ return 1;
+ }
+ ret = usb_claim_interface(dediprog_handle, 0);
+ if (ret < 0) {
+ msg_perr("Could not claim USB device interface %i: %i %s\n",
+ 0, ret, usb_strerror());
+ if (usb_close(dediprog_handle))
+ msg_perr("Could not close USB device!\n");
+ return 1;
+ }
+ dediprog_endpoint = 2;
/* URB 6. Command A. */
if (dediprog_command_a())
return 1;
@@ -461,8 +560,12 @@
if (dediprog_set_spi_voltage(0x0))
return 1;
+ if (usb_release_interface(dediprog_handle, 0)) {
+ msg_perr("Could not release USB interface!\n");
+ return 1;
+ }
if (usb_close(dediprog_handle)) {
- msg_perr("Couldn't close USB device!\n");
+ msg_perr("Could not close USB device!\n");
return 1;
}
return 0;