[U-Boot] [PATCH 5/5] fpga: virtex2: Add slave serial programming support

Robert Hancock hancock at sedsystems.ca
Tue Jun 18 15:47:16 UTC 2019


This adds support for slave serial programming, in addition to the
previously supported slave SelectMAP mode. There are two ways that this
can be used:

-Using the clk and wdata callbacks in order to write image data one bit
at a time using pure bit-banging. This works, but is rather painfully
slow with typical image sizes.

-By specifying the wbulkdata callback instead, the image loading process
can be offloaded to SPI hardware. In this mode the clk and wdata
callbacks do not need to be specified. This allows the image to be
loaded much faster, taking only a few seconds with even relatively large
images.

Slave serial programming has been tested on the Kintex-7 series of
FPGAs.

Signed-off-by: Robert Hancock <hancock at sedsystems.ca>
---
 drivers/fpga/virtex2.c | 96 +++++++++++++++++++++++++++++++++++++++++++-------
 include/virtex2.h      | 13 ++-----
 2 files changed, 86 insertions(+), 23 deletions(-)

diff --git a/drivers/fpga/virtex2.c b/drivers/fpga/virtex2.c
index 5028244..3957368 100644
--- a/drivers/fpga/virtex2.c
+++ b/drivers/fpga/virtex2.c
@@ -3,6 +3,8 @@
  * (C) Copyright 2002
  * Rich Ireland, Enterasys Networks, rireland at enterasys.com.
  * Keith Outwater, keith_outwater at mvis.com
+ *
+ * Copyright (c) 2019 SED Systems, a division of Calian Ltd.
  */
 
 /*
@@ -141,8 +143,8 @@ static int virtex2_info(xilinx_desc *desc)
 }
 
 /*
- * Virtex-II Slave SelectMap configuration loader. Configuration via
- * SelectMap is as follows:
+ * Virtex-II Slave SelectMap or Serial configuration loader. Configuration
+ * is as follows:
  * 1. Set the FPGA's PROG_B line low.
  * 2. Set the FPGA's PROG_B line high.  Wait for INIT_B to go high.
  * 3. Write data to the SelectMap port.  If INIT_B goes low at any time
@@ -154,7 +156,7 @@ static int virtex2_info(xilinx_desc *desc)
  *    INIT_B and DONE lines.  If both are high, configuration has
  *    succeeded. Congratulations!
  */
-static int virtex2_slave_pre(xilinx_virtex2_slave_selectmap_fns *fn, int cookie)
+static int virtex2_slave_pre(xilinx_virtex2_slave_fns *fn, int cookie)
 {
 	unsigned long ts;
 
@@ -243,7 +245,7 @@ static int virtex2_slave_pre(xilinx_virtex2_slave_selectmap_fns *fn, int cookie)
 	return FPGA_SUCCESS;
 }
 
