mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/5] ARM: zynqmp: add support for bitstream loading
@ 2019-10-24 10:26 Thomas Hämmerle
  2019-10-24 10:26 ` [PATCH 1/5] ARM: zynqmp: dts: move firmware node to src tree Thomas Hämmerle
                   ` (5 more replies)
  0 siblings, 6 replies; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-24 10:26 UTC (permalink / raw)
  To: barebox; +Cc: Thomas Hämmerle

From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

Michael Tretter (2):
  ARM: zynqmp: dts: move firmware node to src tree
  firmware: zynqmp-fpga: print Xilinx bitstream header

Thomas Haemmerle (3):
  firmware-zynqmp: extend driver with fpga relavant functions
  firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA
  ARM: zynqmp: dts: move pcap node to src tree

 arch/arm/configs/zynqmp_defconfig                  |   1 +
 arch/arm/dts/zynqmp-zcu104-revA.dts                |   1 -
 arch/arm/dts/zynqmp.dtsi                           |  17 -
 arch/arm/mach-zynqmp/firmware-zynqmp.c             |  47 +++
 .../arm/mach-zynqmp/include/mach/firmware-zynqmp.h |  10 +
 drivers/firmware/Kconfig                           |   5 +
 drivers/firmware/Makefile                          |   1 +
 drivers/firmware/zynqmp-fpga.c                     | 366 +++++++++++++++++++++
 dts/src/arm64/xilinx/zynqmp.dtsi                   |  10 +
 9 files changed, 440 insertions(+), 18 deletions(-)
 delete mode 100644 arch/arm/dts/zynqmp.dtsi
 create mode 100644 drivers/firmware/zynqmp-fpga.c

-- 
2.7.4


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

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

* [PATCH 1/5] ARM: zynqmp: dts: move firmware node to src tree
  2019-10-24 10:26 [PATCH 0/5] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
@ 2019-10-24 10:26 ` Thomas Hämmerle
  2019-10-24 12:56   ` Michael Tretter
  2019-10-24 10:26 ` [PATCH 4/5] ARM: zynqmp: dts: move pcap " Thomas Hämmerle
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-24 10:26 UTC (permalink / raw)
  To: barebox; +Cc: Michael Tretter

From: Michael Tretter <m.tretter@pengutronix.de>

The firmware node will be added to the mainline device tree. As it will
eventually enter Barebox via a device tree sync, add it to the src tree
already.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
 arch/arm/dts/zynqmp-zcu104-revA.dts |  1 -
 arch/arm/dts/zynqmp.dtsi            | 17 -----------------
 dts/src/arm64/xilinx/zynqmp.dtsi    |  7 +++++++
 3 files changed, 7 insertions(+), 18 deletions(-)
 delete mode 100644 arch/arm/dts/zynqmp.dtsi

diff --git a/arch/arm/dts/zynqmp-zcu104-revA.dts b/arch/arm/dts/zynqmp-zcu104-revA.dts
index c03112d..8b8dd84 100644
--- a/arch/arm/dts/zynqmp-zcu104-revA.dts
+++ b/arch/arm/dts/zynqmp-zcu104-revA.dts
@@ -8,5 +8,4 @@
  */
 
 #include <arm64/xilinx/zynqmp-zcu104-revA.dts>
-#include "zynqmp.dtsi"
 #include "zynqmp-clk.dtsi"
diff --git a/arch/arm/dts/zynqmp.dtsi b/arch/arm/dts/zynqmp.dtsi
deleted file mode 100644
index 59984ee..0000000
--- a/arch/arm/dts/zynqmp.dtsi
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * dts file for Xilinx ZynqMP
- *
- * (C) Copyright 2014 - 2015, Xilinx, Inc.
- *
- * Michal Simek <michal.simek@xilinx.com>
- */
-
-/ {
-	firmware {
-		zynqmp_firmware: zynqmp-firmware {
-			compatible = "xlnx,zynqmp-firmware";
-			method = "smc";
-		};
-	};
-};
diff --git a/dts/src/arm64/xilinx/zynqmp.dtsi b/dts/src/arm64/xilinx/zynqmp.dtsi
index 9aa6734..9115eae 100644
--- a/dts/src/arm64/xilinx/zynqmp.dtsi
+++ b/dts/src/arm64/xilinx/zynqmp.dtsi
@@ -115,6 +115,13 @@
 		method = "smc";
 	};
 
+	firmware {
+		zynqmp_firmware: zynqmp-firmware {
+			compatible = "xlnx,zynqmp-firmware";
+			method = "smc";
+		};
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupt-parent = <&gic>;
-- 
2.7.4


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

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

* [PATCH 4/5] ARM: zynqmp: dts: move pcap node to src tree
  2019-10-24 10:26 [PATCH 0/5] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
  2019-10-24 10:26 ` [PATCH 1/5] ARM: zynqmp: dts: move firmware node to src tree Thomas Hämmerle
@ 2019-10-24 10:26 ` Thomas Hämmerle
  2019-10-24 10:26 ` [PATCH 3/5] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA Thomas Hämmerle
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-24 10:26 UTC (permalink / raw)
  To: barebox; +Cc: Thomas Hämmerle

From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

The pcap node will be added to the mainline device tree. As it will
eventually enter Barebox via a device tree sync, add it to the src tree
already.

Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
---
 dts/src/arm64/xilinx/zynqmp.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/dts/src/arm64/xilinx/zynqmp.dtsi b/dts/src/arm64/xilinx/zynqmp.dtsi
index 9115eae..1d1e531 100644
--- a/dts/src/arm64/xilinx/zynqmp.dtsi
+++ b/dts/src/arm64/xilinx/zynqmp.dtsi
@@ -119,6 +119,9 @@
 		zynqmp_firmware: zynqmp-firmware {
 			compatible = "xlnx,zynqmp-firmware";
 			method = "smc";
+			zynqmp_pcap: pcap {
+				compatible = "xlnx,zynqmp-pcap-fpga";
+			};
 		};
 	};
 
-- 
2.7.4


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

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

* [PATCH 5/5] firmware: zynqmp-fpga: print Xilinx bitstream header
  2019-10-24 10:26 [PATCH 0/5] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
                   ` (2 preceding siblings ...)
  2019-10-24 10:26 ` [PATCH 3/5] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA Thomas Hämmerle
@ 2019-10-24 10:26 ` Thomas Hämmerle
  2019-10-24 10:26 ` [PATCH 2/5] firmware-zynqmp: extend driver with fpga relavant functions Thomas Hämmerle
  2019-10-25 12:55 ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
  5 siblings, 0 replies; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-24 10:26 UTC (permalink / raw)
  To: barebox; +Cc: Michael Tretter

From: Michael Tretter <m.tretter@pengutronix.de>

The bitstream header has 5 fields, that start with a char for the type.
Four fields have a big-ending length and a null-terminated string for
the design name, the part number, and the date and time of creation. The
last field is a big-endian 32 bit unsigned int for the size of the
bitstream.

Print this info when loading the bitstream.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
 drivers/firmware/zynqmp-fpga.c | 51 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
index 6a32d28..7bf880f 100644
--- a/drivers/firmware/zynqmp-fpga.c
+++ b/drivers/firmware/zynqmp-fpga.c
@@ -39,6 +39,19 @@ struct fpgamgr {
 	u32 features;
 };
 
+struct bs_header {
+	__be16 length;
+	u8 padding[9];
+	__be16 size;
+	char entries[0];
+} __attribute__ ((packed));
+
+struct bs_header_entry {
+	char type;
+	__be16 length;
+	char data[0];
+} __attribute__ ((packed));
+
 /* Xilinx binary format header */
 static const u32 bin_format[] = {
 	DUMMY_WORD,
@@ -100,6 +113,42 @@ static int get_header_length(const char *buf, size_t size)
 	return -EINVAL;
 }
 
+static void zynqmp_fpga_show_header(const struct device_d *dev,
+			 struct bs_header *header, size_t size)
+{
+	struct bs_header_entry *entry;
+	unsigned int i;
+	unsigned int length;
+
+	for (i = 0; i < size - sizeof(*header); i += sizeof(*entry) + length) {
+		entry = (struct bs_header_entry *)&header->entries[i];
+		length = __be16_to_cpu(entry->length);
+
+		switch (entry->type) {
+		case 'a':
+			printf("Design: %s\n", entry->data);
+			break;
+		case 'b':
+			printf("Part number: %s\n", entry->data);
+			break;
+		case 'c':
+			printf("Date: %s\n", entry->data);
+			break;
+		case 'd':
+			printf("Time: %s\n", entry->data);
+			break;
+		case 'e':
+			/* Size entry does not have a length but is be32 int */
+			printf("Size: %d bytes\n",
+			       (length << 16) + (entry->data[0] << 8) + entry->data[1]);
+			return;
+		default:
+			dev_warn(dev, "Invalid header entry: %c", entry->type);
+			return;
+		}
+	}
+}
+
 static int fpgamgr_program_finish(struct firmware_handler *fh)
 {
 	struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
@@ -121,6 +170,8 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 		status = header_length;
 		goto err_free;
 	}
+	zynqmp_fpga_show_header(&mgr->dev,
+			      (struct bs_header *)mgr->buf, header_length);
 
 	byte_order = get_byte_order((u32 *)&mgr->buf[header_length],
 			mgr->size - header_length);
-- 
2.7.4


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

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

* [PATCH 2/5] firmware-zynqmp: extend driver with fpga relavant functions
  2019-10-24 10:26 [PATCH 0/5] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
                   ` (3 preceding siblings ...)
  2019-10-24 10:26 ` [PATCH 5/5] firmware: zynqmp-fpga: print Xilinx bitstream header Thomas Hämmerle
@ 2019-10-24 10:26 ` Thomas Hämmerle
  2019-10-24 12:56   ` Michael Tretter
  2019-10-25 12:55 ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
  5 siblings, 1 reply; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-24 10:26 UTC (permalink / raw)
  To: barebox; +Cc: Thomas Hämmerle

From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

Port functions from xlnx-linux to get FPGA status and invoke bitstream
loading.

Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
---
 arch/arm/mach-zynqmp/firmware-zynqmp.c             | 47 ++++++++++++++++++++++
 .../arm/mach-zynqmp/include/mach/firmware-zynqmp.h |  8 ++++
 2 files changed, 55 insertions(+)

diff --git a/arch/arm/mach-zynqmp/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c
index f2187e9..18a1a51 100644
--- a/arch/arm/mach-zynqmp/firmware-zynqmp.c
+++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c
@@ -508,6 +508,51 @@ static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
 				   arg1, arg2, out);
 }
 
