mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 1/1] added support for zynq7000-fpga-manager
@ 2021-03-25  7:53 Michael Graichen
  2021-03-25  8:09 ` Ahmad Fatoum
  2021-03-25  8:42 ` Michael Tretter
  0 siblings, 2 replies; 6+ messages in thread
From: Michael Graichen @ 2021-03-25  7:53 UTC (permalink / raw)
  To: barebox; +Cc: Michael Tretter

Hey, 

i have reworked the ZynqMP FPGA manager to program the FPGA within the Zynq7000. 

Michael Tretter, would you be so kind an test this on your ZynqMP board?
Since I have no access to a ZynqMP chip I have only tested compiling. 

The name "ZynqMP" may now be missleading for the firmwareload tool, because I intended to use it on both, ZynqMP and Zynq7000.
I would be happy to get read your feedback.

Best Regards 
Michael 


Signed-off-by: Michael Graichen <michael.graichen@hotmail.com>
---
 arch/arm/configs/zynq_defconfig               |   2 +
 arch/arm/mach-zynq/Makefile                   |   2 +-
 arch/arm/mach-zynq/firmware-zynq.c            | 124 ++++++++++++++++++
 .../mach-zynq/include/mach/firmware-zynq.h    |  85 ++++++++++++
 .../include/mach/firmware-zynqmp.h            |  46 +++++++
 drivers/firmware/Kconfig                      |   7 +
 drivers/firmware/Makefile                     |   1 +
 drivers/firmware/zynqmp-fpga.c                | 115 ++++++++--------
 8 files changed, 324 insertions(+), 58 deletions(-)
 create mode 100644 arch/arm/mach-zynq/firmware-zynq.c
 create mode 100644 arch/arm/mach-zynq/include/mach/firmware-zynq.h

diff --git a/arch/arm/configs/zynq_defconfig b/arch/arm/configs/zynq_defconfig
index a16c57d5c..82ea899e2 100644
--- a/arch/arm/configs/zynq_defconfig
+++ b/arch/arm/configs/zynq_defconfig
@@ -36,6 +36,7 @@ CONFIG_CMD_MENU_MANAGEMENT=y
 CONFIG_CMD_READLINE=y
 CONFIG_CMD_TIMEOUT=y
 CONFIG_CMD_CLK=y
+CONFIG_CMD_FIRMWARELOAD=y
 CONFIG_CMD_OFTREE=y
 CONFIG_CMD_TIME=y
 CONFIG_NET=y
@@ -43,5 +44,6 @@ CONFIG_DRIVER_SERIAL_CADENCE=y
 CONFIG_DRIVER_NET_MACB=y
 # CONFIG_SPI is not set
 # CONFIG_PINCTRL is not set
+CONFIG_FIRMWARE_ZYNQ7000_FPGA=y
 CONFIG_FS_TFTP=y
 CONFIG_DIGEST=y
diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
index 06c2ce996..2484abe5c 100644
--- a/arch/arm/mach-zynq/Makefile
+++ b/arch/arm/mach-zynq/Makefile
@@ -1,2 +1,2 @@
-obj-y += zynq.o bootm-zynqimg.o
+obj-y += bootm-zynqimg.o firmware-zynq.o zynq.o
 lwl-y += cpu_init.o
diff --git a/arch/arm/mach-zynq/firmware-zynq.c b/arch/arm/mach-zynq/firmware-zynq.c
new file mode 100644
index 000000000..307b22fe5
--- /dev/null
+++ b/arch/arm/mach-zynq/firmware-zynq.c
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ */
+#include <common.h>
+#include <init.h>
+#include <linux/iopoll.h>
+#include <mach/firmware-zynq.h>
+
+/*
+ * zynq_devc_fpga_load - Perform the fpga load
+ * @mgr:	FPGA-Manager
+ * @address:	Address to write to
+ * @size:	PL bitstream size
+ * @flags:	Flags - unused
+ *
+ * This function provides access to PCAP to transfer
+ * the required bitstream into PL.
+ *
+ * Return:	Returns status, either success or error+reason
+ */
+static int zynq_devc_fpga_load(struct fpgamgr *mgr, u64 address,
+				u32 size, u32 flags)
+{
+	unsigned long reg;
+
+	if (!address || !size)
+		return -EINVAL;
+
+	/*
+	 * The Programming Seqenze, see ug585 (v.12.2) Juny 1, 2018 Chapter
+	 * 6.4.2 on page 211 Configure the PL via PCAP Bridge Example for
+	 * detailed information to this Sequenze
+	 */
+
+	/* Enable the PCAP bridge and select PCAP for reconfiguration */
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg |= ( CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK );
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	/* Clear the Interrupts */
+	writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
+
+	/* Initialize the PL */
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg |= CTRL_PCFG_PROG_B_MASK;
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg &= ~CTRL_PCFG_PROG_B_MASK;
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
+			!(reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
+
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg |= CTRL_PCFG_PROG_B_MASK;
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	/* Clear the Interrupts */
+	writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
+
+	/* Ensure that the PL is ready for programming */
+	readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
+			(reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
+
+	/* Check that there is room in the Command Queue */
+	readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
+			!(reg & STATUS_DMA_CMD_Q_F_MASK), 100 * USEC_PER_MSEC);
+
+	/* Disable the PCAP loopback */
+	reg = readl(mgr->regs + MCTRL_OFFSET);
+	reg &= ~MCTRL_INT_PCAP_LPBK_MASK;
+	writel(reg, mgr->regs + MCTRL_OFFSET);
+
+	/* Program the PCAP_2x clock divider */
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg &= ~CTRL_PCAP_RATE_EN_MASK;
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	/* Source Address: Location of bitstream */
+	writel(address, mgr->regs + DMA_SRC_ADDR_OFFSET);
+
+	/* Destination Address: 0xFFFF_FFFF */
+	writel(0xffffffff, mgr->regs + DMA_DST_ADDR_OFFSET);
+
+	/* Source Length: Total number of 32-bit words in the bitstream */
+	writel((size >> 2), mgr->regs + DMA_SRC_LEN_OFFSET);
+
+	/* Destination Length: Total number of 32-bit words in the bitstream */
+	writel((size >> 2), mgr->regs + DMA_DEST_LEN_OFFSET);
+
+	/* Wait for the DMA transfer to be done */
+	readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
+			(reg & INT_STS_D_P_DONE_MASK), 100 * USEC_PER_MSEC);
+
+	/* Check for errors */
+	if(reg & INT_STS_ERROR_FLAGS_MASK) {
+		printf("interrupt status register (0x%04lx)\n", reg);
+		return -EIO;
+	}
+
+	/* Wait for the DMA transfer to be done */
+	readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
+			(reg & INT_STS_DONE_INT_MASK), 100 * USEC_PER_MSEC);
+
+	printf("FPGA config done\n");
+
+	return 0;
+}
+
+static const struct zynq_devc_ops devc_ops = {
+	.fpga_load = zynq_devc_fpga_load,
+};
+
+/**
+ * zynq_get_devc_ops - Get devc ops functions
+ *
+ * Return: Pointer of devc_ops structure
+ */
+const struct zynq_devc_ops *zynq_get_devc_ops(void)
+{
+	return &devc_ops;
+}
+EXPORT_SYMBOL_GPL(zynq_get_devc_ops);
diff --git a/arch/arm/mach-zynq/include/mach/firmware-zynq.h b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
new file mode 100644
index 000000000..217b1e9b2
--- /dev/null
+++ b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Xilinx Zynq Firmware layer
+ *
+ */
+
+#ifndef FIRMWARE_ZYNQ_H_
+#define FIRMWARE_ZYNQ_H_
+
+#include <firmware.h>
+
+#define CTRL_OFFSET				0x00
+#define LOCK_OFFSET				0x04
+#define INT_STS_OFFSET				0x0c
+#define INT_MASK_OFFSET			0x10
+#define STATUS_OFFSET				0x14
+#define DMA_SRC_ADDR_OFFSET			0x18
+#define DMA_DST_ADDR_OFFSET			0x1c
+#define DMA_SRC_LEN_OFFSET			0x20
+#define DMA_DEST_LEN_OFFSET			0x24
+#define UNLOCK_OFFSET				0x34
+#define MCTRL_OFFSET				0x80
+
+#define CTRL_PCFG_PROG_B_MASK			BIT(30)
+#define CTRL_PCAP_PR_MASK			BIT(27)
+#define CTRL_PCAP_MODE_MASK			BIT(26)
+#define CTRL_PCAP_RATE_EN_MASK		BIT(25)
+
+#define STATUS_DMA_CMD_Q_F_MASK		BIT(31)
+#define STATUS_PCFG_INIT_MASK			BIT(4)
+
+#define INT_STS_D_P_DONE_MASK			BIT(12)
+#define INT_STS_DONE_INT_MASK			BIT(2)
+#define INT_STS_ERROR_FLAGS_MASK		0x00f4c860
+
+#define MCTRL_INT_PCAP_LPBK_MASK		BIT(4)
+
+/*
+ * Xilinx 7-Series Bitstream Composition:
+ *
+ * Bitstream can be provided with an optinal header (`struct bs_header`).
+ * The true bitstream starts with the binary-header composed of 13 words:
+ *
+ *  0: 0xFFFFFFFF (Dummy pad word)
+ *     ...
+ *  7: 0xFFFFFFFF (Dummy pad word)
+ *  8: 0x000000BB (Bus width auto detect word 1)
+ *  9: 0x11220044 (Bus width auto detect word 2)
+ * 10: 0xFFFFFFFF (Dummy pad word)
+ * 11: 0xFFFFFFFF (Dummy pad word)
+ * 12: 0xAA995566 (Sync word)
+ *
+ * See Xilinx UG470 (v1.13.1) August 20 2018, Chapter 5 "Configuration
+ * Details - Bitstream Composition" for further details.
+ */
+
+#define DUMMY_WORD				0xFFFFFFFF
+#define BUS_WIDTH_AUTO_DETECT1_OFFSET		8
+#define BUS_WIDTH_AUTO_DETECT1		0x000000BB
+#define BUS_WIDTH_AUTO_DETECT2_OFFSET		9
+#define BUS_WIDTH_AUTO_DETECT2		0x11220044
+#define SYNC_WORD_OFFSET			12
+#define SYNC_WORD				0xAA995566
+#define BIN_HEADER_LENGTH			13
+
+#define DEVC_UNLOCK_CODE			0x757bdf0d
+
+struct fpgamgr {
+	struct firmware_handler fh;
+	struct device_d dev;
+	void __iomem *regs;
+	const struct zynq_devc_ops *devc_ops;
+	int programmed;
+	char *buf;
+	size_t size;
+	u32 features;
+};
+
+struct zynq_devc_ops {
+	int (*fpga_load)(struct fpgamgr *mgr, u64 address, u32 size, u32 flags);
+};
+
+const struct zynq_devc_ops *zynq_get_devc_ops(void);
+
+#endif /* FIRMWARE_ZYNQ_H_ */
diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
index a04482237..1764a2db3 100644
--- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
+++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
@@ -15,6 +15,8 @@
 #ifndef FIRMWARE_ZYNQMP_H_
 #define FIRMWARE_ZYNQMP_H_

+#include <firmware.h>
+
 #define PAYLOAD_ARG_CNT			4

 #define ZYNQMP_PM_VERSION(MAJOR, MINOR)	((MAJOR << 16) | MINOR)
@@ -27,6 +29,50 @@

 #define ZYNQMP_PCAP_STATUS_FPGA_DONE	BIT(3)

