From: Chee Hong Ang <chee.hong....@intel.com>

Enable FPGA reconfiguration support on Stratix10 SoC.

Signed-off-by: Chee Hong Ang <chee.hong....@intel.com>
---
 drivers/fpga/Kconfig     |  10 ++
 drivers/fpga/Makefile    |   1 +
 drivers/fpga/stratix10.c | 298 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 309 insertions(+)
 create mode 100644 drivers/fpga/stratix10.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index d36c4c5..255683d 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -31,6 +31,16 @@ config FPGA_CYCLON2
          Enable FPGA driver for loading bitstream in BIT and BIN format
          on Altera Cyclone II device.
 
+config FPGA_STRATIX10
+       bool "Enable Altera FPGA driver for Stratix 10"
+       depends on FPGA_ALTERA && TARGET_SOCFPGA_STRATIX10
+       help
+         Say Y here to enable the Altera Stratix 10 FPGA specific driver
+
+         This provides common functionality for Altera Stratix 10 devices.
+         Enable FPGA driver for writing bitstream into Altera Stratix10
+         device.
+
 config FPGA_XILINX
        bool "Enable Xilinx FPGA drivers"
        select FPGA
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 08c9ff8..3c906ec 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o
 obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o
 obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o
 obj-$(CONFIG_FPGA_STRATIX_V) += stratixv.o
+obj-$(CONFIG_FPGA_STRATIX10) += stratix10.o
 obj-$(CONFIG_FPGA_SOCFPGA) += socfpga.o
 obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += socfpga_gen5.o
 obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += socfpga_arria10.o
diff --git a/drivers/fpga/stratix10.c b/drivers/fpga/stratix10.c
new file mode 100644
index 0000000..f0c5ace
--- /dev/null
+++ b/drivers/fpga/stratix10.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2018 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <altera.h>
+#include <asm/arch/mailbox_s10.h>
+
+#define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS           60000
+#define RECONFIG_STATUS_INTERVAL_DELAY_US              1000000
+
+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, "Acknowledgement 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!"},
+       {-ETIMEDOUT, "I/O timeout error"},
+       {-1, "Unknown error!"}
+};
+
+#define MBOX_CFGSTAT_MAX \
+         (sizeof(mbox_cfgstat_state) / sizeof(struct 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;
+}
+
+static void inc_cmd_id(u8 *id)
+{
+       u8 val = *id + 1;
+
+       if (val > 15)
+               val = 1;
+
+       *id = val;
+}
+
+/*
+ * Polling the FPGA configuration status.
+ * Return 0 for success, non-zero for error.
+ */
+static int reconfig_status_polling_resp(void)
+{
+       u32 reconfig_status_resp_len;
+       u32 reconfig_status_resp[RECONFIG_STATUS_RESPONSE_LEN];
+       int ret;
+       unsigned long start = get_timer(0);
+
+       while (1) {
+               reconfig_status_resp_len = RECONFIG_STATUS_RESPONSE_LEN;
+               ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RECONFIG_STATUS,
+                                   MBOX_CMD_DIRECT, 0, NULL, 0,
+                                   &reconfig_status_resp_len,
+                                   reconfig_status_resp);
+
+               if (ret) {
+                       puts("Failure in RECONFIG_STATUS mailbox command!\n");
+                       return ret;
+               }
+
+               /* Check for any error */
+               ret = reconfig_status_resp[RECONFIG_STATUS_STATE];
+               if (ret && ret != MBOX_CFGSTAT_STATE_CONFIG)
+                       return ret;
+
+               /* Make sure nStatus is not 0 */
+               ret = reconfig_status_resp[RECONFIG_STATUS_PIN_STATUS];
+               if (!(ret & RCF_PIN_STATUS_NSTATUS))
+                       return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
+
+               ret = reconfig_status_resp[RECONFIG_STATUS_SOFTFUNC_STATUS];
+               if (ret & RCF_SOFTFUNC_STATUS_SEU_ERROR)
+                       return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
+
+               if ((ret & RCF_SOFTFUNC_STATUS_CONF_DONE) &&
+                   (ret & RCF_SOFTFUNC_STATUS_INIT_DONE) &&
+                   !reconfig_status_resp[RECONFIG_STATUS_STATE])
+                       return 0;       /* configuration success */
+
+               if (get_timer(start) > RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
+                       break;  /* time out */
+
+               puts(".");
+               udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+       }
+
+       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 i;
+       u32 mbox_hdr;
+       u32 resp_len;
+       u32 hdr_len;
+       u32 buf[MBOX_RESP_BUFFER_SIZE];
+
+       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;
+}
+
+static int send_reconfig_data(const void *rbf_data, size_t rbf_size,
+                             u32 xfer_max, u32 buf_size_max)
+{
+       u32 resp_rindex = 0;
+       u32 resp_windex = 0;
+       u32 resp_count = 0;
+       u32 response_buffer[MBOX_RESP_BUFFER_SIZE];
+       u8 resp_err = 0;
+       u8 cmd_id = 1;
+       u32 xfer_count = 0;
+       u32 xfer_pending[MBOX_RESP_BUFFER_SIZE];
+       u32 args[3];
+       int ret = 0;
+       u32 i;
+
+       debug("SDM xfer_max = %d\n", xfer_max);
+       debug("SDM buf_size_max = %x\n\n", buf_size_max);
+
+       for (i = 0; i < MBOX_RESP_BUFFER_SIZE; i++)
+               xfer_pending[i] = 0;
+
+       while (rbf_size || xfer_count) {
+               if (!resp_err && rbf_size && xfer_count < xfer_max) {
+                       args[0] = (1 << 8);
+                       args[1] = (u32)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] = (u32)rbf_size;
+                               rbf_size = 0;
+                       }
+
+                       debug("Sending MBOX_RECONFIG_DATA...\n");
+
+                       ret = mbox_send_cmd_only(cmd_id, MBOX_RECONFIG_DATA,
+                                                MBOX_CMD_INDIRECT, 3, args);
+                       if (ret) {
+                               resp_err = 1;
+                       } else {
+                               xfer_count++;
+                               for (i = 0; i < MBOX_RESP_BUFFER_SIZE; i++) {
+                                       if (!xfer_pending[i]) {
+                                               xfer_pending[i] = cmd_id;
+                                               inc_cmd_id(&cmd_id);
+                                               break;
+                                       }
+                               }
+                               debug("+xfer_count = %d\n", xfer_count);
+                               debug("xfer ID = %d\n", xfer_pending[i]);
+                               debug("data offset = %08x\n", args[1]);
+                               debug("data size = %08x\n", args[2]);
+                       }
+#ifndef DEBUG
+                       puts(".");
+#endif
+               } else {
+                       u32 r_id = 0;
+                       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 */
+                       if (!resp_hdr)
+                               continue;
+
+                       /* Expect 0 length from RECONFIG_DATA */
+                       if (MBOX_RESP_LEN_GET(resp_hdr))
+                               continue;
+
+                       /* Check for response's status */
+                       if (!resp_err) {
+                               ret = MBOX_RESP_ERR_GET(resp_hdr);
+                               debug("Response error code: %08x\n", ret);
+                               /* Error in response */
+                               if (ret)
+                                       resp_err = 1;
+                       }
+
+                       /* Read the response header's ID */
+                       r_id = MBOX_RESP_ID_GET(resp_hdr);
+                       for (i = 0; i < MBOX_RESP_BUFFER_SIZE; i++) {
+                               if (r_id == xfer_pending[i]) {
+                                       /* Reclaim ID */
+                                       cmd_id = (u32)xfer_pending[i];
+                                       xfer_pending[i] = 0;
+                                       xfer_count--;
+                                       break;
+                               }
+                       }
+
+                       debug("Reclaimed xfer ID = %d\n", cmd_id);
+                       debug("-xfer_count = %d\n", xfer_count);
+                       if (resp_err && !xfer_count)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * This is the interface used by FPGA driver.
+ * Return 0 for success, non-zero for error.
+ */
+int stratix10_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
+{
+       int ret;
+       u32 resp_len = 2;
+       u32 resp_buf[2];
+
+       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("\nPolling with MBOX_RECONFIG_STATUS...\n");
+       ret = reconfig_status_polling_resp();
+       if (ret) {
+               printf("Error: %s\n", mbox_cfgstat_to_str(ret));
+               return ret;
+       }
+
+       puts("\nFPGA reconfiguration OK!\n");
+
+       return ret;
+}
-- 
2.2.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to