summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChee Hong Ang <chee.hong.ang@intel.com>2018-03-12 19:26:26 +0800
committerChee Hong Ang <chee.hong.ang@intel.com>2018-03-15 00:54:11 +0800
commit0bc2894b900be99915ea851664cbc0428b303f1d (patch)
tree09eb370937b6c8e9c9b5f571dfd6b47ab09a1082
parentd97e2bf12068173fe827ddfc9c0421d85061210f (diff)
downloadu-boot-socfpga-0bc2894b900be99915ea851664cbc0428b303f1d.tar.gz
FogBugz #540144-7: Add S10 FPGA configuration SMC (SiP) services
Allow PSCI layer to handle the S10 FPGA configuration service calls. All these services are also known as FPGA configuration service layer for S10. This service layer support FPGA configuration service requests from OS (EL1). It acts as the middle layer between SDM (Secure Device Manager) and the OS. It enables OS (EL1) to invoke SMC call to this service layer (EL3) and pass the FPGA bit stream to SDM for FPGA configuration. Signed-off-by: Chee Hong Ang <chee.hong.ang@intel.com>
-rw-r--r--arch/arm/mach-socfpga/Kconfig4
-rw-r--r--arch/arm/mach-socfpga/Makefile1
-rw-r--r--arch/arm/mach-socfpga/smc_fpga_reconfig_s10.c469
-rw-r--r--include/linux/intel-smc.h234
4 files changed, 708 insertions, 0 deletions
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index c0e48fcc22..368219e0e4 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -131,6 +131,10 @@ config TARGET_SOCFPGA_STRATIX10_SOCDK
bool "Intel SOCFPGA SoCDK (Stratix 10)"
select TARGET_SOCFPGA_STRATIX10
+config STRATIX10_FPGA_RECONFIG
+ bool "Intel Stratix 10 FPGA configuration support"
+ depends on TARGET_SOCFPGA_STRATIX10_SOCDK
+
config TARGET_SOCFPGA_TERASIC_DE0_NANO
bool "Terasic DE0-Nano-Atlas (Cyclone V)"
select TARGET_SOCFPGA_CYCLONE5
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index 15a5271ccb..b2b514e68a 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -40,6 +40,7 @@ obj-y += reset_manager_s10.o
obj-y += system_manager_s10.o
obj-y += wrap_pinmux_config_s10.o
obj-y += wrap_pll_config_s10.o
+obj-$(CONFIG_STRATIX10_FPGA_RECONFIG) += smc_fpga_reconfig_s10.o
endif
ifdef CONFIG_SPL_BUILD
diff --git a/arch/arm/mach-socfpga/smc_fpga_reconfig_s10.c b/arch/arm/mach-socfpga/smc_fpga_reconfig_s10.c
new file mode 100644
index 0000000000..ce9fb185e3
--- /dev/null
+++ b/arch/arm/mach-socfpga/smc_fpga_reconfig_s10.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2018 Intel Corporation. All rights reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/psci.h>
+#include <asm/secure.h>
+#include <asm/arch/mailbox_s10.h>
+#include <linux/intel-smc.h>
+
+#define FPGA_CONFIG_RESEVED_MEM_START 0x1000
+#define FPGA_CONFIG_RESERVED_MEM_SIZE 0x1000000 /* 16 MB */
+
+#define SMC_ARG0 0
+#define SMC_ARG1 (SMC_ARG0 + 1)
+#define SMC_ARG2 (SMC_ARG1 + 1)
+#define SMC_ARG3 (SMC_ARG2 + 1)
+#define SMC_RETURN_ARGS_MAX (SMC_ARG3 + 1)
+
+/* Macro functions for allocation and read/write of
+ variables to be assigned to registers */
+/* Allocate memory for variable */
+#define SMC_ALLOC_REG_MEM(var) unsigned long var[SMC_RETURN_ARGS_MAX]
+/* Clear variable */
+#define SMC_INIT_REG_MEM(var) \
+ do { \
+ int i; \
+ for (i = 0; i < SMC_RETURN_ARGS_MAX; i++) \
+ var[i] = 0; \
+ } while (0)
+/* Read variable */
+#define SMC_GET_REG_MEM(var, i) var[i]
+/* Write Variable */
+#define SMC_ASSIGN_REG_MEM(var, i, val) \
+ do { \
+ var[i] = (val); \
+ } while (0)
+/* Assign variables back to registers */
+#define SMC_RET_REG_MEM(var) \
+ do { \
+ asm volatile("ldr x0, %0\n" \
+ "ldr x1, %1\n" \
+ "ldr x2, %2\n" \
+ "ldr x3, %3\n" \
+ : : "m" (var[0]), "m" (var[1]), \
+ "m" (var[2]), "m" (var[3]) : ); \
+ } while (0)
+
+#define FPGA_CONFIG_BUF_MAX 16
+
+#define FPGA_BUF_STAT_IDLE 0
+#define FPGA_BUF_STAT_PENDING 1
+#define FPGA_BUF_STAT_COMPLETED 2
+#define FPGA_BUF_STAT_SUCCESS 3
+#define FPGA_BUF_STAT_ERROR 4
+
+#define IS_BUF_FREE(x) (x.state == FPGA_BUF_STAT_IDLE)
+#define IS_BUF_PENDING(x) (x.state == FPGA_BUF_STAT_PENDING)
+#define IS_BUF_SUBMITTED(x) (x.state >= FPGA_BUF_STAT_PENDING && \
+ x.submit_count > 0)
+#define IS_BUF_COMPLETED(x) (x.state == FPGA_BUF_STAT_COMPLETED && \
+ x.submit_count > 0)
+#define IS_BUF_FULLY_COMPLETED(x) (x.state == FPGA_BUF_STAT_COMPLETED && \
+ x.submit_count == 0)
+#define IS_BUF_SUCCESS(x) (x.state == FPGA_BUF_STAT_SUCCESS)
+#define IS_BUF_ERROR(x) (x.state == FPGA_BUF_STAT_ERROR)
+
+static __secure_data struct fpga_buf_list {
+ u32 state;
+ u32 buf_id;
+ u64 buf_addr;
+ u64 buf_size;
+ u32 buf_off;
+ u32 submit_count;
+} fpga_buf_list[FPGA_CONFIG_BUF_MAX];
+
+static u8 __secure_data fpga_error = 1;
+static u8 __secure_data fpga_buf_id = 1;
+static u32 __secure_data fpga_xfer_max = 4;
+static u32 __secure_data fpga_buf_read_index;
+static u32 __secure_data fpga_buf_write_index;
+static u32 __secure_data fpga_buf_count;
+/* 20bits DMA size with 8 bytes alignment */
+static u32 __secure_data fpga_buf_size_max = 0xFFFF8;
+/* Number of data blocks received from OS(EL1) */
+static u32 __secure_data fpga_buf_rcv_count;
+/* Number of data blocks submitted to SDM */
+static u32 __secure_data fpga_xfer_submitted_count;
+
+/* Check for any responses from SDM and update the status in buffer list */
+static void __secure reclaim_completed_buf(void)
+{
+ u32 i, j;
+ u32 resp_len;
+ u32 buf[MBOX_RESP_BUFFER_SIZE];
+
+ /* If no buffer has been submitted to SDM */
+ if (!fpga_xfer_submitted_count)
+ return;
+
+ /* Read the SDM responses asynchronously */
+ resp_len = mbox_rcv_resp_psci(buf, MBOX_RESP_BUFFER_SIZE);
+
+ for (i = 0; i < resp_len; i++) {
+ /* Skip mailbox response headers which are not belong to us */
+ if (MBOX_RESP_LEN_GET(buf[i]) ||
+ MBOX_RESP_CLIENT_GET(buf[i]) != MBOX_CLIENT_ID_UBOOT)
+ continue;
+
+ for (j = 0; j < FPGA_CONFIG_BUF_MAX; j++) {
+ /* Check buffer id */
+ if (fpga_buf_list[j].buf_id !=
+ MBOX_RESP_ID_GET(buf[i]))
+ continue;
+
+ if (IS_BUF_SUBMITTED(fpga_buf_list[j])) {
+ if (fpga_buf_list[j].submit_count)
+ fpga_buf_list[j].submit_count--;
+ fpga_xfer_submitted_count--;
+ /* Error occur in transaction */
+ if (MBOX_RESP_ERR_GET(buf[i])) {
+ fpga_error = 1;
+ fpga_buf_list[j].state =
+ FPGA_BUF_STAT_ERROR;
+ fpga_buf_list[j].submit_count = 0;
+ } else if (IS_BUF_FULLY_COMPLETED(
+ fpga_buf_list[j])) {
+ /* Last chunk in buffer and no error */
+ fpga_buf_list[j].state =
+ FPGA_BUF_STAT_SUCCESS;
+ }
+ break;
+ } else if (IS_BUF_ERROR(fpga_buf_list[j])) {
+ fpga_xfer_submitted_count--;
+ break;
+ }
+ }
+ }
+}
+
+static void __secure do_xfer_buf(void)
+{
+ u32 i = fpga_buf_read_index;
+ u32 args[3];
+ int ret;
+
+ /* No buffer found in buffer list or SDM can't handle xfer anymore */
+ if (!fpga_buf_rcv_count ||
+ fpga_xfer_submitted_count == fpga_xfer_max)
+ return;
+
+ while (fpga_xfer_submitted_count < fpga_xfer_max) {
+ if (IS_BUF_FREE(fpga_buf_list[i]) ||
+ IS_BUF_ERROR(fpga_buf_list[i]))
+ break;
+ if (IS_BUF_PENDING(fpga_buf_list[i])) {
+ args[0] = (1 << 8);
+ args[1] = (u32)(fpga_buf_list[i].buf_addr +
+ fpga_buf_list[i].buf_off);
+ if ((fpga_buf_list[i].buf_size -
+ fpga_buf_list[i].buf_off) > fpga_buf_size_max) {
+ args[2] = fpga_buf_size_max;
+ fpga_buf_list[i].buf_off += fpga_buf_size_max;
+ } else {
+ args[2] = (u32)(fpga_buf_list[i].buf_size -
+ fpga_buf_list[i].buf_off);
+ fpga_buf_list[i].state =
+ FPGA_BUF_STAT_COMPLETED;
+ }
+
+ ret = mbox_send_cmd_only_psci(fpga_buf_list[i].buf_id,
+ MBOX_RECONFIG_DATA, MBOX_CMD_INDIRECT, 3,
+ args);
+ if (ret) {
+ fpga_error = 1;
+ fpga_buf_list[i].state =
+ FPGA_BUF_STAT_ERROR;
+ fpga_buf_list[i].submit_count = 0;
+ break;
+ } else {
+ fpga_buf_list[i].submit_count++;
+ fpga_xfer_submitted_count++;
+ }
+
+ if (fpga_xfer_submitted_count >= fpga_xfer_max)
+ break;
+ }
+
+ if (IS_BUF_COMPLETED(fpga_buf_list[i]) ||
+ IS_BUF_SUCCESS(fpga_buf_list[i])) {
+ i++;
+ i %= FPGA_CONFIG_BUF_MAX;
+ if (i == fpga_buf_write_index)
+ break;
+ }
+ }
+}
+
+static void __secure smc_socfpga_config_get_mem(unsigned long function_id)
+{
+ SMC_ALLOC_REG_MEM(r);
+
+ SMC_INIT_REG_MEM(r);
+
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0, INTEL_SIP_SMC_STATUS_OK);
+ /* Start physical address of reserved memory */
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG1, FPGA_CONFIG_RESEVED_MEM_START);
+ /* Size of reserved memory */
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG2, FPGA_CONFIG_RESERVED_MEM_SIZE -
+ FPGA_CONFIG_RESEVED_MEM_START);
+
+ SMC_RET_REG_MEM(r);
+}
+
+static void __secure smc_socfpga_config_start(unsigned long function_id,
+ unsigned long config_type)
+{
+ SMC_ALLOC_REG_MEM(r);
+ int ret, i;
+ u32 resp_len = 2;
+ u32 resp_buf[2];
+
+ /* Clear any previous pending SDM reponses */
+ mbox_rcv_resp_psci(NULL, MBOX_RESP_BUFFER_SIZE);
+
+ SMC_INIT_REG_MEM(r);
+
+ fpga_error = 0;
+
+ ret = mbox_send_cmd_psci(MBOX_ID_UBOOT, MBOX_RECONFIG, MBOX_CMD_DIRECT,
+ 0, NULL, 0, &resp_len, resp_buf);
+ if (ret) {
+ fpga_error = 1;
+ goto ret;
+ }
+
+ /* Init state in buffer list PGA_CONFIG_RESERVED_MEM_SIZ*/
+ for (i = 0; i < FPGA_CONFIG_BUF_MAX; i++) {
+ fpga_buf_list[i].state = FPGA_BUF_STAT_IDLE;
+ fpga_buf_list[i].buf_id = 0;
+ }
+
+ /* Read maximum transaction allowed by SDM */
+ fpga_xfer_max = resp_buf[0];
+ /* Read maximum buffer size allowed by SDM */
+ fpga_buf_size_max = resp_buf[1];
+ fpga_buf_count = 0;
+ fpga_buf_rcv_count = 0;
+ fpga_xfer_submitted_count = 0;
+ fpga_buf_read_index = 0;
+ fpga_buf_write_index = 0;
+ fpga_buf_id = 1;
+ret:
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0, INTEL_SIP_SMC_STATUS_OK);
+
+ SMC_RET_REG_MEM(r);
+}
+
+static void __secure smc_socfpga_config_write(
+ unsigned long function_id,
+ unsigned long phys_addr,
+ unsigned long phys_size)
+{
+ SMC_ALLOC_REG_MEM(r);
+
+ SMC_INIT_REG_MEM(r);
+
+ reclaim_completed_buf();
+
+ if (fpga_error) {
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR);
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG1,
+ fpga_buf_list[fpga_buf_read_index].
+ buf_addr);
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG2,
+ fpga_buf_list[fpga_buf_read_index].
+ buf_size);
+ goto ret;
+ }
+
+ do_xfer_buf();
+
+ if (fpga_buf_rcv_count == fpga_xfer_max ||
+ (fpga_buf_count == FPGA_CONFIG_BUF_MAX &&
+ fpga_buf_write_index == fpga_buf_read_index)) {
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_REJECTED);
+ goto ret;
+ }
+
+ if (!phys_addr || !phys_size) {
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR);
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG1, phys_addr);
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG2, phys_size);
+ goto ret;
+ }
+
+ /* Look for free buffer in buffer list */
+ if (IS_BUF_FREE(fpga_buf_list[fpga_buf_write_index])) {
+ fpga_buf_list[fpga_buf_write_index].state =
+ FPGA_BUF_STAT_PENDING;
+ fpga_buf_list[fpga_buf_write_index].buf_addr = phys_addr;
+ fpga_buf_list[fpga_buf_write_index].buf_size = phys_size;
+ fpga_buf_list[fpga_buf_write_index].buf_off = 0;
+ fpga_buf_list[fpga_buf_write_index].buf_id = fpga_buf_id++;
+ /* Rollover buffer id */
+ if (fpga_buf_id > 15)
+ fpga_buf_id = 1;
+ fpga_buf_count++;
+ fpga_buf_write_index++;
+ fpga_buf_write_index %= FPGA_CONFIG_BUF_MAX;
+ fpga_buf_rcv_count++;
+ if (fpga_buf_rcv_count == fpga_xfer_max)
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY);
+ else
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_STATUS_OK);
+ /* Attempt to submit new buffer to SDM */
+ do_xfer_buf();
+ } else {
+ /* No free buffer avalable in buffer list */
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_REJECTED);
+ }
+
+ret:
+ SMC_RET_REG_MEM(r);
+}
+
+static void __secure smc_socfpga_config_completed_write(unsigned long function_id)
+{
+ SMC_ALLOC_REG_MEM(r);
+ int i;
+ int count = 3, r_index = 1;
+
+ SMC_INIT_REG_MEM(r);
+
+ reclaim_completed_buf();
+ do_xfer_buf();
+
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_STATUS_OK);
+
+ for (i = 0; i < FPGA_CONFIG_BUF_MAX; i++) {
+ if (IS_BUF_SUCCESS(fpga_buf_list[fpga_buf_read_index])) {
+ SMC_ASSIGN_REG_MEM(r, r_index++,
+ fpga_buf_list[fpga_buf_read_index].buf_addr);
+ fpga_buf_list[fpga_buf_read_index].state =
+ FPGA_BUF_STAT_IDLE;
+ fpga_buf_list[fpga_buf_read_index].buf_id = 0;
+ fpga_buf_count--;
+ fpga_buf_read_index++;
+ fpga_buf_read_index %= FPGA_CONFIG_BUF_MAX;
+ fpga_buf_rcv_count--;
+ count--;
+ if (!count)
+ break;
+ } else if (IS_BUF_ERROR(fpga_buf_list[fpga_buf_read_index]) &&
+ !fpga_buf_list[fpga_buf_read_index].submit_count) {
+ SMC_INIT_REG_MEM(r);
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR);
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG1,
+ fpga_buf_list[fpga_buf_read_index].buf_addr);
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG2,
+ fpga_buf_list[fpga_buf_read_index].buf_size);
+ goto ret;
+ }
+ }
+
+ /* No completed buffers found */
+ if (r_index == 1 && fpga_xfer_submitted_count)
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY);
+
+ret:
+ SMC_RET_REG_MEM(r);
+}
+
+static void __secure smc_socfpga_config_isdone(unsigned long function_id)
+{
+ SMC_ALLOC_REG_MEM(r);
+ u32 reconfig_status_resp_len;
+ u32 reconfig_status_resp[RECONFIG_STATUS_RESPONSE_LEN];
+ int ret;
+
+ SMC_INIT_REG_MEM(r);
+
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0, INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY);
+
+ reclaim_completed_buf();
+ do_xfer_buf();
+
+ if (fpga_error) {
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR);
+ goto ret;
+ }
+
+ if (fpga_xfer_submitted_count)
+ goto ret;
+
+ reconfig_status_resp_len = RECONFIG_STATUS_RESPONSE_LEN;
+ ret = mbox_send_cmd_psci(MBOX_ID_UBOOT, MBOX_RECONFIG_STATUS,
+ MBOX_CMD_DIRECT, 0, NULL, 0,
+ &reconfig_status_resp_len,
+ reconfig_status_resp);
+
+ if (ret) {
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR);
+ goto ret;
+ }
+
+ /* Check for any error */
+ ret = reconfig_status_resp[RECONFIG_STATUS_STATE];
+ if (ret && ret != MBOX_CFGSTAT_STATE_CONFIG)
+ goto ret;
+
+ /* Make sure nStatus is not 0 */
+ ret = reconfig_status_resp[RECONFIG_STATUS_PIN_STATUS];
+ if (!(ret & RCF_PIN_STATUS_NSTATUS)) {
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR);
+ goto ret;
+ }
+
+ ret = reconfig_status_resp[RECONFIG_STATUS_SOFTFUNC_STATUS];
+ if (ret & RCF_SOFTFUNC_STATUS_SEU_ERROR) {
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR);
+ goto ret;
+ }
+
+ if ((ret & RCF_SOFTFUNC_STATUS_CONF_DONE) &&
+ (ret & RCF_SOFTFUNC_STATUS_INIT_DONE) &&
+ !reconfig_status_resp[RECONFIG_STATUS_STATE]) {
+ /* FPGA configuration completed successfully */
+ SMC_ASSIGN_REG_MEM(r, SMC_ARG0,
+ INTEL_SIP_SMC_STATUS_OK);
+ goto ret;
+ }
+
+ret:
+ if (SMC_GET_REG_MEM(r, SMC_ARG0) ==
+ INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR)
+ fpga_error = 1;
+
+ SMC_RET_REG_MEM(r);
+}
+
+DECLARE_SECURE_SVC(config_get_mem, INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM,
+ smc_socfpga_config_get_mem);
+DECLARE_SECURE_SVC(config_start, INTEL_SIP_SMC_FPGA_CONFIG_START,
+ smc_socfpga_config_start);
+DECLARE_SECURE_SVC(config_write, INTEL_SIP_SMC_FPGA_CONFIG_WRITE,
+ smc_socfpga_config_write);
+DECLARE_SECURE_SVC(config_completed_write,
+ INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE,
+ smc_socfpga_config_completed_write);
+DECLARE_SECURE_SVC(config_isdone, INTEL_SIP_SMC_FPGA_CONFIG_ISDONE,
+ smc_socfpga_config_isdone);
diff --git a/include/linux/intel-smc.h b/include/linux/intel-smc.h
new file mode 100644
index 0000000000..1a07629633
--- /dev/null
+++ b/include/linux/intel-smc.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2018 Intel Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __INTEL_SMC_H
+#define __INTEL_SMC_H
+
+
+#include <linux/arm-smccc.h>
+#ifndef __ASSEMBLY__
+#include <linux/bitops.h>
+#endif
+
+/*
+ * This file defines the Secure Monitor Call (SMC) message protocol used for
+ * service driver in normal world (EL1) to communicate with bootloader
+ * in Secure Monitor Exception level 3 (EL3)
+ *
+ * An ARM SMC instruction takes a function identifier and up to 6 64-bit
+ * register values as arguments, and can return up to 4 64-bit register
+ * value. The operation of the secure monitor is determined by the parameter
+ * values passed in through registers.
+
+ * EL1 and EL3 communicates pointer as physical address rather than the
+ * virtual address
+ */
+
+
+/*
+ * Functions specified by ARM SMC Calling convention
+ *
+ * FAST call executes atomic operations, returns when the requested operation
+ * has completed
+ * STD call starts a operation which can be preempted by a non-secure
+ * interrupt. The call can return before the requested operation has
+ * completed
+ *
+ * a0..a7 is used as register names in the descriptions below, on arm32
+ * that translates to r0..r7 and on arm64 to w0..w7
+ */
+
+#define INTEL_SIP_SMC_STD_CALL_VAL(func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_SIP, (func_num))
+
+#define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_SIP, (func_num))
+
+
+/*
+ * Return values in INTEL_SIP_SMC_* call
+ *
+ * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION:
+ * Secure world does not recognize this request
+ *
+ * INTEL_SIP_SMC_STATUS_OK:
+ * FPGA configuration completed successfully,
+ * In case of FPGA configuration write operation, it
+ * means bootloader can accept the next chunk of FPGA
+ * configuration data
+ *
+ * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY:
+ * In case of FPGA configuration write operation, it means
+ * bootloader is still processing previous data & can't accept
+ * the next chunk of data. Service driver needs to issue
+ * INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE call to query the
+ * completed block(s)
+ *
+ * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR:
+ * There is error during the FPGA configuration process
+ */
+#define INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF
+#define INTEL_SIP_SMC_STATUS_OK 0x0
+#define INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY 0x1
+#define INTEL_SIP_SMC_FPGA_CONFIG_STATUS_REJECTED 0x2
+#define INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR 0x4
+
+/*
+ * a0..a7 is used as register names in the descriptions below, on arm32
+ * that translates to r0..r7 and on arm64 to w0..w7.
+ */
+
+
+/*
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_START
+ *
+ * Sync call used by service driver at EL1 to request the FPGA in EL3 to
+ * be prepare to receive a new configuration
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_FPGA_CONFIG_START
+ * a1-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK indicates secure world is ready for
+ * FPGA configuration, or negative value for failure
+ * a1-3: not used
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_START 1
+#define INTEL_SIP_SMC_FPGA_CONFIG_START \
+ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_START)
+
+
+/*
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_WRITE
+ *
+ * Async call used by service driver at EL1 to provide FPGA configuration data
+ * to secure world
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_FPGA_CONFIG_WRITE
+ * a1 64bit physical address of the configuration data memory block
+ * a2 Size of configuration data block
+ * a3-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ * a1 64bit physical address of 1st completed memory block if
+ * any completed block, otherwise zero value
+ * a2 64bit physical address of 2nd completed memory block if
+ * any completed block, otherwise zero value
+ * a3 64bit physical address of 3rd completed memory block if
+ * any completed block, otherwise zero value
+ *
+ * Or
+ * a0 INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY
+ * a1-3 not used
+ *
+ * Or
+ * a0 INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR
+ * a1-3 not used
+*/
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_WRITE 2
+#define INTEL_SIP_SMC_FPGA_CONFIG_WRITE \
+ INTEL_SIP_SMC_STD_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_WRITE)
+
+
+/*
+* Request INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE
+*
+* Sync call used by service driver at EL1 to track the completed write
+* transactions. This request is called after INTEL_SIP_SMC_FPGA_CONFIG_WRITE
+* call with INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY
+*
+* Call register usage:
+* a0 INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE
+* a1-7 not used
+*
+* Return status
+* a0 INTEL_SIP_SMC_STATUS_OK
+* a1 64bit physical address of 1st completed memory block
+* a2 64bit physical address of 2nd completed memory block if
+* any completed block, otherwise zero value
+* a3 64bit physical address of 3rd completed memory block if
+* any completed block, otherwise zero value
+*
+* Or
+* a0 INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY
+* a1-3 not used
+*
+* Or
+* a0 INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR
+* a1-3 not used
+*/
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE 3
+#define INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE \
+ INTEL_SIP_SMC_FAST_CALL_VAL( \
+ INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
+
+
+/*
+* Request INTEL_SIP_SMC_FPGA_CONFIG_ISDONE
+*
+* Sync call used by service driver at EL1 to inform secure world that all
+* data are sent, to check whether or not the secure world completes
+* the FPGA configuration process
+*
+* Call register usage:
+* a0 INTEL_SIP_SMC_FPGA_CONFIG_ISDONE
+* a1-7 not used
+*
+* Return status
+* a0 INTEL_SIP_SMC_STATUS_OK for FPGA configuration process completed
+* successfully
+*
+* or
+* INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY for FPGA configuration is still
+* in process
+*
+* or
+* INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR for error encountered during
+* FPGA configuration
+*
+* a1-3: not used
+*/
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_ISDONE 4
+#define INTEL_SIP_SMC_FPGA_CONFIG_ISDONE \
+ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_ISDONE)
+
+
+
+/*
+* Request INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM
+*
+* Sync call used by service driver at EL1 to query the physical address of
+* memory block reserved by bootloader
+*
+* Call register usage:
+* a0 INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM
+* a1-7 not used
+*
+* Return status
+* a0 INTEL_SIP_SMC_STATUS_OK
+* a1: start of physical address of reserved memory block
+* a2: size of reserved memory block
+* a3: not used
+*/
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_GET_MEM 5
+#define INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM \
+ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_GET_MEM)
+#endif