Replace most of the switch cases in the spi code with lookup on a struct instead

This brings the SPI code in line with the generic programmer
infrastructure.

This patch is a reworked version of a patch by Jakob Bornecrantz.

Corresponding to flashrom svn r657.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Signed-off-by: Jakob Bornecrantz <wallbraker@gmail.com>
Acked-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Jakob Bornecrantz <wallbraker@gmail.com>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
diff --git a/flash.h b/flash.h
index e31a219..ba201ec 100644
--- a/flash.h
+++ b/flash.h
@@ -420,8 +420,18 @@
 	const unsigned char *writearr;
 	unsigned char *readarr;
 };
+struct spi_programmer {
+	int (*command)(unsigned int writecnt, unsigned int readcnt,
+		   const unsigned char *writearr, unsigned char *readarr);
+	int (*multicommand)(struct spi_command *spicommands);
+
+	/* 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);
+};
 
 extern enum spi_controller spi_controller;
+extern const struct spi_programmer spi_programmer[];
 extern void *spibar;
 int probe_spi_rdid(struct flashchip *flash);
 int probe_spi_rdid4(struct flashchip *flash);
@@ -452,6 +462,9 @@
 int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize);
 int spi_aai_write(struct flashchip *flash, uint8_t *buf);
 uint32_t spi_get_valid_read_addr(void);
+int default_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			     const unsigned char *writearr, unsigned char *readarr);
+int default_spi_send_multicommand(struct spi_command *spicommands);
 
 /* 82802ab.c */
 int probe_82802ab(struct flashchip *flash);
@@ -477,6 +490,7 @@
 		    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_send_multicommand(struct spi_command *spicommands);
 
 /* it87spi.c */
 extern char *it87opts;
diff --git a/ichspi.c b/ichspi.c
index 73dc249..5d2e40f 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -742,3 +742,23 @@
 
 	return result;
 }
+
+int ich_spi_send_multicommand(struct spi_command *spicommands)
+{
+	int ret = 0;
+	while ((spicommands->writecnt || spicommands->readcnt) && !ret) {
+		ret = ich_spi_send_command(spicommands->writecnt, spicommands->readcnt,
+					   spicommands->writearr, spicommands->readarr);
+		/* This awful hack needs to be smarter.
+		 */
+		if ((ret == SPI_INVALID_OPCODE) &&
+		    ((spicommands->writearr[0] == JEDEC_WREN) ||
+		     (spicommands->writearr[0] == JEDEC_EWSR))) {
+			printf_debug(" due to SPI master limitation, ignoring"
+				     " and hoping it will be run as PREOP\n");
+			ret = 0;
+		}
+		spicommands++;
+	}
+	return ret;
+}
diff --git a/spi.c b/spi.c
index ceda14e..3a3c77a 100644
--- a/spi.c
+++ b/spi.c
@@ -32,59 +32,123 @@
 
 void spi_prettyprint_status_register(struct flashchip *flash);
 
