]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
Xilinx: ARM: fpga: Add a driver to configure the Zynq PL
authorJoe Hershberger <joe.hershberger@ni.com>
Thu, 31 May 2012 01:33:51 +0000 (20:33 -0500)
committerJohn Linn <john.linn@xilinx.com>
Fri, 1 Jun 2012 21:41:07 +0000 (14:41 -0700)
Add support for configuring the programmable logic on a ZC7Z020
from within u-boot using fpga command

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
drivers/fpga/Makefile
drivers/fpga/xilinx.c
drivers/fpga/zynqpl.c [new file with mode: 0644]
include/xilinx.h
include/zynqpl.h [new file with mode: 0644]

index b48f623c180364f600d45edf5cb584d1f3c32041..0b51dcdef370c585048fd5595707f7e5c4cab732 100644 (file)
@@ -30,6 +30,7 @@ COBJS-y += fpga.o
 COBJS-$(CONFIG_FPGA_SPARTAN2) += spartan2.o
 COBJS-$(CONFIG_FPGA_SPARTAN3) += spartan3.o
 COBJS-$(CONFIG_FPGA_VIRTEX2) += virtex2.o
+COBJS-$(CONFIG_FPGA_ZYNQPL) += zynqpl.o
 COBJS-$(CONFIG_FPGA_XILINX) += xilinx.o
 COBJS-$(CONFIG_FPGA_LATTICE) += ivm_core.o lattice.o
 ifdef CONFIG_FPGA_ALTERA
index 08dfdecdee3f29d1a47be0fa1750b8cdaa5fdfcb..dd124e00e8137d120a8e3cc43366fe54044664d5 100644 (file)
@@ -31,6 +31,7 @@
 #include <virtex2.h>
 #include <spartan2.h>
 #include <spartan3.h>
+#include <zynqpl.h>
 
 #if 0
 #define FPGA_DEBUG
@@ -84,6 +85,16 @@ int xilinx_load (Xilinx_desc * desc, void *buf, size_t bsize)
 #else
                        printf ("%s: No support for Virtex-II devices.\n",
                                        __FUNCTION__);
+#endif
+                       break;
+               case Xilinx_Zynq:
+#if defined(CONFIG_FPGA_ZYNQPL)
+                       PRINTF("%s: Launching the Zynq PL Loader...\n",
+                                       __func__);
+                       ret_val = zynq_load(desc, buf, bsize);
+#else
+                       printf("%s: No support for Zynq devices.\n",
+                                       __func__);
 #endif
                        break;
 
@@ -131,6 +142,16 @@ int xilinx_dump (Xilinx_desc * desc, void *buf, size_t bsize)
 #else
                        printf ("%s: No support for Virtex-II devices.\n",
                                        __FUNCTION__);
+#endif
+                       break;
+               case Xilinx_Zynq:
+#if defined(CONFIG_FPGA_ZYNQPL)
+                       PRINTF("%s: Launching the Zynq PL Reader...\n",
+                                       __func__);
+                       ret_val = zynq_dump(desc, buf, bsize);
+#else
+                       printf("%s: No support for Zynq devices.\n",
+                                       __func__);
 #endif
                        break;
 
@@ -158,6 +179,9 @@ int xilinx_info (Xilinx_desc * desc)
                case Xilinx_Virtex2:
                        printf ("Virtex-II\n");
                        break;
+               case Xilinx_Zynq:
+                       printf("Zynq PL\n");
+                       break;
                        /* Add new family types here */
                default:
                        printf ("Unknown family type, %d\n", desc->family);
@@ -183,6 +207,9 @@ int xilinx_info (Xilinx_desc * desc)
                case master_selectmap:
                        printf ("Master SelectMap Mode\n");
                        break;
+               case devcfg:
+                       printf("Device configuration interface (Zynq)\n");
+                       break;
                        /* Add new interface types here */
                default:
                        printf ("Unsupported interface type, %d\n", desc->iface);
@@ -222,6 +249,14 @@ int xilinx_info (Xilinx_desc * desc)
                                                __FUNCTION__);
 #endif
                                break;
+                       case Xilinx_Zynq:
+#if defined(CONFIG_FPGA_ZYNQPL)
+                               zynq_info(desc);
+#else
+                               /* just in case */
+                               printf("%s: No support for Zynq devices.\n",
+                                               __func__);
+#endif
                                /* Add new family types here */
                        default:
                                /* we don't need a message here - we give one up above */
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
new file mode 100644 (file)
index 0000000..5367bfb
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger <joe.hershberger@ni.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <zynqpl.h>
+
+#ifndef CONFIG_SYS_FPGA_WAIT
+#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
+#endif
+
+#ifndef CONFIG_SYS_FPGA_PROG_TIME
+#define CONFIG_SYS_FPGA_PROG_TIME CONFIG_SYS_HZ        /* 1 s */
+#endif
+
+#define SLCR_BASEADDR 0xF8000000
+#define SLCR_LOCK (SLCR_BASEADDR + 0x04)
+#define SLCR_LOCK_VALUE 0x767B
+#define SLCR_UNLOCK (SLCR_BASEADDR + 0x08)
+#define SLCR_UNLOCK_VALUE 0xDF0D
+#define SLCR_FPGA_RST_CTRL (SLCR_BASEADDR + 0x240)
+#define SLCR_LVL_SHFTR_EN (SLCR_BASEADDR + 0x900)
+
+#define DEVCFG_BASEADDR 0xF8007000
+#define DEVCFG_CTRL (DEVCFG_BASEADDR + 0x00)
+#define DEVCFG_CTRL_PCFG_PROG_B 0x40000000
+#define DEVCFG_LOCK (DEVCFG_BASEADDR + 0x04)
+#define DEVCFG_CFG (DEVCFG_BASEADDR + 0x08)
+#define DEVCFG_ISR (DEVCFG_BASEADDR + 0x0C)
+#define DEVCFG_ISR_FATAL_ERROR_MASK 0x00740040
+#define DEVCFG_ISR_ERROR_FLAGS_MASK 0x00340840
+#define DEVCFG_ISR_RX_FIFO_OV 0x00040000
+#define DEVCFG_ISR_DMA_DONE 0x00002000
+#define DEVCFG_ISR_PCFG_DONE 0x00000004
+#define DEVCFG_STATUS (DEVCFG_BASEADDR + 0x14)
+#define DEVCFG_STATUS_DMA_CMD_Q_F 0x80000000
+#define DEVCFG_STATUS_DMA_CMD_Q_E 0x40000000
+#define DEVCFG_STATUS_DMA_DONE_CNT_MASK 0x30000000
+#define DEVCFG_STATUS_PCFG_INIT 0x00000010
+#define DEVCFG_DMA_SRC_ADDR (DEVCFG_BASEADDR + 0x18)
+#define DEVCFG_DMA_DST_ADDR (DEVCFG_BASEADDR + 0x1C)
+#define DEVCFG_DMA_SRC_LEN (DEVCFG_BASEADDR + 0x20)
+#define DEVCFG_DMA_DEST_LEN (DEVCFG_BASEADDR + 0x24)
+#define DEVCFG_MCTRL (DEVCFG_BASEADDR + 0x80)
+#define DEVCFG_MCTRL_RFIFO_FLUSH 0x00000002
+#define DEVCFG_MCTRL_WFIFO_FLUSH 0x00000001
+#define DEVCFG_DEBUG_XFER_WRITE_COUNT (DEVCFG_BASEADDR + 0x88)
+#define DEVCFG_DEBUG_XFER_READ_COUNT (DEVCFG_BASEADDR + 0x8C)
+
+/* ------------------------------------------------------------------------- */
+/* Zynq Implementation */
+
+int zynq_info(Xilinx_desc *desc)
+{
+       return FPGA_SUCCESS;
+}
+
+int zynq_load(Xilinx_desc *desc, void *buf, size_t bsize)
+{
+       unsigned long ts;               /* timestamp */
+       u32 control;
+       u32 isr_status;
+       u32 status;
+
+       out_le32(SLCR_UNLOCK, SLCR_UNLOCK_VALUE);
+       out_le32(SLCR_FPGA_RST_CTRL, 0xFFFFFFFF); /* Disable AXI interface */
+       /* Set Level Shifters DT618760*/
+       out_le32(SLCR_LVL_SHFTR_EN, 0x0000000A);
+       /* Setting PCFG_PROG_B signal to high */
+       control = in_le32(DEVCFG_CTRL);
+       out_le32(DEVCFG_CTRL, control | DEVCFG_CTRL_PCFG_PROG_B);
+       /* Setting PCFG_PROG_B signal to low */
+       out_le32(DEVCFG_CTRL, control & ~DEVCFG_CTRL_PCFG_PROG_B);
+
+       /* Polling the PCAP_INIT status for Reset */
+       ts = get_timer(0);
+       while (in_le32(DEVCFG_STATUS) & DEVCFG_STATUS_PCFG_INIT) {
+               if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
+                       puts("Error: Timeout waiting for INIT to clear.\n");
+                       return FPGA_FAIL;
+               }
+       }
+
+       /* Setting PCFG_PROG_B signal to high */
+       out_le32(DEVCFG_CTRL, control | DEVCFG_CTRL_PCFG_PROG_B);
+
+       /* Polling the PCAP_INIT status for Set */
+       ts = get_timer(0);
+       while (!(in_le32(DEVCFG_STATUS) & DEVCFG_STATUS_PCFG_INIT)) {
+               if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
+                       puts("Error: Timeout waiting for INIT to set.\n");
+                       return FPGA_FAIL;
+               }
+       }
+
+       out_le32(SLCR_LOCK, SLCR_LOCK_VALUE);
+
+       isr_status = in_le32(DEVCFG_ISR);
+
+       /* Clear it all, so if Boot ROM comes back, it can proceed */
+       out_le32(DEVCFG_ISR, 0xFFFFFFFF);
+
+       if (isr_status & DEVCFG_ISR_FATAL_ERROR_MASK) {
+               debug("Fatal errors in PCAP 0x%X\n", isr_status);
+
+               /* If RX FIFO overflow, need to flush RX FIFO first */
+               if (isr_status & DEVCFG_ISR_RX_FIFO_OV) {
+                       out_le32(DEVCFG_MCTRL, DEVCFG_MCTRL_RFIFO_FLUSH);
+                       out_le32(DEVCFG_ISR, 0xFFFFFFFF);
+               }
+               return FPGA_FAIL;
+       }
+
+       status = in_le32(DEVCFG_STATUS);
+
+       debug("status = 0x%08X\n", status);
+
+       if (status & DEVCFG_STATUS_DMA_CMD_Q_F) {
+               debug("Error: device busy\n");
+               return FPGA_FAIL;
+       }
+
+       debug("device ready\n");
+
+       if (!(status & DEVCFG_STATUS_DMA_CMD_Q_E)) {
+               if (!(in_le32(DEVCFG_ISR) & DEVCFG_ISR_DMA_DONE)) {
+                       /* error state, transfer cannot occur */
+                       debug("isr indicates error\n");
+                       return FPGA_FAIL;
+               } else {
+                       /* clear out the status */
+                       out_le32(DEVCFG_ISR, DEVCFG_ISR_DMA_DONE);
+               }
+       }
+
+       if (status & DEVCFG_STATUS_DMA_DONE_CNT_MASK) {
+               /* Clear the count of completed DMA transfers */
+               out_le32(DEVCFG_STATUS, DEVCFG_STATUS_DMA_DONE_CNT_MASK);
+       }
+
+       debug("Source = 0x%08X\n", (u32)buf);
+       debug("Size = %zu\n", bsize);
+
+       /* set up the transfer */
+       out_le32(DEVCFG_DMA_SRC_ADDR, (u32)buf | 1);
+       out_le32(DEVCFG_DMA_DST_ADDR, 0xFFFFFFFF);
+       out_le32(DEVCFG_DMA_SRC_LEN, bsize >> 2);
+       out_le32(DEVCFG_DMA_DEST_LEN, 0);
+
+       isr_status = in_le32(DEVCFG_ISR);
+
+       /* 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("Error: isr = 0x%08X\n", isr_status);
+                       debug("Write count = 0x%08X\n",
+                               in_le32(DEVCFG_DEBUG_XFER_WRITE_COUNT));
+                       debug("Read count = 0x%08X\n",
+                               in_le32(DEVCFG_DEBUG_XFER_READ_COUNT));
+
+                       return FPGA_FAIL;
+               }
+               if (get_timer(ts) > CONFIG_SYS_FPGA_PROG_TIME) {
+                       puts("Error: Timeout waiting for DMA to complete.\n");
+                       return FPGA_FAIL;
+               }
+               isr_status = in_le32(DEVCFG_ISR);
+       }
+
+       debug("DMA transfer is done\n");
+
+       /* Check FPGA configuration completion */
+       ts = get_timer(0);
+       while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
+               if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
+                       puts("Error: Timeout waiting for FPGA to config.\n");
+                       return FPGA_FAIL;
+               }
+               isr_status = in_le32(DEVCFG_ISR);
+       }
+
+       debug("FPGA config done\n");
+
+       /* clear out the DMA status */
+       out_le32(DEVCFG_ISR, DEVCFG_ISR_DMA_DONE);
+
+       out_le32(SLCR_UNLOCK, SLCR_UNLOCK_VALUE);
+
+       /* Set Level Shifters DT618760*/
+       out_le32(SLCR_LVL_SHFTR_EN, 0x0000000F);
+       /* Disable AXI interface */
+       out_le32(SLCR_FPGA_RST_CTRL, 0x00000000);
+
+       out_le32(SLCR_LOCK, SLCR_LOCK_VALUE);
+
+       return FPGA_SUCCESS;
+}
+
+int zynq_dump(Xilinx_desc *desc, void *buf, size_t bsize)
+{
+       return FPGA_FAIL;
+}
index 2cb2e5b6aadc60922751c1aafa702592f0ad7b8d..3b096aeec3fc3bc7e1968a52123d0cbccd7f65d1 100644 (file)
 #define CONFIG_SYS_VIRTEX_E                    CONFIG_SYS_FPGA_DEV( 0x2 )
 #define CONFIG_SYS_VIRTEX2                     CONFIG_SYS_FPGA_DEV( 0x4 )
 #define CONFIG_SYS_SPARTAN3                    CONFIG_SYS_FPGA_DEV( 0x8 )
