Convert SPI chips to partial write
However, wrap the write functions in a compat layer to allow converting
the rest of flashrom later. Tested on Intel NM10 by David Hendricks.
Corresponding to flashrom svn r1080.
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
diff --git a/bitbang_spi.c b/bitbang_spi.c
index f60a7e1..adb1038 100644
--- a/bitbang_spi.c
+++ b/bitbang_spi.c
@@ -139,10 +139,8 @@
return spi_read_chunked(flash, buf, start, len, 64 * 1024);
}
-int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf)
+int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
{
- int total_size = 1024 * flash->total_size;
-
- msg_pdbg("total_size is %d\n", total_size);
- return spi_write_chunked(flash, buf, 0, total_size, 256);
+ spi_disable_blockprotect();
+ return spi_write_chunked(flash, buf, start, len, 256);
}
diff --git a/buspirate_spi.c b/buspirate_spi.c
index e0683ec..e93cf1a 100644
--- a/buspirate_spi.c
+++ b/buspirate_spi.c
@@ -309,18 +309,8 @@
return spi_read_chunked(flash, buf, start, len, 12);
}
-int buspirate_spi_write_256(struct flashchip *flash, uint8_t *buf)
+int buspirate_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
{
- int total_size = 1024 * flash->total_size;
-
spi_disable_blockprotect();
- /* Erase first. */
- msg_pinfo("Erasing flash before programming... ");
- if (erase_flash(flash)) {
- msg_perr("ERASE FAILED!\n");
- return -1;
- }
- msg_pinfo("done.\n");
-
- return spi_write_chunked(flash, buf, 0, total_size, 12);
+ return spi_write_chunked(flash, buf, start, len, 12);
}
diff --git a/chipdrivers.h b/chipdrivers.h
index aeee095..ca3b190 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -43,6 +43,8 @@
int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen);
int spi_chip_write_1(struct flashchip *flash, uint8_t *buf);
int spi_chip_write_256(struct flashchip *flash, uint8_t *buf);
+int spi_chip_write_1_new(struct flashchip *flash, uint8_t *buf, int start, int len);
+int spi_chip_write_256_new(struct flashchip *flash, uint8_t *buf, int start, int len);
int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
uint8_t spi_read_status_register(void);
int spi_disable_blockprotect(void);
@@ -51,7 +53,7 @@
int spi_nbyte_read(int addr, uint8_t *bytes, int len);
int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize);
int spi_write_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize);
-int spi_aai_write(struct flashchip *flash, uint8_t *buf);
+int spi_aai_write(struct flashchip *flash, uint8_t *buf, int start, int len);
/* 82802ab.c */
uint8_t wait_82802ab(chipaddr bios);
diff --git a/dummyflasher.c b/dummyflasher.c
index 5f88fc4..479a938 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -167,3 +167,12 @@
return spi_read_chunked(flash, buf, start, len, 64 * 1024);
}
+/* Is is impossible to trigger this code path because dummyflasher probing will
+ * never be successful, and the current frontend refuses to write in that case.
+ * Other frontends may allow writing even for non-detected chips, though.
+ */
+int dummy_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+ spi_disable_blockprotect();
+ return spi_write_chunked(flash, buf, start, len, 256);
+}
diff --git a/flash.h b/flash.h
index cd7cb46..1b82d42 100644
--- a/flash.h
+++ b/flash.h
@@ -456,6 +456,7 @@
int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
int dummy_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
+int dummy_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
#endif
/* nic3com.c */
@@ -529,7 +530,7 @@
int ft2232_spi_init(void);
int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf);
+int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
/* bitbang_spi.c */
extern int bitbang_spi_half_period;
@@ -537,7 +538,7 @@
int bitbang_spi_init(void);
int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf);
+int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
/* buspirate_spi.c */
struct buspirate_spispeeds {
@@ -548,7 +549,7 @@
int buspirate_spi_shutdown(void);
int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int buspirate_spi_write_256(struct flashchip *flash, uint8_t *buf);
+int buspirate_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
/* dediprog.c */
int dediprog_init(void);
@@ -668,7 +669,7 @@
/* Optimized functions for this programmer */
int (*read)(struct flashchip *flash, uint8_t *buf, int start, int len);
- int (*write_256)(struct flashchip *flash, uint8_t *buf);
+ int (*write_256)(struct flashchip *flash, uint8_t *buf, int start, int len);
};
extern enum spi_controller spi_controller;
@@ -689,7 +690,7 @@
int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
int ich_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int ich_spi_write_256(struct flashchip *flash, uint8_t * buf);
+int ich_spi_write_256(struct flashchip *flash, uint8_t * buf, int start, int len);
int ich_spi_send_multicommand(struct spi_command *cmds);
/* it87spi.c */
@@ -701,13 +702,13 @@
int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf);
+int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
/* sb600spi.c */
int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf);
+int sb600_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len);
extern uint8_t *sb600_spibar;
/* wbsio_spi.c */
@@ -715,7 +716,7 @@
int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr);
int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
-int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf);
+int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf, int start, int len);
/* serprog.c */
int serprog_init(void);
diff --git a/flashchips.c b/flashchips.c
index 32caee0..5954eb2 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -1423,7 +1423,7 @@
.block_erase = spi_block_erase_c7,
}
},
- .write = spi_aai_write,
+ .write = spi_chip_write_1,
.read = spi_chip_read,
},
diff --git a/ft2232_spi.c b/ft2232_spi.c
index 1dd2e0c..ee8515f 100644
--- a/ft2232_spi.c
+++ b/ft2232_spi.c
@@ -288,20 +288,10 @@
return spi_read_chunked(flash, buf, start, len, 64 * 1024);
}
-int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf)
+int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
{
- int total_size = 1024 * flash->total_size;
-
spi_disable_blockprotect();
- /* Erase first. */
- msg_pinfo("Erasing flash before programming... ");
- if (erase_flash(flash)) {
- msg_perr("ERASE FAILED!\n");
- return -1;
- }
- msg_pinfo("done.\n");
- msg_pdbg("total_size is %d\n", total_size);
- return spi_write_chunked(flash, buf, 0, total_size, 256);
+ return spi_write_chunked(flash, buf, start, len, 256);
}
#endif
diff --git a/ichspi.c b/ichspi.c
index fead7e6..8fa3c29 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -683,36 +683,15 @@
return spi_read_chunked(flash, buf, start, len, maxdata);
}
-int ich_spi_write_256(struct flashchip *flash, uint8_t * buf)
+int ich_spi_write_256(struct flashchip *flash, uint8_t * buf, int start, int len)
{
- int i, ret = 0;
- int total_size = flash->total_size * 1024;
- int erase_size = 64 * 1024;
int maxdata = 64;
if (spi_controller == SPI_CONTROLLER_VIA)
maxdata = 16;
spi_disable_blockprotect();
- /* Erase first */
- msg_pinfo("Erasing flash before programming... ");
- if (erase_flash(flash)) {
- msg_perr("ERASE FAILED!\n");
- return -1;
- }
- msg_pinfo("done.\n");
-
- msg_pinfo("Programming page: \n");
- for (i = 0; i < total_size / erase_size; i++) {
- ret = spi_write_chunked(flash, buf + (i * erase_size),
- i * erase_size, erase_size, maxdata);
- if (ret)
- break;
- }
-
- msg_pinfo("\n");
-
- return ret;
+ return spi_write_chunked(flash, buf, start, len, maxdata);
}
int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
diff --git a/it87spi.c b/it87spi.c
index 3019729..69d10a6 100644
--- a/it87spi.c
+++ b/it87spi.c
@@ -292,7 +292,7 @@
}
/* Page size is usually 256 bytes */
-static int it8716f_spi_page_program(struct flashchip *flash, int block, uint8_t *buf)
+static int it8716f_spi_page_program(struct flashchip *flash, uint8_t *buf, int start)
{
int i;
int result;
@@ -305,7 +305,7 @@
OUTB(0x06, it8716f_flashport + 1);
OUTB(((2 + (fast_spi ? 1 : 0)) << 4), it8716f_flashport);
for (i = 0; i < 256; i++) {
- chip_writeb(buf[256 * block + i], bios + 256 * block + i);
+ chip_writeb(buf[i], bios + start + i);
}
OUTB(0, it8716f_flashport);
/* Wait until the Write-In-Progress bit is cleared.
@@ -334,29 +334,39 @@
return 0;
}
-int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
+int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
{
- int total_size = 1024 * flash->total_size;
- int i;
-
/*
* IT8716F only allows maximum of 512 kb SPI chip size for memory
* mapped access.
*/
- if ((programmer == PROGRAMMER_IT87SPI) || (total_size > 512 * 1024)) {
- spi_chip_write_1(flash, buf);
+ if ((programmer == PROGRAMMER_IT87SPI) || (flash->total_size * 1024 > 512 * 1024)) {
+ spi_chip_write_1_new(flash, buf, start, len);
} else {
+ int lenhere;
spi_disable_blockprotect();
- /* Erase first */
- msg_pinfo("Erasing flash before programming... ");
- if (erase_flash(flash)) {
- msg_perr("ERASE FAILED!\n");
- return -1;
+
+ if (start % 256) {
+ /* start to the end of the page or start + len,
+ * whichever is smaller. Page length is hardcoded to
+ * 256 bytes (IT87 SPI hardware limitation).
+ */
+ lenhere = min(len, (start | 0xff) - start + 1);
+ spi_chip_write_1_new(flash, buf, start, lenhere);
+ start += lenhere;
+ len -= lenhere;
+ buf += lenhere;
}
- msg_pinfo("done.\n");
- for (i = 0; i < total_size / 256; i++) {
- it8716f_spi_page_program(flash, i, buf);
+
+ /* FIXME: Handle chips which have max writechunk size >1 and <256. */
+ while (len >= 256) {
+ it8716f_spi_page_program(flash, buf, start);
+ start += 256;
+ len -= 256;
+ buf += 256;
}
+ if (len)
+ spi_chip_write_1_new(flash, buf, start, len);
}
return 0;
diff --git a/sb600spi.c b/sb600spi.c
index b44a585..72181d1 100644
--- a/sb600spi.c
+++ b/sb600spi.c
@@ -48,25 +48,10 @@
return spi_read_chunked(flash, buf, start, len, 8);
}
-/* FIXME: SB600 can write 5 bytes per transaction. */
-int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf)
+int sb600_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
{
- int total_size = flash->total_size * 1024;
- int result = 0;
-
spi_disable_blockprotect();
- /* Erase first */
- msg_pinfo("Erasing flash before programming... ");
- if (erase_flash(flash)) {
- msg_perr("ERASE FAILED!\n");
- return -1;
- }
- msg_pinfo("done.\n");
-
- msg_pinfo("Programming flash");
- result = spi_write_chunked(flash, buf, 0, total_size, 5);
- msg_pinfo(" done.\n");
- return result;
+ return spi_write_chunked(flash, buf, start, len, 5);
}
static void reset_internal_fifo_pointer(void)
diff --git a/spi.c b/spi.c
index ea64882..94dbe9e 100644
--- a/spi.c
+++ b/spi.c
@@ -66,7 +66,7 @@
.command = sb600_spi_send_command,
.multicommand = default_spi_send_multicommand,
.read = sb600_spi_read,
- .write_256 = sb600_spi_write_1,
+ .write_256 = sb600_spi_write_256,
},
{ /* SPI_CONTROLLER_VIA */
@@ -99,7 +99,7 @@
.command = dummy_spi_send_command,
.multicommand = default_spi_send_multicommand,
.read = dummy_spi_read,
- .write_256 = NULL,
+ .write_256 = dummy_spi_write_256,
},
#endif
@@ -117,7 +117,7 @@
.command = dediprog_spi_send_command,
.multicommand = default_spi_send_multicommand,
.read = dediprog_spi_read,
- .write_256 = spi_chip_write_1,
+ .write_256 = spi_chip_write_1_new,
},
#endif
@@ -196,8 +196,11 @@
/*
* Program chip using page (256 bytes) programming.
* Some SPI masters can't do this, they use single byte programming instead.
+ * The redirect to single byte programming is achieved by setting
+ * .write_256 = spi_chip_write_1
*/
-int spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
+/* real chunksize is up to 256, logical chunksize is 256 */
+int spi_chip_write_256_new(struct flashchip *flash, uint8_t *buf, int start, int len)
{
if (!spi_programmer[spi_controller].write_256) {
msg_perr("%s called, but SPI page write is unsupported on this "
@@ -206,7 +209,28 @@
return 1;
}
- return spi_programmer[spi_controller].write_256(flash, buf);
+ return spi_programmer[spi_controller].write_256(flash, buf, start, len);
+}
+
+/* Wrapper function until the generic code is converted to partial writes. */
+int spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
+{
+ int ret;
+
+ spi_disable_blockprotect();
+ msg_pinfo("Erasing flash before programming... ");
+ if (erase_flash(flash)) {
+ msg_perr("ERASE FAILED!\n");
+ return -1;
+ }
+ msg_pinfo("done.\n");
+ msg_pinfo("Programming flash... ");
+ ret = spi_chip_write_256_new(flash, buf, 0, flash->total_size * 1024);
+ if (!ret)
+ msg_pinfo("done.\n");
+ else
+ msg_pinfo("\n");
+ return ret;
}
/*
diff --git a/spi25.c b/spi25.c
index 51be397..fa76531 100644
--- a/spi25.c
+++ b/spi25.c
@@ -874,6 +874,7 @@
/*
* Read a part of the flash chip.
+ * FIXME: Use the chunk code from Michael Karcher instead.
* Each page is read separately in chunks with a maximum size of chunksize.
*/
int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize)
@@ -913,6 +914,7 @@
/*
* Write a part of the flash chip.
+ * FIXME: Use the chunk code from Michael Karcher instead.
* Each page is written separately in chunks with a maximum size of chunksize.
*/
int spi_write_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize)
@@ -963,20 +965,13 @@
* and for chips where memory mapped programming is impossible
* (e.g. due to size constraints in IT87* for over 512 kB)
*/
-int spi_chip_write_1(struct flashchip *flash, uint8_t *buf)
+/* real chunksize is 1, logical chunksize is 1 */
+int spi_chip_write_1_new(struct flashchip *flash, uint8_t *buf, int start, int len)
{
- int total_size = 1024 * flash->total_size;
int i, result = 0;
spi_disable_blockprotect();
- /* Erase first */
- msg_cinfo("Erasing flash before programming... ");
- if (erase_flash(flash)) {
- msg_cerr("ERASE FAILED!\n");
- return -1;
- }
- msg_cinfo("done.\n");
- for (i = 0; i < total_size; i++) {
+ for (i = start; i < start + len; i++) {
result = spi_byte_program(i, buf[i]);
if (result)
return 1;
@@ -987,11 +982,23 @@
return 0;
}
-int spi_aai_write(struct flashchip *flash, uint8_t *buf)
+int spi_chip_write_1(struct flashchip *flash, uint8_t *buf)
{
- uint32_t addr = 0;
- uint32_t len = flash->total_size * 1024;
- uint32_t pos = addr;
+ spi_disable_blockprotect();
+ /* Erase first */
+ msg_cinfo("Erasing flash before programming... ");
+ if (erase_flash(flash)) {
+ msg_cerr("ERASE FAILED!\n");
+ return -1;
+ }
+ msg_cinfo("done.\n");
+
+ return spi_chip_write_1_new(flash, buf, 0, flash->total_size * 1024);
+}
+
+int spi_aai_write(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+ uint32_t pos = start;
int result;
unsigned char cmd[JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE] = {
JEDEC_AAI_WORD_PROGRAM,
@@ -1006,9 +1013,9 @@
.writecnt = JEDEC_AAI_WORD_PROGRAM_OUTSIZE,
.writearr = (const unsigned char[]){
JEDEC_AAI_WORD_PROGRAM,
- (pos >> 16) & 0xff,
- (pos >> 8) & 0xff,
- (pos & 0xff),
+ (start >> 16) & 0xff,
+ (start >> 8) & 0xff,
+ (start & 0xff),
buf[0],
buf[1]
},
@@ -1026,17 +1033,21 @@
#if defined(__i386__) || defined(__x86_64__)
case SPI_CONTROLLER_IT87XX:
case SPI_CONTROLLER_WBSIO:
- msg_cerr("%s: impossible with this SPI controller,"
+ msg_perr("%s: impossible with this SPI controller,"
" degrading to byte program\n", __func__);
- return spi_chip_write_1(flash, buf);
+ return spi_chip_write_1_new(flash, buf, start, len);
#endif
#endif
default:
break;
}
+ /* The even start address and even length requirements can be either
+ * honored outside this function, or we can call spi_byte_program
+ * for the first and/or last byte and use AAI for the rest.
+ */
/* The data sheet requires a start address with the low bit cleared. */
- if (addr % 2) {
+ if (start % 2) {
msg_cerr("%s: start address not even! Please report a bug at "
"flashrom@flashrom.org\n", __func__);
return SPI_GENERIC_ERROR;
@@ -1048,15 +1059,14 @@
return SPI_GENERIC_ERROR;
}
- if (erase_flash(flash)) {
- msg_cerr("ERASE FAILED!\n");
- return -1;
- }
result = spi_send_multicommand(cmds);
if (result) {
msg_cerr("%s failed during start command execution\n",
__func__);
+ /* FIXME: Should we send WRDI here as well to make sure the chip
+ * is not in AAI mode?
+ */
return result;
}
while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
@@ -1065,7 +1075,7 @@
/* We already wrote 2 bytes in the multicommand step. */
pos += 2;
- while (pos < addr + len) {
+ while (pos < start + len) {
cmd[1] = buf[pos++];
cmd[2] = buf[pos++];
spi_send_command(JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL);
diff --git a/wbsio_spi.c b/wbsio_spi.c
index ca7bd01..8db6524 100644
--- a/wbsio_spi.c
+++ b/wbsio_spi.c
@@ -189,16 +189,14 @@
return read_memmapped(flash, buf, start, len);
}
-int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf)
+int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf, int start, int len)
{
- int size = flash->total_size * 1024;
-
- if (size > 1024 * 1024) {
+ if (flash->total_size * 1024 > 1024 * 1024) {
msg_perr("%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__);
return 1;
}
- return spi_chip_write_1(flash, buf);
+ return spi_chip_write_1_new(flash, buf, start, len);
}
#endif