+const struct spi_programmer spi_programmer[] = {
+	{ /* SPI_CONTROLLER_NONE */
+		.command = NULL,
+		.multicommand = NULL,
+		.read = NULL,
+		.write_256 = NULL,
+	},
+
+	{ /* SPI_CONTROLLER_ICH7 */
+		.command = ich_spi_send_command,
+		.multicommand = ich_spi_send_multicommand,
+		.read = ich_spi_read,
+		.write_256 = ich_spi_write_256,
+	},
+
+	{ /* SPI_CONTROLLER_ICH9 */
+		.command = ich_spi_send_command,
+		.multicommand = ich_spi_send_multicommand,
+		.read = ich_spi_read,
+		.write_256 = ich_spi_write_256,
+	},
+
+	{ /* SPI_CONTROLLER_IT87XX */
+		.command = it8716f_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = it8716f_spi_chip_read,
+		.write_256 = it8716f_spi_chip_write_256,
+	},
+
+	{ /* SPI_CONTROLLER_SB600 */
+		.command = sb600_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = sb600_spi_read,
+		.write_256 = sb600_spi_write_1,
+	},
+
+	{ /* SPI_CONTROLLER_VIA */
+		.command = ich_spi_send_command,
+		.multicommand = ich_spi_send_multicommand,
+		.read = ich_spi_read,
+		.write_256 = ich_spi_write_256,
+	},
+
+	{ /* SPI_CONTROLLER_WBSIO */
+		.command = wbsio_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = wbsio_spi_read,
+		.write_256 = wbsio_spi_write_1,
+	},
+
+	{ /* SPI_CONTROLLER_FT2232 */
+		.command = ft2232_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = ft2232_spi_read,
+		.write_256 = ft2232_spi_write_256,
+	},
+
+	{ /* SPI_CONTROLLER_DUMMY */
+		.command = dummy_spi_send_command,
+		.multicommand = default_spi_send_multicommand,
+		.read = NULL,
+		.write_256 = NULL,
+	},
+};
+
+
 int spi_send_command(unsigned int writecnt, unsigned int readcnt,
 		const unsigned char *writearr, unsigned char *readarr)
 {
-	switch (spi_controller) {
-	case SPI_CONTROLLER_IT87XX:
-		return it8716f_spi_send_command(writecnt, readcnt, writearr,
-					   readarr);
-	case SPI_CONTROLLER_ICH7:
-	case SPI_CONTROLLER_ICH9:
-	case SPI_CONTROLLER_VIA:
-		return ich_spi_send_command(writecnt, readcnt, writearr, readarr);
-	case SPI_CONTROLLER_SB600:
-		return sb600_spi_send_command(writecnt, readcnt, writearr, readarr);
-	case SPI_CONTROLLER_WBSIO:
-		return wbsio_spi_send_command(writecnt, readcnt, writearr, readarr);
-	case SPI_CONTROLLER_FT2232:
-		return ft2232_spi_send_command(writecnt, readcnt, writearr, readarr);
-	case SPI_CONTROLLER_DUMMY:
-		return dummy_spi_send_command(writecnt, readcnt, writearr, readarr);
-	default:
-		printf_debug
-		    ("%s called, but no SPI chipset/strapping detected\n",
-		     __FUNCTION__);
+	if (!spi_programmer[spi_controller].command) {
+		fprintf(stderr, "%s called, but SPI is unsupported on this "
+			"hardware. Please report a bug.\n", __func__);
+		return 1;
 	}
-	return 1;
+
+	return spi_programmer[spi_controller].command(writecnt, readcnt,
+						      writearr, readarr);
 }
 
 int spi_send_multicommand(struct spi_command *spicommands)
 {
-	int ret = 0;
-	while ((spicommands->writecnt || spicommands->readcnt) && !ret) {
-		ret = spi_send_command(spicommands->writecnt, spicommands->readcnt,
-				       spicommands->writearr, spicommands->readarr);
-		/* This awful hack needs to be replaced with a multicommand
-		 * capable ICH/VIA SPI driver.
-		 */
-		if ((ret == SPI_INVALID_OPCODE) &&
-		    ((spicommands->writearr[0] == JEDEC_WREN) ||
-		     (spicommands->writearr[0] == JEDEC_EWSR))) {
-			switch (spi_controller) {
-			case SPI_CONTROLLER_ICH7:
-			case SPI_CONTROLLER_ICH9:
-			case SPI_CONTROLLER_VIA:
-				printf_debug(" due to SPI master limitation, ignoring"
-					     " and hoping it will be run as PREOP\n");
-				ret = 0;
-			default:
-				break;
-			}
-		}
-		spicommands++;
+	if (!spi_programmer[spi_controller].multicommand) {
+		fprintf(stderr, "%s called, but SPI is unsupported on this "
+			"hardware. Please report a bug.\n", __func__);
+		return 1;
 	}
-	return ret;
+
+	return spi_programmer[spi_controller].multicommand(spicommands);
+}
+
+int default_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			     const unsigned char *writearr, unsigned char *readarr)
+{
+	struct spi_command cmd[] = {
+	{
+		.writecnt = writecnt,
+		.readcnt = readcnt,
+		.writearr = writearr,
+		.readarr = readarr,
+	}, {
+		.writecnt = 0,
+		.writearr = NULL,
+		.readcnt = 0,
+		.readarr = NULL,
+	}};
+
+	return spi_send_multicommand(cmd);
+}
+
+int default_spi_send_multicommand(struct spi_command *spicommands)
+{
+	int result = 0;
+	while ((spicommands->writecnt || spicommands->readcnt) && !result) {
+		result = spi_send_command(spicommands->writecnt, spicommands->readcnt,
+					  spicommands->writearr, spicommands->readarr);
+	}
+	return result;
 }
 
 static int spi_rdid(unsigned char *readarr, int bytes)
@@ -298,18 +362,18 @@
 uint8_t spi_read_status_register(void)
 {
 	const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { JEDEC_RDSR };
+	/* FIXME: No workarounds for driver/hardware bugs in generic code. */
 	unsigned char readarr[2]; /* JEDEC_RDSR_INSIZE=1 but wbsio needs 2 */
 	int ret;
 
 	/* Read Status Register */
-	if (spi_controller == SPI_CONTROLLER_SB600) {
-		/* SB600 uses a different way to read status register. */
+	if (spi_controller == SPI_CONTROLLER_SB600) { /* FIXME */
+		/* Workaround for SB600 hardware bug. Can be killed later. */
 		return sb600_read_status_register();
-	} else {
-		ret = spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr);
-		if (ret)
-			printf_debug("RDSR failed!\n");
 	}
+	ret = spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr);
+	if (ret)
+		printf_debug("RDSR failed!\n");
 
 	return readarr[0];
 }
