[flashrom] [PATCH 1/3] Add SPI support to serprog protocol.

Stefan Tauner stefan.tauner at student.tuwien.ac.at
Tue Jun 21 22:22:11 CEST 2011


Signed-off-by: Urja Rannikko <urjaman at gmail.com>
---
 programmer.h         |    6 ++
 serprog-protocol.txt |    9 ++-
 serprog.c            |  246 +++++++++++++++++++++++++++++++++++---------------
 3 files changed, 188 insertions(+), 73 deletions(-)

diff --git a/programmer.h b/programmer.h
index ce0ffa1..7df2120 100644
--- a/programmer.h
+++ b/programmer.h
@@ -539,6 +539,9 @@ enum spi_controller {
 #if CONFIG_OGP_SPI == 1 || CONFIG_NICINTEL_SPI == 1 || CONFIG_RAYER_SPI == 1 || (CONFIG_INTERNAL == 1 && (defined(__i386__) || defined(__x86_64__)))
 	SPI_CONTROLLER_BITBANG,
 #endif
+#if CONFIG_SERPROG == 1
+	SPI_CONTROLLER_SERPROG,
+#endif
 };
 extern const int spi_programmer_count;
 
@@ -599,6 +602,9 @@ void serprog_chip_writeb(uint8_t val, chipaddr addr);
 uint8_t serprog_chip_readb(const chipaddr addr);
 void serprog_chip_readn(uint8_t *buf, const chipaddr addr, size_t len);
 void serprog_delay(int delay);
+int serprog_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+			const unsigned char *writearr, unsigned char *readarr);
+int serprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len);
 #endif
 
 /* serial.c */
diff --git a/serprog-protocol.txt b/serprog-protocol.txt
index c5464a4..cced0dc 100644
--- a/serprog-protocol.txt
+++ b/serprog-protocol.txt
@@ -31,6 +31,8 @@ COMMAND	Description			Parameters			Return Value
 0x10	Sync NOP			none				NAK + ACK (for synchronization)
 0x11	Query maximum read-n length	none				ACK + 24-bit length (0==2^24) / NAK
 0x12	Set used bustype		8-bit flags (as with 0x05)	ACK / NAK
+0x13	Perform SPI operation		24-bit slen + 24-bit rlen	ACK + rlen bytes of data / NAK
+					 + slen bytes of data
 0x??	unimplemented command - invalid.
 
 
@@ -50,7 +52,7 @@ Additional information of the above commands:
 		it should return a big bogus value - eg 0xFFFF.
 	0x05 (Q_BUSTYPE):
 		The bit's are defined as follows:
-		bit 0: PARALLEL, bit 1: LPC, bit 2: FWH, bit 3: SPI (if ever supported).
+		bit 0: PARALLEL, bit 1: LPC, bit 2: FWH, bit 3: SPI.
 	0x06 (Q_CHIPSIZE):
 		Only applicable to parallel programmers.
 		An LPC/FWH/SPI-programmer can report this as not supported in the command bitmap.
@@ -66,6 +68,10 @@ Additional information of the above commands:
 		Set's the used bustype if the programmer can support more than one flash protocol.
 		Sending a byte with more than 1 bit set will make the programmer decide among them
 		on it's own. Bit values as with Q_BUSTYPE.
+	0x13 (O_SPIOP):
+		Maximum slen is Q_WRNMAXLEN result after Q_BUSTYPE returns
+		only SPI or S_BUSTYPE == SPI is used. Same for rlen and Q_RDNMAXLEN.
+		This operation is immediate, meaning it doesnt use the operation buffer.
 	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.
