fpga: Added support to load bit stream from SD/MMC

Added support to load a bitstream image in chunks by reading it in
chunks from SD/MMC.
Command format:
loadfs [dev] [address] [image size] [blocksize] <interface>
       [<dev[:part]>] <filename>
Example: fpga loadfs 0 1000000 3dbafc 4000 mmc 0 fpga.bin

Signed-off-by: Siva Durga Prasad Paladugu <sivadur@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c
index e770950..37946d5 100644
--- a/drivers/fpga/fpga.c
+++ b/drivers/fpga/fpga.c
@@ -180,6 +180,34 @@
 	return FPGA_FAIL;
 }
 
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+int fpga_fsload(int devnum, const void *buf, size_t size,
+		 fpga_fs_info *fpga_fsinfo)
+{
+	int ret_val = FPGA_FAIL;           /* assume failure */
+	const fpga_desc *desc = fpga_validate(devnum, buf, size,
+					      (char *)__func__);
+
+	if (desc) {
+		switch (desc->devtype) {
+		case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+			ret_val = xilinx_loadfs(desc->devdesc, buf, size,
+						fpga_fsinfo);
+#else
+			fpga_no_sup((char *)__func__, "Xilinx devices");
+#endif
+			break;
+		default:
+			printf("%s: Invalid or unsupported device type %d\n",
+			       __func__, desc->devtype);
+		}
+	}
+
+	return ret_val;
+}
+#endif
+
 /*
  * Generic multiplexing code
  */
diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c
index ab9f517..3795c1a 100644
--- a/drivers/fpga/xilinx.c
+++ b/drivers/fpga/xilinx.c
@@ -142,6 +142,22 @@
 	return desc->operations->load(desc, buf, bsize, bstype);
 }
 
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+int xilinx_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+		   fpga_fs_info *fpga_fsinfo)
+{
+	if (!xilinx_validate(desc, (char *)__func__)) {
+		printf("%s: Invalid device descriptor\n", __func__);
+		return FPGA_FAIL;
+	}
+
+	if (!desc->operations->loadfs)
+		return FPGA_FAIL;
+
+	return desc->operations->loadfs(desc, buf, bsize, fpga_fsinfo);
+}
+#endif
+
 int xilinx_dump(xilinx_desc *desc, const void *buf, size_t bsize)
 {
 	if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
index 915f077..68fe0f3 100644
--- a/drivers/fpga/zynqpl.c
+++ b/drivers/fpga/zynqpl.c
@@ -9,6 +9,7 @@
 
 #include <common.h>
 #include <asm/io.h>
+#include <fs.h>
 #include <zynqpl.h>
 #include <linux/sizes.h>
 #include <asm/arch/hardware.h>
@@ -398,6 +399,87 @@
 	return FPGA_SUCCESS;
 }
 
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+		       fpga_fs_info *fsinfo)
+{
+	unsigned long ts; /* Timestamp */
+	u32 isr_status, swap;
+	u32 partialbit = 0;
+	u32 blocksize;
+	u32 pos = 0;
+	int fstype;
+	char *interface, *dev_part, *filename;
+
+	blocksize = fsinfo->blocksize;
+	interface = fsinfo->interface;
+	dev_part = fsinfo->dev_part;
+	filename = fsinfo->filename;
+	fstype = fsinfo->fstype;
+
+	if (fs_set_blk_dev(interface, dev_part, fstype))
+		return FPGA_FAIL;
+
+	if (fs_read(filename, (u32) buf, pos, blocksize) < 0)
+		return FPGA_FAIL;
+
+	if (zynq_validate_bitstream(desc, buf, bsize, blocksize, &swap,
+				    &partialbit))
+		return FPGA_FAIL;
+
+	dcache_disable();
+
+	do {
+		buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
+
+		if (zynq_dma_transfer((u32)buf | 1, blocksize >> 2,
+				      0xffffffff, 0))
+			return FPGA_FAIL;
+
+		bsize -= blocksize;
+		pos   += blocksize;
+
+		if (fs_set_blk_dev(interface, dev_part, fstype))
+			return FPGA_FAIL;
+
+		if (bsize > blocksize) {
+			if (fs_read(filename, (u32) buf, pos, blocksize) < 0)
+				return FPGA_FAIL;
+		} else {
+			if (fs_read(filename, (u32) buf, pos, bsize) < 0)
+				return FPGA_FAIL;
+		}
+	} while (bsize > blocksize);
+
+	buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
+
+	if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0))
+		return FPGA_FAIL;
+
+	dcache_enable();
+
+	isr_status = readl(&devcfg_base->int_sts);
+
+	/* Check FPGA configuration completion */
+	ts = get_timer(0);
+	while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
+		if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
+			printf("%s: Timeout wait for FPGA to config\n",
+			       __func__);
+			return FPGA_FAIL;
+		}
+		isr_status = readl(&devcfg_base->int_sts);
+	}
+
+	debug("%s: FPGA config done\n", __func__);
+
+	if (!partialbit)
+		zynq_slcr_devcfg_enable();
+
+	return FPGA_SUCCESS;
+}
+#endif
+
 static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize)
 {
 	return FPGA_FAIL;
@@ -405,6 +487,9 @@
 
 struct xilinx_fpga_op zynq_op = {
 	.load = zynq_load,
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+	.loadfs = zynq_loadfs,
+#endif
 	.dump = zynq_dump,
 	.info = zynq_info,
 };