diff mbox series

[v5,15/17] arm: socfpga: stratix10: Add ATF support for FPGA reconfig driver

Message ID 1584019434-45856-16-git-send-email-chee.hong.ang@intel.com
State New
Headers show
Series Enable ARM Trusted Firmware for U-Boot | expand

Commit Message

Ang, Chee Hong March 12, 2020, 1:23 p.m. UTC
From: Chee Hong Ang <chee.hong.ang at intel.com>

In non-secure mode (EL2), FPGA reconfiguration driver calls the
SMC/PSCI services provided by ATF to configure the FPGA.

Signed-off-by: Chee Hong Ang <chee.hong.ang at intel.com>
---
 drivers/fpga/stratix10.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 140 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/fpga/stratix10.c b/drivers/fpga/stratix10.c
index d8e3250..d726a1b 100644
--- a/drivers/fpga/stratix10.c
+++ b/drivers/fpga/stratix10.c
@@ -5,11 +5,148 @@ 
 
 #include <common.h>
 #include <altera.h>
-#include <asm/arch/mailbox_s10.h>
 
 #define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS		60000
 #define RECONFIG_STATUS_INTERVAL_DELAY_US		1000000
 
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF)
+
+#include <asm/arch/misc.h>
+#include <linux/intel-smc.h>
+
+#define BITSTREAM_CHUNK_SIZE				0xFFFF0
+#define RECONFIG_STATUS_POLL_RETRY_MAX			100
+
+/*
+ * Polling the FPGA configuration status.
+ * Return 0 for success, non-zero for error.
+ */
+static int reconfig_status_polling_resp(void)
+{
+	int ret;
+	unsigned long start = get_timer(0);
+
+	while (1) {
+		ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_ISDONE, NULL, 0,
+				 NULL, 0);
+
+		if (!ret)
+			return 0;	/* configuration success */
+
+		if (ret != INTEL_SIP_SMC_STATUS_BUSY)
+			return ret;
+
+		if (get_timer(start) > RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
+			break;	/* time out */
+
+		puts(".");
+		udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int send_bistream(const void *rbf_data, size_t rbf_size)
+{
+	int i;
+	u64 res_buf[3];
+	u64 args[2];
+	u32 xfer_count = 0;
+	int ret, wr_ret = 0, retry = 0;
+	size_t buf_size = (rbf_size > BITSTREAM_CHUNK_SIZE) ?
+				BITSTREAM_CHUNK_SIZE : rbf_size;
+
+	while (rbf_size || xfer_count) {
+		if (!wr_ret && rbf_size) {
+			args[0] = (u64)rbf_data;
+			args[1] = buf_size;
+			wr_ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_WRITE,
+					    args, 2, NULL, 0);
+
+			debug("wr_ret = %d, rbf_data = %p, buf_size = %08lx\n",
+			      wr_ret, rbf_data, buf_size);
+
+			if (wr_ret == INTEL_SIP_SMC_STATUS_REJECTED)
+				continue;
+
+			rbf_size -= buf_size;
+			rbf_data += buf_size;
+
+			if (buf_size >= rbf_size)
+				buf_size = rbf_size;
+
+			xfer_count++;
+			puts(".");
+		} else {
+			ret = invoke_smc(
+				INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE,
+				NULL, 0, res_buf, 3);
+			if (!ret) {
+				for (i = 0; i < 3; i++) {
+					if (!res_buf[i])
+						break;
+					xfer_count--;
+					wr_ret = 0;
+					retry = 0;
+				}
+			} else if (ret !=
+				   INTEL_SIP_SMC_STATUS_BUSY)
+				return ret;
+			else if (!xfer_count)
+				return INTEL_SIP_SMC_STATUS_ERROR;
+
+			if (++retry >= RECONFIG_STATUS_POLL_RETRY_MAX)
+				return -ETIMEDOUT;
+
+			udelay(20000);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This is the interface used by FPGA driver.
+ * Return 0 for success, non-zero for error.
+ */
+int stratix10_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
+{
+	int ret;
+
+	debug("Invoking FPGA_CONFIG_START...\n");
+
+	ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_START, NULL, 0, NULL, 0);
+
+	if (ret) {
+		puts("Failure in RECONFIG mailbox command!\n");
+		return ret;
+	}
+
+	ret = send_bistream(rbf_data, rbf_size);
+	if (ret) {
+		printf("Error sending bitstream!\n");
+		return ret;
+	}
+
+	/* Make sure we don't send MBOX_RECONFIG_STATUS too fast */
+	udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+
+	debug("Polling with MBOX_RECONFIG_STATUS...\n");
+	ret = reconfig_status_polling_resp();
+	if (ret) {
+		printf("FPGA reconfiguration failed!");
+		return ret;
+	}
+
+	puts("FPGA reconfiguration OK!\n");
+
+	return ret;
+}
+
+#else
+
+#include <asm/arch/mailbox_s10.h>
+
 static const struct mbox_cfgstat_state {
 	int			err_no;
 	const char		*error_name;
@@ -281,3 +418,5 @@  int stratix10_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
 
 	return ret;
 }
+
+#endif