@@ -99,3 +105,4 @@ This define listing should help C coders - (it's here to be the single source fo
 #define S_CMD_SYNCNOP		0x10		/* Special no-operation that returns NAK+ACK	*/
 #define S_CMD_Q_RDNMAXLEN	0x11		/* Query read-n maximum length			*/
 #define S_CMD_S_BUSTYPE		0x12		/* Set used bustype(s).				*/
+#define S_CMD_O_SPIOP		0x13		/* Perform SPI operation.			*/
diff --git a/serprog.c b/serprog.c
index b91e376..d61d0d7 100644
--- a/serprog.c
+++ b/serprog.c
@@ -1,7 +1,7 @@
 /*
  * This file is part of the flashrom project.
  *
- * Copyright (C) 2009 Urja Rannikko <urjaman at gmail.com>
+ * Copyright (C) 2009, 2011 Urja Rannikko <urjaman at gmail.com>
  * Copyright (C) 2009 Carl-Daniel Hailfinger
  *
  * This program is free software; you can redistribute it and/or modify
@@ -36,6 +36,7 @@
 #include <termios.h>
 #include "flash.h"
 #include "programmer.h"
+#include "chipdrivers.h"
 
 #define MSGHEADER "serprog:"
 
@@ -67,6 +68,7 @@ static int serprog_shutdown(void *data);
 #define S_CMD_SYNCNOP		0x10	/* Special no-operation that returns NAK+ACK    */
 #define S_CMD_Q_RDNMAXLEN	0x11	/* Query read-n maximum length			*/
 #define S_CMD_S_BUSTYPE		0x12	/* Set used bustype(s).				*/
+#define S_CMD_O_SPIOP		0x13	/* Perform SPI operation.			*/
 
 static uint16_t sp_device_serbuf_size = 16;
 static uint16_t sp_device_opbuf_size = 300;
@@ -302,6 +304,16 @@ static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t * parms)
 	return 0;
 }
 
+static struct spi_programmer spi_programmer_serprog = {
+	.type = SPI_CONTROLLER_SERPROG,
+	.max_data_read = MAX_DATA_READ_UNLIMITED,
+	.max_data_write = MAX_DATA_WRITE_UNLIMITED,
+	.command = serprog_spi_send_command,
+	.multicommand = default_spi_send_multicommand,
+	.read = serprog_spi_read,
+	.write_256 = default_spi_write_256,
+};
+
 int serprog_init(void)
 {
 	uint16_t iface;
@@ -325,7 +337,7 @@ int serprog_init(void)
 			msg_perr("Error: No baudrate specified.\n"
 				 "Use flashrom -p serprog:dev=/dev/device:baud\n");
 			free(device);
-			return 1;		
+			return 1;
 		}
 		if (strlen(device)) {
 			sp_fd = sp_openserport(device, atoi(baudport));
@@ -358,7 +370,7 @@ int serprog_init(void)
 			msg_perr("Error: No port specified.\n"
 				 "Use flashrom -p serprog:ip=ipaddr:port\n");
 			free(device);
-			return 1;		
+			return 1;
 		}
 		if (strlen(device)) {
 			sp_fd = sp_opensocket(device, atoi(baudport));
@@ -410,35 +422,110 @@ int serprog_init(void)
 
 	sp_check_avail_automatic = 1;
 
-	/* Check for the minimum operational set of commands */
-	if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
-		msg_perr("Error: Single byte read not supported\n");
-		exit(1);
-	}
-	/* This could be translated to single byte reads (if missing),	*
-	 * but now we dont support that.				*/
-	if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
-		msg_perr("Error: Read n bytes not supported\n");
-		exit(1);
-	}
-	/* In the future one could switch to read-only mode if these	*
-	 * are not available.						*/
-	if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
-		msg_perr("Error: Initialize operation buffer not supported\n");
-		exit(1);
-	}
-	if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
-		msg_perr("Error: Write to opbuf: write byte not supported\n");
-		exit(1);
+
+	if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
+		msg_perr("Warning: NAK to query supported buses\n");
+		c = CHIP_BUSTYPE_NONSPI;	/* A reasonable default for now. */
 	}