+/**
+ * zynqmp_pm_fpga_load - Perform the fpga load
+ * @address:	Address to write to
+ * @size:	pl bitstream size
+ * @flags:	Flags are used to specify the type of Bitstream file -
+ * 		defined in ZYNQMP_FPGA_BIT_*-macros
+ *
+ * This function provides access to xilfpga library to transfer
+ * the required bitstream into PL.
+ *
+ * Return:	Returns status, either success or error+reason
+ */
+static int zynqmp_pm_fpga_load(u64 address, u32 size, u32 flags)
+{
+	if (!address || !size)
+		return -EINVAL;
+
+	return zynqmp_pm_invoke_fn(PM_FPGA_LOAD,
+			lower_32_bits(address),	upper_32_bits(address),
+			size, flags, NULL);
+}
+
+/**
+ * zynqmp_pm_fpga_get_status - Read value from PCAP status register
+ * @value:	Value to read
+ *
+ * This function provides access to the xilfpga library to get
+ * the PCAP status
+ *
+ * Return:	Returns status, either success or error+reason
+ */
+static int zynqmp_pm_fpga_get_status(u32 *value)
+{
+	u32 ret_payload[PAYLOAD_ARG_CNT];
+	int ret = 0;
+
+	if (!value)
+		return -EINVAL;
+
+	ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
+	*value = ret_payload[1];
+
+	return ret;
+}
+
 static const struct zynqmp_eemi_ops eemi_ops = {
 	.get_api_version = zynqmp_pm_get_api_version,
 	.query_data = zynqmp_pm_query_data,
@@ -521,6 +566,8 @@ static const struct zynqmp_eemi_ops eemi_ops = {
 	.clock_setparent = zynqmp_pm_clock_setparent,
 	.clock_getparent = zynqmp_pm_clock_getparent,
 	.ioctl = zynqmp_pm_ioctl,
+	.fpga_getstatus = zynqmp_pm_fpga_get_status,
+	.fpga_load = zynqmp_pm_fpga_load,
 };
 
 /**
diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
index 9e7a2e3..f19d73d 100644
--- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
+++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
@@ -17,6 +17,12 @@
 
 #define PAYLOAD_ARG_CNT         4
 
+#define ZYNQMP_FPGA_BIT_AUTH_DDR	BIT(1)
+#define ZYNQMP_FPGA_BIT_AUTH_OCM	BIT(2)
+#define ZYNQMP_FPGA_BIT_ENC_USR_KEY	BIT(3)
+#define ZYNQMP_FPGA_BIT_ENC_DEV_KEY	BIT(4)
+#define ZYNQMP_FPGA_BIT_ONLY_BIN	BIT(5)
+
 enum pm_ioctl_id {
 	IOCTL_SET_PLL_FRAC_MODE = 8,
 	IOCTL_GET_PLL_FRAC_MODE,
@@ -61,6 +67,8 @@ struct zynqmp_eemi_ops {
 	int (*clock_setparent)(u32 clock_id, u32 parent_id);
 	int (*clock_getparent)(u32 clock_id, u32 *parent_id);
 	int (*ioctl)(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, u32 *out);
+	int (*fpga_getstatus)(u32 *status);
+	int (*fpga_load)(u64 address, u32 size, u32 flags);
 };
 
 const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);
-- 
2.7.4


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

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

* [PATCH 3/5] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA
  2019-10-24 10:26 [PATCH 0/5] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
  2019-10-24 10:26 ` [PATCH 1/5] ARM: zynqmp: dts: move firmware node to src tree Thomas Hämmerle
  2019-10-24 10:26 ` [PATCH 4/5] ARM: zynqmp: dts: move pcap " Thomas Hämmerle
@ 2019-10-24 10:26 ` Thomas Hämmerle
  2019-10-24 12:56   ` Michael Tretter
  2019-10-24 10:26 ` [PATCH 5/5] firmware: zynqmp-fpga: print Xilinx bitstream header Thomas Hämmerle
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-24 10:26 UTC (permalink / raw)
  To: barebox; +Cc: Thomas Hämmerle

From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

The driver provides functionalities to check and load a bitstream to FPGA.
A boolean parameter to check if FPGA is already programmed is
added.

Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
---
 arch/arm/configs/zynqmp_defconfig                  |   1 +
 .../arm/mach-zynqmp/include/mach/firmware-zynqmp.h |   2 +
 drivers/firmware/Kconfig                           |   5 +
 drivers/firmware/Makefile                          |   1 +
 drivers/firmware/zynqmp-fpga.c                     | 315 +++++++++++++++++++++
 5 files changed, 324 insertions(+)
 create mode 100644 drivers/firmware/zynqmp-fpga.c

diff --git a/arch/arm/configs/zynqmp_defconfig b/arch/arm/configs/zynqmp_defconfig
index 4dea964..834212e 100644
--- a/arch/arm/configs/zynqmp_defconfig
+++ b/arch/arm/configs/zynqmp_defconfig
@@ -35,4 +35,5 @@ CONFIG_CMD_OFTREE=y
 CONFIG_CMD_TIME=y
 CONFIG_DRIVER_SERIAL_CADENCE=y
 # CONFIG_SPI is not set
+CONFIG_FIRMWARE_ZYNQMP_PL=y
 CONFIG_DIGEST=y
diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
index f19d73d..6fcfba5 100644
--- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
+++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
@@ -23,6 +23,8 @@
 #define ZYNQMP_FPGA_BIT_ENC_DEV_KEY	BIT(4)
 #define ZYNQMP_FPGA_BIT_ONLY_BIN	BIT(5)
 
+#define ZYNQMP_PCAP_STATUS_FPGA_DONE	BIT(3)
+
 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 710b500..3113f40 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -14,4 +14,9 @@ config FIRMWARE_ALTERA_SOCFPGA
 	bool "Altera SoCFPGA fpga loader"
 	depends on ARCH_SOCFPGA
 	select FIRMWARE
+	
+config FIRMWARE_ZYNQMP_FPGA
+	bool "Xilinx ZynqMP FPGA loader"
+	depends on ARCH_ZYNQMP
+	select FIRMWARE
 endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index c3a3c34..b162b08 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
 obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
+obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
new file mode 100644
index 0000000..6a32d28
--- /dev/null
+++ b/drivers/firmware/zynqmp-fpga.c
@@ -0,0 +1,315 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Xilinx Zynq MPSoC PL loading
+ *
+ * Copyright (c) 2018 Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
+ *
+ * based on U-Boot zynqmppl code
+ *
+ * (C) Copyright 2015 - 2016, Xilinx, Inc,
+ * Michal Simek <michal.simek@xilinx.com>
+ * Siva Durga Prasad <siva.durga.paladugu@xilinx.com> *
+ */
+
+#include <firmware.h>
+#include <common.h>
+#include <init.h>
+#include <dma.h>
+#include <mach/firmware-zynqmp.h>
+
+#define ZYNQMP_PM_VERSION_1_1			((1 << 16) | 1)
+
+#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL	BIT(0)
+
+#define ZYNQMP_PM_VERSION_1_0_FEATURES	0
+#define ZYNQMP_PM_VERSION_1_1_FEATURES  ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL
+
+#define DUMMY_WORD			0xFFFFFFFF
+
+#define XILINX_BYTE_ORDER_BIT		0
+#define XILINX_BYTE_ORDER_BIN		1
+
+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;
+};
+
+/* Xilinx binary format header */
+static const u32 bin_format[] = {
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	0x000000bb,
+	0x11220044,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	0xaa995566,
+};
+
+static void copy_words_swapped(u32 *dst, const u32 *src, size_t size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		dst[i] = __swab32(src[i]);
+}
+
+static int get_byte_order(const u32 *buf, size_t size)
+{
+	u32 buf_check[ARRAY_SIZE(bin_format)];
+
+	memcpy(buf_check, buf, ARRAY_SIZE(buf_check));
+	if (memcmp(buf_check, bin_format, sizeof(buf_check)) == 0)
+		return XILINX_BYTE_ORDER_BIT;
+
+	copy_words_swapped(buf_check, buf, ARRAY_SIZE(buf_check));
+	if (memcmp(buf_check, bin_format, sizeof(buf_check)) == 0)
+		return XILINX_BYTE_ORDER_BIN;
+
+	return -EINVAL;
+}
+
+static int get_header_length(const char *buf, size_t size)
+{
+	u32 *buf_u32;
+	int p;
+
+	for (p = 0; p < size; p++) {
+		buf_u32 = (u32 *)&buf[p];
+		if (*buf_u32 == DUMMY_WORD)
+			return p;
+	}
+	return -EINVAL;
+}
+
+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;
+	int header_length = 0, byte_order = 0;
+	u64 addr;
+	int status = 0, xilfpga_old = 1;
+	u8 flags = 0;
+
+	if (!mgr->buf) {
+		status = -ENOBUFS;
+		dev_err(&mgr->dev, "buffer is NULL\n");
+		goto err_free;
+	}
+
+	header_length = get_header_length(mgr->buf, mgr->size);
+	if (header_length < 0) {
+		status = header_length;
+		goto err_free;
+	}
+
+	byte_order = get_byte_order((u32 *)&mgr->buf[header_length],
+			mgr->size - header_length);
+	if (byte_order < 0) {
+		status = byte_order;
+		goto err_free;
+	}
+
+	if (mgr->features & ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL) {
+		/* PMUFW version > 1.0 accepts both byte orders*/
+		byte_order = 0;
+		xilfpga_old = 0;
+	} else {
+		buf_size = dma_alloc_coherent(sizeof(*buf_size),
+		DMA_ADDRESS_BROKEN);
+		if (!buf_size) {
+			status = -ENOBUFS;
+			goto err_free;
+		}
+		*buf_size = mgr->size - header_length;
+	}
+
+	buf_aligned = dma_alloc_coherent(mgr->size - header_length,
+			DMA_ADDRESS_BROKEN);
+	if (!buf_aligned) {
+		status = -ENOBUFS;
+		goto err_free;
+	}
+
+	if (byte_order == XILINX_BYTE_ORDER_BIN)
+		copy_words_swapped((u32 *)buf_aligned,
+				(u32 *)(&(mgr->buf[header_length])),
+				(mgr->size - header_length) / sizeof(u32));
+	else
+		memcpy((u32 *)buf_aligned, (u32 *)(&(mgr->buf[header_length])),
+			(mgr->size - header_length));
+
+	addr = (u64)buf_aligned;
+
+	/* we do not provide a header */
+	flags |= ZYNQMP_FPGA_BIT_ONLY_BIN;
+
+	if (xilfpga_old && buf_size) {
+		status = mgr->eemi_ops->fpga_load(addr,
+				(u32)(uintptr_t)buf_size,
+				flags);
+		dma_free_coherent(buf_size, 0, sizeof(*buf_size));
+	} else {
+		status = mgr->eemi_ops->fpga_load(addr,
+				(u32)(mgr->size - header_length),
+				flags);
+	}
+
+	if (status < 0)
+		dev_err(&mgr->dev, "unable to load fpga\n");
+
+	dma_free_coherent(buf_aligned, 0, mgr->size - header_length);
+
+ err_free:
+	free(mgr->buf);
+
+	return status;
+}
+
+static int fpgamgr_program_write_buf(struct firmware_handler *fh,
+		const void *buf, size_t size)
+{
+	struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
+
+	/* Since write() is called by copy_file, we only receive chuncks with
+	 * size RW_BUF_SIZE of the bitstream.
+	 * Buffer the chunks here and handle it in close()
+	 */
+
+	mgr->buf = realloc(mgr->buf, mgr->size + size);
+	if (!mgr->buf)
+		return -ENOBUFS;
+
+	memcpy(&(mgr->buf[mgr->size]), buf, size);
+	mgr->size += size;
+
+	return 0;
+}
+
+static int fpgamgr_program_start(struct firmware_handler *fh)
+{
+	struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
+
+	mgr->size = 0;
+	mgr->buf = NULL;
+
+	return 0;
+}
+
+static int programmed_get(struct param_d *p, void *priv)
+{
+	struct fpgamgr *mgr = priv;
+	u32 status = 0x00;
+	int ret = 0;
+
+	ret = mgr->eemi_ops->fpga_getstatus(&status);
+	if (ret)
+		return ret;
+
+	mgr->programmed = !!(status & ZYNQMP_PCAP_STATUS_FPGA_DONE);
+
+	return 0;
+}
+
+static int zynqmp_fpga_probe(struct device_d *dev)
+{
+	struct fpgamgr *mgr;
+	struct firmware_handler *fh;
+	const char *alias = of_alias_get(dev->device_node);
+	const char *model = NULL;
+	struct param_d *p;
+	u32 api_version;
+	int ret;
+
+	mgr = xzalloc(sizeof(*mgr));
+	fh = &mgr->fh;
+
+	if (alias)
+		fh->id = xstrdup(alias);
+	else
+		fh->id = xstrdup("zynqmp-fpga-manager");
+
+	fh->open = fpgamgr_program_start;
+	fh->write = fpgamgr_program_write_buf;
+	fh->close = fpgamgr_program_finish;
+	of_property_read_string(dev->device_node, "compatible", &model);
+	if (model)
+		fh->model = xstrdup(model);
+	fh->dev = dev;
+
+	mgr->eemi_ops = zynqmp_pm_get_eemi_ops();
+
+	ret = mgr->eemi_ops->get_api_version(&api_version);
+	if (ret) {
+		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_FEATURE_BYTE_ORDER_IRREL;
+
+	dev_dbg(dev, "Registering ZynqMP FPGA programmer\n");
+	mgr->dev.id = DEVICE_ID_SINGLE;
+	dev_set_name(&mgr->dev, "zynqmp_fpga");
+	mgr->dev.parent = dev;
+	ret = register_device(&mgr->dev);
+	if (ret)
+		goto out;
+
+	p = dev_add_param_bool(&mgr->dev, "programmed", NULL, programmed_get,
+			&mgr->programmed, mgr);
+	if (IS_ERR(p)) {
+		ret = PTR_ERR(p);
+		goto out_unreg;
+	}
+
+	fh->dev = &mgr->dev;
+	ret = firmwaremgr_register(fh);
+	if (ret != 0) {
+		free(mgr);
+		goto out_unreg;
+	}
+
+	return 0;
+out_unreg:
+	unregister_device(&mgr->dev);
+out:
+	free(fh->id);
+	free(mgr);
+
+	return ret;
+}
+
+static struct of_device_id zynqmpp_fpga_id_table[] = {
+	{
+		.compatible = "xlnx,zynqmp-pcap-fpga",
+	},
+};
+
+static struct driver_d zynqmp_fpga_driver = {
+	.name = "zynqmp_fpga_manager",
+	.of_compatible = DRV_OF_COMPAT(zynqmpp_fpga_id_table),
+	.probe = zynqmp_fpga_probe,
+};
+device_platform_driver(zynqmp_fpga_driver);
-- 
2.7.4


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

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

* Re: [PATCH 1/5] ARM: zynqmp: dts: move firmware node to src tree
  2019-10-24 10:26 ` [PATCH 1/5] ARM: zynqmp: dts: move firmware node to src tree Thomas Hämmerle
@ 2019-10-24 12:56   ` Michael Tretter
  0 siblings, 0 replies; 15+ messages in thread
From: Michael Tretter @ 2019-10-24 12:56 UTC (permalink / raw)
  To: Thomas Hämmerle; +Cc: barebox

On Thu, 24 Oct 2019 10:26:50 +0000, Thomas Hämmerle wrote:
> From: Michael Tretter <m.tretter@pengutronix.de>
> 
> The firmware node will be added to the mainline device tree. As it will
> eventually enter Barebox via a device tree sync, add it to the src tree
> already.

Not sure, but I think that we should wait with the device tree changes
until they arrive via a sync with the kernel tree.

Michael

> 
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> ---
>  arch/arm/dts/zynqmp-zcu104-revA.dts |  1 -
>  arch/arm/dts/zynqmp.dtsi            | 17 -----------------
>  dts/src/arm64/xilinx/zynqmp.dtsi    |  7 +++++++
>  3 files changed, 7 insertions(+), 18 deletions(-)
>  delete mode 100644 arch/arm/dts/zynqmp.dtsi
> 
> diff --git a/arch/arm/dts/zynqmp-zcu104-revA.dts b/arch/arm/dts/zynqmp-zcu104-revA.dts
> index c03112d..8b8dd84 100644
> --- a/arch/arm/dts/zynqmp-zcu104-revA.dts
> +++ b/arch/arm/dts/zynqmp-zcu104-revA.dts
> @@ -8,5 +8,4 @@
>   */
>  
>  #include <arm64/xilinx/zynqmp-zcu104-revA.dts>
> -#include "zynqmp.dtsi"
>  #include "zynqmp-clk.dtsi"
> diff --git a/arch/arm/dts/zynqmp.dtsi b/arch/arm/dts/zynqmp.dtsi
> deleted file mode 100644
> index 59984ee..0000000
> --- a/arch/arm/dts/zynqmp.dtsi
> +++ /dev/null
> @@ -1,17 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0+
> -/*
> - * dts file for Xilinx ZynqMP
> - *
> - * (C) Copyright 2014 - 2015, Xilinx, Inc.
> - *
> - * Michal Simek <michal.simek@xilinx.com>
> - */
> -
> -/ {
> -	firmware {
> -		zynqmp_firmware: zynqmp-firmware {
> -			compatible = "xlnx,zynqmp-firmware";
> -			method = "smc";
> -		};
> -	};
> -};
> diff --git a/dts/src/arm64/xilinx/zynqmp.dtsi b/dts/src/arm64/xilinx/zynqmp.dtsi
> index 9aa6734..9115eae 100644
> --- a/dts/src/arm64/xilinx/zynqmp.dtsi
> +++ b/dts/src/arm64/xilinx/zynqmp.dtsi
> @@ -115,6 +115,13 @@
>  		method = "smc";
>  	};
>  
> +	firmware {
> +		zynqmp_firmware: zynqmp-firmware {
> +			compatible = "xlnx,zynqmp-firmware";
> +			method = "smc";
> +		};
> +	};
> +
>  	timer {
>  		compatible = "arm,armv8-timer";
>  		interrupt-parent = <&gic>;

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

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

* Re: [PATCH 2/5] firmware-zynqmp: extend driver with fpga relavant functions
  2019-10-24 10:26 ` [PATCH 2/5] firmware-zynqmp: extend driver with fpga relavant functions Thomas Hämmerle
@ 2019-10-24 12:56   ` Michael Tretter
  0 siblings, 0 replies; 15+ messages in thread
From: Michael Tretter @ 2019-10-24 12:56 UTC (permalink / raw)
  To: Thomas Hämmerle; +Cc: barebox

On Thu, 24 Oct 2019 10:26:51 +0000, Thomas Hämmerle wrote:
> From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> 
> Port functions from xlnx-linux to get FPGA status and invoke bitstream
> loading.
> 
> Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

Reviewed-by: Michael Tretter <m.tretter@pengutronix.de>

> ---
>  arch/arm/mach-zynqmp/firmware-zynqmp.c             | 47 ++++++++++++++++++++++
>  .../arm/mach-zynqmp/include/mach/firmware-zynqmp.h |  8 ++++
>  2 files changed, 55 insertions(+)
> 
> diff --git a/arch/arm/mach-zynqmp/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c
> index f2187e9..18a1a51 100644
> --- a/arch/arm/mach-zynqmp/firmware-zynqmp.c
> +++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c
> @@ -508,6 +508,51 @@ static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
>  				   arg1, arg2, out);
>  }
>  
> +/**
> + * zynqmp_pm_fpga_load - Perform the fpga load
> + * @address:	Address to write to
> + * @size:	pl bitstream size
> + * @flags:	Flags are used to specify the type of Bitstream file -
> + * 		defined in ZYNQMP_FPGA_BIT_*-macros
> + *
> + * This function provides access to xilfpga library to transfer
> + * the required bitstream into PL.
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_fpga_load(u64 address, u32 size, u32 flags)
> +{
> +	if (!address || !size)
> +		return -EINVAL;
> +
> +	return zynqmp_pm_invoke_fn(PM_FPGA_LOAD,
> +			lower_32_bits(address),	upper_32_bits(address),
> +			size, flags, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_fpga_get_status - Read value from PCAP status register
> + * @value:	Value to read
> + *
> + * This function provides access to the xilfpga library to get
> + * the PCAP status
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_fpga_get_status(u32 *value)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +	int ret = 0;
> +
> +	if (!value)
> +		return -EINVAL;
> +
> +	ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
> +	*value = ret_payload[1];
> +
> +	return ret;
> +}
> +
>  static const struct zynqmp_eemi_ops eemi_ops = {
>  	.get_api_version = zynqmp_pm_get_api_version,
>  	.query_data = zynqmp_pm_query_data,
> @@ -521,6 +566,8 @@ static const struct zynqmp_eemi_ops eemi_ops = {
>  	.clock_setparent = zynqmp_pm_clock_setparent,
>  	.clock_getparent = zynqmp_pm_clock_getparent,
>  	.ioctl = zynqmp_pm_ioctl,
> +	.fpga_getstatus = zynqmp_pm_fpga_get_status,
> +	.fpga_load = zynqmp_pm_fpga_load,
>  };
>  
>  /**
> diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> index 9e7a2e3..f19d73d 100644
> --- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> +++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> @@ -17,6 +17,12 @@
>  
>  #define PAYLOAD_ARG_CNT         4
>  
> +#define ZYNQMP_FPGA_BIT_AUTH_DDR	BIT(1)
> +#define ZYNQMP_FPGA_BIT_AUTH_OCM	BIT(2)
> +#define ZYNQMP_FPGA_BIT_ENC_USR_KEY	BIT(3)
> +#define ZYNQMP_FPGA_BIT_ENC_DEV_KEY	BIT(4)
> +#define ZYNQMP_FPGA_BIT_ONLY_BIN	BIT(5)
> +

I was not sure if the flags belong to the firmware interface or into
the driver that uses the interface. While unlikely, other drivers might
use the calls as well and, thus, here is the right place.

Michael

>  enum pm_ioctl_id {
>  	IOCTL_SET_PLL_FRAC_MODE = 8,
>  	IOCTL_GET_PLL_FRAC_MODE,
> @@ -61,6 +67,8 @@ struct zynqmp_eemi_ops {
>  	int (*clock_setparent)(u32 clock_id, u32 parent_id);
>  	int (*clock_getparent)(u32 clock_id, u32 *parent_id);
>  	int (*ioctl)(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, u32 *out);
> +	int (*fpga_getstatus)(u32 *status);
> +	int (*fpga_load)(u64 address, u32 size, u32 flags);
>  };
>  
>  const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);

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

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

* Re: [PATCH 3/5] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA
  2019-10-24 10:26 ` [PATCH 3/5] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA Thomas Hämmerle
@ 2019-10-24 12:56   ` Michael Tretter
  0 siblings, 0 replies; 15+ messages in thread
From: Michael Tretter @ 2019-10-24 12:56 UTC (permalink / raw)
  To: Thomas Hämmerle; +Cc: barebox

On Thu, 24 Oct 2019 10:26:51 +0000, Thomas Hämmerle wrote:
> From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> 
> The driver provides functionalities to check and load a bitstream to FPGA.
> A boolean parameter to check if FPGA is already programmed is
> added.
> 
> Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> ---
>  arch/arm/configs/zynqmp_defconfig                  |   1 +
>  .../arm/mach-zynqmp/include/mach/firmware-zynqmp.h |   2 +
>  drivers/firmware/Kconfig                           |   5 +
>  drivers/firmware/Makefile                          |   1 +
>  drivers/firmware/zynqmp-fpga.c                     | 315 +++++++++++++++++++++
>  5 files changed, 324 insertions(+)
>  create mode 100644 drivers/firmware/zynqmp-fpga.c
> 
> diff --git a/arch/arm/configs/zynqmp_defconfig b/arch/arm/configs/zynqmp_defconfig
> index 4dea964..834212e 100644
> --- a/arch/arm/configs/zynqmp_defconfig
> +++ b/arch/arm/configs/zynqmp_defconfig
> @@ -35,4 +35,5 @@ CONFIG_CMD_OFTREE=y
>  CONFIG_CMD_TIME=y
>  CONFIG_DRIVER_SERIAL_CADENCE=y
>  # CONFIG_SPI is not set
> +CONFIG_FIRMWARE_ZYNQMP_PL=y
>  CONFIG_DIGEST=y
> diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> index f19d73d..6fcfba5 100644
> --- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> +++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> @@ -23,6 +23,8 @@
>  #define ZYNQMP_FPGA_BIT_ENC_DEV_KEY	BIT(4)
>  #define ZYNQMP_FPGA_BIT_ONLY_BIN	BIT(5)
>  
> +#define ZYNQMP_PCAP_STATUS_FPGA_DONE	BIT(3)
> +

Should be part of the previous patch.

>  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 710b500..3113f40 100644
> --- a/drivers/firmware/Kconfig
> +++ b/drivers/firmware/Kconfig
> @@ -14,4 +14,9 @@ config FIRMWARE_ALTERA_SOCFPGA
>  	bool "Altera SoCFPGA fpga loader"
>  	depends on ARCH_SOCFPGA
>  	select FIRMWARE
> +	
> +config FIRMWARE_ZYNQMP_FPGA
> +	bool "Xilinx ZynqMP FPGA loader"
> +	depends on ARCH_ZYNQMP
> +	select FIRMWARE
>  endmenu
> diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
> index c3a3c34..b162b08 100644
> --- a/drivers/firmware/Makefile
> +++ b/drivers/firmware/Makefile
> @@ -1,2 +1,3 @@
>  obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
>  obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
> +obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
> diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
> new file mode 100644
> index 0000000..6a32d28
> --- /dev/null
> +++ b/drivers/firmware/zynqmp-fpga.c
> @@ -0,0 +1,315 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Xilinx Zynq MPSoC PL loading
> + *
> + * Copyright (c) 2018 Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> + *
> + * based on U-Boot zynqmppl code
> + *
> + * (C) Copyright 2015 - 2016, Xilinx, Inc,
> + * Michal Simek <michal.simek@xilinx.com>
> + * Siva Durga Prasad <siva.durga.paladugu@xilinx.com> *
> + */
> +
> +#include <firmware.h>
> +#include <common.h>
> +#include <init.h>
> +#include <dma.h>
> +#include <mach/firmware-zynqmp.h>
> +
> +#define ZYNQMP_PM_VERSION_1_1			((1 << 16) | 1)

