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/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);