-	if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
-		msg_perr("Error: Write to opbuf: delay not supported\n");
-		exit(1);
+	buses_supported = c;
+	/* Check for the minimum operational set of commands. */
+	if (buses_supported & CHIP_BUSTYPE_SPI) {
+		uint8_t bt = CHIP_BUSTYPE_SPI;
+		if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
+			msg_perr("Error: SPI operation not supported while the SPI bustype is\n");
+			exit(1);
+		}
+		/* Success of any of these commands is optional. We dont need
+		   the programmer to tell us it's limits, but if it doesnt, we
+		   will assume stuff, so it's in the programmers best interest
+		   to tell us. */
+		sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL);
+		if (!sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
+			uint32_t v;
+			v = ((unsigned int)(rbuf[0]) << 0);
+			v |= ((unsigned int)(rbuf[1]) << 8);
+			v |= ((unsigned int)(rbuf[2]) << 16);
+			/* Limit to 256 because we dont need longer writes. */
+			if ((v==0)||(v>256)) {
+				v = 256;
+			}
+			spi_programmer_serprog.max_data_write = v;
+		}
+		if (!sp_docommand(S_CMD_Q_RDNMAXLEN, 0, NULL, 3, rbuf)) {
+			uint32_t v;
+			v = ((unsigned int)(rbuf[0]) << 0);
+			v |= ((unsigned int)(rbuf[1]) << 8);
+			v |= ((unsigned int)(rbuf[2]) << 16);
+			if (v==0) {
+				v = (1<<24)-1; /* SPI-op maximum. */
+			}
+			spi_programmer_serprog.max_data_read = v;
+		}
+		bt = buses_supported;
+		sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL);
+		register_spi_programmer(&spi_programmer_serprog);
 	}
-	if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
-		msg_perr(
-			"Error: Execute operation buffer not supported\n");
-		exit(1);
+
+	if (buses_supported & CHIP_BUSTYPE_NONSPI) {
+		if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
+			msg_perr("Error: Initialize operation buffer not supported\n");
+			exit(1);
+		}
+
+		if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
+			msg_perr("Error: Write to opbuf: delay not supported\n");
+			exit(1);
+		}
+
+		/* S_CMD_O_EXEC availability checked later. */
+
+		if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
+			msg_perr("Error: Single byte read not supported\n");
+			exit(1);
+		}
+		/* This could be translated to single byte reads (if missing),	*
+		* but now we dont support that.				*/
+		if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
+			msg_perr("Error: Read n bytes not supported\n");
+			exit(1);
+		}
+		if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
+			msg_perr("Error: Write to opbuf: write byte not supported\n");
+			exit(1);
+		}
+
+		if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
+			msg_pdbg(MSGHEADER "Write-n not supported");
+			sp_max_write_n = 0;
+		} else {
+			sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
+			sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
+			sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
+			if (!sp_max_write_n) {
+				sp_max_write_n = (1<<24);
+			}
+			msg_pdbg(MSGHEADER "Maximum write-n length %d\n",
+			     sp_max_write_n);
+			sp_write_n_buf = malloc(sp_max_write_n);
+			if (!sp_write_n_buf) {
+				msg_perr("Error: cannot allocate memory for Write-n buffer\n");
+				exit(1);
+			}
+			sp_write_n_bytes = 0;
+		}
+
+		if ((sp_check_commandavail(S_CMD_Q_RDNMAXLEN))
+			&&((sp_docommand(S_CMD_Q_RDNMAXLEN,0,NULL, 3, rbuf) == 0))) {
+			sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
+			sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
+			sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
+			msg_pdbg(MSGHEADER "Maximum read-n length %d\n",
+				sp_max_read_n ? sp_max_read_n : (1<<24));
+		} else {
+			msg_pdbg(MSGHEADER "Maximum read-n length not reported\n");
+			sp_max_read_n = 0;
+		}
+
 	}
 
 	if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) {
@@ -454,51 +541,24 @@ int serprog_init(void)
 	msg_pdbg(MSGHEADER "serial buffer size %d\n",
 		     sp_device_serbuf_size);
 
-	if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2, &sp_device_opbuf_size)) {
-		msg_perr("Warning: NAK to query operation buffer size\n");
-	}
-	msg_pdbg(MSGHEADER "operation buffer size %d\n",
-		     sp_device_opbuf_size);
-
-	if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) {
-		msg_perr("Warning: NAK to query supported buses\n");
-		c = CHIP_BUSTYPE_NONSPI;	/* A reasonable default for now. */
-	}
-	buses_supported = c;
-
-	if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
-		msg_perr("Error: NAK to initialize operation buffer\n");
-		exit(1);
-	}
+	if (sp_check_commandavail(S_CMD_O_INIT)) {
+		/* This would be inconsistent. */
+		if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
+			msg_perr("Error: Execute operation buffer not supported\n");
+			exit(1);
+		}
 