A macro ZYNQMP_PM_VERSION(MAJOR, MINOR) would be more intuitive.

> +
> +#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL	BIT(0)
> +
> +#define ZYNQMP_PM_VERSION_1_0_FEATURES	0
> +#define ZYNQMP_PM_VERSION_1_1_FEATURES  ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL
> +
> +#define DUMMY_WORD			0xFFFFFFFF
> +
> +#define XILINX_BYTE_ORDER_BIT		0
> +#define XILINX_BYTE_ORDER_BIN		1
> +
> +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;
> +};
> +
> +/* Xilinx binary format header */
> +static const u32 bin_format[] = {
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	0x000000bb,
> +	0x11220044,
> +	DUMMY_WORD,
> +	DUMMY_WORD,
> +	0xaa995566,
> +};
> +
> +static void copy_words_swapped(u32 *dst, const u32 *src, size_t size)
> +{
> +	int i;
> +
> +	for (i = 0; i < size; i++)
> +		dst[i] = __swab32(src[i]);
> +}
> +
> +static int get_byte_order(const u32 *buf, size_t size)
> +{
> +	u32 buf_check[ARRAY_SIZE(bin_format)];
> +
> +	memcpy(buf_check, buf, ARRAY_SIZE(buf_check));
> +	if (memcmp(buf_check, bin_format, sizeof(buf_check)) == 0)
> +		return XILINX_BYTE_ORDER_BIT;
> +
> +	copy_words_swapped(buf_check, buf, ARRAY_SIZE(buf_check));
> +	if (memcmp(buf_check, bin_format, sizeof(buf_check)) == 0)
> +		return XILINX_BYTE_ORDER_BIN;
> +
> +	return -EINVAL;
> +}

