]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/fpga/zynqpl.c
Merge remote-tracking branch 'u-boot/master' into test
[karo-tx-uboot.git] / drivers / fpga / zynqpl.c
index 8cc16fd2c2db3da9c77dabbd1e2ad89cd9bb36eb..c066f21d79f323f17227b4001fa55358f9b14735 100644 (file)
@@ -4,12 +4,13 @@
  * (C) Copyright 2012
  * Joe Hershberger <joe.hershberger@ni.com>
  *
- * SPDX-License-Identifier:    GPL-2.0+ 
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <asm/io.h>
 #include <zynqpl.h>
+#include <linux/sizes.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/sys_proto.h>
 
@@ -23,6 +24,7 @@
 #define DEVCFG_STATUS_DMA_CMD_Q_E      0x40000000
 #define DEVCFG_STATUS_DMA_DONE_CNT_MASK        0x30000000
 #define DEVCFG_STATUS_PCFG_INIT                0x00000010
+#define DEVCFG_MCTRL_PCAP_LPBK         0x00000010
 #define DEVCFG_MCTRL_RFIFO_FLUSH       0x00000002
 #define DEVCFG_MCTRL_WFIFO_FLUSH       0x00000001
 
 #endif
 
 #ifndef CONFIG_SYS_FPGA_PROG_TIME
-#define CONFIG_SYS_FPGA_PROG_TIME CONFIG_SYS_HZ        /* 1 s */
+#define CONFIG_SYS_FPGA_PROG_TIME      (CONFIG_SYS_HZ * 4) /* 4 s */
 #endif
 
-int zynq_info(Xilinx_desc *desc)
+static int zynq_info(xilinx_desc *desc)
 {
        return FPGA_SUCCESS;
 }
@@ -145,60 +147,60 @@ static void *check_data(u8 *buf, size_t bsize, u32 *swap)
                }
                /* Loop can be huge - support CTRL + C */
                if (ctrlc())
-                       return 0;
+                       return NULL;
        }
-       return 0;
+       return NULL;
 }
 
-
-int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize)
+static int zynq_dma_transfer(u32 srcbuf, u32 srclen, u32 dstbuf, u32 dstlen)
 {
-       unsigned long ts; /* Timestamp */
-       u32 partialbit = 0;
-       u32 i, control, isr_status, status, swap, diff;
-       u32 *buf_start;
-
-       /* Detect if we are going working with partial or full bitstream */
-       if (bsize != desc->size) {
-               printf("%s: Working with partial bitstream\n", __func__);
-               partialbit = 1;
-       }
+       unsigned long ts;
+       u32 isr_status;
 
-       buf_start = check_data((u8 *)buf, bsize, &swap);
-       if (!buf_start)
-               return FPGA_FAIL;
+       /* Set up the transfer */
+       writel((u32)srcbuf, &devcfg_base->dma_src_addr);
+       writel(dstbuf, &devcfg_base->dma_dst_addr);
+       writel(srclen, &devcfg_base->dma_src_len);
+       writel(dstlen, &devcfg_base->dma_dst_len);
 
-       /* Check if data is postpone from start */
-       diff = (u32)buf_start - (u32)buf;
-       if (diff) {
-               printf("%s: Bitstream is not validated yet (diff %x)\n",
-                      __func__, diff);
-               return FPGA_FAIL;
-       }
+       isr_status = readl(&devcfg_base->int_sts);
 
-       if ((u32)buf_start & 0x3) {
-               u32 *new_buf = (u32 *)((u32)buf & ~0x3);
+       /* Polling the PCAP_INIT status for Set */
+       ts = get_timer(0);
+       while (!(isr_status & DEVCFG_ISR_DMA_DONE)) {
+               if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) {
+                       debug("%s: Error: isr = 0x%08X\n", __func__,
+                             isr_status);
+                       debug("%s: Write count = 0x%08X\n", __func__,
+                             readl(&devcfg_base->write_count));
+                       debug("%s: Read count = 0x%08X\n", __func__,
+                             readl(&devcfg_base->read_count));
 
-               printf("%s: Align buffer at %x to %x(swap %d)\n", __func__,
-                      (u32)buf_start, (u32)new_buf, swap);
+                       return FPGA_FAIL;
+               }
+               if (get_timer(ts) > CONFIG_SYS_FPGA_PROG_TIME) {
+                       printf("%s: Timeout wait for DMA to complete\n",
+                              __func__);
+                       return FPGA_FAIL;
+               }
+               isr_status = readl(&devcfg_base->int_sts);
+       }
 
-               for (i = 0; i < (bsize/4); i++)
-                       new_buf[i] = load_word(&buf_start[i], swap);
+       debug("%s: DMA transfer is done\n", __func__);
 
-               swap = SWAP_DONE;
-               buf = new_buf;
-       } else if (swap != SWAP_DONE) {
-               /* For bitstream which are aligned */
-               u32 *new_buf = (u32 *)buf;
+       /* Clear out the DMA status */
+       writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);
 
-               printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__,
-                      swap);
+       return FPGA_SUCCESS;
+}
 
-               for (i = 0; i < (bsize/4); i++)
-                       new_buf[i] = load_word(&buf_start[i], swap);
+static int zynq_dma_xfer_init(u32 partialbit)
+{
+       u32 status, control, isr_status;
+       unsigned long ts;
 
-               swap = SWAP_DONE;
-       }
+       /* Clear loopback bit */
+       clrbits_le32(&devcfg_base->mctrl, DEVCFG_MCTRL_PCAP_LPBK);
 
        if (!partialbit) {
                zynq_slcr_devcfg_disable();
@@ -277,40 +279,112 @@ int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize)
                writel(DEVCFG_STATUS_DMA_DONE_CNT_MASK, &devcfg_base->status);
        }
 
