Patchwork RFC: high level operations support and an example implementation in serprog

login
register
about
Submitter Urja Rannikko
Date 2013-10-10 10:13:11
Message ID <CAPCnQJkW2pkgJFazpAsdsX4154L4yroNKdmn25vFyeiYJYEChA@mail.gmail.com>
Download mbox | patch
Permalink /patch/4077/
State New
Headers show

Comments

Urja Rannikko - 2013-10-10 10:13:11
Hi,

Add mechanism to allow the external programmer to take over a higher
level operation than previously. As an useful first example jedec
toggle ready on serprog is included.

Signed-off-by: Urja Rannikko <urjaman@gmail.com>

-----
I dont have much to say about this, except that there is one more
patch following this to make proper use of the speed improvement this
allows to write_jedec_1,
and that serprog LPC support still depends on
http://patchwork.coreboot.org/patch/3465/ or something similar.
What do you think?


Oh and there is an example of the device code for this added serprog operation
here: https://github.com/urjaman/frser-atmega644

Patch

Index: flash.h
===================================================================
--- flash.h	(revision 1757)
+++ flash.h	(working copy)
@@ -29,6 +29,7 @@ 
 #include <stdint.h>
 #include <stddef.h>
 #include <stdbool.h>
+#include <stdarg.h>
 #ifdef _WIN32
 #include <windows.h>
 #undef min
@@ -40,6 +41,7 @@ 
 /* Error codes */
 #define ERROR_OOM	-100
 #define TIMEOUT_ERROR	-101
+struct flashctx;
 
 /* TODO: check using code for correct usage of types */
 typedef uintptr_t chipaddr;
@@ -53,10 +55,15 @@ 
 #define PRIxCHIPADDR "06"PRIx32
 #define PRIuCHIPSIZE PRIu32
 
+enum highlevel_cmd {
+	HL_ID_TOGGLE_READY_JEDEC = 1
+};
+
 int register_shutdown(int (*function) (void *data), void *data);
 void *programmer_map_flash_region(const char *descr, uintptr_t phys_addr, size_t len);
 void programmer_unmap_flash_region(void *virt_addr, size_t len);
 void programmer_delay(int usecs);
+int programmer_highlevel(const struct flashctx *flash, enum highlevel_cmd id, ...);
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
@@ -120,7 +127,6 @@ 
 #define FEATURE_OTP		(1 << 8)
 #define FEATURE_QPI		(1 << 9)
 