The function does not only find the byte order, but also checks if the
header is valid. I would prefer, if we could have a function for
getting the byte order (no copy necessary, just check for one of the
values that allow to distinguish the byte order) and another function
for checking if the header is valid. 

> +
> +static int get_header_length(const char *buf, size_t size)
> +{
> +	u32 *buf_u32;
> +	int p;
> +
> +	for (p = 0; p < size; p++) {
> +		buf_u32 = (u32 *)&buf[p];
> +		if (*buf_u32 == DUMMY_WORD)
> +			return p;
> +	}
> +	return -EINVAL;
> +}
> +
> +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;
> +	int header_length = 0, byte_order = 0;
> +	u64 addr;
> +	int status = 0, xilfpga_old = 1;
> +	u8 flags = 0;
> +
> +	if (!mgr->buf) {
> +		status = -ENOBUFS;
> +		dev_err(&mgr->dev, "buffer is NULL\n");
> +		goto err_free;
> +	}
> +
> +	header_length = get_header_length(mgr->buf, mgr->size);
> +	if (header_length < 0) {
> +		status = header_length;
> +		goto err_free;
> +	}
> +
> +	byte_order = get_byte_order((u32 *)&mgr->buf[header_length],
> +			mgr->size - header_length);

I think helper variables u32 *body and size_t body_size would probably make
this a lot more readable.