@@ -875,26 +939,13 @@
 
 int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
-	switch (spi_controller) {
-	case SPI_CONTROLLER_IT87XX:
-		return it8716f_spi_chip_read(flash, buf, start, len);
-	case SPI_CONTROLLER_SB600:
-		return sb600_spi_read(flash, buf, start, len);
-	case SPI_CONTROLLER_ICH7:
-	case SPI_CONTROLLER_ICH9:
-	case SPI_CONTROLLER_VIA:
-		return ich_spi_read(flash, buf, start, len);
-	case SPI_CONTROLLER_WBSIO:
-		return wbsio_spi_read(flash, buf, start, len);
-	case SPI_CONTROLLER_FT2232:
-		return ft2232_spi_read(flash, buf, start, len);
-	default:
-		printf_debug
-		    ("%s called, but no SPI chipset/strapping detected\n",
-		     __FUNCTION__);
+	if (!spi_programmer[spi_controller].read) {
+		fprintf(stderr, "%s called, but SPI read is unsupported on this"
+			" hardware. Please report a bug.\n", __func__);
+		return 1;
 	}
 
-	return 1;
+	return spi_programmer[spi_controller].read(flash, buf, start, len);
 }
 
 /*
@@ -924,26 +975,13 @@
  */
 int spi_chip_write_256(struct flashchip *flash, uint8_t *buf)
 {
-	switch (spi_controller) {
-	case SPI_CONTROLLER_IT87XX:
-		return it8716f_spi_chip_write_256(flash, buf);
-	case SPI_CONTROLLER_SB600:
-		return sb600_spi_write_1(flash, buf);
-	case SPI_CONTROLLER_ICH7:
-	case SPI_CONTROLLER_ICH9:
-	case SPI_CONTROLLER_VIA:
-		return ich_spi_write_256(flash, buf);
-	case SPI_CONTROLLER_WBSIO:
-		return wbsio_spi_write_1(flash, buf);
-	case SPI_CONTROLLER_FT2232:
-		return ft2232_spi_write_256(flash, buf);
-	default:
-		printf_debug
-		    ("%s called, but no SPI chipset/strapping detected\n",
-		     __FUNCTION__);
+	if (!spi_programmer[spi_controller].write_256) {
+		fprintf(stderr, "%s called, but SPI page write is unsupported "
+			" on this hardware. Please report a bug.\n", __func__);
+		return 1;
 	}
 
-	return 1;
+	return spi_programmer[spi_controller].write_256(flash, buf);
 }
 
 uint32_t spi_get_valid_read_addr(void)