-static int virtex2_slave_post(xilinx_virtex2_slave_selectmap_fns *fn,
+static int virtex2_slave_post(xilinx_virtex2_slave_fns *fn,
 			      int cookie)
 {
 	int ret_val = FPGA_SUCCESS;
@@ -284,11 +286,16 @@ static int virtex2_slave_post(xilinx_virtex2_slave_selectmap_fns *fn,
 			ret_val = FPGA_FAIL;
 			break;
 		}
-		(*fn->wdata) (0xff, true, cookie);
-		CONFIG_FPGA_DELAY();
-		(*fn->clk) (false, true, cookie);
-		CONFIG_FPGA_DELAY();
-		(*fn->clk) (true, true, cookie);
+		if (fn->wbulkdata) {
+			unsigned char dummy = 0xff;
+			(*fn->wbulkdata)(&dummy, 1, true, cookie);
+		} else {
+			(*fn->wdata)(0xff, true, cookie);
+			CONFIG_FPGA_DELAY();
+			(*fn->clk)(false, true, cookie);
+			CONFIG_FPGA_DELAY();
+			(*fn->clk)(true, true, cookie);
+		}
 	}
 
 	if (ret_val == FPGA_SUCCESS) {
@@ -312,7 +319,7 @@ static int virtex2_slave_post(xilinx_virtex2_slave_selectmap_fns *fn,
 static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize)
 {
 	int ret_val = FPGA_FAIL;
-	xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns;
+	xilinx_virtex2_slave_fns *fn = desc->iface_fns;
 	size_t bytecount = 0;
 	unsigned char *data = (unsigned char *)buf;
 	int cookie = desc->cookie;
@@ -387,7 +394,7 @@ static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize)
 static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize)
 {
 	int ret_val = FPGA_FAIL;
-	xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns;
+	xilinx_virtex2_slave_fns *fn = desc->iface_fns;
 
 	if (fn) {
 		unsigned char *data = (unsigned char *)buf;
@@ -438,8 +445,71 @@ static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize)
 
 static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize)
 {
-	printf("%s: Slave Serial Loading is unsupported\n", __func__);
-	return FPGA_FAIL;
+	int ret_val = FPGA_FAIL;
+	xilinx_virtex2_slave_fns *fn = desc->iface_fns;
+	unsigned char *data = (unsigned char *)buf;
+	int cookie = desc->cookie;
+
+	ret_val = virtex2_slave_pre(fn, cookie);
+	if (ret_val != FPGA_SUCCESS)
+		return ret_val;
+
+	if (fn->wbulkdata) {
+		/* Load the data in a single chunk */
+		(*fn->wbulkdata)(data, bsize, true, cookie);
+	} else {
+		size_t bytecount = 0;
+
+		/*
+		 * Load the data bit by bit
+		 */
+		while (bytecount < bsize) {
+			unsigned char curr_data = data[bytecount++];
+			int bit;
+
+#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
+			if (ctrlc()) {
+				(*fn->abort) (cookie);
+				return FPGA_FAIL;
+			}
+#endif
+
+			if ((*fn->done)(cookie) == FPGA_SUCCESS) {
+				PRINTF("%s:%d:done went active early, bytecount = %d\n",
+				       __func__, __LINE__, bytecount);
+				break;
+			}
+
+#ifdef CONFIG_SYS_FPGA_CHECK_ERROR
+			if ((*fn->init)(cookie)) {
+				printf("\n%s:%d:  ** Error: INIT asserted during configuration\n",
+				       __func__, __LINE__);
+				printf("%zu = buffer offset, %zu = buffer size\n",
+				       bytecount, bsize);
+				(*fn->abort)(cookie);
+				return FPGA_FAIL;
+			}
+#endif
+
+			for (bit = 7; bit >= 0; --bit) {
+				unsigned char curr_bit = (curr_data >> bit) & 1;
+				(*fn->wdata)(curr_bit, true, cookie);
+				CONFIG_FPGA_DELAY();
+				(*fn->clk)(false, true, cookie);
+				CONFIG_FPGA_DELAY();
+				(*fn->clk)(true, true, cookie);
+			}
+
+			/* Slave serial never uses a busy pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+			if (bytecount % (bsize / 40) == 0)
+				putc('.');
+#endif
+		}
+	}
+
+	return virtex2_slave_post(fn, cookie);
 }
 
 static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize)
diff --git a/include/virtex2.h b/include/virtex2.h
index a481130..7e8d93f 100644
--- a/include/virtex2.h
+++ b/include/virtex2.h
@@ -11,7 +11,7 @@
 #include <xilinx.h>
 
 /*
- * Slave SelectMap Implementation function table.
+ * Slave SelectMap or Serial Implementation function table.
  */
 typedef struct {
 	xilinx_pre_fn	pre;
@@ -24,18 +24,11 @@ typedef struct {
 	xilinx_wr_fn	wr;
 	xilinx_rdata_fn	rdata;
 	xilinx_wdata_fn	wdata;
+	xilinx_bwr_fn   wbulkdata;
 	xilinx_busy_fn	busy;
 	xilinx_abort_fn	abort;
 	xilinx_post_fn	post;
-} xilinx_virtex2_slave_selectmap_fns;
-
-/* Slave Serial Implementation function table */
-typedef struct {
-	xilinx_pgm_fn	pgm;
-	xilinx_clk_fn	clk;
-	xilinx_rdata_fn	rdata;
-	xilinx_wdata_fn	wdata;
-} xilinx_virtex2_slave_serial_fns;
+} xilinx_virtex2_slave_fns;
 
 #if defined(CONFIG_FPGA_VIRTEX2)
 extern struct xilinx_fpga_op virtex2_op;
-- 
1.8.3.1



More information about the U-Boot mailing list