[PATCH v2 5/5] drivers: fpga: Add partial reconfig support for Altera SoCs

Naresh Kumar Ravulapalli nareshkumar.ravulapalli at altera.com
Sat May 24 22:37:37 CEST 2025


Support for Altera SoCs which support partial reconfiguration is
added. This functionality will enable these devices to perform
partial reconfiguration on the specified regions.

Signed-off-by: Naresh Kumar Ravulapalli <nareshkumar.ravulapalli at altera.com>
---
 drivers/fpga/altera.c | 163 ++++++++++++++++++++++++++++++++++++++++++
 drivers/fpga/fpga.c   |  11 +++
 include/altera.h      |   7 ++
 3 files changed, 181 insertions(+)

diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c
index 64fda3a307c..978250147f0 100644
--- a/drivers/fpga/altera.c
+++ b/drivers/fpga/altera.c
@@ -5,6 +5,8 @@
  *
  * (C) Copyright 2002
  * Rich Ireland, Enterasys Networks, rireland at enterasys.com.
+ *
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
  */
 
 #define LOG_CATEGORY UCLASS_FPGA
@@ -20,6 +22,29 @@
 #include <ACEX1K.h>
 #include <log.h>
 #include <stratixII.h>
+#include <errno.h>
+#include <wait_bit.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/libfdt.h>
+#include <fdtdec.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define FREEZE_CSR_STATUS_OFFSET		0
+#define FREEZE_CSR_CTRL_OFFSET			4
+#define FREEZE_CSR_ILLEGAL_REQ_OFFSET		8
+#define FREEZE_CSR_REG_VERSION			12
+
+#define FREEZE_TIMEOUT				20000
+
+#define FREEZE_CSR_STATUS_FREEZE_REQ_DONE	BIT(0)
+#define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE	BIT(1)
+
+#define FREEZE_CSR_CTRL_FREEZE_REQ		BIT(0)
+#define FREEZE_CSR_CTRL_RESET_REQ		BIT(1)
+#define FREEZE_CSR_CTRL_UNFREEZE_REQ		BIT(2)
 
 static const struct altera_fpga {
 	enum altera_family	family;
@@ -218,3 +243,141 @@ int altera_info(Altera_desc *desc)
 
 	return FPGA_SUCCESS;
 }
+
+#if IS_ENABLED(CONFIG_FPGA_PR)
+static int altera_get_freeze_br_addr(fdt_addr_t *addr, unsigned int region)
+{
+	int offset;
+	char freeze_br[12];
+	struct fdt_resource r;
+	int ret;
+
+	snprintf(freeze_br, sizeof(freeze_br), "freeze-br%d", region);
+
+	const char *alias = fdt_get_alias(gd->fdt_blob, freeze_br);
+
+	if (!alias)	{
+		printf("alias %s not found in dts\n", freeze_br);
+		return -ENODEV;
+	}
+
+	offset = fdt_path_offset(gd->fdt_blob, alias);
+	if (offset < 0) {
+		printf("%s not found in dts\n", alias);
+		return -ENODEV;
+	}
+
+	ret = fdt_get_resource(gd->fdt_blob, offset, "reg", 0, &r);
+	if (ret) {
+		printf("%s has no 'reg' property!\n", freeze_br);
+		return ret;
+	}
+
+	*addr = r.start;
+
+	return ret;
+}
+
+static int altera_freeze_br_req_ack(fdt_addr_t addr, u32 req_ack)
+{
+	u32 status, illegal, ctrl;
+	int ret = -ETIMEDOUT;
+	unsigned long start = get_timer(0);
+
+	while (1) {
+		illegal = readl(addr + FREEZE_CSR_ILLEGAL_REQ_OFFSET);
+		if (illegal) {
+			printf("illegal request 0x%08x detected in freeze bridge\n", illegal);
+
+			writel(illegal, addr + FREEZE_CSR_ILLEGAL_REQ_OFFSET);
+
+			illegal = readl(addr + FREEZE_CSR_ILLEGAL_REQ_OFFSET);
+			if (illegal)
+				printf("illegal request 0x%08x detected in freeze bridge are not cleared\n",
+				       illegal);
+
+			ret = -EINVAL;
+			break;
+		}
+
+		status = readl(addr + FREEZE_CSR_STATUS_OFFSET);
+		status &= req_ack;
+		if (status) {
+			ctrl = readl(addr + FREEZE_CSR_CTRL_OFFSET);
+			printf("%s request %x acknowledged %x ctrl %x\n",
+			       __func__, req_ack, status, ctrl);
+
+			ret = 0;
+			break;
+		}
+
+		if (get_timer(start) > FREEZE_TIMEOUT)
+			break;
+
+		udelay(1);
+		schedule();
+	}
+
+	return ret;
+}
+
+int altera_freeze(unsigned int region)
+{
+	u32 status;
+	int ret;
+	fdt_addr_t addr;
+
+	ret = altera_get_freeze_br_addr(&addr, region);
+	if (ret)
+		return ret;
+
+	status = readl(addr + FREEZE_CSR_STATUS_OFFSET);
+
+	if (status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE)
+		return 0;
+
+	if (!(status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE))
+		return -EINVAL;
+
+	writel(FREEZE_CSR_CTRL_FREEZE_REQ, addr + FREEZE_CSR_CTRL_OFFSET);
+
+	ret = altera_freeze_br_req_ack(addr, FREEZE_CSR_STATUS_FREEZE_REQ_DONE);
+	if (ret) {
+		writel(0, addr + FREEZE_CSR_CTRL_OFFSET);
+		debug("%s: freeze request not acknowledged\n", __func__);
+	} else {
+		writel(FREEZE_CSR_CTRL_RESET_REQ, addr + FREEZE_CSR_CTRL_OFFSET);
+	}
+
+	return ret;
+}
+
+int altera_unfreeze(unsigned int region)
+{
+	u32 status;
+	int ret;
+	fdt_addr_t addr;
+
+	ret = altera_get_freeze_br_addr(&addr, region);
+	if (ret)
+		return ret;
+
+	writel(0, addr + FREEZE_CSR_CTRL_OFFSET);
+
+	status = readl(addr + FREEZE_CSR_STATUS_OFFSET);
+
+	if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE)
+		return 0;
+
+	if (!(status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE))
+		return -EINVAL;
+
+	writel(FREEZE_CSR_CTRL_UNFREEZE_REQ, addr + FREEZE_CSR_CTRL_OFFSET);
+
+	ret = altera_freeze_br_req_ack(addr, FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE);
+
+	writel(0, addr + FREEZE_CSR_CTRL_OFFSET);
+
+	return ret;
+}
+#endif
diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c
index c1d10c9cad4..55f42b9bd7e 100644
--- a/drivers/fpga/fpga.c
+++ b/drivers/fpga/fpga.c
@@ -411,6 +411,17 @@ int fpga_pr(int devnum, const char *cmd, unsigned int region)
 
 	if (desc) {
 		switch (desc->devtype) {
+		case fpga_altera:
+			if (IS_ENABLED(CONFIG_FPGA_ALTERA)) {
+				if (strcmp(cmd, "start") == 0)
+					ret_val = altera_freeze(region);
+				else if (strcmp(cmd, "stop") == 0)
+					ret_val = altera_unfreeze(region);
+			} else {
+				fpga_no_sup((char *)__func__, "Altera devices");
+			}
+			break;
+
 		default:
 			printf("%s: Invalid or unsupported device type %d\n",
 			       __func__, desc->devtype);
diff --git a/include/altera.h b/include/altera.h
index 946413c66e8..610e9cba070 100644
--- a/include/altera.h
+++ b/include/altera.h
@@ -2,6 +2,8 @@
 /*
  * (C) Copyright 2002
  * Rich Ireland, Enterasys Networks, rireland at enterasys.com.
+ *
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
  */
 
 #include <fpga.h>
@@ -125,4 +127,9 @@ int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data,
 		      size_t rbf_size);
 #endif
 
+#ifdef CONFIG_FPGA_PR
+int altera_freeze(unsigned int region);
+int altera_unfreeze(unsigned int region);
+#endif
+
 #endif /* _ALTERA_H_ */
-- 
2.35.3



More information about the U-Boot mailing list