serprog: add opcode to control the programmer's output drivers

This allowed me to let the clips remain attached on my D946GZIS while
playing with coreboot/serialice.

Corresponding to flashrom svn r1618.

Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
diff --git a/Documentation/serprog-protocol.txt b/Documentation/serprog-protocol.txt
index 821cf28..58f4417 100644
--- a/Documentation/serprog-protocol.txt
+++ b/Documentation/serprog-protocol.txt
@@ -34,6 +34,7 @@
 0x13	Perform SPI operation		24-bit slen + 24-bit rlen	ACK + rlen bytes of data / NAK
 					 + slen bytes of data
 0x14	Set SPI clock frequency in Hz	32-bit requested frequency	ACK + 32-bit set frequency / NAK
+0x15	Toggle flash chip pin drivers	8-bit (0 disable, else enable)	ACK / NAK
 0x??	unimplemented command - invalid.
 
 
@@ -82,6 +83,12 @@
 		lower than the one requested. If there is no lower frequency
 		available the lowest possible should be used. The value
 		chosen is sent back in the reply with an ACK.
+	0x15 (S_CMD_S_PIN_STATE):
+		Sets the state of the pin drivers connected to the flash chip. Disabling them allows other
+		devices (e.g. a mainboard's chipset) to access the chip. This way the serprog controller can
+		remain attached to the flash chip even when the board is running. The user is responsible to
+		NOT connect VCC and other permanently externally driven signals to the programmer as needed.
+		If the value is 0, then the drivers should be disabled, otherwise they should be enabled.
 	About mandatory commands:
 		The only truly mandatory commands for any device are 0x00, 0x01, 0x02 and 0x10,
 		but one can't really do anything with these commands.
diff --git a/serprog.c b/serprog.c
index 28faac8..edc5a7b 100644
--- a/serprog.c
+++ b/serprog.c
@@ -664,6 +664,15 @@
 			 sp_device_opbuf_size);
   	}
 
+	if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
+		uint8_t en = 1;
+		if (sp_docommand(S_CMD_S_PIN_STATE, 1, &en, 0, NULL) != 0) {
+			msg_perr("Error: could not enable output buffers\n");
+			return 1;
+		} else
+			msg_pdbg(MSGHEADER "Output drivers enabled\n");
+	} else
+		msg_pdbg(MSGHEADER "Warning: Programmer does not support toggling its output drivers\n");
 	sp_prev_was_write = 0;
 	sp_streamed_transmit_ops = 0;
 	sp_streamed_transmit_bytes = 0;
@@ -736,9 +745,15 @@
 
 static int serprog_shutdown(void *data)
 {
-	msg_pspew("%s\n", __func__);
 	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
 		sp_execute_opbuf();
+	if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
+		uint8_t dis = 0;
+		if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
+			msg_pdbg(MSGHEADER "Output drivers disabled\n");
+		else
+			msg_perr(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
+	}
 	/* FIXME: fix sockets on windows(?), especially closing */
 	serialport_shutdown(&sp_fd);
 	if (sp_max_write_n)
diff --git a/serprog.h b/serprog.h
index 8d11772..b54aaea 100644
--- a/serprog.h
+++ b/serprog.h
@@ -22,3 +22,4 @@
 #define S_CMD_S_BUSTYPE		0x12	/* Set used bustype(s).				*/
 #define S_CMD_O_SPIOP		0x13	/* Perform SPI operation.			*/
 #define S_CMD_S_SPI_FREQ	0x14	/* Set SPI clock frequency			*/
+#define S_CMD_S_PIN_STATE	0x15	/* Enable/disable output drivers		*/