-	if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
-		msg_pdbg(MSGHEADER "Write-n not supported");
-		sp_max_write_n = 0;
-	} else {
-		sp_max_write_n = ((unsigned int)(rbuf[0]) << 0);
-		sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8);
-		sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16);
-		msg_pdbg(MSGHEADER "Maximum write-n length %d\n",
-			     sp_max_write_n);
-		sp_write_n_buf = malloc(sp_max_write_n);
-		if (!sp_write_n_buf) {
-			msg_perr("Error: cannot allocate memory for Write-n buffer\n");
+		if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
+			msg_perr("Error: NAK to initialize operation buffer\n");
 			exit(1);
 		}
-		sp_write_n_bytes = 0;
-	}
-	
-	if ((sp_check_commandavail(S_CMD_Q_RDNMAXLEN))
-		&&((sp_docommand(S_CMD_Q_RDNMAXLEN,0,NULL, 3, rbuf) == 0))) {
-		sp_max_read_n = ((unsigned int)(rbuf[0]) << 0);
-		sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8);
-		sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16);
-		msg_pdbg(MSGHEADER "Maximum read-n length %d\n",
-			sp_max_read_n ? sp_max_read_n : (1<<24));
-	} else {
-		msg_pdbg(MSGHEADER "Maximum read-n length not reported\n");
-		sp_max_read_n = 0;
-	}
+
+		if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2, &sp_device_opbuf_size)) {
+			msg_perr("Warning: NAK to query operation buffer size\n");
+		}
+		msg_pdbg(MSGHEADER "operation buffer size %d\n",
+		     sp_device_opbuf_size);
+  	}
 
 	sp_prev_was_write = 0;
 	sp_streamed_transmit_ops = 0;
@@ -679,6 +739,11 @@ void serprog_delay(int delay)
 {
 	unsigned char buf[4];
 	msg_pspew("%s\n", __func__);
+	if (!sp_check_commandavail(S_CMD_O_DELAY)) {
+		internal_delay(delay);
+		msg_pdbg("Note: serprog_delay used, but the programmer doesnt support delay\n");
+		return;
+	}
 	if ((sp_max_write_n) && (sp_write_n_bytes))
 		sp_pass_writen();
 	sp_check_opbuf_usage(5);
@@ -690,3 +755,40 @@ void serprog_delay(int delay)
 	sp_opbuf_usage += 5;
 	sp_prev_was_write = 0;
 }
+
+int serprog_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+                        const unsigned char *writearr, unsigned char *readarr)
+{
+	unsigned char *parmbuf;
+	int ret;
+	msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
+	if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+		sp_execute_opbuf();
+	parmbuf = malloc(writecnt+6);
+	if (!parmbuf) sp_die("Error: cannot malloc SPI send param buffer");
+	parmbuf[0] = (writecnt >> 0) & 0xFF;
+	parmbuf[1] = (writecnt >> 8) & 0xFF;
+	parmbuf[2] = (writecnt >> 16) & 0xFF;
+	parmbuf[3] = (readcnt >> 0) & 0xFF;
+	parmbuf[4] = (readcnt >> 8) & 0xFF;
+	parmbuf[5] = (readcnt >> 16) & 0xFF;
+	memcpy(parmbuf+6, writearr, writecnt);
+	ret = sp_docommand(S_CMD_O_SPIOP, writecnt+6, parmbuf, readcnt, readarr);
+	free(parmbuf);
+	return ret;
+}
+
+int serprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	int i;
+	int max_read = spi_programmer_serprog.max_data_read;
+	/* This function is optimized in that it doesnt split the read into
+	   chip page_size length blocks unnecessarily. */
+	for(i=0;i<len;) {
+		int rv;
+		int len_left = ((len-i)>max_read) ? max_read : (len-i);
+		if ((rv=spi_nbyte_read(start+i, buf+i, len_left))) return rv;
+		i += len_left;
+	}
+	return 0;
+}
-- 
1.7.1





More information about the flashrom mailing list