-struct flashctx;
 typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
 
 struct flashchip {
Index: jedec.c
===================================================================
--- jedec.c	(revision 1757)
+++ jedec.c	(working copy)
@@ -22,6 +22,7 @@ 
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
+#include <stdlib.h>
 #include "flash.h"
 
 #define MAX_REFLASH_TRIES 0x10
@@ -43,6 +44,8 @@ 
 	unsigned int i = 0;
 	uint8_t tmp1, tmp2;
 
+	if (programmer_highlevel(flash, HL_ID_TOGGLE_READY_JEDEC, dst, delay)) return;
+
 	tmp1 = chip_readb(flash, dst) & 0x40;
 
 	while (i++ < 0xFFFFFFF) {
Index: serprog.c
===================================================================
--- serprog.c	(revision 1757)
+++ serprog.c	(working copy)
@@ -886,6 +886,47 @@ 
 	sp_prev_was_write = 0;
 }
 
+int serprog_highlevel(const struct flashctx *flash, enum highlevel_cmd id, va_list ap)
+{
+	switch (id) {
+		default: /* Any new ids, by default not handled. */
+			return 0;
+		case HL_ID_TOGGLE_READY_JEDEC:
+			if (sp_check_commandavail(S_CMD_O_TOGGLERDY)) {
+
+				uint8_t buf[7];
+				if ((sp_max_write_n) && (sp_write_n_bytes))
+					sp_pass_writen();
+				sp_check_opbuf_usage(8);
+				unsigned int addr = va_arg(ap,unsigned int);
+				int usecs = va_arg(ap,int);
+				buf[0] = ((usecs >> 0) & 0xFF);
+				buf[1] = ((usecs >> 8) & 0xFF);
+				buf[2] = ((usecs >> 16) & 0xFF);
+				buf[3] = ((usecs >> 24) & 0xFF);
+				buf[4] = ((addr >> 0) & 0xFF);
+				buf[5] = ((addr >> 8) & 0xFF);
+				buf[6] = ((addr >> 16) & 0xFF);
+				sp_stream_buffer_op(S_CMD_O_TOGGLERDY, 7, buf);
+				sp_opbuf_usage += 8;
+				sp_prev_was_write = 0;
+				msg_pspew(MSGHEADER "highlevel toggle ready dly=%d addr=0x%x\n",
+					usecs,addr);
+				if (sp_opbuf_usage > (sp_device_opbuf_size/3)) {
+					/* Since this was previously a natural exec point,
+					   execute if we have more than 33% of opbuf in use. */
+					/* FIXME: Return error. */
+					sp_execute_opbuf_noflush();
+				}
+				return 1; /* Handled by programmer. */	
+			}
+			return 0;
+		
+	}
+	/* If you accidentally fall here, not handled. */
+	return 0;
+}
+
 static int serprog_spi_send_command(struct flashctx *flash,
 				    unsigned int writecnt, unsigned int readcnt,
 				    const unsigned char *writearr,
Index: serprog.h
===================================================================
--- serprog.h	(revision 1757)
+++ serprog.h	(working copy)
@@ -23,3 +23,4 @@ 
 #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		*/
+#define S_CMD_O_TOGGLERDY	0x16	/* Write to opbuf: Wait Jedec Toggle		*/
Index: Documentation/serprog-protocol.txt
===================================================================
--- Documentation/serprog-protocol.txt	(revision 1757)
+++ Documentation/serprog-protocol.txt	(working copy)
@@ -35,6 +35,8 @@ 
 					 + 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
+0x16	Write to opbuf: Toggle Ready	32-bit delay + 24-bit addr	ACK / NAK (NOTE: 8 bytes in opbuf)
+	JEDEC
 0x??	unimplemented command - invalid.
 
 
Index: flashrom.c
===================================================================
--- flashrom.c	(revision 1757)
+++ flashrom.c	(working copy)
@@ -194,6 +194,7 @@ 
 		.map_flash_region	= fallback_map,
 		.unmap_flash_region	= fallback_unmap,
 		.delay			= serprog_delay,
+		.highlevel		= serprog_highlevel,
 	},
 #endif
 
@@ -490,6 +491,17 @@ 
 	programmer_table[programmer].delay(usecs);
 }
 
+int programmer_highlevel(const struct flashctx *flash, enum highlevel_cmd id, ...)
+{
+	int rv = 0;
+	va_list ap;
+	va_start(ap,id);
+	if (programmer_table[programmer].highlevel)
+		rv = programmer_table[programmer].highlevel(flash,id,ap);
+	va_end(ap);
+	return rv;
+}
+
 void map_flash_registers(struct flashctx *flash)
 {
 	size_t size = flash->chip->total_size * 1024;
Index: programmer.h
===================================================================
--- programmer.h	(revision 1757)
+++ programmer.h	(working copy)
@@ -121,6 +121,8 @@ 
 	void (*unmap_flash_region) (void *virt_addr, size_t len);
 
 	void (*delay) (int usecs);
+
+	int (*highlevel) (const struct flashctx *flash, enum highlevel_cmd id, va_list ap);
 };
 
 extern const struct programmer_entry programmer_table[];
@@ -655,6 +657,7 @@ 
 #if CONFIG_SERPROG == 1
 int serprog_init(void);
 void serprog_delay(int usecs);
+int serprog_highlevel(const struct flashctx *flash, enum highlevel_cmd id, va_list ap);
 #endif
 
 /* serial.c */