1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-26 22:52:34 +02:00

Speed up dediprog SPI page writes

All chips which use spi_chip_write_256 should be written at native
speed. Chips using spi_chip_write_1 or spi_chip_write_aai will
still be slow.

Thanks to Steven A. Falco for testing with a ST/Numonyx M25P16.
Thanks to David Hendricks for testing with a Winbond W25Q64.

Corresponding to flashrom svn r1477.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Steven A. Falco <sfalco@coincident.com>
This commit is contained in:
Carl-Daniel Hailfinger 2011-12-20 01:54:19 +00:00
parent 33a65a0672
commit 64204b5745

View File

@ -299,22 +299,109 @@ static int dediprog_spi_read(struct flashctx *flash, uint8_t *buf,
return 0;
}
/* Bulk write interface, will read multiple page_size byte chunks aligned to page_size bytes.
* @start start address
* @len length
* @return 0 on success, 1 on failure
*/
static int dediprog_spi_bulk_write(struct flashctx *flash, uint8_t *buf,
unsigned int start, unsigned int len)
{
int ret;
unsigned int i;
/* USB transfer size must be 512, other sizes will NOT work at all.
* chunksize is the real data size per USB bulk transfer. The remaining
* space in a USB bulk transfer must be filled with 0xff padding.
*/
const unsigned int chunksize = flash->page_size;
const unsigned int count = len / chunksize;
const char count_and_chunk[] = {count & 0xff,
(count >> 8) & 0xff,
chunksize & 0xff,
(chunksize >> 8) & 0xff};
char usbbuf[512];
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 writes, so chicken out. */
if (!len)
return 0;
/* Command Write SPI Bulk. No idea which write command is used on the
* SPI side.
*/
ret = usb_control_msg(dediprog_handle, 0x42, 0x30, start % 0x10000,
start / 0x10000, (char *)count_and_chunk,
sizeof(count_and_chunk), DEFAULT_TIMEOUT);
if (ret != sizeof(count_and_chunk)) {
msg_perr("Command Write SPI Bulk failed, %i %s!\n", ret,
usb_strerror());
return 1;
}
for (i = 0; i < count; i++) {
memset(usbbuf, 0xff, sizeof(usbbuf));
memcpy(usbbuf, buf + i * chunksize, chunksize);
ret = usb_bulk_write(dediprog_handle, dediprog_endpoint,
usbbuf, 512,
DEFAULT_TIMEOUT);
if (ret != 512) {
msg_perr("SPI bulk write failed, expected %i, got %i "
"%s!\n", 512, ret, usb_strerror());
return 1;
}
}
return 0;
}
static int dediprog_spi_write_256(struct flashctx *flash, uint8_t *buf,
unsigned int start, unsigned int len)
{
int ret;
const unsigned int chunksize = flash->page_size;
unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0;
unsigned int bulklen;
dediprog_set_leds(PASS_OFF|BUSY_ON|ERROR_OFF);
/* No idea about the real limit. Maybe 12, maybe more, maybe less. */
ret = spi_write_chunked(flash, buf, start, len, 12);
if (residue) {
msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n",
start, residue);
/* No idea about the real limit. Maybe 12, maybe more. */
ret = spi_write_chunked(flash, buf, start, residue, 12);
if (ret) {
dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
return ret;
}
}
if (ret)
/* Round down. */
bulklen = (len - residue) / chunksize * chunksize;
ret = dediprog_spi_bulk_write(flash, buf + residue, start + residue,
bulklen);
if (ret) {
dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
else
dediprog_set_leds(PASS_ON|BUSY_OFF|ERROR_OFF);
return ret;
}
return ret;
len -= residue + bulklen;
if (len) {
msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n",
start, len);
ret = spi_write_chunked(flash, buf + residue + bulklen,
start + residue + bulklen, len, 12);
if (ret) {
dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
return ret;
}
}
dediprog_set_leds(PASS_ON|BUSY_OFF|ERROR_OFF);
return 0;
}
static int dediprog_spi_send_command(struct flashctx *flash,
@ -494,6 +581,76 @@ static int dediprog_command_f(int timeout)
}
return 0;
}
/* Start/stop blinking?
* Present in eng_detect_blink.log with firmware 3.1.8
* Preceded by Command J
*/
static int dediprog_command_g(void)
{
int ret;
ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x03, NULL, 0x0, DEFAULT_TIMEOUT);
if (ret != 0x0) {
msg_perr("Command G failed (%s)!\n", usb_strerror());
return 1;
}
return 0;
}
/* Something.
* Present in all logs with firmware 5.1.5
* Always preceded by Command Receive Device String
* Always followed by Command Set SPI Voltage nonzero
*/
static int dediprog_command_h(void)
{
int ret;
ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x05, NULL, 0x0, DEFAULT_TIMEOUT);
if (ret != 0x0) {
msg_perr("Command H failed (%s)!\n", usb_strerror());
return 1;
}
return 0;
}
/* Shutdown for firmware 5.x?
* Present in all logs with firmware 5.1.5
* Often preceded by a SPI operation (Command Read SPI Bulk or Receive SPI)
* Always followed by Command Set SPI Voltage 0x0000
*/
static int dediprog_command_i(void)
{
int ret;
ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x06, NULL, 0x0, DEFAULT_TIMEOUT);
if (ret != 0x0) {
msg_perr("Command I failed (%s)!\n", usb_strerror());
return 1;
}
return 0;
}
/* Start/stop blinking?
* Present in all logs with firmware 5.1.5
* Always preceded by Command Receive Device String on 5.1.5
* Always followed by Command Set SPI Voltage nonzero on 5.1.5
* Present in eng_detect_blink.log with firmware 3.1.8
* Preceded by Command B in eng_detect_blink.log
* Followed by Command G in eng_detect_blink.log
*/
static int dediprog_command_j(void)
{
int ret;
ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x07, NULL, 0x0, DEFAULT_TIMEOUT);
if (ret != 0x0) {
msg_perr("Command J failed (%s)!\n", usb_strerror());
return 1;
}
return 0;
}
#endif
static int parse_voltage(char *voltage)
@ -558,6 +715,13 @@ static int dediprog_shutdown(void *data)
{
msg_pspew("%s\n", __func__);
#if 0
/* Shutdown on firmware 5.x */
if (dediprog_firmwareversion == 5)
if (dediprog_command_i())
return 1;
#endif
/* URB 28. Command Set SPI Voltage to 0. */
if (dediprog_set_spi_voltage(0x0))
return 1;