From: Chee Hong Ang <chee.hong....@intel.com> In non-secure mode (EL2), FPGA reconfiguration driver calls the SMC/PSCI services provided by ATF to configure the FPGA.
Signed-off-by: Chee Hong Ang <chee.hong....@intel.com> --- drivers/fpga/intel_sdm_mb.c | 139 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/drivers/fpga/intel_sdm_mb.c b/drivers/fpga/intel_sdm_mb.c index 9a1dc2c0c8..f5fd9a14c2 100644 --- a/drivers/fpga/intel_sdm_mb.c +++ b/drivers/fpga/intel_sdm_mb.c @@ -8,11 +8,149 @@ #include <log.h> #include <watchdog.h> #include <asm/arch/mailbox_s10.h> +#include <asm/arch/smc_api.h> #include <linux/delay.h> +#include <linux/intel-smc.h> #define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS 60000 #define RECONFIG_STATUS_INTERVAL_DELAY_US 1000000 +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF) + +#define BITSTREAM_CHUNK_SIZE 0xFFFF0 +#define RECONFIG_STATUS_POLL_RETRY_MAX 100 + +/* + * 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 = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_ISDONE, NULL, 0, + NULL, 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); + WATCHDOG_RESET(); + } + + 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) + 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); + } + WATCHDOG_RESET(); + } + + 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; + + debug("Invoking FPGA_CONFIG_START...\n"); + + ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_START, &arg, 1, NULL, 0); + + if (ret) { + puts("Failure in RECONFIG mailbox command!\n"); + return ret; + } + + ret = send_bitstream(rbf_data, rbf_size); + if (ret) { + puts("Error sending bitstream!\n"); + 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) { + puts("FPGA reconfiguration failed!"); + return ret; + } + + puts("FPGA reconfiguration OK!\n"); + + return ret; +} + +#else + static const struct mbox_cfgstat_state { int err_no; const char *error_name; @@ -286,3 +424,4 @@ int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) return ret; } +#endif -- 2.13.0