[flashrom] [commit] r1442 - trunk

repository service svn at flashrom.org
Fri Sep 16 01:38:15 CEST 2011


Author: stefanct
Date: Fri Sep 16 01:38:14 2011
New Revision: 1442
URL: http://flashrom.org/trac/flashrom/changeset/1442

Log:
serprog: add SPI support

Adds a new opcode (0x13) that just relays SPI bytes and wires it up to be
usable within serprog.c. Checks for mandatory opcodes are moved around and
changed a bit, but non-SPI programmers should not be harmed by this patch.

Signed-off-by: Urja Rannikko <urjaman at gmail.com>
Signed-off-by: Stefan Tauner <stefan.tauner at student.tuwien.ac.at>
Acked-by: Uwe Hermann <uwe at hermann-uwe.de>

Modified:
   trunk/programmer.h
   trunk/serprog-protocol.txt
   trunk/serprog.c

Modified: trunk/programmer.h
==============================================================================
--- trunk/programmer.h	Thu Sep 15 00:09:48 2011	(r1441)
+++ trunk/programmer.h	Fri Sep 16 01:38:14 2011	(r1442)
@@ -545,6 +545,9 @@
 #if CONFIG_LINUX_SPI == 1
 	SPI_CONTROLLER_LINUX,
 #endif
+#if CONFIG_SERPROG == 1
+	SPI_CONTROLLER_SERPROG,
+#endif
 };
 extern const int spi_programmer_count;
 
@@ -605,6 +608,9 @@
 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 */

Modified: trunk/serprog-protocol.txt
==============================================================================
--- trunk/serprog-protocol.txt	Thu Sep 15 00:09:48 2011	(r1441)
+++ trunk/serprog-protocol.txt	Fri Sep 16 01:38:14 2011	(r1442)
@@ -31,6 +31,8 @@
 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 @@
 		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,11 @@
 		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):
+		Send and receive bytes via SPI.
+		Maximum slen is Q_WRNMAXLEN in case Q_BUSTYPE returns SPI only or S_BUSTYPE was used
+		to set SPI exclusively before. 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 +106,4 @@
 #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.			*/

Modified: trunk/serprog.c
==============================================================================
--- trunk/serprog.c	Thu Sep 15 00:09:48 2011	(r1441)
+++ trunk/serprog.c	Fri Sep 16 01:38:14 2011	(r1442)
@@ -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 @@
 #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 @@
 	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 @@
 			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 @@
 			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,115 @@
 
 	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 = BUS_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 & BUS_SPI) {
+		uint8_t bt = BUS_SPI;
+		if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
+			msg_perr("Error: SPI operation not supported while the "
+				 "bustype is SPI\n");
+			exit(1);
+		}
+		/* Success of any of these commands is optional. We don't need
+		   the programmer to tell us its limits, but if it doesn't, 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);
+			if (v == 0)
+				v = (1 << 24) - 1; /* SPI-op maximum. */
+			spi_programmer_serprog.max_data_write = v;
+			msg_pdbg(MSGHEADER "Maximum write-n length is %d\n", 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;
+			msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", 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 & BUS_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 don't 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 is %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 is %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 +546,27 @@
 	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 = BUS_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 +747,12 @@
 {
 	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 doesn't "
+			 "support delay\n");
+		return;
+	}
 	if ((sp_max_write_n) && (sp_write_n_bytes))
 		sp_pass_writen();
 	sp_check_opbuf_usage(5);
@@ -690,3 +764,48 @@
 	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;
+}
+
+/* FIXME: This function is optimized so that it does not split each transaction
+ * into chip page_size long blocks unnecessarily like spi_read_chunked. This has
+ * the advantage that it is much faster for most chips, but breaks those with
+ * non-contiguous address space (like AT45DB161D). When spi_read_chunked is
+ * fixed this method can be removed. */
+int serprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
+{
+	int i;
+	int cur_len;
+	const int max_read = spi_programmer_serprog.max_data_read;
+	for (i = 0; i < len; i += cur_len) {
+		int ret;
+		cur_len = min(max_read, (len - i));
+		ret = spi_nbyte_read(start + i, buf + i, cur_len);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}




More information about the flashrom mailing list