> +	if (byte_order < 0) {
> +		status = byte_order;
> +		goto err_free;
> +	}
> +
> +	if (mgr->features & ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL) {
> +		/* PMUFW version > 1.0 accepts both byte orders*/
> +		byte_order = 0;
> +		xilfpga_old = 0;
> +	} else {
> +		buf_size = dma_alloc_coherent(sizeof(*buf_size),
> +		DMA_ADDRESS_BROKEN);
> +		if (!buf_size) {
> +			status = -ENOBUFS;
> +			goto err_free;
> +		}
> +		*buf_size = mgr->size - header_length;
> +	}
> +
> +	buf_aligned = dma_alloc_coherent(mgr->size - header_length,
> +			DMA_ADDRESS_BROKEN);
> +	if (!buf_aligned) {
> +		status = -ENOBUFS;
> +		goto err_free;
> +	}
> +
> +	if (byte_order == XILINX_BYTE_ORDER_BIN)
> +		copy_words_swapped((u32 *)buf_aligned,
> +				(u32 *)(&(mgr->buf[header_length])),
> +				(mgr->size - header_length) / sizeof(u32));
> +	else
> +		memcpy((u32 *)buf_aligned, (u32 *)(&(mgr->buf[header_length])),
> +			(mgr->size - header_length));
> +
> +	addr = (u64)buf_aligned;
> +
> +	/* we do not provide a header */
> +	flags |= ZYNQMP_FPGA_BIT_ONLY_BIN;
> +
> +	if (xilfpga_old && buf_size) {

The xilfpga_old variable is pretty hard to follow. Maybe always check
for the feature flag or test the feature flag once and set a local
variable (with a proper name) that is used whenever the feature flag is
relevant.

Michael

> +		status = mgr->eemi_ops->fpga_load(addr,
> +				(u32)(uintptr_t)buf_size,
> +				flags);
> +		dma_free_coherent(buf_size, 0, sizeof(*buf_size));
> +	} else {
> +		status = mgr->eemi_ops->fpga_load(addr,
> +				(u32)(mgr->size - header_length),
> +				flags);
> +	}
> +
> +	if (status < 0)
> +		dev_err(&mgr->dev, "unable to load fpga\n");
> +
> +	dma_free_coherent(buf_aligned, 0, mgr->size - header_length);
> +
> + err_free:
> +	free(mgr->buf);
> +
> +	return status;
> +}
> +
> +static int fpgamgr_program_write_buf(struct firmware_handler *fh,
> +		const void *buf, size_t size)
> +{
> +	struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
> +
> +	/* Since write() is called by copy_file, we only receive chuncks with
> +	 * size RW_BUF_SIZE of the bitstream.
> +	 * Buffer the chunks here and handle it in close()
> +	 */
> +
> +	mgr->buf = realloc(mgr->buf, mgr->size + size);
> +	if (!mgr->buf)
> +		return -ENOBUFS;
> +
> +	memcpy(&(mgr->buf[mgr->size]), buf, size);
> +	mgr->size += size;
> +
> +	return 0;
> +}
> +
> +static int fpgamgr_program_start(struct firmware_handler *fh)
> +{
> +	struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
> +
> +	mgr->size = 0;
> +	mgr->buf = NULL;
> +
> +	return 0;
> +}
> +
> +static int programmed_get(struct param_d *p, void *priv)
> +{
> +	struct fpgamgr *mgr = priv;
> +	u32 status = 0x00;
> +	int ret = 0;
> +
> +	ret = mgr->eemi_ops->fpga_getstatus(&status);
> +	if (ret)
> +		return ret;
> +
> +	mgr->programmed = !!(status & ZYNQMP_PCAP_STATUS_FPGA_DONE);
> +
> +	return 0;
> +}
> +
> +static int zynqmp_fpga_probe(struct device_d *dev)
> +{
> +	struct fpgamgr *mgr;
> +	struct firmware_handler *fh;
> +	const char *alias = of_alias_get(dev->device_node);
> +	const char *model = NULL;
> +	struct param_d *p;
> +	u32 api_version;
> +	int ret;
> +
> +	mgr = xzalloc(sizeof(*mgr));
> +	fh = &mgr->fh;
> +
> +	if (alias)
> +		fh->id = xstrdup(alias);
> +	else
> +		fh->id = xstrdup("zynqmp-fpga-manager");
> +
> +	fh->open = fpgamgr_program_start;
> +	fh->write = fpgamgr_program_write_buf;
> +	fh->close = fpgamgr_program_finish;
> +	of_property_read_string(dev->device_node, "compatible", &model);
> +	if (model)
> +		fh->model = xstrdup(model);
> +	fh->dev = dev;
> +
> +	mgr->eemi_ops = zynqmp_pm_get_eemi_ops();
> +
> +	ret = mgr->eemi_ops->get_api_version(&api_version);
> +	if (ret) {
> +		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_FEATURE_BYTE_ORDER_IRREL;
> +
> +	dev_dbg(dev, "Registering ZynqMP FPGA programmer\n");
> +	mgr->dev.id = DEVICE_ID_SINGLE;
> +	dev_set_name(&mgr->dev, "zynqmp_fpga");
> +	mgr->dev.parent = dev;
> +	ret = register_device(&mgr->dev);
> +	if (ret)
> +		goto out;
> +
> +	p = dev_add_param_bool(&mgr->dev, "programmed", NULL, programmed_get,
> +			&mgr->programmed, mgr);
> +	if (IS_ERR(p)) {
> +		ret = PTR_ERR(p);
> +		goto out_unreg;
> +	}
> +
> +	fh->dev = &mgr->dev;
> +	ret = firmwaremgr_register(fh);
> +	if (ret != 0) {
> +		free(mgr);
> +		goto out_unreg;
> +	}
> +
> +	return 0;
> +out_unreg:
> +	unregister_device(&mgr->dev);
> +out:
> +	free(fh->id);
> +	free(mgr);
> +
> +	return ret;
> +}
> +
> +static struct of_device_id zynqmpp_fpga_id_table[] = {
> +	{
> +		.compatible = "xlnx,zynqmp-pcap-fpga",
> +	},
> +};
> +
> +static struct driver_d zynqmp_fpga_driver = {
> +	.name = "zynqmp_fpga_manager",
> +	.of_compatible = DRV_OF_COMPAT(zynqmpp_fpga_id_table),
> +	.probe = zynqmp_fpga_probe,
> +};
> +device_platform_driver(zynqmp_fpga_driver);

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

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

* [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading
  2019-10-24 10:26 [PATCH 0/5] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
                   ` (4 preceding siblings ...)
  2019-10-24 10:26 ` [PATCH 2/5] firmware-zynqmp: extend driver with fpga relavant functions Thomas Hämmerle
@ 2019-10-25 12:55 ` Thomas Hämmerle
  2019-10-25 12:55   ` [PATCH v2 1/4] firmware-zynqmp: add macros for PMU and trustzone firmware versions Thomas Hämmerle
                     ` (4 more replies)
  5 siblings, 5 replies; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-25 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Thomas Hämmerle

From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

Changes from v1:
- remove dts commits
- add commit for pmu and trustzone firmware virsion macro
- split bin-header validation and byte-order detection
- add description for bitstream

Michael Tretter (1):
  firmware: zynqmp-fpga: print Xilinx bitstream header

Thomas Haemmerle (3):
  firmware-zynqmp: add macros for PMU and trustzone firmware versions
  firmware-zynqmp: extend driver with fpga relavant functions
  firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA

 arch/arm/configs/zynqmp_defconfig                  |   1 +
 arch/arm/mach-zynqmp/firmware-zynqmp.c             |  68 +++-
 .../arm/mach-zynqmp/include/mach/firmware-zynqmp.h |  14 +-
 drivers/firmware/Kconfig                           |   7 +
 drivers/firmware/Makefile                          |   1 +
 drivers/firmware/zynqmp-fpga.c                     | 410 +++++++++++++++++++++
 6 files changed, 488 insertions(+), 13 deletions(-)
 create mode 100644 drivers/firmware/zynqmp-fpga.c

-- 
2.7.4


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

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

* [PATCH v2 1/4] firmware-zynqmp: add macros for PMU and trustzone firmware versions
  2019-10-25 12:55 ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
@ 2019-10-25 12:55   ` Thomas Hämmerle
  2019-10-25 12:55   ` [PATCH v2 2/4] firmware-zynqmp: extend driver with fpga relavant functions Thomas Hämmerle
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-25 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Thomas Hämmerle

From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
---
 arch/arm/mach-zynqmp/firmware-zynqmp.c | 22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mach-zynqmp/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c
index f2187e9..d91dcb0 100644
--- a/arch/arm/mach-zynqmp/firmware-zynqmp.c
+++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c
@@ -18,17 +18,13 @@
 
 #include <mach/firmware-zynqmp.h>
 
-#define ZYNQMP_PM_VERSION_MAJOR	1
-#define ZYNQMP_PM_VERSION_MINOR	0
+#define ZYNQMP_PM_VERSION(MAJOR, MINOR)	((MAJOR << 16) | MINOR)
+#define ZYNQMP_TZ_VERSION(MAJOR, MINOR)	((MAJOR << 16) | MINOR)
 
-#define ZYNQMP_PM_VERSION	((ZYNQMP_PM_VERSION_MAJOR << 16) | \
-					ZYNQMP_PM_VERSION_MINOR)
-
-#define ZYNQMP_TZ_VERSION_MAJOR 1
-#define ZYNQMP_TZ_VERSION_MINOR 0
-
-#define ZYNQMP_TZ_VERSION	((ZYNQMP_TZ_VERSION_MAJOR << 16) | \
-				ZYNQMP_TZ_VERSION_MINOR)
+#define ZYNQMP_PM_VERSION_MAJOR		1
+#define ZYNQMP_PM_VERSION_MINOR		0
+#define ZYNQMP_TZ_VERSION_MAJOR		1
+#define ZYNQMP_TZ_VERSION_MINOR		0
 
 /* SMC SIP service Call Function Identifier Prefix */
 #define PM_SIP_SVC		0xC2000000
@@ -544,7 +540,8 @@ static int zynqmp_firmware_probe(struct device_d *dev)
 		goto out;
 
 	zynqmp_pm_get_api_version(&pm_api_version);
-	if (pm_api_version < ZYNQMP_PM_VERSION) {
+	if (pm_api_version < ZYNQMP_PM_VERSION(ZYNQMP_PM_VERSION_MAJOR,
+					       ZYNQMP_PM_VERSION_MINOR)) {
 		dev_err(dev, "Platform Management API version error."
 				"Expected: v%d.%d - Found: v%d.%d\n",
 				ZYNQMP_PM_VERSION_MAJOR,
@@ -563,7 +560,8 @@ static int zynqmp_firmware_probe(struct device_d *dev)
 		goto out;
 	}
 
-	if (pm_tz_version < ZYNQMP_TZ_VERSION) {
+	if (pm_tz_version < ZYNQMP_TZ_VERSION(ZYNQMP_TZ_VERSION_MAJOR,
+					      ZYNQMP_TZ_VERSION_MINOR)) {
 		dev_err(dev, "Trustzone version error."
 				"Expected: v%d.%d - Found: v%d.%d\n",
 				ZYNQMP_TZ_VERSION_MAJOR,
-- 
2.7.4


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

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

* [PATCH v2 2/4] firmware-zynqmp: extend driver with fpga relavant functions
  2019-10-25 12:55 ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
  2019-10-25 12:55   ` [PATCH v2 1/4] firmware-zynqmp: add macros for PMU and trustzone firmware versions Thomas Hämmerle
@ 2019-10-25 12:55   ` Thomas Hämmerle
  2019-10-25 12:55   ` [PATCH v2 4/4] firmware: zynqmp-fpga: print Xilinx bitstream header Thomas Hämmerle
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-25 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Thomas Hämmerle

From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

Port functions from xlnx-linux to get FPGA status and invoke bitstream
loading.

Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
---
 arch/arm/mach-zynqmp/firmware-zynqmp.c             | 48 +++++++++++++++++++++-
 .../arm/mach-zynqmp/include/mach/firmware-zynqmp.h | 14 ++++++-
 2 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-zynqmp/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c
index d91dcb0..6123aa1 100644
--- a/arch/arm/mach-zynqmp/firmware-zynqmp.c
+++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c
@@ -18,7 +18,6 @@
 
 #include <mach/firmware-zynqmp.h>
 
-#define ZYNQMP_PM_VERSION(MAJOR, MINOR)	((MAJOR << 16) | MINOR)
 #define ZYNQMP_TZ_VERSION(MAJOR, MINOR)	((MAJOR << 16) | MINOR)
 
 #define ZYNQMP_PM_VERSION_MAJOR		1
@@ -504,6 +503,51 @@ static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
 				   arg1, arg2, out);
 }
 