+#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL	BIT(0)
+#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED	BIT(1)
+
+#define ZYNQMP_PM_VERSION_1_0_FEATURES	0
+#define ZYNQMP_PM_VERSION_1_1_FEATURES	(ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
+					 ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
+
+/*
+ * Xilinx KU040 Bitstream Composition:
+ *
+ * Bitstream can be provided with an optinal header (`struct bs_header`).
+ * The true bitstream starts with the binary-header composed of 21 words:
+ *
+ *  0: 0xFFFFFFFF (Dummy pad word)
+ *     ...
+ * 15: 0xFFFFFFFF (Dummy pad word)
+ * 16: 0x000000BB (Bus width auto detect word 1)
+ * 17: 0x11220044 (Bus width auto detect word 2)
+ * 18: 0xFFFFFFFF (Dummy pad word)
+ * 19: 0xFFFFFFFF (Dummy pad word)
+ * 20: 0xAA995566 (Sync word)
+ *
+ * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
+ * Details - Bitstream Composition" for further details.
+ */
+#define DUMMY_WORD			0xFFFFFFFF
+#define BUS_WIDTH_AUTO_DETECT1_OFFSET	16
+#define BUS_WIDTH_AUTO_DETECT1		0x000000BB
+#define BUS_WIDTH_AUTO_DETECT2_OFFSET	17
+#define BUS_WIDTH_AUTO_DETECT2		0x11220044
+#define SYNC_WORD_OFFSET		20
+#define SYNC_WORD			0xAA995566
+#define BIN_HEADER_LENGTH		21
+
+struct fpgamgr {
+	struct firmware_handler fh;
+	struct device_d dev;
+	const struct zynqmp_eemi_ops *eemi_ops;
+	int programmed;
+	char *buf;
+	size_t size;
+	u32 features;
+};
+
 enum pm_ioctl_id {
 	IOCTL_SET_PLL_FRAC_MODE = 8,
 	IOCTL_GET_PLL_FRAC_MODE,
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 90b4c0ab9..a00d682a9 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -15,6 +15,13 @@ config FIRMWARE_ALTERA_SOCFPGA
 	depends on ARCH_SOCFPGA
 	select FIRMWARE

+config FIRMWARE_ZYNQ7000_FPGA
+	bool "Xilinx Zynq 7000 FPGA loader"
+	depends on ARCH_ZYNQ
+	select FIRMWARE
+	help
+	  Load a bitstream to the PL of Zynq
+
 config FIRMWARE_ZYNQMP_FPGA
 	bool "Xilinx ZynqMP FPGA loader"
 	depends on ARCH_ZYNQMP
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index b162b08b0..a7c6344bf 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
 obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
+obj-$(CONFIG_FIRMWARE_ZYNQ7000_FPGA) += zynqmp-fpga.o
 obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
index ab70d9993..4ce835e18 100644
--- a/drivers/firmware/zynqmp-fpga.c
+++ b/drivers/firmware/zynqmp-fpga.c
@@ -15,57 +15,19 @@
 #include <common.h>
 #include <init.h>
 #include <dma.h>
+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
 #include <mach/firmware-zynqmp.h>
-
-#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL	BIT(0)
-#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED	BIT(1)
-
-#define ZYNQMP_PM_VERSION_1_0_FEATURES	0
-#define ZYNQMP_PM_VERSION_1_1_FEATURES	(ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
-					 ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
-
-/*
- * Xilinx KU040 Bitstream Composition:
- *
- * Bitstream can be provided with an optinal header (`struct bs_header`).
- * The true bitstream starts with the binary-header composed of 21 words:
- *
- *  0: 0xFFFFFFFF (Dummy pad word)
- *     ...
- * 15: 0xFFFFFFFF (Dummy pad word)
- * 16: 0x000000BB (Bus width auto detect word 1)
- * 17: 0x11220044 (Bus width auto detect word 2)
- * 18: 0xFFFFFFFF (Dummy pad word)
- * 19: 0xFFFFFFFF (Dummy pad word)
- * 20: 0xAA995566 (Sync word)
- *
- * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
- * Details - Bitstream Composition" for further details.
- */
-#define DUMMY_WORD			0xFFFFFFFF
-#define BUS_WIDTH_AUTO_DETECT1_OFFSET	16
-#define BUS_WIDTH_AUTO_DETECT1		0x000000BB
-#define BUS_WIDTH_AUTO_DETECT2_OFFSET	17
-#define BUS_WIDTH_AUTO_DETECT2		0x11220044
-#define SYNC_WORD_OFFSET		20
-#define SYNC_WORD			0xAA995566
-#define BIN_HEADER_LENGTH		21
+#endif
+#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
+#include <mach/firmware-zynq.h>
+#include <mach/zynq7000-regs.h>
+#endif

 enum xilinx_byte_order {
 	XILINX_BYTE_ORDER_BIT,
 	XILINX_BYTE_ORDER_BIN,
 };

-struct fpgamgr {
-	struct firmware_handler fh;
-	struct device_d dev;
-	const struct zynqmp_eemi_ops *eemi_ops;
-	int programmed;
-	char *buf;
-	size_t size;
-	u32 features;
-};
-
 struct bs_header {
 	__be16 length;
 	u8 padding[9];
@@ -234,6 +196,13 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 		goto err_free;
 	}

+	buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
+	if (!buf_aligned) {
+		status = -ENOBUFS;
+		goto err_free;
+	}
+
+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
 	if (!(mgr->features & ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)) {
 		buf_size = dma_alloc_coherent(sizeof(*buf_size),
 		DMA_ADDRESS_BROKEN);
@@ -244,12 +213,6 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 		*buf_size = body_length;
 	}

-	buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
-	if (!buf_aligned) {
-		status = -ENOBUFS;
-		goto err_free;
-	}
-
 	if (!(mgr->features & ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL) &&
 	    byte_order == XILINX_BYTE_ORDER_BIN)
 		copy_words_swapped((u32 *)buf_aligned, body,
@@ -271,7 +234,32 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 		status = mgr->eemi_ops->fpga_load(addr, (u32)(body_length),
 						  flags);
 	}
+#endif
+#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
+	/* UG585 (v1.12.2) July 1, 2018 Chapter 6.4.3
+	 * In all modes, the DMA transactions must be 64-byte aligned to prevent
+	 * accidently crossing a 4K byte boundary.
+	 */
+	if(byte_order == XILINX_BYTE_ORDER_BIN)
+		copy_words_swapped((u32 *)buf_aligned, body, body_length / sizeof(u32));
+	else
+		memcpy((u32 *)buf_aligned, body, body_length);
+
+	addr = (u32)buf_aligned;
+
+	writel(0x0000DF0D, ZYNQ_SLCR_UNLOCK);
+	writel(0x0000000f, ZYNQ_SLCR_BASE + 0x240); // assert FPGA resets
+
+	writel(0x00000000, ZYNQ_SLCR_BASE + 0x900); // disable levelshifter
+	writel(0x0000000a, ZYNQ_SLCR_BASE + 0x900); // enable levelshifter PS-PL
+
+	status = mgr->devc_ops->fpga_load(mgr, addr, (u32)(body_length), 0);

+	writel(0x0000000f, ZYNQ_SLCR_BASE + 0x900); // enable all levelshifter
+	writel(0x00000000, ZYNQ_SLCR_BASE + 0x240); // deassert FPGA resets
+
+	writel(0x0000767B, ZYNQ_SLCR_LOCK);
+#endif
 	if (status < 0)
 		dev_err(&mgr->dev, "unable to load fpga\n");

@@ -313,8 +301,10 @@ static int fpgamgr_program_start(struct firmware_handler *fh)
 	return 0;
 }

+
 static int programmed_get(struct param_d *p, void *priv)
 {
+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
 	struct fpgamgr *mgr = priv;
 	u32 status = 0x00;
 	int ret = 0;
@@ -324,7 +314,7 @@ static int programmed_get(struct param_d *p, void *priv)
 		return ret;

 	mgr->programmed = !!(status & ZYNQMP_PCAP_STATUS_FPGA_DONE);
-
+#endif
 	return 0;
 }

@@ -336,6 +326,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
 	const char *model = NULL;
 	struct param_d *p;
 	u32 api_version;
+	struct resource *iores;
 	int ret;

 	mgr = xzalloc(sizeof(*mgr));
@@ -354,6 +345,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
 		fh->model = xstrdup(model);
 	fh->dev = dev;

+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
 	mgr->eemi_ops = zynqmp_pm_get_eemi_ops();

 	ret = mgr->eemi_ops->get_api_version(&api_version);
@@ -361,11 +353,21 @@ static int zynqmp_fpga_probe(struct device_d *dev)
 		dev_err(&mgr->dev, "could not get API version\n");
 		goto out;
 	}
-
-	mgr->features = 0;
-
 	if (api_version >= ZYNQMP_PM_VERSION(1, 1))
 		mgr->features |= ZYNQMP_PM_VERSION_1_1_FEATURES;
+#endif
+#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores)) {
+		ret = PTR_ERR(iores);
+		goto out;
+	}
+	mgr->regs = IOMEM(iores->start);
+	mgr->devc_ops = zynq_get_devc_ops();
+	/* Unlock DevC in case BootROM did not do it */
+	writel(DEVC_UNLOCK_CODE, mgr->regs + UNLOCK_OFFSET);
+#endif
+	mgr->features = 0;

 	dev_dbg(dev, "Registering ZynqMP FPGA programmer\n");
 	mgr->dev.id = DEVICE_ID_SINGLE;
@@ -400,9 +402,8 @@ out:
 }

 static struct of_device_id zynqmpp_fpga_id_table[] = {
-	{
-		.compatible = "xlnx,zynqmp-pcap-fpga",
-	},
+	{ .compatible = "xlnx,zynqmp-pcap-fpga" },
+	{ .compatible = "xlnx,zynq-devcfg-1.0" },
 	{ /* sentinel */ }
 };

--
2.25.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/1] added support for zynq7000-fpga-manager
  2021-03-25  7:53 [PATCH 1/1] added support for zynq7000-fpga-manager Michael Graichen
@ 2021-03-25  8:09 ` Ahmad Fatoum
  2021-03-25  8:42 ` Michael Tretter
  1 sibling, 0 replies; 6+ messages in thread
From: Ahmad Fatoum @ 2021-03-25  8:09 UTC (permalink / raw)
  To: Michael Graichen, barebox; +Cc: Michael Tretter

Hello Michael,

On 25.03.21 08:53, Michael Graichen wrote:
> +	reg = readl(mgr->regs + CTRL_OFFSET);
> +	reg &= ~CTRL_PCFG_PROG_B_MASK;
> +	writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +	readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +			!(reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);

Perhaps exit if a timeout occurred? Unchecked readx_poll_timeout looks odd.

