summaryrefslogtreecommitdiff
path: root/drivers/fpga
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/fpga')
-rw-r--r--drivers/fpga/ACEX1K.c245
-rw-r--r--drivers/fpga/Kconfig174
-rw-r--r--drivers/fpga/Makefile28
-rw-r--r--drivers/fpga/altera.c220
-rw-r--r--drivers/fpga/cyclon2.c201
-rw-r--r--drivers/fpga/fpga-uclass.c11
-rw-r--r--drivers/fpga/fpga.c379
-rw-r--r--drivers/fpga/intel_sdm_mb.c1064
-rw-r--r--drivers/fpga/ivm_core.c3149
-rw-r--r--drivers/fpga/lattice.c379
-rw-r--r--drivers/fpga/sandbox.c17
-rw-r--r--drivers/fpga/socfpga.c71
-rw-r--r--drivers/fpga/socfpga_arria10.c951
-rw-r--r--drivers/fpga/socfpga_gen5.c247
-rw-r--r--drivers/fpga/spartan2.c445
-rw-r--r--drivers/fpga/spartan3.c464
-rw-r--r--drivers/fpga/stratixII.c179
-rw-r--r--drivers/fpga/stratixv.c103
-rw-r--r--drivers/fpga/versalpl.c60
-rw-r--r--drivers/fpga/virtex2.c507
-rw-r--r--drivers/fpga/xilinx.c318
-rw-r--r--drivers/fpga/zynqmppl.c387
-rw-r--r--drivers/fpga/zynqpl.c578
23 files changed, 10177 insertions, 0 deletions
diff --git a/drivers/fpga/ACEX1K.c b/drivers/fpga/ACEX1K.c
new file mode 100644
index 00000000000..e1514fc56d0
--- /dev/null
+++ b/drivers/fpga/ACEX1K.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2003
+ * Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de
+ *
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ */
+
+#define LOG_CATEGORY UCLASS_FPGA
+
+#include <config.h> /* core U-Boot definitions */
+#include <console.h>
+#include <log.h>
+#include <ACEX1K.h> /* ACEX device family */
+#include <linux/delay.h>
+#include <time.h>
+
+/* Note: The assumption is that we cannot possibly run fast enough to
+ * overrun the device (the Slave Parallel mode can free run at 50MHz).
+ * If there is a need to operate slower, define CFG_FPGA_DELAY in
+ * the board config file to slow things down.
+ */
+#ifndef CFG_FPGA_DELAY
+#define CFG_FPGA_DELAY()
+#endif
+
+#ifndef CFG_SYS_FPGA_WAIT
+#define CFG_SYS_FPGA_WAIT CONFIG_SYS_HZ/10 /* 100 ms */
+#endif
+
+static int ACEX1K_ps_load(Altera_desc *desc, const void *buf, size_t bsize);
+static int ACEX1K_ps_dump(Altera_desc *desc, const void *buf, size_t bsize);
+/* static int ACEX1K_ps_info(Altera_desc *desc); */
+
+/* ------------------------------------------------------------------------- */
+/* ACEX1K Generic Implementation */
+int ACEX1K_load(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ log_debug("Launching Passive Serial Loader\n");
+ ret_val = ACEX1K_ps_load (desc, buf, bsize);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int ACEX1K_dump(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ log_debug("Launching Passive Serial Dump\n");
+ ret_val = ACEX1K_ps_dump (desc, buf, bsize);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int ACEX1K_info( Altera_desc *desc )
+{
+ return FPGA_SUCCESS;
+}
+
+/* ------------------------------------------------------------------------- */
+/* ACEX1K Passive Serial Generic Implementation */
+
+static int ACEX1K_ps_load(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Altera_ACEX1K_Passive_Serial_fns *fn = desc->iface_fns;
+ int i;
+
+ log_debug("start with interface functions @ 0x%p\n", fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ log_debug("Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "config:\t0x%p\n"
+ "status:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "data:\t0x%p\n"
+ "done:\t0x%p\n\n",
+ &fn, fn, fn->config, fn->status,
+ fn->clk, fn->data, fn->done);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...", cookie);
+#endif
+
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->config) (true, true, cookie); /* Assert nCONFIG */
+
+ udelay(2); /* T_cfg > 2us */
+
+ /* nSTATUS should be asserted now */
+ (*fn->done) (cookie);
+ if ( !(*fn->status) (cookie) ) {
+ puts ("** nSTATUS is not asserted.\n");
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+
+ (*fn->config) (false, true, cookie); /* Deassert nCONFIG */
+ udelay(2); /* T_cf2st1 < 4us */
+
+ /* Wait for nSTATUS to be released (i.e. deasserted) */
+ ts = get_timer (0); /* get current time */
+ do {
+ CFG_FPGA_DELAY ();
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for STATUS to go high.\n");
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+ (*fn->done) (cookie);
+ } while ((*fn->status) (cookie));
+
+ /* Get ready for the burn */
+ CFG_FPGA_DELAY ();
+
+ /* Load the data */
+ while (bytecount < bsize) {
+ unsigned char val=0;
+#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
+ if (ctrlc ()) {
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+#endif
+ /* Altera detects an error if INIT goes low (active)
+ while DONE is low (inactive) */
+#if 0 /* not yet implemented */
+ if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
+ puts ("** CRC error during FPGA load.\n");
+ (*fn->abort) (cookie);
+ return (FPGA_FAIL);
+ }
+#endif
+ val = data [bytecount ++ ];
+ i = 8;
+ do {
+ /* Deassert the clock */
+ (*fn->clk) (false, true, cookie);
+ CFG_FPGA_DELAY ();
+ /* Write data */
+ (*fn->data) ((val & 0x01), true, cookie);
+ CFG_FPGA_DELAY ();
+ /* Assert the clock */
+ (*fn->clk) (true, true, cookie);
+ CFG_FPGA_DELAY ();
+ val >>= 1;
+ i --;
+ } while (i > 0);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ CFG_FPGA_DELAY ();
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc (' '); /* terminate the dotted line */
+#endif
+
+ /*
+ * Checking FPGA's CONF_DONE signal - correctly booted ?
+ */
+
+ if ( ! (*fn->done) (cookie) ) {
+ puts ("** Booting failed! CONF_DONE is still deasserted.\n");
+ (*fn->abort) (cookie);
+ return (FPGA_FAIL);
+ }
+
+ /*
+ * "DCLK must be clocked an additional 10 times fpr ACEX 1K..."
+ */
+
+ for (i = 0; i < 12; i++) {
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ }
+
+ ret_val = FPGA_SUCCESS;
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS) {
+ puts ("Done.\n");
+ }
+ else {
+ puts ("Fail.\n");
+ }
+#endif
+ (*fn->post) (cookie);
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int ACEX1K_ps_dump(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ /* Readback is only available through the Slave Parallel and */
+ /* boundary-scan interfaces. */
+ printf ("%s: Passive Serial Dumping is unavailable\n",
+ __FUNCTION__);
+ return FPGA_FAIL;
+}
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
new file mode 100644
index 00000000000..9456ca3149a
--- /dev/null
+++ b/drivers/fpga/Kconfig
@@ -0,0 +1,174 @@
+menu "FPGA support"
+
+config FPGA
+ bool
+
+config FPGA_ALTERA
+ bool "Enable Altera FPGA drivers"
+ select FPGA
+ help
+ Say Y here to enable the Altera FPGA driver
+
+ This provides basic infrastructure to support Altera FPGA devices.
+ Enable Altera FPGA specific functions which includes bitstream
+ (in BIT format), fpga and device validation.
+
+config FPGA_SOCFPGA
+ bool "Enable Gen5 and Arria10 common FPGA drivers"
+ depends on ARCH_SOCFPGA
+ select FPGA_ALTERA
+ help
+ Say Y here to enable the Gen5 and Arria10 common FPGA driver
+
+ This provides common functionality for Gen5 and Arria10 devices.
+
+config FPGA_STRATIX_II
+ bool "Enable Stratix II FPGA drivers"
+ depends on FPGA_ALTERA
+ help
+ Say Y here to enable the Altera Stratix II FPGA-specific driver.
+
+config FPGA_STRATIX_V
+ bool "Enable Stratix V FPGA drivers"
+ depends on FPGA_ALTERA
+ help
+ Say Y here to enable the Altera Stratix V FPGA specific driver.
+
+config FPGA_ACEX1K
+ bool "Enable Altera ACEX 1K driver"
+ depends on FPGA_ALTERA
+ help
+ Say Y here to enable the Altera ACEX 1K FPGA specific driver.
+
+config FPGA_CYCLON2
+ bool "Enable Altera FPGA driver for Cyclone II"
+ depends on FPGA_ALTERA
+ help
+ Say Y here to enable the Altera Cyclone II FPGA specific driver
+
+ This provides common functionality for Altera Cyclone II devices.
+ Enable FPGA driver for loading bitstream in BIT and BIN format
+ on Altera Cyclone II device.
+
+config FPGA_INTEL_SDM_MAILBOX
+ bool "Enable Intel FPGA Full Reconfiguration SDM Mailbox driver"
+ depends on TARGET_SOCFPGA_SOC64
+ select FPGA_ALTERA
+ help
+ Say Y here to enable the Intel FPGA Full Reconfig SDM Mailbox driver
+
+ This provides common functionality for Intel FPGA devices.
+ Enable FPGA driver for writing full bitstream into Intel FPGA
+ devices through SDM (Secure Device Manager) Mailbox.
+
+config FPGA_LATTICE
+ bool "Enable Lattice FPGA driver"
+ help
+ This is used for the lattice FPGAs. Please check the source code as
+ there is no documentation for this at present.
+
+config FPGA_XILINX
+ bool "Enable Xilinx FPGA drivers"
+ select FPGA
+ help
+ Enable Xilinx FPGA specific functions which includes bitstream
+ (in BIT format), fpga and device validation.
+
+config FPGA_ZYNQMPPL
+ bool "Enable Xilinx FPGA driver for ZynqMP"
+ depends on FPGA_XILINX && ZYNQMP_FIRMWARE
+ help
+ Enable FPGA driver for loading bitstream in BIT and BIN format
+ on Xilinx Zynq UltraScale+ (ZynqMP) device.
+
+config FPGA_VERSALPL
+ bool "Enable Xilinx FPGA driver for Versal"
+ depends on FPGA_XILINX
+ help
+ Enable FPGA driver for loading bitstream in PDI format on Xilinx
+ Versal device. PDI is a new programmable device image format for
+ Versal. The bitstream will only be generated as PDI for Versal
+ platform.
+
+config FPGA_SPARTAN2
+ bool "Enable Spartan2 FPGA driver"
+ depends on FPGA_XILINX
+ help
+ Enable Spartan2 FPGA driver.
+
+config FPGA_SPARTAN3
+ bool "Enable Spartan3 FPGA driver"
+ depends on FPGA_XILINX
+ help
+ Enable Spartan3 FPGA driver for loading in BIT format.
+
+config FPGA_VIRTEX2
+ bool "Enable Xilinx Virtex-II and later FPGA driver"
+ depends on FPGA_XILINX
+ help
+ Enable Virtex-II FPGA driver for loading in BIT format. This driver
+ also supports many newer Xilinx FPGA families.
+
+config SYS_FPGA_CHECK_BUSY
+ bool "Perform busy check during load from FPGA"
+ depends on FPGA_SPARTAN2 || FPGA_SPARTAN3 || FPGA_VIRTEX2
+
+config FPGA_ZYNQPL
+ bool "Enable Xilinx FPGA for Zynq"
+ depends on ARCH_ZYNQ
+ help
+ Enable FPGA driver for loading bitstream in BIT and BIN format
+ on Xilinx Zynq devices.
+
+config SYS_FPGA_CHECK_CTRLC
+ bool "Allow Control-C to interrupt FPGA configuration"
+ depends on FPGA
+ help
+ User can interrupt FPGA configuration by pressing CTRL+C.
+
+config SYS_FPGA_PROG_FEEDBACK
+ bool "Progress output during FPGA configuration"
+ depends on FPGA
+ default y if FPGA_VIRTEX2
+ help
+ Enable printing of hash marks during FPGA configuration.
+
+config FPGA_LOAD_SECURE
+ bool "Enable loading secure bitstreams"
+ depends on FPGA
+ help
+ Enables the fpga loads() functions that are used to load secure
+ (authenticated or encrypted or both) bitstreams on to FPGA.
+
+config SPL_FPGA_LOAD_SECURE
+ bool "Enable loading secure bitstreams for SPL"
+ depends on SPL_FPGA
+ help
+ Enables the fpga loads() functions that are used to load secure
+ (authenticated or encrypted or both) bitstreams on to FPGA.
+
+config DM_FPGA
+ bool "Enable Driver Model for FPGA drivers"
+ depends on DM
+ select FPGA
+ help
+ Enable driver model for Field-Programmable Gate Array (FPGA) devices.
+ The devices cover a wide range of applications and are configured at
+ runtime by loading a bitstream into the FPGA device.
+ Loading a bitstream from any kind of storage is the main task of the
+ FPGA drivers.
+ For now this uclass has no methods yet.
+
+config SANDBOX_FPGA
+ bool "Enable sandbox FPGA driver"
+ depends on SANDBOX && DM_FPGA
+ help
+ This is a driver model based FPGA driver for sandbox.
+ Currently it is a stub only, as there are no usable uclass methods yet.
+
+config MAX_FPGA_DEVICES
+ int "Maximum number of FPGA devices"
+ depends on FPGA
+ default 5
+
+endmenu
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
new file mode 100644
index 00000000000..610c168fc35
--- /dev/null
+++ b/drivers/fpga/Makefile
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+obj-y += fpga.o
+obj-$(CONFIG_DM_FPGA) += fpga-uclass.o
+obj-$(CONFIG_SANDBOX_FPGA) += sandbox.o
+
+obj-$(CONFIG_FPGA_SPARTAN2) += spartan2.o
+obj-$(CONFIG_FPGA_SPARTAN3) += spartan3.o
+obj-$(CONFIG_FPGA_VERSALPL) += versalpl.o
+obj-$(CONFIG_FPGA_VIRTEX2) += virtex2.o
+obj-$(CONFIG_FPGA_ZYNQPL) += zynqpl.o
+obj-$(CONFIG_FPGA_ZYNQMPPL) += zynqmppl.o
+obj-$(CONFIG_FPGA_XILINX) += xilinx.o
+obj-$(CONFIG_FPGA_LATTICE) += ivm_core.o lattice.o
+ifdef CONFIG_FPGA_ALTERA
+obj-y += altera.o
+obj-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o
+obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o
+obj-$(CONFIG_FPGA_INTEL_SDM_MAILBOX) += intel_sdm_mb.o
+obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o
+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
+endif
diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c
new file mode 100644
index 00000000000..64fda3a307c
--- /dev/null
+++ b/drivers/fpga/altera.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2003
+ * Steven Scholz, imc Measurement & Control, steven.scholz@imc-berlin.de
+ *
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ */
+
+#define LOG_CATEGORY UCLASS_FPGA
+
+/*
+ * Altera FPGA support
+ */
+#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX) || \
+ IS_ENABLED(CONFIG_TARGET_SOCFPGA_STRATIX10)
+#include <asm/arch/misc.h>
+#endif
+#include <errno.h>
+#include <ACEX1K.h>
+#include <log.h>
+#include <stratixII.h>
+
+static const struct altera_fpga {
+ enum altera_family family;
+ const char *name;
+ int (*load)(Altera_desc *, const void *, size_t);
+ int (*dump)(Altera_desc *, const void *, size_t);
+ int (*info)(Altera_desc *);
+} altera_fpga[] = {
+#if defined(CONFIG_FPGA_ACEX1K)
+ { Altera_ACEX1K, "ACEX1K", ACEX1K_load, ACEX1K_dump, ACEX1K_info },
+ { Altera_CYC2, "ACEX1K", ACEX1K_load, ACEX1K_dump, ACEX1K_info },
+#elif defined(CONFIG_FPGA_CYCLON2)
+ { Altera_ACEX1K, "CycloneII", CYC2_load, CYC2_dump, CYC2_info },
+ { Altera_CYC2, "CycloneII", CYC2_load, CYC2_dump, CYC2_info },
+#endif
+#if defined(CONFIG_FPGA_STRATIX_II)
+ { Altera_StratixII, "StratixII", StratixII_load,
+ StratixII_dump, StratixII_info },
+#endif
+#if defined(CONFIG_FPGA_STRATIX_V)
+ { Altera_StratixV, "StratixV", stratixv_load, NULL, NULL },
+#endif
+#if defined(CONFIG_FPGA_SOCFPGA)
+ { Altera_SoCFPGA, "SoC FPGA", socfpga_load, NULL, NULL },
+#endif
+#if defined(CONFIG_FPGA_INTEL_SDM_MAILBOX)
+ { Intel_FPGA_SDM_Mailbox, "Intel SDM Mailbox", intel_sdm_mb_load, NULL,
+ NULL },
+#endif
+};
+
+#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX) || \
+ IS_ENABLED(CONFIG_TARGET_SOCFPGA_STRATIX10)
+int fpga_is_partial_data(int devnum, size_t img_len)
+{
+ /*
+ * The FPGA data (full or partial) is checked by
+ * the SDM hardware, for Intel SDM Mailbox based
+ * devices. Hence always return full bitstream.
+ *
+ * For Cyclone V and Arria 10 family, the bitstream
+ * type parameter is not handled by the driver.
+ */
+ return 0;
+}
+
+int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
+ bitstream_type bstype)
+{
+ int ret_val;
+ int flags = 0;
+
+ ret_val = fpga_load(devnum, (void *)fpgadata, size, bstype, flags);
+
+ /*
+ * Enable the HPS to FPGA bridges when FPGA load is completed
+ * successfully. This is to ensure the FPGA is accessible
+ * by the HPS.
+ */
+ if (!ret_val) {
+ printf("Enable FPGA bridges\n");
+ do_bridge_reset(1, ~0);
+ }
+
+ return ret_val;
+}
+#endif
+
+static int altera_validate(Altera_desc *desc, const char *fn)
+{
+ if (!desc) {
+ printf("%s: NULL descriptor!\n", fn);
+ return -EINVAL;
+ }
+
+ if ((desc->family < min_altera_type) ||
+ (desc->family > max_altera_type)) {
+ printf("%s: Invalid family type, %d\n", fn, desc->family);
+ return -EINVAL;
+ }
+
+ if ((desc->iface < min_altera_iface_type) ||
+ (desc->iface > max_altera_iface_type)) {
+ printf("%s: Invalid Interface type, %d\n", fn, desc->iface);
+ return -EINVAL;
+ }
+
+ if (!desc->size) {
+ printf("%s: NULL part size\n", fn);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct altera_fpga *
+altera_desc_to_fpga(Altera_desc *desc, const char *fn)
+{
+ int i;
+
+ if (altera_validate(desc, fn)) {
+ printf("%s: Invalid device descriptor\n", fn);
+ return NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(altera_fpga); i++) {
+ if (desc->family == altera_fpga[i].family)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(altera_fpga)) {
+ printf("%s: Unsupported family type, %d\n", fn, desc->family);
+ return NULL;
+ }
+
+ return &altera_fpga[i];
+}
+
+int altera_load(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ const struct altera_fpga *fpga = altera_desc_to_fpga(desc, __func__);
+
+ if (!fpga)
+ return FPGA_FAIL;
+
+ log_debug("Launching the %s Loader...\n", fpga->name);
+ if (fpga->load)
+ return fpga->load(desc, buf, bsize);
+ return 0;
+}
+
+int altera_dump(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ const struct altera_fpga *fpga = altera_desc_to_fpga(desc, __func__);
+
+ if (!fpga)
+ return FPGA_FAIL;
+
+ log_debug("Launching the %s Reader...\n", fpga->name);
+ if (fpga->dump)
+ return fpga->dump(desc, buf, bsize);
+ return 0;
+}
+
+int altera_info(Altera_desc *desc)
+{
+ const struct altera_fpga *fpga = altera_desc_to_fpga(desc, __func__);
+
+ if (!fpga)
+ return FPGA_FAIL;
+
+ printf("Family: \t%s\n", fpga->name);
+
+ printf("Interface type:\t");
+ switch (desc->iface) {
+ case passive_serial:
+ printf("Passive Serial (PS)\n");
+ break;
+ case passive_parallel_synchronous:
+ printf("Passive Parallel Synchronous (PPS)\n");
+ break;
+ case passive_parallel_asynchronous:
+ printf("Passive Parallel Asynchronous (PPA)\n");
+ break;
+ case passive_serial_asynchronous:
+ printf("Passive Serial Asynchronous (PSA)\n");
+ break;
+ case altera_jtag_mode: /* Not used */
+ printf("JTAG Mode\n");
+ break;
+ case fast_passive_parallel:
+ printf("Fast Passive Parallel (FPP)\n");
+ break;
+ case fast_passive_parallel_security:
+ printf("Fast Passive Parallel with Security (FPPS)\n");
+ break;
+ case secure_device_manager_mailbox:
+ puts("Secure Device Manager (SDM) Mailbox\n");
+ break;
+ /* Add new interface types here */
+ default:
+ printf("Unsupported interface type, %d\n", desc->iface);
+ }
+
+ printf("Device Size: \t%zd bytes\n"
+ "Cookie: \t0x%x (%d)\n",
+ desc->size, desc->cookie, desc->cookie);
+
+ if (desc->iface_fns) {
+ printf("Device Function Table @ 0x%p\n", desc->iface_fns);
+ if (fpga->info)
+ fpga->info(desc);
+ } else {
+ printf("No Device Function Table.\n");
+ }
+
+ return FPGA_SUCCESS;
+}
diff --git a/drivers/fpga/cyclon2.c b/drivers/fpga/cyclon2.c
new file mode 100644
index 00000000000..7e78d6e2d6c
--- /dev/null
+++ b/drivers/fpga/cyclon2.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2006
+ * Heiko Schocher, hs@denx.de
+ * Based on ACE1XK.c
+ */
+
+#define LOG_CATEGORY UCLASS_FPGA
+
+#include <config.h> /* core U-Boot definitions */
+#include <log.h>
+#include <time.h>
+#include <altera.h>
+#include <ACEX1K.h> /* ACEX device family */
+#include <linux/delay.h>
+
+/* Note: The assumption is that we cannot possibly run fast enough to
+ * overrun the device (the Slave Parallel mode can free run at 50MHz).
+ * If there is a need to operate slower, define CFG_FPGA_DELAY in
+ * the board config file to slow things down.
+ */
+#ifndef CFG_FPGA_DELAY
+#define CFG_FPGA_DELAY()
+#endif
+
+#ifndef CFG_SYS_FPGA_WAIT
+#define CFG_SYS_FPGA_WAIT CONFIG_SYS_HZ / 10 /* 100 ms */
+#endif
+
+static int CYC2_ps_load(Altera_desc *desc, const void *buf, size_t bsize);
+static int CYC2_ps_dump(Altera_desc *desc, const void *buf, size_t bsize);
+/* static int CYC2_ps_info( Altera_desc *desc ); */
+
+/* ------------------------------------------------------------------------- */
+/* CYCLON2 Generic Implementation */
+int CYC2_load(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ log_debug("Launching Passive Serial Loader\n");
+ ret_val = CYC2_ps_load(desc, buf, bsize);
+ break;
+
+ case fast_passive_parallel:
+ /* Fast Passive Parallel (FPP) and PS only differ in what is
+ * done in the write() callback. Use the existing PS load
+ * function for FPP, too.
+ */
+ log_debug("Launching Fast Passive Parallel Loader\n");
+ ret_val = CYC2_ps_load(desc, buf, bsize);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf("%s: Unsupported interface type, %d\n",
+ __func__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int CYC2_dump(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ log_debug("Launching Passive Serial Dump\n");
+ ret_val = CYC2_ps_dump(desc, buf, bsize);
+ break;
+
+ /* Add new interface types here */
+
+ default:
+ printf("%s: Unsupported interface type, %d\n",
+ __func__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+int CYC2_info(Altera_desc *desc)
+{
+ return FPGA_SUCCESS;
+}
+
+/* ------------------------------------------------------------------------- */
+/* CYCLON2 Passive Serial Generic Implementation */
+static int CYC2_ps_load(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ Altera_CYC2_Passive_Serial_fns *fn = desc->iface_fns;
+ int ret = 0;
+
+ log_debug("start with interface functions @ 0x%p\n", fn);
+
+ if (fn) {
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ log_debug("Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "config:\t0x%p\n"
+ "status:\t0x%p\n"
+ "write:\t0x%p\n"
+ "done:\t0x%p\n\n",
+ &fn, fn, fn->config, fn->status,
+ fn->write, fn->done);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf("Loading FPGA Device %d...", cookie);
+#endif
+
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre)
+ (*fn->pre) (cookie);
+
+ /* Establish the initial state */
+ (*fn->config) (false, true, cookie); /* De-assert nCONFIG */
+ udelay(100);
+ (*fn->config) (true, true, cookie); /* Assert nCONFIG */
+
+ udelay(2); /* T_cfg > 2us */
+
+ /* Wait for nSTATUS to be asserted */
+ ts = get_timer(0); /* get current time */
+ do {
+ CFG_FPGA_DELAY();
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT) {
+ /* check the time */
+ puts("** Timeout waiting for STATUS to go high.\n");
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+ } while (!(*fn->status) (cookie));
+
+ /* Get ready for the burn */
+ CFG_FPGA_DELAY();
+
+ ret = (*fn->write) (buf, bsize, true, cookie);
+ if (ret) {
+ puts("** Write failed.\n");
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ puts(" OK? ...");
+#endif
+
+ CFG_FPGA_DELAY();
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc(' '); /* terminate the dotted line */
+#endif
+
+ /*
+ * Checking FPGA's CONF_DONE signal - correctly booted ?
+ */
+
+ if (!(*fn->done) (cookie)) {
+ puts("** Booting failed! CONF_DONE is still deasserted.\n");
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ puts(" OK\n");
+#endif
+
+ ret_val = FPGA_SUCCESS;
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS)
+ puts("Done.\n");
+ else
+ puts("Fail.\n");
+#endif
+
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post)
+ (*fn->post) (cookie);
+ } else {
+ printf("%s: NULL Interface function table!\n", __func__);
+ }
+
+ return ret_val;
+}
+
+static int CYC2_ps_dump(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ /* Readback is only available through the Slave Parallel and */
+ /* boundary-scan interfaces. */
+ printf("%s: Passive Serial Dumping is unavailable\n", __func__);
+ return FPGA_FAIL;
+}
diff --git a/drivers/fpga/fpga-uclass.c b/drivers/fpga/fpga-uclass.c
new file mode 100644
index 00000000000..4278ec28e56
--- /dev/null
+++ b/drivers/fpga/fpga-uclass.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 Alexander Dahl <post@lespocky.de>
+ */
+
+#include <dm.h>
+
+UCLASS_DRIVER(fpga) = {
+ .name = "fpga",
+ .id = UCLASS_FPGA,
+};
diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c
new file mode 100644
index 00000000000..2297fefd149
--- /dev/null
+++ b/drivers/fpga/fpga.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ */
+
+/* Generic FPGA support */
+#include <init.h>
+#include <log.h>
+#include <xilinx.h> /* xilinx specific definitions */
+#include <altera.h> /* altera specific definitions */
+#include <lattice.h>
+#include <dm/device_compat.h>
+
+/* Local static data */
+static int next_desc = FPGA_INVALID_DEVICE;
+static fpga_desc desc_table[CONFIG_MAX_FPGA_DEVICES];
+
+/* fpga_get_desc
+ * map a device number to a descriptor
+ */
+const fpga_desc *fpga_get_desc(int devnum)
+{
+ const fpga_desc *desc = NULL;
+
+ if ((devnum >= 0) && (devnum < next_desc)) {
+ desc = &desc_table[devnum];
+ log_debug("found fpga descriptor #%d @ 0x%p\n",
+ devnum, desc);
+ }
+
+ return desc;
+}
+
+/*
+ * fpga_validate
+ * generic parameter checking code
+ */
+const fpga_desc *fpga_validate(int devnum, const void *buf,
+ size_t bsize)
+{
+ const fpga_desc *desc = fpga_get_desc(devnum);
+
+ if (!desc)
+ log_err("Invalid device number %d\n", devnum);
+
+ if (!buf) {
+ log_err("Null buffer.\n");
+ return NULL;
+ }
+ return desc;
+}
+
+/*
+ * fpga_dev_info
+ * generic multiplexing code
+ */
+static int fpga_dev_info(int devnum)
+{
+ int ret_val = FPGA_FAIL; /* assume failure */
+ const fpga_desc *desc = fpga_get_desc(devnum);
+
+ if (desc) {
+ log_info("Device Descriptor @ 0x%p\n",
+ desc->devdesc);
+
+ switch (desc->devtype) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ log_info("Xilinx Device\nDescriptor @ 0x%p\n", desc);
+ ret_val = xilinx_info(desc->devdesc);
+#else
+ log_err("No support for Xilinx devices.\n");
+#endif
+ break;
+ case fpga_altera:
+#if defined(CONFIG_FPGA_ALTERA)
+ log_info("Altera Device\nDescriptor @ 0x%p\n", desc);
+ ret_val = altera_info(desc->devdesc);
+#else
+ log_err("No support for Altera devices.\n");
+#endif
+ break;
+ case fpga_lattice:
+#if defined(CONFIG_FPGA_LATTICE)
+ log_info("Lattice Device\nDescriptor @ 0x%p\n", desc);
+ ret_val = lattice_info(desc->devdesc);
+#else
+ log_err("No support for Lattice devices.\n");
+#endif
+ break;
+ default:
+ log_err("Invalid or unsupported device type %d\n",
+ desc->devtype);
+ }
+ } else {
+ log_err("Invalid device number %d\n", devnum);
+ }
+
+ return ret_val;
+}
+
+/*
+ * fpga_init is usually called from misc_init_r() and MUST be called
+ * before any of the other fpga functions are used.
+ */
+void fpga_init(void)
+{
+ next_desc = 0;
+ memset(desc_table, 0, sizeof(desc_table));
+
+ debug("%s\n", __func__);
+}
+
+/*
+ * fpga_count
+ * Basic interface function to get the current number of devices available.
+ */
+int fpga_count(void)
+{
+ return next_desc;
+}
+
+/*
+ * fpga_add
+ * Add the device descriptor to the device table.
+ */
+int fpga_add(fpga_type devtype, void *desc)
+{
+ int devnum = FPGA_INVALID_DEVICE;
+
+ if (!desc) {
+ log_err("NULL device descriptor\n");
+ return devnum;
+ }
+
+ if (next_desc < 0) {
+ log_err("FPGA support not initialized!\n");
+ } else if ((devtype > fpga_min_type) && (devtype < fpga_undefined)) {
+ if (next_desc < CONFIG_MAX_FPGA_DEVICES) {
+ devnum = next_desc;
+ desc_table[next_desc].devtype = devtype;
+ desc_table[next_desc++].devdesc = desc;
+ } else {
+ log_err("Exceeded Max FPGA device count\n");
+ }
+ } else {
+ log_err("Unsupported FPGA type %d\n", devtype);
+ }
+
+ return devnum;
+}
+
+/*
+ * Return 1 if the fpga data is partial.
+ * This is only required for fpga drivers that support bitstream_type.
+ */
+int __weak fpga_is_partial_data(int devnum, size_t img_len)
+{
+ return 0;
+}
+
+/*
+ * Convert bitstream data and load into the fpga
+ */
+int __weak fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
+ bitstream_type bstype)
+{
+ log_err("Bitstream support not implemented for this FPGA device\n");
+ return FPGA_FAIL;
+}
+
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+int fpga_fsload(int devnum, const void *buf, size_t size,
+ fpga_fs_info *fpga_fsinfo)
+{
+ int ret_val = FPGA_FAIL; /* assume failure */
+ const fpga_desc *desc = fpga_validate(devnum, buf, size);
+
+ if (desc) {
+ switch (desc->devtype) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ ret_val = xilinx_loadfs(desc->devdesc, buf, size,
+ fpga_fsinfo);
+#else
+ log_err("No support for Xilinx devices.\n");
+#endif
+ break;
+ default:
+ log_err("Invalid or unsupported device type %d\n",
+ desc->devtype);
+ }
+ }
+
+ return ret_val;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE)
+int fpga_loads(int devnum, const void *buf, size_t size,
+ struct fpga_secure_info *fpga_sec_info)
+{
+ int ret_val = FPGA_FAIL;
+
+ const fpga_desc *desc = fpga_validate(devnum, buf, size);
+
+ if (desc) {
+ switch (desc->devtype) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ ret_val = xilinx_loads(desc->devdesc, buf, size,
+ fpga_sec_info);
+#else
+ log_err("No support for Xilinx devices.\n");
+#endif
+ break;
+ default:
+ log_err("Invalid or unsupported device type %d\n",
+ desc->devtype);
+ }
+ }
+
+ return ret_val;
+}
+#endif
+
+static int fpga_load_event_notify(const void *buf, size_t bsize, int result)
+{
+ if (CONFIG_IS_ENABLED(EVENT)) {
+ struct event_fpga_load load = {
+ .buf = buf,
+ .bsize = bsize,
+ .result = result
+ };
+
+ return event_notify(EVT_FPGA_LOAD, &load, sizeof(load));
+ }
+
+ return 0;
+}
+
+/*
+ * Generic multiplexing code
+ */
+int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype,
+ int flags)
+{
+ int ret_val = FPGA_FAIL; /* assume failure */
+ int ret_notify;
+ const fpga_desc *desc = fpga_validate(devnum, buf, bsize);
+
+ if (desc) {
+ switch (desc->devtype) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ ret_val = xilinx_load(desc->devdesc, buf, bsize,
+ bstype, flags);
+#else
+ log_err("No support for Xilinx devices.\n");
+#endif
+ break;
+ case fpga_altera:
+#if defined(CONFIG_FPGA_ALTERA)
+ ret_val = altera_load(desc->devdesc, buf, bsize);
+#else
+ log_err("No support for Altera devices.\n");
+#endif
+ break;
+ case fpga_lattice:
+#if defined(CONFIG_FPGA_LATTICE)
+ ret_val = lattice_load(desc->devdesc, buf, bsize);
+#else
+ log_err("No support for Lattice devices.\n");
+#endif
+ break;
+ default:
+ log_err("Invalid or unsupported device type %d\n",
+ desc->devtype);
+ }
+ }
+
+ ret_notify = fpga_load_event_notify(buf, bsize, ret_val);
+ if (ret_notify)
+ return ret_notify;
+
+ return ret_val;
+}
+
+/*
+ * fpga_dump
+ * generic multiplexing code
+ */
+int fpga_dump(int devnum, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume failure */
+ const fpga_desc *desc = fpga_validate(devnum, buf, bsize);
+
+ if (desc) {
+ switch (desc->devtype) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ ret_val = xilinx_dump(desc->devdesc, buf, bsize);
+#else
+ log_err("No support for Xilinx devices.\n");
+#endif
+ break;
+ case fpga_altera:
+#if defined(CONFIG_FPGA_ALTERA)
+ ret_val = altera_dump(desc->devdesc, buf, bsize);
+#else
+ log_err("No support for Altera devices.\n");
+#endif
+ break;
+ case fpga_lattice:
+#if defined(CONFIG_FPGA_LATTICE)
+ ret_val = lattice_dump(desc->devdesc, buf, bsize);
+#else
+ log_err("No support for Lattice devices.\n");
+#endif
+ break;
+ default:
+ log_err("Invalid or unsupported device type %d\n",
+ desc->devtype);
+ }
+ }
+
+ return ret_val;
+}
+
+/*
+ * fpga_info
+ * front end to fpga_dev_info. If devnum is invalid, report on all
+ * available devices.
+ */
+int fpga_info(int devnum)
+{
+ if (devnum == FPGA_INVALID_DEVICE) {
+ if (next_desc > 0) {
+ int dev;
+
+ for (dev = 0; dev < next_desc; dev++)
+ fpga_dev_info(dev);
+
+ return FPGA_SUCCESS;
+ } else {
+ log_err("No FPGA devices available.\n");
+ return FPGA_FAIL;
+ }
+ }
+
+ return fpga_dev_info(devnum);
+}
+
+#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE)
+int fpga_compatible2flag(int devnum, const char *compatible)
+{
+ const fpga_desc *desc = fpga_get_desc(devnum);
+
+ if (!desc)
+ return 0;
+
+ switch (desc->devtype) {
+#if defined(CONFIG_FPGA_XILINX)
+ case fpga_xilinx:
+ {
+ xilinx_desc *xdesc = (xilinx_desc *)desc->devdesc;
+
+ if (xdesc->operations && xdesc->operations->str2flag)
+ return xdesc->operations->str2flag(xdesc, compatible);
+ }
+#endif
+ default:
+ break;
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/fpga/intel_sdm_mb.c b/drivers/fpga/intel_sdm_mb.c
new file mode 100644
index 00000000000..5f4aae47d6d
--- /dev/null
+++ b/drivers/fpga/intel_sdm_mb.c
@@ -0,0 +1,1064 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Intel Corporation <www.intel.com>
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
+ */
+
+#include <altera.h>
+#include <log.h>
+#include <time.h>
+#include <watchdog.h>
+#include <asm/arch/mailbox_s10.h>
+#include <asm/arch/smc_api.h>
+#include <asm/cache.h>
+#include <cpu_func.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/intel-smc.h>
+#include <linux/string.h>
+
+#define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS 60000
+#define RECONFIG_STATUS_INTERVAL_DELAY_US 1000000
+
+#if !defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_ATF)
+
+#define BITSTREAM_CHUNK_SIZE 0xFFFF0
+#define RECONFIG_STATUS_POLL_RETRY_MAX 100
+
+static const struct mbox_cfgstat_major_err {
+ int err_no;
+ const char *error_name;
+} mbox_cfgstat_major_err[] = {
+ {MBOX_CFGSTATE_MAJOR_ERR_WRONG_BL31_VER,
+ "Please check ATF BL31 version, require v2.11 above to print more error status."},
+ {MBOX_CFGSTATE_MAJOR_ERR_STATE_CONFIG,
+ "Mailbox in configuration state."},
+ {MBOX_CFGSTATE_MAJOR_ERR_BITSTREAM_ERR,
+ "Bitstream Invalid."},
+ {MBOX_CFGSTATE_MAJOR_ERR_EXT_HW_ACCESS_FAIL,
+ "External HW access failure."},
+ {MBOX_CFGSTATE_MAJOR_ERR_BITSTREAM_CORRUPTION,
+ "Bitstream valid but corrupted. Bitstream corruption error when reading the bitstream from the source."
+ },
+ {MBOX_CFGSTATE_MAJOR_ERR_INTERNAL_ERR,
+ "Bitstream element not understood. Internal error."},
+ {MBOX_CFGSTATE_MAJOR_ERR_DEVICE_ERR,
+ "Unable to communicate on internal configuration network. Device operation error."},
+ {MBOX_CFGSTATE_MAJOR_ERR_HPS_WDT,
+ "HPS Watchdog Timer. HPS watchdog timeout failure."},
+ {MBOX_CFGSTATE_MAJOR_ERR_INTERNAL_UNKNOWN_ERR,
+ "Other unknown error occurred"},
+ {MBOX_CFGSTATE_MAJOR_ERR_SYSTEM_INIT_ERR,
+ "Error before main CMF start. System initialization failure."},
+ {MBOX_CFGSTATE_MAJOR_ERR_DECRYPTION_ERR,
+ "Decryption Error."},
+ {MBOX_CFGSTATE_MAJOR_ERR_VERIFY_IMAGE_ERR,
+ "Verify image error."},
+ {MBOX_CFGSTATE_MAJOR_ERR_UNK,
+ "Unknown error number at major field!"}
+};
+
+#define MBOX_CFGSTAT_MAJOR_ERR_MAX ARRAY_SIZE(mbox_cfgstat_major_err)
+
+static const struct mbox_cfgstat_minor_err {
+ int err_no;
+ const char *error_name;
+} mbox_cfgstat_minor_err[] = {
+ {MBOX_CFGSTATE_MINOR_ERR_BASIC_ERR,
+ "Catchall Error."},
+ {MBOX_CFGSTATE_MINOR_ERR_CNT_RESP_ERR,
+ "Detected an error during configuration. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_QSPI_DEV_ERR,
+ "QSPI Device related error. Detected QSPI device related error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_INV,
+ "Bitstream section main descriptor invalid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_BS_INCOMPATIBLE,
+ "Bistream not compatible with device. Detected an error during configuration due to incompatible bitstream with the device."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_BS_INV_SHA,
+ "Bitstream invalid SHA setting. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_ROUTE_FAIL,
+ "Bitstream processing route failed. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_GO_BIT_ALREADY_SET,
+ "Failed DMA during bitstream processing. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_CPU_BLK_FAIL,
+ "Failed DMA during bitstream processing. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_SKIP_FAIL,
+ "Skip action failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_MCAST_FAIL,
+ "Multicast Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_IND_SZ_FAIL,
+ "Index Size Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_IF_FAIL,
+ "If Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_PIN_FAIL,
+ "Pin Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_FUSEFLTR_FAIL,
+ "Fuse Filter Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_GENERIC_FAIL,
+ "Other Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_DATA_STARVE_ERR,
+ "Datapath starved. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_CNT_RAM_INIT_FAIL,
+ "CNT/SSM RAM Initialization Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_SETUP_S4,
+ "S4 Setup Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_WIPE_DATA_STARVE,
+ "Datapath starved during wipe. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_FUSE_RD_FAIL,
+ "eFUSE Read Failure. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_AUTH_FAIL,
+ "Authentication Failure. Detected a bitstream authentication error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_SHA_FAIL,
+ "Bitstream Section Main Descriptor Hash Check Failed. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_SKIP_DATA_RAM_FAIL,
+ "Skip Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_FIXED_FAIL,
+ "Fixed Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_MCAST_FLTR_FAIL,
+ "Multicast Filter Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_SECTOR_FAIL,
+ "Sector Group Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_HASH_FAIL,
+ "Hash Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_DECOMP_SETUP_FAIL,
+ "Decompression Setup Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_INTERNAL_OS_ERR,
+ "RTOS Error. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_WIPE_FAIL,
+ "Wipe Bitstream Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_CNOC_ERR,
+ "Internal Configuration Network Failure. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_RESUME_FAIL,
+ "Power Management Firmware Failed Resume. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_RUN_FAIL,
+ "Power Management Firmware Failed Run. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_PAUSE_FAIL,
+ "Power Management Firmware Failed Pause. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RET_INT_ASSERT_FAIL,
+ "Internal Configuration Network Return Interrupt Failure. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_STATE_MACHINE_ERR,
+ "Configuration State Machine Error. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_CMF_TRANSITION_FAIL,
+ "Error during CMF load/reload. Detected a firmware transition error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_SHA_SETUP_FAIL,
+ "Error setting up SHA engine. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_WR_DMA_TIMEOUT,
+ "Write DMA timed out. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MEM_ALLOC_FAIL,
+ "Out of Memory. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYNC_RD_FAIL,
+ "Sync Block Read Fail. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_CHK_CFG_REQ_FAIL,
+ "Configuration Status Check Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_HPS_CFG_REQ_FAIL,
+ "HPS Configuration Request Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_CFG_HANDLE_ERR,
+ "Driver Handle Error. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_INV_ACTION_ITEM,
+ "Bistream contains invalid action. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_SKIP_DATA_PREBUF_ERR,
+ "Prebuffer Error during Skip Action. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_TIMEOUT,
+ "Mailbox Processing Timeout. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_AVST_FIFO_OVERFLOW_ERR,
+ "AVST FIFO Overflow. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_RD_DMA_TIMEOUT,
+ "Read DMA timed out. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_INIT_ERR,
+ "Power Management Firmware Initialization Error. Detected a PMBUS error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_SHUTDOWN_ERR,
+ "Power Management Firmware Shutdown Error. Detected a PMBUS error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_BITSTREAM_INTERRUPTED,
+ "Bitstream processing was interrupted by another event. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_FPGA_MBOX_WIPE_TIMEOUT,
+ "Mailbox Wipe Timeout. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_TYPE_INV,
+ "Bitstream Section Main Descriptor Type is Invalid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_VERSION_INV,
+ "Bitstream Section Main Descriptor Version is Invalid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_DEVICE_TYPE_INV,
+ "Bitstream Section Main Descriptor Device is Invalid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_DESIGN_HASH_ERR,
+ "Bitstream Section Main Descriptor Hash Mismatch. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_EXT_REF_CLK_ERR,
+ "Bitstream Section Main Descriptor External Clock Setting Invalid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_PWR_TBL_INV,
+ "Bitstream Section Main Descriptor Power Table is invalid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_PIN_TBL_OFST_ERR,
+ "Bitstream Section Main Descriptor Offset to Pin Table is Invalid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_PIN_TBL_INV,
+ "Bitstream Section Main Descriptor Pin Table is Invalid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_NO_PIN_TBL,
+ "Bitstream Section Main Descriptor missing pin table. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_CFG_CLK_PLL_FAILED,
+ "Bitstream Section Main Descriptor PLL setting failure. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_AS_CLK_FAILED,
+ "Bitstream Section Main Descriptor QSPI Clock Setting Failure. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_POF_ID_FAILED,
+ "Bitstream Section Main Descriptor POF ID not valid. Detected an incompatible PR bitstream during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_PW_TBL_OFST_ERR,
+ "code not used."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_PP_TBL_OFST_ERR,
+ "code not used."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_PP_TBL_INV,
+ "code not used."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_SP_TBL_OFST_ERR,
+ "code not used."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_SP_TBL_INV,
+ "code not used."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_SU_TBL_OFST_ERR,
+ "code not used."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_SU_TBL_INV,
+ "code not used."},
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_TASK_CRYPTO_SRC_CLR_ERR,
+ "Mailbox Source Failed to Clear. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_TASK_EVENT_GROUP_POST_ERR,
+ "Mailbox Event Post Error. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_TRNG_TEST_FAIL,
+ "True Random Number Generator Failed Test. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_TASK_ANTI_DOS_TMR_INIT_ERR,
+ "Mailbox Anti-DOS Timer failed initialization. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_OS_STK_CHK_ERR,
+ "RTOS Stack Check Error. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_TASK_INIT,
+ "Mailbox Task failed to initialize. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_COMPAT_ID_MATCH_ERR,
+ "Bitstream Section Main Descriptor Compatibility ID mismatch. Detected a bitstream error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_COMPAT_ID_INV,
+ "Bitstream Section Main Descriptor Compatibility ID not Valid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_AES_ECRYPT_CHK_FAIL,
+ "Bitstream Section Main Descriptor AES Test Failed. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_KEY_FAIL,
+ "Key Action Failure. Detected a bitstream decryption error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_KEY_CHALLENGE_FAIL,
+ "Key Challenge Failure. Detected a bitstream decryption error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_TASK_MSGQ_DEQUEUE_FAIL,
+ "Mailbox Task Queue failed to dequeue. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_SECT_COMPAT_CHK_ERR,
+ "Bitstream Section Compatibility Check Error. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_SECT_COMPAT_UPDATE_ERR,
+ "Bitstream Section Compatibility Update Error. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_SECT_SEC_CHK_FAILED,
+ "Bitstream Section Security Check Failed. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_CNT_RAM_ECC_ERR_UNRECOVERABLE,
+ "Unrecoverable Error in CNT/SSM RAM. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_REFORMAT_INPUT_ERR,
+ "Mailbox Input Processing Error. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_REFORMAT_OUTPUT_ERR,
+ "Mailbox Output Processing Error. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_WLBL_ERR,
+ "(Provision only) Provision CMF's allowed mailbox cmd group is invalid. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MBOX_HOOK_CB_ERR,
+ "Mailbox Callback Error. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_CMF_RLD_DECOMP_LOAD_ERR,
+ "CMF Reload failed to load Decompression Code. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_CMF_RLD_DECOMP_RUN_ERR,
+ "CMF Reload failed to run Decompression Code. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_CNT_PERIPH_ECC_ERR_UNRECOVERABLE,
+ "Unrecoverable Error in CNT/SSM Peripheral. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_SECT_ADDR_ERR,
+ "(Provision only) invalid Flash image CMF header's main section address. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_SCRAMBLE_RATIO_CHK_FAIL,
+ "Bitstream Section Main Descriptor Invalid Scrambler Ratio. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TAMPER_EVENT_TRIGGERED,
+ "Tamper Detected. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_ANTI_TAMPER_TBL_INV,
+ "Bitstream Section Main Descriptor Anti Tamper Table Invalid. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_EXT_CLCK_MODE_DISALLOWED,
+ "External Clock info presented, but external clock not allowed on device. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_SEC_OPTIONS_INIT_FAIL,
+ "Bitstream Section Main Descriptor Security Option Initialization Failed. Detected an error during configuration due to a corrupted bitstream."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_EN_USR_CAN_FUSE_INV,
+ "User cancellation fuse table initialization failed. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_AS_DEVICE_NO_SGX_ERR,
+ "Not yet turned on for Rearch code. Detected an incompatible bitstream during configuration. You cannot use the bitstream from an advanced security-enabled devices on a non-advanced security-enabled device."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_POF_ID_LIMIT_EXCEED_ERR,
+ "Not yet turned on for Rearch code. Detected an invalid bitstream during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PROVISION_CMF_INV_STATE,
+ "(Provision only) Internal state machine wrong state. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PROVISION_CMF_FATAL_ERR,
+ "(Provision only) Fatal error detected with Provision CMF. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PROVISION_CMF_SM_EXIT_FAIL,
+ "(Provision only) State machine's state function exit error. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PROVISION_CMF_SM_ENTRY_FAIL,
+ "(Provision only) State machine's state function entry error. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_ACTION_DATA_UNSUPPORTED_CTX,
+ "Not yet turned on for Rearch code. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_CMF_EXCEPTION,
+ "Processor Exception. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ECC_INIT_FAIL,
+ "SDM Peripheral ECC Initialization Failure. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_DEFAULT_UNREGISTERED_ISR,
+ "Unregistered Interrupt Occurred. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_GENERAL_TIMEOUT,
+ "Execution Timeout. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_OPERATION_CLK_FAIL,
+ "Clock Operation Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_VERIFY_HASH_FAIL,
+ "Verify Hash Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_CFG_STATE_UPDATE_ERR,
+ "Error updating configuration state. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_READ_DDR_HASH_FAIL,
+ "Error while reading HPS DDR hash from main descriptor."},
+ {MBOX_CFGSTATE_MINOR_ERR_CVP_FLOW_ERR,
+ "Error during CvP Phase 2 data flow handling or handshake."},
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_KEYED_HASH_ERR,
+ "Encountered keyed hash error while processing a main descriptor."},
+ {MBOX_CFGSTATE_MINOR_ERR_CMF_DESC_BAD_JTAG_ID,
+ "New CMF Descriptor JTAG ID mismatch with original configured CMF JTAG ID."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_PMF_NOT_SUPPORTED,
+ "The IO Descriptor contains a power table but the current CMF does not support PMF. Bitstream incompatile with Firmware."
+ },
+ {
+ MBOX_CFGSTATE_MINOR_ERR_MAIN_DESC_ANTI_TAMPER_NOT_SUPPORTED,
+ "The IO Descriptor contains anti-tamper setting but the current CMF does not support anti-tamper. Bitstream incompatile with Firmware."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_ACT_RECOVERY_FAIL,
+ "Recovery Action Failed. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_COLD_RESET_CMF_CORRUPTED,
+ "Error when process CMF section after cold reset. Detected CMF section error or incompatible upon cold reset using JTAG or AVST."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_COLD_RESET_IO_HPS_CORRUPTED,
+ "Error when process IO/HPIO/HPS section after cold reset and hps wipe. Detected an error when try to bring up HPS again after cold reset."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_COLD_RESET_FPGA_CORRUPTED,
+ "Error when process FPGA section header after cold reset. Detected an error in FPGA after successfully bring up HPS."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_CRC_CHK_FAIL,
+ " CRC32 Check Fail. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_COMPAT_TBL_SFIXED_VALUE_INV,
+ "Error when process compatibility table in main section header. SFixed offset value in compatibility table is not valid."
+ },
+ {
+ MBOX_CFGSTATE_MINOR_ERR_FEATURE_EN_FUSE_NOT_BLOWN,
+ "Error bitstream contains feature(s) that are only allowed when a feature fuse is blown on the device, and the device did not have the feature fuse blown. Bitstream requires feature enable fuse to be blown."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_UIB_REFCLK_MISSING,
+ "UIB REFCLK missing. Device requires refclk to proceed configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_UIB_REFCLK_TIMEOUT,
+ "UIB REFCLK timeout. Device requires refclk to proceed configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_UIB_REFCLK_TIMEOUT_MISSING,
+ "UIB REFCLK missing and timeout. Device requires refclk to proceed configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_SYNC_BLCK_ERR,
+ "Sync block before SSBL processing failure. Detected a firmware error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_SSBL_SHA_ERR,
+ "SSBL sha mismatch with bitstream. Detected a bitstream error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_BLCK0_SHA_MISMATCH_ERR,
+ "Block0 Sha mismatch when trampoline reloads. Detected a bitstream error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_BLCK0_AUTH_ERR,
+ "Trampoline authentication failure. Detected a bitstream error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_TRAMP_LOAD_ERR,
+ "Trampoline Load compressed tramp failure. Detected a bitstream error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_CMF_SIZE_ERR,
+ "Trampoline failed to retrieve SSBL or TSBL load information. Detected a bitstream error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_TRANSITION_ERR,
+ "Trampoline failed to find a bootable DCMF. Detected an error during application images transition."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_SYNC_ERR,
+ "Only used by RMA and ENG loader on legacy code. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_LOAD_CERT_ERR,
+ "Main CMF failed to authenticate a certificate bitstream. Detected a bitstream authentication error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_LOAD_NOT_ALLOWED_ERR,
+ "Only used by Provision CMF, failure to initialize HW drivers. Detected an error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_FUSE_ERR,
+ "Only used by RMA and Eng loader on Legacy code. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_INPUT_BUFFER_ERR,
+ "Provision CMF only, Trampoline inbuf HW access error. Detected a hardware error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_CMF_TYPE_ERR,
+ "Trampoline/DCMF loading another CMF andfound CMF type mismatched with current one. Detected a bitstream error during reconfiguration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_TRAMP_QSPI_INDR_READ_START_ERR,
+ "Trampoline QSPI indirect read start error. Detected an error when accessing the QSPI flash."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_I2C_COMM_ERR,
+ "Generic I2C error, ie Bad Address."},
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_TARGET_VOLTAGE_ERR,
+ "Failed to reach Target Voltage. Voltage Regulator unable to achieve the requested voltage."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_HANDSHAKE_ERR,
+ "Slave Mode ALERT/VOUT_COMMAND handshake did not happen."},
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_ITD_OUT_OF_RANGE_ERR,
+ "Fuse values calculated voltage greater that cutoff max. ITD fuse is out of range."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_PWR_TABLE_ERR,
+ "Error while reading or processing the Power Table. Internal Error while reading or decoding the Bitstream's Power Table."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_EFUSE_DECODE_ERR,
+ "Error while reading or decoding the efuse values. Internal Error while reading or decoding the efuse values."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_VCCL_PWRGOOD_ERR,
+ "Failed to verify the vccl power is good. Failed to validate the vccl power is valid on the board."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_CLR_FAULTS_ERR,
+ "Error while sending CLEAR_FAULTS command. Error while sending CLEAR_FAULTS command,"
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_VOUT_MODE_ERR,
+ "Error while sending VOUT_MODE command. Error while sending VOUT_MODE command,"},
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_PAGE_COMMAND_ERR,
+ "Error while sending PAGE_COMMAND command. Error while sending PAGE_COMMAND command,"
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_VOUT_COMMAND_ERR,
+ "Error while sending VOUT_COMMAND command. Error while sending VOUT_COMMAND command,"
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_READ_VOUT_ERR,
+ "Error while sending READ_VOUT command. Error while sending READ_VOUT command,"},
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_LTM4677_DEFAULT_ADC_CTRL_ERR,
+ "Error while sending the vendor specific LTM4677 MFR_ADC_CTRL command. Error while sending the vendor specific LTM4677 MFR_ADC_CTRL command,"
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_PMF_FIRST_I2C_CMD_FAILED_ERR,
+ "First I2C messaged failed, ie Bad Address. The first I2C command has failed, no response from Voltage Regulator."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_CMF_AUTH_ERR,
+ "Failed to authenticate CMF section. Detected a firmware authentication error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_USER_AUTH_ERR,
+ "Failed to authenticate USER section. Detected a bitstream authentication error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_CMF_DESC_SHA_MISMATCH,
+ "Block0 SHA mismatch when DCMF loads an APP image. Detected an error when loading the application image from flash."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_POINTERS_NOT_FOUND_ERR,
+ "RSU CPB table parsing failed. Detected an error when parsing the RSU CPB block."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_QSPI_FREQ_CHANGE,
+ "QSPI reference clock freq update failed. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_FACTORY_IMG_FAILED,
+ "RSU factory image failed to boot. Detected an error when loading the factory image. Check the factory image validity. If corrupted, regenerate and reprogram again the factory image in the flash. When authentication enabled,"
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_CMF_TYPE_ERR,
+ "APP image CMF type mismatched with DCMF. Detected an error when loading the application image."
+ },
+ {
+ MBOX_CFGSTATE_MINOR_ERR_RSU_UCMF_SIG_DESC_ERR,
+ "UCMF reports failure in parsing of an signature block, can be from new DCMF, new DCIO or new Factory. Detected an error during factory image update in flash."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_UCMF_INTERNAL_AUTH_ERR,
+ "UCMF reports authentication failure of new DCMF, new DCIO or new Factory. Detected an error during DCMF update in flash."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_UCMF_COPY_FAILED,
+ "UCMF reports QSPI flash write failure while upgrading DCMF, DCIO or Factory. Detected an error during DCMF update in flash."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_UCMF_ERASE_FAILED,
+ "UCMF reports QSPI flash erase failure while upgrading DCMF, DCIO or Factory. Detected an error during DCMF update in flash."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_RM_UCMF_FROM_CPB_FAILED,
+ "UCMF reports failure to remove UCMF address from RSU CPB table. Detected an error during RSU CPB table update in flash."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_UCMF_COMBINED_APP_AUTH_ERR,
+ "UCMF reports authentication failure of new combined app image. Detected an error during combined app image update in flash."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_UCMF_FLASH_ACCESS_ERR,
+ "UCMF failed to upgrade for more than max retry times. Detected an error during DCMF update in flash."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_DCMF_DCIO_CORRUPTED,
+ "DCMF reports failure when parse dcio section, causing force factory boot. Detected an error when parsing dcio section."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_DCMF_CPB0_CORRUPTED,
+ "DCMF reports failure when parse cpb0 and thus cpb1 is used. Detected an error in RSU CPB0 table."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_DCMF_CPB1_CORRUPTED,
+ "DCMF reports failure when parse both cpb0 and cpb1, causing force factory boot. Detected an error in both RSU CPB0 and CPB1 table."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_PROVISION_COMPLETE,
+ "Non-JTAG Provisioning Successful. Non-Jtag Provisioning was Successful DCMF will load next highest priority application image."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_RSU_PROVISION_ERR,
+ "Non-JTAG Provisioning Failed. An error occurred while provisioning the device."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_EFUSE_INIT_FAIL,
+ "Efuse cache generation failure. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_SEC_PROT_ERR,
+ "Security lock and disable driver failure. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_EFUSE_LCK_ERR,
+ "efuse lock operation failure."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_SEC_BBRAM_CLEAN_ERR,
+ "BBRAM clean up failure."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_ENG_LOAD_DIMK_ERR,
+ "DIMK failed to derive device identity."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_SEC_UKV_CLEAN_ERR,
+ "Key Vault clean up failure."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_EFUSE_ZERO_ERR,
+ "No security efuse allowed."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_ENG_LOAD_ERR,
+ "efuse policy check failed."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_PERST_INIT_FAIL,
+ "Peristent data initialization failure. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_DIMK_INIT_FAIL,
+ "DIMK Initialization failure. Detected an error during configuration."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_PERST_SECONDARY_INIT_FAIL,
+ "Handoff data include CMF main and signature blocks validation failure. Detected an error during configuration."
+ },
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_BR_INFO_INIT_FAIL,
+ "CMF Bootrom header validation failure."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_CMF_DESC_FAIL,
+ "CMF Descriptor failure."},
+ {MBOX_CFGSTATE_MINOR_ERR_SYSINIT_DRNG_INIT_FAIL,
+ "DRNG Initialization failed."},
+ {MBOX_CFGSTATE_MINOR_ERR_UNK,
+ "Unknown error number at minor field!"}
+};
+
+#define MBOX_CFGSTAT_MINOR_ERR_MAX ARRAY_SIZE(mbox_cfgstat_minor_err)
+
+struct mbox_err_msg {
+ const char *major_err_str;
+ const char *minor_err_str;
+};
+
+static void mbox_cfgstat_to_str(int err, struct mbox_err_msg *err_msg)
+{
+ int i;
+ u32 major_err;
+ u32 minor_err;
+
+ major_err = FIELD_GET(MBOX_CFG_STATUS_MAJOR_ERR_MSK, err);
+
+ minor_err = FIELD_GET(MBOX_CFG_STATUS_MINOR_ERR_MSK, err);
+
+ if (!err_msg) {
+ printf("Invalid argument\n");
+ return;
+ }
+
+ err_msg->major_err_str = "";
+ err_msg->minor_err_str = "";
+
+ /*
+ * In the case of getting error number 0, meaning the
+ * ATF BL31 is not supporting the feature yet thus,
+ * the SMC call will return 0 at the second argument
+ * return the message to indicate that current BL31
+ * is not yet supporting feature and need to check
+ * the BL31 version.
+ */
+ if (err == 0) {
+ err_msg->major_err_str = mbox_cfgstat_major_err[err].error_name;
+ return;
+ }
+
+ /* Initialize the major error string with unknown error */
+ err_msg->major_err_str = mbox_cfgstat_major_err[0].error_name;
+
+ for (i = 0; i < MBOX_CFGSTAT_MAJOR_ERR_MAX - 1; i++) {
+ if (mbox_cfgstat_major_err[i].err_no == major_err) {
+ err_msg->major_err_str = mbox_cfgstat_major_err[i].error_name;
+ break;
+ }
+ }
+
+ /* Return configuration state if device still under config state */
+ if (major_err == MBOX_CFGSTATE_MAJOR_ERR_STATE_CONFIG)
+ return;
+
+ /* Initialize the minor error string with unknown error */
+ err_msg->minor_err_str = mbox_cfgstat_minor_err[0].error_name;
+
+ for (i = 0; i < MBOX_CFGSTAT_MINOR_ERR_MAX - 1; i++) {
+ if (mbox_cfgstat_minor_err[i].err_no == minor_err) {
+ err_msg->minor_err_str = mbox_cfgstat_minor_err[i].error_name;
+ break;
+ }
+ }
+}
+
+/*
+ * Polling the FPGA configuration status.
+ * Return 0 for success, non-zero for error.
+ */
+static int reconfig_status_polling_resp(uint32_t *error_status)
+{
+ int ret;
+ u64 res_buf[3];
+ unsigned long start = get_timer(0);
+
+ while (1) {
+ ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_ISDONE, NULL, 0,
+ res_buf, ARRAY_SIZE(res_buf));
+
+ if (error_status)
+ *error_status = (uint32_t)res_buf[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)
+ return -ETIMEDOUT; /* time out */
+
+ puts(".");
+ udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+ schedule();
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int send_bitstream(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_OK &&
+ wr_ret != INTEL_SIP_SMC_STATUS_BUSY)
+ 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, ARRAY_SIZE(res_buf));
+ if (!ret) {
+ for (i = 0; i < ARRAY_SIZE(res_buf); 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);
+ }
+ schedule();
+ }
+
+ return 0;
+}
+
+/*
+ * This is the interface used by FPGA driver.
+ * Return 0 for success, non-zero for error.
+ */
+int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
+{
+ int ret;
+ u64 arg = 1;
+ u32 err_status = 0;
+ u64 res_buf[3];
+ struct mbox_err_msg err_msg;
+
+ debug("Invoking FPGA_CONFIG_START...\n");
+
+ flush_dcache_range((unsigned long)rbf_data, (unsigned long)(rbf_data + rbf_size));
+
+ ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_START, &arg, 1, NULL, 0);
+
+ if (ret) {
+ puts("U-Boot SMC: Failure in RECONFIG mailbox command!\n");
+ return ret;
+ }
+
+ ret = send_bitstream(rbf_data, rbf_size);
+ if (ret) {
+ puts("\nU-Boot SMC: Error sending bitstream!\n");
+ ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_ISDONE, NULL, 0,
+ res_buf, ARRAY_SIZE(res_buf));
+
+ err_status = res_buf[0];
+ mbox_cfgstat_to_str(err_status, &err_msg);
+ printf("SDM: Config status: (0x%x)\nSDM Err: %s\n%s\n", err_status,
+ err_msg.major_err_str, err_msg.minor_err_str);
+
+ return ret;
+ }
+
+ /* Make sure we don't send MBOX_RECONFIG_STATUS too fast */
+ udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+
+ debug("U-Boot SMC: Polling with MBOX_RECONFIG_STATUS...\n");
+ ret = reconfig_status_polling_resp(&err_status);
+ if (ret) {
+ printf("\nU-Boot SMC: FPGA reconfiguration failed!\n");
+ mbox_cfgstat_to_str(err_status, &err_msg);
+ printf("SDM: Config status: (0x%x)\nSDM Err:%s\n%s\n", err_status,
+ err_msg.major_err_str, err_msg.minor_err_str);
+
+ return ret;
+ }
+
+ puts("FPGA reconfiguration OK!\n");
+
+ return ret;
+}
+
+#else
+
+static const struct mbox_cfgstat_state {
+ int err_no;
+ const char *error_name;
+} mbox_cfgstat_state[] = {
+ {MBOX_CFGSTAT_STATE_IDLE, "FPGA in idle mode."},
+ {MBOX_CFGSTAT_STATE_CONFIG, "FPGA in config mode."},
+ {MBOX_CFGSTAT_STATE_FAILACK, "Acknowledgment failed!"},
+ {MBOX_CFGSTAT_STATE_ERROR_INVALID, "Invalid bitstream!"},
+ {MBOX_CFGSTAT_STATE_ERROR_CORRUPT, "Corrupted bitstream!"},
+ {MBOX_CFGSTAT_STATE_ERROR_AUTH, "Authentication failed!"},
+ {MBOX_CFGSTAT_STATE_ERROR_CORE_IO, "I/O error!"},
+ {MBOX_CFGSTAT_STATE_ERROR_HARDWARE, "Hardware error!"},
+ {MBOX_CFGSTAT_STATE_ERROR_FAKE, "Fake error!"},
+ {MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO, "Error in boot info!"},
+ {MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR, "Error in QSPI!"},
+ {MBOX_RESP_ERROR, "Mailbox general error!"},
+ {-ETIMEDOUT, "I/O timeout error"},
+ {-1, "Unknown error!"}
+};
+
+#define MBOX_CFGSTAT_MAX ARRAY_SIZE(mbox_cfgstat_state)
+
+static const char *mbox_cfgstat_to_str(int err)
+{
+ int i;
+
+ for (i = 0; i < MBOX_CFGSTAT_MAX - 1; i++) {
+ if (mbox_cfgstat_state[i].err_no == err)
+ return mbox_cfgstat_state[i].error_name;
+ }
+
+ return mbox_cfgstat_state[MBOX_CFGSTAT_MAX - 1].error_name;
+}
+
+/*
+ * Add the ongoing transaction's command ID into pending list and return
+ * the command ID for next transfer.
+ */
+static u8 add_transfer(u32 *xfer_pending_list, size_t list_size, u8 id)
+{
+ int i;
+
+ for (i = 0; i < list_size; i++) {
+ if (xfer_pending_list[i])
+ continue;
+ xfer_pending_list[i] = id;
+ debug("ID(%d) added to transaction pending list\n", id);
+ /*
+ * Increment command ID for next transaction.
+ * Valid command ID (4 bits) is from 1 to 15.
+ */
+ id = (id % 15) + 1;
+ break;
+ }
+
+ return id;
+}
+
+/*
+ * Check whether response ID match the command ID in the transfer
+ * pending list. If a match is found in the transfer pending list,
+ * it clears the transfer pending list and return the matched
+ * command ID.
+ */
+static int get_and_clr_transfer(u32 *xfer_pending_list, size_t list_size,
+ u8 id)
+{
+ int i;
+
+ for (i = 0; i < list_size; i++) {
+ if (id != xfer_pending_list[i])
+ continue;
+ xfer_pending_list[i] = 0;
+ return id;
+ }
+
+ return 0;
+}
+
+/*
+ * 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 = mbox_get_fpga_config_status(MBOX_RECONFIG_STATUS);
+ if (!ret)
+ return 0; /* configuration success */
+
+ if (ret != MBOX_CFGSTAT_STATE_CONFIG)
+ return ret;
+
+ if (get_timer(start) > RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
+ break; /* time out */
+
+ puts(".");
+ udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+ schedule();
+ }
+
+ return -ETIMEDOUT;
+}
+
+static u32 get_resp_hdr(u32 *r_index, u32 *w_index, u32 *resp_count,
+ u32 *resp_buf, u32 buf_size, u32 client_id)
+{
+ u32 buf[MBOX_RESP_BUFFER_SIZE];
+ u32 mbox_hdr;
+ u32 resp_len;
+ u32 hdr_len;
+ u32 i;
+
+ if (*resp_count < buf_size) {
+ u32 rcv_len_max = buf_size - *resp_count;
+
+ if (rcv_len_max > MBOX_RESP_BUFFER_SIZE)
+ rcv_len_max = MBOX_RESP_BUFFER_SIZE;
+ resp_len = mbox_rcv_resp(buf, rcv_len_max);
+
+ for (i = 0; i < resp_len; i++) {
+ resp_buf[(*w_index)++] = buf[i];
+ *w_index %= buf_size;
+ (*resp_count)++;
+ }
+ }
+
+ /* No response in buffer */
+ if (*resp_count == 0)
+ return 0;
+
+ mbox_hdr = resp_buf[*r_index];
+
+ hdr_len = MBOX_RESP_LEN_GET(mbox_hdr);
+
+ /* Insufficient header length to return a mailbox header */
+ if ((*resp_count - 1) < hdr_len)
+ return 0;
+
+ *r_index += (hdr_len + 1);
+ *r_index %= buf_size;
+ *resp_count -= (hdr_len + 1);
+
+ /* Make sure response belongs to us */
+ if (MBOX_RESP_CLIENT_GET(mbox_hdr) != client_id)
+ return 0;
+
+ return mbox_hdr;
+}
+
+/* Send bit stream data to SDM via RECONFIG_DATA mailbox command */
+static int send_reconfig_data(const void *rbf_data, size_t rbf_size,
+ u32 xfer_max, u32 buf_size_max)
+{
+ u32 response_buffer[MBOX_RESP_BUFFER_SIZE];
+ u32 xfer_pending[MBOX_RESP_BUFFER_SIZE];
+ u32 resp_rindex = 0;
+ u32 resp_windex = 0;
+ u32 resp_count = 0;
+ u32 xfer_count = 0;
+ int resp_err = 0;
+ u8 cmd_id = 1;
+ u32 args[3];
+ int ret;
+
+ debug("SDM xfer_max = %d\n", xfer_max);
+ debug("SDM buf_size_max = %x\n\n", buf_size_max);
+
+ memset(xfer_pending, 0, sizeof(xfer_pending));
+
+ while (rbf_size || xfer_count) {
+ if (!resp_err && rbf_size && xfer_count < xfer_max) {
+ args[0] = MBOX_ARG_DESC_COUNT(1);
+ args[1] = (u64)rbf_data;
+ if (rbf_size >= buf_size_max) {
+ args[2] = buf_size_max;
+ rbf_size -= buf_size_max;
+ rbf_data += buf_size_max;
+ } else {
+ args[2] = (u64)rbf_size;
+ rbf_size = 0;
+ }
+
+ resp_err = mbox_send_cmd_only(cmd_id, MBOX_RECONFIG_DATA,
+ MBOX_CMD_INDIRECT, 3, args);
+ if (!resp_err) {
+ xfer_count++;
+ cmd_id = add_transfer(xfer_pending,
+ MBOX_RESP_BUFFER_SIZE,
+ cmd_id);
+ }
+ puts(".");
+ } else {
+ u32 resp_hdr = get_resp_hdr(&resp_rindex, &resp_windex,
+ &resp_count,
+ response_buffer,
+ MBOX_RESP_BUFFER_SIZE,
+ MBOX_CLIENT_ID_UBOOT);
+
+ /*
+ * If no valid response header found or
+ * non-zero length from RECONFIG_DATA
+ */
+ if (!resp_hdr || MBOX_RESP_LEN_GET(resp_hdr))
+ continue;
+
+ /* Check for response's status */
+ if (!resp_err) {
+ resp_err = MBOX_RESP_ERR_GET(resp_hdr);
+ debug("Response error code: %08x\n", resp_err);
+ }
+
+ ret = get_and_clr_transfer(xfer_pending,
+ MBOX_RESP_BUFFER_SIZE,
+ MBOX_RESP_ID_GET(resp_hdr));
+ if (ret) {
+ /* Claim and reuse the ID */
+ cmd_id = (u8)ret;
+ xfer_count--;
+ }
+
+ if (resp_err && !xfer_count)
+ return resp_err;
+ }
+ schedule();
+ }
+
+ return 0;
+}
+
+/*
+ * This is the interface used by FPGA driver.
+ * Return 0 for success, non-zero for error.
+ */
+int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
+{
+ int ret;
+ u32 resp_len = 2;
+ u32 resp_buf[2];
+
+ flush_dcache_range((unsigned long)rbf_data, (unsigned long)(rbf_data + rbf_size));
+
+ debug("Sending MBOX_RECONFIG...\n");
+ ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RECONFIG, MBOX_CMD_DIRECT, 0,
+ NULL, 0, &resp_len, resp_buf);
+ if (ret) {
+ puts("Failure in RECONFIG mailbox command!\n");
+ return ret;
+ }
+
+ ret = send_reconfig_data(rbf_data, rbf_size, resp_buf[0], resp_buf[1]);
+ if (ret) {
+ printf("RECONFIG_DATA error: %08x, %s\n", ret,
+ mbox_cfgstat_to_str(ret));
+ 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("RECONFIG_STATUS Error: %08x, %s\n", ret,
+ mbox_cfgstat_to_str(ret));
+ return ret;
+ }
+
+ puts("FPGA reconfiguration OK!\n");
+
+ return ret;
+}
+#endif
diff --git a/drivers/fpga/ivm_core.c b/drivers/fpga/ivm_core.c
new file mode 100644
index 00000000000..37d5c5ec9ec
--- /dev/null
+++ b/drivers/fpga/ivm_core.c
@@ -0,0 +1,3149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Porting to u-boot:
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * Lattice ispVME Embedded code to load Lattice's FPGA:
+ *
+ * Copyright 2009 Lattice Semiconductor Corp.
+ *
+ * ispVME Embedded allows programming of Lattice's suite of FPGA
+ * devices on embedded systems through the JTAG port. The software
+ * is distributed in source code form and is open to re - distribution
+ * and modification where applicable.
+ *
+ * Revision History of ivm_core.c module:
+ * 4/25/06 ht Change some variables from unsigned short or int
+ * to long int to make the code compiler independent.
+ * 5/24/06 ht Support using RESET (TRST) pin as a special purpose
+ * control pin such as triggering the loading of known
+ * state exit.
+ * 3/6/07 ht added functions to support output to terminals
+ *
+ * 09/11/07 NN Type cast mismatch variables
+ * Moved the sclock() function to hardware.c
+ * 08/28/08 NN Added Calculate checksum support.
+ * 4/1/09 Nguyen replaced the recursive function call codes on
+ * the ispVMLCOUNT function
+ */
+
+#include <log.h>
+#include <linux/string.h>
+#include <malloc.h>
+#include <lattice.h>
+#include <vsprintf.h>
+
+#define vme_out_char(c) printf("%c", c)
+#define vme_out_hex(c) printf("%x", c)
+#define vme_out_string(s) printf("%s", s)
+
+/*
+ *
+ * Global variables used to specify the flow control and data type.
+ *
+ * g_usFlowControl: flow control register. Each bit in the
+ * register can potentially change the
+ * personality of the embedded engine.
+ * g_usDataType: holds the data type of the current row.
+ *
+ */
+
+static unsigned short g_usFlowControl;
+unsigned short g_usDataType;
+
+/*
+ *
+ * Global variables used to specify the ENDDR and ENDIR.
+ *
+ * g_ucEndDR: the state that the device goes to after SDR.
+ * g_ucEndIR: the state that the device goes to after SIR.
+ *
+ */
+
+unsigned char g_ucEndDR = DRPAUSE;
+unsigned char g_ucEndIR = IRPAUSE;
+
+/*
+ *
+ * Global variables used to support header/trailer.
+ *
+ * g_usHeadDR: the number of lead devices in bypass.
+ * g_usHeadIR: the sum of IR length of lead devices.
+ * g_usTailDR: the number of tail devices in bypass.
+ * g_usTailIR: the sum of IR length of tail devices.
+ *
+ */
+
+static unsigned short g_usHeadDR;
+static unsigned short g_usHeadIR;
+static unsigned short g_usTailDR;
+static unsigned short g_usTailIR;
+
+/*
+ *
+ * Global variable to store the number of bits of data or instruction
+ * to be shifted into or out from the device.
+ *
+ */
+
+static unsigned short g_usiDataSize;
+
+/*
+ *
+ * Stores the frequency. Default to 1 MHz.
+ *
+ */
+
+static int g_iFrequency = 1000;
+
+/*
+ *
+ * Stores the maximum amount of ram needed to hold a row of data.
+ *
+ */
+
+static unsigned short g_usMaxSize;
+
+/*
+ *
+ * Stores the LSH or RSH value.
+ *
+ */
+
+static unsigned short g_usShiftValue;
+
+/*
+ *
+ * Stores the current repeat loop value.
+ *
+ */
+
+static unsigned short g_usRepeatLoops;
+
+/*
+ *
+ * Stores the current vendor.
+ *
+ */
+
+static signed char g_cVendor = LATTICE;
+
+/*
+ *
+ * Stores the VME file CRC.
+ *
+ */
+
+unsigned short g_usCalculatedCRC;
+
+/*
+ *
+ * Stores the Device Checksum.
+ *
+ */
+/* 08/28/08 NN Added Calculate checksum support. */
+unsigned long g_usChecksum;
+static unsigned int g_uiChecksumIndex;
+
+/*
+ *
+ * Stores the current state of the JTAG state machine.
+ *
+ */
+
+static signed char g_cCurrentJTAGState;
+
+/*
+ *
+ * Global variables used to support looping.
+ *
+ * g_pucHeapMemory: holds the entire repeat loop.
+ * g_iHeapCounter: points to the current byte in the repeat loop.
+ * g_iHEAPSize: the current size of the repeat in bytes.
+ *
+ */
+
+unsigned char *g_pucHeapMemory;
+unsigned short g_iHeapCounter;
+unsigned short g_iHEAPSize;
+static unsigned short previous_size;
+
+/*
+ *
+ * Global variables used to support intelligent programming.
+ *
+ * g_usIntelDataIndex: points to the current byte of the
+ * intelligent buffer.
+ * g_usIntelBufferSize: holds the size of the intelligent
+ * buffer.
+ *
+ */
+
+unsigned short g_usIntelDataIndex;
+unsigned short g_usIntelBufferSize;
+
+/*
+ *
+ * Supported VME versions.
+ *
+ */
+
+const char *const g_szSupportedVersions[] = {
+ "__VME2.0", "__VME3.0", "____12.0", "____12.1", 0};
+
+/*
+ *
+ * Holds the maximum size of each respective buffer. These variables are used
+ * to write the HEX files when converting VME to HEX.
+ *
+*/
+
+static unsigned short g_usTDOSize;
+static unsigned short g_usMASKSize;
+static unsigned short g_usTDISize;
+static unsigned short g_usDMASKSize;
+static unsigned short g_usLCOUNTSize;
+static unsigned short g_usHDRSize;
+static unsigned short g_usTDRSize;
+static unsigned short g_usHIRSize;
+static unsigned short g_usTIRSize;
+static unsigned short g_usHeapSize;
+
+/*
+ *
+ * Global variables used to store data.
+ *
+ * g_pucOutMaskData: local RAM to hold one row of MASK data.
+ * g_pucInData: local RAM to hold one row of TDI data.
+ * g_pucOutData: local RAM to hold one row of TDO data.
+ * g_pucHIRData: local RAM to hold the current SIR header.
+ * g_pucTIRData: local RAM to hold the current SIR trailer.
+ * g_pucHDRData: local RAM to hold the current SDR header.
+ * g_pucTDRData: local RAM to hold the current SDR trailer.
+ * g_pucIntelBuffer: local RAM to hold the current intelligent buffer
+ * g_pucOutDMaskData: local RAM to hold one row of DMASK data.
+ *
+ */
+
+unsigned char *g_pucOutMaskData = NULL,
+ *g_pucInData = NULL,
+ *g_pucOutData = NULL,
+ *g_pucHIRData = NULL,
+ *g_pucTIRData = NULL,
+ *g_pucHDRData = NULL,
+ *g_pucTDRData = NULL,
+ *g_pucIntelBuffer = NULL,
+ *g_pucOutDMaskData = NULL;
+
+/*
+ *
+ * JTAG state machine transition table.
+ *
+ */
+
+struct {
+ unsigned char CurState; /* From this state */
+ unsigned char NextState; /* Step to this state */
+ unsigned char Pattern; /* The tragetory of TMS */
+ unsigned char Pulses; /* The number of steps */
+} g_JTAGTransistions[25] = {
+{ RESET, RESET, 0xFC, 6 }, /* Transitions from RESET */
+{ RESET, IDLE, 0x00, 1 },
+{ RESET, DRPAUSE, 0x50, 5 },
+{ RESET, IRPAUSE, 0x68, 6 },
+{ IDLE, RESET, 0xE0, 3 }, /* Transitions from IDLE */
+{ IDLE, DRPAUSE, 0xA0, 4 },
+{ IDLE, IRPAUSE, 0xD0, 5 },
+{ DRPAUSE, RESET, 0xF8, 5 }, /* Transitions from DRPAUSE */
+{ DRPAUSE, IDLE, 0xC0, 3 },
+{ DRPAUSE, IRPAUSE, 0xF4, 7 },
+{ DRPAUSE, DRPAUSE, 0xE8, 6 },/* 06/14/06 Support POLL STATUS LOOP*/
+{ IRPAUSE, RESET, 0xF8, 5 }, /* Transitions from IRPAUSE */
+{ IRPAUSE, IDLE, 0xC0, 3 },
+{ IRPAUSE, DRPAUSE, 0xE8, 6 },
+{ DRPAUSE, SHIFTDR, 0x80, 2 }, /* Extra transitions using SHIFTDR */
+{ IRPAUSE, SHIFTDR, 0xE0, 5 },
+{ SHIFTDR, DRPAUSE, 0x80, 2 },
+{ SHIFTDR, IDLE, 0xC0, 3 },
+{ IRPAUSE, SHIFTIR, 0x80, 2 },/* Extra transitions using SHIFTIR */
+{ SHIFTIR, IRPAUSE, 0x80, 2 },
+{ SHIFTIR, IDLE, 0xC0, 3 },
+{ DRPAUSE, DRCAPTURE, 0xE0, 4 }, /* 11/15/05 Support DRCAPTURE*/
+{ DRCAPTURE, DRPAUSE, 0x80, 2 },
+{ IDLE, DRCAPTURE, 0x80, 2 },
+{ IRPAUSE, DRCAPTURE, 0xE0, 4 }
+};
+
+/*
+ *
+ * List to hold all LVDS pairs.
+ *
+ */
+
+LVDSPair *g_pLVDSList;
+unsigned short g_usLVDSPairCount;
+
+/*
+ *
+ * Function prototypes.
+ *
+ */
+
+static signed char ispVMDataCode(void);
+static long ispVMDataSize(void);
+static void ispVMData(unsigned char *Data);
+static signed char ispVMShift(signed char Code);
+static signed char ispVMAmble(signed char Code);
+static signed char ispVMLoop(unsigned short a_usLoopCount);
+static signed char ispVMBitShift(signed char mode, unsigned short bits);
+static void ispVMComment(unsigned short a_usCommentSize);
+static void ispVMHeader(unsigned short a_usHeaderSize);
+static signed char ispVMLCOUNT(unsigned short a_usCountSize);
+static void ispVMClocks(unsigned short Clocks);
+static void ispVMBypass(signed char ScanType, unsigned short Bits);
+static void ispVMStateMachine(signed char NextState);
+static signed char ispVMSend(unsigned short int);
+static signed char ispVMRead(unsigned short int);
+static signed char ispVMReadandSave(unsigned short int);
+static signed char ispVMProcessLVDS(unsigned short a_usLVDSCount);
+static void ispVMMemManager(signed char types, unsigned short size);
+
+/*
+ *
+ * External variables and functions in hardware.c module
+ *
+ */
+static signed char g_cCurrentJTAGState;
+
+#ifdef DEBUG
+
+/*
+ *
+ * GetState
+ *
+ * Returns the state as a string based on the opcode. Only used
+ * for debugging purposes.
+ *
+ */
+
+const char *GetState(unsigned char a_ucState)
+{
+ switch (a_ucState) {
+ case RESET:
+ return "RESET";
+ case IDLE:
+ return "IDLE";
+ case IRPAUSE:
+ return "IRPAUSE";
+ case DRPAUSE:
+ return "DRPAUSE";
+ case SHIFTIR:
+ return "SHIFTIR";
+ case SHIFTDR:
+ return "SHIFTDR";
+ case DRCAPTURE:/* 11/15/05 support DRCAPTURE*/
+ return "DRCAPTURE";
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * PrintData
+ *
+ * Prints the data. Only used for debugging purposes.
+ *
+ */
+
+void PrintData(unsigned short a_iDataSize, unsigned char *a_pucData)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned short usByteSize = 0;
+ unsigned short usBitIndex = 0;
+ signed short usByteIndex = 0;
+ unsigned char ucByte = 0;
+ unsigned char ucFlipByte = 0;
+
+ if (a_iDataSize % 8) {
+ /* 09/11/07 NN Type cast mismatch variables */
+ usByteSize = (unsigned short)(a_iDataSize / 8 + 1);
+ } else {
+ /* 09/11/07 NN Type cast mismatch variables */
+ usByteSize = (unsigned short)(a_iDataSize / 8);
+ }
+ puts("(");
+ /* 09/11/07 NN Type cast mismatch variables */
+ for (usByteIndex = (signed short)(usByteSize - 1);
+ usByteIndex >= 0; usByteIndex--) {
+ ucByte = a_pucData[usByteIndex];
+ ucFlipByte = 0x00;
+
+ /*
+ *
+ * Flip each byte.
+ *
+ */
+
+ for (usBitIndex = 0; usBitIndex < 8; usBitIndex++) {
+ ucFlipByte <<= 1;
+ if (ucByte & 0x1) {
+ ucFlipByte |= 0x1;
+ }
+
+ ucByte >>= 1;
+ }
+
+ /*
+ *
+ * Print the flipped byte.
+ *
+ */
+
+ printf("%.02X", ucFlipByte);
+ if ((usByteSize - usByteIndex) % 40 == 39) {
+ puts("\n\t\t");
+ }
+ if (usByteIndex < 0)
+ break;
+ }
+ puts(")");
+}
+#endif /* DEBUG */
+
+void ispVMMemManager(signed char cTarget, unsigned short usSize)
+{
+ switch (cTarget) {
+ case XTDI:
+ case TDI:
+ if (g_pucInData != NULL) {
+ if (previous_size == usSize) {/*memory exist*/
+ break;
+ } else {
+ free(g_pucInData);
+ g_pucInData = NULL;
+ }
+ }
+ g_pucInData = (unsigned char *) malloc(usSize / 8 + 2);
+ previous_size = usSize;
+ case XTDO:
+ case TDO:
+ if (g_pucOutData != NULL) {
+ if (previous_size == usSize) { /*already exist*/
+ break;
+ } else {
+ free(g_pucOutData);
+ g_pucOutData = NULL;
+ }
+ }
+ g_pucOutData = (unsigned char *) malloc(usSize / 8 + 2);
+ previous_size = usSize;
+ break;
+ case MASK:
+ if (g_pucOutMaskData != NULL) {
+ if (previous_size == usSize) {/*already allocated*/
+ break;
+ } else {
+ free(g_pucOutMaskData);
+ g_pucOutMaskData = NULL;
+ }
+ }
+ g_pucOutMaskData = (unsigned char *) malloc(usSize / 8 + 2);
+ previous_size = usSize;
+ break;
+ case HIR:
+ if (g_pucHIRData != NULL) {
+ free(g_pucHIRData);
+ g_pucHIRData = NULL;
+ }
+ g_pucHIRData = (unsigned char *) malloc(usSize / 8 + 2);
+ break;
+ case TIR:
+ if (g_pucTIRData != NULL) {
+ free(g_pucTIRData);
+ g_pucTIRData = NULL;
+ }
+ g_pucTIRData = (unsigned char *) malloc(usSize / 8 + 2);
+ break;
+ case HDR:
+ if (g_pucHDRData != NULL) {
+ free(g_pucHDRData);
+ g_pucHDRData = NULL;
+ }
+ g_pucHDRData = (unsigned char *) malloc(usSize / 8 + 2);
+ break;
+ case TDR:
+ if (g_pucTDRData != NULL) {
+ free(g_pucTDRData);
+ g_pucTDRData = NULL;
+ }
+ g_pucTDRData = (unsigned char *) malloc(usSize / 8 + 2);
+ break;
+ case HEAP:
+ if (g_pucHeapMemory != NULL) {
+ free(g_pucHeapMemory);
+ g_pucHeapMemory = NULL;
+ }
+ g_pucHeapMemory = (unsigned char *) malloc(usSize + 2);
+ break;
+ case DMASK:
+ if (g_pucOutDMaskData != NULL) {
+ if (previous_size == usSize) { /*already allocated*/
+ break;
+ } else {
+ free(g_pucOutDMaskData);
+ g_pucOutDMaskData = NULL;
+ }
+ }
+ g_pucOutDMaskData = (unsigned char *) malloc(usSize / 8 + 2);
+ previous_size = usSize;
+ break;
+ case LHEAP:
+ if (g_pucIntelBuffer != NULL) {
+ free(g_pucIntelBuffer);
+ g_pucIntelBuffer = NULL;
+ }
+ g_pucIntelBuffer = (unsigned char *) malloc(usSize + 2);
+ break;
+ case LVDS:
+ if (g_pLVDSList != NULL) {
+ free(g_pLVDSList);
+ g_pLVDSList = NULL;
+ }
+ g_pLVDSList = (LVDSPair *) malloc(usSize * sizeof(LVDSPair));
+ if (g_pLVDSList)
+ memset(g_pLVDSList, 0, usSize * sizeof(LVDSPair));
+ break;
+ default:
+ return;
+ }
+}
+
+void ispVMFreeMem(void)
+{
+ if (g_pucHeapMemory != NULL) {
+ free(g_pucHeapMemory);
+ g_pucHeapMemory = NULL;
+ }
+
+ if (g_pucOutMaskData != NULL) {
+ free(g_pucOutMaskData);
+ g_pucOutMaskData = NULL;
+ }
+
+ if (g_pucInData != NULL) {
+ free(g_pucInData);
+ g_pucInData = NULL;
+ }
+
+ if (g_pucOutData != NULL) {
+ free(g_pucOutData);
+ g_pucOutData = NULL;
+ }
+
+ if (g_pucHIRData != NULL) {
+ free(g_pucHIRData);
+ g_pucHIRData = NULL;
+ }
+
+ if (g_pucTIRData != NULL) {
+ free(g_pucTIRData);
+ g_pucTIRData = NULL;
+ }
+
+ if (g_pucHDRData != NULL) {
+ free(g_pucHDRData);
+ g_pucHDRData = NULL;
+ }
+
+ if (g_pucTDRData != NULL) {
+ free(g_pucTDRData);
+ g_pucTDRData = NULL;
+ }
+
+ if (g_pucOutDMaskData != NULL) {
+ free(g_pucOutDMaskData);
+ g_pucOutDMaskData = NULL;
+ }
+
+ if (g_pucIntelBuffer != NULL) {
+ free(g_pucIntelBuffer);
+ g_pucIntelBuffer = NULL;
+ }
+
+ if (g_pLVDSList != NULL) {
+ free(g_pLVDSList);
+ g_pLVDSList = NULL;
+ }
+}
+
+/*
+ *
+ * ispVMDataSize
+ *
+ * Returns a VME-encoded number, usually used to indicate the
+ * bit length of an SIR/SDR command.
+ *
+ */
+
+long ispVMDataSize(void)
+{
+ /* 09/11/07 NN added local variables initialization */
+ long int iSize = 0;
+ signed char cCurrentByte = 0;
+ signed char cIndex = 0;
+ cIndex = 0;
+ while ((cCurrentByte = GetByte()) & 0x80) {
+ iSize |= ((long int) (cCurrentByte & 0x7F)) << cIndex;
+ cIndex += 7;
+ }
+ iSize |= ((long int) (cCurrentByte & 0x7F)) << cIndex;
+ return iSize;
+}
+
+/*
+ *
+ * ispVMCode
+ *
+ * This is the heart of the embedded engine. All the high-level opcodes
+ * are extracted here. Once they have been identified, then it
+ * will call other functions to handle the processing.
+ *
+ */
+
+signed char ispVMCode(void)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned short iRepeatSize = 0;
+ signed char cOpcode = 0;
+ signed char cRetCode = 0;
+ unsigned char ucState = 0;
+ unsigned short usDelay = 0;
+ unsigned short usToggle = 0;
+ unsigned char usByte = 0;
+
+ /*
+ *
+ * Check the compression flag only if this is the first time
+ * this function is entered. Do not check the compression flag if
+ * it is being called recursively from other functions within
+ * the embedded engine.
+ *
+ */
+
+ if (!(g_usDataType & LHEAP_IN) && !(g_usDataType & HEAP_IN)) {
+ usByte = GetByte();
+ if (usByte == 0xf1) {
+ g_usDataType |= COMPRESS;
+ } else if (usByte == 0xf2) {
+ g_usDataType &= ~COMPRESS;
+ } else {
+ return VME_INVALID_FILE;
+ }
+ }
+
+ /*
+ *
+ * Begin looping through all the VME opcodes.
+ *
+ */
+
+ while ((cOpcode = GetByte()) >= 0) {
+
+ switch (cOpcode) {
+ case STATE:
+
+ /*
+ * Step the JTAG state machine.
+ */
+
+ ucState = GetByte();
+
+ /*
+ * Step the JTAG state machine to DRCAPTURE
+ * to support Looping.
+ */
+
+ if ((g_usDataType & LHEAP_IN) &&
+ (ucState == DRPAUSE) &&
+ (g_cCurrentJTAGState == ucState)) {
+ ispVMStateMachine(DRCAPTURE);
+ }
+
+ ispVMStateMachine(ucState);
+
+#ifdef DEBUG
+ if (g_usDataType & LHEAP_IN) {
+ debug("LDELAY %s ", GetState(ucState));
+ } else {
+ debug("STATE %s;\n", GetState(ucState));
+ }
+#endif /* DEBUG */
+ break;
+ case SIR:
+ case SDR:
+ case XSDR:
+
+#ifdef DEBUG
+ switch (cOpcode) {
+ case SIR:
+ puts("SIR ");
+ break;
+ case SDR:
+ case XSDR:
+ if (g_usDataType & LHEAP_IN) {
+ puts("LSDR ");
+ } else {
+ puts("SDR ");
+ }
+ break;
+ }
+#endif /* DEBUG */
+ /*
+ *
+ * Shift in data into the device.
+ *
+ */
+
+ cRetCode = ispVMShift(cOpcode);
+ if (cRetCode != 0) {
+ return cRetCode;
+ }
+ break;
+ case WAIT:
+
+ /*
+ *
+ * Observe delay.
+ *
+ */
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ usDelay = (unsigned short) ispVMDataSize();
+ ispVMDelay(usDelay);
+
+#ifdef DEBUG
+ if (usDelay & 0x8000) {
+
+ /*
+ * Since MSB is set, the delay time must be
+ * decoded to millisecond. The SVF2VME encodes
+ * the MSB to represent millisecond.
+ */
+
+ usDelay &= ~0x8000;
+ if (g_usDataType & LHEAP_IN) {
+ printf("%.2E SEC;\n",
+ (float) usDelay / 1000);
+ } else {
+ printf("RUNTEST %.2E SEC;\n",
+ (float) usDelay / 1000);
+ }
+ } else {
+ /*
+ * Since MSB is not set, the delay time
+ * is given as microseconds.
+ */
+
+ if (g_usDataType & LHEAP_IN) {
+ printf("%.2E SEC;\n",
+ (float) usDelay / 1000000);
+ } else {
+ printf("RUNTEST %.2E SEC;\n",
+ (float) usDelay / 1000000);
+ }
+ }
+#endif /* DEBUG */
+ break;
+ case TCK:
+
+ /*
+ * Issue clock toggles.
+ */
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ usToggle = (unsigned short) ispVMDataSize();
+ ispVMClocks(usToggle);
+
+#ifdef DEBUG
+ printf("RUNTEST %d TCK;\n", usToggle);
+#endif /* DEBUG */
+ break;
+ case ENDDR:
+
+ /*
+ *
+ * Set the ENDDR.
+ *
+ */
+
+ g_ucEndDR = GetByte();
+
+#ifdef DEBUG
+ printf("ENDDR %s;\n", GetState(g_ucEndDR));
+#endif /* DEBUG */
+ break;
+ case ENDIR:
+
+ /*
+ *
+ * Set the ENDIR.
+ *
+ */
+
+ g_ucEndIR = GetByte();
+
+#ifdef DEBUG
+ printf("ENDIR %s;\n", GetState(g_ucEndIR));
+#endif /* DEBUG */
+ break;
+ case HIR:
+ case TIR:
+ case HDR:
+ case TDR:
+
+#ifdef DEBUG
+ switch (cOpcode) {
+ case HIR:
+ puts("HIR ");
+ break;
+ case TIR:
+ puts("TIR ");
+ break;
+ case HDR:
+ puts("HDR ");
+ break;
+ case TDR:
+ puts("TDR ");
+ break;
+ }
+#endif /* DEBUG */
+ /*
+ * Set the header/trailer of the device in order
+ * to bypass
+ * successfully.
+ */
+
+ cRetCode = ispVMAmble(cOpcode);
+ if (cRetCode != 0) {
+ return cRetCode;
+ }
+
+#ifdef DEBUG
+ puts(";\n");
+#endif /* DEBUG */
+ break;
+ case MEM:
+
+ /*
+ * The maximum RAM required to support
+ * processing one row of the VME file.
+ */
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_usMaxSize = (unsigned short) ispVMDataSize();
+
+#ifdef DEBUG
+ printf("// MEMSIZE %d\n", g_usMaxSize);
+#endif /* DEBUG */
+ break;
+ case VENDOR:
+
+ /*
+ *
+ * Set the VENDOR type.
+ *
+ */
+
+ cOpcode = GetByte();
+ switch (cOpcode) {
+ case LATTICE:
+#ifdef DEBUG
+ puts("// VENDOR LATTICE\n");
+#endif /* DEBUG */
+ g_cVendor = LATTICE;
+ break;
+ case ALTERA:
+#ifdef DEBUG
+ puts("// VENDOR ALTERA\n");
+#endif /* DEBUG */
+ g_cVendor = ALTERA;
+ break;
+ case XILINX:
+#ifdef DEBUG
+ puts("// VENDOR XILINX\n");
+#endif /* DEBUG */
+ g_cVendor = XILINX;
+ break;
+ default:
+ break;
+ }
+ break;
+ case SETFLOW:
+
+ /*
+ * Set the flow control. Flow control determines
+ * the personality of the embedded engine.
+ */
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_usFlowControl |= (unsigned short) ispVMDataSize();
+ break;
+ case RESETFLOW:
+
+ /*
+ *
+ * Unset the flow control.
+ *
+ */
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_usFlowControl &= (unsigned short) ~(ispVMDataSize());
+ break;
+ case HEAP:
+
+ /*
+ *
+ * Allocate heap size to store loops.
+ *
+ */
+
+ cRetCode = GetByte();
+ if (cRetCode != SECUREHEAP) {
+ return VME_INVALID_FILE;
+ }
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_iHEAPSize = (unsigned short) ispVMDataSize();
+
+ /*
+ * Store the maximum size of the HEAP buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_iHEAPSize > g_usHeapSize) {
+ g_usHeapSize = g_iHEAPSize;
+ }
+
+ ispVMMemManager(HEAP, (unsigned short) g_iHEAPSize);
+ break;
+ case REPEAT:
+
+ /*
+ *
+ * Execute loops.
+ *
+ */
+
+ g_usRepeatLoops = 0;
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ iRepeatSize = (unsigned short) ispVMDataSize();
+
+ cRetCode = ispVMLoop((unsigned short) iRepeatSize);
+ if (cRetCode != 0) {
+ return cRetCode;
+ }
+ break;
+ case ENDLOOP:
+
+ /*
+ *
+ * Exit point from processing loops.
+ *
+ */
+
+ return cRetCode;
+ case ENDVME:
+
+ /*
+ * The only valid exit point that indicates
+ * end of programming.
+ */
+
+ return cRetCode;
+ case SHR:
+
+ /*
+ *
+ * Right-shift address.
+ *
+ */
+
+ g_usFlowControl |= SHIFTRIGHT;
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_usShiftValue = (unsigned short) (g_usRepeatLoops *
+ (unsigned short)GetByte());
+ break;
+ case SHL:
+
+ /*
+ * Left-shift address.
+ */
+
+ g_usFlowControl |= SHIFTLEFT;
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_usShiftValue = (unsigned short) (g_usRepeatLoops *
+ (unsigned short)GetByte());
+ break;
+ case FREQUENCY:
+
+ /*
+ *
+ * Set the frequency.
+ *
+ */
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_iFrequency = (int) (ispVMDataSize() / 1000);
+ if (g_iFrequency == 1)
+ g_iFrequency = 1000;
+
+#ifdef DEBUG
+ printf("FREQUENCY %.2E HZ;\n",
+ (float) g_iFrequency * 1000);
+#endif /* DEBUG */
+ break;
+ case LCOUNT:
+
+ /*
+ *
+ * Process LCOUNT command.
+ *
+ */
+
+ cRetCode = ispVMLCOUNT((unsigned short)ispVMDataSize());
+ if (cRetCode != 0) {
+ return cRetCode;
+ }
+ break;
+ case VUES:
+
+ /*
+ *
+ * Set the flow control to verify USERCODE.
+ *
+ */
+
+ g_usFlowControl |= VERIFYUES;
+ break;
+ case COMMENT:
+
+ /*
+ *
+ * Display comment.
+ *
+ */
+
+ ispVMComment((unsigned short) ispVMDataSize());
+ break;
+ case LVDS:
+
+ /*
+ *
+ * Process LVDS command.
+ *
+ */
+
+ ispVMProcessLVDS((unsigned short) ispVMDataSize());
+ break;
+ case HEADER:
+
+ /*
+ *
+ * Discard header.
+ *
+ */
+
+ ispVMHeader((unsigned short) ispVMDataSize());
+ break;
+ /* 03/14/06 Support Toggle ispENABLE signal*/
+ case ispEN:
+ ucState = GetByte();
+ if ((ucState == ON) || (ucState == 0x01))
+ writePort(g_ucPinENABLE, 0x01);
+ else
+ writePort(g_ucPinENABLE, 0x00);
+ ispVMDelay(1);
+ break;
+ /* 05/24/06 support Toggle TRST pin*/
+ case TRST:
+ ucState = GetByte();
+ if (ucState == 0x01)
+ writePort(g_ucPinTRST, 0x01);
+ else
+ writePort(g_ucPinTRST, 0x00);
+ ispVMDelay(1);
+ break;
+ default:
+
+ /*
+ *
+ * Invalid opcode encountered.
+ *
+ */
+
+#ifdef DEBUG
+ printf("\nINVALID OPCODE: 0x%.2X\n", cOpcode);
+#endif /* DEBUG */
+
+ return VME_INVALID_FILE;
+ }
+ }
+
+ /*
+ *
+ * Invalid exit point. Processing the token 'ENDVME' is the only
+ * valid way to exit the embedded engine.
+ *
+ */
+
+ return VME_INVALID_FILE;
+}
+
+/*
+ *
+ * ispVMDataCode
+ *
+ * Processes the TDI/TDO/MASK/DMASK etc of an SIR/SDR command.
+ *
+ */
+
+signed char ispVMDataCode(void)
+{
+ /* 09/11/07 NN added local variables initialization */
+ signed char cDataByte = 0;
+ signed char siDataSource = 0; /*source of data from file by default*/
+
+ if (g_usDataType & HEAP_IN) {
+ siDataSource = 1; /*the source of data from memory*/
+ }
+
+ /*
+ *
+ * Clear the data type register.
+ *
+ **/
+
+ g_usDataType &= ~(MASK_DATA + TDI_DATA +
+ TDO_DATA + DMASK_DATA + CMASK_DATA);
+
+ /*
+ * Iterate through SIR/SDR command and look for TDI,
+ * TDO, MASK, etc.
+ */
+
+ while ((cDataByte = GetByte()) >= 0) {
+ ispVMMemManager(cDataByte, g_usMaxSize);
+ switch (cDataByte) {
+ case TDI:
+
+ /*
+ * Store the maximum size of the TDI buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usiDataSize > g_usTDISize) {
+ g_usTDISize = g_usiDataSize;
+ }
+ /*
+ * Updated data type register to indicate that
+ * TDI data is currently being used. Process the
+ * data in the VME file into the TDI buffer.
+ */
+
+ g_usDataType |= TDI_DATA;
+ ispVMData(g_pucInData);
+ break;
+ case XTDO:
+
+ /*
+ * Store the maximum size of the TDO buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usiDataSize > g_usTDOSize) {
+ g_usTDOSize = g_usiDataSize;
+ }
+
+ /*
+ * Updated data type register to indicate that
+ * TDO data is currently being used.
+ */
+
+ g_usDataType |= TDO_DATA;
+ break;
+ case TDO:
+
+ /*
+ * Store the maximum size of the TDO buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usiDataSize > g_usTDOSize) {
+ g_usTDOSize = g_usiDataSize;
+ }
+
+ /*
+ * Updated data type register to indicate
+ * that TDO data is currently being used.
+ * Process the data in the VME file into the
+ * TDO buffer.
+ */
+
+ g_usDataType |= TDO_DATA;
+ ispVMData(g_pucOutData);
+ break;
+ case MASK:
+
+ /*
+ * Store the maximum size of the MASK buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usiDataSize > g_usMASKSize) {
+ g_usMASKSize = g_usiDataSize;
+ }
+
+ /*
+ * Updated data type register to indicate that
+ * MASK data is currently being used. Process
+ * the data in the VME file into the MASK buffer
+ */
+
+ g_usDataType |= MASK_DATA;
+ ispVMData(g_pucOutMaskData);
+ break;
+ case DMASK:
+
+ /*
+ * Store the maximum size of the DMASK buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usiDataSize > g_usDMASKSize) {
+ g_usDMASKSize = g_usiDataSize;
+ }
+
+ /*
+ * Updated data type register to indicate that
+ * DMASK data is currently being used. Process
+ * the data in the VME file into the DMASK
+ * buffer.
+ */
+
+ g_usDataType |= DMASK_DATA;
+ ispVMData(g_pucOutDMaskData);
+ break;
+ case CMASK:
+
+ /*
+ * Updated data type register to indicate that
+ * MASK data is currently being used. Process
+ * the data in the VME file into the MASK buffer
+ */
+
+ g_usDataType |= CMASK_DATA;
+ ispVMData(g_pucOutMaskData);
+ break;
+ case CONTINUE:
+ return 0;
+ default:
+ /*
+ * Encountered invalid opcode.
+ */
+ return VME_INVALID_FILE;
+ }
+
+ switch (cDataByte) {
+ case TDI:
+
+ /*
+ * Left bit shift. Used when performing
+ * algorithm looping.
+ */
+
+ if (g_usFlowControl & SHIFTLEFT) {
+ ispVMBitShift(SHL, g_usShiftValue);
+ g_usFlowControl &= ~SHIFTLEFT;
+ }
+
+ /*
+ * Right bit shift. Used when performing
+ * algorithm looping.
+ */
+
+ if (g_usFlowControl & SHIFTRIGHT) {
+ ispVMBitShift(SHR, g_usShiftValue);
+ g_usFlowControl &= ~SHIFTRIGHT;
+ }
+ default:
+ break;
+ }
+
+ if (siDataSource) {
+ g_usDataType |= HEAP_IN; /*restore from memory*/
+ }
+ }
+
+ if (siDataSource) { /*fetch data from heap memory upon return*/
+ g_usDataType |= HEAP_IN;
+ }
+
+ if (cDataByte < 0) {
+
+ /*
+ * Encountered invalid opcode.
+ */
+
+ return VME_INVALID_FILE;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ *
+ * ispVMData
+ * Extract one row of data operand from the current data type opcode. Perform
+ * the decompression if necessary. Extra RAM is not required for the
+ * decompression process. The decompression scheme employed in this module
+ * is on row by row basis. The format of the data stream:
+ * [compression code][compressed data stream]
+ * 0x00 --No compression
+ * 0x01 --Compress by 0x00.
+ * Example:
+ * Original stream: 0x000000000000000000000001
+ * Compressed stream: 0x01000901
+ * Detail: 0x01 is the code, 0x00 is the key,
+ * 0x09 is the count of 0x00 bytes,
+ * 0x01 is the uncompressed byte.
+ * 0x02 --Compress by 0xFF.
+ * Example:
+ * Original stream: 0xFFFFFFFFFFFFFFFFFFFFFF01
+ * Compressed stream: 0x02FF0901
+ * Detail: 0x02 is the code, 0xFF is the key,
+ * 0x09 is the count of 0xFF bytes,
+ * 0x01 is the uncompressed byte.
+ * 0x03
+ * : :
+ * 0xFE -- Compress by nibble blocks.
+ * Example:
+ * Original stream: 0x84210842108421084210
+ * Compressed stream: 0x0584210
+ * Detail: 0x05 is the code, means 5 nibbles block.
+ * 0x84210 is the 5 nibble blocks.
+ * The whole row is 80 bits given by g_usiDataSize.
+ * The number of times the block repeat itself
+ * is found by g_usiDataSize/(4*0x05) which is 4.
+ * 0xFF -- Compress by the most frequently happen byte.
+ * Example:
+ * Original stream: 0x04020401030904040404
+ * Compressed stream: 0xFF04(0,1,0x02,0,1,0x01,1,0x03,1,0x09,0,0,0)
+ * or: 0xFF044090181C240
+ * Detail: 0xFF is the code, 0x04 is the key.
+ * a bit of 0 represent the key shall be put into
+ * the current bit position and a bit of 1
+ * represent copying the next of 8 bits of data
+ * in.
+ *
+ */
+
+void ispVMData(unsigned char *ByteData)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned short size = 0;
+ unsigned short i, j, m, getData = 0;
+ unsigned char cDataByte = 0;
+ unsigned char compress = 0;
+ unsigned short FFcount = 0;
+ unsigned char compr_char = 0xFF;
+ unsigned short index = 0;
+ signed char compression = 0;
+
+ /*convert number in bits to bytes*/
+ if (g_usiDataSize % 8 > 0) {
+ /* 09/11/07 NN Type cast mismatch variables */
+ size = (unsigned short)(g_usiDataSize / 8 + 1);
+ } else {
+ /* 09/11/07 NN Type cast mismatch variables */
+ size = (unsigned short)(g_usiDataSize / 8);
+ }
+
+ /*
+ * If there is compression, then check if compress by key
+ * of 0x00 or 0xFF or by other keys or by nibble blocks
+ */
+
+ if (g_usDataType & COMPRESS) {
+ compression = 1;
+ compress = GetByte();
+ if ((compress == VAR) && (g_usDataType & HEAP_IN)) {
+ getData = 1;
+ g_usDataType &= ~(HEAP_IN);
+ compress = GetByte();
+ }
+
+ switch (compress) {
+ case 0x00:
+ /* No compression */
+ compression = 0;
+ break;
+ case 0x01:
+ /* Compress by byte 0x00 */
+ compr_char = 0x00;
+ break;
+ case 0x02:
+ /* Compress by byte 0xFF */
+ compr_char = 0xFF;
+ break;
+ case 0xFF:
+ /* Huffman encoding */
+ compr_char = GetByte();
+ i = 8;
+ for (index = 0; index < size; index++) {
+ ByteData[index] = 0x00;
+ if (i > 7) {
+ cDataByte = GetByte();
+ i = 0;
+ }
+ if ((cDataByte << i++) & 0x80)
+ m = 8;
+ else {
+ ByteData[index] = compr_char;
+ m = 0;
+ }
+
+ for (j = 0; j < m; j++) {
+ if (i > 7) {
+ cDataByte = GetByte();
+ i = 0;
+ }
+ ByteData[index] |=
+ ((cDataByte << i++) & 0x80) >> j;
+ }
+ }
+ size = 0;
+ break;
+ default:
+ for (index = 0; index < size; index++)
+ ByteData[index] = 0x00;
+ for (index = 0; index < compress; index++) {
+ if (index % 2 == 0)
+ cDataByte = GetByte();
+ for (i = 0; i < size * 2 / compress; i++) {
+ j = (unsigned short)(index +
+ (i * (unsigned short)compress));
+ /*clear the nibble to zero first*/
+ if (j%2) {
+ if (index % 2)
+ ByteData[j/2] |=
+ cDataByte & 0xF;
+ else
+ ByteData[j/2] |=
+ cDataByte >> 4;
+ } else {
+ if (index % 2)
+ ByteData[j/2] |=
+ cDataByte << 4;
+ else
+ ByteData[j/2] |=
+ cDataByte & 0xF0;
+ }
+ }
+ }
+ size = 0;
+ break;
+ }
+ }
+
+ FFcount = 0;
+
+ /* Decompress by byte 0x00 or 0xFF */
+ for (index = 0; index < size; index++) {
+ if (FFcount <= 0) {
+ cDataByte = GetByte();
+ if ((cDataByte == VAR) && (g_usDataType&HEAP_IN) &&
+ !getData && !(g_usDataType&COMPRESS)) {
+ getData = 1;
+ g_usDataType &= ~(HEAP_IN);
+ cDataByte = GetByte();
+ }
+ ByteData[index] = cDataByte;
+ if ((compression) && (cDataByte == compr_char))
+ /* 09/11/07 NN Type cast mismatch variables */
+ FFcount = (unsigned short) ispVMDataSize();
+ /*The number of 0xFF or 0x00 bytes*/
+ } else {
+ FFcount--; /*Use up the 0xFF chain first*/
+ ByteData[index] = compr_char;
+ }
+ }
+
+ if (getData) {
+ g_usDataType |= HEAP_IN;
+ getData = 0;
+ }
+}
+
+/*
+ *
+ * ispVMShift
+ *
+ * Processes the SDR/XSDR/SIR commands.
+ *
+ */
+
+signed char ispVMShift(signed char a_cCode)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned short iDataIndex = 0;
+ unsigned short iReadLoop = 0;
+ signed char cRetCode = 0;
+
+ cRetCode = 0;
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_usiDataSize = (unsigned short) ispVMDataSize();
+
+ /*clear the flags first*/
+ g_usDataType &= ~(SIR_DATA + EXPRESS + SDR_DATA);
+ switch (a_cCode) {
+ case SIR:
+ g_usDataType |= SIR_DATA;
+ /*
+ * 1/15/04 If performing cascading, then go directly to SHIFTIR.
+ * Else, go to IRPAUSE before going to SHIFTIR
+ */
+ if (g_usFlowControl & CASCADE) {
+ ispVMStateMachine(SHIFTIR);
+ } else {
+ ispVMStateMachine(IRPAUSE);
+ ispVMStateMachine(SHIFTIR);
+ if (g_usHeadIR > 0) {
+ ispVMBypass(HIR, g_usHeadIR);
+ sclock();
+ }
+ }
+ break;
+ case XSDR:
+ g_usDataType |= EXPRESS; /*mark simultaneous in and out*/
+ case SDR:
+ g_usDataType |= SDR_DATA;
+ /*
+ * 1/15/04 If already in SHIFTDR, then do not move state or
+ * shift in header. This would imply that the previously
+ * shifted frame was a cascaded frame.
+ */
+ if (g_cCurrentJTAGState != SHIFTDR) {
+ /*
+ * 1/15/04 If performing cascading, then go directly
+ * to SHIFTDR. Else, go to DRPAUSE before going
+ * to SHIFTDR
+ */
+ if (g_usFlowControl & CASCADE) {
+ if (g_cCurrentJTAGState == DRPAUSE) {
+ ispVMStateMachine(SHIFTDR);
+ /*
+ * 1/15/04 If cascade flag has been seat
+ * and the current state is DRPAUSE,
+ * this implies that the first cascaded
+ * frame is about to be shifted in. The
+ * header must be shifted prior to
+ * shifting the first cascaded frame.
+ */
+ if (g_usHeadDR > 0) {
+ ispVMBypass(HDR, g_usHeadDR);
+ sclock();
+ }
+ } else {
+ ispVMStateMachine(SHIFTDR);
+ }
+ } else {
+ ispVMStateMachine(DRPAUSE);
+ ispVMStateMachine(SHIFTDR);
+ if (g_usHeadDR > 0) {
+ ispVMBypass(HDR, g_usHeadDR);
+ sclock();
+ }
+ }
+ }
+ break;
+ default:
+ return VME_INVALID_FILE;
+ }
+
+ cRetCode = ispVMDataCode();
+
+ if (cRetCode != 0) {
+ return VME_INVALID_FILE;
+ }
+
+#ifdef DEBUG
+ printf("%d ", g_usiDataSize);
+
+ if (g_usDataType & TDI_DATA) {
+ puts("TDI ");
+ PrintData(g_usiDataSize, g_pucInData);
+ }
+
+ if (g_usDataType & TDO_DATA) {
+ puts("\n\t\tTDO ");
+ PrintData(g_usiDataSize, g_pucOutData);
+ }
+
+ if (g_usDataType & MASK_DATA) {
+ puts("\n\t\tMASK ");
+ PrintData(g_usiDataSize, g_pucOutMaskData);
+ }
+
+ if (g_usDataType & DMASK_DATA) {
+ puts("\n\t\tDMASK ");
+ PrintData(g_usiDataSize, g_pucOutDMaskData);
+ }
+
+ puts(";\n");
+#endif /* DEBUG */
+
+ if (g_usDataType & TDO_DATA || g_usDataType & DMASK_DATA) {
+ if (g_usDataType & DMASK_DATA) {
+ cRetCode = ispVMReadandSave(g_usiDataSize);
+ if (!cRetCode) {
+ if (g_usTailDR > 0) {
+ sclock();
+ ispVMBypass(TDR, g_usTailDR);
+ }
+ ispVMStateMachine(DRPAUSE);
+ ispVMStateMachine(SHIFTDR);
+ if (g_usHeadDR > 0) {
+ ispVMBypass(HDR, g_usHeadDR);
+ sclock();
+ }
+ for (iDataIndex = 0;
+ iDataIndex < g_usiDataSize / 8 + 1;
+ iDataIndex++)
+ g_pucInData[iDataIndex] =
+ g_pucOutData[iDataIndex];
+ g_usDataType &= ~(TDO_DATA + DMASK_DATA);
+ cRetCode = ispVMSend(g_usiDataSize);
+ }
+ } else {
+ cRetCode = ispVMRead(g_usiDataSize);
+ if (cRetCode == -1 && g_cVendor == XILINX) {
+ for (iReadLoop = 0; iReadLoop < 30;
+ iReadLoop++) {
+ cRetCode = ispVMRead(g_usiDataSize);
+ if (!cRetCode) {
+ break;
+ } else {
+ /* Always DRPAUSE */
+ ispVMStateMachine(DRPAUSE);
+ /*
+ * Bypass other devices
+ * when appropriate
+ */
+ ispVMBypass(TDR, g_usTailDR);
+ ispVMStateMachine(g_ucEndDR);
+ ispVMStateMachine(IDLE);
+ ispVMDelay(1000);
+ }
+ }
+ }
+ }
+ } else { /*TDI only*/
+ cRetCode = ispVMSend(g_usiDataSize);
+ }
+
+ /*transfer the input data to the output buffer for the next verify*/
+ if ((g_usDataType & EXPRESS) || (a_cCode == SDR)) {
+ if (g_pucOutData) {
+ for (iDataIndex = 0; iDataIndex < g_usiDataSize / 8 + 1;
+ iDataIndex++)
+ g_pucOutData[iDataIndex] =
+ g_pucInData[iDataIndex];
+ }
+ }
+
+ switch (a_cCode) {
+ case SIR:
+ /* 1/15/04 If not performing cascading, then shift ENDIR */
+ if (!(g_usFlowControl & CASCADE)) {
+ if (g_usTailIR > 0) {
+ sclock();
+ ispVMBypass(TIR, g_usTailIR);
+ }
+ ispVMStateMachine(g_ucEndIR);
+ }
+ break;
+ case XSDR:
+ case SDR:
+ /* 1/15/04 If not performing cascading, then shift ENDDR */
+ if (!(g_usFlowControl & CASCADE)) {
+ if (g_usTailDR > 0) {
+ sclock();
+ ispVMBypass(TDR, g_usTailDR);
+ }
+ ispVMStateMachine(g_ucEndDR);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return cRetCode;
+}
+
+/*
+ *
+ * ispVMAmble
+ *
+ * This routine is to extract Header and Trailer parameter for SIR and
+ * SDR operations.
+ *
+ * The Header and Trailer parameter are the pre-amble and post-amble bit
+ * stream need to be shifted into TDI or out of TDO of the devices. Mostly
+ * is for the purpose of bypassing the leading or trailing devices. ispVM
+ * supports only shifting data into TDI to bypass the devices.
+ *
+ * For a single device, the header and trailer parameters are all set to 0
+ * as default by ispVM. If it is for multiple devices, the header and trailer
+ * value will change as specified by the VME file.
+ *
+ */
+
+signed char ispVMAmble(signed char Code)
+{
+ signed char compress = 0;
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_usiDataSize = (unsigned short)ispVMDataSize();
+
+#ifdef DEBUG
+ printf("%d", g_usiDataSize);
+#endif /* DEBUG */
+
+ if (g_usiDataSize) {
+
+ /*
+ * Discard the TDI byte and set the compression bit in the data
+ * type register to false if compression is set because TDI data
+ * after HIR/HDR/TIR/TDR is not compressed.
+ */
+
+ GetByte();
+ if (g_usDataType & COMPRESS) {
+ g_usDataType &= ~(COMPRESS);
+ compress = 1;
+ }
+ }
+
+ switch (Code) {
+ case HIR:
+
+ /*
+ * Store the maximum size of the HIR buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usiDataSize > g_usHIRSize) {
+ g_usHIRSize = g_usiDataSize;
+ }
+
+ /*
+ * Assign the HIR value and allocate memory.
+ */
+
+ g_usHeadIR = g_usiDataSize;
+ if (g_usHeadIR) {
+ ispVMMemManager(HIR, g_usHeadIR);
+ ispVMData(g_pucHIRData);
+
+#ifdef DEBUG
+ puts(" TDI ");
+ PrintData(g_usHeadIR, g_pucHIRData);
+#endif /* DEBUG */
+ }
+ break;
+ case TIR:
+
+ /*
+ * Store the maximum size of the TIR buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usiDataSize > g_usTIRSize) {
+ g_usTIRSize = g_usiDataSize;
+ }
+
+ /*
+ * Assign the TIR value and allocate memory.
+ */
+
+ g_usTailIR = g_usiDataSize;
+ if (g_usTailIR) {
+ ispVMMemManager(TIR, g_usTailIR);
+ ispVMData(g_pucTIRData);
+
+#ifdef DEBUG
+ puts(" TDI ");
+ PrintData(g_usTailIR, g_pucTIRData);
+#endif /* DEBUG */
+ }
+ break;
+ case HDR:
+
+ /*
+ * Store the maximum size of the HDR buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usiDataSize > g_usHDRSize) {
+ g_usHDRSize = g_usiDataSize;
+ }
+
+ /*
+ * Assign the HDR value and allocate memory.
+ *
+ */
+
+ g_usHeadDR = g_usiDataSize;
+ if (g_usHeadDR) {
+ ispVMMemManager(HDR, g_usHeadDR);
+ ispVMData(g_pucHDRData);
+
+#ifdef DEBUG
+ puts(" TDI ");
+ PrintData(g_usHeadDR, g_pucHDRData);
+#endif /* DEBUG */
+ }
+ break;
+ case TDR:
+
+ /*
+ * Store the maximum size of the TDR buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usiDataSize > g_usTDRSize) {
+ g_usTDRSize = g_usiDataSize;
+ }
+
+ /*
+ * Assign the TDR value and allocate memory.
+ *
+ */
+
+ g_usTailDR = g_usiDataSize;
+ if (g_usTailDR) {
+ ispVMMemManager(TDR, g_usTailDR);
+ ispVMData(g_pucTDRData);
+
+#ifdef DEBUG
+ puts(" TDI ");
+ PrintData(g_usTailDR, g_pucTDRData);
+#endif /* DEBUG */
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ *
+ * Re-enable compression if it was previously set.
+ *
+ **/
+
+ if (compress) {
+ g_usDataType |= COMPRESS;
+ }
+
+ if (g_usiDataSize) {
+ Code = GetByte();
+ if (Code == CONTINUE) {
+ return 0;
+ } else {
+
+ /*
+ * Encountered invalid opcode.
+ */
+
+ return VME_INVALID_FILE;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * ispVMLoop
+ *
+ * Perform the function call upon by the REPEAT opcode.
+ * Memory is to be allocated to store the entire loop from REPEAT to ENDLOOP.
+ * After the loop is stored then execution begin. The REPEATLOOP flag is set
+ * on the g_usFlowControl register to indicate the repeat loop is in session
+ * and therefore fetch opcode from the memory instead of from the file.
+ *
+ */
+
+signed char ispVMLoop(unsigned short a_usLoopCount)
+{
+ /* 09/11/07 NN added local variables initialization */
+ signed char cRetCode = 0;
+ unsigned short iHeapIndex = 0;
+ unsigned short iLoopIndex = 0;
+
+ g_usShiftValue = 0;
+ for (iHeapIndex = 0; iHeapIndex < g_iHEAPSize; iHeapIndex++) {
+ g_pucHeapMemory[iHeapIndex] = GetByte();
+ }
+
+ if (g_pucHeapMemory[iHeapIndex - 1] != ENDLOOP) {
+ return VME_INVALID_FILE;
+ }
+
+ g_usFlowControl |= REPEATLOOP;
+ g_usDataType |= HEAP_IN;
+
+ for (iLoopIndex = 0; iLoopIndex < a_usLoopCount; iLoopIndex++) {
+ g_iHeapCounter = 0;
+ cRetCode = ispVMCode();
+ g_usRepeatLoops++;
+ if (cRetCode < 0) {
+ break;
+ }
+ }
+
+ g_usDataType &= ~(HEAP_IN);
+ g_usFlowControl &= ~(REPEATLOOP);
+ return cRetCode;
+}
+
+/*
+ *
+ * ispVMBitShift
+ *
+ * Shift the TDI stream left or right by the number of bits. The data in
+ * *g_pucInData is of the VME format, so the actual shifting is the reverse of
+ * IEEE 1532 or SVF format.
+ *
+ */
+
+signed char ispVMBitShift(signed char mode, unsigned short bits)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned short i = 0;
+ unsigned short size = 0;
+ unsigned short tmpbits = 0;
+
+ if (g_usiDataSize % 8 > 0) {
+ /* 09/11/07 NN Type cast mismatch variables */
+ size = (unsigned short)(g_usiDataSize / 8 + 1);
+ } else {
+ /* 09/11/07 NN Type cast mismatch variables */
+ size = (unsigned short)(g_usiDataSize / 8);
+ }
+
+ switch (mode) {
+ case SHR:
+ for (i = 0; i < size; i++) {
+ if (g_pucInData[i] != 0) {
+ tmpbits = bits;
+ while (tmpbits > 0) {
+ g_pucInData[i] <<= 1;
+ if (g_pucInData[i] == 0) {
+ i--;
+ g_pucInData[i] = 1;
+ }
+ tmpbits--;
+ }
+ }
+ }
+ break;
+ case SHL:
+ for (i = 0; i < size; i++) {
+ if (g_pucInData[i] != 0) {
+ tmpbits = bits;
+ while (tmpbits > 0) {
+ g_pucInData[i] >>= 1;
+ if (g_pucInData[i] == 0) {
+ i--;
+ g_pucInData[i] = 8;
+ }
+ tmpbits--;
+ }
+ }
+ }
+ break;
+ default:
+ return VME_INVALID_FILE;
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * ispVMComment
+ *
+ * Displays the SVF comments.
+ *
+ */
+
+void ispVMComment(unsigned short a_usCommentSize)
+{
+ char cCurByte = 0;
+ for (; a_usCommentSize > 0; a_usCommentSize--) {
+ /*
+ *
+ * Print character to the terminal.
+ *
+ **/
+ cCurByte = GetByte();
+ vme_out_char(cCurByte);
+ }
+ cCurByte = '\n';
+ vme_out_char(cCurByte);
+}
+
+/*
+ *
+ * ispVMHeader
+ *
+ * Iterate the length of the header and discard it.
+ *
+ */
+
+void ispVMHeader(unsigned short a_usHeaderSize)
+{
+ for (; a_usHeaderSize > 0; a_usHeaderSize--) {
+ GetByte();
+ }
+}
+
+/*
+ *
+ * ispVMCalculateCRC32
+ *
+ * Calculate the 32-bit CRC.
+ *
+ */
+
+void ispVMCalculateCRC32(unsigned char a_ucData)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned char ucIndex = 0;
+ unsigned char ucFlipData = 0;
+ unsigned short usCRCTableEntry = 0;
+ unsigned int crc_table[16] = {
+ 0x0000, 0xCC01, 0xD801,
+ 0x1400, 0xF001, 0x3C00,
+ 0x2800, 0xE401, 0xA001,
+ 0x6C00, 0x7800, 0xB401,
+ 0x5000, 0x9C01, 0x8801,
+ 0x4400
+ };
+
+ for (ucIndex = 0; ucIndex < 8; ucIndex++) {
+ ucFlipData <<= 1;
+ if (a_ucData & 0x01) {
+ ucFlipData |= 0x01;
+ }
+ a_ucData >>= 1;
+ }
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ usCRCTableEntry = (unsigned short)(crc_table[g_usCalculatedCRC & 0xF]);
+ g_usCalculatedCRC = (unsigned short)((g_usCalculatedCRC >> 4) & 0x0FFF);
+ g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^
+ usCRCTableEntry ^ crc_table[ucFlipData & 0xF]);
+ usCRCTableEntry = (unsigned short)(crc_table[g_usCalculatedCRC & 0xF]);
+ g_usCalculatedCRC = (unsigned short)((g_usCalculatedCRC >> 4) & 0x0FFF);
+ g_usCalculatedCRC = (unsigned short)(g_usCalculatedCRC ^
+ usCRCTableEntry ^ crc_table[(ucFlipData >> 4) & 0xF]);
+}
+
+/*
+ *
+ * ispVMLCOUNT
+ *
+ * Process the intelligent programming loops.
+ *
+ */
+
+signed char ispVMLCOUNT(unsigned short a_usCountSize)
+{
+ unsigned short usContinue = 1;
+ unsigned short usIntelBufferIndex = 0;
+ unsigned short usCountIndex = 0;
+ signed char cRetCode = 0;
+ signed char cRepeatHeap = 0;
+ signed char cOpcode = 0;
+ unsigned char ucState = 0;
+ unsigned short usDelay = 0;
+ unsigned short usToggle = 0;
+
+ g_usIntelBufferSize = (unsigned short)ispVMDataSize();
+
+ /*
+ * Allocate memory for intel buffer.
+ *
+ */
+
+ ispVMMemManager(LHEAP, g_usIntelBufferSize);
+
+ /*
+ * Store the maximum size of the intelligent buffer.
+ * Used to convert VME to HEX.
+ */
+
+ if (g_usIntelBufferSize > g_usLCOUNTSize) {
+ g_usLCOUNTSize = g_usIntelBufferSize;
+ }
+
+ /*
+ * Copy intel data to the buffer.
+ */
+
+ for (usIntelBufferIndex = 0; usIntelBufferIndex < g_usIntelBufferSize;
+ usIntelBufferIndex++) {
+ g_pucIntelBuffer[usIntelBufferIndex] = GetByte();
+ }
+
+ /*
+ * Set the data type register to get data from the intelligent
+ * data buffer.
+ */
+
+ g_usDataType |= LHEAP_IN;
+
+ /*
+ *
+ * If the HEAP_IN flag is set, temporarily unset the flag so data will be
+ * retrieved from the status buffer.
+ *
+ **/
+
+ if (g_usDataType & HEAP_IN) {
+ g_usDataType &= ~HEAP_IN;
+ cRepeatHeap = 1;
+ }
+
+#ifdef DEBUG
+ printf("LCOUNT %d;\n", a_usCountSize);
+#endif /* DEBUG */
+
+ /*
+ * Iterate through the intelligent programming command.
+ */
+
+ for (usCountIndex = 0; usCountIndex < a_usCountSize; usCountIndex++) {
+
+ /*
+ *
+ * Initialize the intel data index to 0 before each iteration.
+ *
+ **/
+
+ g_usIntelDataIndex = 0;
+ cOpcode = 0;
+ ucState = 0;
+ usDelay = 0;
+ usToggle = 0;
+ usContinue = 1;
+
+ /*
+ *
+ * Begin looping through all the VME opcodes.
+ *
+ */
+ /*
+ * 4/1/09 Nguyen replaced the recursive function call codes on
+ * the ispVMLCOUNT function
+ *
+ */
+ while (usContinue) {
+ cOpcode = GetByte();
+ switch (cOpcode) {
+ case HIR:
+ case TIR:
+ case HDR:
+ case TDR:
+ /*
+ * Set the header/trailer of the device in order
+ * to bypass successfully.
+ */
+
+ ispVMAmble(cOpcode);
+ break;
+ case STATE:
+
+ /*
+ * Step the JTAG state machine.
+ */
+
+ ucState = GetByte();
+ /*
+ * Step the JTAG state machine to DRCAPTURE
+ * to support Looping.
+ */
+
+ if ((g_usDataType & LHEAP_IN) &&
+ (ucState == DRPAUSE) &&
+ (g_cCurrentJTAGState == ucState)) {
+ ispVMStateMachine(DRCAPTURE);
+ }
+ ispVMStateMachine(ucState);
+#ifdef DEBUG
+ printf("LDELAY %s ", GetState(ucState));
+#endif /* DEBUG */
+ break;
+ case SIR:
+#ifdef DEBUG
+ printf("SIR ");
+#endif /* DEBUG */
+ /*
+ * Shift in data into the device.
+ */
+
+ cRetCode = ispVMShift(cOpcode);
+ break;
+ case SDR:
+
+#ifdef DEBUG
+ printf("LSDR ");
+#endif /* DEBUG */
+ /*
+ * Shift in data into the device.
+ */
+
+ cRetCode = ispVMShift(cOpcode);
+ break;
+ case WAIT:
+
+ /*
+ *
+ * Observe delay.
+ *
+ */
+
+ usDelay = (unsigned short)ispVMDataSize();
+ ispVMDelay(usDelay);
+
+#ifdef DEBUG
+ if (usDelay & 0x8000) {
+
+ /*
+ * Since MSB is set, the delay time must
+ * be decoded to millisecond. The
+ * SVF2VME encodes the MSB to represent
+ * millisecond.
+ */
+
+ usDelay &= ~0x8000;
+ printf("%.2E SEC;\n",
+ (float) usDelay / 1000);
+ } else {
+ /*
+ * Since MSB is not set, the delay time
+ * is given as microseconds.
+ */
+
+ printf("%.2E SEC;\n",
+ (float) usDelay / 1000000);
+ }
+#endif /* DEBUG */
+ break;
+ case TCK:
+
+ /*
+ * Issue clock toggles.
+ */
+
+ usToggle = (unsigned short)ispVMDataSize();
+ ispVMClocks(usToggle);
+
+#ifdef DEBUG
+ printf("RUNTEST %d TCK;\n", usToggle);
+#endif /* DEBUG */
+ break;
+ case ENDLOOP:
+
+ /*
+ * Exit point from processing loops.
+ */
+ usContinue = 0;
+ break;
+
+ case COMMENT:
+
+ /*
+ * Display comment.
+ */
+
+ ispVMComment((unsigned short) ispVMDataSize());
+ break;
+ case ispEN:
+ ucState = GetByte();
+ if ((ucState == ON) || (ucState == 0x01))
+ writePort(g_ucPinENABLE, 0x01);
+ else
+ writePort(g_ucPinENABLE, 0x00);
+ ispVMDelay(1);
+ break;
+ case TRST:
+ if (GetByte() == 0x01)
+ writePort(g_ucPinTRST, 0x01);
+ else
+ writePort(g_ucPinTRST, 0x00);
+ ispVMDelay(1);
+ break;
+ default:
+
+ /*
+ * Invalid opcode encountered.
+ */
+
+ debug("\nINVALID OPCODE: 0x%.2X\n", cOpcode);
+
+ return VME_INVALID_FILE;
+ }
+ }
+ if (cRetCode >= 0) {
+ /*
+ * Break if intelligent programming is successful.
+ */
+
+ break;
+ }
+
+ }
+ /*
+ * If HEAP_IN flag was temporarily disabled,
+ * re-enable it before exiting
+ */
+
+ if (cRepeatHeap) {
+ g_usDataType |= HEAP_IN;
+ }
+
+ /*
+ * Set the data type register to not get data from the
+ * intelligent data buffer.
+ */
+
+ g_usDataType &= ~LHEAP_IN;
+ return cRetCode;
+}
+/*
+ *
+ * ispVMClocks
+ *
+ * Applies the specified number of pulses to TCK.
+ *
+ */
+
+void ispVMClocks(unsigned short Clocks)
+{
+ unsigned short iClockIndex = 0;
+ for (iClockIndex = 0; iClockIndex < Clocks; iClockIndex++) {
+ sclock();
+ }
+}
+
+/*
+ *
+ * ispVMBypass
+ *
+ * This procedure takes care of the HIR, HDR, TIR, TDR for the
+ * purpose of putting the other devices into Bypass mode. The
+ * current state is checked to find out if it is at DRPAUSE or
+ * IRPAUSE. If it is at DRPAUSE, perform bypass register scan.
+ * If it is at IRPAUSE, scan into instruction registers the bypass
+ * instruction.
+ *
+ */
+
+void ispVMBypass(signed char ScanType, unsigned short Bits)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned short iIndex = 0;
+ unsigned short iSourceIndex = 0;
+ unsigned char cBitState = 0;
+ unsigned char cCurByte = 0;
+ unsigned char *pcSource = NULL;
+
+ if (Bits <= 0) {
+ return;
+ }
+
+ switch (ScanType) {
+ case HIR:
+ pcSource = g_pucHIRData;
+ break;
+ case TIR:
+ pcSource = g_pucTIRData;
+ break;
+ case HDR:
+ pcSource = g_pucHDRData;
+ break;
+ case TDR:
+ pcSource = g_pucTDRData;
+ break;
+ default:
+ break;
+ }
+
+ iSourceIndex = 0;
+ cBitState = 0;
+ for (iIndex = 0; iIndex < Bits - 1; iIndex++) {
+ /* Scan instruction or bypass register */
+ if (iIndex % 8 == 0) {
+ cCurByte = pcSource[iSourceIndex++];
+ }
+ cBitState = (unsigned char) (((cCurByte << iIndex % 8) & 0x80)
+ ? 0x01 : 0x00);
+ writePort(g_ucPinTDI, cBitState);
+ sclock();
+ }
+
+ if (iIndex % 8 == 0) {
+ cCurByte = pcSource[iSourceIndex++];
+ }
+
+ cBitState = (unsigned char) (((cCurByte << iIndex % 8) & 0x80)
+ ? 0x01 : 0x00);
+ writePort(g_ucPinTDI, cBitState);
+}
+
+/*
+ *
+ * ispVMStateMachine
+ *
+ * This procedure steps all devices in the daisy chain from a given
+ * JTAG state to the next desirable state. If the next state is TLR,
+ * the JTAG state machine is brute forced into TLR by driving TMS
+ * high and pulse TCK 6 times.
+ *
+ */
+
+void ispVMStateMachine(signed char cNextJTAGState)
+{
+ /* 09/11/07 NN added local variables initialization */
+ signed char cPathIndex = 0;
+ signed char cStateIndex = 0;
+
+ if ((g_cCurrentJTAGState == cNextJTAGState) &&
+ (cNextJTAGState != RESET)) {
+ return;
+ }
+
+ for (cStateIndex = 0; cStateIndex < 25; cStateIndex++) {
+ if ((g_cCurrentJTAGState ==
+ g_JTAGTransistions[cStateIndex].CurState) &&
+ (cNextJTAGState ==
+ g_JTAGTransistions[cStateIndex].NextState)) {
+ break;
+ }
+ }
+
+ g_cCurrentJTAGState = cNextJTAGState;
+ for (cPathIndex = 0;
+ cPathIndex < g_JTAGTransistions[cStateIndex].Pulses;
+ cPathIndex++) {
+ if ((g_JTAGTransistions[cStateIndex].Pattern << cPathIndex)
+ & 0x80) {
+ writePort(g_ucPinTMS, (unsigned char) 0x01);
+ } else {
+ writePort(g_ucPinTMS, (unsigned char) 0x00);
+ }
+ sclock();
+ }
+
+ writePort(g_ucPinTDI, 0x00);
+ writePort(g_ucPinTMS, 0x00);
+}
+
+/*
+ *
+ * ispVMStart
+ *
+ * Enable the port to the device and set the state to RESET (TLR).
+ *
+ */
+
+void ispVMStart(void)
+{
+#ifdef DEBUG
+ printf("// ISPVM EMBEDDED ADDED\n");
+ printf("STATE RESET;\n");
+#endif
+ g_usFlowControl = 0;
+ g_usDataType = g_uiChecksumIndex = g_cCurrentJTAGState = 0;
+ g_usHeadDR = g_usHeadIR = g_usTailDR = g_usTailIR = 0;
+ g_usMaxSize = g_usShiftValue = g_usRepeatLoops = 0;
+ g_usTDOSize = g_usMASKSize = g_usTDISize = 0;
+ g_usDMASKSize = g_usLCOUNTSize = g_usHDRSize = 0;
+ g_usTDRSize = g_usHIRSize = g_usTIRSize = g_usHeapSize = 0;
+ g_pLVDSList = NULL;
+ g_usLVDSPairCount = 0;
+ previous_size = 0;
+
+ ispVMStateMachine(RESET); /*step devices to RESET state*/
+}
+
+/*
+ *
+ * ispVMEnd
+ *
+ * Set the state of devices to RESET to enable the devices and disable
+ * the port.
+ *
+ */
+
+void ispVMEnd(void)
+{
+#ifdef DEBUG
+ printf("// ISPVM EMBEDDED ADDED\n");
+ printf("STATE RESET;\n");
+ printf("RUNTEST 1.00E-001 SEC;\n");
+#endif
+
+ ispVMStateMachine(RESET); /*step devices to RESET state */
+ ispVMDelay(1000); /*wake up devices*/
+}
+
+/*
+ *
+ * ispVMSend
+ *
+ * Send the TDI data stream to devices. The data stream can be
+ * instructions or data.
+ *
+ */
+
+signed char ispVMSend(unsigned short a_usiDataSize)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned short iIndex = 0;
+ unsigned short iInDataIndex = 0;
+ unsigned char cCurByte = 0;
+ unsigned char cBitState = 0;
+
+ for (iIndex = 0; iIndex < a_usiDataSize - 1; iIndex++) {
+ if (iIndex % 8 == 0) {
+ cCurByte = g_pucInData[iInDataIndex++];
+ }
+ cBitState = (unsigned char)(((cCurByte << iIndex % 8) & 0x80)
+ ? 0x01 : 0x00);
+ writePort(g_ucPinTDI, cBitState);
+ sclock();
+ }
+
+ if (iIndex % 8 == 0) {
+ /* Take care of the last bit */
+ cCurByte = g_pucInData[iInDataIndex];
+ }
+
+ cBitState = (unsigned char) (((cCurByte << iIndex % 8) & 0x80)
+ ? 0x01 : 0x00);
+
+ writePort(g_ucPinTDI, cBitState);
+ if (g_usFlowControl & CASCADE) {
+ /*1/15/04 Clock in last bit for the first n-1 cascaded frames */
+ sclock();
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * ispVMRead
+ *
+ * Read the data stream from devices and verify.
+ *
+ */
+
+signed char ispVMRead(unsigned short a_usiDataSize)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned short usDataSizeIndex = 0;
+ unsigned short usErrorCount = 0;
+ unsigned short usLastBitIndex = 0;
+ unsigned char cDataByte = 0;
+ unsigned char cMaskByte = 0;
+ unsigned char cInDataByte = 0;
+ unsigned char cCurBit = 0;
+ unsigned char cByteIndex = 0;
+ unsigned short usBufferIndex = 0;
+ unsigned char ucDisplayByte = 0x00;
+ unsigned char ucDisplayFlag = 0x01;
+ char StrChecksum[256] = {0};
+ unsigned char g_usCalculateChecksum = 0x00;
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ usLastBitIndex = (unsigned short)(a_usiDataSize - 1);
+
+#ifndef DEBUG
+ /*
+ * If mask is not all zeros, then set the display flag to 0x00,
+ * otherwise it shall be set to 0x01 to indicate that data read
+ * from the device shall be displayed. If DEBUG is defined,
+ * always display data.
+ */
+
+ for (usDataSizeIndex = 0; usDataSizeIndex < (a_usiDataSize + 7) / 8;
+ usDataSizeIndex++) {
+ if (g_usDataType & MASK_DATA) {
+ if (g_pucOutMaskData[usDataSizeIndex] != 0x00) {
+ ucDisplayFlag = 0x00;
+ break;
+ }
+ } else if (g_usDataType & CMASK_DATA) {
+ g_usCalculateChecksum = 0x01;
+ ucDisplayFlag = 0x00;
+ break;
+ } else {
+ ucDisplayFlag = 0x00;
+ break;
+ }
+ }
+#endif /* DEBUG */
+
+ /*
+ *
+ * Begin shifting data in and out of the device.
+ *
+ **/
+
+ for (usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize;
+ usDataSizeIndex++) {
+ if (cByteIndex == 0) {
+
+ /*
+ * Grab byte from TDO buffer.
+ */
+
+ if (g_usDataType & TDO_DATA) {
+ cDataByte = g_pucOutData[usBufferIndex];
+ }
+
+ /*
+ * Grab byte from MASK buffer.
+ */
+
+ if (g_usDataType & MASK_DATA) {
+ cMaskByte = g_pucOutMaskData[usBufferIndex];
+ } else {
+ cMaskByte = 0xFF;
+ }
+
+ /*
+ * Grab byte from CMASK buffer.
+ */
+
+ if (g_usDataType & CMASK_DATA) {
+ cMaskByte = 0x00;
+ g_usCalculateChecksum = 0x01;
+ }
+
+ /*
+ * Grab byte from TDI buffer.
+ */
+
+ if (g_usDataType & TDI_DATA) {
+ cInDataByte = g_pucInData[usBufferIndex];
+ }
+
+ usBufferIndex++;
+ }
+
+ cCurBit = readPort();
+
+ if (ucDisplayFlag) {
+ ucDisplayByte <<= 1;
+ ucDisplayByte |= cCurBit;
+ }
+
+ /*
+ * Check if data read from port matches with expected TDO.
+ */
+
+ if (g_usDataType & TDO_DATA) {
+ /* 08/28/08 NN Added Calculate checksum support. */
+ if (g_usCalculateChecksum) {
+ if (cCurBit == 0x01)
+ g_usChecksum +=
+ (1 << (g_uiChecksumIndex % 8));
+ g_uiChecksumIndex++;
+ } else {
+ if ((((cMaskByte << cByteIndex) & 0x80)
+ ? 0x01 : 0x00)) {
+ if (cCurBit != (unsigned char)
+ (((cDataByte << cByteIndex) & 0x80)
+ ? 0x01 : 0x00)) {
+ usErrorCount++;
+ }
+ }
+ }
+ }
+
+ /*
+ * Write TDI data to the port.
+ */
+
+ writePort(g_ucPinTDI,
+ (unsigned char)(((cInDataByte << cByteIndex) & 0x80)
+ ? 0x01 : 0x00));
+
+ if (usDataSizeIndex < usLastBitIndex) {
+
+ /*
+ * Clock data out from the data shift register.
+ */
+
+ sclock();
+ } else if (g_usFlowControl & CASCADE) {
+
+ /*
+ * Clock in last bit for the first N - 1 cascaded frames
+ */
+
+ sclock();
+ }
+
+ /*
+ * Increment the byte index. If it exceeds 7, then reset it back
+ * to zero.
+ */
+
+ cByteIndex++;
+ if (cByteIndex >= 8) {
+ if (ucDisplayFlag) {
+
+ /*
+ * Store displayed data in the TDO buffer. By reusing
+ * the TDO buffer to store displayed data, there is no
+ * need to allocate a buffer simply to hold display
+ * data. This will not cause any false verification
+ * errors because the true TDO byte has already
+ * been consumed.
+ */
+
+ g_pucOutData[usBufferIndex - 1] = ucDisplayByte;
+ ucDisplayByte = 0;
+ }
+
+ cByteIndex = 0;
+ }
+ /* 09/12/07 Nguyen changed to display the 1 bit expected data */
+ else if (a_usiDataSize == 1) {
+ if (ucDisplayFlag) {
+
+ /*
+ * Store displayed data in the TDO buffer.
+ * By reusing the TDO buffer to store displayed
+ * data, there is no need to allocate
+ * a buffer simply to hold display data. This
+ * will not cause any false verification errors
+ * because the true TDO byte has already
+ * been consumed.
+ */
+
+ /*
+ * Flip ucDisplayByte and store it in cDataByte.
+ */
+ cDataByte = 0x00;
+ for (usBufferIndex = 0; usBufferIndex < 8;
+ usBufferIndex++) {
+ cDataByte <<= 1;
+ if (ucDisplayByte & 0x01) {
+ cDataByte |= 0x01;
+ }
+ ucDisplayByte >>= 1;
+ }
+ g_pucOutData[0] = cDataByte;
+ ucDisplayByte = 0;
+ }
+
+ cByteIndex = 0;
+ }
+ }
+
+ if (ucDisplayFlag) {
+
+#ifdef DEBUG
+ debug("RECEIVED TDO (");
+#else
+ vme_out_string("Display Data: 0x");
+#endif /* DEBUG */
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ for (usDataSizeIndex = (unsigned short)
+ ((a_usiDataSize + 7) / 8);
+ usDataSizeIndex > 0 ; usDataSizeIndex--) {
+ cMaskByte = g_pucOutData[usDataSizeIndex - 1];
+ cDataByte = 0x00;
+
+ /*
+ * Flip cMaskByte and store it in cDataByte.
+ */
+
+ for (usBufferIndex = 0; usBufferIndex < 8;
+ usBufferIndex++) {
+ cDataByte <<= 1;
+ if (cMaskByte & 0x01) {
+ cDataByte |= 0x01;
+ }
+ cMaskByte >>= 1;
+ }
+#ifdef DEBUG
+ printf("%.2X", cDataByte);
+ if ((((a_usiDataSize + 7) / 8) - usDataSizeIndex)
+ % 40 == 39) {
+ printf("\n\t\t");
+ }
+#else
+ vme_out_hex(cDataByte);
+#endif /* DEBUG */
+ }
+
+#ifdef DEBUG
+ printf(")\n\n");
+#else
+ vme_out_string("\n\n");
+#endif /* DEBUG */
+ /* 09/02/08 Nguyen changed to display the data Checksum */
+ if (g_usChecksum != 0) {
+ g_usChecksum &= 0xFFFF;
+ sprintf(StrChecksum, "Data Checksum: %.4lX\n\n",
+ g_usChecksum);
+ vme_out_string(StrChecksum);
+ g_usChecksum = 0;
+ }
+ }
+
+ if (usErrorCount > 0) {
+ if (g_usFlowControl & VERIFYUES) {
+ vme_out_string(
+ "USERCODE verification failed. "
+ "Continue programming......\n\n");
+ g_usFlowControl &= ~(VERIFYUES);
+ return 0;
+ } else {
+
+#ifdef DEBUG
+ printf("TOTAL ERRORS: %d\n", usErrorCount);
+#endif /* DEBUG */
+
+ return VME_VERIFICATION_FAILURE;
+ }
+ } else {
+ if (g_usFlowControl & VERIFYUES) {
+ vme_out_string("USERCODE verification passed. "
+ "Programming aborted.\n\n");
+ g_usFlowControl &= ~(VERIFYUES);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+/*
+ *
+ * ispVMReadandSave
+ *
+ * Support dynamic I/O.
+ *
+ */
+
+signed char ispVMReadandSave(unsigned short int a_usiDataSize)
+{
+ /* 09/11/07 NN added local variables initialization */
+ unsigned short int usDataSizeIndex = 0;
+ unsigned short int usLastBitIndex = 0;
+ unsigned short int usBufferIndex = 0;
+ unsigned short int usOutBitIndex = 0;
+ unsigned short int usLVDSIndex = 0;
+ unsigned char cDataByte = 0;
+ unsigned char cDMASKByte = 0;
+ unsigned char cInDataByte = 0;
+ unsigned char cCurBit = 0;
+ unsigned char cByteIndex = 0;
+ signed char cLVDSByteIndex = 0;
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ usLastBitIndex = (unsigned short) (a_usiDataSize - 1);
+
+ /*
+ *
+ * Iterate through the data bits.
+ *
+ */
+
+ for (usDataSizeIndex = 0; usDataSizeIndex < a_usiDataSize;
+ usDataSizeIndex++) {
+ if (cByteIndex == 0) {
+
+ /*
+ * Grab byte from DMASK buffer.
+ */
+
+ if (g_usDataType & DMASK_DATA) {
+ cDMASKByte = g_pucOutDMaskData[usBufferIndex];
+ } else {
+ cDMASKByte = 0x00;
+ }
+
+ /*
+ * Grab byte from TDI buffer.
+ */
+
+ if (g_usDataType & TDI_DATA) {
+ cInDataByte = g_pucInData[usBufferIndex];
+ }
+
+ usBufferIndex++;
+ }
+
+ cCurBit = readPort();
+ cDataByte = (unsigned char)(((cInDataByte << cByteIndex) & 0x80)
+ ? 0x01 : 0x00);
+
+ /*
+ * Initialize the byte to be zero.
+ */
+
+ if (usOutBitIndex % 8 == 0) {
+ g_pucOutData[usOutBitIndex / 8] = 0x00;
+ }
+
+ /*
+ * Use TDI, DMASK, and device TDO to create new TDI (actually
+ * stored in g_pucOutData).
+ */
+
+ if ((((cDMASKByte << cByteIndex) & 0x80) ? 0x01 : 0x00)) {
+
+ if (g_pLVDSList) {
+ for (usLVDSIndex = 0;
+ usLVDSIndex < g_usLVDSPairCount;
+ usLVDSIndex++) {
+ if (g_pLVDSList[usLVDSIndex].
+ usNegativeIndex ==
+ usDataSizeIndex) {
+ g_pLVDSList[usLVDSIndex].
+ ucUpdate = 0x01;
+ break;
+ }
+ }
+ }
+
+ /*
+ * DMASK bit is 1, use TDI.
+ */
+
+ g_pucOutData[usOutBitIndex / 8] |= (unsigned char)
+ (((cDataByte & 0x1) ? 0x01 : 0x00) <<
+ (7 - usOutBitIndex % 8));
+ } else {
+
+ /*
+ * DMASK bit is 0, use device TDO.
+ */
+
+ g_pucOutData[usOutBitIndex / 8] |= (unsigned char)
+ (((cCurBit & 0x1) ? 0x01 : 0x00) <<
+ (7 - usOutBitIndex % 8));
+ }
+
+ /*
+ * Shift in TDI in order to get TDO out.
+ */
+
+ usOutBitIndex++;
+ writePort(g_ucPinTDI, cDataByte);
+ if (usDataSizeIndex < usLastBitIndex) {
+ sclock();
+ }
+
+ /*
+ * Increment the byte index. If it exceeds 7, then reset it back
+ * to zero.
+ */
+
+ cByteIndex++;
+ if (cByteIndex >= 8) {
+ cByteIndex = 0;
+ }
+ }
+
+ /*
+ * If g_pLVDSList exists and pairs need updating, then update
+ * the negative-pair to receive the flipped positive-pair value.
+ */
+
+ if (g_pLVDSList) {
+ for (usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount;
+ usLVDSIndex++) {
+ if (g_pLVDSList[usLVDSIndex].ucUpdate) {
+
+ /*
+ * Read the positive value and flip it.
+ */
+
+ cDataByte = (unsigned char)
+ (((g_pucOutData[g_pLVDSList[usLVDSIndex].
+ usPositiveIndex / 8]
+ << (g_pLVDSList[usLVDSIndex].
+ usPositiveIndex % 8)) & 0x80) ?
+ 0x01 : 0x00);
+ /* 09/11/07 NN Type cast mismatch variables */
+ cDataByte = (unsigned char) (!cDataByte);
+
+ /*
+ * Get the byte that needs modification.
+ */
+
+ cInDataByte =
+ g_pucOutData[g_pLVDSList[usLVDSIndex].
+ usNegativeIndex / 8];
+
+ if (cDataByte) {
+
+ /*
+ * Copy over the current byte and
+ * set the negative bit to 1.
+ */
+
+ cDataByte = 0x00;
+ for (cLVDSByteIndex = 7;
+ cLVDSByteIndex >= 0;
+ cLVDSByteIndex--) {
+ cDataByte <<= 1;
+ if (7 -
+ (g_pLVDSList[usLVDSIndex].
+ usNegativeIndex % 8) ==
+ cLVDSByteIndex) {
+
+ /*
+ * Set negative bit to 1
+ */
+
+ cDataByte |= 0x01;
+ } else if (cInDataByte & 0x80) {
+ cDataByte |= 0x01;
+ }
+
+ cInDataByte <<= 1;
+ }
+
+ /*
+ * Store the modified byte.
+ */
+
+ g_pucOutData[g_pLVDSList[usLVDSIndex].
+ usNegativeIndex / 8] = cDataByte;
+ } else {
+
+ /*
+ * Copy over the current byte and set
+ * the negative bit to 0.
+ */
+
+ cDataByte = 0x00;
+ for (cLVDSByteIndex = 7;
+ cLVDSByteIndex >= 0;
+ cLVDSByteIndex--) {
+ cDataByte <<= 1;
+ if (7 -
+ (g_pLVDSList[usLVDSIndex].
+ usNegativeIndex % 8) ==
+ cLVDSByteIndex) {
+
+ /*
+ * Set negative bit to 0
+ */
+
+ cDataByte |= 0x00;
+ } else if (cInDataByte & 0x80) {
+ cDataByte |= 0x01;
+ }
+
+ cInDataByte <<= 1;
+ }
+
+ /*
+ * Store the modified byte.
+ */
+
+ g_pucOutData[g_pLVDSList[usLVDSIndex].
+ usNegativeIndex / 8] = cDataByte;
+ }
+
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+signed char ispVMProcessLVDS(unsigned short a_usLVDSCount)
+{
+ unsigned short usLVDSIndex = 0;
+
+ /*
+ * Allocate memory to hold LVDS pairs.
+ */
+
+ ispVMMemManager(LVDS, a_usLVDSCount);
+ g_usLVDSPairCount = a_usLVDSCount;
+
+#ifdef DEBUG
+ printf("LVDS %d (", a_usLVDSCount);
+#endif /* DEBUG */
+
+ /*
+ * Iterate through each given LVDS pair.
+ */
+
+ for (usLVDSIndex = 0; usLVDSIndex < g_usLVDSPairCount; usLVDSIndex++) {
+
+ /*
+ * Assign the positive and negative indices of the LVDS pair.
+ */
+
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_pLVDSList[usLVDSIndex].usPositiveIndex =
+ (unsigned short) ispVMDataSize();
+ /* 09/11/07 NN Type cast mismatch variables */
+ g_pLVDSList[usLVDSIndex].usNegativeIndex =
+ (unsigned short)ispVMDataSize();
+
+#ifdef DEBUG
+ if (usLVDSIndex < g_usLVDSPairCount - 1) {
+ printf("%d:%d, ",
+ g_pLVDSList[usLVDSIndex].usPositiveIndex,
+ g_pLVDSList[usLVDSIndex].usNegativeIndex);
+ } else {
+ printf("%d:%d",
+ g_pLVDSList[usLVDSIndex].usPositiveIndex,
+ g_pLVDSList[usLVDSIndex].usNegativeIndex);
+ }
+#endif /* DEBUG */
+
+ }
+
+#ifdef DEBUG
+ printf(");\n");
+#endif /* DEBUG */
+
+ return 0;
+}
diff --git a/drivers/fpga/lattice.c b/drivers/fpga/lattice.c
new file mode 100644
index 00000000000..29cf2f60974
--- /dev/null
+++ b/drivers/fpga/lattice.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ *
+ * ispVM functions adapted from Lattice's ispmVMEmbedded code:
+ * Copyright 2009 Lattice Semiconductor Corp.
+ */
+
+#include <log.h>
+#include <malloc.h>
+#include <fpga.h>
+#include <lattice.h>
+#include <linux/delay.h>
+
+static lattice_board_specific_func *pfns;
+static const char *fpga_image;
+static unsigned long read_bytes;
+static unsigned long bufsize;
+static unsigned short expectedCRC;
+
+/*
+ * External variables and functions declared in ivm_core.c module.
+ */
+extern unsigned short g_usCalculatedCRC;
+extern unsigned short g_usDataType;
+extern unsigned char *g_pucIntelBuffer;
+extern unsigned char *g_pucHeapMemory;
+extern unsigned short g_iHeapCounter;
+extern unsigned short g_iHEAPSize;
+extern unsigned short g_usIntelDataIndex;
+extern unsigned short g_usIntelBufferSize;
+extern char *const g_szSupportedVersions[];
+
+/*
+ * ispVMDelay
+ *
+ * Users must implement a delay to observe a_usTimeDelay, where
+ * bit 15 of the a_usTimeDelay defines the unit.
+ * 1 = milliseconds
+ * 0 = microseconds
+ * Example:
+ * a_usTimeDelay = 0x0001 = 1 microsecond delay.
+ * a_usTimeDelay = 0x8001 = 1 millisecond delay.
+ *
+ * This subroutine is called upon to provide a delay from 1 millisecond to a few
+ * hundreds milliseconds each time.
+ * It is understood that due to a_usTimeDelay is defined as unsigned short, a 16
+ * bits integer, this function is restricted to produce a delay to 64000
+ * micro-seconds or 32000 milli-second maximum. The VME file will never pass on
+ * to this function a delay time > those maximum number. If it needs more than
+ * those maximum, the VME file will launch the delay function several times to
+ * realize a larger delay time cummulatively.
+ * It is perfectly alright to provide a longer delay than required. It is not
+ * acceptable if the delay is shorter.
+ */
+void ispVMDelay(unsigned short delay)
+{
+ if (delay & 0x8000)
+ delay = (delay & ~0x8000) * 1000;
+ udelay(delay);
+}
+
+void writePort(unsigned char a_ucPins, unsigned char a_ucValue)
+{
+ a_ucValue = a_ucValue ? 1 : 0;
+
+ switch (a_ucPins) {
+ case g_ucPinTDI:
+ pfns->jtag_set_tdi(a_ucValue);
+ break;
+ case g_ucPinTCK:
+ pfns->jtag_set_tck(a_ucValue);
+ break;
+ case g_ucPinTMS:
+ pfns->jtag_set_tms(a_ucValue);
+ break;
+ default:
+ printf("%s: requested unknown pin\n", __func__);
+ }
+}
+
+unsigned char readPort(void)
+{
+ return pfns->jtag_get_tdo();
+}
+
+void sclock(void)
+{
+ writePort(g_ucPinTCK, 0x01);
+ writePort(g_ucPinTCK, 0x00);
+}
+
+void calibration(void)
+{
+ /* Apply 2 pulses to TCK. */
+ writePort(g_ucPinTCK, 0x00);
+ writePort(g_ucPinTCK, 0x01);
+ writePort(g_ucPinTCK, 0x00);
+ writePort(g_ucPinTCK, 0x01);
+ writePort(g_ucPinTCK, 0x00);
+
+ ispVMDelay(0x8001);
+
+ /* Apply 2 pulses to TCK. */
+ writePort(g_ucPinTCK, 0x01);
+ writePort(g_ucPinTCK, 0x00);
+ writePort(g_ucPinTCK, 0x01);
+ writePort(g_ucPinTCK, 0x00);
+}
+
+/*
+ * GetByte
+ *
+ * Returns a byte to the caller. The returned byte depends on the
+ * g_usDataType register. If the HEAP_IN bit is set, then the byte
+ * is returned from the HEAP. If the LHEAP_IN bit is set, then
+ * the byte is returned from the intelligent buffer. Otherwise,
+ * the byte is returned directly from the VME file.
+ */
+unsigned char GetByte(void)
+{
+ unsigned char ucData;
+ unsigned int block_size = 4 * 1024;
+
+ if (g_usDataType & HEAP_IN) {
+
+ /*
+ * Get data from repeat buffer.
+ */
+
+ if (g_iHeapCounter > g_iHEAPSize) {
+
+ /*
+ * Data over-run.
+ */
+
+ return 0xFF;
+ }
+
+ ucData = g_pucHeapMemory[g_iHeapCounter++];
+ } else if (g_usDataType & LHEAP_IN) {
+
+ /*
+ * Get data from intel buffer.
+ */
+
+ if (g_usIntelDataIndex >= g_usIntelBufferSize) {
+ return 0xFF;
+ }
+
+ ucData = g_pucIntelBuffer[g_usIntelDataIndex++];
+ } else {
+ if (read_bytes == bufsize) {
+ return 0xFF;
+ }
+ ucData = *fpga_image++;
+ read_bytes++;
+
+ if (!(read_bytes % block_size)) {
+ printf("Downloading FPGA %ld/%ld completed\r",
+ read_bytes,
+ bufsize);
+ }
+
+ if (expectedCRC != 0) {
+ ispVMCalculateCRC32(ucData);
+ }
+ }
+
+ return ucData;
+}
+
+signed char ispVM(void)
+{
+ char szFileVersion[9] = { 0 };
+ signed char cRetCode = 0;
+ signed char cIndex = 0;
+ signed char cVersionIndex = 0;
+ unsigned char ucReadByte = 0;
+ unsigned short crc;
+
+ g_pucHeapMemory = NULL;
+ g_iHeapCounter = 0;
+ g_iHEAPSize = 0;
+ g_usIntelDataIndex = 0;
+ g_usIntelBufferSize = 0;
+ g_usCalculatedCRC = 0;
+ expectedCRC = 0;
+ ucReadByte = GetByte();
+ switch (ucReadByte) {
+ case FILE_CRC:
+ crc = (unsigned char)GetByte();
+ crc <<= 8;
+ crc |= GetByte();
+ expectedCRC = crc;
+
+ for (cIndex = 0; cIndex < 8; cIndex++)
+ szFileVersion[cIndex] = GetByte();
+
+ break;
+ default:
+ szFileVersion[0] = (signed char) ucReadByte;
+ for (cIndex = 1; cIndex < 8; cIndex++)
+ szFileVersion[cIndex] = GetByte();
+
+ break;
+ }
+
+ /*
+ *
+ * Compare the VME file version against the supported version.
+ *
+ */
+
+ for (cVersionIndex = 0; g_szSupportedVersions[cVersionIndex] != 0;
+ cVersionIndex++) {
+ for (cIndex = 0; cIndex < 8; cIndex++) {
+ if (szFileVersion[cIndex] !=
+ g_szSupportedVersions[cVersionIndex][cIndex]) {
+ cRetCode = VME_VERSION_FAILURE;
+ break;
+ }
+ cRetCode = 0;
+ }
+
+ if (cRetCode == 0) {
+ break;
+ }
+ }
+
+ if (cRetCode < 0) {
+ return VME_VERSION_FAILURE;
+ }
+
+ printf("VME file checked: starting downloading to FPGA\n");
+
+ ispVMStart();
+
+ cRetCode = ispVMCode();
+
+ ispVMEnd();
+ ispVMFreeMem();
+ puts("\n");
+
+ if (cRetCode == 0 && expectedCRC != 0 &&
+ (expectedCRC != g_usCalculatedCRC)) {
+ printf("Expected CRC: 0x%.4X\n", expectedCRC);
+ printf("Calculated CRC: 0x%.4X\n", g_usCalculatedCRC);
+ return VME_CRC_FAILURE;
+ }
+ return cRetCode;
+}
+
+static int lattice_validate(Lattice_desc *desc, const char *fn)
+{
+ int ret_val = false;
+
+ if (desc) {
+ if ((desc->family > min_lattice_type) &&
+ (desc->family < max_lattice_type)) {
+ if ((desc->iface > min_lattice_iface_type) &&
+ (desc->iface < max_lattice_iface_type)) {
+ if (desc->size) {
+ ret_val = true;
+ } else {
+ printf("%s: NULL part size\n", fn);
+ }
+ } else {
+ printf("%s: Invalid Interface type, %d\n",
+ fn, desc->iface);
+ }
+ } else {
+ printf("%s: Invalid family type, %d\n",
+ fn, desc->family);
+ }
+ } else {
+ printf("%s: NULL descriptor!\n", fn);
+ }
+
+ return ret_val;
+}
+
+int lattice_load(Lattice_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ if (!lattice_validate(desc, (char *)__func__)) {
+ printf("%s: Invalid device descriptor\n", __func__);
+ } else {
+ pfns = desc->iface_fns;
+
+ switch (desc->family) {
+ case Lattice_XP2:
+ fpga_image = buf;
+ read_bytes = 0;
+ bufsize = bsize;
+ debug("%s: Launching the Lattice ISPVME Loader:"
+ " addr %p size 0x%lx...\n",
+ __func__, fpga_image, bufsize);
+ ret_val = ispVM();
+ if (ret_val)
+ printf("%s: error %d downloading FPGA image\n",
+ __func__, ret_val);
+ else
+ puts("FPGA downloaded successfully\n");
+ break;
+ default:
+ printf("%s: Unsupported family type, %d\n",
+ __func__, desc->family);
+ }
+ }
+
+ return ret_val;
+}
+
+int lattice_dump(Lattice_desc *desc, const void *buf, size_t bsize)
+{
+ puts("Dump not supported for Lattice FPGA\n");
+
+ return FPGA_FAIL;
+
+}
+
+int lattice_info(Lattice_desc *desc)
+{
+ int ret_val = FPGA_FAIL;
+
+ if (lattice_validate(desc, (char *)__func__)) {
+ printf("Family: \t");
+ switch (desc->family) {
+ case Lattice_XP2:
+ puts("XP2\n");
+ break;
+ /* Add new family types here */
+ default:
+ printf("Unknown family type, %d\n", desc->family);
+ }
+
+ puts("Interface type:\t");
+ switch (desc->iface) {
+ case lattice_jtag_mode:
+ puts("JTAG Mode\n");
+ break;
+ /* Add new interface types here */
+ default:
+ printf("Unsupported interface type, %d\n", desc->iface);
+ }
+
+ printf("Device Size: \t%zu bytes\n",
+ desc->size);
+
+ if (desc->iface_fns) {
+ printf("Device Function Table @ 0x%p\n",
+ desc->iface_fns);
+ switch (desc->family) {
+ case Lattice_XP2:
+ break;
+ /* Add new family types here */
+ default:
+ break;
+ }
+ } else {
+ puts("No Device Function Table.\n");
+ }
+
+ if (desc->desc)
+ printf("Model: \t%s\n", desc->desc);
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf("%s: Invalid device descriptor\n", __func__);
+ }
+
+ return ret_val;
+}
diff --git a/drivers/fpga/sandbox.c b/drivers/fpga/sandbox.c
new file mode 100644
index 00000000000..f17a8221795
--- /dev/null
+++ b/drivers/fpga/sandbox.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 Alexander Dahl <post@lespocky.de>
+ */
+
+#include <dm.h>
+
+static const struct udevice_id sandbox_fpga_match[] = {
+ { .compatible = "sandbox,fpga" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sandbox_fpga) = {
+ .name = "sandbox_fpga",
+ .id = UCLASS_FPGA,
+ .of_match = sandbox_fpga_match,
+};
diff --git a/drivers/fpga/socfpga.c b/drivers/fpga/socfpga.c
new file mode 100644
index 00000000000..bb98c0e2bcf
--- /dev/null
+++ b/drivers/fpga/socfpga.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (C) 2012-2017 Altera Corporation <www.altera.com>
+ * All rights reserved.
+ */
+
+#include <config.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <asm/arch/fpga_manager.h>
+#include <asm/arch/reset_manager.h>
+#include <asm/arch/system_manager.h>
+
+/* Timeout count */
+#define FPGA_TIMEOUT_CNT 0x1000000
+
+static struct socfpga_fpga_manager *fpgamgr_regs =
+ (struct socfpga_fpga_manager *)SOCFPGA_FPGAMGRREGS_ADDRESS;
+
+int fpgamgr_dclkcnt_set(unsigned long cnt)
+{
+ unsigned long i;
+
+ /* Clear any existing done status */
+ if (readl(&fpgamgr_regs->dclkstat))
+ writel(0x1, &fpgamgr_regs->dclkstat);
+
+ /* Write the dclkcnt */
+ writel(cnt, &fpgamgr_regs->dclkcnt);
+
+ /* Wait till the dclkcnt done */
+ for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
+ if (!readl(&fpgamgr_regs->dclkstat))
+ continue;
+
+ writel(0x1, &fpgamgr_regs->dclkstat);
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
+/* Write the RBF data to FPGA Manager */
+void fpgamgr_program_write(const void *rbf_data, size_t rbf_size)
+{
+ uint32_t src = (uint32_t)rbf_data;
+ uint32_t dst = SOCFPGA_FPGAMGRDATA_ADDRESS;
+
+ /* Number of loops for 32-byte long copying. */
+ uint32_t loops32 = rbf_size / 32;
+ /* Number of loops for 4-byte long copying + trailing bytes */
+ uint32_t loops4 = DIV_ROUND_UP(rbf_size % 32, 4);
+
+ asm volatile(
+ " cmp %2, #0\n"
+ " beq 2f\n"
+ "1: ldmia %0!, {r0-r7}\n"
+ " stmia %1!, {r0-r7}\n"
+ " sub %1, #32\n"
+ " subs %2, #1\n"
+ " bne 1b\n"
+ "2: cmp %3, #0\n"
+ " beq 4f\n"
+ "3: ldr %2, [%0], #4\n"
+ " str %2, [%1]\n"
+ " subs %3, #1\n"
+ " bne 3b\n"
+ "4: nop\n"
+ : "+r"(src), "+r"(dst), "+r"(loops32), "+r"(loops4) :
+ : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "cc");
+}
diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c
new file mode 100644
index 00000000000..e9822b2bb0e
--- /dev/null
+++ b/drivers/fpga/socfpga_arria10.c
@@ -0,0 +1,951 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017-2019 Intel Corporation <www.intel.com>
+ */
+#include <image.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/arch/fpga_manager.h>
+#include <asm/arch/reset_manager.h>
+#include <asm/arch/system_manager.h>
+#include <asm/arch/sdram.h>
+#include <asm/arch/misc.h>
+#include <altera.h>
+#include <asm/arch/pinmux.h>
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <errno.h>
+#include <fs_loader.h>
+#include <wait_bit.h>
+#include <watchdog.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#define CFGWDTH_32 1
+#define MIN_BITSTREAM_SIZECHECK 230
+#define ENCRYPTION_OFFSET 69
+#define COMPRESSION_OFFSET 229
+#define FPGA_TIMEOUT_MSEC 1000 /* timeout in ms */
+#define FPGA_TIMEOUT_CNT 0x1000000
+#define DEFAULT_DDR_LOAD_ADDRESS 0x400
+#define DDR_BUFFER_SIZE 0x100000
+
+/* When reading bitstream from a filesystem, the size of the first read is
+ * changed so that the subsequent reads are aligned to this value. This value
+ * was chosen so that in subsequent reads the fat fs driver doesn't have to
+ * allocate a temporary buffer in get_contents (assuming 8KiB clusters).
+ */
+#define MAX_FIRST_LOAD_SIZE 0x2000
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct socfpga_fpga_manager *fpga_manager_base =
+ (void *)SOCFPGA_FPGAMGRREGS_ADDRESS;
+
+static void fpgamgr_set_cd_ratio(unsigned long ratio);
+
+static uint32_t fpgamgr_get_msel(void)
+{
+ u32 reg;
+
+ reg = readl(&fpga_manager_base->imgcfg_stat);
+ reg = (reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SET_MSD) >>
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL0_LSB;
+
+ return reg;
+}
+
+static void fpgamgr_set_cfgwdth(int width)
+{
+ if (width)
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
+ ALT_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SET_MSK);
+ else
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
+ ALT_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SET_MSK);
+}
+
+int is_fpgamgr_user_mode(void)
+{
+ return (readl(&fpga_manager_base->imgcfg_stat) &
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK) != 0;
+}
+
+static int wait_for_user_mode(void)
+{
+ return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat,
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK,
+ 1, FPGA_TIMEOUT_MSEC, false);
+}
+
+static int wait_for_fifo_empty(void)
+{
+ return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat,
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_IMGCFG_FIFOEMPTY_SET_MSK,
+ 1, FPGA_TIMEOUT_MSEC, false);
+}
+
+int is_fpgamgr_early_user_mode(void)
+{
+ return (readl(&fpga_manager_base->imgcfg_stat) &
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE_SET_MSK) != 0;
+}
+
+int fpgamgr_wait_early_user_mode(void)
+{
+ u32 sync_data = 0xffffffff;
+ u32 i = 0;
+ unsigned start = get_timer(0);
+ unsigned long cd_ratio;
+
+ /* Getting existing CDRATIO */
+ cd_ratio = (readl(&fpga_manager_base->imgcfg_ctrl_02) &
+ ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK) >>
+ ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_LSB;
+
+ /* Using CDRATIO_X1 for better compatibility */
+ fpgamgr_set_cd_ratio(CDRATIO_x1);
+
+ while (!is_fpgamgr_early_user_mode()) {
+ if (get_timer(start) > FPGA_TIMEOUT_MSEC)
+ return -ETIMEDOUT;
+ fpgamgr_program_write((const long unsigned int *)&sync_data,
+ sizeof(sync_data));
+ udelay(FPGA_TIMEOUT_MSEC);
+ i++;
+ }
+
+ debug("FPGA: Additional %i sync word needed\n", i);
+
+ /* restoring original CDRATIO */
+ fpgamgr_set_cd_ratio(cd_ratio);
+
+ return 0;
+}
+
+/* Read f2s_nconfig_pin and f2s_nstatus_pin; loop until de-asserted */
+static int wait_for_nconfig_pin_and_nstatus_pin(void)
+{
+ unsigned long mask = ALT_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN_SET_MSK |
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK;
+
+ /*
+ * Poll until f2s_nconfig_pin and f2s_nstatus_pin; loop until
+ * de-asserted, timeout at 1000ms
+ */
+ return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat, mask,
+ true, FPGA_TIMEOUT_MSEC, false);
+}
+
+static int wait_for_f2s_nstatus_pin(unsigned long value)
+{
+ /* Poll until f2s to specific value, timeout at 1000ms */
+ return wait_for_bit_le32(&fpga_manager_base->imgcfg_stat,
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK,
+ value, FPGA_TIMEOUT_MSEC, false);
+}
+
+/* set CD ratio */
+static void fpgamgr_set_cd_ratio(unsigned long ratio)
+{
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
+ ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK);
+
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
+ (ratio << ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_LSB) &
+ ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK);
+}
+
+/* get the MSEL value, verify we are set for FPP configuration mode */
+static int fpgamgr_verify_msel(void)
+{
+ u32 msel = fpgamgr_get_msel();
+
+ if (msel & ~BIT(0)) {
+ printf("Fail: read msel=%d\n", msel);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+/*
+ * Write cdratio and cdwidth based on whether the bitstream is compressed
+ * and/or encoded
+ */
+static int fpgamgr_set_cdratio_cdwidth(unsigned int cfg_width, u32 *rbf_data,
+ size_t rbf_size)
+{
+ unsigned int cd_ratio;
+ bool encrypt, compress;
+
+ /*
+ * According to the bitstream specification,
+ * both encryption and compression status are
+ * in location before offset 230 of the buffer.
+ */
+ if (rbf_size < MIN_BITSTREAM_SIZECHECK)
+ return -EINVAL;
+
+ encrypt = (rbf_data[ENCRYPTION_OFFSET] >> 2) & 3;
+ encrypt = encrypt != 0;
+
+ compress = (rbf_data[COMPRESSION_OFFSET] >> 1) & 1;
+ compress = !compress;
+
+ debug("FPGA: Header word %d = %08x.\n", 69, rbf_data[69]);
+ debug("FPGA: Header word %d = %08x.\n", 229, rbf_data[229]);
+ debug("FPGA: Read from rbf header: encrypt=%d compress=%d.\n", encrypt,
+ compress);
+
+ /*
+ * from the register map description of cdratio in imgcfg_ctrl_02:
+ * Normal Configuration : 32bit Passive Parallel
+ * Partial Reconfiguration : 16bit Passive Parallel
+ */
+
+ /*
+ * cd ratio is dependent on cfg width and whether the bitstream
+ * is encrypted and/or compressed.
+ *
+ * | width | encr. | compr. | cd ratio |
+ * | 16 | 0 | 0 | 1 |
+ * | 16 | 0 | 1 | 4 |
+ * | 16 | 1 | 0 | 2 |
+ * | 16 | 1 | 1 | 4 |
+ * | 32 | 0 | 0 | 1 |
+ * | 32 | 0 | 1 | 8 |
+ * | 32 | 1 | 0 | 4 |
+ * | 32 | 1 | 1 | 8 |
+ */
+ if (!compress && !encrypt) {
+ cd_ratio = CDRATIO_x1;
+ } else {
+ if (compress)
+ cd_ratio = CDRATIO_x4;
+ else
+ cd_ratio = CDRATIO_x2;
+
+ /* if 32 bit, double the cd ratio (so register
+ field setting is incremented) */
+ if (cfg_width == CFGWDTH_32)
+ cd_ratio += 1;
+ }
+
+ fpgamgr_set_cfgwdth(cfg_width);
+ fpgamgr_set_cd_ratio(cd_ratio);
+
+ return 0;
+}
+
+static int fpgamgr_reset(void)
+{
+ unsigned long reg;
+
+ /* S2F_NCONFIG = 0 */
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
+ ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK);
+
+ /* Wait for f2s_nstatus == 0 */
+ if (wait_for_f2s_nstatus_pin(0))
+ return -ETIME;
+
+ /* S2F_NCONFIG = 1 */
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
+ ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK);
+
+ /* Wait for f2s_nstatus == 1 */
+ if (wait_for_f2s_nstatus_pin(1))
+ return -ETIME;
+
+ /* read and confirm f2s_condone_pin = 0 and f2s_condone_oe = 1 */
+ reg = readl(&fpga_manager_base->imgcfg_stat);
+ if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) != 0)
+ return -EPERM;
+
+ if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_OE_SET_MSK) == 0)
+ return -EPERM;
+
+ return 0;
+}
+
+/* Start the FPGA programming by initialize the FPGA Manager */
+int fpgamgr_program_init(u32 * rbf_data, size_t rbf_size)
+{
+ int ret;
+
+ /* Step 1 */
+ if (fpgamgr_verify_msel())
+ return -EPERM;
+
+ /* Step 2 */
+ if (fpgamgr_set_cdratio_cdwidth(CFGWDTH_32, rbf_data, rbf_size))
+ return -EPERM;
+
+ /*
+ * Step 3:
+ * Make sure no other external devices are trying to interfere with
+ * programming:
+ */
+ if (wait_for_nconfig_pin_and_nstatus_pin())
+ return -ETIME;
+
+ /*
+ * Step 4:
+ * Deassert the signal drives from HPS
+ *
+ * S2F_NCE = 1
+ * S2F_PR_REQUEST = 0
+ * EN_CFG_CTRL = 0
+ * EN_CFG_DATA = 0
+ * S2F_NCONFIG = 1
+ * S2F_NSTATUS_OE = 0
+ * S2F_CONDONE_OE = 0
+ */
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
+ ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK);
+
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
+ ALT_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST_SET_MSK);
+
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
+ ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK |
+ ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK);
+
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
+ ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK);
+
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
+ ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NSTATUS_OE_SET_MSK |
+ ALT_FPGAMGR_IMGCFG_CTL_00_S2F_CONDONE_OE_SET_MSK);
+
+ /*
+ * Step 5:
+ * Enable overrides
+ * S2F_NENABLE_CONFIG = 0
+ * S2F_NENABLE_NCONFIG = 0
+ */
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
+ ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG_SET_MSK);
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
+ ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG_SET_MSK);
+
+ /*
+ * Disable driving signals that HPS doesn't need to drive.
+ * S2F_NENABLE_NSTATUS = 1
+ * S2F_NENABLE_CONDONE = 1
+ */
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
+ ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS_SET_MSK |
+ ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE_SET_MSK);
+
+ /*
+ * Step 6:
+ * Drive chip select S2F_NCE = 0
+ */
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
+ ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK);
+
+ /* Step 7 */
+ if (wait_for_nconfig_pin_and_nstatus_pin())
+ return -ETIME;
+
+ /* Step 8 */
+ ret = fpgamgr_reset();
+
+ if (ret)
+ return ret;
+
+ /*
+ * Step 9:
+ * EN_CFG_CTRL and EN_CFG_DATA = 1
+ */
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
+ ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK |
+ ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK);
+
+ return 0;
+}
+
+/* Ensure the FPGA entering config done */
+static int fpgamgr_program_poll_cd(void)
+{
+ unsigned long reg, i;
+
+ for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
+ reg = readl(&fpga_manager_base->imgcfg_stat);
+ if (reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK)
+ return 0;
+
+ if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK) == 0) {
+ printf("nstatus == 0 while waiting for condone\n");
+ return -EPERM;
+ }
+ schedule();
+ }
+
+ if (i == FPGA_TIMEOUT_CNT)
+ return -ETIME;
+
+ return 0;
+}
+
+/* Ensure the FPGA entering user mode */
+static int fpgamgr_program_poll_usermode(void)
+{
+ unsigned long reg;
+ int ret = 0;
+
+ if (fpgamgr_dclkcnt_set(0xf))
+ return -ETIME;
+
+ ret = wait_for_user_mode();
+ if (ret < 0) {
+ printf("%s: Failed to enter user mode with ", __func__);
+ printf("error code %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Step 14:
+ * Stop DATA path and Dclk
+ * EN_CFG_CTRL and EN_CFG_DATA = 0
+ */
+ clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02,
+ ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK |
+ ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK);
+
+ /*
+ * Step 15:
+ * Disable overrides
+ * S2F_NENABLE_CONFIG = 1
+ * S2F_NENABLE_NCONFIG = 1
+ */
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
+ ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG_SET_MSK);
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_00,
+ ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG_SET_MSK);
+
+ /* Disable chip select S2F_NCE = 1 */
+ setbits_le32(&fpga_manager_base->imgcfg_ctrl_01,
+ ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK);
+
+ /*
+ * Step 16:
+ * Final check
+ */
+ reg = readl(&fpga_manager_base->imgcfg_stat);
+ if (((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK) !=
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK) ||
+ ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) !=
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) ||
+ ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK) !=
+ ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK))
+ return -EPERM;
+
+ return 0;
+}
+
+int fpgamgr_program_finish(void)
+{
+ /* Ensure the FPGA entering config done */
+ int status = fpgamgr_program_poll_cd();
+
+ if (status) {
+ printf("FPGA: Poll CD failed with error code %d\n", status);
+ return -EPERM;
+ }
+
+ /* Ensure the FPGA entering user mode */
+ status = fpgamgr_program_poll_usermode();
+ if (status) {
+ printf("FPGA: Poll usermode failed with error code %d\n",
+ status);
+ return -EPERM;
+ }
+
+ printf("Full Configuration Succeeded.\n");
+
+ return 0;
+}
+
+ofnode get_fpga_mgr_ofnode(ofnode from)
+{
+ return ofnode_by_compatible(from, "altr,socfpga-a10-fpga-mgr");
+}
+
+const char *get_fpga_filename(void)
+{
+ const char *fpga_filename = NULL;
+
+ ofnode fpgamgr_node = get_fpga_mgr_ofnode(ofnode_null());
+
+ if (ofnode_valid(fpgamgr_node))
+ fpga_filename = ofnode_read_string(fpgamgr_node,
+ "altr,bitstream");
+
+ return fpga_filename;
+}
+
+static void get_rbf_image_info(struct rbf_info *rbf, u16 *buffer)
+{
+ /*
+ * Magic ID starting at:
+ * -> 1st dword[15:0] in periph.rbf
+ * -> 2nd dword[15:0] in core.rbf
+ * Note: dword == 32 bits
+ */
+ u32 word_reading_max = 2;
+ u32 i;
+
+ for (i = 0; i < word_reading_max; i++) {
+ if (*(buffer + i) == FPGA_SOCFPGA_A10_RBF_UNENCRYPTED) {
+ rbf->security = unencrypted;
+ } else if (*(buffer + i) == FPGA_SOCFPGA_A10_RBF_ENCRYPTED) {
+ rbf->security = encrypted;
+ } else if (*(buffer + i + 1) ==
+ FPGA_SOCFPGA_A10_RBF_UNENCRYPTED) {
+ rbf->security = unencrypted;
+ } else if (*(buffer + i + 1) ==
+ FPGA_SOCFPGA_A10_RBF_ENCRYPTED) {
+ rbf->security = encrypted;
+ } else {
+ rbf->security = invalid;
+ continue;
+ }
+
+ /* PERIPH RBF(buffer + i + 1), CORE RBF(buffer + i + 2) */
+ if (*(buffer + i + 1) == FPGA_SOCFPGA_A10_RBF_PERIPH) {
+ rbf->section = periph_section;
+ break;
+ } else if (*(buffer + i + 1) == FPGA_SOCFPGA_A10_RBF_CORE) {
+ rbf->section = core_section;
+ break;
+ } else if (*(buffer + i + 2) == FPGA_SOCFPGA_A10_RBF_PERIPH) {
+ rbf->section = periph_section;
+ break;
+ } else if (*(buffer + i + 2) == FPGA_SOCFPGA_A10_RBF_CORE) {
+ rbf->section = core_section;
+ break;
+ }
+
+ rbf->section = unknown;
+ break;
+
+ schedule();
+ }
+}
+
+#ifdef CONFIG_FS_LOADER
+static int first_loading_rbf_to_buffer(struct udevice *dev,
+ struct fpga_loadfs_info *fpga_loadfs,
+ u32 *buffer, size_t *buffer_bsize,
+ size_t *buffer_bsize_ori)
+{
+ u32 *buffer_p = (u32 *)*buffer;
+ u32 *loadable = buffer_p;
+ size_t buffer_size = *buffer_bsize;
+ size_t fit_size;
+ int ret, i, count, confs_noffset, images_noffset, rbf_offset, rbf_size;
+ const char *fpga_node_name = NULL;
+ const char *uname = NULL;
+
+ /* Load image header into buffer */
+ ret = request_firmware_into_buf(dev,
+ fpga_loadfs->fpga_fsinfo->filename,
+ buffer_p, sizeof(struct legacy_img_hdr),
+ 0);
+ if (ret < 0) {
+ debug("FPGA: Failed to read image header from flash.\n");
+ return -ENOENT;
+ }
+
+ if (image_get_magic((struct legacy_img_hdr *)buffer_p) != FDT_MAGIC) {
+ debug("FPGA: No FDT magic was found.\n");
+ return -EBADF;
+ }
+
+ fit_size = fdt_totalsize(buffer_p);
+
+ if (fit_size > buffer_size) {
+ debug("FPGA: FIT image is larger than available buffer.\n");
+ debug("Please use FIT external data or increasing buffer.\n");
+ return -ENOMEM;
+ }
+
+ /* Load entire FIT into buffer */
+ ret = request_firmware_into_buf(dev,
+ fpga_loadfs->fpga_fsinfo->filename,
+ buffer_p, fit_size, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = fit_check_format(buffer_p, IMAGE_SIZE_INVAL);
+ if (ret) {
+ debug("FPGA: No valid FIT image was found.\n");
+ return ret;
+ }
+
+ confs_noffset = fdt_path_offset(buffer_p, FIT_CONFS_PATH);
+ images_noffset = fdt_path_offset(buffer_p, FIT_IMAGES_PATH);
+ if (confs_noffset < 0 || images_noffset < 0) {
+ debug("FPGA: No Configurations or images nodes were found.\n");
+ return -ENOENT;
+ }
+
+ /* Get default configuration unit name from default property */
+ confs_noffset = fit_conf_get_node(buffer_p, NULL);
+ if (confs_noffset < 0) {
+ debug("FPGA: No default configuration was found in config.\n");
+ return -ENOENT;
+ }
+
+ count = fit_conf_get_prop_node_count(buffer_p, confs_noffset,
+ FIT_FPGA_PROP);
+ if (count < 0) {
+ debug("FPGA: Invalid configuration format for FPGA node.\n");
+ return count;
+ }
+ debug("FPGA: FPGA node count: %d\n", count);
+
+ for (i = 0; i < count; i++) {
+ images_noffset = fit_conf_get_prop_node_index(buffer_p,
+ confs_noffset,
+ FIT_FPGA_PROP, i);
+ uname = fit_get_name(buffer_p, images_noffset, NULL);
+ if (uname) {
+ debug("FPGA: %s\n", uname);
+
+ if (strstr(uname, "fpga-periph") &&
+ (!is_fpgamgr_early_user_mode() ||
+ is_fpgamgr_user_mode() ||
+ is_periph_program_force())) {
+ fpga_node_name = uname;
+ printf("FPGA: Start to program ");
+ printf("peripheral/full bitstream ...\n");
+ break;
+ } else if (strstr(uname, "fpga-core") &&
+ (is_fpgamgr_early_user_mode() &&
+ !is_fpgamgr_user_mode())) {
+ fpga_node_name = uname;
+ printf("FPGA: Start to program core ");
+ printf("bitstream ...\n");
+ break;
+ }
+ }
+ schedule();
+ }
+
+ if (!fpga_node_name) {
+ debug("FPGA: No suitable bitstream was found, count: %d.\n", i);
+ return 1;
+ }
+
+ images_noffset = fit_image_get_node(buffer_p, fpga_node_name);
+ if (images_noffset < 0) {
+ debug("FPGA: No node '%s' was found in FIT.\n",
+ fpga_node_name);
+ return -ENOENT;
+ }
+
+ if (!fit_image_get_data_position(buffer_p, images_noffset,
+ &rbf_offset)) {
+ debug("FPGA: Data position was found.\n");
+ } else if (!fit_image_get_data_offset(buffer_p, images_noffset,
+ &rbf_offset)) {
+ /*
+ * For FIT with external data, figure out where
+ * the external images start. This is the base
+ * for the data-offset properties in each image.
+ */
+ rbf_offset += ((fdt_totalsize(buffer_p) + 3) & ~3);
+ debug("FPGA: Data offset was found.\n");
+ } else {
+ debug("FPGA: No data position/offset was found.\n");
+ return -ENOENT;
+ }
+
+ ret = fit_image_get_data_size(buffer_p, images_noffset, &rbf_size);
+ if (ret < 0) {
+ debug("FPGA: No data size was found (err=%d).\n", ret);
+ return -ENOENT;
+ }
+
+ if (gd->ram_size < rbf_size) {
+ debug("FPGA: Using default OCRAM buffer and size.\n");
+ } else {
+ ret = fit_image_get_load(buffer_p, images_noffset,
+ (ulong *)loadable);
+ if (ret < 0) {
+ buffer_p = (u32 *)DEFAULT_DDR_LOAD_ADDRESS;
+ debug("FPGA: No loadable was found.\n");
+ debug("FPGA: Using default DDR load address: 0x%x .\n",
+ DEFAULT_DDR_LOAD_ADDRESS);
+ } else {
+ buffer_p = (u32 *)*loadable;
+ debug("FPGA: Found loadable address = 0x%x.\n",
+ *loadable);
+ }
+
+ buffer_size = rbf_size;
+ *buffer_bsize_ori = DDR_BUFFER_SIZE;
+ }
+
+ debug("FPGA: External data: offset = 0x%x, size = 0x%x.\n",
+ rbf_offset, rbf_size);
+
+ fpga_loadfs->remaining = rbf_size;
+
+ /*
+ * Determine buffer size vs bitstream size, and calculating number of
+ * chunk by chunk transfer is required due to smaller buffer size
+ * compare to bitstream
+ */
+
+ if (buffer_size > MAX_FIRST_LOAD_SIZE)
+ buffer_size = MAX_FIRST_LOAD_SIZE;
+
+ if (rbf_size <= buffer_size) {
+ /* Loading whole bitstream into buffer */
+ buffer_size = rbf_size;
+ fpga_loadfs->remaining = 0;
+ } else {
+ buffer_size -= rbf_offset % buffer_size;
+ fpga_loadfs->remaining -= buffer_size;
+ }
+
+ fpga_loadfs->offset = rbf_offset;
+ /* Loading bitstream into buffer */
+ ret = request_firmware_into_buf(dev,
+ fpga_loadfs->fpga_fsinfo->filename,
+ buffer_p, buffer_size,
+ fpga_loadfs->offset);
+ if (ret < 0) {
+ debug("FPGA: Failed to read bitstream from flash.\n");
+ return -ENOENT;
+ }
+
+ /* Getting info about bitstream types */
+ get_rbf_image_info(&fpga_loadfs->rbfinfo, (u16 *)buffer_p);
+
+ /* Update next reading bitstream offset */
+ fpga_loadfs->offset += buffer_size;
+
+ /* Update the final addr for bitstream */
+ *buffer = (u32)buffer_p;
+
+ /* Update the size of bitstream to be programmed into FPGA */
+ *buffer_bsize = buffer_size;
+
+ return 0;
+}
+
+static int subsequent_loading_rbf_to_buffer(struct udevice *dev,
+ struct fpga_loadfs_info *fpga_loadfs,
+ u32 *buffer, size_t *buffer_bsize)
+{
+ int ret = 0;
+ u32 *buffer_p = (u32 *)*buffer;
+
+ /* Read the bitstream chunk by chunk. */
+ if (fpga_loadfs->remaining > *buffer_bsize) {
+ fpga_loadfs->remaining -= *buffer_bsize;
+ } else {
+ *buffer_bsize = fpga_loadfs->remaining;
+ fpga_loadfs->remaining = 0;
+ }
+
+ ret = request_firmware_into_buf(dev,
+ fpga_loadfs->fpga_fsinfo->filename,
+ buffer_p, *buffer_bsize,
+ fpga_loadfs->offset);
+ if (ret < 0) {
+ debug("FPGA: Failed to read bitstream from flash.\n");
+ return -ENOENT;
+ }
+
+ /* Update next reading bitstream offset */
+ fpga_loadfs->offset += *buffer_bsize;
+
+ return 0;
+}
+
+int socfpga_loadfs(fpga_fs_info *fpga_fsinfo, const void *buf, size_t bsize,
+ u32 offset)
+{
+ struct fpga_loadfs_info fpga_loadfs;
+ struct udevice *dev;
+ int status, ret;
+ u32 buffer = (uintptr_t)buf;
+ size_t buffer_sizebytes = bsize;
+ size_t buffer_sizebytes_ori = bsize;
+ size_t total_sizeof_image = 0;
+ ofnode node;
+
+ node = get_fpga_mgr_ofnode(ofnode_null());
+ if (!ofnode_valid(node)) {
+ debug("FPGA: FPGA manager node was not found.\n");
+ return -ENOENT;
+ }
+
+ ret = get_fs_loader(&dev);
+ if (ret)
+ return ret;
+
+ memset(&fpga_loadfs, 0, sizeof(fpga_loadfs));
+
+ fpga_loadfs.fpga_fsinfo = fpga_fsinfo;
+ fpga_loadfs.offset = offset;
+
+ printf("FPGA: Checking FPGA configuration setting ...\n");
+
+ /*
+ * Note: Both buffer and buffer_sizebytes values can be altered by
+ * function below.
+ */
+ ret = first_loading_rbf_to_buffer(dev, &fpga_loadfs, &buffer,
+ &buffer_sizebytes,
+ &buffer_sizebytes_ori);
+ if (ret == 1) {
+ printf("FPGA: Skipping configuration ...\n");
+ return 0;
+ } else if (ret) {
+ return ret;
+ }
+
+ if (fpga_loadfs.rbfinfo.section == core_section &&
+ !(is_fpgamgr_early_user_mode() && !is_fpgamgr_user_mode())) {
+ debug("FPGA : Must be in Early Release mode to program ");
+ debug("core bitstream.\n");
+ return -EPERM;
+ }
+
+ /* Disable all signals from HPS peripheral controller to FPGA */
+ writel(0, socfpga_get_sysmgr_addr() + SYSMGR_A10_FPGAINTF_EN_GLOBAL);
+
+ /* Disable all axi bridges (hps2fpga, lwhps2fpga & fpga2hps) */
+ socfpga_bridges_reset();
+
+ if (fpga_loadfs.rbfinfo.section == periph_section) {
+ /* Initialize the FPGA Manager */
+ status = fpgamgr_program_init((u32 *)buffer, buffer_sizebytes);
+ if (status) {
+ debug("FPGA: Init with peripheral bitstream failed.\n");
+ return -EPERM;
+ }
+ }
+
+ /* Transfer bitstream to FPGA Manager */
+ fpgamgr_program_write((void *)buffer, buffer_sizebytes);
+
+ total_sizeof_image += buffer_sizebytes;
+
+ while (fpga_loadfs.remaining) {
+ ret = subsequent_loading_rbf_to_buffer(dev,
+ &fpga_loadfs,
+ &buffer,
+ &buffer_sizebytes_ori);
+
+ if (ret)
+ return ret;
+
+ /* Transfer data to FPGA Manager */
+ fpgamgr_program_write((void *)buffer,
+ buffer_sizebytes_ori);
+
+ total_sizeof_image += buffer_sizebytes_ori;
+
+ schedule();
+ }
+ wait_for_fifo_empty();
+
+ if (fpga_loadfs.rbfinfo.section == periph_section) {
+ if (fpgamgr_wait_early_user_mode() != -ETIMEDOUT) {
+ config_pins(gd->fdt_blob, "shared");
+ puts("FPGA: Early Release Succeeded.\n");
+ } else {
+ debug("FPGA: Failed to see Early Release.\n");
+ return -EIO;
+ }
+
+ /* For monolithic bitstream */
+ if (is_fpgamgr_user_mode()) {
+ /* Ensure the FPGA entering config done */
+ status = fpgamgr_program_finish();
+ if (status)
+ return status;
+
+ config_pins(gd->fdt_blob, "fpga");
+ puts("FPGA: Enter user mode.\n");
+ }
+ } else if (fpga_loadfs.rbfinfo.section == core_section) {
+ /* Ensure the FPGA entering config done */
+ status = fpgamgr_program_finish();
+ if (status)
+ return status;
+
+ config_pins(gd->fdt_blob, "fpga");
+ puts("FPGA: Enter user mode.\n");
+ } else {
+ debug("FPGA: Config Error: Unsupported bitstream type.\n");
+ return -ENOEXEC;
+ }
+
+ return (int)total_sizeof_image;
+}
+
+void fpgamgr_program(const void *buf, size_t bsize, u32 offset)
+{
+ fpga_fs_info fpga_fsinfo;
+
+ fpga_fsinfo.filename = get_fpga_filename();
+
+ if (fpga_fsinfo.filename)
+ socfpga_loadfs(&fpga_fsinfo, buf, bsize, offset);
+}
+#endif
+
+/* This function is used to load the core bitstream from the OCRAM. */
+int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
+{
+ unsigned long status;
+ struct rbf_info rbfinfo;
+
+ memset(&rbfinfo, 0, sizeof(rbfinfo));
+
+ /* Disable all signals from hps peripheral controller to fpga */
+ writel(0, socfpga_get_sysmgr_addr() + SYSMGR_A10_FPGAINTF_EN_GLOBAL);
+
+ /* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */
+ socfpga_bridges_reset();
+
+ /* Getting info about bitstream types */
+ get_rbf_image_info(&rbfinfo, (u16 *)rbf_data);
+
+ if (rbfinfo.section == periph_section) {
+ /* Initialize the FPGA Manager */
+ status = fpgamgr_program_init((u32 *)rbf_data, rbf_size);
+ if (status)
+ return status;
+ }
+
+ if (rbfinfo.section == core_section &&
+ !(is_fpgamgr_early_user_mode() && !is_fpgamgr_user_mode())) {
+ debug("FPGA : Must be in early release mode to program ");
+ debug("core bitstream.\n");
+ return -EPERM;
+ }
+
+ /* Write the bitstream to FPGA Manager */
+ fpgamgr_program_write(rbf_data, rbf_size);
+
+ status = fpgamgr_program_finish();
+ if (status)
+ return status;
+
+ config_pins(gd->fdt_blob, "fpga");
+ puts("FPGA: Enter user mode.\n");
+
+ return status;
+}
diff --git a/drivers/fpga/socfpga_gen5.c b/drivers/fpga/socfpga_gen5.c
new file mode 100644
index 00000000000..9473f057328
--- /dev/null
+++ b/drivers/fpga/socfpga_gen5.c
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (C) 2012 Altera Corporation <www.altera.com>
+ * All rights reserved.
+ */
+
+#include <config.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <asm/arch/fpga_manager.h>
+#include <asm/arch/reset_manager.h>
+#include <asm/arch/system_manager.h>
+
+#define FPGA_TIMEOUT_CNT 0x1000000
+
+static struct socfpga_fpga_manager *fpgamgr_regs =
+ (struct socfpga_fpga_manager *)SOCFPGA_FPGAMGRREGS_ADDRESS;
+
+/* Set CD ratio */
+static void fpgamgr_set_cd_ratio(unsigned long ratio)
+{
+ clrsetbits_le32(&fpgamgr_regs->ctrl,
+ 0x3 << FPGAMGRREGS_CTRL_CDRATIO_LSB,
+ (ratio & 0x3) << FPGAMGRREGS_CTRL_CDRATIO_LSB);
+}
+
+/* Start the FPGA programming by initialize the FPGA Manager */
+static int fpgamgr_program_init(void)
+{
+ unsigned long msel, i;
+
+ /* Get the MSEL value */
+ msel = readl(&fpgamgr_regs->stat);
+ msel &= FPGAMGRREGS_STAT_MSEL_MASK;
+ msel >>= FPGAMGRREGS_STAT_MSEL_LSB;
+
+ /*
+ * Set the cfg width
+ * If MSEL[3] = 1, cfg width = 32 bit
+ */
+ if (msel & 0x8) {
+ setbits_le32(&fpgamgr_regs->ctrl,
+ FPGAMGRREGS_CTRL_CFGWDTH_MASK);
+
+ /* To determine the CD ratio */
+ /* MSEL[1:0] = 0, CD Ratio = 1 */
+ if ((msel & 0x3) == 0x0)
+ fpgamgr_set_cd_ratio(CDRATIO_x1);
+ /* MSEL[1:0] = 1, CD Ratio = 4 */
+ else if ((msel & 0x3) == 0x1)
+ fpgamgr_set_cd_ratio(CDRATIO_x4);
+ /* MSEL[1:0] = 2, CD Ratio = 8 */
+ else if ((msel & 0x3) == 0x2)
+ fpgamgr_set_cd_ratio(CDRATIO_x8);
+
+ } else { /* MSEL[3] = 0 */
+ clrbits_le32(&fpgamgr_regs->ctrl,
+ FPGAMGRREGS_CTRL_CFGWDTH_MASK);
+
+ /* To determine the CD ratio */
+ /* MSEL[1:0] = 0, CD Ratio = 1 */
+ if ((msel & 0x3) == 0x0)
+ fpgamgr_set_cd_ratio(CDRATIO_x1);
+ /* MSEL[1:0] = 1, CD Ratio = 2 */
+ else if ((msel & 0x3) == 0x1)
+ fpgamgr_set_cd_ratio(CDRATIO_x2);
+ /* MSEL[1:0] = 2, CD Ratio = 4 */
+ else if ((msel & 0x3) == 0x2)
+ fpgamgr_set_cd_ratio(CDRATIO_x4);
+ }
+
+ /* To enable FPGA Manager configuration */
+ clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCE_MASK);
+
+ /* To enable FPGA Manager drive over configuration line */
+ setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK);
+
+ /* Put FPGA into reset phase */
+ setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK);
+
+ /* (1) wait until FPGA enter reset phase */
+ for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
+ if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_RESETPHASE)
+ break;
+ }
+
+ /* If not in reset state, return error */
+ if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_RESETPHASE) {
+ puts("FPGA: Could not reset\n");
+ return -1;
+ }
+
+ /* Release FPGA from reset phase */
+ clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK);
+
+ /* (2) wait until FPGA enter configuration phase */
+ for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
+ if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_CFGPHASE)
+ break;
+ }
+
+ /* If not in configuration state, return error */
+ if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_CFGPHASE) {
+ puts("FPGA: Could not configure\n");
+ return -2;
+ }
+
+ /* Clear all interrupts in CB Monitor */
+ writel(0xFFF, &fpgamgr_regs->gpio_porta_eoi);
+
+ /* Enable AXI configuration */
+ setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK);
+
+ return 0;
+}
+
+/* Ensure the FPGA entering config done */
+static int fpgamgr_program_poll_cd(void)
+{
+ const uint32_t mask = FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK |
+ FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK;
+ unsigned long reg, i;
+
+ /* (3) wait until full config done */
+ for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
+ reg = readl(&fpgamgr_regs->gpio_ext_porta);
+
+ /* Config error */
+ if (!(reg & mask)) {
+ printf("FPGA: Configuration error.\n");
+ return -3;
+ }
+
+ /* Config done without error */
+ if (reg & mask)
+ break;
+ }
+
+ /* Timeout happened, return error */
+ if (i == FPGA_TIMEOUT_CNT) {
+ printf("FPGA: Timeout waiting for program.\n");
+ return -4;
+ }
+
+ /* Disable AXI configuration */
+ clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK);
+
+ return 0;
+}
+
+/* Ensure the FPGA entering init phase */
+static int fpgamgr_program_poll_initphase(void)
+{
+ unsigned long i;
+
+ /* Additional clocks for the CB to enter initialization phase */
+ if (fpgamgr_dclkcnt_set(0x4))
+ return -5;
+
+ /* (4) wait until FPGA enter init phase or user mode */
+ for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
+ if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_INITPHASE)
+ break;
+ if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE)
+ break;
+ }
+
+ /* If not in configuration state, return error */
+ if (i == FPGA_TIMEOUT_CNT)
+ return -6;
+
+ return 0;
+}
+
+/* Ensure the FPGA entering user mode */
+static int fpgamgr_program_poll_usermode(void)
+{
+ unsigned long i;
+
+ /* Additional clocks for the CB to exit initialization phase */
+ if (fpgamgr_dclkcnt_set(0x5000))
+ return -7;
+
+ /* (5) wait until FPGA enter user mode */
+ for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
+ if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE)
+ break;
+ }
+ /* If not in configuration state, return error */
+ if (i == FPGA_TIMEOUT_CNT)
+ return -8;
+
+ /* To release FPGA Manager drive over configuration line */
+ clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK);
+
+ return 0;
+}
+
+/*
+ * FPGA Manager to program the FPGA. This is the interface used by FPGA driver.
+ * Return 0 for sucess, non-zero for error.
+ */
+int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
+{
+ int status;
+
+ if ((uint32_t)rbf_data & 0x3) {
+ puts("FPGA: Unaligned data, realign to 32bit boundary.\n");
+ return -EINVAL;
+ }
+
+ /* Prior programming the FPGA, all bridges need to be shut off */
+
+ /* Disable all signals from hps peripheral controller to fpga */
+ writel(0, socfpga_get_sysmgr_addr() + SYSMGR_GEN5_FPGAINFGRP_MODULE);
+
+ /* Disable all signals from FPGA to HPS SDRAM */
+#define SDR_CTRLGRP_FPGAPORTRST_ADDRESS 0x5080
+ writel(0, SOCFPGA_SDR_ADDRESS + SDR_CTRLGRP_FPGAPORTRST_ADDRESS);
+
+ /* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */
+ socfpga_bridges_reset(1);
+
+ /* Unmap the bridges from NIC-301 */
+ writel(0x1, SOCFPGA_L3REGS_ADDRESS);
+
+ /* Initialize the FPGA Manager */
+ status = fpgamgr_program_init();
+ if (status)
+ return status;
+
+ /* Write the RBF data to FPGA Manager */
+ fpgamgr_program_write(rbf_data, rbf_size);
+
+ /* Ensure the FPGA entering config done */
+ status = fpgamgr_program_poll_cd();
+ if (status)
+ return status;
+
+ /* Ensure the FPGA entering init phase */
+ status = fpgamgr_program_poll_initphase();
+ if (status)
+ return status;
+
+ /* Ensure the FPGA entering user mode */
+ return fpgamgr_program_poll_usermode();
+}
diff --git a/drivers/fpga/spartan2.c b/drivers/fpga/spartan2.c
new file mode 100644
index 00000000000..792e4033428
--- /dev/null
+++ b/drivers/fpga/spartan2.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ */
+
+#define LOG_CATEGORY UCLASS_FPGA
+
+#include <config.h> /* core U-Boot definitions */
+#include <log.h>
+#include <spartan2.h> /* Spartan-II device family */
+#include <time.h>
+
+/* Note: The assumption is that we cannot possibly run fast enough to
+ * overrun the device (the Slave Parallel mode can free run at 50MHz).
+ * If there is a need to operate slower, define CFG_FPGA_DELAY in
+ * the board config file to slow things down.
+ */
+#ifndef CFG_FPGA_DELAY
+#define CFG_FPGA_DELAY()
+#endif
+
+#ifndef CFG_SYS_FPGA_WAIT
+#define CFG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
+#endif
+
+static int spartan2_sp_load(xilinx_desc *desc, const void *buf, size_t bsize);
+static int spartan2_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize);
+/* static int spartan2_sp_info(xilinx_desc *desc ); */
+
+static int spartan2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize);
+static int spartan2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
+/* static int spartan2_ss_info(xilinx_desc *desc ); */
+
+/* ------------------------------------------------------------------------- */
+/* Spartan-II Generic Implementation */
+static int spartan2_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype, int flags)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ log_debug("Launching Slave Serial Load\n");
+ ret_val = spartan2_ss_load(desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ log_debug("Launching Slave Parallel Load\n");
+ ret_val = spartan2_sp_load(desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+static int spartan2_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ log_debug("Launching Slave Serial Dump\n");
+ ret_val = spartan2_ss_dump(desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ log_debug("Launching Slave Parallel Dump\n");
+ ret_val = spartan2_sp_dump(desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+static int spartan2_info(xilinx_desc *desc)
+{
+ return FPGA_SUCCESS;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Spartan-II Slave Parallel Generic Implementation */
+
+static int spartan2_sp_load(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ xilinx_spartan2_slave_parallel_fns *fn = desc->iface_fns;
+
+ log_debug("start with interface functions @ 0x%p\n", fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ log_debug("Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "pre: 0x%p\n"
+ "pgm:\t0x%p\n"
+ "init:\t0x%p\n"
+ "err:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "cs:\t0x%p\n"
+ "wr:\t0x%p\n"
+ "read data:\t0x%p\n"
+ "write data:\t0x%p\n"
+ "busy:\t0x%p\n"
+ "abort:\t0x%p\n"
+ "post:\t0x%p\n\n",
+ &fn, fn, fn->pre, fn->pgm, fn->init, fn->err,
+ fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy,
+ fn->abort, fn->post);
+
+ /*
+ * This code is designed to emulate the "Express Style"
+ * Continuous Data Loading in Slave Parallel Mode for
+ * the Spartan-II Family.
+ */
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...\n", cookie);
+#endif
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->pgm) (true, true, cookie); /* Assert the program, commit */
+
+ /* Get ready for the burn */
+ CFG_FPGA_DELAY ();
+ (*fn->pgm) (false, true, cookie); /* Deassert the program, commit */
+
+ ts = get_timer (0); /* get current time */
+ /* Now wait for INIT and BUSY to go high */
+ do {
+ CFG_FPGA_DELAY ();
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init) (cookie) && (*fn->busy) (cookie));
+
+ (*fn->wr) (true, true, cookie); /* Assert write, commit */
+ (*fn->cs) (true, true, cookie); /* Assert chip select, commit */
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ /* Load the data */
+ while (bytecount < bsize) {
+ /* XXX - do we check for an Ctrl-C press in here ??? */
+ /* XXX - Check the error bit? */
+
+ (*fn->wdata) (data[bytecount++], true, cookie); /* write the data */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
+ ts = get_timer (0); /* get current time */
+ while ((*fn->busy) (cookie)) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for BUSY to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ return FPGA_FAIL;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ CFG_FPGA_DELAY ();
+ (*fn->cs) (false, true, cookie); /* Deassert the chip select */
+ (*fn->wr) (false, true, cookie); /* Deassert the write pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+
+ /* now check for done signal */
+ ts = get_timer (0); /* get current time */
+ ret_val = FPGA_SUCCESS;
+ while ((*fn->done) (cookie) == FPGA_FAIL) {
+
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for DONE to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ }
+
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post)
+ (*fn->post) (cookie);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS)
+ puts ("Done.\n");
+ else
+ puts ("Fail.\n");
+#endif
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int spartan2_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ xilinx_spartan2_slave_parallel_fns *fn = desc->iface_fns;
+
+ if (fn) {
+ unsigned char *data = (unsigned char *) buf;
+ size_t bytecount = 0;
+ int cookie = desc->cookie; /* make a local copy */
+
+ printf ("Starting Dump of FPGA Device %d...\n", cookie);
+
+ (*fn->cs) (true, true, cookie); /* Assert chip select, commit */
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ /* dump the data */
+ while (bytecount < bsize) {
+ /* XXX - do we check for an Ctrl-C press in here ??? */
+
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+ (*fn->rdata) (&(data[bytecount++]), cookie); /* read the data */
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ (*fn->cs) (false, false, cookie); /* Deassert the chip select */
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+ puts ("Done.\n");
+
+ /* XXX - checksum the data? */
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int spartan2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ xilinx_spartan2_slave_serial_fns *fn = desc->iface_fns;
+ int i;
+ unsigned char val;
+
+ log_debug("start with interface functions @ 0x%p\n", fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ log_debug("Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "pgm:\t0x%p\n"
+ "init:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "wr:\t0x%p\n"
+ "done:\t0x%p\n\n",
+ &fn, fn, fn->pgm, fn->init,
+ fn->clk, fn->wr, fn->done);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...\n", cookie);
+#endif
+
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->pgm) (true, true, cookie); /* Assert the program, commit */
+
+ /* Wait for INIT state (init low) */
+ ts = get_timer (0); /* get current time */
+ do {
+ CFG_FPGA_DELAY ();
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to start.\n");
+ return FPGA_FAIL;
+ }
+ } while (!(*fn->init) (cookie));
+
+ /* Get ready for the burn */
+ CFG_FPGA_DELAY ();
+ (*fn->pgm) (false, true, cookie); /* Deassert the program, commit */
+
+ ts = get_timer (0); /* get current time */
+ /* Now wait for INIT to go high */
+ do {
+ CFG_FPGA_DELAY ();
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to clear.\n");
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init) (cookie));
+
+ /* Load the data */
+ while (bytecount < bsize) {
+
+ /* Xilinx detects an error if INIT goes low (active)
+ while DONE is low (inactive) */
+ if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
+ puts ("** CRC error during FPGA load.\n");
+ return (FPGA_FAIL);
+ }
+ val = data [bytecount ++];
+ i = 8;
+ do {
+ /* Deassert the clock */
+ (*fn->clk) (false, true, cookie);
+ CFG_FPGA_DELAY ();
+ /* Write data */
+ (*fn->wr) ((val & 0x80), true, cookie);
+ CFG_FPGA_DELAY ();
+ /* Assert the clock */
+ (*fn->clk) (true, true, cookie);
+ CFG_FPGA_DELAY ();
+ val <<= 1;
+ i --;
+ } while (i > 0);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ CFG_FPGA_DELAY ();
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+
+ /* now check for done signal */
+ ts = get_timer (0); /* get current time */
+ ret_val = FPGA_SUCCESS;
+ (*fn->wr) (true, true, cookie);
+
+ while (! (*fn->done) (cookie)) {
+
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ putc ('*');
+
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for DONE to clear.\n");
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ }
+ putc ('\n'); /* terminate the dotted line */
+
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post)
+ (*fn->post) (cookie);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS)
+ puts ("Done.\n");
+ else
+ puts ("Fail.\n");
+#endif
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int spartan2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ /* Readback is only available through the Slave Parallel and */
+ /* boundary-scan interfaces. */
+ printf ("%s: Slave Serial Dumping is unavailable\n",
+ __FUNCTION__);
+ return FPGA_FAIL;
+}
+
+struct xilinx_fpga_op spartan2_op = {
+ .load = spartan2_load,
+ .dump = spartan2_dump,
+ .info = spartan2_info,
+};
diff --git a/drivers/fpga/spartan3.c b/drivers/fpga/spartan3.c
new file mode 100644
index 00000000000..98405589134
--- /dev/null
+++ b/drivers/fpga/spartan3.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ */
+
+/*
+ * Configuration support for Xilinx Spartan3 devices. Based
+ * on spartan2.c (Rich Ireland, rireland@enterasys.com).
+ */
+
+#define LOG_CATEGORY UCLASS_FPGA
+
+#include <config.h> /* core U-Boot definitions */
+#include <log.h>
+#include <time.h>
+#include <spartan3.h> /* Spartan-II device family */
+
+/* Note: The assumption is that we cannot possibly run fast enough to
+ * overrun the device (the Slave Parallel mode can free run at 50MHz).
+ * If there is a need to operate slower, define CFG_FPGA_DELAY in
+ * the board config file to slow things down.
+ */
+#ifndef CFG_FPGA_DELAY
+#define CFG_FPGA_DELAY()
+#endif
+
+#ifndef CFG_SYS_FPGA_WAIT
+#define CFG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
+#endif
+
+static int spartan3_sp_load(xilinx_desc *desc, const void *buf, size_t bsize);
+static int spartan3_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize);
+/* static int spartan3_sp_info(xilinx_desc *desc ); */
+
+static int spartan3_ss_load(xilinx_desc *desc, const void *buf, size_t bsize);
+static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
+/* static int spartan3_ss_info(xilinx_desc *desc); */
+
+/* ------------------------------------------------------------------------- */
+/* Spartan-II Generic Implementation */
+static int spartan3_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype, int flags)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ log_debug("Launching Slave Serial Load\n");
+ ret_val = spartan3_ss_load(desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ log_debug("Launching Slave Parallel Load\n");
+ ret_val = spartan3_sp_load(desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+static int spartan3_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ log_debug("Launching Slave Serial Dump\n");
+ ret_val = spartan3_ss_dump(desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ log_debug("Launching Slave Parallel Dump\n");
+ ret_val = spartan3_sp_dump(desc, buf, bsize);
+ break;
+
+ default:
+ printf ("%s: Unsupported interface type, %d\n",
+ __FUNCTION__, desc->iface);
+ }
+
+ return ret_val;
+}
+
+static int spartan3_info(xilinx_desc *desc)
+{
+ return FPGA_SUCCESS;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Spartan-II Slave Parallel Generic Implementation */
+
+static int spartan3_sp_load(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ xilinx_spartan3_slave_parallel_fns *fn = desc->iface_fns;
+
+ log_debug("start with interface functions @ 0x%p\n", fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ log_debug("Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "pre: 0x%p\n"
+ "pgm:\t0x%p\n"
+ "init:\t0x%p\n"
+ "err:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "cs:\t0x%p\n"
+ "wr:\t0x%p\n"
+ "read data:\t0x%p\n"
+ "write data:\t0x%p\n"
+ "busy:\t0x%p\n"
+ "abort:\t0x%p\n"
+ "post:\t0x%p\n\n",
+ &fn, fn, fn->pre, fn->pgm, fn->init, fn->err,
+ fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata, fn->busy,
+ fn->abort, fn->post);
+
+ /*
+ * This code is designed to emulate the "Express Style"
+ * Continuous Data Loading in Slave Parallel Mode for
+ * the Spartan-II Family.
+ */
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...\n", cookie);
+#endif
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->pgm) (true, true, cookie); /* Assert the program, commit */
+
+ /* Get ready for the burn */
+ CFG_FPGA_DELAY ();
+ (*fn->pgm) (false, true, cookie); /* Deassert the program, commit */
+
+ ts = get_timer (0); /* get current time */
+ /* Now wait for INIT and BUSY to go high */
+ do {
+ CFG_FPGA_DELAY ();
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init) (cookie) && (*fn->busy) (cookie));
+
+ (*fn->wr) (true, true, cookie); /* Assert write, commit */
+ (*fn->cs) (true, true, cookie); /* Assert chip select, commit */
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ /* Load the data */
+ while (bytecount < bsize) {
+ /* XXX - do we check for an Ctrl-C press in here ??? */
+ /* XXX - Check the error bit? */
+
+ (*fn->wdata) (data[bytecount++], true, cookie); /* write the data */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
+ ts = get_timer (0); /* get current time */
+ while ((*fn->busy) (cookie)) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for BUSY to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ return FPGA_FAIL;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ CFG_FPGA_DELAY ();
+ (*fn->cs) (false, true, cookie); /* Deassert the chip select */
+ (*fn->wr) (false, true, cookie); /* Deassert the write pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+
+ /* now check for done signal */
+ ts = get_timer (0); /* get current time */
+ ret_val = FPGA_SUCCESS;
+ while ((*fn->done) (cookie) == FPGA_FAIL) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for DONE to clear.\n");
+ (*fn->abort) (cookie); /* abort the burn */
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ }
+
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post)
+ (*fn->post) (cookie);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS)
+ puts ("Done.\n");
+ else
+ puts ("Fail.\n");
+#endif
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int spartan3_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ xilinx_spartan3_slave_parallel_fns *fn = desc->iface_fns;
+
+ if (fn) {
+ unsigned char *data = (unsigned char *) buf;
+ size_t bytecount = 0;
+ int cookie = desc->cookie; /* make a local copy */
+
+ printf ("Starting Dump of FPGA Device %d...\n", cookie);
+
+ (*fn->cs) (true, true, cookie); /* Assert chip select, commit */
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ /* dump the data */
+ while (bytecount < bsize) {
+ /* XXX - do we check for an Ctrl-C press in here ??? */
+
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+ (*fn->rdata) (&(data[bytecount++]), cookie); /* read the data */
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+
+ (*fn->cs) (false, false, cookie); /* Deassert the chip select */
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+ puts ("Done.\n");
+
+ /* XXX - checksum the data? */
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int spartan3_ss_load(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL; /* assume the worst */
+ xilinx_spartan3_slave_serial_fns *fn = desc->iface_fns;
+ int i;
+ unsigned char val;
+
+ log_debug("start with interface functions @ 0x%p\n", fn);
+
+ if (fn) {
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *) buf;
+ int cookie = desc->cookie; /* make a local copy */
+ unsigned long ts; /* timestamp */
+
+ log_debug("Function Table:\n"
+ "ptr:\t0x%p\n"
+ "struct: 0x%p\n"
+ "pgm:\t0x%p\n"
+ "init:\t0x%p\n"
+ "clk:\t0x%p\n"
+ "wr:\t0x%p\n"
+ "done:\t0x%p\n\n",
+ &fn, fn, fn->pgm, fn->init,
+ fn->clk, fn->wr, fn->done);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf ("Loading FPGA Device %d...\n", cookie);
+#endif
+
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre) {
+ (*fn->pre) (cookie);
+ }
+
+ /* Establish the initial state */
+ (*fn->pgm) (true, true, cookie); /* Assert the program, commit */
+
+ /* Wait for INIT state (init low) */
+ ts = get_timer (0); /* get current time */
+ do {
+ CFG_FPGA_DELAY ();
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to start.\n");
+ if (*fn->abort)
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+ } while (!(*fn->init) (cookie));
+
+ /* Get ready for the burn */
+ CFG_FPGA_DELAY ();
+ (*fn->pgm) (false, true, cookie); /* Deassert the program, commit */
+
+ ts = get_timer (0); /* get current time */
+ /* Now wait for INIT to go high */
+ do {
+ CFG_FPGA_DELAY ();
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for INIT to clear.\n");
+ if (*fn->abort)
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init) (cookie));
+
+ /* Load the data */
+ if(*fn->bwr)
+ (*fn->bwr) (data, bsize, true, cookie);
+ else {
+ while (bytecount < bsize) {
+
+ /* Xilinx detects an error if INIT goes low (active)
+ while DONE is low (inactive) */
+ if ((*fn->done) (cookie) == 0 && (*fn->init) (cookie)) {
+ puts ("** CRC error during FPGA load.\n");
+ if (*fn->abort)
+ (*fn->abort) (cookie);
+ return (FPGA_FAIL);
+ }
+ val = data [bytecount ++];
+ i = 8;
+ do {
+ /* Deassert the clock */
+ (*fn->clk) (false, true, cookie);
+ CFG_FPGA_DELAY ();
+ /* Write data */
+ (*fn->wr) ((val & 0x80), true, cookie);
+ CFG_FPGA_DELAY ();
+ /* Assert the clock */
+ (*fn->clk) (true, true, cookie);
+ CFG_FPGA_DELAY ();
+ val <<= 1;
+ i --;
+ } while (i > 0);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc ('.'); /* let them know we are alive */
+#endif
+ }
+ }
+
+ CFG_FPGA_DELAY ();
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc ('\n'); /* terminate the dotted line */
+#endif
+
+ /* now check for done signal */
+ ts = get_timer (0); /* get current time */
+ ret_val = FPGA_SUCCESS;
+ (*fn->wr) (true, true, cookie);
+
+ while (! (*fn->done) (cookie)) {
+ /* XXX - we should have a check in here somewhere to
+ * make sure we aren't busy forever... */
+
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (false, true, cookie); /* Deassert the clock pin */
+ CFG_FPGA_DELAY ();
+ (*fn->clk) (true, true, cookie); /* Assert the clock pin */
+
+ putc ('*');
+
+ if (get_timer (ts) > CFG_SYS_FPGA_WAIT) { /* check the time */
+ puts ("** Timeout waiting for DONE to clear.\n");
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ }
+ putc ('\n'); /* terminate the dotted line */
+
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post)
+ (*fn->post) (cookie);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (ret_val == FPGA_SUCCESS)
+ puts ("Done.\n");
+ else
+ puts ("Fail.\n");
+#endif
+
+ } else {
+ printf ("%s: NULL Interface function table!\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ /* Readback is only available through the Slave Parallel and */
+ /* boundary-scan interfaces. */
+ printf ("%s: Slave Serial Dumping is unavailable\n",
+ __FUNCTION__);
+ return FPGA_FAIL;
+}
+
+struct xilinx_fpga_op spartan3_op = {
+ .load = spartan3_load,
+ .dump = spartan3_dump,
+ .info = spartan3_info,
+};
diff --git a/drivers/fpga/stratixII.c b/drivers/fpga/stratixII.c
new file mode 100644
index 00000000000..3f984385316
--- /dev/null
+++ b/drivers/fpga/stratixII.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2007
+ * Eran Liberty, Extricom , eran.liberty@gmail.com
+ */
+
+#include <altera.h>
+#include <stratixII.h>
+#include <linux/delay.h>
+
+/****************************************************************/
+/* Stratix II Generic Implementation */
+int StratixII_ps_fpp_dump(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ printf("Stratix II Fast Passive Parallel dump is not implemented\n");
+ return FPGA_FAIL;
+}
+
+int StratixII_ps_fpp_load(Altera_desc *desc, const void *buf, size_t bsize,
+ int isSerial, int isSecure)
+{
+ altera_board_specific_func *fns;
+ int cookie;
+ int ret_val = FPGA_FAIL;
+ int bytecount;
+ const char *buff = buf;
+ int i;
+
+ if (!desc) {
+ log_err("Altera_desc missing\n");
+ return FPGA_FAIL;
+ }
+ if (!buff) {
+ log_err("buffer is missing\n");
+ return FPGA_FAIL;
+ }
+ if (!bsize) {
+ log_err("size is zero\n");
+ return FPGA_FAIL;
+ }
+ if (!desc->iface_fns) {
+ log_err("Altera_desc function interface table is missing\n");
+ return FPGA_FAIL;
+ }
+ fns = (altera_board_specific_func *) (desc->iface_fns);
+ cookie = desc->cookie;
+
+ if (!
+ (fns->config && fns->status && fns->done && fns->data
+ && fns->abort)) {
+ log_err("Missing some function in the function interface table\n");
+ return FPGA_FAIL;
+ }
+
+ /* 1. give board specific a chance to do anything before we start */
+ if (fns->pre) {
+ if ((ret_val = fns->pre (cookie)) < 0) {
+ return ret_val;
+ }
+ }
+
+ /* from this point on we must fail gracfully by calling lower layer abort */
+
+ /* 2. Strat burn cycle by deasserting config for t_CFG and waiting t_CF2CK after reaserted */
+ fns->config (0, 1, cookie);
+ udelay(5); /* nCONFIG low pulse width 2usec */
+ fns->config (1, 1, cookie);
+ udelay(100); /* nCONFIG high to first rising edge on DCLK */
+
+ /* 3. Start the Data cycle with clk deasserted */
+ bytecount = 0;
+ fns->clk (0, 1, cookie);
+
+ printf("loading to fpga ");
+ while (bytecount < bsize) {
+ /* 3.1 check stratix has not signaled us an error */
+ if (fns->status (cookie) != 1) {
+ log_err("\nStratix failed (byte transferred till failure 0x%x)\n",
+ bytecount);
+ fns->abort (cookie);
+ return FPGA_FAIL;
+ }
+ if (isSerial) {
+ int i;
+ uint8_t data = buff[bytecount++];
+ for (i = 0; i < 8; i++) {
+ /* 3.2(ps) put data on the bus */
+ fns->data ((data >> i) & 1, 1, cookie);
+
+ /* 3.3(ps) clock once */
+ fns->clk (1, 1, cookie);
+ fns->clk (0, 1, cookie);
+ }
+ } else {
+ /* 3.2(fpp) put data on the bus */
+ fns->data (buff[bytecount++], 1, cookie);
+
+ /* 3.3(fpp) clock once */
+ fns->clk (1, 1, cookie);
+ fns->clk (0, 1, cookie);
+
+ /* 3.4(fpp) for secure cycle push 3 more clocks */
+ for (i = 0; isSecure && i < 3; i++) {
+ fns->clk (1, 1, cookie);
+ fns->clk (0, 1, cookie);
+ }
+ }
+
+ /* 3.5 while clk is deasserted it is safe to print some progress indication */
+ if ((bytecount % (bsize / 100)) == 0) {
+ printf("\b\b\b%02zu\%%", bytecount * 100 / bsize);
+ }
+ }
+
+ /* 4. Set one last clock and check conf done signal */
+ fns->clk (1, 1, cookie);
+ udelay(100);
+ if (!fns->done (cookie)) {
+ printf(" error!.\n");
+ fns->abort (cookie);
+ return FPGA_FAIL;
+ } else {
+ printf("\b\b\b done.\n");
+ }
+
+ /* 5. call lower layer post configuration */
+ if (fns->post) {
+ if ((ret_val = fns->post (cookie)) < 0) {
+ fns->abort (cookie);
+ return ret_val;
+ }
+ }
+
+ return FPGA_SUCCESS;
+}
+
+int StratixII_load(Altera_desc *desc, const void *buf, size_t size)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ ret_val = StratixII_ps_fpp_load(desc, buf, size, 1, 0);
+ break;
+ case fast_passive_parallel:
+ ret_val = StratixII_ps_fpp_load(desc, buf, size, 0, 0);
+ break;
+ case fast_passive_parallel_security:
+ ret_val = StratixII_ps_fpp_load(desc, buf, size, 0, 1);
+ break;
+
+ /* Add new interface types here */
+ default:
+ log_err("Unsupported interface type, %d\n", desc->iface);
+ }
+ return ret_val;
+}
+
+int StratixII_dump(Altera_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case passive_serial:
+ case fast_passive_parallel:
+ case fast_passive_parallel_security:
+ ret_val = StratixII_ps_fpp_dump(desc, buf, bsize);
+ break;
+ /* Add new interface types here */
+ default:
+ log_err("Unsupported interface type, %d\n", desc->iface);
+ }
+ return ret_val;
+}
+
+int StratixII_info(Altera_desc *desc)
+{
+ return FPGA_SUCCESS;
+}
diff --git a/drivers/fpga/stratixv.c b/drivers/fpga/stratixv.c
new file mode 100644
index 00000000000..4b251994598
--- /dev/null
+++ b/drivers/fpga/stratixv.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ */
+
+#include <altera.h>
+#include <log.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+
+/* Write the RBF data to FPGA via SPI */
+static int program_write(int spi_bus, int spi_dev, const void *rbf_data,
+ unsigned long rbf_size)
+{
+ struct spi_slave *slave;
+ int ret;
+
+ debug("%s (%d): data=%p size=%ld\n",
+ __func__, __LINE__, rbf_data, rbf_size);
+
+ /* FIXME: How to get the max. SPI clock and SPI mode? */
+ slave = spi_setup_slave(spi_bus, spi_dev, 27777777, SPI_MODE_3);
+ if (!slave)
+ return -1;
+
+ if (spi_claim_bus(slave))
+ return -1;
+
+ ret = spi_xfer(slave, rbf_size * 8, rbf_data, (void *)rbf_data,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+
+ spi_release_bus(slave);
+
+ return ret;
+}
+
+/*
+ * This is the interface used by FPGA driver.
+ * Return 0 for sucess, non-zero for error.
+ */
+int stratixv_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
+{
+ altera_board_specific_func *pfns = desc->iface_fns;
+ int cookie = desc->cookie;
+ int spi_bus;
+ int spi_dev;
+ int ret = 0;
+
+ if ((size_t)rbf_data & 0x3) {
+ puts("FPGA: Unaligned data, realign to 32bit boundary.\n");
+ return -EINVAL;
+ }
+
+ /* Run the pre configuration function if there is one */
+ if (pfns->pre)
+ (pfns->pre)(cookie);
+
+ /* Establish the initial state */
+ if (pfns->config) {
+ /* De-assert nCONFIG */
+ (pfns->config)(false, true, cookie);
+
+ /* nConfig minimum low pulse width is 2us */
+ udelay(200);
+
+ /* Assert nCONFIG */
+ (pfns->config)(true, true, cookie);
+
+ /* nCONFIG high to first rising clock on DCLK min 1506 us */
+ udelay(1600);
+ }
+
+ /* Write the RBF data to FPGA */
+ if (pfns->write) {
+ /*
+ * Use board specific data function to write bitstream
+ * into the FPGA
+ */
+ ret = (pfns->write)(rbf_data, rbf_size, true, cookie);
+ } else {
+ /*
+ * Use common SPI functions to write bitstream into the
+ * FPGA
+ */
+ spi_bus = COOKIE2SPI_BUS(cookie);
+ spi_dev = COOKIE2SPI_DEV(cookie);
+ ret = program_write(spi_bus, spi_dev, rbf_data, rbf_size);
+ }
+ if (ret)
+ return ret;
+
+ /* Check done pin */
+ if (pfns->done) {
+ ret = (pfns->done)(cookie);
+
+ if (ret)
+ printf("Error: DONE not set (ret=%d)!\n", ret);
+ }
+
+ return ret;
+}
diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c
new file mode 100644
index 00000000000..624493ad838
--- /dev/null
+++ b/drivers/fpga/versalpl.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2019, Xilinx, Inc,
+ * Siva Durga Prasad Paladugu <siva.durga.prasad.paladugu@amd.com>>
+ */
+
+#include <cpu_func.h>
+#include <log.h>
+#include <memalign.h>
+#include <versalpl.h>
+#include <zynqmp_firmware.h>
+#include <asm/cache.h>
+
+static ulong versal_align_dma_buffer(ulong *buf, u32 len)
+{
+ ulong *new_buf;
+
+ if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) {
+ new_buf = (ulong *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN);
+ memcpy(new_buf, buf, len);
+ buf = new_buf;
+ }
+
+ return (ulong)buf;
+}
+
+static int versal_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype, int flags)
+{
+ ulong bin_buf;
+ int ret;
+ u32 buf_lo, buf_hi;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ bin_buf = versal_align_dma_buffer((ulong *)buf, bsize);
+
+ debug("%s called!\n", __func__);
+ flush_dcache_range(bin_buf, bin_buf + bsize);
+
+ buf_lo = lower_32_bits(bin_buf);
+ buf_hi = upper_32_bits(bin_buf);
+
+
+ if (desc->family == xilinx_versal2) {
+ ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_hi,
+ buf_lo, 0, ret_payload);
+ } else {
+ ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo,
+ buf_hi, 0, ret_payload);
+ }
+
+ if (ret)
+ printf("PL FPGA LOAD failed with err: 0x%08x\n", ret);
+
+ return ret;
+}
+
+struct xilinx_fpga_op versal_op = {
+ .load = versal_load,
+};
diff --git a/drivers/fpga/virtex2.c b/drivers/fpga/virtex2.c
new file mode 100644
index 00000000000..805cbac8082
--- /dev/null
+++ b/drivers/fpga/virtex2.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ * Keith Outwater, keith_outwater@mvis.com
+ *
+ * Copyright (c) 2019 SED Systems, a division of Calian Ltd.
+ */
+
+/*
+ * Configuration support for Xilinx Virtex2 devices. Based
+ * on spartan2.c (Rich Ireland, rireland@enterasys.com).
+ */
+
+#define LOG_CATEGORY UCLASS_FPGA
+
+#include <config.h>
+#include <console.h>
+#include <log.h>
+#include <virtex2.h>
+#include <linux/delay.h>
+#include <time.h>
+
+/*
+ * If the SelectMap interface can be overrun by the processor, enable
+ * CONFIG_SYS_FPGA_CHECK_BUSY and/or define CFG_FPGA_DELAY in the board
+ * configuration file and add board-specific support for checking BUSY status.
+ * By default, assume that the SelectMap interface cannot be overrun.
+ */
+
+#ifndef CFG_FPGA_DELAY
+#define CFG_FPGA_DELAY()
+#endif
+
+/*
+ * Check for errors during configuration by default
+ */
+#ifndef CFG_SYS_FPGA_CHECK_ERROR
+#define CFG_SYS_FPGA_CHECK_ERROR
+#endif
+
+/*
+ * The default timeout in mS for INIT_B to deassert after PROG_B has
+ * been deasserted. Per the latest Virtex II Handbook (page 347), the
+ * max time from PORG_B deassertion to INIT_B deassertion is 4uS per
+ * data frame for the XC2V8000. The XC2V8000 has 2860 data frames
+ * which yields 11.44 mS. So let's make it bigger in order to handle
+ * an XC2V1000, if anyone can ever get ahold of one.
+ */
+#ifndef CFG_SYS_FPGA_WAIT_INIT
+#define CFG_SYS_FPGA_WAIT_INIT CONFIG_SYS_HZ / 2 /* 500 ms */
+#endif
+
+/*
+ * The default timeout for waiting for BUSY to deassert during configuration.
+ * This is normally not necessary since for most reasonable configuration
+ * clock frequencies (i.e. 66 MHz or less), BUSY monitoring is unnecessary.
+ */
+#ifndef CFG_SYS_FPGA_WAIT_BUSY
+#define CFG_SYS_FPGA_WAIT_BUSY CONFIG_SYS_HZ / 200 /* 5 ms*/
+#endif
+
+/* Default timeout for waiting for FPGA to enter operational mode after
+ * configuration data has been written.
+ */
+#ifndef CFG_SYS_FPGA_WAIT_CONFIG
+#define CFG_SYS_FPGA_WAIT_CONFIG CONFIG_SYS_HZ / 5 /* 200 ms */
+#endif
+
+static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize);
+static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize);
+
+static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize);
+static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
+
+static int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype, int flags)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ log_debug("Launching Slave Serial Load\n");
+ ret_val = virtex2_ss_load(desc, buf, bsize);
+ break;
+
+ case slave_selectmap:
+ log_debug("Launching Slave Parallel Load\n");
+ ret_val = virtex2_ssm_load(desc, buf, bsize);
+ break;
+
+ default:
+ printf("%s: Unsupported interface type, %d\n",
+ __func__, desc->iface);
+ }
+ return ret_val;
+}
+
+static int virtex2_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+
+ switch (desc->iface) {
+ case slave_serial:
+ log_debug("Launching Slave Serial Dump\n");
+ ret_val = virtex2_ss_dump(desc, buf, bsize);
+ break;
+
+ case slave_parallel:
+ log_debug("Launching Slave Parallel Dump\n");
+ ret_val = virtex2_ssm_dump(desc, buf, bsize);
+ break;
+
+ default:
+ printf("%s: Unsupported interface type, %d\n",
+ __func__, desc->iface);
+ }
+ return ret_val;
+}
+
+static int virtex2_info(xilinx_desc *desc)
+{
+ return FPGA_SUCCESS;
+}
+
+/*
+ * Virtex-II Slave SelectMap or Serial configuration loader. Configuration
+ * is as follows:
+ * 1. Set the FPGA's PROG_B line low.
+ * 2. Set the FPGA's PROG_B line high. Wait for INIT_B to go high.
+ * 3. Write data to the SelectMap port. If INIT_B goes low at any time
+ * this process, a configuration error (most likely CRC failure) has
+ * ocurred. At this point a status word may be read from the
+ * SelectMap interface to determine the source of the problem (You
+ * could, for instance, put this in your 'abort' function handler).
+ * 4. After all data has been written, test the state of the FPGA
+ * INIT_B and DONE lines. If both are high, configuration has
+ * succeeded. Congratulations!
+ */
+static int virtex2_slave_pre(xilinx_virtex2_slave_fns *fn, int cookie)
+{
+ unsigned long ts;
+
+ log_debug("Start with interface functions @ 0x%p\n", fn);
+
+ if (!fn) {
+ printf("%s:%d: NULL Interface function table!\n",
+ __func__, __LINE__);
+ return FPGA_FAIL;
+ }
+
+ /* Gotta split this one up (so the stack won't blow??) */
+ log_debug("Function Table:\n"
+ " base 0x%p\n"
+ " struct 0x%p\n"
+ " pre 0x%p\n"
+ " prog 0x%p\n"
+ " init 0x%p\n"
+ " error 0x%p\n",
+ &fn, fn, fn->pre, fn->pgm, fn->init, fn->err);
+ log_debug(" clock 0x%p\n"
+ " cs 0x%p\n"
+ " write 0x%p\n"
+ " rdata 0x%p\n"
+ " wdata 0x%p\n"
+ " busy 0x%p\n"
+ " abort 0x%p\n"
+ " post 0x%p\n\n",
+ fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata,
+ fn->busy, fn->abort, fn->post);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf("Initializing FPGA Device %d...\n", cookie);
+#endif
+ /*
+ * Run the pre configuration function if there is one.
+ */
+ if (*fn->pre)
+ (*fn->pre)(cookie);
+
+ /*
+ * Assert the program line. The minimum pulse width for
+ * Virtex II devices is 300 nS (Tprogram parameter in datasheet).
+ * There is no maximum value for the pulse width. Check to make
+ * sure that INIT_B goes low after assertion of PROG_B
+ */
+ (*fn->pgm)(true, true, cookie);
+ udelay(10);
+ ts = get_timer(0);
+ do {
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT_INIT) {
+ printf("%s:%d: ** Timeout after %d ticks waiting for INIT to assert.\n",
+ __func__, __LINE__, CFG_SYS_FPGA_WAIT_INIT);
+ (*fn->abort)(cookie);
+ return FPGA_FAIL;
+ }
+ } while (!(*fn->init)(cookie));
+
+ (*fn->pgm)(false, true, cookie);
+ CFG_FPGA_DELAY();
+ if (fn->clk)
+ (*fn->clk)(true, true, cookie);
+
+ /*
+ * Start a timer and wait for INIT_B to go high
+ */
+ ts = get_timer(0);
+ do {
+ CFG_FPGA_DELAY();
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT_INIT) {
+ printf("%s:%d: ** Timeout after %d ticks waiting for INIT to deassert.\n",
+ __func__, __LINE__, CFG_SYS_FPGA_WAIT_INIT);
+ (*fn->abort)(cookie);
+ return FPGA_FAIL;
+ }
+ } while ((*fn->init)(cookie) && (*fn->busy)(cookie));
+
+ if (fn->wr)
+ (*fn->wr)(true, true, cookie);
+ if (fn->cs)
+ (*fn->cs)(true, true, cookie);
+
+ mdelay(10);
+ return FPGA_SUCCESS;
+}
+
+static int virtex2_slave_post(xilinx_virtex2_slave_fns *fn,
+ int cookie)
+{
+ int ret_val = FPGA_SUCCESS;
+ int num_done = 0;
+ unsigned long ts;
+
+ /*
+ * Finished writing the data; deassert FPGA CS_B and WRITE_B signals.
+ */
+ CFG_FPGA_DELAY();
+ if (fn->cs)
+ (*fn->cs)(false, true, cookie);
+ if (fn->wr)
+ (*fn->wr)(false, true, cookie);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc('\n');
+#endif
+
+ /*
+ * Check for successful configuration. FPGA INIT_B and DONE
+ * should both be high upon successful configuration. Continue pulsing
+ * clock with data set to all ones until DONE is asserted and for 8
+ * clock cycles afterwards.
+ */
+ ts = get_timer(0);
+ while (true) {
+ if ((*fn->done)(cookie) == FPGA_SUCCESS &&
+ !((*fn->init)(cookie))) {
+ if (num_done++ >= 8)
+ break;
+ }
+
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT_CONFIG) {
+ printf("%s:%d: ** Timeout after %d ticks waiting for DONE to assert and INIT to deassert\n",
+ __func__, __LINE__, CFG_SYS_FPGA_WAIT_CONFIG);
+ (*fn->abort)(cookie);
+ ret_val = FPGA_FAIL;
+ break;
+ }
+ if (fn->wbulkdata) {
+ unsigned char dummy = 0xff;
+ (*fn->wbulkdata)(&dummy, 1, true, cookie);
+ } else {
+ (*fn->wdata)(0xff, true, cookie);
+ CFG_FPGA_DELAY();
+ (*fn->clk)(false, true, cookie);
+ CFG_FPGA_DELAY();
+ (*fn->clk)(true, true, cookie);
+ }
+ }
+
+ if (ret_val == FPGA_SUCCESS) {
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf("Initialization of FPGA device %d complete\n", cookie);
+#endif
+ /*
+ * Run the post configuration function if there is one.
+ */
+ if (*fn->post)
+ (*fn->post)(cookie);
+ } else {
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ printf("** Initialization of FPGA device %d FAILED\n",
+ cookie);
+#endif
+ }
+ return ret_val;
+}
+
+static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+ xilinx_virtex2_slave_fns *fn = desc->iface_fns;
+ size_t bytecount = 0;
+ unsigned char *data = (unsigned char *)buf;
+ int cookie = desc->cookie;
+ unsigned long ts;
+
+ ret_val = virtex2_slave_pre(fn, cookie);
+ if (ret_val != FPGA_SUCCESS)
+ return ret_val;
+
+ /*
+ * Load the data byte by byte
+ */
+ while (bytecount < bsize) {
+#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
+ if (ctrlc()) {
+ (*fn->abort)(cookie);
+ return FPGA_FAIL;
+ }
+#endif
+
+ if ((*fn->done)(cookie) == FPGA_SUCCESS) {
+ log_debug("done went active early, bytecount = %zu\n",
+ bytecount);
+ break;
+ }
+
+#ifdef CFG_SYS_FPGA_CHECK_ERROR
+ if ((*fn->init)(cookie)) {
+ printf("\n%s:%d: ** Error: INIT asserted during configuration\n",
+ __func__, __LINE__);
+ printf("%zu = buffer offset, %zu = buffer size\n",
+ bytecount, bsize);
+ (*fn->abort)(cookie);
+ return FPGA_FAIL;
+ }
+#endif
+
+ (*fn->wdata)(data[bytecount++], true, cookie);
+ CFG_FPGA_DELAY();
+
+ /*
+ * Cycle the clock pin
+ */
+ (*fn->clk)(false, true, cookie);
+ CFG_FPGA_DELAY();
+ (*fn->clk)(true, true, cookie);
+
+#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
+ ts = get_timer(0);
+ while ((*fn->busy)(cookie)) {
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT_BUSY) {
+ printf("%s:%d: ** Timeout after %d ticks waiting for BUSY to deassert\n",
+ __func__, __LINE__,
+ CFG_SYS_FPGA_WAIT_BUSY);
+ (*fn->abort)(cookie);
+ return FPGA_FAIL;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc('.');
+#endif
+ }
+
+ return virtex2_slave_post(fn, cookie);
+}
+
+/*
+ * Read the FPGA configuration data
+ */
+static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+ xilinx_virtex2_slave_fns *fn = desc->iface_fns;
+
+ if (fn) {
+ unsigned char *data = (unsigned char *)buf;
+ size_t bytecount = 0;
+ int cookie = desc->cookie;
+
+ printf("Starting Dump of FPGA Device %d...\n", cookie);
+
+ (*fn->cs)(true, true, cookie);
+ (*fn->clk)(true, true, cookie);
+
+ while (bytecount < bsize) {
+#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
+ if (ctrlc()) {
+ (*fn->abort)(cookie);
+ return FPGA_FAIL;
+ }
+#endif
+ /*
+ * Cycle the clock and read the data
+ */
+ (*fn->clk)(false, true, cookie);
+ (*fn->clk)(true, true, cookie);
+ (*fn->rdata)(&data[bytecount++], cookie);
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc('.');
+#endif
+ }
+
+ /*
+ * Deassert CS_B and cycle the clock to deselect the device.
+ */
+ (*fn->cs)(false, false, cookie);
+ (*fn->clk)(false, true, cookie);
+ (*fn->clk)(true, true, cookie);
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ putc('\n');
+#endif
+ puts("Done.\n");
+ } else {
+ printf("%s:%d: NULL Interface function table!\n",
+ __func__, __LINE__);
+ }
+ return ret_val;
+}
+
+static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ int ret_val = FPGA_FAIL;
+ xilinx_virtex2_slave_fns *fn = desc->iface_fns;
+ unsigned char *data = (unsigned char *)buf;
+ int cookie = desc->cookie;
+
+ ret_val = virtex2_slave_pre(fn, cookie);
+ if (ret_val != FPGA_SUCCESS)
+ return ret_val;
+
+ if (fn->wbulkdata) {
+ /* Load the data in a single chunk */
+ (*fn->wbulkdata)(data, bsize, true, cookie);
+ } else {
+ size_t bytecount = 0;
+
+ /*
+ * Load the data bit by bit
+ */
+ while (bytecount < bsize) {
+ unsigned char curr_data = data[bytecount++];
+ int bit;
+
+#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
+ if (ctrlc()) {
+ (*fn->abort) (cookie);
+ return FPGA_FAIL;
+ }
+#endif
+
+ if ((*fn->done)(cookie) == FPGA_SUCCESS) {
+ log_debug("done went active early, bytecount = %zu\n",
+ bytecount);
+ break;
+ }
+
+#ifdef CFG_SYS_FPGA_CHECK_ERROR
+ if ((*fn->init)(cookie)) {
+ printf("\n%s:%d: ** Error: INIT asserted during configuration\n",
+ __func__, __LINE__);
+ printf("%zu = buffer offset, %zu = buffer size\n",
+ bytecount, bsize);
+ (*fn->abort)(cookie);
+ return FPGA_FAIL;
+ }
+#endif
+
+ for (bit = 7; bit >= 0; --bit) {
+ unsigned char curr_bit = (curr_data >> bit) & 1;
+ (*fn->wdata)(curr_bit, true, cookie);
+ CFG_FPGA_DELAY();
+ (*fn->clk)(false, true, cookie);
+ CFG_FPGA_DELAY();
+ (*fn->clk)(true, true, cookie);
+ }
+
+ /* Slave serial never uses a busy pin */
+
+#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
+ if (bytecount % (bsize / 40) == 0)
+ putc('.');
+#endif
+ }
+ }
+
+ return virtex2_slave_post(fn, cookie);
+}
+
+static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ printf("%s: Slave Serial Dumping is unsupported\n", __func__);
+ return FPGA_FAIL;
+}
+
+/* vim: set ts=4 tw=78: */
+
+struct xilinx_fpga_op virtex2_op = {
+ .load = virtex2_load,
+ .dump = virtex2_dump,
+ .info = virtex2_info,
+};
diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c
new file mode 100644
index 00000000000..28c68faba55
--- /dev/null
+++ b/drivers/fpga/xilinx.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012-2013, Xilinx, Michal Simek
+ *
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ * Keith Outwater, keith_outwater@mvis.com
+ */
+
+/*
+ * Xilinx FPGA support
+ */
+
+#include <fpga.h>
+#include <log.h>
+#include <virtex2.h>
+#include <spartan2.h>
+#include <spartan3.h>
+#include <zynqpl.h>
+#include <linux/string.h>
+
+/* Local Static Functions */
+static int xilinx_validate(xilinx_desc *desc, char *fn);
+
+/* ------------------------------------------------------------------------- */
+
+int fpga_is_partial_data(int devnum, size_t img_len)
+{
+ const fpga_desc * const desc = fpga_get_desc(devnum);
+ xilinx_desc *desc_xilinx = desc->devdesc;
+
+ /* Check datasize against FPGA size */
+ if (img_len >= desc_xilinx->size)
+ return 0;
+
+ /* datasize is smaller, must be partial data */
+ return 1;
+}
+
+int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
+ bitstream_type bstype)
+{
+ unsigned int length;
+ unsigned int swapsize;
+ unsigned char *dataptr;
+ unsigned int i;
+ const fpga_desc *desc;
+ xilinx_desc *xdesc;
+
+ dataptr = (unsigned char *)fpgadata;
+ /* Find out fpga_description */
+ desc = fpga_validate(devnum, dataptr, 0);
+ /* Assign xilinx device description */
+ xdesc = desc->devdesc;
+
+ /* skip the first bytes of the bitsteam, their meaning is unknown */
+ length = (*dataptr << 8) + *(dataptr + 1);
+ dataptr += 2;
+ dataptr += length;
+
+ /* get design name (identifier, length, string) */
+ length = (*dataptr << 8) + *(dataptr + 1);
+ dataptr += 2;
+ if (*dataptr++ != 0x61) {
+ debug("%s: Design name id not recognized in bitstream\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+
+ length = (*dataptr << 8) + *(dataptr + 1);
+ dataptr += 2;
+ printf(" design filename = \"%s\"\n", dataptr);
+ dataptr += length;
+
+ /* get part number (identifier, length, string) */
+ if (*dataptr++ != 0x62) {
+ printf("%s: Part number id not recognized in bitstream\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+
+ length = (*dataptr << 8) + *(dataptr + 1);
+ dataptr += 2;
+
+ if (xdesc->name) {
+ i = (ulong)strstr((char *)dataptr, xdesc->name);
+ if (!i) {
+ printf("%s: Wrong bitstream ID for this device\n",
+ __func__);
+ printf("%s: Bitstream ID %s, current device ID %d/%s\n",
+ __func__, dataptr, devnum, xdesc->name);
+ return FPGA_FAIL;
+ }
+ } else {
+ printf("%s: Please fill correct device ID to xilinx_desc\n",
+ __func__);
+ }
+ printf(" part number = \"%s\"\n", dataptr);
+ dataptr += length;
+
+ /* get date (identifier, length, string) */
+ if (*dataptr++ != 0x63) {
+ printf("%s: Date identifier not recognized in bitstream\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+
+ length = (*dataptr << 8) + *(dataptr+1);
+ dataptr += 2;
+ printf(" date = \"%s\"\n", dataptr);
+ dataptr += length;
+
+ /* get time (identifier, length, string) */
+ if (*dataptr++ != 0x64) {
+ printf("%s: Time identifier not recognized in bitstream\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+
+ length = (*dataptr << 8) + *(dataptr+1);
+ dataptr += 2;
+ printf(" time = \"%s\"\n", dataptr);
+ dataptr += length;
+
+ /* get fpga data length (identifier, length) */
+ if (*dataptr++ != 0x65) {
+ printf("%s: Data length id not recognized in bitstream\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ swapsize = ((unsigned int) *dataptr << 24) +
+ ((unsigned int) *(dataptr + 1) << 16) +
+ ((unsigned int) *(dataptr + 2) << 8) +
+ ((unsigned int) *(dataptr + 3));
+ dataptr += 4;
+ printf(" bytes in bitstream = %d\n", swapsize);
+
+ return fpga_load(devnum, dataptr, swapsize, bstype, 0);
+}
+
+int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype, int flags)
+{
+ if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ return FPGA_FAIL;
+ }
+
+ if (!desc->operations || !desc->operations->load) {
+ printf("%s: Missing load operation\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ return desc->operations->load(desc, buf, bsize, bstype, flags);
+}
+
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+int xilinx_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+ fpga_fs_info *fpga_fsinfo)
+{
+ if (!xilinx_validate(desc, (char *)__func__)) {
+ printf("%s: Invalid device descriptor\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ if (!desc->operations || !desc->operations->loadfs) {
+ printf("%s: Missing loadfs operation\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ return desc->operations->loadfs(desc, buf, bsize, fpga_fsinfo);
+}
+#endif
+
+#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE)
+int xilinx_loads(xilinx_desc *desc, const void *buf, size_t bsize,
+ struct fpga_secure_info *fpga_sec_info)
+{
+ if (!xilinx_validate(desc, (char *)__func__)) {
+ printf("%s: Invalid device descriptor\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ if (!desc->operations || !desc->operations->loads) {
+ printf("%s: Missing loads operation\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ return desc->operations->loads(desc, buf, bsize, fpga_sec_info);
+}
+#endif
+
+int xilinx_dump(xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ return FPGA_FAIL;
+ }
+
+ if (!desc->operations || !desc->operations->dump) {
+ printf("%s: Missing dump operation\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ return desc->operations->dump(desc, buf, bsize);
+}
+
+int xilinx_info(xilinx_desc *desc)
+{
+ int ret_val = FPGA_FAIL;
+
+ if (xilinx_validate (desc, (char *)__FUNCTION__)) {
+ printf ("Family: \t");
+ switch (desc->family) {
+ case xilinx_spartan2:
+ printf ("Spartan-II\n");
+ break;
+ case xilinx_spartan3:
+ printf ("Spartan-III\n");
+ break;
+ case xilinx_virtex2:
+ printf ("Virtex-II\n");
+ break;
+ case xilinx_zynq:
+ printf("Zynq PL\n");
+ break;
+ case xilinx_zynqmp:
+ printf("ZynqMP PL\n");
+ break;
+ case xilinx_versal:
+ printf("Versal PL\n");
+ break;
+ /* Add new family types here */
+ default:
+ printf ("Unknown family type, %d\n", desc->family);
+ }
+
+ printf ("Interface type:\t");
+ switch (desc->iface) {
+ case slave_serial:
+ printf ("Slave Serial\n");
+ break;
+ case master_serial: /* Not used */
+ printf ("Master Serial\n");
+ break;
+ case slave_parallel:
+ printf ("Slave Parallel\n");
+ break;
+ case jtag_mode: /* Not used */
+ printf ("JTAG Mode\n");
+ break;
+ case slave_selectmap:
+ printf ("Slave SelectMap Mode\n");
+ break;
+ case master_selectmap:
+ printf ("Master SelectMap Mode\n");
+ break;
+ case devcfg:
+ printf("Device configuration interface (Zynq)\n");
+ break;
+ case csu_dma:
+ printf("csu_dma configuration interface (ZynqMP)\n");
+ break;
+ case cfi:
+ printf("CFI configuration interface (Versal)\n");
+ break;
+ /* Add new interface types here */
+ default:
+ printf ("Unsupported interface type, %d\n", desc->iface);
+ }
+
+ printf("Device Size: \t%zd bytes\n"
+ "Cookie: \t0x%x (%d)\n",
+ desc->size, desc->cookie, desc->cookie);
+ if (desc->name)
+ printf("Device name: \t%s\n", desc->name);
+
+ if (desc->iface_fns)
+ printf ("Device Function Table @ 0x%p\n", desc->iface_fns);
+ else
+ printf ("No Device Function Table.\n");
+
+ if (desc->operations && desc->operations->info)
+ desc->operations->info(desc);
+
+ ret_val = FPGA_SUCCESS;
+ } else {
+ printf ("%s: Invalid device descriptor\n", __FUNCTION__);
+ }
+
+ return ret_val;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int xilinx_validate(xilinx_desc *desc, char *fn)
+{
+ int ret_val = false;
+
+ if (desc) {
+ if ((desc->family > min_xilinx_type) &&
+ (desc->family < max_xilinx_type)) {
+ if ((desc->iface > min_xilinx_iface_type) &&
+ (desc->iface < max_xilinx_iface_type)) {
+ if (desc->size) {
+ ret_val = true;
+ } else
+ printf ("%s: NULL part size\n", fn);
+ } else
+ printf ("%s: Invalid Interface type, %d\n",
+ fn, desc->iface);
+ } else
+ printf ("%s: Invalid family type, %d\n", fn, desc->family);
+ } else
+ printf ("%s: NULL descriptor!\n", fn);
+
+ return ret_val;
+}
diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c
new file mode 100644
index 00000000000..1199b249e36
--- /dev/null
+++ b/drivers/fpga/zynqmppl.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2015 - 2016, Xilinx, Inc,
+ * Michal Simek <michal.simek@amd.com>
+ * Siva Durga Prasad Paladugu <siva.durga.prasad.paladugu@amd.com>
+ */
+
+#include <console.h>
+#include <compiler.h>
+#include <cpu_func.h>
+#include <fpga.h>
+#include <log.h>
+#include <zynqmppl.h>
+#include <zynqmp_firmware.h>
+#include <asm/cache.h>
+#include <linux/bitops.h>
+#include <linux/sizes.h>
+#include <asm/arch/sys_proto.h>
+#include <memalign.h>
+
+#define DUMMY_WORD 0xffffffff
+
+/* Xilinx binary format header */
+static const u32 bin_format[] = {
+ DUMMY_WORD, /* Dummy words */
+ 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, /* Sync word */
+ 0x11220044, /* Sync word */
+ DUMMY_WORD,
+ DUMMY_WORD,
+ 0xaa995566, /* Sync word */
+};
+
+#define SWAP_NO 1
+#define SWAP_DONE 2
+
+/*
+ * Load the whole word from unaligned buffer
+ * Keep in your mind that it is byte loading on little-endian system
+ */
+static u32 load_word(const void *buf, u32 swap)
+{
+ u32 word = 0;
+ u8 *bitc = (u8 *)buf;
+ int p;
+
+ if (swap == SWAP_NO) {
+ for (p = 0; p < 4; p++) {
+ word <<= 8;
+ word |= bitc[p];
+ }
+ } else {
+ for (p = 3; p >= 0; p--) {
+ word <<= 8;
+ word |= bitc[p];
+ }
+ }
+
+ return word;
+}
+
+static u32 check_header(const void *buf)
+{
+ u32 i, pattern;
+ int swap = SWAP_NO;
+ u32 *test = (u32 *)buf;
+
+ debug("%s: Let's check bitstream header\n", __func__);
+
+ /* Checking that passing bin is not a bitstream */
+ for (i = 0; i < ARRAY_SIZE(bin_format); i++) {
+ pattern = load_word(&test[i], swap);
+
+ /*
+ * Bitstreams in binary format are swapped
+ * compare to regular bistream.
+ * Do not swap dummy word but if swap is done assume
+ * that parsing buffer is binary format
+ */
+ if ((__swab32(pattern) != DUMMY_WORD) &&
+ (__swab32(pattern) == bin_format[i])) {
+ swap = SWAP_DONE;
+ debug("%s: data swapped - let's swap\n", __func__);
+ }
+
+ debug("%s: %d/%px: pattern %x/%x bin_format\n", __func__, i,
+ &test[i], pattern, bin_format[i]);
+ }
+ debug("%s: Found bitstream header at %px %s swapinng\n", __func__,
+ buf, swap == SWAP_NO ? "without" : "with");
+
+ return swap;
+}
+
+static void *check_data(u8 *buf, size_t bsize, u32 *swap)
+{
+ u32 word, p = 0; /* possition */
+
+ /* Because buf doesn't need to be aligned let's read it by chars */
+ for (p = 0; p < bsize; p++) {
+ word = load_word(&buf[p], SWAP_NO);
+ debug("%s: word %x %x/%px\n", __func__, word, p, &buf[p]);
+
+ /* Find the first bitstream dummy word */
+ if (word == DUMMY_WORD) {
+ debug("%s: Found dummy word at position %x/%px\n",
+ __func__, p, &buf[p]);
+ *swap = check_header(&buf[p]);
+ if (*swap) {
+ /* FIXME add full bitstream checking here */
+ return &buf[p];
+ }
+ }
+ /* Loop can be huge - support CTRL + C */
+ if (ctrlc())
+ return NULL;
+ }
+ return NULL;
+}
+
+static ulong zynqmp_align_dma_buffer(u32 *buf, u32 len, u32 swap)
+{
+ u32 *new_buf;
+ u32 i;
+
+ if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) {
+ new_buf = (u32 *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN);
+
+ /*
+ * This might be dangerous but permits to flash if
+ * ARCH_DMA_MINALIGN is greater than header size
+ */
+ if (new_buf > (u32 *)buf) {
+ debug("%s: Aligned buffer is after buffer start\n",
+ __func__);
+ new_buf -= ARCH_DMA_MINALIGN;
+ }
+ printf("%s: Align buffer at %px to %px(swap %d)\n", __func__,
+ buf, new_buf, swap);
+
+ for (i = 0; i < (len/4); i++)
+ new_buf[i] = load_word(&buf[i], swap);
+
+ buf = new_buf;
+ } else if ((swap != SWAP_DONE) &&
+ (zynqmp_firmware_version() <= PMUFW_V1_0)) {
+ /* For bitstream which are aligned */
+ new_buf = buf;
+
+ printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__,
+ swap);
+
+ for (i = 0; i < (len/4); i++)
+ new_buf[i] = load_word(&buf[i], swap);
+ }
+
+ return (ulong)buf;
+}
+
+static int zynqmp_validate_bitstream(xilinx_desc *desc, const void *buf,
+ size_t bsize, u32 blocksize, u32 *swap)
+{
+ ulong *buf_start;
+ ulong diff;
+
+ buf_start = check_data((u8 *)buf, blocksize, swap);
+
+ if (!buf_start)
+ return FPGA_FAIL;
+
+ /* Check if data is postpone from start */
+ diff = (ulong)buf_start - (ulong)buf;
+ if (diff) {
+ printf("%s: Bitstream is not validated yet (diff %lx)\n",
+ __func__, diff);
+ return FPGA_FAIL;
+ }
+
+ if ((ulong)buf < SZ_1M) {
+ log_err("Bitstream has to be placed above 1MB (%px)\n",
+ buf);
+ return FPGA_FAIL;
+ }
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE)
+static int zynqmp_check_compatible(xilinx_desc *desc, int flags)
+{
+ /*
+ * If no flags set, the image may be legacy, but we need to
+ * signal caller this situation with specific error code.
+ */
+ if (!flags)
+ return -ENODATA;
+
+ /* For legacy bitstream images no need for other methods exist */
+ if ((flags & desc->flags) && flags == FPGA_LEGACY)
+ return 0;
+
+ /*
+ * Other images are handled in secure callback loads(). Check
+ * callback existence besides image type support.
+ */
+ if (desc->operations->loads && (flags & desc->flags))
+ return 0;
+
+ return -ENODEV;
+}
+#endif
+
+static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype, int flags)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(u32, bsizeptr, 1);
+ u32 swap = 0;
+ ulong bin_buf;
+ int ret;
+ u32 buf_lo, buf_hi;
+ u32 bsize_req = (u32)bsize;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE)
+ struct fpga_secure_info info = { 0 };
+
+ ret = zynqmp_check_compatible(desc, flags);
+ if (ret) {
+ if (ret != -ENODATA) {
+ puts("Missing loads() operation or unsupported bitstream type\n");
+ return FPGA_FAIL;
+ }
+ /* If flags is not set, the image treats as legacy */
+ flags = FPGA_LEGACY;
+ }
+
+ switch (flags) {
+ case FPGA_LEGACY:
+ break; /* Handle the legacy image later in this function */
+#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE)
+ case FPGA_XILINX_ZYNQMP_DDRAUTH:
+ /* DDR authentication */
+ info.authflag = ZYNQMP_FPGA_AUTH_DDR;
+ info.encflag = FPGA_NO_ENC_OR_NO_AUTH;
+ return desc->operations->loads(desc, buf, bsize, &info);
+ case FPGA_XILINX_ZYNQMP_ENC:
+ /* Encryption using device key */
+ info.authflag = FPGA_NO_ENC_OR_NO_AUTH;
+ info.encflag = FPGA_ENC_DEV_KEY;
+ return desc->operations->loads(desc, buf, bsize, &info);
+#endif
+ default:
+ printf("Unsupported bitstream type %d\n", flags);
+ return FPGA_FAIL;
+ }
+#endif
+
+ if (zynqmp_firmware_version() <= PMUFW_V1_0) {
+ puts("WARN: PMUFW v1.0 or less is detected\n");
+ puts("WARN: Not all bitstream formats are supported\n");
+ puts("WARN: Please upgrade PMUFW\n");
+ if (zynqmp_validate_bitstream(desc, buf, bsize, bsize, &swap))
+ return FPGA_FAIL;
+ bsizeptr = (u32 *)&bsize;
+ flush_dcache_range((ulong)bsizeptr,
+ (ulong)bsizeptr + sizeof(size_t));
+ bsize_req = (u32)(uintptr_t)bsizeptr;
+ bstype |= BIT(ZYNQMP_FPGA_BIT_NS);
+ } else {
+ bstype = 0;
+ }
+
+ bin_buf = zynqmp_align_dma_buffer((u32 *)buf, bsize, swap);
+
+ flush_dcache_range(bin_buf, bin_buf + bsize);
+
+ buf_lo = (u32)bin_buf;
+ buf_hi = upper_32_bits(bin_buf);
+
+ ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi,
+ bsize_req, bstype, ret_payload);
+ if (ret)
+ printf("PL FPGA LOAD failed with err: 0x%08x\n", ret);
+
+ return ret;
+}
+
+#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE)
+static int zynqmp_loads(xilinx_desc *desc, const void *buf, size_t bsize,
+ struct fpga_secure_info *fpga_sec_info)
+{
+ int ret;
+ u32 buf_lo, buf_hi;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ u8 flag = 0;
+
+ flush_dcache_range((ulong)buf, (ulong)buf +
+ ALIGN(bsize, CONFIG_SYS_CACHELINE_SIZE));
+
+ if (!fpga_sec_info->encflag)
+ flag |= BIT(ZYNQMP_FPGA_BIT_ENC_DEV_KEY);
+
+ if (fpga_sec_info->userkey_addr &&
+ fpga_sec_info->encflag == FPGA_ENC_USR_KEY) {
+ flush_dcache_range((ulong)fpga_sec_info->userkey_addr,
+ (ulong)fpga_sec_info->userkey_addr +
+ ALIGN(KEY_PTR_LEN,
+ CONFIG_SYS_CACHELINE_SIZE));
+ flag |= BIT(ZYNQMP_FPGA_BIT_ENC_USR_KEY);
+ }
+
+ if (!fpga_sec_info->authflag)
+ flag |= BIT(ZYNQMP_FPGA_BIT_AUTH_OCM);
+
+ if (fpga_sec_info->authflag == ZYNQMP_FPGA_AUTH_DDR)
+ flag |= BIT(ZYNQMP_FPGA_BIT_AUTH_DDR);
+
+ buf_lo = lower_32_bits((ulong)buf);
+ buf_hi = upper_32_bits((ulong)buf);
+
+ if ((u32)(uintptr_t)fpga_sec_info->userkey_addr)
+ ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo,
+ buf_hi,
+ (u32)(uintptr_t)fpga_sec_info->userkey_addr,
+ flag, ret_payload);
+ else
+ ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo,
+ buf_hi, (u32)bsize,
+ flag, ret_payload);
+
+ if (ret)
+ puts("PL FPGA LOAD fail\n");
+ else
+ puts("Bitstream successfully loaded\n");
+
+ return ret;
+}
+#endif
+
+static int zynqmp_pcap_info(xilinx_desc *desc)
+{
+ int ret;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ ret = xilinx_pm_request(PM_FPGA_GET_STATUS, 0, 0, 0,
+ 0, ret_payload);
+ if (!ret)
+ printf("PCAP status\t0x%x\n", ret_payload[1]);
+
+ return ret;
+}
+
+static int __maybe_unused zynqmp_str2flag(xilinx_desc *desc, const char *str)
+{
+ if (!strncmp(str, "u-boot,fpga-legacy", 18))
+ return FPGA_LEGACY;
+#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE)
+ if (!strncmp(str, "u-boot,zynqmp-fpga-ddrauth", 26))
+ return FPGA_XILINX_ZYNQMP_DDRAUTH;
+
+ if (!strncmp(str, "u-boot,zynqmp-fpga-enc", 22))
+ return FPGA_XILINX_ZYNQMP_ENC;
+#endif
+ return 0;
+}
+
+struct xilinx_fpga_op zynqmp_op = {
+ .load = zynqmp_load,
+ .info = zynqmp_pcap_info,
+#if CONFIG_IS_ENABLED(FPGA_LOAD_SECURE)
+ .loads = zynqmp_loads,
+ .str2flag = zynqmp_str2flag,
+#endif
+};
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
new file mode 100644
index 00000000000..5a37a33b0a7
--- /dev/null
+++ b/drivers/fpga/zynqpl.c
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012-2013, Xilinx, Michal Simek
+ *
+ * (C) Copyright 2012
+ * Joe Hershberger <joe.hershberger@ni.com>
+ */
+
+#include <config.h>
+#include <console.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <time.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <fs.h>
+#include <zynqpl.h>
+#include <linux/delay.h>
+#include <linux/sizes.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+
+#define DEVCFG_CTRL_PCFG_PROG_B 0x40000000
+#define DEVCFG_CTRL_PCFG_AES_EFUSE_MASK 0x00001000
+#define DEVCFG_CTRL_PCAP_RATE_EN_MASK 0x02000000
+#define DEVCFG_CTRL_PCFG_AES_EN_MASK 0x00000E00
+#define DEVCFG_ISR_FATAL_ERROR_MASK 0x00740040
+#define DEVCFG_ISR_ERROR_FLAGS_MASK 0x00340840
+#define DEVCFG_ISR_RX_FIFO_OV 0x00040000
+#define DEVCFG_ISR_DMA_DONE 0x00002000
+#define DEVCFG_ISR_PCFG_DONE 0x00000004
+#define DEVCFG_STATUS_DMA_CMD_Q_F 0x80000000
+#define DEVCFG_STATUS_DMA_CMD_Q_E 0x40000000
+#define DEVCFG_STATUS_DMA_DONE_CNT_MASK 0x30000000
+#define DEVCFG_STATUS_PCFG_INIT 0x00000010
+#define DEVCFG_MCTRL_PCAP_LPBK 0x00000010
+#define DEVCFG_MCTRL_RFIFO_FLUSH 0x00000002
+#define DEVCFG_MCTRL_WFIFO_FLUSH 0x00000001
+
+#ifndef CFG_SYS_FPGA_WAIT
+#define CFG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
+#endif
+
+#ifndef CFG_SYS_FPGA_PROG_TIME
+#define CFG_SYS_FPGA_PROG_TIME (CONFIG_SYS_HZ * 4) /* 4 s */
+#endif
+
+#define DUMMY_WORD 0xffffffff
+
+/* Xilinx binary format header */
+static const u32 bin_format[] = {
+ DUMMY_WORD, /* Dummy words */
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
+ 0x000000bb, /* Sync word */
+ 0x11220044, /* Sync word */
+ DUMMY_WORD,
+ DUMMY_WORD,
+ 0xaa995566, /* Sync word */
+};
+
+#define SWAP_NO 1
+#define SWAP_DONE 2
+
+/*
+ * Load the whole word from unaligned buffer
+ * Keep in your mind that it is byte loading on little-endian system
+ */
+static u32 load_word(const void *buf, u32 swap)
+{
+ u32 word = 0;
+ u8 *bitc = (u8 *)buf;
+ int p;
+
+ if (swap == SWAP_NO) {
+ for (p = 0; p < 4; p++) {
+ word <<= 8;
+ word |= bitc[p];
+ }
+ } else {
+ for (p = 3; p >= 0; p--) {
+ word <<= 8;
+ word |= bitc[p];
+ }
+ }
+
+ return word;
+}
+
+static u32 check_header(const void *buf)
+{
+ u32 i, pattern;
+ int swap = SWAP_NO;
+ u32 *test = (u32 *)buf;
+
+ debug("%s: Let's check bitstream header\n", __func__);
+
+ /* Checking that passing bin is not a bitstream */
+ for (i = 0; i < ARRAY_SIZE(bin_format); i++) {
+ pattern = load_word(&test[i], swap);
+
+ /*
+ * Bitstreams in binary format are swapped
+ * compare to regular bistream.
+ * Do not swap dummy word but if swap is done assume
+ * that parsing buffer is binary format
+ */
+ if ((__swab32(pattern) != DUMMY_WORD) &&
+ (__swab32(pattern) == bin_format[i])) {
+ pattern = __swab32(pattern);
+ swap = SWAP_DONE;
+ debug("%s: data swapped - let's swap\n", __func__);
+ }
+
+ debug("%s: %d/%x: pattern %x/%x bin_format\n", __func__, i,
+ (u32)&test[i], pattern, bin_format[i]);
+ if (pattern != bin_format[i]) {
+ debug("%s: Bitstream is not recognized\n", __func__);
+ return 0;
+ }
+ }
+ debug("%s: Found bitstream header at %x %s swapinng\n", __func__,
+ (u32)buf, swap == SWAP_NO ? "without" : "with");
+
+ return swap;
+}
+
+static void *check_data(u8 *buf, size_t bsize, u32 *swap)
+{
+ u32 word, p = 0; /* possition */
+
+ /* Because buf doesn't need to be aligned let's read it by chars */
+ for (p = 0; p < bsize; p++) {
+ word = load_word(&buf[p], SWAP_NO);
+ debug("%s: word %x %x/%x\n", __func__, word, p, (u32)&buf[p]);
+
+ /* Find the first bitstream dummy word */
+ if (word == DUMMY_WORD) {
+ debug("%s: Found dummy word at position %x/%x\n",
+ __func__, p, (u32)&buf[p]);
+ *swap = check_header(&buf[p]);
+ if (*swap) {
+ /* FIXME add full bitstream checking here */
+ return &buf[p];
+ }
+ }
+ /* Loop can be huge - support CTRL + C */
+ if (ctrlc())
+ return NULL;
+ }
+ return NULL;
+}
+
+static int zynq_dma_transfer(u32 srcbuf, u32 srclen, u32 dstbuf, u32 dstlen)
+{
+ unsigned long ts;
+ u32 isr_status;
+
+ /* Set up the transfer */
+ writel((u32)srcbuf, &devcfg_base->dma_src_addr);
+ writel(dstbuf, &devcfg_base->dma_dst_addr);
+ writel(srclen, &devcfg_base->dma_src_len);
+ writel(dstlen, &devcfg_base->dma_dst_len);
+
+ isr_status = readl(&devcfg_base->int_sts);
+
+ /* Polling the PCAP_INIT status for Set */
+ ts = get_timer(0);
+ while (!(isr_status & DEVCFG_ISR_DMA_DONE)) {
+ if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) {
+ debug("%s: Error: isr = 0x%08X\n", __func__,
+ isr_status);
+ debug("%s: Write count = 0x%08X\n", __func__,
+ readl(&devcfg_base->write_count));
+ debug("%s: Read count = 0x%08X\n", __func__,
+ readl(&devcfg_base->read_count));
+
+ return FPGA_FAIL;
+ }
+ if (get_timer(ts) > CFG_SYS_FPGA_PROG_TIME) {
+ printf("%s: Timeout wait for DMA to complete\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ isr_status = readl(&devcfg_base->int_sts);
+ }
+
+ debug("%s: DMA transfer is done\n", __func__);
+
+ /* Clear out the DMA status */
+ writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);
+
+ return FPGA_SUCCESS;
+}
+
+static int zynq_dma_xfer_init(bitstream_type bstype)
+{
+ u32 status, control, isr_status;
+ unsigned long ts;
+
+ /* Clear loopback bit */
+ clrbits_le32(&devcfg_base->mctrl, DEVCFG_MCTRL_PCAP_LPBK);
+
+ if (bstype != BIT_PARTIAL && bstype != BIT_NONE) {
+ zynq_slcr_devcfg_disable();
+
+ /* Setting PCFG_PROG_B signal to high */
+ control = readl(&devcfg_base->ctrl);
+ writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+
+ /*
+ * Delay is required if AES efuse is selected as
+ * key source.
+ */
+ if (control & DEVCFG_CTRL_PCFG_AES_EFUSE_MASK)
+ mdelay(5);
+
+ /* Setting PCFG_PROG_B signal to low */
+ writel(control & ~DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+
+ /*
+ * Delay is required if AES efuse is selected as
+ * key source.
+ */
+ if (control & DEVCFG_CTRL_PCFG_AES_EFUSE_MASK)
+ mdelay(5);
+
+ /* Polling the PCAP_INIT status for Reset */
+ ts = get_timer(0);
+ while (readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT) {
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT) {
+ printf("%s: Timeout wait for INIT to clear\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ }
+
+ /* Setting PCFG_PROG_B signal to high */
+ writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+
+ /* Polling the PCAP_INIT status for Set */
+ ts = get_timer(0);
+ while (!(readl(&devcfg_base->status) &
+ DEVCFG_STATUS_PCFG_INIT)) {
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT) {
+ printf("%s: Timeout wait for INIT to set\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ }
+ }
+
+ isr_status = readl(&devcfg_base->int_sts);
+
+ /* Clear it all, so if Boot ROM comes back, it can proceed */
+ writel(0xFFFFFFFF, &devcfg_base->int_sts);
+
+ if (isr_status & DEVCFG_ISR_FATAL_ERROR_MASK) {
+ debug("%s: Fatal errors in PCAP 0x%X\n", __func__, isr_status);
+
+ /* If RX FIFO overflow, need to flush RX FIFO first */
+ if (isr_status & DEVCFG_ISR_RX_FIFO_OV) {
+ writel(DEVCFG_MCTRL_RFIFO_FLUSH, &devcfg_base->mctrl);
+ writel(0xFFFFFFFF, &devcfg_base->int_sts);
+ }
+ return FPGA_FAIL;
+ }
+
+ status = readl(&devcfg_base->status);
+
+ debug("%s: Status = 0x%08X\n", __func__, status);
+
+ if (status & DEVCFG_STATUS_DMA_CMD_Q_F) {
+ debug("%s: Error: device busy\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ debug("%s: Device ready\n", __func__);
+
+ if (!(status & DEVCFG_STATUS_DMA_CMD_Q_E)) {
+ if (!(readl(&devcfg_base->int_sts) & DEVCFG_ISR_DMA_DONE)) {
+ /* Error state, transfer cannot occur */
+ debug("%s: ISR indicates error\n", __func__);
+ return FPGA_FAIL;
+ } else {
+ /* Clear out the status */
+ writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);
+ }
+ }
+
+ if (status & DEVCFG_STATUS_DMA_DONE_CNT_MASK) {
+ /* Clear the count of completed DMA transfers */
+ writel(DEVCFG_STATUS_DMA_DONE_CNT_MASK, &devcfg_base->status);
+ }
+
+ return FPGA_SUCCESS;
+}
+
+static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap)
+{
+ u32 *new_buf;
+ u32 i;
+
+ if ((u32)buf != ALIGN((u32)buf, ARCH_DMA_MINALIGN)) {
+ new_buf = (u32 *)ALIGN((u32)buf, ARCH_DMA_MINALIGN);
+
+ /*
+ * This might be dangerous but permits to flash if
+ * ARCH_DMA_MINALIGN is greater than header size
+ */
+ if (new_buf > buf) {
+ debug("%s: Aligned buffer is after buffer start\n",
+ __func__);
+ new_buf = (u32 *)((u32)new_buf - ARCH_DMA_MINALIGN);
+ }
+ printf("%s: Align buffer at %x to %x(swap %d)\n", __func__,
+ (u32)buf, (u32)new_buf, swap);
+
+ for (i = 0; i < (len/4); i++)
+ new_buf[i] = load_word(&buf[i], swap);
+
+ buf = new_buf;
+ } else if (swap != SWAP_DONE) {
+ /* For bitstream which are aligned */
+ u32 *new_buf = (u32 *)buf;
+
+ printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__,
+ swap);
+
+ for (i = 0; i < (len/4); i++)
+ new_buf[i] = load_word(&buf[i], swap);
+ }
+
+ return buf;
+}
+
+static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf,
+ size_t bsize, u32 blocksize, u32 *swap,
+ bitstream_type *bstype)
+{
+ u32 *buf_start;
+ u32 diff;
+
+ buf_start = check_data((u8 *)buf, blocksize, swap);
+
+ if (!buf_start)
+ return FPGA_FAIL;
+
+ /* Check if data is postpone from start */
+ diff = (u32)buf_start - (u32)buf;
+ if (diff) {
+ printf("%s: Bitstream is not validated yet (diff %x)\n",
+ __func__, diff);
+ return FPGA_FAIL;
+ }
+
+ if ((u32)buf < SZ_1M) {
+ log_err("Bitstream has to be placed above 1MB (%x)\n",
+ (u32)buf);
+ return FPGA_FAIL;
+ }
+
+ if (zynq_dma_xfer_init(*bstype))
+ return FPGA_FAIL;
+
+ return 0;
+}
+
+static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype, int flags)
+{
+ unsigned long ts; /* Timestamp */
+ u32 isr_status, swap;
+
+ /*
+ * send bsize inplace of blocksize as it was not a bitstream
+ * in chunks
+ */
+ if (zynq_validate_bitstream(desc, buf, bsize, bsize, &swap,
+ &bstype))
+ return FPGA_FAIL;
+
+ buf = zynq_align_dma_buffer((u32 *)buf, bsize, swap);
+
+ debug("%s: Source = 0x%08X\n", __func__, (u32)buf);
+ debug("%s: Size = %zu\n", __func__, bsize);
+
+ /* flush(clean & invalidate) d-cache range buf */
+ flush_dcache_range((u32)buf, (u32)buf +
+ roundup(bsize, ARCH_DMA_MINALIGN));
+
+ if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0))
+ return FPGA_FAIL;
+
+ isr_status = readl(&devcfg_base->int_sts);
+ /* Check FPGA configuration completion */
+ ts = get_timer(0);
+ while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT) {
+ printf("%s: Timeout wait for FPGA to config\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ isr_status = readl(&devcfg_base->int_sts);
+ }
+
+ debug("%s: FPGA config done\n", __func__);
+
+ if (bstype != BIT_PARTIAL)
+ zynq_slcr_devcfg_enable();
+
+ if (!IS_ENABLED(CONFIG_XPL_BUILD))
+ puts("INFO:post config was not run, please run manually if needed\n");
+
+ return FPGA_SUCCESS;
+}
+
+#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_XPL_BUILD)
+static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+ fpga_fs_info *fsinfo)
+{
+ unsigned long ts; /* Timestamp */
+ u32 isr_status, swap;
+ u32 partialbit = 0;
+ loff_t blocksize, actread;
+ loff_t pos = 0;
+ int fstype;
+ char *interface, *dev_part;
+ const char *filename;
+
+ blocksize = fsinfo->blocksize;
+ interface = fsinfo->interface;
+ dev_part = fsinfo->dev_part;
+ filename = fsinfo->filename;
+ fstype = fsinfo->fstype;
+
+ if (fs_set_blk_dev(interface, dev_part, fstype))
+ return FPGA_FAIL;
+
+ if (fs_read(filename, (u32) buf, pos, blocksize, &actread) < 0)
+ return FPGA_FAIL;
+
+ if (zynq_validate_bitstream(desc, buf, bsize, blocksize, &swap,
+ &partialbit))
+ return FPGA_FAIL;
+
+ dcache_disable();
+
+ do {
+ buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
+
+ if (zynq_dma_transfer((u32)buf | 1, blocksize >> 2,
+ 0xffffffff, 0))
+ return FPGA_FAIL;
+
+ bsize -= blocksize;
+ pos += blocksize;
+
+ if (fs_set_blk_dev(interface, dev_part, fstype))
+ return FPGA_FAIL;
+
+ if (bsize > blocksize) {
+ if (fs_read(filename, (u32) buf, pos, blocksize, &actread) < 0)
+ return FPGA_FAIL;
+ } else {
+ if (fs_read(filename, (u32) buf, pos, bsize, &actread) < 0)
+ return FPGA_FAIL;
+ }
+ } while (bsize > blocksize);
+
+ buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
+
+ if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0))
+ return FPGA_FAIL;
+
+ dcache_enable();
+
+ isr_status = readl(&devcfg_base->int_sts);
+
+ /* Check FPGA configuration completion */
+ ts = get_timer(0);
+ while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT) {
+ printf("%s: Timeout wait for FPGA to config\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ isr_status = readl(&devcfg_base->int_sts);
+ }
+
+ debug("%s: FPGA config done\n", __func__);
+
+ if (!partialbit)
+ zynq_slcr_devcfg_enable();
+
+ return FPGA_SUCCESS;
+}
+#endif
+
+struct xilinx_fpga_op zynq_op = {
+ .load = zynq_load,
+#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_XPL_BUILD)
+ .loadfs = zynq_loadfs,
+#endif
+};
+
+#ifdef CONFIG_CMD_ZYNQ_AES
+/*
+ * Load the encrypted image from src addr and decrypt the image and
+ * place it back the decrypted image into dstaddr.
+ */
+int zynq_decrypt_load(u32 srcaddr, u32 srclen, u32 dstaddr, u32 dstlen,
+ u8 bstype)
+{
+ u32 isr_status, ts;
+
+ if (srcaddr < SZ_1M || dstaddr < SZ_1M) {
+ printf("%s: src and dst addr should be > 1M\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+
+ /* Check AES engine is enabled */
+ if (!(readl(&devcfg_base->ctrl) &
+ DEVCFG_CTRL_PCFG_AES_EN_MASK)) {
+ printf("%s: AES engine is not enabled\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ if (zynq_dma_xfer_init(bstype)) {
+ printf("%s: zynq_dma_xfer_init FAIL\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ writel((readl(&devcfg_base->ctrl) | DEVCFG_CTRL_PCAP_RATE_EN_MASK),
+ &devcfg_base->ctrl);
+
+ debug("%s: Source = 0x%08X\n", __func__, (u32)srcaddr);
+ debug("%s: Size = %zu\n", __func__, srclen);
+
+ /* flush(clean & invalidate) d-cache range buf */
+ flush_dcache_range((u32)srcaddr, (u32)srcaddr +
+ roundup(srclen << 2, ARCH_DMA_MINALIGN));
+ /*
+ * Flush destination address range only if image is not
+ * bitstream.
+ */
+ if (bstype == BIT_NONE && dstaddr != 0xFFFFFFFF)
+ flush_dcache_range((u32)dstaddr, (u32)dstaddr +
+ roundup(dstlen << 2, ARCH_DMA_MINALIGN));
+
+ if (zynq_dma_transfer(srcaddr | 1, srclen, dstaddr | 1, dstlen))
+ return FPGA_FAIL;
+
+ if (bstype == BIT_FULL) {
+ isr_status = readl(&devcfg_base->int_sts);
+ /* Check FPGA configuration completion */
+ ts = get_timer(0);
+ while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
+ if (get_timer(ts) > CFG_SYS_FPGA_WAIT) {
+ printf("%s: Timeout wait for FPGA to config\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ isr_status = readl(&devcfg_base->int_sts);
+ }
+ printf("%s: FPGA config done\n", __func__);
+ zynq_slcr_devcfg_enable();
+ }
+
+ return FPGA_SUCCESS;
+}
+#endif