+#define CONFIG_SYS_ZYNQ                                CONFIG_SYS_FPGA_DEV(0x10)
 #define CONFIG_SYS_XILINX_SPARTAN2     (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_SPARTAN2)
 #define CONFIG_SYS_XILINX_VIRTEX_E     (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_VIRTEX_E)
 #define CONFIG_SYS_XILINX_VIRTEX2      (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_VIRTEX2)
 #define CONFIG_SYS_XILINX_SPARTAN3     (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_SPARTAN3)
+#define CONFIG_SYS_XILINX_ZYNQ (CONFIG_SYS_FPGA_XILINX | CONFIG_SYS_ZYNQ)
 /* XXX - Add new models here */
 
 
@@ -59,6 +61,7 @@ typedef enum {                        /* typedef Xilinx_iface */
        jtag_mode,              /* jtag/tap serial (not used ) */
        master_selectmap,       /* master SelectMap (virtex2)           */
        slave_selectmap,        /* slave SelectMap (virtex2)            */
+       devcfg,                 /* devcfg interface (zynq) */
        max_xilinx_iface_type   /* insert all new types before this */
 } Xilinx_iface;                        /* end, typedef Xilinx_iface */
 
@@ -68,6 +71,7 @@ typedef enum {                        /* typedef Xilinx_Family */
        Xilinx_VirtexE,         /* Virtex-E Family */
        Xilinx_Virtex2,         /* Virtex2 Family */
        Xilinx_Spartan3,        /* Spartan-III Family */
+       Xilinx_Zynq,            /* Zynq Family */
        max_xilinx_type         /* insert all new types before this */
 } Xilinx_Family;               /* end, typedef Xilinx_Family */
 
diff --git a/include/zynqpl.h b/include/zynqpl.h
new file mode 100644 (file)
index 0000000..ceab19a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger <joe.hershberger@ni.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef _ZYNQPL_H_
+#define _ZYNQPL_H_
+
+#include <xilinx.h>
+
+extern int zynq_load(Xilinx_desc *desc, void *image, size_t size);
+extern int zynq_dump(Xilinx_desc *desc, void *buf, size_t bsize);
+extern int zynq_info(Xilinx_desc *desc);
+
+/* Device Image Sizes
+ *********************************************************************/
+#define XILINX_XC7Z020_SIZE    32364512/8
+
+/* Descriptor Macros
+ *********************************************************************/
+#define XILINX_XC7Z020_DESC(cookie) \
+{ Xilinx_Zynq, devcfg, XILINX_XC7Z020_SIZE, NULL, cookie }
+
+#endif /* _ZYNQPL_H_ */