> +	/* Check for errors */
> +	if(reg & INT_STS_ERROR_FLAGS_MASK) {

Missing space

> +		printf("interrupt status register (0x%04lx)\n", reg);

Better use pr_warn and co here with a suitable pr_fmt at top:

 - Messages will indicate where the error came from
 - Messages can be formatted according to severity
 - Messages will go into the barebox log, which Linux could read out via
   pstore if needed.

Cheers,
Ahmad

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/1] added support for zynq7000-fpga-manager
  2021-03-25  7:53 [PATCH 1/1] added support for zynq7000-fpga-manager Michael Graichen
  2021-03-25  8:09 ` Ahmad Fatoum
@ 2021-03-25  8:42 ` Michael Tretter
  2021-03-30 12:05   ` AW: " Michael Graichen
  1 sibling, 1 reply; 6+ messages in thread
From: Michael Tretter @ 2021-03-25  8:42 UTC (permalink / raw)
  To: Michael Graichen; +Cc: barebox

On Thu, 25 Mar 2021 07:53:33 +0000, Michael Graichen wrote:
> i have reworked the ZynqMP FPGA manager to program the FPGA within the Zynq7000. 

Great, thanks.

> 
> Michael Tretter, would you be so kind an test this on your ZynqMP board?
> Since I have no access to a ZynqMP chip I have only tested compiling. 

I will test the patch and I already have a few comments down below.

> 
> The name "ZynqMP" may now be missleading for the firmwareload tool, because
> I intended to use it on both, ZynqMP and Zynq7000.  I would be happy to get
> read your feedback.

I think, it would be fine to use only "zynq" instead of zynqmp for the
firmware loader/fpga manager. (I didn't compare the Zynq7000 and ZynqMP low
level interfaces for programming the FPGA, yet, but I guess that programming
the FPGA on the ZynqMP in EL3 instead of EL2/EL1 is actually the same as on
Zynq7000.) I am also ok with treating ZynqMP as a second class citizen in the
driver.

> 
> Best Regards 
> Michael 
> 
> 
> Signed-off-by: Michael Graichen <michael.graichen@hotmail.com>
> ---
>  arch/arm/configs/zynq_defconfig               |   2 +
>  arch/arm/mach-zynq/Makefile                   |   2 +-
>  arch/arm/mach-zynq/firmware-zynq.c            | 124 ++++++++++++++++++
>  .../mach-zynq/include/mach/firmware-zynq.h    |  85 ++++++++++++
>  .../include/mach/firmware-zynqmp.h            |  46 +++++++
>  drivers/firmware/Kconfig                      |   7 +
>  drivers/firmware/Makefile                     |   1 +
>  drivers/firmware/zynqmp-fpga.c                | 115 ++++++++--------
>  8 files changed, 324 insertions(+), 58 deletions(-)
>  create mode 100644 arch/arm/mach-zynq/firmware-zynq.c
>  create mode 100644 arch/arm/mach-zynq/include/mach/firmware-zynq.h
> 
> diff --git a/arch/arm/configs/zynq_defconfig b/arch/arm/configs/zynq_defconfig
> index a16c57d5c..82ea899e2 100644
> --- a/arch/arm/configs/zynq_defconfig
> +++ b/arch/arm/configs/zynq_defconfig
> @@ -36,6 +36,7 @@ CONFIG_CMD_MENU_MANAGEMENT=y
>  CONFIG_CMD_READLINE=y
>  CONFIG_CMD_TIMEOUT=y
>  CONFIG_CMD_CLK=y
> +CONFIG_CMD_FIRMWARELOAD=y
>  CONFIG_CMD_OFTREE=y
>  CONFIG_CMD_TIME=y
>  CONFIG_NET=y
> @@ -43,5 +44,6 @@ CONFIG_DRIVER_SERIAL_CADENCE=y
>  CONFIG_DRIVER_NET_MACB=y
>  # CONFIG_SPI is not set
>  # CONFIG_PINCTRL is not set
> +CONFIG_FIRMWARE_ZYNQ7000_FPGA=y
>  CONFIG_FS_TFTP=y
>  CONFIG_DIGEST=y
> diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
> index 06c2ce996..2484abe5c 100644
> --- a/arch/arm/mach-zynq/Makefile
> +++ b/arch/arm/mach-zynq/Makefile
> @@ -1,2 +1,2 @@
> -obj-y += zynq.o bootm-zynqimg.o
> +obj-y += bootm-zynqimg.o firmware-zynq.o zynq.o
>  lwl-y += cpu_init.o
> diff --git a/arch/arm/mach-zynq/firmware-zynq.c b/arch/arm/mach-zynq/firmware-zynq.c
> new file mode 100644
> index 000000000..307b22fe5
> --- /dev/null
> +++ b/arch/arm/mach-zynq/firmware-zynq.c
> @@ -0,0 +1,124 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + */
> +#include <common.h>
> +#include <init.h>
> +#include <linux/iopoll.h>
> +#include <mach/firmware-zynq.h>
> +
> +/*
> + * zynq_devc_fpga_load - Perform the fpga load
> + * @mgr:	FPGA-Manager
> + * @address:	Address to write to
> + * @size:	PL bitstream size
> + * @flags:	Flags - unused
> + *
> + * This function provides access to PCAP to transfer
> + * the required bitstream into PL.
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynq_devc_fpga_load(struct fpgamgr *mgr, u64 address,
> +				u32 size, u32 flags)
> +{
> +	unsigned long reg;
> +
> +	if (!address || !size)
> +		return -EINVAL;
> +
> +	/*
> +	 * The Programming Seqenze, see ug585 (v.12.2) Juny 1, 2018 Chapter
> +	 * 6.4.2 on page 211 Configure the PL via PCAP Bridge Example for
> +	 * detailed information to this Sequenze
> +	 */
> +
> +	/* Enable the PCAP bridge and select PCAP for reconfiguration */
> +	reg = readl(mgr->regs + CTRL_OFFSET);
> +	reg |= ( CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK );
> +	writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +	/* Clear the Interrupts */
> +	writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
> +
> +	/* Initialize the PL */
> +	reg = readl(mgr->regs + CTRL_OFFSET);
> +	reg |= CTRL_PCFG_PROG_B_MASK;
> +	writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +	reg = readl(mgr->regs + CTRL_OFFSET);
> +	reg &= ~CTRL_PCFG_PROG_B_MASK;
> +	writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +	readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +			!(reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
> +
> +	reg = readl(mgr->regs + CTRL_OFFSET);
> +	reg |= CTRL_PCFG_PROG_B_MASK;
> +	writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +	/* Clear the Interrupts */
> +	writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
> +
> +	/* Ensure that the PL is ready for programming */
> +	readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +			(reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
> +
> +	/* Check that there is room in the Command Queue */
> +	readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +			!(reg & STATUS_DMA_CMD_Q_F_MASK), 100 * USEC_PER_MSEC);
> +
> +	/* Disable the PCAP loopback */
> +	reg = readl(mgr->regs + MCTRL_OFFSET);
> +	reg &= ~MCTRL_INT_PCAP_LPBK_MASK;
> +	writel(reg, mgr->regs + MCTRL_OFFSET);
> +
> +	/* Program the PCAP_2x clock divider */
> +	reg = readl(mgr->regs + CTRL_OFFSET);
> +	reg &= ~CTRL_PCAP_RATE_EN_MASK;
> +	writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +	/* Source Address: Location of bitstream */
> +	writel(address, mgr->regs + DMA_SRC_ADDR_OFFSET);
> +
> +	/* Destination Address: 0xFFFF_FFFF */
> +	writel(0xffffffff, mgr->regs + DMA_DST_ADDR_OFFSET);
> +
> +	/* Source Length: Total number of 32-bit words in the bitstream */
> +	writel((size >> 2), mgr->regs + DMA_SRC_LEN_OFFSET);
> +
> +	/* Destination Length: Total number of 32-bit words in the bitstream */
> +	writel((size >> 2), mgr->regs + DMA_DEST_LEN_OFFSET);
> +
> +	/* Wait for the DMA transfer to be done */
> +	readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
> +			(reg & INT_STS_D_P_DONE_MASK), 100 * USEC_PER_MSEC);
> +
> +	/* Check for errors */
> +	if(reg & INT_STS_ERROR_FLAGS_MASK) {
> +		printf("interrupt status register (0x%04lx)\n", reg);
> +		return -EIO;
> +	}
> +
> +	/* Wait for the DMA transfer to be done */
> +	readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
> +			(reg & INT_STS_DONE_INT_MASK), 100 * USEC_PER_MSEC);
> +
> +	printf("FPGA config done\n");
> +
> +	return 0;
> +}
> +
> +static const struct zynq_devc_ops devc_ops = {
> +	.fpga_load = zynq_devc_fpga_load,
> +};
> +
> +/**
> + * zynq_get_devc_ops - Get devc ops functions
> + *
> + * Return: Pointer of devc_ops structure
> + */
> +const struct zynq_devc_ops *zynq_get_devc_ops(void)
> +{
> +	return &devc_ops;
> +}
> +EXPORT_SYMBOL_GPL(zynq_get_devc_ops);

Don't try to hide the loading code behind function pointers in machine
specific code. Just put the zynq_devc_fpga_load function straight into
drivers/firmware/zynqmp-fpga.c.

For the ZynqMP there is this abstraction, because the ZyqnMP has another
driver that is used to instruct another firmware (TF-A) to program the FPGA.
As this isn't the case for the Zynq7000, I don't see a reason to make things
more complicated than they are.

> diff --git a/arch/arm/mach-zynq/include/mach/firmware-zynq.h b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
> new file mode 100644
> index 000000000..217b1e9b2
> --- /dev/null
> +++ b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
> @@ -0,0 +1,85 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Xilinx Zynq Firmware layer
> + *
> + */
> +
> +#ifndef FIRMWARE_ZYNQ_H_
> +#define FIRMWARE_ZYNQ_H_
> +
> +#include <firmware.h>
> +
> +#define CTRL_OFFSET				0x00
> +#define LOCK_OFFSET				0x04
> +#define INT_STS_OFFSET				0x0c
> +#define INT_MASK_OFFSET			0x10
> +#define STATUS_OFFSET				0x14
> +#define DMA_SRC_ADDR_OFFSET			0x18
> +#define DMA_DST_ADDR_OFFSET			0x1c
> +#define DMA_SRC_LEN_OFFSET			0x20
> +#define DMA_DEST_LEN_OFFSET			0x24
> +#define UNLOCK_OFFSET				0x34
> +#define MCTRL_OFFSET				0x80
> +
> +#define CTRL_PCFG_PROG_B_MASK			BIT(30)
> +#define CTRL_PCAP_PR_MASK			BIT(27)
> +#define CTRL_PCAP_MODE_MASK			BIT(26)
> +#define CTRL_PCAP_RATE_EN_MASK		BIT(25)
> +
> +#define STATUS_DMA_CMD_Q_F_MASK		BIT(31)
> +#define STATUS_PCFG_INIT_MASK			BIT(4)
> +
> +#define INT_STS_D_P_DONE_MASK			BIT(12)
> +#define INT_STS_DONE_INT_MASK			BIT(2)
> +#define INT_STS_ERROR_FLAGS_MASK		0x00f4c860
> +
> +#define MCTRL_INT_PCAP_LPBK_MASK		BIT(4)
> +
> +/*
> + * Xilinx 7-Series Bitstream Composition:
> + *
> + * Bitstream can be provided with an optinal header (`struct bs_header`).
> + * The true bitstream starts with the binary-header composed of 13 words:
> + *
> + *  0: 0xFFFFFFFF (Dummy pad word)
> + *     ...
> + *  7: 0xFFFFFFFF (Dummy pad word)
> + *  8: 0x000000BB (Bus width auto detect word 1)
> + *  9: 0x11220044 (Bus width auto detect word 2)
> + * 10: 0xFFFFFFFF (Dummy pad word)
> + * 11: 0xFFFFFFFF (Dummy pad word)
> + * 12: 0xAA995566 (Sync word)
> + *
> + * See Xilinx UG470 (v1.13.1) August 20 2018, Chapter 5 "Configuration
> + * Details - Bitstream Composition" for further details.
> + */
> +
> +#define DUMMY_WORD				0xFFFFFFFF
> +#define BUS_WIDTH_AUTO_DETECT1_OFFSET		8
> +#define BUS_WIDTH_AUTO_DETECT1		0x000000BB
> +#define BUS_WIDTH_AUTO_DETECT2_OFFSET		9
> +#define BUS_WIDTH_AUTO_DETECT2		0x11220044
> +#define SYNC_WORD_OFFSET			12
> +#define SYNC_WORD				0xAA995566
> +#define BIN_HEADER_LENGTH			13
> +
> +#define DEVC_UNLOCK_CODE			0x757bdf0d
> +
> +struct fpgamgr {
> +	struct firmware_handler fh;
> +	struct device_d dev;
> +	void __iomem *regs;
> +	const struct zynq_devc_ops *devc_ops;
> +	int programmed;
> +	char *buf;
> +	size_t size;
> +	u32 features;
> +};
> +
> +struct zynq_devc_ops {
> +	int (*fpga_load)(struct fpgamgr *mgr, u64 address, u32 size, u32 flags);
> +};
> +
> +const struct zynq_devc_ops *zynq_get_devc_ops(void);
> +
> +#endif /* FIRMWARE_ZYNQ_H_ */
> diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> index a04482237..1764a2db3 100644
> --- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> +++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> @@ -15,6 +15,8 @@
>  #ifndef FIRMWARE_ZYNQMP_H_
>  #define FIRMWARE_ZYNQMP_H_
> 
> +#include <firmware.h>
> +
>  #define PAYLOAD_ARG_CNT			4
> 
>  #define ZYNQMP_PM_VERSION(MAJOR, MINOR)	((MAJOR << 16) | MINOR)
> @@ -27,6 +29,50 @@
> 
>  #define ZYNQMP_PCAP_STATUS_FPGA_DONE	BIT(3)
> 
> +#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL	BIT(0)
> +#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED	BIT(1)
> +
> +#define ZYNQMP_PM_VERSION_1_0_FEATURES	0
> +#define ZYNQMP_PM_VERSION_1_1_FEATURES	(ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
> +					 ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
> +
> +/*
> + * Xilinx KU040 Bitstream Composition:
> + *
> + * Bitstream can be provided with an optinal header (`struct bs_header`).
> + * The true bitstream starts with the binary-header composed of 21 words:
> + *
> + *  0: 0xFFFFFFFF (Dummy pad word)
> + *     ...
> + * 15: 0xFFFFFFFF (Dummy pad word)
> + * 16: 0x000000BB (Bus width auto detect word 1)
> + * 17: 0x11220044 (Bus width auto detect word 2)
> + * 18: 0xFFFFFFFF (Dummy pad word)
> + * 19: 0xFFFFFFFF (Dummy pad word)
> + * 20: 0xAA995566 (Sync word)
> + *
> + * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
> + * Details - Bitstream Composition" for further details.
> + */
> +#define DUMMY_WORD			0xFFFFFFFF
> +#define BUS_WIDTH_AUTO_DETECT1_OFFSET	16
> +#define BUS_WIDTH_AUTO_DETECT1		0x000000BB
> +#define BUS_WIDTH_AUTO_DETECT2_OFFSET	17
> +#define BUS_WIDTH_AUTO_DETECT2		0x11220044
> +#define SYNC_WORD_OFFSET		20
> +#define SYNC_WORD			0xAA995566
> +#define BIN_HEADER_LENGTH		21
> +
> +struct fpgamgr {
> +	struct firmware_handler fh;
> +	struct device_d dev;
> +	const struct zynqmp_eemi_ops *eemi_ops;
> +	int programmed;
> +	char *buf;
> +	size_t size;
> +	u32 features;
> +};
> +
>  enum pm_ioctl_id {
>  	IOCTL_SET_PLL_FRAC_MODE = 8,
>  	IOCTL_GET_PLL_FRAC_MODE,
> diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
> index 90b4c0ab9..a00d682a9 100644
> --- a/drivers/firmware/Kconfig
> +++ b/drivers/firmware/Kconfig
> @@ -15,6 +15,13 @@ config FIRMWARE_ALTERA_SOCFPGA
>  	depends on ARCH_SOCFPGA
>  	select FIRMWARE
> 
> +config FIRMWARE_ZYNQ7000_FPGA
> +	bool "Xilinx Zynq 7000 FPGA loader"
> +	depends on ARCH_ZYNQ
> +	select FIRMWARE
> +	help
> +	  Load a bitstream to the PL of Zynq
> +
>  config FIRMWARE_ZYNQMP_FPGA
>  	bool "Xilinx ZynqMP FPGA loader"
>  	depends on ARCH_ZYNQMP
> diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
> index b162b08b0..a7c6344bf 100644
> --- a/drivers/firmware/Makefile
> +++ b/drivers/firmware/Makefile
> @@ -1,3 +1,4 @@
>  obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
>  obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
> +obj-$(CONFIG_FIRMWARE_ZYNQ7000_FPGA) += zynqmp-fpga.o
>  obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
> diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
> index ab70d9993..4ce835e18 100644
> --- a/drivers/firmware/zynqmp-fpga.c
> +++ b/drivers/firmware/zynqmp-fpga.c
> @@ -15,57 +15,19 @@
>  #include <common.h>
>  #include <init.h>
>  #include <dma.h>
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
>  #include <mach/firmware-zynqmp.h>
> -
> -#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL	BIT(0)
> -#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED	BIT(1)
> -
> -#define ZYNQMP_PM_VERSION_1_0_FEATURES	0
> -#define ZYNQMP_PM_VERSION_1_1_FEATURES	(ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
> -					 ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
> -
> -/*
> - * Xilinx KU040 Bitstream Composition:
> - *
> - * Bitstream can be provided with an optinal header (`struct bs_header`).
> - * The true bitstream starts with the binary-header composed of 21 words:
> - *
> - *  0: 0xFFFFFFFF (Dummy pad word)
> - *     ...
> - * 15: 0xFFFFFFFF (Dummy pad word)
> - * 16: 0x000000BB (Bus width auto detect word 1)
> - * 17: 0x11220044 (Bus width auto detect word 2)
> - * 18: 0xFFFFFFFF (Dummy pad word)
> - * 19: 0xFFFFFFFF (Dummy pad word)
> - * 20: 0xAA995566 (Sync word)
> - *
> - * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
> - * Details - Bitstream Composition" for further details.
> - */
> -#define DUMMY_WORD			0xFFFFFFFF
> -#define BUS_WIDTH_AUTO_DETECT1_OFFSET	16
> -#define BUS_WIDTH_AUTO_DETECT1		0x000000BB
> -#define BUS_WIDTH_AUTO_DETECT2_OFFSET	17
> -#define BUS_WIDTH_AUTO_DETECT2		0x11220044
> -#define SYNC_WORD_OFFSET		20
> -#define SYNC_WORD			0xAA995566
> -#define BIN_HEADER_LENGTH		21
> +#endif
> +#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
> +#include <mach/firmware-zynq.h>
> +#include <mach/zynq7000-regs.h>
> +#endif

Is it possible to change the is_bin_header_valid() function to identify the
(slightly) different bitstream header formats at runtime? I would like to keep
the header specification in the driver instead of moving it to header files
and making it configuration dependent.

> 
>  enum xilinx_byte_order {
>  	XILINX_BYTE_ORDER_BIT,
>  	XILINX_BYTE_ORDER_BIN,
>  };
> 
> -struct fpgamgr {
> -	struct firmware_handler fh;
> -	struct device_d dev;
> -	const struct zynqmp_eemi_ops *eemi_ops;
> -	int programmed;
> -	char *buf;
> -	size_t size;
> -	u32 features;
> -};
> -
>  struct bs_header {
>  	__be16 length;
>  	u8 padding[9];
> @@ -234,6 +196,13 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
>  		goto err_free;
>  	}
> 
> +	buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
> +	if (!buf_aligned) {
> +		status = -ENOBUFS;
> +		goto err_free;
> +	}
> +
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA

Avoid the #ifdefs in the driver. Check for the compatible or add an identifier
to struct fpgamgr to decide if the driver can access the register directly or
needs to use the ZynqMP firmware calls.

If necessary, stub functions in the headers if some configuration is not set
and return an error.

Michael

>  	if (!(mgr->features & ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)) {
>  		buf_size = dma_alloc_coherent(sizeof(*buf_size),
>  		DMA_ADDRESS_BROKEN);
> @@ -244,12 +213,6 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
>  		*buf_size = body_length;
>  	}
> 
> -	buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
> -	if (!buf_aligned) {
> -		status = -ENOBUFS;
> -		goto err_free;
> -	}
> -
>  	if (!(mgr->features & ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL) &&
>  	    byte_order == XILINX_BYTE_ORDER_BIN)
>  		copy_words_swapped((u32 *)buf_aligned, body,
> @@ -271,7 +234,32 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
>  		status = mgr->eemi_ops->fpga_load(addr, (u32)(body_length),
>  						  flags);
>  	}
> +#endif
> +#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
> +	/* UG585 (v1.12.2) July 1, 2018 Chapter 6.4.3
> +	 * In all modes, the DMA transactions must be 64-byte aligned to prevent
> +	 * accidently crossing a 4K byte boundary.
> +	 */
> +	if(byte_order == XILINX_BYTE_ORDER_BIN)
> +		copy_words_swapped((u32 *)buf_aligned, body, body_length / sizeof(u32));
> +	else
> +		memcpy((u32 *)buf_aligned, body, body_length);
> +
> +	addr = (u32)buf_aligned;
> +
> +	writel(0x0000DF0D, ZYNQ_SLCR_UNLOCK);
> +	writel(0x0000000f, ZYNQ_SLCR_BASE + 0x240); // assert FPGA resets
> +
> +	writel(0x00000000, ZYNQ_SLCR_BASE + 0x900); // disable levelshifter
> +	writel(0x0000000a, ZYNQ_SLCR_BASE + 0x900); // enable levelshifter PS-PL
> +
> +	status = mgr->devc_ops->fpga_load(mgr, addr, (u32)(body_length), 0);
> 
> +	writel(0x0000000f, ZYNQ_SLCR_BASE + 0x900); // enable all levelshifter
> +	writel(0x00000000, ZYNQ_SLCR_BASE + 0x240); // deassert FPGA resets
> +
> +	writel(0x0000767B, ZYNQ_SLCR_LOCK);
> +#endif
>  	if (status < 0)
>  		dev_err(&mgr->dev, "unable to load fpga\n");
> 
> @@ -313,8 +301,10 @@ static int fpgamgr_program_start(struct firmware_handler *fh)
>  	return 0;
>  }
> 
> +
>  static int programmed_get(struct param_d *p, void *priv)
>  {
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
>  	struct fpgamgr *mgr = priv;
>  	u32 status = 0x00;
>  	int ret = 0;
> @@ -324,7 +314,7 @@ static int programmed_get(struct param_d *p, void *priv)
>  		return ret;
> 
>  	mgr->programmed = !!(status & ZYNQMP_PCAP_STATUS_FPGA_DONE);
> -
> +#endif
>  	return 0;
>  }
> 
> @@ -336,6 +326,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
>  	const char *model = NULL;
>  	struct param_d *p;
>  	u32 api_version;
> +	struct resource *iores;
>  	int ret;
> 
>  	mgr = xzalloc(sizeof(*mgr));
> @@ -354,6 +345,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
>  		fh->model = xstrdup(model);
>  	fh->dev = dev;
> 
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
>  	mgr->eemi_ops = zynqmp_pm_get_eemi_ops();
> 
>  	ret = mgr->eemi_ops->get_api_version(&api_version);
> @@ -361,11 +353,21 @@ static int zynqmp_fpga_probe(struct device_d *dev)
>  		dev_err(&mgr->dev, "could not get API version\n");
>  		goto out;
>  	}
> -
> -	mgr->features = 0;
> -
>  	if (api_version >= ZYNQMP_PM_VERSION(1, 1))
>  		mgr->features |= ZYNQMP_PM_VERSION_1_1_FEATURES;
> +#endif
> +#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
> +	iores = dev_request_mem_resource(dev, 0);
> +	if (IS_ERR(iores)) {
> +		ret = PTR_ERR(iores);
> +		goto out;
> +	}
> +	mgr->regs = IOMEM(iores->start);
> +	mgr->devc_ops = zynq_get_devc_ops();
> +	/* Unlock DevC in case BootROM did not do it */
> +	writel(DEVC_UNLOCK_CODE, mgr->regs + UNLOCK_OFFSET);
> +#endif
> +	mgr->features = 0;
> 
>  	dev_dbg(dev, "Registering ZynqMP FPGA programmer\n");
>  	mgr->dev.id = DEVICE_ID_SINGLE;
> @@ -400,9 +402,8 @@ out:
>  }
> 
>  static struct of_device_id zynqmpp_fpga_id_table[] = {
> -	{
> -		.compatible = "xlnx,zynqmp-pcap-fpga",
> -	},
> +	{ .compatible = "xlnx,zynqmp-pcap-fpga" },
> +	{ .compatible = "xlnx,zynq-devcfg-1.0" },
>  	{ /* sentinel */ }
>  };
> 
> --
> 2.25.1
> 
> 

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 6+ messages in thread

* AW: [PATCH 1/1] added support for zynq7000-fpga-manager
  2021-03-25  8:42 ` Michael Tretter
