efi_loader: round the memory area in efi_add_memory_map()
[oweals/u-boot.git] / drivers / fpga / zynqpl.c
index c066f21d79f323f17227b4001fa55358f9b14735..21624f715ba0092a7dc9206966fa6bb21f0a81b9 100644 (file)
@@ -1,20 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2012-2013, Xilinx, Michal Simek
  *
  * (C) Copyright 2012
  * Joe Hershberger <joe.hershberger@ni.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
+#include <console.h>
+#include <cpu_func.h>
 #include <asm/io.h>
+#include <fs.h>
 #include <zynqpl.h>
 #include <linux/sizes.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/sys_proto.h>
 
 #define DEVCFG_CTRL_PCFG_PROG_B                0x40000000
+#define DEVCFG_CTRL_PCFG_AES_EFUSE_MASK        0x00001000
+#define DEVCFG_CTRL_PCAP_RATE_EN_MASK  0x02000000
 #define DEVCFG_ISR_FATAL_ERROR_MASK    0x00740040
 #define DEVCFG_ISR_ERROR_FLAGS_MASK    0x00340840
 #define DEVCFG_ISR_RX_FIFO_OV          0x00040000
 #define CONFIG_SYS_FPGA_PROG_TIME      (CONFIG_SYS_HZ * 4) /* 4 s */
 #endif
 
-static int zynq_info(xilinx_desc *desc)
-{
-       return FPGA_SUCCESS;
-}
-
 #define DUMMY_WORD     0xffffffff
 
 /* Xilinx binary format header */
@@ -194,7 +193,7 @@ static int zynq_dma_transfer(u32 srcbuf, u32 srclen, u32 dstbuf, u32 dstlen)
        return FPGA_SUCCESS;
 }
 
-static int zynq_dma_xfer_init(u32 partialbit)
+static int zynq_dma_xfer_init(bitstream_type bstype)
 {
        u32 status, control, isr_status;
        unsigned long ts;
@@ -202,15 +201,30 @@ static int zynq_dma_xfer_init(u32 partialbit)
        /* Clear loopback bit */
        clrbits_le32(&devcfg_base->mctrl, DEVCFG_MCTRL_PCAP_LPBK);
 
-       if (!partialbit) {
+       if (bstype != BIT_PARTIAL) {
                zynq_slcr_devcfg_disable();
 
                /* Setting PCFG_PROG_B signal to high */
                control = readl(&devcfg_base->ctrl);
                writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+
+               /*
+                * Delay is required if AES efuse is selected as
+                * key source.
+                */
+               if (control & DEVCFG_CTRL_PCFG_AES_EFUSE_MASK)
+                       mdelay(5);
+
                /* Setting PCFG_PROG_B signal to low */
                writel(control & ~DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
 
+               /*
+                * Delay is required if AES efuse is selected as
+                * key source.
+                */
+               if (control & DEVCFG_CTRL_PCFG_AES_EFUSE_MASK)
+                       mdelay(5);
+
                /* Polling the PCAP_INIT status for Reset */
                ts = get_timer(0);
                while (readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT) {
@@ -322,16 +336,11 @@ static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap)
 
 static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf,
                                   size_t bsize, u32 blocksize, u32 *swap,
-                                  u32 *partialbit)
+                                  bitstream_type *bstype)
 {
        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)
@@ -351,17 +360,16 @@ static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf,
                return FPGA_FAIL;
        }
 
-       if (zynq_dma_xfer_init(*partialbit))
+       if (zynq_dma_xfer_init(*bstype))
                return FPGA_FAIL;
 
        return 0;
 }
 
-
-static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
+static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize,
+                    bitstream_type bstype)
 {
        unsigned long ts; /* Timestamp */
-       u32 partialbit = 0;
        u32 isr_status, swap;
 
        /*
@@ -369,7 +377,7 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
         * in chunks
         */
        if (zynq_validate_bitstream(desc, buf, bsize, bsize, &swap,
-                                   &partialbit))
+                                   &bstype))
                return FPGA_FAIL;
 
        buf = zynq_align_dma_buffer((u32 *)buf, bsize, swap);
@@ -398,19 +406,143 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
 
        debug("%s: FPGA config done\n", __func__);
 
-       if (!partialbit)
+       if (bstype != BIT_PARTIAL)
                zynq_slcr_devcfg_enable();
 
+       puts("INFO:post config was not run, please run manually if needed\n");
+
        return FPGA_SUCCESS;
 }
 
-static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_SPL_BUILD)
+static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+                      fpga_fs_info *fsinfo)
 {
-       return FPGA_FAIL;
+       unsigned long ts; /* Timestamp */
+       u32 isr_status, swap;
+       u32 partialbit = 0;
+       loff_t blocksize, actread;
+       loff_t pos = 0;
+       int fstype;
+       char *interface, *dev_part;
+       const char *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, &actread) < 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, &actread) < 0)
+                               return FPGA_FAIL;
+               } else {
+                       if (fs_read(filename, (u32) buf, pos, bsize, &actread) < 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
 
 struct xilinx_fpga_op zynq_op = {
        .load = zynq_load,
-       .dump = zynq_dump,
-       .info = zynq_info,
+#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_SPL_BUILD)
+       .loadfs = zynq_loadfs,
+#endif
 };
+
+#ifdef CONFIG_CMD_ZYNQ_AES
+/*
+ * Load the encrypted image from src addr and decrypt the image and
+ * place it back the decrypted image into dstaddr.
+ */
+int zynq_decrypt_load(u32 srcaddr, u32 srclen, u32 dstaddr, u32 dstlen)
+{
+       if (srcaddr < SZ_1M || dstaddr < SZ_1M) {
+               printf("%s: src and dst addr should be > 1M\n",
+                      __func__);
+               return FPGA_FAIL;
+       }
+
+       if (zynq_dma_xfer_init(BIT_NONE)) {
+               printf("%s: zynq_dma_xfer_init FAIL\n", __func__);
+               return FPGA_FAIL;
+       }
+
+       writel((readl(&devcfg_base->ctrl) | DEVCFG_CTRL_PCAP_RATE_EN_MASK),
+              &devcfg_base->ctrl);
+
+       debug("%s: Source = 0x%08X\n", __func__, (u32)srcaddr);
+       debug("%s: Size = %zu\n", __func__, srclen);
+
+       /* flush(clean & invalidate) d-cache range buf */
+       flush_dcache_range((u32)srcaddr, (u32)srcaddr +
+                       roundup(srclen << 2, ARCH_DMA_MINALIGN));
+       /*
+        * Flush destination address range only if image is not
+        * bitstream.
+        */
+       flush_dcache_range((u32)dstaddr, (u32)dstaddr +
+                          roundup(dstlen << 2, ARCH_DMA_MINALIGN));
+
+       if (zynq_dma_transfer(srcaddr | 1, srclen, dstaddr | 1, dstlen))
+               return FPGA_FAIL;
+
+       writel((readl(&devcfg_base->ctrl) & ~DEVCFG_CTRL_PCAP_RATE_EN_MASK),
+              &devcfg_base->ctrl);
+
+       return FPGA_SUCCESS;
+}
+#endif