+/**
+ * zynqmp_pm_fpga_load - Perform the fpga load
+ * @address:	Address to write to
+ * @size:	pl bitstream size
+ * @flags:	Flags are used to specify the type of Bitstream file -
+ * 		defined in ZYNQMP_FPGA_BIT_*-macros
+ *
+ * This function provides access to xilfpga library to transfer
+ * the required bitstream into PL.
+ *
+ * Return:	Returns status, either success or error+reason
+ */
+static int zynqmp_pm_fpga_load(u64 address, u32 size, u32 flags)
+{
+	if (!address || !size)
+		return -EINVAL;
+
+	return zynqmp_pm_invoke_fn(PM_FPGA_LOAD,
+			lower_32_bits(address),	upper_32_bits(address),
+			size, flags, NULL);
+}
+
+/**
+ * zynqmp_pm_fpga_get_status - Read value from PCAP status register
+ * @value:	Value to read
+ *
+ * This function provides access to the xilfpga library to get
+ * the PCAP status
+ *
+ * Return:	Returns status, either success or error+reason
+ */
+static int zynqmp_pm_fpga_get_status(u32 *value)
+{
+	u32 ret_payload[PAYLOAD_ARG_CNT];
+	int ret = 0;
+
+	if (!value)
+		return -EINVAL;
+
+	ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
+	*value = ret_payload[1];
+
+	return ret;
+}
+
 static const struct zynqmp_eemi_ops eemi_ops = {
 	.get_api_version = zynqmp_pm_get_api_version,
 	.query_data = zynqmp_pm_query_data,
@@ -517,6 +561,8 @@ static const struct zynqmp_eemi_ops eemi_ops = {
 	.clock_setparent = zynqmp_pm_clock_setparent,
 	.clock_getparent = zynqmp_pm_clock_getparent,
 	.ioctl = zynqmp_pm_ioctl,
+	.fpga_getstatus = zynqmp_pm_fpga_get_status,
+	.fpga_load = zynqmp_pm_fpga_load,
 };
 
 /**
diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
index 9e7a2e3..a044822 100644
--- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
+++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
@@ -15,7 +15,17 @@
 #ifndef FIRMWARE_ZYNQMP_H_
 #define FIRMWARE_ZYNQMP_H_
 
-#define PAYLOAD_ARG_CNT         4
+#define PAYLOAD_ARG_CNT			4
+
+#define ZYNQMP_PM_VERSION(MAJOR, MINOR)	((MAJOR << 16) | MINOR)
+
+#define ZYNQMP_FPGA_BIT_AUTH_DDR	BIT(1)
+#define ZYNQMP_FPGA_BIT_AUTH_OCM	BIT(2)
+#define ZYNQMP_FPGA_BIT_ENC_USR_KEY	BIT(3)
+#define ZYNQMP_FPGA_BIT_ENC_DEV_KEY	BIT(4)
+#define ZYNQMP_FPGA_BIT_ONLY_BIN	BIT(5)
+
+#define ZYNQMP_PCAP_STATUS_FPGA_DONE	BIT(3)
 
 enum pm_ioctl_id {
 	IOCTL_SET_PLL_FRAC_MODE = 8,
@@ -61,6 +71,8 @@ struct zynqmp_eemi_ops {
 	int (*clock_setparent)(u32 clock_id, u32 parent_id);
 	int (*clock_getparent)(u32 clock_id, u32 *parent_id);
 	int (*ioctl)(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, u32 *out);
+	int (*fpga_getstatus)(u32 *status);
+	int (*fpga_load)(u64 address, u32 size, u32 flags);
 };
 
 const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);
-- 
2.7.4


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

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

* [PATCH v2 3/4] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA
  2019-10-25 12:55 ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
                     ` (2 preceding siblings ...)
  2019-10-25 12:55   ` [PATCH v2 4/4] firmware: zynqmp-fpga: print Xilinx bitstream header Thomas Hämmerle
@ 2019-10-25 12:55   ` Thomas Hämmerle
  2019-10-28 11:00   ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Sascha Hauer
  4 siblings, 0 replies; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-25 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Thomas Hämmerle

From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>

The driver provides functionalities to check and load a bitstream to FPGA.
A boolean parameter to check if FPGA is already programmed is
added.

Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
---
 arch/arm/configs/zynqmp_defconfig |   1 +
 drivers/firmware/Kconfig          |   7 +
 drivers/firmware/Makefile         |   1 +
 drivers/firmware/zynqmp-fpga.c    | 359 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 368 insertions(+)
 create mode 100644 drivers/firmware/zynqmp-fpga.c

diff --git a/arch/arm/configs/zynqmp_defconfig b/arch/arm/configs/zynqmp_defconfig
index 4dea964..834212e 100644
--- a/arch/arm/configs/zynqmp_defconfig
+++ b/arch/arm/configs/zynqmp_defconfig
@@ -35,4 +35,5 @@ CONFIG_CMD_OFTREE=y
 CONFIG_CMD_TIME=y
 CONFIG_DRIVER_SERIAL_CADENCE=y
 # CONFIG_SPI is not set
+CONFIG_FIRMWARE_ZYNQMP_PL=y
 CONFIG_DIGEST=y
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 710b500..90b4c0a 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -14,4 +14,11 @@ config FIRMWARE_ALTERA_SOCFPGA
 	bool "Altera SoCFPGA fpga loader"
 	depends on ARCH_SOCFPGA
 	select FIRMWARE
+
+config FIRMWARE_ZYNQMP_FPGA
+	bool "Xilinx ZynqMP FPGA loader"
+	depends on ARCH_ZYNQMP
+	select FIRMWARE
+	help
+	  Load a bitstream to the PL of Zynq Ultrascale+
 endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index c3a3c34..b162b08 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
 obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
+obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
new file mode 100644
index 0000000..47862a7
--- /dev/null
+++ b/drivers/firmware/zynqmp-fpga.c
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx Zynq MPSoC PL loading
+ *
+ * Copyright (c) 2018 Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
+ *
+ * based on U-Boot zynqmppl code
+ *
+ * (C) Copyright 2015 - 2016, Xilinx, Inc,
+ * Michal Simek <michal.simek@xilinx.com>
+ * Siva Durga Prasad <siva.durga.paladugu@xilinx.com> *
+ */
+
+#include <firmware.h>
+#include <common.h>
+#include <init.h>
+#include <dma.h>
+#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)
+
+#define DUMMY_WORD			0xFFFFFFFF
+#define BUS_WIDTH_WORD_1		0x000000BB
+#define BUS_WIDTH_WORD_2		0x11220044
+#define SYNC_WORD			0xAA995566
+#define SYNC_WORD_OFFS			20
+
+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;
+};
+
+/*
+ * 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:
+ *
+ *  1: 0xFFFFFFFF (Dummy pad word)
+ *     ...
+ * 16: 0xFFFFFFFF (Dummy pad word)
+ * 17: 0x000000BB (Bus width auto detect word 1)
+ * 18: 0x11220044 (Bus width auto detect word 2)
+ * 19: 0xFFFFFFFF (Dummy pad word)
+ * 20: 0xFFFFFFFF (Dummy pad word)
+ * 21: 0xAA995566 (Sync word)
+ *
+ * Please refer to  Xilinx UG570 (v1.11) September 30 2019,
+ * Chapter 9 Configuration Details - Bitstream Composition
+ * for further details!
+ */
+static const u32 bin_format[] = {
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	BUS_WIDTH_WORD_1,
+	BUS_WIDTH_WORD_2,
+	DUMMY_WORD,
+	DUMMY_WORD,
+	SYNC_WORD,
+};
+
+static void copy_words_swapped(u32 *dst, const u32 *src, size_t size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		dst[i] = __swab32(src[i]);
+}
+
+static int get_byte_order(const u32 *bin_header, size_t size,
+			  enum xilinx_byte_order *byte_order)
+{
+	if (size < sizeof(bin_format))
+		return -EINVAL;
+
+	if (bin_header[SYNC_WORD_OFFS] == SYNC_WORD) {
+		*byte_order = XILINX_BYTE_ORDER_BIT;
+		return 0;
+	}
+
+	if (bin_header[SYNC_WORD_OFFS] == __swab32(SYNC_WORD)) {
+		*byte_order =  XILINX_BYTE_ORDER_BIN;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int is_bin_header_valid(const u32 *bin_header, size_t size,
+			       enum xilinx_byte_order byte_order)
+{
+	int i;
+
+	if (size < ARRAY_SIZE(bin_format))
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(bin_format); i++)
+		if (bin_header != (byte_order == XILINX_BYTE_ORDER_BIT) ?
+				  bin_format[i] : __swab32(bin_format[i]))
+			return 0;
+
+	return 1;
+}
+
+static int get_header_length(const char *header, size_t size)
+{
+	u32 *buf_u32;
+	int p;
+
+	for (p = 0; p < size; p++) {
+		buf_u32 = (u32 *)&header[p];
+		if (*buf_u32 == DUMMY_WORD)
+			return p;
+	}
+	return -EINVAL;
+}
+
+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;
+	u8 flags = 0;
+
+	if (!mgr->buf) {
+		status = -ENOBUFS;
+		dev_err(&mgr->dev, "buffer is NULL\n");
+		goto err_free;
+	}
+
+	header_length = get_header_length(mgr->buf, mgr->size);
+	if (header_length < 0) {
+		status = header_length;
+		goto err_free;
+	}
+
+	body = (u32 *)&mgr->buf[header_length];
+	body_length = mgr->size - header_length;
+
+	status = get_byte_order(body, body_length, &byte_order);
+	if (status < 0)
+		goto err_free;
+
+	if (!is_bin_header_valid(body, body_length, byte_order)) {
+		status =  -EINVAL;
+		goto err_free;
+	}
+
+	if (!(mgr->features & ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)) {
+		buf_size = dma_alloc_coherent(sizeof(*buf_size),
+		DMA_ADDRESS_BROKEN);
+		if (!buf_size) {
+			status = -ENOBUFS;
+			goto err_free;
+		}
+		*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,
+				   body_length / sizeof(u32));
+	else
+		memcpy((u32 *)buf_aligned, body, body_length);
+
+	addr = (u64)buf_aligned;
+
+	/* we do not provide a header */
+	flags |= ZYNQMP_FPGA_BIT_ONLY_BIN;
+
+	if (!(mgr->features & ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED) && buf_size) {
+		status = mgr->eemi_ops->fpga_load(addr,
+				(u32)(uintptr_t)buf_size,
+				flags);
+		dma_free_coherent(buf_size, 0, sizeof(*buf_size));
+	} else {
+		status = mgr->eemi_ops->fpga_load(addr, (u32)(body_length),
+						  flags);
+	}
+
+	if (status < 0)
+		dev_err(&mgr->dev, "unable to load fpga\n");
+
+	dma_free_coherent(buf_aligned, 0, body_length);
+
+ err_free:
+	free(mgr->buf);
+
+	return status;
+}
+
+static int fpgamgr_program_write_buf(struct firmware_handler *fh,
+		const void *buf, size_t size)
+{
+	struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
+
+	/* Since write() is called by copy_file, we only receive chuncks with
+	 * size RW_BUF_SIZE of the bitstream.
+	 * Buffer the chunks here and handle it in close()
+	 */
+
+	mgr->buf = realloc(mgr->buf, mgr->size + size);
+	if (!mgr->buf)
+		return -ENOBUFS;
+
+	memcpy(&(mgr->buf[mgr->size]), buf, size);
+	mgr->size += size;
+
+	return 0;
+}
+
+static int fpgamgr_program_start(struct firmware_handler *fh)
+{
+	struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
+
+	mgr->size = 0;
+	mgr->buf = NULL;
+
+	return 0;
+}
+
+static int programmed_get(struct param_d *p, void *priv)
+{
+	struct fpgamgr *mgr = priv;
+	u32 status = 0x00;
+	int ret = 0;
+
+	ret = mgr->eemi_ops->fpga_getstatus(&status);
+	if (ret)
+		return ret;
+
+	mgr->programmed = !!(status & ZYNQMP_PCAP_STATUS_FPGA_DONE);
+
+	return 0;
+}
+
+static int zynqmp_fpga_probe(struct device_d *dev)
+{
+	struct fpgamgr *mgr;
+	struct firmware_handler *fh;
+	const char *alias = of_alias_get(dev->device_node);
+	const char *model = NULL;
+	struct param_d *p;
+	u32 api_version;
+	int ret;
+
+	mgr = xzalloc(sizeof(*mgr));
+	fh = &mgr->fh;
+
+	if (alias)
+		fh->id = xstrdup(alias);
+	else
+		fh->id = xstrdup("zynqmp-fpga-manager");
+
+	fh->open = fpgamgr_program_start;
+	fh->write = fpgamgr_program_write_buf;
+	fh->close = fpgamgr_program_finish;
+	of_property_read_string(dev->device_node, "compatible", &model);
+	if (model)
+		fh->model = xstrdup(model);
+	fh->dev = dev;
+
+	mgr->eemi_ops = zynqmp_pm_get_eemi_ops();
+
+	ret = mgr->eemi_ops->get_api_version(&api_version);
+	if (ret) {
+		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;
+
+	dev_dbg(dev, "Registering ZynqMP FPGA programmer\n");
+	mgr->dev.id = DEVICE_ID_SINGLE;
+	dev_set_name(&mgr->dev, "zynqmp_fpga");
+	mgr->dev.parent = dev;
+	ret = register_device(&mgr->dev);
+	if (ret)
+		goto out;
+
+	p = dev_add_param_bool(&mgr->dev, "programmed", NULL, programmed_get,
+			&mgr->programmed, mgr);
+	if (IS_ERR(p)) {
+		ret = PTR_ERR(p);
+		goto out_unreg;
+	}
+
+	fh->dev = &mgr->dev;
+	ret = firmwaremgr_register(fh);
+	if (ret != 0) {
+		free(mgr);
+		goto out_unreg;
+	}
+
+	return 0;
+out_unreg:
+	unregister_device(&mgr->dev);
+out:
+	free(fh->id);
+	free(mgr);
+
+	return ret;
+}
+
+static struct of_device_id zynqmpp_fpga_id_table[] = {
+	{
+		.compatible = "xlnx,zynqmp-pcap-fpga",
+	},
+};
+
+static struct driver_d zynqmp_fpga_driver = {
+	.name = "zynqmp_fpga_manager",
+	.of_compatible = DRV_OF_COMPAT(zynqmpp_fpga_id_table),
+	.probe = zynqmp_fpga_probe,
+};
+device_platform_driver(zynqmp_fpga_driver);
-- 
2.7.4


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

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

* [PATCH v2 4/4] firmware: zynqmp-fpga: print Xilinx bitstream header
  2019-10-25 12:55 ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
  2019-10-25 12:55   ` [PATCH v2 1/4] firmware-zynqmp: add macros for PMU and trustzone firmware versions Thomas Hämmerle
  2019-10-25 12:55   ` [PATCH v2 2/4] firmware-zynqmp: extend driver with fpga relavant functions Thomas Hämmerle
@ 2019-10-25 12:55   ` Thomas Hämmerle
  2019-10-25 12:55   ` [PATCH v2 3/4] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA Thomas Hämmerle
  2019-10-28 11:00   ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Sascha Hauer
  4 siblings, 0 replies; 15+ messages in thread
From: Thomas Hämmerle @ 2019-10-25 12:55 UTC (permalink / raw)
  To: barebox; +Cc: Michael Tretter

From: Michael Tretter <m.tretter@pengutronix.de>

The bitstream header has 5 fields, that start with a char for the type.
Four fields have a big-ending length and a null-terminated string for
the design name, the part number, and the date and time of creation. The
last field is a big-endian 32 bit unsigned int for the size of the
bitstream.

Print this info when loading the bitstream.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
 drivers/firmware/zynqmp-fpga.c | 51 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
index 47862a7..8878658 100644
--- a/drivers/firmware/zynqmp-fpga.c
+++ b/drivers/firmware/zynqmp-fpga.c
@@ -45,6 +45,19 @@ struct fpgamgr {
 	u32 features;
 };
 
+struct bs_header {
+	__be16 length;
+	u8 padding[9];
+	__be16 size;
+	char entries[0];
+} __attribute__ ((packed));
+
+struct bs_header_entry {
+	char type;
+	__be16 length;
+	char data[0];
+} __attribute__ ((packed));
+
 /*
  * Xilinx KU040 Bitstream Composition:
  * Bitstream can be provided with an optinal header (`struct bs_header`).
@@ -143,6 +156,42 @@ static int get_header_length(const char *header, size_t size)
 	return -EINVAL;
 }
 
+static void zynqmp_fpga_show_header(const struct device_d *dev,
+			 struct bs_header *header, size_t size)
+{
+	struct bs_header_entry *entry;
+	unsigned int i;
+	unsigned int length;
+
+	for (i = 0; i < size - sizeof(*header); i += sizeof(*entry) + length) {
+		entry = (struct bs_header_entry *)&header->entries[i];
+		length = __be16_to_cpu(entry->length);
+
+		switch (entry->type) {
+		case 'a':
+			printf("Design: %s\n", entry->data);
+			break;
+		case 'b':
+			printf("Part number: %s\n", entry->data);
+			break;
+		case 'c':
+			printf("Date: %s\n", entry->data);
+			break;
+		case 'd':
+			printf("Time: %s\n", entry->data);
+			break;
+		case 'e':
+			/* Size entry does not have a length but is be32 int */
+			printf("Size: %d bytes\n",
+			       (length << 16) + (entry->data[0] << 8) + entry->data[1]);
+			return;
+		default:
+			dev_warn(dev, "Invalid header entry: %c", entry->type);
+			return;
+		}
+	}
+}
+
 static int fpgamgr_program_finish(struct firmware_handler *fh)
 {
 	struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
@@ -167,6 +216,8 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
 		status = header_length;
 		goto err_free;
 	}