@ 2021-03-30 12:05   ` Michael Graichen
  2021-04-08 15:28     ` Michael Tretter
  0 siblings, 1 reply; 6+ messages in thread
From: Michael Graichen @ 2021-03-30 12:05 UTC (permalink / raw)
  To: Michael Tretter, Ahmad Fatoum; +Cc: barebox

Hey, 

Ahmad, thanks for your reply. I'll will work your points out for the next patch. 

> I think, it would be fine to use only "zynq" instead of zynqmp for the
> firmware loader/fpga manager. (I didn't compare the Zynq7000 and ZynqMP low
> level interfaces for programming the FPGA, yet, but I guess that programming
> the FPGA on the ZynqMP in EL3 instead of EL2/EL1 is actually the same as on
> Zynq7000.) I am also ok with treating ZynqMP as a second class citizen in the
> driver. 

As I compared https://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf page 211ff and https://www.xilinx.com/support/documentation/user_guides/ug1085-zynq-ultrascale-trm.pdf page 261ff the programming of the PCAP seem to be similar, but PCAP is embedded in CSU/PMU on ZynqMP, which looks much more complex then DEVC on Zynq7000. But I don't know how much of CSUs functionality is acctually needed to programm the FPGA.

Is the CSU within ZynqMP used for something other than programming the firmware in barebox?

Best regard,
Michael 

________________________________________
Von: Michael Tretter <m.tretter@pengutronix.de>
Gesendet: Donnerstag, 25. März 2021 09:42
An: Michael Graichen
Cc: barebox@lists.infradead.org
Betreff: Re: [PATCH 1/1] added support for zynq7000-fpga-manager

On Thu, 25 Mar 2021 07:53:33 +0000, Michael Graichen wrote:
> i have reworked the ZynqMP FPGA manager to program the FPGA within the Zynq7000.

Great, thanks.

>
> Michael Tretter, would you be so kind an test this on your ZynqMP board?
> Since I have no access to a ZynqMP chip I have only tested compiling.

I will test the patch and I already have a few comments down below.

>
> The name "ZynqMP" may now be missleading for the firmwareload tool, because
> I intended to use it on both, ZynqMP and Zynq7000.  I would be happy to get
> read your feedback.

I think, it would be fine to use only "zynq" instead of zynqmp for the
firmware loader/fpga manager. (I didn't compare the Zynq7000 and ZynqMP low
level interfaces for programming the FPGA, yet, but I guess that programming
the FPGA on the ZynqMP in EL3 instead of EL2/EL1 is actually the same as on
Zynq7000.) I am also ok with treating ZynqMP as a second class citizen in the
driver.