-       debug("%s: Source = 0x%08X\n", __func__, (u32)buf);
-       debug("%s: Size = %zu\n", __func__, bsize);
+       return FPGA_SUCCESS;
+}
 
-       /* Set up the transfer */
-       writel((u32)buf | 1, &devcfg_base->dma_src_addr);
-       writel(0xFFFFFFFF, &devcfg_base->dma_dst_addr);
-       writel(bsize >> 2, &devcfg_base->dma_src_len);
-       writel(0, &devcfg_base->dma_dst_len);
+static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap)
+{
+       u32 *new_buf;
+       u32 i;
 
-       isr_status = readl(&devcfg_base->int_sts);
+       if ((u32)buf != ALIGN((u32)buf, ARCH_DMA_MINALIGN)) {
+               new_buf = (u32 *)ALIGN((u32)buf, ARCH_DMA_MINALIGN);
 
-       /* Polling the PCAP_INIT status for Set */
-       ts = get_timer(0);
-       while (!(isr_status & DEVCFG_ISR_DMA_DONE)) {
-               if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) {
-                       debug("%s: Error: isr = 0x%08X\n", __func__,
-                             isr_status);
-                       debug("%s: Write count = 0x%08X\n", __func__,
-                             readl(&devcfg_base->write_count));
-                       debug("%s: Read count = 0x%08X\n", __func__,
-                             readl(&devcfg_base->read_count));
-
-                       return FPGA_FAIL;
-               }
-               if (get_timer(ts) > CONFIG_SYS_FPGA_PROG_TIME) {
-                       printf("%s: Timeout wait for DMA to complete\n",
-                              __func__);
-                       return FPGA_FAIL;
+               /*
+                * This might be dangerous but permits to flash if
+                * ARCH_DMA_MINALIGN is greater than header size
+                */
+               if (new_buf > buf) {
+                       debug("%s: Aligned buffer is after buffer start\n",
+                             __func__);
+                       new_buf -= ARCH_DMA_MINALIGN;
                }
-               isr_status = readl(&devcfg_base->int_sts);
+               printf("%s: Align buffer at %x to %x(swap %d)\n", __func__,
+                      (u32)buf, (u32)new_buf, swap);
+
+               for (i = 0; i < (len/4); i++)
+                       new_buf[i] = load_word(&buf[i], swap);
+
+               buf = new_buf;
+       } else if (swap != SWAP_DONE) {
+               /* For bitstream which are aligned */
+               u32 *new_buf = (u32 *)buf;
+
+               printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__,
+                      swap);
+
+               for (i = 0; i < (len/4); i++)
+                       new_buf[i] = load_word(&buf[i], swap);
        }
 
-       debug("%s: DMA transfer is done\n", __func__);
+       return buf;
+}
+
+static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf,
+                                  size_t bsize, u32 blocksize, u32 *swap,
+                                  u32 *partialbit)
+{
+       u32 *buf_start;
+       u32 diff;
+
+       /* Detect if we are going working with partial or full bitstream */
+       if (bsize != desc->size) {
+               printf("%s: Working with partial bitstream\n", __func__);
+               *partialbit = 1;
+       }
+       buf_start = check_data((u8 *)buf, blocksize, swap);
+
+       if (!buf_start)
+               return FPGA_FAIL;
 
+       /* Check if data is postpone from start */
+       diff = (u32)buf_start - (u32)buf;
+       if (diff) {
+               printf("%s: Bitstream is not validated yet (diff %x)\n",
+                      __func__, diff);
+               return FPGA_FAIL;
+       }
+
+       if ((u32)buf < SZ_1M) {
+               printf("%s: Bitstream has to be placed up to 1MB (%x)\n",
+                      __func__, (u32)buf);
+               return FPGA_FAIL;
+       }
+
+       if (zynq_dma_xfer_init(*partialbit))
+               return FPGA_FAIL;
+
+       return 0;
+}
+
+
+static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+       unsigned long ts; /* Timestamp */
+       u32 partialbit = 0;
+       u32 isr_status, swap;
+
+       /*
+        * send bsize inplace of blocksize as it was not a bitstream
+        * in chunks
+        */
+       if (zynq_validate_bitstream(desc, buf, bsize, bsize, &swap,
+                                   &partialbit))
+               return FPGA_FAIL;
+
+       buf = zynq_align_dma_buffer((u32 *)buf, bsize, swap);
+
+       debug("%s: Source = 0x%08X\n", __func__, (u32)buf);
+       debug("%s: Size = %zu\n", __func__, bsize);
+
+       /* flush(clean & invalidate) d-cache range buf */
+       flush_dcache_range((u32)buf, (u32)buf +
+                          roundup(bsize, ARCH_DMA_MINALIGN));
+
+       if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0))
+               return FPGA_FAIL;
+
+       isr_status = readl(&devcfg_base->int_sts);
        /* Check FPGA configuration completion */
        ts = get_timer(0);
        while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
@@ -324,16 +398,19 @@ int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize)
 
        debug("%s: FPGA config done\n", __func__);
 
-       /* Clear out the DMA status */
-       writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);
-
        if (!partialbit)
                zynq_slcr_devcfg_enable();
 
        return FPGA_SUCCESS;
 }
 
-int zynq_dump(Xilinx_desc *desc, const void *buf, size_t bsize)
+static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize)
 {
        return FPGA_FAIL;
 }
+
+struct xilinx_fpga_op zynq_op = {
+       .load = zynq_load,
+       .dump = zynq_dump,
+       .info = zynq_info,
+};