diff mbox series

driver: fpga: Adding Freeze Bridge for PR console support

Message ID 20220901031045.10890-1-jit.loon.lim@intel.com
State Needs Review / ACK, archived
Delegated to: Marek Vasut
Headers show
Series driver: fpga: Adding Freeze Bridge for PR console support | expand

Commit Message

Jit Loon Lim Sept. 1, 2022, 3:10 a.m. UTC
From: Chin Liang See <chin.liang.see@intel.com>

Adding Partial Reconfiguration (pr) command at U-Boot console. The pr
command will control the Freeze Controller which will freeze
and unfreeze the Partial Reconfiguration region. The pr command also
support multiple Partial Reconfiguration region by specifying the
region ID.

Here are the example of expected steps for partial reconfiguration
$ bridge enable
$ fatload mmc 0:1 100 pr_bitstream.rbf
$ pr start 0
$ fpga load 0 100 $filesize
$ pr end 0

Signed-off-by: Chin Liang See <chin.liang.see@intel.com>
Signed-off-by: Jit Loon Lim <jit.loon.lim@intel.com>
---
 drivers/fpga/Kconfig    |   9 +++
 drivers/fpga/Makefile   |   1 +
 drivers/fpga/intel_pr.c | 141 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 151 insertions(+)
 create mode 100644 drivers/fpga/intel_pr.c
diff mbox series

Patch

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index e07a9cf80e..6e542353fe 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -48,6 +48,15 @@  config FPGA_INTEL_SDM_MAILBOX
 	  Enable FPGA driver for writing full bitstream into Intel FPGA
 	  devices through SDM (Secure Device Manager) Mailbox.
 
+config FPGA_INTEL_PR
+	bool "Enable Intel FPGA Partial Reconfiguration driver"
+	depends on FPGA_ALTERA
+	help
+	  Say Y here to enable the Intel FPGA Partial Reconfiguration driver
+
+	  This provides basic functionality for partial reconfiguration which
+	  include the freeze controller support.
+
 config FPGA_XILINX
 	bool "Enable Xilinx FPGA drivers"
 	select FPGA
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 83243fb107..2eff387100 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -22,4 +22,5 @@  obj-$(CONFIG_FPGA_STRATIX_V) += stratixv.o
 obj-$(CONFIG_FPGA_SOCFPGA) += socfpga.o
 obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += socfpga_gen5.o
 obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += socfpga_arria10.o
+obj-$(CONFIG_FPGA_INTEL_PR) += intel_pr.o
 endif
diff --git a/drivers/fpga/intel_pr.c b/drivers/fpga/intel_pr.c
new file mode 100644
index 0000000000..05f2092600
--- /dev/null
+++ b/drivers/fpga/intel_pr.c
@@ -0,0 +1,141 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <command.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_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)
+
+#define FREEZE_TIMEOUT				20000
+
+static int intel_get_freeze_br_addr(fdt_addr_t *addr, unsigned int region)
+{
+	int offset;
+	char freeze_br[12];
+
+	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;
+	}
+
+	*addr = fdtdec_get_addr(gd->fdt_blob, offset, "reg");
+	if (*addr == FDT_ADDR_T_NONE) {
+		printf("%s has no 'reg' property!\n", freeze_br);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int intel_freeze_br_do_freeze(unsigned int region)
+{
+	u32 status;
+	int ret;
+	fdt_addr_t addr;
+
+	ret = intel_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;
+	else if (!(status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE))
+		return -EINVAL;
+
+	writel(FREEZE_CSR_CTRL_FREEZE_REQ, addr + FREEZE_CSR_CTRL_OFFSET);
+
+	return wait_for_bit_le32((const u32 *)(addr +
+				 FREEZE_CSR_STATUS_OFFSET),
+				 FREEZE_CSR_STATUS_FREEZE_REQ_DONE, true,
+				 FREEZE_TIMEOUT, false);
+}
+
+static int intel_freeze_br_do_unfreeze(unsigned int region)
+{
+	u32 status;
+	int ret;
+	fdt_addr_t addr;
+
+	ret = intel_get_freeze_br_addr(&addr, region);
+	if (ret)
+		return ret;
+
+	status = readl(addr + FREEZE_CSR_STATUS_OFFSET);
+
+	if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE)
+		return 0;
+	else if (!(status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE))
+		return -EINVAL;
+
+	writel(FREEZE_CSR_CTRL_UNFREEZE_REQ, addr + FREEZE_CSR_CTRL_OFFSET);
+
+	return wait_for_bit_le32((const u32 *)(addr +
+				 FREEZE_CSR_STATUS_OFFSET),
+				 FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE, true,
+				 FREEZE_TIMEOUT, false);
+}
+
+static int do_pr(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+	const char *cmd;
+	char *region;
+	unsigned int region_num = 0;
+
+	if (argc != 2 && argc != 3)
+		return CMD_RET_USAGE;
+
+	cmd = argv[1];
+	if (argc == 3)
+		region_num = simple_strtoul(argv[2], &region, 0);
+
+	if (strcmp(cmd, "start") == 0)
+		return intel_freeze_br_do_freeze(region_num);
+	else if (strcmp(cmd, "end") == 0)
+		return intel_freeze_br_do_unfreeze(region_num);
+
+	return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(
+	pr, 3, 1, do_pr,
+	"SoCFPGA partial reconfiguration control",
+	"start [region] - Start the partial reconfiguration by freeze the\n"
+	"PR region\n"
+	"end [region] - End the partial reconfiguration by unfreeze the PR\n"
+	"region\n"
+	""
+);