+	zynqmp_fpga_show_header(&mgr->dev,
+			      (struct bs_header *)mgr->buf, header_length);
 
 	body = (u32 *)&mgr->buf[header_length];
 	body_length = mgr->size - header_length;
-- 
2.7.4


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

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

* Re: [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading
  2019-10-25 12:55 ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
                     ` (3 preceding siblings ...)
  2019-10-25 12:55   ` [PATCH v2 3/4] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA Thomas Hämmerle
@ 2019-10-28 11:00   ` Sascha Hauer
  4 siblings, 0 replies; 15+ messages in thread
From: Sascha Hauer @ 2019-10-28 11:00 UTC (permalink / raw)
  To: Thomas Hämmerle; +Cc: barebox

On Fri, Oct 25, 2019 at 12:55:38PM +0000, Thomas Hämmerle wrote:
> From: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
> 
> Changes from v1:
> - remove dts commits
> - add commit for pmu and trustzone firmware virsion macro
> - split bin-header validation and byte-order detection
> - add description for bitstream
> 
> Michael Tretter (1):
>   firmware: zynqmp-fpga: print Xilinx bitstream header
> 
> Thomas Haemmerle (3):
>   firmware-zynqmp: add macros for PMU and trustzone firmware versions
>   firmware-zynqmp: extend driver with fpga relavant functions
>   firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 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] 15+ messages in thread

end of thread, other threads:[~2019-10-28 11:00 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-24 10:26 [PATCH 0/5] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
2019-10-24 10:26 ` [PATCH 1/5] ARM: zynqmp: dts: move firmware node to src tree Thomas Hämmerle
2019-10-24 12:56   ` Michael Tretter
2019-10-24 10:26 ` [PATCH 4/5] ARM: zynqmp: dts: move pcap " Thomas Hämmerle
2019-10-24 10:26 ` [PATCH 3/5] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA Thomas Hämmerle
2019-10-24 12:56   ` Michael Tretter
2019-10-24 10:26 ` [PATCH 5/5] firmware: zynqmp-fpga: print Xilinx bitstream header Thomas Hämmerle
2019-10-24 10:26 ` [PATCH 2/5] firmware-zynqmp: extend driver with fpga relavant functions Thomas Hämmerle
2019-10-24 12:56   ` Michael Tretter
2019-10-25 12:55 ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Thomas Hämmerle
2019-10-25 12:55   ` [PATCH v2 1/4] firmware-zynqmp: add macros for PMU and trustzone firmware versions Thomas Hämmerle
2019-10-25 12:55   ` [PATCH v2 2/4] firmware-zynqmp: extend driver with fpga relavant functions Thomas Hämmerle
2019-10-25 12:55   ` [PATCH v2 4/4] firmware: zynqmp-fpga: print Xilinx bitstream header Thomas Hämmerle
2019-10-25 12:55   ` [PATCH v2 3/4] firmware: zynqmp-fpga: introduce driver to load bitstream to FPGA Thomas Hämmerle
2019-10-28 11:00   ` [PATCH v2 0/4] ARM: zynqmp: add support for bitstream loading Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox