@@ -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
@@ -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
new file mode 100644
@@ -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], ®ion, 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"
+ ""
+);