summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>2010-11-16 21:25:29 +0000
committerCarl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>2010-11-16 21:25:29 +0000
commit482e97443dac5158b6bf48af1b7636a9388debf6 (patch)
treeb61604ec05b3e13148c88a5800d373bec63c3489
parentd836941f9ee5c207d59baf897153be0010ce361c (diff)
downloadast2050-flashrom-482e97443dac5158b6bf48af1b7636a9388debf6.zip
ast2050-flashrom-482e97443dac5158b6bf48af1b7636a9388debf6.tar.gz
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>
-rw-r--r--dediprog.c115
1 files changed, 109 insertions, 6 deletions
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 @@ static int dediprog_set_spi_speed(uint16_t speed)
}
#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 @@ int dediprog_init(void)
struct usb_device *dev;
char *voltage;
int millivolt = 3500;
+ int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +455,23 @@ int dediprog_init(void)
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 @@ int dediprog_shutdown(void)
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;
OpenPOWER on IntegriCloud