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/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,
 };