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@enterasys.com.
  * Keith Outwater, keith_outwater@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;