>
> Best Regards
> Michael
>
>
> Signed-off-by: Michael Graichen <michael.graichen@hotmail.com>
> ---
>  arch/arm/configs/zynq_defconfig               |   2 +
>  arch/arm/mach-zynq/Makefile                   |   2 +-
>  arch/arm/mach-zynq/firmware-zynq.c            | 124 ++++++++++++++++++
>  .../mach-zynq/include/mach/firmware-zynq.h    |  85 ++++++++++++
>  .../include/mach/firmware-zynqmp.h            |  46 +++++++
>  drivers/firmware/Kconfig                      |   7 +
>  drivers/firmware/Makefile                     |   1 +
>  drivers/firmware/zynqmp-fpga.c                | 115 ++++++++--------
>  8 files changed, 324 insertions(+), 58 deletions(-)
>  create mode 100644 arch/arm/mach-zynq/firmware-zynq.c
>  create mode 100644 arch/arm/mach-zynq/include/mach/firmware-zynq.h
>
> diff --git a/arch/arm/configs/zynq_defconfig b/arch/arm/configs/zynq_defconfig
> index a16c57d5c..82ea899e2 100644
> --- a/arch/arm/configs/zynq_defconfig
> +++ b/arch/arm/configs/zynq_defconfig
> @@ -36,6 +36,7 @@ CONFIG_CMD_MENU_MANAGEMENT=y
>  CONFIG_CMD_READLINE=y
>  CONFIG_CMD_TIMEOUT=y
>  CONFIG_CMD_CLK=y
> +CONFIG_CMD_FIRMWARELOAD=y
>  CONFIG_CMD_OFTREE=y
>  CONFIG_CMD_TIME=y
>  CONFIG_NET=y
> @@ -43,5 +44,6 @@ CONFIG_DRIVER_SERIAL_CADENCE=y
>  CONFIG_DRIVER_NET_MACB=y
>  # CONFIG_SPI is not set
>  # CONFIG_PINCTRL is not set
> +CONFIG_FIRMWARE_ZYNQ7000_FPGA=y
>  CONFIG_FS_TFTP=y
>  CONFIG_DIGEST=y
> diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
> index 06c2ce996..2484abe5c 100644
> --- a/arch/arm/mach-zynq/Makefile
> +++ b/arch/arm/mach-zynq/Makefile
> @@ -1,2 +1,2 @@
> -obj-y += zynq.o bootm-zynqimg.o
> +obj-y += bootm-zynqimg.o firmware-zynq.o zynq.o
>  lwl-y += cpu_init.o
> diff --git a/arch/arm/mach-zynq/firmware-zynq.c b/arch/arm/mach-zynq/firmware-zynq.c
> new file mode 100644
> index 000000000..307b22fe5
> --- /dev/null
> +++ b/arch/arm/mach-zynq/firmware-zynq.c
> @@ -0,0 +1,124 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + */
> +#include <common.h>
> +#include <init.h>
> +#include <linux/iopoll.h>
> +#include <mach/firmware-zynq.h>
> +
> +/*
> + * zynq_devc_fpga_load - Perform the fpga load
> + * @mgr:     FPGA-Manager
> + * @address: Address to write to
> + * @size:    PL bitstream size
> + * @flags:   Flags - unused
> + *
> + * This function provides access to PCAP to transfer
> + * the required bitstream into PL.
> + *
> + * Return:   Returns status, either success or error+reason
> + */
> +static int zynq_devc_fpga_load(struct fpgamgr *mgr, u64 address,
> +                             u32 size, u32 flags)
> +{
> +     unsigned long reg;
> +
> +     if (!address || !size)
> +             return -EINVAL;
> +
> +     /*
> +      * The Programming Seqenze, see ug585 (v.12.2) Juny 1, 2018 Chapter
> +      * 6.4.2 on page 211 Configure the PL via PCAP Bridge Example for
> +      * detailed information to this Sequenze
> +      */
> +
> +     /* Enable the PCAP bridge and select PCAP for reconfiguration */
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg |= ( CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK );
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     /* Clear the Interrupts */
> +     writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
> +
> +     /* Initialize the PL */
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg |= CTRL_PCFG_PROG_B_MASK;
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg &= ~CTRL_PCFG_PROG_B_MASK;
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +                     !(reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
> +
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg |= CTRL_PCFG_PROG_B_MASK;
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     /* Clear the Interrupts */
> +     writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
> +
> +     /* Ensure that the PL is ready for programming */
> +     readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +                     (reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
> +
> +     /* Check that there is room in the Command Queue */
> +     readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +                     !(reg & STATUS_DMA_CMD_Q_F_MASK), 100 * USEC_PER_MSEC);
> +
> +     /* Disable the PCAP loopback */
> +     reg = readl(mgr->regs + MCTRL_OFFSET);
> +     reg &= ~MCTRL_INT_PCAP_LPBK_MASK;
> +     writel(reg, mgr->regs + MCTRL_OFFSET);
> +
> +     /* Program the PCAP_2x clock divider */
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg &= ~CTRL_PCAP_RATE_EN_MASK;
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     /* Source Address: Location of bitstream */
> +     writel(address, mgr->regs + DMA_SRC_ADDR_OFFSET);
> +
> +     /* Destination Address: 0xFFFF_FFFF */
> +     writel(0xffffffff, mgr->regs + DMA_DST_ADDR_OFFSET);
> +
> +     /* Source Length: Total number of 32-bit words in the bitstream */
> +     writel((size >> 2), mgr->regs + DMA_SRC_LEN_OFFSET);
> +
> +     /* Destination Length: Total number of 32-bit words in the bitstream */
> +     writel((size >> 2), mgr->regs + DMA_DEST_LEN_OFFSET);
> +
> +     /* Wait for the DMA transfer to be done */
> +     readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
> +                     (reg & INT_STS_D_P_DONE_MASK), 100 * USEC_PER_MSEC);
> +
> +     /* Check for errors */
> +     if(reg & INT_STS_ERROR_FLAGS_MASK) {
> +             printf("interrupt status register (0x%04lx)\n", reg);
> +             return -EIO;
> +     }
> +
> +     /* Wait for the DMA transfer to be done */
> +     readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
> +                     (reg & INT_STS_DONE_INT_MASK), 100 * USEC_PER_MSEC);
> +
> +     printf("FPGA config done\n");
> +
> +     return 0;
> +}
> +
> +static const struct zynq_devc_ops devc_ops = {
> +     .fpga_load = zynq_devc_fpga_load,
> +};
> +
> +/**
> + * zynq_get_devc_ops - Get devc ops functions
> + *
> + * Return: Pointer of devc_ops structure
> + */
> +const struct zynq_devc_ops *zynq_get_devc_ops(void)
> +{
> +     return &devc_ops;
> +}
> +EXPORT_SYMBOL_GPL(zynq_get_devc_ops);

Don't try to hide the loading code behind function pointers in machine
specific code. Just put the zynq_devc_fpga_load function straight into
drivers/firmware/zynqmp-fpga.c.

For the ZynqMP there is this abstraction, because the ZyqnMP has another
driver that is used to instruct another firmware (TF-A) to program the FPGA.
As this isn't the case for the Zynq7000, I don't see a reason to make things
more complicated than they are.

> diff --git a/arch/arm/mach-zynq/include/mach/firmware-zynq.h b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
> new file mode 100644
> index 000000000..217b1e9b2
> --- /dev/null
> +++ b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
> @@ -0,0 +1,85 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Xilinx Zynq Firmware layer
> + *
> + */
> +
> +#ifndef FIRMWARE_ZYNQ_H_
> +#define FIRMWARE_ZYNQ_H_
> +
> +#include <firmware.h>
> +
> +#define CTRL_OFFSET                          0x00
> +#define LOCK_OFFSET                          0x04
> +#define INT_STS_OFFSET                               0x0c
> +#define INT_MASK_OFFSET                      0x10
> +#define STATUS_OFFSET                                0x14
> +#define DMA_SRC_ADDR_OFFSET                  0x18
> +#define DMA_DST_ADDR_OFFSET                  0x1c
> +#define DMA_SRC_LEN_OFFSET                   0x20
> +#define DMA_DEST_LEN_OFFSET                  0x24
> +#define UNLOCK_OFFSET                                0x34
> +#define MCTRL_OFFSET                         0x80
> +
> +#define CTRL_PCFG_PROG_B_MASK                        BIT(30)
> +#define CTRL_PCAP_PR_MASK                    BIT(27)
> +#define CTRL_PCAP_MODE_MASK                  BIT(26)
> +#define CTRL_PCAP_RATE_EN_MASK               BIT(25)
> +
> +#define STATUS_DMA_CMD_Q_F_MASK              BIT(31)
> +#define STATUS_PCFG_INIT_MASK                        BIT(4)
> +
> +#define INT_STS_D_P_DONE_MASK                        BIT(12)
> +#define INT_STS_DONE_INT_MASK                        BIT(2)
> +#define INT_STS_ERROR_FLAGS_MASK             0x00f4c860
> +
> +#define MCTRL_INT_PCAP_LPBK_MASK             BIT(4)
> +
> +/*
> + * Xilinx 7-Series Bitstream Composition:
> + *
> + * Bitstream can be provided with an optinal header (`struct bs_header`).
> + * The true bitstream starts with the binary-header composed of 13 words:
> + *
> + *  0: 0xFFFFFFFF (Dummy pad word)
> + *     ...
> + *  7: 0xFFFFFFFF (Dummy pad word)
> + *  8: 0x000000BB (Bus width auto detect word 1)
> + *  9: 0x11220044 (Bus width auto detect word 2)
> + * 10: 0xFFFFFFFF (Dummy pad word)
> + * 11: 0xFFFFFFFF (Dummy pad word)
> + * 12: 0xAA995566 (Sync word)
> + *
> + * See Xilinx UG470 (v1.13.1) August 20 2018, Chapter 5 "Configuration
> + * Details - Bitstream Composition" for further details.
> + */
> +
> +#define DUMMY_WORD                           0xFFFFFFFF
> +#define BUS_WIDTH_AUTO_DETECT1_OFFSET                8
> +#define BUS_WIDTH_AUTO_DETECT1               0x000000BB
> +#define BUS_WIDTH_AUTO_DETECT2_OFFSET                9
> +#define BUS_WIDTH_AUTO_DETECT2               0x11220044
> +#define SYNC_WORD_OFFSET                     12
> +#define SYNC_WORD                            0xAA995566
> +#define BIN_HEADER_LENGTH                    13
> +
> +#define DEVC_UNLOCK_CODE                     0x757bdf0d
> +
> +struct fpgamgr {
> +     struct firmware_handler fh;
> +     struct device_d dev;
> +     void __iomem *regs;
> +     const struct zynq_devc_ops *devc_ops;
> +     int programmed;
> +     char *buf;
> +     size_t size;
> +     u32 features;
> +};
> +
> +struct zynq_devc_ops {
> +     int (*fpga_load)(struct fpgamgr *mgr, u64 address, u32 size, u32 flags);
> +};
> +
> +const struct zynq_devc_ops *zynq_get_devc_ops(void);
> +
> +#endif /* FIRMWARE_ZYNQ_H_ */
> diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> index a04482237..1764a2db3 100644
> --- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> +++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> @@ -15,6 +15,8 @@
>  #ifndef FIRMWARE_ZYNQMP_H_
>  #define FIRMWARE_ZYNQMP_H_
>
> +#include <firmware.h>
> +
>  #define PAYLOAD_ARG_CNT                      4
>
>  #define ZYNQMP_PM_VERSION(MAJOR, MINOR)      ((MAJOR << 16) | MINOR)
> @@ -27,6 +29,50 @@
>
>  #define ZYNQMP_PCAP_STATUS_FPGA_DONE BIT(3)
>
> +#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL   BIT(0)
> +#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED    BIT(1)
> +
> +#define ZYNQMP_PM_VERSION_1_0_FEATURES       0
> +#define ZYNQMP_PM_VERSION_1_1_FEATURES       (ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
> +                                      ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
> +
> +/*
> + * Xilinx KU040 Bitstream Composition:
> + *
> + * Bitstream can be provided with an optinal header (`struct bs_header`).
> + * The true bitstream starts with the binary-header composed of 21 words:
> + *
> + *  0: 0xFFFFFFFF (Dummy pad word)
> + *     ...
> + * 15: 0xFFFFFFFF (Dummy pad word)
> + * 16: 0x000000BB (Bus width auto detect word 1)
> + * 17: 0x11220044 (Bus width auto detect word 2)
> + * 18: 0xFFFFFFFF (Dummy pad word)
> + * 19: 0xFFFFFFFF (Dummy pad word)
> + * 20: 0xAA995566 (Sync word)
> + *
> + * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
> + * Details - Bitstream Composition" for further details.
> + */
> +#define DUMMY_WORD                   0xFFFFFFFF
> +#define BUS_WIDTH_AUTO_DETECT1_OFFSET        16
> +#define BUS_WIDTH_AUTO_DETECT1               0x000000BB
> +#define BUS_WIDTH_AUTO_DETECT2_OFFSET        17
> +#define BUS_WIDTH_AUTO_DETECT2               0x11220044
> +#define SYNC_WORD_OFFSET             20
> +#define SYNC_WORD                    0xAA995566
> +#define BIN_HEADER_LENGTH            21
> +
> +struct fpgamgr {
> +     struct firmware_handler fh;
> +     struct device_d dev;
> +     const struct zynqmp_eemi_ops *eemi_ops;
> +     int programmed;
> +     char *buf;
> +     size_t size;
> +     u32 features;
> +};
> +
>  enum pm_ioctl_id {
>       IOCTL_SET_PLL_FRAC_MODE = 8,
>       IOCTL_GET_PLL_FRAC_MODE,
> diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
> index 90b4c0ab9..a00d682a9 100644
> --- a/drivers/firmware/Kconfig
> +++ b/drivers/firmware/Kconfig
> @@ -15,6 +15,13 @@ config FIRMWARE_ALTERA_SOCFPGA
>       depends on ARCH_SOCFPGA
>       select FIRMWARE
>
> +config FIRMWARE_ZYNQ7000_FPGA
> +     bool "Xilinx Zynq 7000 FPGA loader"
> +     depends on ARCH_ZYNQ
> +     select FIRMWARE
> +     help
> +       Load a bitstream to the PL of Zynq
> +
>  config FIRMWARE_ZYNQMP_FPGA
>       bool "Xilinx ZynqMP FPGA loader"
>       depends on ARCH_ZYNQMP
> diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
> index b162b08b0..a7c6344bf 100644
> --- a/drivers/firmware/Makefile
> +++ b/drivers/firmware/Makefile
> @@ -1,3 +1,4 @@
>  obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
>  obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
> +obj-$(CONFIG_FIRMWARE_ZYNQ7000_FPGA) += zynqmp-fpga.o
>  obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
> diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
> index ab70d9993..4ce835e18 100644
> --- a/drivers/firmware/zynqmp-fpga.c
> +++ b/drivers/firmware/zynqmp-fpga.c
> @@ -15,57 +15,19 @@
>  #include <common.h>
>  #include <init.h>
>  #include <dma.h>
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
>  #include <mach/firmware-zynqmp.h>
> -
> -#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL   BIT(0)
> -#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED    BIT(1)
> -
> -#define ZYNQMP_PM_VERSION_1_0_FEATURES       0
> -#define ZYNQMP_PM_VERSION_1_1_FEATURES       (ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
> -                                      ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
> -
> -/*
> - * Xilinx KU040 Bitstream Composition:
> - *
> - * Bitstream can be provided with an optinal header (`struct bs_header`).
> - * The true bitstream starts with the binary-header composed of 21 words:
> - *
> - *  0: 0xFFFFFFFF (Dummy pad word)
> - *     ...
> - * 15: 0xFFFFFFFF (Dummy pad word)
> - * 16: 0x000000BB (Bus width auto detect word 1)
> - * 17: 0x11220044 (Bus width auto detect word 2)
> - * 18: 0xFFFFFFFF (Dummy pad word)
> - * 19: 0xFFFFFFFF (Dummy pad word)
> - * 20: 0xAA995566 (Sync word)
> - *
> - * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
> - * Details - Bitstream Composition" for further details.
> - */
> -#define DUMMY_WORD                   0xFFFFFFFF
> -#define BUS_WIDTH_AUTO_DETECT1_OFFSET        16
> -#define BUS_WIDTH_AUTO_DETECT1               0x000000BB
> -#define BUS_WIDTH_AUTO_DETECT2_OFFSET        17
> -#define BUS_WIDTH_AUTO_DETECT2               0x11220044
> -#define SYNC_WORD_OFFSET             20
> -#define SYNC_WORD                    0xAA995566
> -#define BIN_HEADER_LENGTH            21
> +#endif
> +#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
> +#include <mach/firmware-zynq.h>
> +#include <mach/zynq7000-regs.h>
> +#endif

Is it possible to change the is_bin_header_valid() function to identify the
(slightly) different bitstream header formats at runtime? I would like to keep
the header specification in the driver instead of moving it to header files
and making it configuration dependent.

>
>  enum xilinx_byte_order {
>       XILINX_BYTE_ORDER_BIT,
>       XILINX_BYTE_ORDER_BIN,
>  };
>
> -struct fpgamgr {
> -     struct firmware_handler fh;
> -     struct device_d dev;
> -     const struct zynqmp_eemi_ops *eemi_ops;
> -     int programmed;
> -     char *buf;
> -     size_t size;
> -     u32 features;
> -};
> -
>  struct bs_header {
>       __be16 length;
>       u8 padding[9];
> @@ -234,6 +196,13 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
>               goto err_free;
>       }
>
> +     buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
> +     if (!buf_aligned) {
> +             status = -ENOBUFS;
> +             goto err_free;
> +     }
> +
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA

Avoid the #ifdefs in the driver. Check for the compatible or add an identifier
to struct fpgamgr to decide if the driver can access the register directly or
needs to use the ZynqMP firmware calls.

If necessary, stub functions in the headers if some configuration is not set
and return an error.

Michael

>       if (!(mgr->features & ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)) {
>               buf_size = dma_alloc_coherent(sizeof(*buf_size),
>               DMA_ADDRESS_BROKEN);
> @@ -244,12 +213,6 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
>               *buf_size = body_length;
>       }
>
> -     buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
> -     if (!buf_aligned) {
> -             status = -ENOBUFS;
> -             goto err_free;
> -     }
> -
>       if (!(mgr->features & ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL) &&
>           byte_order == XILINX_BYTE_ORDER_BIN)
>               copy_words_swapped((u32 *)buf_aligned, body,
> @@ -271,7 +234,32 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
>               status = mgr->eemi_ops->fpga_load(addr, (u32)(body_length),
>                                                 flags);
>       }
> +#endif
> +#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
> +     /* UG585 (v1.12.2) July 1, 2018 Chapter 6.4.3
> +      * In all modes, the DMA transactions must be 64-byte aligned to prevent
> +      * accidently crossing a 4K byte boundary.
> +      */
> +     if(byte_order == XILINX_BYTE_ORDER_BIN)
> +             copy_words_swapped((u32 *)buf_aligned, body, body_length / sizeof(u32));
> +     else
> +             memcpy((u32 *)buf_aligned, body, body_length);
> +
> +     addr = (u32)buf_aligned;
> +
> +     writel(0x0000DF0D, ZYNQ_SLCR_UNLOCK);
> +     writel(0x0000000f, ZYNQ_SLCR_BASE + 0x240); // assert FPGA resets
> +
> +     writel(0x00000000, ZYNQ_SLCR_BASE + 0x900); // disable levelshifter
> +     writel(0x0000000a, ZYNQ_SLCR_BASE + 0x900); // enable levelshifter PS-PL
> +
> +     status = mgr->devc_ops->fpga_load(mgr, addr, (u32)(body_length), 0);
>
> +     writel(0x0000000f, ZYNQ_SLCR_BASE + 0x900); // enable all levelshifter
> +     writel(0x00000000, ZYNQ_SLCR_BASE + 0x240); // deassert FPGA resets
> +
> +     writel(0x0000767B, ZYNQ_SLCR_LOCK);
> +#endif
>       if (status < 0)
>               dev_err(&mgr->dev, "unable to load fpga\n");
>
> @@ -313,8 +301,10 @@ static int fpgamgr_program_start(struct firmware_handler *fh)
>       return 0;
>  }
>
> +
>  static int programmed_get(struct param_d *p, void *priv)
>  {
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
>       struct fpgamgr *mgr = priv;
>       u32 status = 0x00;
>       int ret = 0;
> @@ -324,7 +314,7 @@ static int programmed_get(struct param_d *p, void *priv)
>               return ret;
>
>       mgr->programmed = !!(status & ZYNQMP_PCAP_STATUS_FPGA_DONE);
> -
> +#endif
>       return 0;
>  }
>
> @@ -336,6 +326,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
>       const char *model = NULL;
>       struct param_d *p;
>       u32 api_version;
> +     struct resource *iores;
>       int ret;
>
>       mgr = xzalloc(sizeof(*mgr));
> @@ -354,6 +345,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
>               fh->model = xstrdup(model);
>       fh->dev = dev;
>
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
>       mgr->eemi_ops = zynqmp_pm_get_eemi_ops();
>
>       ret = mgr->eemi_ops->get_api_version(&api_version);
> @@ -361,11 +353,21 @@ static int zynqmp_fpga_probe(struct device_d *dev)
>               dev_err(&mgr->dev, "could not get API version\n");
>               goto out;
>       }
> -
> -     mgr->features = 0;
> -
>       if (api_version >= ZYNQMP_PM_VERSION(1, 1))
>               mgr->features |= ZYNQMP_PM_VERSION_1_1_FEATURES;
> +#endif
> +#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
> +     iores = dev_request_mem_resource(dev, 0);
> +     if (IS_ERR(iores)) {
> +             ret = PTR_ERR(iores);
> +             goto out;
> +     }
> +     mgr->regs = IOMEM(iores->start);
> +     mgr->devc_ops = zynq_get_devc_ops();
> +     /* Unlock DevC in case BootROM did not do it */
> +     writel(DEVC_UNLOCK_CODE, mgr->regs + UNLOCK_OFFSET);
> +#endif
> +     mgr->features = 0;
>
>       dev_dbg(dev, "Registering ZynqMP FPGA programmer\n");
>       mgr->dev.id = DEVICE_ID_SINGLE;
> @@ -400,9 +402,8 @@ out:
>  }
>
>  static struct of_device_id zynqmpp_fpga_id_table[] = {
> -     {
> -             .compatible = "xlnx,zynqmp-pcap-fpga",
> -     },
> +     { .compatible = "xlnx,zynqmp-pcap-fpga" },
> +     { .compatible = "xlnx,zynq-devcfg-1.0" },
>       { /* sentinel */ }
>  };
>
> --
> 2.25.1
>
>

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/1] added support for zynq7000-fpga-manager
  2021-03-30 12:05   ` AW: " Michael Graichen
@ 2021-04-08 15:28     ` Michael Tretter
  2021-04-28  8:16       ` AW: " Michael Graichen
  0 siblings, 1 reply; 6+ messages in thread
From: Michael Tretter @ 2021-04-08 15:28 UTC (permalink / raw)
  To: Michael Graichen; +Cc: Ahmad Fatoum, barebox

Hi Michael,

On Tue, 30 Mar 2021 12:05:31 +0000, Michael Graichen wrote:
> > I think, it would be fine to use only "zynq" instead of zynqmp for the
> > firmware loader/fpga manager. (I didn't compare the Zynq7000 and ZynqMP low
> > level interfaces for programming the FPGA, yet, but I guess that programming
> > the FPGA on the ZynqMP in EL3 instead of EL2/EL1 is actually the same as on
> > Zynq7000.) I am also ok with treating ZynqMP as a second class citizen in the
> > driver. 
> 
> As I compared
> https://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf
> page 211ff and
> https://www.xilinx.com/support/documentation/user_guides/ug1085-zynq-ultrascale-trm.pdf
> page 261ff the programming of the PCAP seem to be similar, but PCAP is
> embedded in CSU/PMU on ZynqMP, which looks much more complex then DEVC on
> Zynq7000. But I don't know how much of CSUs functionality is acctually
> needed to programm the FPGA.

The PCAP behave similar and have similar registers and bits, but the register
layouts are completely different. It seems that for programming the FPGA on
the ZynqMP, one would at least have to configure the internal stream switch
and use CSU DMA engine for the image transfer. For encrypted bitstreams, the
AES engine in the CSU has to be used as well.

> 
> Is the CSU within ZynqMP used for something other than programming the
> firmware in barebox?

At the moment, Barebox doesn't directly use the CSU. Barebox is not even
allowed to access the CSU register. It uses SMCs via TF-A to instruct the
PMU-FW to program the FPGA. The PMU-FW then talks to the CSU for actually
programming the FPGA.

If Barebox would run as first stage bootloader, it might use the CSU to read
the PS version or might use some of the authentication/encryption features of
the CSU, but this is currently not the case.

Watch out for the overloaded term "firmware". The firmware manager in the
zynqmp-fpga driver in Barebox is able to _load_ a "firmware", in this case the
FPGA bitstream. The firmware-zynqmp driver is a driver to _talk to_ the PMU
firmware, which is a firmware that is already running on the system.

Michael

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 6+ messages in thread

* AW: [PATCH 1/1] added support for zynq7000-fpga-manager
  2021-04-08 15:28     ` Michael Tretter
@ 2021-04-28  8:16       ` Michael Graichen
  0 siblings, 0 replies; 6+ messages in thread
From: Michael Graichen @ 2021-04-28  8:16 UTC (permalink / raw)
  To: Michael Tretter; +Cc: Ahmad Fatoum, barebox

Hi Michael,

Thanks, for the explanation.

I have attached two patches below.
0001-added-support-for-zynq7000-fpga-manager.patch adds the fpga-manager for Zynq-7000 with some changes mentioned by Ahmed. 
0002-renamed-zynqmp_fpga_manager-to-zynq_fpga_manager.patch renames it


> On Tue, 30 Mar 2021 12:05:31 +0000, Michael Graichen wrote:
> > I think, it would be fine to use only "zynq" instead of zynqmp for the
> > firmware loader/fpga manager. (I didn't compare the Zynq7000 and ZynqMP low
> > level interfaces for programming the FPGA, yet, but I guess that programming
> > the FPGA on the ZynqMP in EL3 instead of EL2/EL1 is actually the same as on
> > Zynq7000.) I am also ok with treating ZynqMP as a second class citizen in the
> > driver.
>
> As I compared
> https://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf
> page 211ff and
> https://www.xilinx.com/support/documentation/user_guides/ug1085-zynq-ultrascale-trm.pdf
> page 261ff the programming of the PCAP seem to be similar, but PCAP is
> embedded in CSU/PMU on ZynqMP, which looks much more complex then DEVC on
> Zynq7000. But I don't know how much of CSUs functionality is acctually
> needed to programm the FPGA.

The PCAP behave similar and have similar registers and bits, but the register
layouts are completely different. It seems that for programming the FPGA on
the ZynqMP, one would at least have to configure the internal stream switch
and use CSU DMA engine for the image transfer. For encrypted bitstreams, the
AES engine in the CSU has to be used as well.

>
> Is the CSU within ZynqMP used for something other than programming the
> firmware in barebox?

At the moment, Barebox doesn't directly use the CSU. Barebox is not even
allowed to access the CSU register. It uses SMCs via TF-A to instruct the
PMU-FW to program the FPGA. The PMU-FW then talks to the CSU for actually
programming the FPGA.

If Barebox would run as first stage bootloader, it might use the CSU to read
the PS version or might use some of the authentication/encryption features of
the CSU, but this is currently not the case.

Watch out for the overloaded term "firmware". The firmware manager in the
zynqmp-fpga driver in Barebox is able to _load_ a "firmware", in this case the
FPGA bitstream. The firmware-zynqmp driver is a driver to _talk to_ the PMU
firmware, which is a firmware that is already running on the system.

Michael

>From f97da4115d5a66adcf293ef2d1f3de51c10729d7 Mon Sep 17 00:00:00 2001
From: Michael Graichen <michael.graichen@hotmail.com>
Date: Wed, 28 Apr 2021 08:46:02 +0200
Subject: [PATCH 1/2] added support for zynq7000-fpga-manager

Signed-off-by: Michael Graichen <michael.graichen@hotmail.com>
---
 arch/arm/configs/zynq_defconfig               |   2 +
 arch/arm/mach-zynq/Makefile                   |   2 +-
 arch/arm/mach-zynq/firmware-zynq.c            | 145 ++++++++++++++++++
 .../mach-zynq/include/mach/firmware-zynq.h    |  85 ++++++++++
 .../include/mach/firmware-zynqmp.h            |  46 ++++++
 drivers/firmware/Kconfig                      |   7 +
 drivers/firmware/Makefile                     |   1 +
 drivers/firmware/zynqmp-fpga.c                | 124 ++++++++-------
 8 files changed, 352 insertions(+), 60 deletions(-)
 create mode 100644 arch/arm/mach-zynq/firmware-zynq.c
 create mode 100644 arch/arm/mach-zynq/include/mach/firmware-zynq.h

diff --git a/arch/arm/configs/zynq_defconfig b/arch/arm/configs/zynq_defconfig
index a16c57d5c..82ea899e2 100644
--- a/arch/arm/configs/zynq_defconfig
+++ b/arch/arm/configs/zynq_defconfig
@@ -36,6 +36,7 @@ CONFIG_CMD_MENU_MANAGEMENT=y
 CONFIG_CMD_READLINE=y
 CONFIG_CMD_TIMEOUT=y
 CONFIG_CMD_CLK=y
+CONFIG_CMD_FIRMWARELOAD=y
 CONFIG_CMD_OFTREE=y
 CONFIG_CMD_TIME=y
 CONFIG_NET=y
@@ -43,5 +44,6 @@ CONFIG_DRIVER_SERIAL_CADENCE=y
 CONFIG_DRIVER_NET_MACB=y
 # CONFIG_SPI is not set
 # CONFIG_PINCTRL is not set
+CONFIG_FIRMWARE_ZYNQ7000_FPGA=y
 CONFIG_FS_TFTP=y
 CONFIG_DIGEST=y
diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
index 06c2ce996..2484abe5c 100644
--- a/arch/arm/mach-zynq/Makefile
+++ b/arch/arm/mach-zynq/Makefile
@@ -1,2 +1,2 @@
-obj-y += zynq.o bootm-zynqimg.o
+obj-y += bootm-zynqimg.o firmware-zynq.o zynq.o
 lwl-y += cpu_init.o
diff --git a/arch/arm/mach-zynq/firmware-zynq.c b/arch/arm/mach-zynq/firmware-zynq.c
new file mode 100644
index 000000000..947e83a89
--- /dev/null
+++ b/arch/arm/mach-zynq/firmware-zynq.c
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ */
+#include <common.h>
+#include <init.h>
+#include <linux/iopoll.h>
+#include <mach/firmware-zynq.h>
+
+/*
+ * zynq_devc_fpga_load - Perform the fpga load
+ * @mgr:	FPGA-Manager
+ * @address:	Address to write to
+ * @size:	PL bitstream size
+ * @flags:	Flags - unused
+ *
+ * This function provides access to PCAP to transfer
+ * the required bitstream into PL.
+ *
+ * Return:	Returns status, either success or error+reason
+ */
+static int zynq_devc_fpga_load(struct fpgamgr *mgr, u64 address,
+				u32 size, u32 flags)
+{
+	unsigned long reg;
+	int ret;
+
+	if (!address || !size)
+		return -EINVAL;
+
+	/*
+	 * The Programming Seqenze, see ug585 (v.12.2) Juny 1, 2018 Chapter
+	 * 6.4.2 on page 211 Configure the PL via PCAP Bridge Example for
+	 * detailed information to this Sequenze
+	 */
+
+	/* Enable the PCAP bridge and select PCAP for reconfiguration */
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg |= ( CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK );
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	/* Clear the interrupts */
+	writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
+
+	/* Initialize the PL */
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg |= CTRL_PCFG_PROG_B_MASK;
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg &= ~CTRL_PCFG_PROG_B_MASK;
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	ret = readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
+			!(reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
+	if (ret < 0) {
+		dev_err(&mgr->dev, "initialisation timout");
+		return ret;
+	}
+
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg |= CTRL_PCFG_PROG_B_MASK;
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	/* Clear the Interrupts */
+	writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
+
+	/* Ensure that the PL is ready for programming */
+	ret = readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
+			(reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
+	if (ret < 0) {
+		dev_err(&mgr->dev, "timeout waiting for PL");
+		return ret;
+	}
+
+	/* Check that there is room in the command queue */
+	ret = readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
+			!(reg & STATUS_DMA_CMD_Q_F_MASK), 100 * USEC_PER_MSEC);
+	if (ret < 0) {
+		dev_err(&mgr->dev, "not enough space in DMA queue");
+		return ret;
+	}
+
+	/* Disable the PCAP loopback */
+	reg = readl(mgr->regs + MCTRL_OFFSET);
+	reg &= ~MCTRL_INT_PCAP_LPBK_MASK;
+	writel(reg, mgr->regs + MCTRL_OFFSET);
+
+	/* Program the PCAP_2x clock divider */
+	reg = readl(mgr->regs + CTRL_OFFSET);
+	reg &= ~CTRL_PCAP_RATE_EN_MASK;
+	writel(reg, mgr->regs + CTRL_OFFSET);
+
+	/* Source Address: Location of bitstream */
+	writel(address, mgr->regs + DMA_SRC_ADDR_OFFSET);
+
+	/* Destination Address: 0xFFFF_FFFF */
+	writel(0xffffffff, mgr->regs + DMA_DST_ADDR_OFFSET);
+
+	/* Source Length: Total number of 32-bit words in the bitstream */
+	writel((size >> 2), mgr->regs + DMA_SRC_LEN_OFFSET);
+
+	/* Destination Length: Total number of 32-bit words in the bitstream */
+	writel((size >> 2), mgr->regs + DMA_DEST_LEN_OFFSET);
+
+	/* Wait for the DMA transfer to be done */
+	ret = readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
+			(reg & INT_STS_D_P_DONE_MASK), 100 * USEC_PER_MSEC);
+	if (ret < 0) {
+		dev_err(&mgr->dev, "PCAP/DMA transfer timeout");
+		return ret;
+	}
+
+	/* Check for errors */
+	if (reg & INT_STS_ERROR_FLAGS_MASK) {
+		dev_err(&mgr->dev, "interrupt status register (0x%04lx)\n", reg);
+		return -EIO;
+	}
+
+	/* Wait for the DMA transfer to be done and PL is in user mode */
+	ret = readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
+			(reg & INT_STS_DONE_INT_MASK), 100 * USEC_PER_MSEC);
+	if (ret < 0) {
+		dev_err(&mgr->dev, "PL programming timeout");
+		return ret;
+	}
+
+	dev_info(&mgr->dev, "FPGA config done\n");
+
+	return 0;
+}
+
+static const struct zynq_devc_ops devc_ops = {
+	.fpga_load = zynq_devc_fpga_load,
+};
+
+/**
+ * zynq_get_devc_ops - Get devc ops functions
+ *
+ * Return: Pointer of devc_ops structure
+ */
+const struct zynq_devc_ops *zynq_get_devc_ops(void)
+{
+	return &devc_ops;
+}
+EXPORT_SYMBOL_GPL(zynq_get_devc_ops);
diff --git a/arch/arm/mach-zynq/include/mach/firmware-zynq.h b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
new file mode 100644
index 000000000..217b1e9b2
--- /dev/null
+++ b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Xilinx Zynq Firmware layer
+ *
+ */
+
+#ifndef FIRMWARE_ZYNQ_H_
+#define FIRMWARE_ZYNQ_H_
+
+#include <firmware.h>
+
+#define CTRL_OFFSET				0x00
+#define LOCK_OFFSET				0x04
+#define INT_STS_OFFSET				0x0c
+#define INT_MASK_OFFSET			0x10
+#define STATUS_OFFSET				0x14
+#define DMA_SRC_ADDR_OFFSET			0x18
+#define DMA_DST_ADDR_OFFSET			0x1c
+#define DMA_SRC_LEN_OFFSET			0x20
+#define DMA_DEST_LEN_OFFSET			0x24
+#define UNLOCK_OFFSET				0x34
+#define MCTRL_OFFSET				0x80
+
+#define CTRL_PCFG_PROG_B_MASK			BIT(30)
+#define CTRL_PCAP_PR_MASK			BIT(27)
+#define CTRL_PCAP_MODE_MASK			BIT(26)
+#define CTRL_PCAP_RATE_EN_MASK		BIT(25)
+
+#define STATUS_DMA_CMD_Q_F_MASK		BIT(31)
+#define STATUS_PCFG_INIT_MASK			BIT(4)
+
+#define INT_STS_D_P_DONE_MASK			BIT(12)
+#define INT_STS_DONE_INT_MASK			BIT(2)
+#define INT_STS_ERROR_FLAGS_MASK		0x00f4c860
+
+#define MCTRL_INT_PCAP_LPBK_MASK		BIT(4)
+
+/*
+ * Xilinx 7-Series Bitstream Composition:
+ *
+ * Bitstream can be provided with an optinal header (`struct bs_header`).
+ * The true bitstream starts with the binary-header composed of 13 words:
+ *
+ *  0: 0xFFFFFFFF (Dummy pad word)
+ *     ...
+ *  7: 0xFFFFFFFF (Dummy pad word)
+ *  8: 0x000000BB (Bus width auto detect word 1)
+ *  9: 0x11220044 (Bus width auto detect word 2)
+ * 10: 0xFFFFFFFF (Dummy pad word)
+ * 11: 0xFFFFFFFF (Dummy pad word)
+ * 12: 0xAA995566 (Sync word)
+ *
+ * See Xilinx UG470 (v1.13.1) August 20 2018, Chapter 5 "Configuration
+ * Details - Bitstream Composition" for further details.
+ */
+
+#define DUMMY_WORD				0xFFFFFFFF
+#define BUS_WIDTH_AUTO_DETECT1_OFFSET		8
+#define BUS_WIDTH_AUTO_DETECT1		0x000000BB
+#define BUS_WIDTH_AUTO_DETECT2_OFFSET		9
+#define BUS_WIDTH_AUTO_DETECT2		0x11220044
+#define SYNC_WORD_OFFSET			12
+#define SYNC_WORD				0xAA995566
+#define BIN_HEADER_LENGTH			13
+
+#define DEVC_UNLOCK_CODE			0x757bdf0d
+
+struct fpgamgr {
+	struct firmware_handler fh;
+	struct device_d dev;
+	void __iomem *regs;
+	const struct zynq_devc_ops *devc_ops;
+	int programmed;
+	char *buf;
+	size_t size;
+	u32 features;
+};
+
+struct zynq_devc_ops {
+	int (*fpga_load)(struct fpgamgr *mgr, u64 address, u32 size, u32 flags);
+};
+
+const struct zynq_devc_ops *zynq_get_devc_ops(void);
+
+#endif /* FIRMWARE_ZYNQ_H_ */
diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
index a04482237..1764a2db3 100644
--- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
+++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
@@ -15,6 +15,8 @@
 #ifndef FIRMWARE_ZYNQMP_H_
 #define FIRMWARE_ZYNQMP_H_
 
+#include <firmware.h>
+
 #define PAYLOAD_ARG_CNT			4
 
 #define ZYNQMP_PM_VERSION(MAJOR, MINOR)	((MAJOR << 16) | MINOR)
@@ -27,6 +29,50 @@
 
 #define ZYNQMP_PCAP_STATUS_FPGA_DONE	BIT(3)
 
+#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL	BIT(0)
+#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED	BIT(1)
+
+#define ZYNQMP_PM_VERSION_1_0_FEATURES	0
+#define ZYNQMP_PM_VERSION_1_1_FEATURES	(ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
+					 ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
+
+/*
+ * Xilinx KU040 Bitstream Composition:
+ *
+ * Bitstream can be provided with an optinal header (`struct bs_header`).
+ * The true bitstream starts with the binary-header composed of 21 words:
+ *
+ *  0: 0xFFFFFFFF (Dummy pad word)
+ *     ...
+ * 15: 0xFFFFFFFF (Dummy pad word)
+ * 16: 0x000000BB (Bus width auto detect word 1)
+ * 17: 0x11220044 (Bus width auto detect word 2)
+ * 18: 0xFFFFFFFF (Dummy pad word)
+ * 19: 0xFFFFFFFF (Dummy pad word)
+ * 20: 0xAA995566 (Sync word)
+ *
+ * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
+ * Details - Bitstream Composition" for further details.
+ */
+#define DUMMY_WORD			0xFFFFFFFF
+#define BUS_WIDTH_AUTO_DETECT1_OFFSET	16
+#define BUS_WIDTH_AUTO_DETECT1		0x000000BB
+#define BUS_WIDTH_AUTO_DETECT2_OFFSET	17
+#define BUS_WIDTH_AUTO_DETECT2		0x11220044
+#define SYNC_WORD_OFFSET		20
+#define SYNC_WORD			0xAA995566
+#define BIN_HEADER_LENGTH		21
+
+struct fpgamgr {
+	struct firmware_handler fh;
+	struct device_d dev;
+	const struct zynqmp_eemi_ops *eemi_ops;
+	int programmed;
+	char *buf;
+	size_t size;
+	u32 features;
+};
+
 enum pm_ioctl_id {
 	IOCTL_SET_PLL_FRAC_MODE = 8,
 	IOCTL_GET_PLL_FRAC_MODE,
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 90b4c0ab9..a00d682a9 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -15,6 +15,13 @@ config FIRMWARE_ALTERA_SOCFPGA
 	depends on ARCH_SOCFPGA
 	select FIRMWARE
 
+config FIRMWARE_ZYNQ7000_FPGA
+	bool "Xilinx Zynq 7000 FPGA loader"
+	depends on ARCH_ZYNQ
+	select FIRMWARE
+	help
+	  Load a bitstream to the PL of Zynq
+
 config FIRMWARE_ZYNQMP_FPGA
 	bool "Xilinx ZynqMP FPGA loader"
 	depends on ARCH_ZYNQMP
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index b162b08b0..a7c6344bf 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
 obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
+obj-$(CONFIG_FIRMWARE_ZYNQ7000_FPGA) += zynqmp-fpga.o
 obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
index ab70d9993..707a018b5 100644
--- a/drivers/firmware/zynqmp-fpga.c
+++ b/drivers/firmware/zynqmp-fpga.c
@@ -15,57 +15,19 @@
 #include <common.h>
 #include <init.h>
 #include <dma.h>
+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
 #include <mach/firmware-zynqmp.h>
-
-#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL	BIT(0)
-#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED	BIT(1)
-
-#define ZYNQMP_PM_VERSION_1_0_FEATURES	0
-#define ZYNQMP_PM_VERSION_1_1_FEATURES	(ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
-					 ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
-
-/*
- * Xilinx KU040 Bitstream Composition:
- *
- * Bitstream can be provided with an optinal header (`struct bs_header`).
- * The true bitstream starts with the binary-header composed of 21 words:
- *
- *  0: 0xFFFFFFFF (Dummy pad word)
- *     ...
- * 15: 0xFFFFFFFF (Dummy pad word)
- * 16: 0x000000BB (Bus width auto detect word 1)
- * 17: 0x11220044 (Bus width auto detect word 2)
- * 18: 0xFFFFFFFF (Dummy pad word)
- * 19: 0xFFFFFFFF (Dummy pad word)
- * 20: 0xAA995566 (Sync word)
- *
- * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
- * Details - Bitstream Composition" for further details.
- */
-#define DUMMY_WORD			0xFFFFFFFF
-#define BUS_WIDTH_AUTO_DETECT1_OFFSET	16
-#define BUS_WIDTH_AUTO_DETECT1		0x000000BB
-#define BUS_WIDTH_AUTO_DETECT2_OFFSET	17
-#define BUS_WIDTH_AUTO_DETECT2		0x11220044
-#define SYNC_WORD_OFFSET		20
-#define SYNC_WORD			0xAA995566
-#define BIN_HEADER_LENGTH		21
+#endif
+#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
+#include <mach/firmware-zynq.h>
+#include <mach/zynq7000-regs.h>
+#endif
 
 enum xilinx_byte_order {
 	XILINX_BYTE_ORDER_BIT,
 	XILINX_BYTE_ORDER_BIN,
 };
 
-struct fpgamgr {
-	struct firmware_handler fh;
-	struct device_d dev;
-	const struct zynqmp_eemi_ops *eemi_ops;
-	int programmed;
-	char *buf;
-	size_t size;
-	u32 features;
-};
-
 struct bs_header {
 	__be16 length;
 	u8 padding[9];
@@ -198,15 +160,16 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 {
 	struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
 	char *buf_aligned;
-	u32 *buf_size = NULL;
 	u32 *body;
 	size_t body_length;
 	int header_length = 0;
 	enum xilinx_byte_order byte_order;
 	u64 addr;
 	int status = 0;
+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
+	u32 *buf_size = NULL;
 	u8 flags = 0;
-
+#endif
 	if (!mgr->buf) {
 		status = -ENOBUFS;
 		dev_err(&mgr->dev, "buffer is NULL\n");
@@ -234,6 +197,13 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 		goto err_free;
 	}
 
+	buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
+	if (!buf_aligned) {
+		status = -ENOBUFS;
+		goto err_free;
+	}
+
+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
 	if (!(mgr->features & ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)) {
 		buf_size = dma_alloc_coherent(sizeof(*buf_size),
 		DMA_ADDRESS_BROKEN);
@@ -244,12 +214,6 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 		*buf_size = body_length;
 	}
 
-	buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
-	if (!buf_aligned) {
-		status = -ENOBUFS;
-		goto err_free;
-	}
-
 	if (!(mgr->features & ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL) &&
 	    byte_order == XILINX_BYTE_ORDER_BIN)
 		copy_words_swapped((u32 *)buf_aligned, body,
@@ -271,7 +235,32 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 		status = mgr->eemi_ops->fpga_load(addr, (u32)(body_length),
 						  flags);
 	}
+#endif
+#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
+	/* UG585 (v1.12.2) July 1, 2018 Chapter 6.4.3
+	 * In all modes, the DMA transactions must be 64-byte aligned to prevent
+	 * accidently crossing a 4K byte boundary.
+	 */
+	if(byte_order == XILINX_BYTE_ORDER_BIN)
+		copy_words_swapped((u32 *)buf_aligned, body, body_length / sizeof(u32));
+	else
+		memcpy((u32 *)buf_aligned, body, body_length);
+
+	addr = (u32)buf_aligned;
+
+	writel(0x0000DF0D, ZYNQ_SLCR_UNLOCK);
+	writel(0x0000000f, ZYNQ_SLCR_BASE + 0x240); // assert FPGA resets
+
+	writel(0x00000000, ZYNQ_SLCR_BASE + 0x900); // disable levelshifter
+	writel(0x0000000a, ZYNQ_SLCR_BASE + 0x900); // enable levelshifter PS-PL
 
+	status = mgr->devc_ops->fpga_load(mgr, addr, (u32)(body_length), 0);
+
+	writel(0x0000000f, ZYNQ_SLCR_BASE + 0x900); // enable all levelshifter
+	writel(0x00000000, ZYNQ_SLCR_BASE + 0x240); // deassert FPGA resets
+
+	writel(0x0000767B, ZYNQ_SLCR_LOCK);
+#endif
 	if (status < 0)
 		dev_err(&mgr->dev, "unable to load fpga\n");
 
@@ -313,8 +302,10 @@ static int fpgamgr_program_start(struct firmware_handler *fh)
 	return 0;
 }
 
+
 static int programmed_get(struct param_d *p, void *priv)
 {
+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
 	struct fpgamgr *mgr = priv;
 	u32 status = 0x00;
 	int ret = 0;
@@ -324,7 +315,7 @@ static int programmed_get(struct param_d *p, void *priv)
 		return ret;
 
 	mgr->programmed = !!(status & ZYNQMP_PCAP_STATUS_FPGA_DONE);
-
+#endif
 	return 0;
 }
 
@@ -335,7 +326,12 @@ static int zynqmp_fpga_probe(struct device_d *dev)
 	const char *alias = of_alias_get(dev->device_node);
 	const char *model = NULL;
 	struct param_d *p;
+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
 	u32 api_version;
+#endif
+#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
+	struct resource *iores;
+#endif
 	int ret;
 
 	mgr = xzalloc(sizeof(*mgr));
@@ -354,6 +350,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
 		fh->model = xstrdup(model);
 	fh->dev = dev;
 
+#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
 	mgr->eemi_ops = zynqmp_pm_get_eemi_ops();
 
 	ret = mgr->eemi_ops->get_api_version(&api_version);
@@ -361,11 +358,21 @@ static int zynqmp_fpga_probe(struct device_d *dev)
 		dev_err(&mgr->dev, "could not get API version\n");
 		goto out;
 	}
-
-	mgr->features = 0;
-
 	if (api_version >= ZYNQMP_PM_VERSION(1, 1))
 		mgr->features |= ZYNQMP_PM_VERSION_1_1_FEATURES;
+#endif
+#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores)) {
+		ret = PTR_ERR(iores);
+		goto out;
+	}
+	mgr->regs = IOMEM(iores->start);
+	mgr->devc_ops = zynq_get_devc_ops();
+	/* Unlock DevC in case BootROM did not do it */
+	writel(DEVC_UNLOCK_CODE, mgr->regs + UNLOCK_OFFSET);
+#endif
+	mgr->features = 0;
 
 	dev_dbg(dev, "Registering ZynqMP FPGA programmer\n");
 	mgr->dev.id = DEVICE_ID_SINGLE;
@@ -400,9 +407,8 @@ out:
 }
 
 static struct of_device_id zynqmpp_fpga_id_table[] = {
-	{
-		.compatible = "xlnx,zynqmp-pcap-fpga",
-	},
+	{ .compatible = "xlnx,zynqmp-pcap-fpga" },
+	{ .compatible = "xlnx,zynq-devcfg-1.0" },
 	{ /* sentinel */ }
 };
 
-- 
2.25.1

>From c3d0306aeecb93f35a7e57ea396db7dbca29f347 Mon Sep 17 00:00:00 2001
From: Michael Graichen <michael.graichen@hotmail.com>
Date: Wed, 28 Apr 2021 10:01:08 +0200
Subject: [PATCH 2/2] renamed "zynqmp_fpga_manager" to "zynq_fpga_manager"

Signed-off-by: Michael Graichen <michael.graichen@hotmail.com>
---
 drivers/firmware/Kconfig                      |  2 +-
 drivers/firmware/Makefile                     |  4 +--
 .../firmware/{zynqmp-fpga.c => zynq-fpga.c}   | 26 +++++++++----------
 3 files changed, 16 insertions(+), 16 deletions(-)
 rename drivers/firmware/{zynqmp-fpga.c => zynq-fpga.c} (94%)

diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index a00d682a9..198566a4e 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -20,7 +20,7 @@ config FIRMWARE_ZYNQ7000_FPGA
 	depends on ARCH_ZYNQ
 	select FIRMWARE
 	help
-	  Load a bitstream to the PL of Zynq
+	  Load a bitstream to the PL of Zynq 7000
 
 config FIRMWARE_ZYNQMP_FPGA
 	bool "Xilinx ZynqMP FPGA loader"
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index a7c6344bf..faa75c15b 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
 obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
-obj-$(CONFIG_FIRMWARE_ZYNQ7000_FPGA) += zynqmp-fpga.o
-obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
+obj-$(CONFIG_FIRMWARE_ZYNQ7000_FPGA) += zynq-fpga.o
+obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynq-fpga.o
diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynq-fpga.c
similarity index 94%
rename from drivers/firmware/zynqmp-fpga.c
rename to drivers/firmware/zynq-fpga.c
index 707a018b5..5cd42c311 100644
--- a/drivers/firmware/zynqmp-fpga.c
+++ b/drivers/firmware/zynq-fpga.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Xilinx Zynq MPSoC PL loading
+ * Xilinx Zynq MPSoC / Zynq 7000 PL loading
  *
  * Copyright (c) 2018 Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
  *
@@ -120,7 +120,7 @@ static int get_header_length(const char *header, size_t size)
 	return -EINVAL;
 }
 
-static void zynqmp_fpga_show_header(const struct device_d *dev,
+static void zynq_fpga_show_header(const struct device_d *dev,
 			 struct bs_header *header, size_t size)
 {
 	struct bs_header_entry *entry;
@@ -181,7 +181,7 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 		status = header_length;
 		goto err_free;
 	}
-	zynqmp_fpga_show_header(&mgr->dev,
+	zynq_fpga_show_header(&mgr->dev,
 			      (struct bs_header *)mgr->buf, header_length);
 
 	body = (u32 *)&mgr->buf[header_length];
@@ -319,7 +319,7 @@ static int programmed_get(struct param_d *p, void *priv)
 	return 0;
 }
 
-static int zynqmp_fpga_probe(struct device_d *dev)
+static int zynq_fpga_probe(struct device_d *dev)
 {
 	struct fpgamgr *mgr;
 	struct firmware_handler *fh;
@@ -340,7 +340,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
 	if (alias)
 		fh->id = xstrdup(alias);
 	else
-		fh->id = xstrdup("zynqmp-fpga-manager");
+		fh->id = xstrdup("zynq-fpga-manager");
 
 	fh->open = fpgamgr_program_start;
 	fh->write = fpgamgr_program_write_buf;
@@ -374,9 +374,9 @@ static int zynqmp_fpga_probe(struct device_d *dev)
 #endif
 	mgr->features = 0;
 
-	dev_dbg(dev, "Registering ZynqMP FPGA programmer\n");
+	dev_dbg(dev, "Registering Zynq FPGA programmer\n");
 	mgr->dev.id = DEVICE_ID_SINGLE;
-	dev_set_name(&mgr->dev, "zynqmp_fpga");
+	dev_set_name(&mgr->dev, "zynq_fpga");
 	mgr->dev.parent = dev;
 	ret = register_device(&mgr->dev);
 	if (ret)
@@ -406,15 +406,15 @@ out:
 	return ret;
 }
 
-static struct of_device_id zynqmpp_fpga_id_table[] = {
+static struct of_device_id zynq_fpga_id_table[] = {
 	{ .compatible = "xlnx,zynqmp-pcap-fpga" },
 	{ .compatible = "xlnx,zynq-devcfg-1.0" },
 	{ /* sentinel */ }
 };
 
-static struct driver_d zynqmp_fpga_driver = {
-	.name = "zynqmp_fpga_manager",
-	.of_compatible = DRV_OF_COMPAT(zynqmpp_fpga_id_table),
-	.probe = zynqmp_fpga_probe,
+static struct driver_d zynq_fpga_driver = {
+	.name = "zynq_fpga_manager",
+	.of_compatible = DRV_OF_COMPAT(zynq_fpga_id_table),
+	.probe = zynq_fpga_probe,
 };
-device_platform_driver(zynqmp_fpga_driver);
+device_platform_driver(zynq_fpga_driver);
-- 
2.25.1

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-04-28  8:18 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-25  7:53 [PATCH 1/1] added support for zynq7000-fpga-manager Michael Graichen
2021-03-25  8:09 ` Ahmad Fatoum
2021-03-25  8:42 ` Michael Tretter
2021-03-30 12:05   ` AW: " Michael Graichen
2021-04-08 15:28     ` Michael Tretter
2021-04-28  8:16       ` AW: " Michael Graichen

mail archive of the barebox mailing list

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://lore.barebox.org/barebox/0 barebox/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 barebox barebox/ https://lore.barebox.org/barebox \
		barebox@lists.infradead.org barebox@lists.infradead.org
	public-inbox-index barebox

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git