Add native SPI AAI write support to the Dediprog SF100 driver

To tell the programmer how to handle the data on the spi bus, a flag in
the fourth byte sent with the usb command is used. The second word was
mistaken for the size of the chunks sent over usb earlier. The third
byte (first of the second word) is now set to zero. This also adds some
checks for the size of data chunks sent over usb.

Corresponding to flashrom svn r1546.

Signed-off-by: Nico Huber <nico.huber@secunet.com>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
diff --git a/dediprog.c b/dediprog.c
index cdd27b0..9559eed 100644
--- a/dediprog.c
+++ b/dediprog.c
@@ -31,6 +31,9 @@
 static int dediprog_firmwareversion;
 static int dediprog_endpoint;
 
+#define DEDI_SPI_CMD_PAGEWRITE	0x1
+#define DEDI_SPI_CMD_AAIWRITE	0x4
+
 #if 0
 /* Might be useful for other pieces of code as well. */
 static void print_hex(void *buf, size_t len)
@@ -307,13 +310,15 @@
 	return 0;
 }
 
-/* Bulk write interface, will write multiple page_size byte chunks aligned to page_size bytes.
- * @start	start address
- * @len		length
- * @return	0 on success, 1 on failure
+/* Bulk write interface, will write multiple chunksize byte chunks aligned to chunksize bytes.
+ * @chunksize       length of data chunks, only 256 supported by now
+ * @start           start address
+ * @len             length
+ * @dedi_spi_cmd    dediprog specific write command for spi bus
+ * @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)
+static int dediprog_spi_bulk_write(struct flashctx *flash, uint8_t *buf, unsigned int chunksize,
+				   unsigned int start, unsigned int len, uint8_t dedi_spi_cmd)
 {
 	int ret;
 	unsigned int i;
@@ -321,14 +326,21 @@
 	 * 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};
+	const char count_and_cmd[] = {count & 0xff, (count >> 8) & 0xff, 0x00, dedi_spi_cmd};
 	char usbbuf[512];
 
+	/*
+	 * We should change this check to
+	 *   chunksize > 512
+	 * once we know how to handle different chunk sizes.
+	 */
+	if (chunksize != 256) {
+		msg_perr("%s: Chunk sizes other than 256 bytes are unsupported, chunksize=%u!\n"
+			 "Please report a bug at flashrom@flashrom.org\n", __func__, chunksize);
+		return 1;
+	}
+
 	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);
@@ -341,10 +353,9 @@
 	/* 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)) {
+	ret = usb_control_msg(dediprog_handle, 0x42, 0x30, start % 0x10000, start / 0x10000,
+			      (char *)count_and_cmd, sizeof(count_and_cmd), DEFAULT_TIMEOUT);
+	if (ret != sizeof(count_and_cmd)) {
 		msg_perr("Command Write SPI Bulk failed, %i %s!\n", ret,
 			 usb_strerror());
 		return 1;
@@ -366,8 +377,8 @@
 	return 0;
 }
 
-static int dediprog_spi_write_256(struct flashctx *flash, uint8_t *buf,
-				  unsigned int start, unsigned int len)
+static int dediprog_spi_write(struct flashctx *flash, uint8_t *buf,
+			      unsigned int start, unsigned int len, uint8_t dedi_spi_cmd)
 {
 	int ret;
 	const unsigned int chunksize = flash->page_size;
@@ -376,6 +387,13 @@
 
 	dediprog_set_leds(PASS_OFF|BUSY_ON|ERROR_OFF);
 
+	if (chunksize != 256) {
+		msg_pdbg("Page sizes other than 256 bytes are unsupported as "
+			 "we don't know how dediprog\nhandles them.\n");
+		/* Write everything like it was residue. */
+		residue = len;
+	}
+
 	if (residue) {
 		msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n",
 			 start, residue);
@@ -389,8 +407,7 @@
 
 	/* Round down. */
 	bulklen = (len - residue) / chunksize * chunksize;
-	ret = dediprog_spi_bulk_write(flash, buf + residue, start + residue,
-				     bulklen);
+	ret = dediprog_spi_bulk_write(flash, buf + residue, chunksize, start + residue, bulklen, dedi_spi_cmd);
 	if (ret) {
 		dediprog_set_leds(PASS_OFF|BUSY_OFF|ERROR_ON);
 		return ret;
@@ -412,6 +429,16 @@
 	return 0;
 }
 
+static int dediprog_spi_write_256(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+	return dediprog_spi_write(flash, buf, start, len, DEDI_SPI_CMD_PAGEWRITE);
+}
+
+static int dediprog_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+	return dediprog_spi_write(flash, buf, start, len, DEDI_SPI_CMD_AAIWRITE);
+}
+
 static int dediprog_spi_send_command(struct flashctx *flash,
 				     unsigned int writecnt,
 				     unsigned int readcnt,
@@ -717,7 +744,7 @@
 	.multicommand	= default_spi_send_multicommand,
 	.read		= dediprog_spi_read,
 	.write_256	= dediprog_spi_write_256,
-	.write_aai	= default_spi_write_aai,
+	.write_aai	= dediprog_spi_write_aai,
 };
 
 static int dediprog_shutdown(void *data)