diff --git a/plat/intel/soc/common/include/socfpga_mailbox.h b/plat/intel/soc/common/include/socfpga_mailbox.h index 90b1fa69e..1f4b2a4a0 100644 --- a/plat/intel/soc/common/include/socfpga_mailbox.h +++ b/plat/intel/soc/common/include/socfpga_mailbox.h @@ -113,6 +113,7 @@ #define MBOX_WORD_BYTE 4U #define MBOX_RESP_BUFFER_SIZE 16 #define MBOX_CMD_BUFFER_SIZE 32 +#define MBOX_INC_HEADER_MAX_WORD_SIZE 1024U /* Execution states for HPS_STAGE_NOTIFY */ #define HPS_EXECUTION_STATE_FSBL 0 @@ -213,6 +214,8 @@ int mailbox_send_cmd(uint32_t job_id, uint32_t cmd, uint32_t *args, unsigned int *resp_len); int mailbox_send_cmd_async(uint32_t *job_id, uint32_t cmd, uint32_t *args, unsigned int len, unsigned int indirect); +int mailbox_send_cmd_async_ext(uint32_t header_cmd, uint32_t *args, + unsigned int len); int mailbox_read_response(uint32_t *job_id, uint32_t *response, unsigned int *resp_len); int mailbox_read_response_async(uint32_t *job_id, uint32_t *header, diff --git a/plat/intel/soc/common/include/socfpga_sip_svc.h b/plat/intel/soc/common/include/socfpga_sip_svc.h index cc44db50d..b1be6a688 100644 --- a/plat/intel/soc/common/include/socfpga_sip_svc.h +++ b/plat/intel/soc/common/include/socfpga_sip_svc.h @@ -24,6 +24,14 @@ #define INTEL_SIP_SMC_CMD_V2_RANGE_BEGIN 0x400 #define INTEL_SIP_SMC_CMD_V2_RANGE_END 0x4FF +/* SiP V2 protocol header */ +#define INTEL_SIP_SMC_HEADER_JOB_ID_MASK 0xF +#define INTEL_SIP_SMC_HEADER_JOB_ID_OFFSET 0U +#define INTEL_SIP_SMC_HEADER_CID_MASK 0xF +#define INTEL_SIP_SMC_HEADER_CID_OFFSET 4U +#define INTEL_SIP_SMC_HEADER_VERSION_MASK 0xF +#define INTEL_SIP_SMC_HEADER_VERSION_OFFSET 60U + /* SMC SiP service function identifier for version 1 */ /* FPGA Reconfig */ @@ -143,6 +151,10 @@ #define INTEL_SIP_SMC_V2_REG_UPDATE 0xC2000403 #define INTEL_SIP_SMC_V2_HPS_SET_BRIDGES 0xC2000404 +/* V2: Mailbox function identifier */ +#define INTEL_SIP_SMC_V2_MAILBOX_SEND_COMMAND 0xC2000420 +#define INTEL_SIP_SMC_V2_MAILBOX_POLL_RESPONSE 0xC2000421 + /* SMC function IDs for SiP Service queries */ #define SIP_SVC_CALL_COUNT 0x8200ff00 #define SIP_SVC_UID 0x8200ff01 diff --git a/plat/intel/soc/common/soc/socfpga_mailbox.c b/plat/intel/soc/common/soc/socfpga_mailbox.c index 0f1214731..778d4af3c 100644 --- a/plat/intel/soc/common/soc/socfpga_mailbox.c +++ b/plat/intel/soc/common/soc/socfpga_mailbox.c @@ -236,7 +236,7 @@ int mailbox_read_response_async(unsigned int *job_id, uint32_t *header, /* copy response data to input buffer if applicable */ ret_resp_len = MBOX_RESP_LEN(mailbox_resp_ctr.payload->header); - if (ret_resp_len > 0 && response && resp_len) { + if ((ret_resp_len > 0) && (response == NULL) && resp_len) { if (*resp_len > ret_resp_len) { *resp_len = ret_resp_len; } @@ -385,6 +385,12 @@ int iterate_resp(uint32_t mbox_resp_len, uint32_t *resp_buf, return MBOX_RET_OK; } +int mailbox_send_cmd_async_ext(uint32_t header_cmd, uint32_t *args, + unsigned int len) +{ + return fill_mailbox_circular_buffer(header_cmd, args, len); +} + int mailbox_send_cmd_async(uint32_t *job_id, uint32_t cmd, uint32_t *args, unsigned int len, unsigned int indirect) { diff --git a/plat/intel/soc/common/socfpga_sip_svc_v2.c b/plat/intel/soc/common/socfpga_sip_svc_v2.c index d1d19920a..791c7148b 100644 --- a/plat/intel/soc/common/socfpga_sip_svc_v2.c +++ b/plat/intel/soc/common/socfpga_sip_svc_v2.c @@ -9,8 +9,119 @@ #include #include +#include "socfpga_mailbox.h" #include "socfpga_sip_svc.h" +static uint32_t intel_v2_mbox_send_cmd(uint32_t req_header, + uint32_t *data, uint32_t data_size) +{ + uint32_t value; + uint32_t len; + + if ((data == NULL) || (data_size == 0)) { + return INTEL_SIP_SMC_STATUS_REJECTED; + } + + if (data_size > (MBOX_INC_HEADER_MAX_WORD_SIZE * MBOX_WORD_BYTE)) { + return INTEL_SIP_SMC_STATUS_REJECTED; + } + + if (!is_size_4_bytes_aligned(data_size)) { + return INTEL_SIP_SMC_STATUS_REJECTED; + } + + /* Make sure client id align in SMC SiP V2 header and mailbox header */ + value = (req_header >> INTEL_SIP_SMC_HEADER_CID_OFFSET) & + INTEL_SIP_SMC_HEADER_CID_MASK; + + if (value != MBOX_RESP_CLIENT_ID(data[0])) { + return INTEL_SIP_SMC_STATUS_REJECTED; + } + + /* Make sure job id align in SMC SiP V2 header and mailbox header */ + value = (req_header >> INTEL_SIP_SMC_HEADER_JOB_ID_OFFSET) & + INTEL_SIP_SMC_HEADER_JOB_ID_MASK; + + if (value != MBOX_RESP_JOB_ID(data[0])) { + return INTEL_SIP_SMC_STATUS_REJECTED; + } + + /* + * Make sure data length align in SMC SiP V2 header and + * mailbox header + */ + len = (data_size / MBOX_WORD_BYTE) - 1; + + if (len != MBOX_RESP_LEN(data[0])) { + return INTEL_SIP_SMC_STATUS_REJECTED; + } + + return mailbox_send_cmd_async_ext(data[0], &data[1], len); +} + +static uint32_t intel_v2_mbox_poll_resp(uint64_t req_header, + uint32_t *data, uint32_t *data_size, + uint64_t *resp_header) +{ + int status = 0; + uint32_t resp_len; + uint32_t job_id = 0; + uint32_t client_id = 0; + uint32_t version; + + if ((data == NULL) || (data_size == NULL) || (resp_header == NULL)) { + return INTEL_SIP_SMC_STATUS_REJECTED; + } + + if (!is_size_4_bytes_aligned(*data_size)) { + return INTEL_SIP_SMC_STATUS_REJECTED; + } + + resp_len = (*data_size / MBOX_WORD_BYTE) - 1; + status = mailbox_read_response_async(&job_id, &data[0], &data[1], + &resp_len, 1); + + if (status == MBOX_BUSY) { + status = INTEL_SIP_SMC_STATUS_BUSY; + } else if (status == MBOX_NO_RESPONSE) { + status = INTEL_SIP_SMC_STATUS_NO_RESPONSE; + } else { + *data_size = 0; + + if (resp_len > 0) { + /* + * Fill in the final response length, + * the length include both mailbox header and payload + */ + *data_size = (resp_len + 1) * MBOX_WORD_BYTE; + + /* Extract the client id from mailbox header */ + client_id = MBOX_RESP_CLIENT_ID(data[0]); + } + + /* + * Extract SMC SiP V2 protocol version from + * SMC request header + */ + version = (req_header >> INTEL_SIP_SMC_HEADER_VERSION_OFFSET) & + INTEL_SIP_SMC_HEADER_VERSION_MASK; + + /* Fill in SMC SiP V2 protocol response header */ + *resp_header = 0; + *resp_header |= (((uint64_t)job_id) & + INTEL_SIP_SMC_HEADER_JOB_ID_MASK) << + INTEL_SIP_SMC_HEADER_JOB_ID_OFFSET; + *resp_header |= (((uint64_t)client_id) & + INTEL_SIP_SMC_HEADER_CID_MASK) << + INTEL_SIP_SMC_HEADER_CID_OFFSET; + *resp_header |= (((uint64_t)version) & + INTEL_SIP_SMC_HEADER_VERSION_MASK) << + INTEL_SIP_SMC_HEADER_VERSION_OFFSET; + } + + return status; +} + uintptr_t sip_smc_handler_v2(uint32_t smc_fid, u_register_t x1, u_register_t x2, @@ -21,6 +132,7 @@ uintptr_t sip_smc_handler_v2(uint32_t smc_fid, u_register_t flags) { uint32_t retval = 0; + uint64_t retval64 = 0; int status = INTEL_SIP_SMC_STATUS_OK; switch (smc_fid) { @@ -46,6 +158,15 @@ uintptr_t sip_smc_handler_v2(uint32_t smc_fid, status = intel_hps_set_bridges(x2, x3); SMC_RET2(handle, status, x1); + case INTEL_SIP_SMC_V2_MAILBOX_SEND_COMMAND: + status = intel_v2_mbox_send_cmd(x1, (uint32_t *)x2, x3); + SMC_RET2(handle, status, x1); + + case INTEL_SIP_SMC_V2_MAILBOX_POLL_RESPONSE: + status = intel_v2_mbox_poll_resp(x1, (uint32_t *)x2, + (uint32_t *) &x3, &retval64); + SMC_RET4(handle, status, retval64, x2, x3); + default: ERROR("%s: unhandled SMC V2 (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK);