blob: bf1b7fb914b59ad628bf340666defa9d9e1c6b54 [file] [log] [blame]
/*
* Copyright (c) 2020-2023, Intel Corporation. All rights reserved.
* Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/mmio.h>
#include <lib/spinlock.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <platform_def.h>
#include "socfpga_mailbox.h"
#include "socfpga_plat_def.h"
#include "socfpga_sip_svc.h"
#include "socfpga_system_manager.h"
#if SIP_SVC_V3
/* Function prototypes */
void mailbox_init_v3(void);
static int mailbox_response_handler_fsm(void);
static inline void mailbox_free_cmd_desc(sdm_command_t *cmd_desc);
static sdm_response_t *mailbox_get_resp_desc(uint8_t client_id, uint8_t job_id,
uint8_t *index);
static sdm_command_t *mailbox_get_cmd_desc(uint8_t client_id, uint8_t job_id);
static inline void mailbox_free_resp_desc(uint8_t index);
static sdm_command_t *mailbox_get_free_cmd_desc(void);
static sdm_response_t *mailbox_get_resp_desc_cid(uint8_t client_id,
uint8_t *index);
static int mailbox_read_response_v3(uint8_t client_id, uint8_t *job_id,
uint32_t *header, uint32_t *resp,
uint32_t *resp_len,
uint8_t ignore_client_id);
static int mailbox_poll_response_v3(uint8_t client_id, uint8_t job_id,
uint32_t *resp, unsigned int *resp_len,
uint32_t urgent);
static spinlock_t mbox_db_lock; /* Mailbox service data base lock */
static spinlock_t mbox_write_lock; /* Hardware mailbox FIFO write lock */
static spinlock_t mbox_read_lock; /* Hardware mailbox FIFO read lock */
static mailbox_service_t mbox_svc; /* Mailbox service data base */
static uint8_t async_v1_job_id;
#endif /* #if SIP_SVC_V3 */
static mailbox_payload_t mailbox_resp_payload;
static mailbox_container_t mailbox_resp_ctr = {0, 0, &mailbox_resp_payload};
static bool is_mailbox_cmdbuf_full(uint32_t cin)
{
uint32_t cout = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
return (((cin + 1U) % MBOX_CMD_BUFFER_SIZE) == cout);
}
static bool is_mailbox_cmdbuf_empty(uint32_t cin)
{
uint32_t cout = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
return (((cout + 1U) % MBOX_CMD_BUFFER_SIZE) == cin);
}
static int wait_for_mailbox_cmdbuf_empty(uint32_t cin)
{
unsigned int timeout = 20000U;
do {
if (is_mailbox_cmdbuf_empty(cin)) {
break;
}
udelay(50U);
} while (--timeout != 0U);
if (timeout == 0U) {
return MBOX_TIMEOUT;
}
return MBOX_RET_OK;
}
static int write_mailbox_cmd_buffer(uint32_t *cin, uint32_t cout,
uint32_t data,
bool *is_doorbell_triggered)
{
unsigned int timeout = 20000U;
VERBOSE("MBOX: 0x%x\n", data);
do {
if (is_mailbox_cmdbuf_full(*cin)) {
if (!(*is_doorbell_triggered)) {
mmio_write_32(MBOX_OFFSET +
MBOX_DOORBELL_TO_SDM, 1U);
*is_doorbell_triggered = true;
}
udelay(50U);
} else {
mmio_write_32(MBOX_ENTRY_TO_ADDR(CMD, (*cin)++), data);
*cin %= MBOX_CMD_BUFFER_SIZE;
mmio_write_32(MBOX_OFFSET + MBOX_CIN, *cin);
break;
}
} while (--timeout != 0U);
if (timeout == 0U) {
return MBOX_TIMEOUT;
}
if (*is_doorbell_triggered) {
int ret = wait_for_mailbox_cmdbuf_empty(*cin);
return ret;
}
return MBOX_RET_OK;
}
/*
* Function description: Write the command header, and its payload one by one
* into the mailbox command buffer. Along with this, check for mailbox buffer
* full condition and trigger doorbell to SDM if the command buffer is full.
*/
static int fill_mailbox_circular_buffer(uint32_t header_cmd, uint32_t *args,
unsigned int len)
{
uint32_t sdm_read_offset, cmd_free_offset;
unsigned int i;
int ret;
bool is_doorbell_triggered = false;
#if SIP_SVC_V3
spin_lock(&mbox_write_lock);
#endif
cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN);
sdm_read_offset = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
/* Write the command header here */
ret = write_mailbox_cmd_buffer(&cmd_free_offset, sdm_read_offset,
header_cmd, &is_doorbell_triggered);
if (ret != 0) {
goto restart_mailbox;
}
/* Write the payload here w.r.to args and its len - one by one. */
for (i = 0U; i < len; i++) {
is_doorbell_triggered = false;
ret = write_mailbox_cmd_buffer(&cmd_free_offset,
sdm_read_offset, args[i],
&is_doorbell_triggered);
if (ret != 0) {
goto restart_mailbox;
}
}
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1U);
#if SIP_SVC_V3
spin_unlock(&mbox_write_lock);
#endif
return MBOX_RET_OK;
restart_mailbox:
/*
* Attempt to restart mailbox if the driver not able to write
* into mailbox command buffer
*/
if (MBOX_CMD_MASK(header_cmd) != MBOX_CMD_RESTART) {
INFO("Mailbox timed out: Attempting mailbox reset\n");
ret = mailbox_init();
if (ret == MBOX_TIMEOUT) {
INFO("Error: Mailbox fail to restart\n");
}
}
#if SIP_SVC_V3
spin_unlock(&mbox_write_lock);
#endif
return MBOX_TIMEOUT;
}
int mailbox_read_response(unsigned int *job_id, uint32_t *response,
unsigned int *resp_len)
{
#if SIP_SVC_V3
return mailbox_read_response_v3(MBOX_ATF_CLIENT_ID,
(uint8_t *)job_id, NULL,
response, resp_len,
0);
#else
uint32_t rin;
uint32_t rout;
uint32_t resp_data;
unsigned int ret_resp_len;
if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) == 1U) {
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
}
rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
if (rout != rin) {
resp_data = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP, (rout)++));
rout %= MBOX_RESP_BUFFER_SIZE;
mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) {
return MBOX_WRONG_ID;
}
*job_id = MBOX_RESP_JOB_ID(resp_data);
ret_resp_len = MBOX_RESP_LEN(resp_data);
if (iterate_resp(ret_resp_len, response, resp_len)
!= MBOX_RET_OK) {
return MBOX_TIMEOUT;
}
if (MBOX_RESP_ERR(resp_data) > 0U) {
INFO("SDM response: Return Code: 0x%x\n", MBOX_RESP_ERR(resp_data));
return -MBOX_RESP_ERR(resp_data);
}
return MBOX_RET_OK;
}
return MBOX_NO_RESPONSE;
#endif
}
int mailbox_read_response_async(unsigned int *job_id, uint32_t *header,
uint32_t *response, unsigned int *resp_len,
uint8_t ignore_client_id)
{
#if SIP_SVC_V3
/* Just to avoid the build warning */
(void)mailbox_resp_ctr;
return mailbox_read_response_v3(MBOX_ATF_CLIENT_ID,
(uint8_t *)job_id, header,
response, resp_len,
ignore_client_id);
#else
uint32_t rin;
uint32_t rout;
uint32_t resp_data;
uint32_t ret_resp_len = 0;
uint8_t is_done = 0;
uint32_t resp_len_check = 0;
if ((mailbox_resp_ctr.flag & MBOX_PAYLOAD_FLAG_BUSY) != 0) {
ret_resp_len = MBOX_RESP_LEN(
mailbox_resp_ctr.payload->header) -
mailbox_resp_ctr.index;
}
if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) == 1U) {
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
}
rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
while (rout != rin && !is_done) {
resp_data = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP, (rout)++));
rout %= MBOX_RESP_BUFFER_SIZE;
mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
if ((mailbox_resp_ctr.flag & MBOX_PAYLOAD_FLAG_BUSY) != 0) {
mailbox_resp_ctr.payload->data[mailbox_resp_ctr.index] = resp_data;
mailbox_resp_ctr.index++;
ret_resp_len--;
} else {
if (!ignore_client_id) {
if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) {
*resp_len = 0;
return MBOX_WRONG_ID;
}
}
*job_id = MBOX_RESP_JOB_ID(resp_data);
ret_resp_len = MBOX_RESP_LEN(resp_data);
mailbox_resp_ctr.payload->header = resp_data;
mailbox_resp_ctr.flag |= MBOX_PAYLOAD_FLAG_BUSY;
}
if (ret_resp_len == 0) {
is_done = 1;
}
}
if (is_done != 0) {
/* copy header data to input address if applicable */
if (header != 0) {
*header = mailbox_resp_ctr.payload->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 != NULL) && (resp_len != NULL)) {
if (*resp_len > ret_resp_len) {
*resp_len = ret_resp_len;
}
resp_len_check = (uint32_t) *resp_len;
if (resp_len_check > MBOX_DATA_MAX_LEN) {
return MBOX_RET_ERROR;
}
memcpy_s((uint8_t *) response, *resp_len * MBOX_WORD_BYTE,
(uint8_t *) mailbox_resp_ctr.payload->data,
*resp_len * MBOX_WORD_BYTE);
}
/* reset async response param */
mailbox_resp_ctr.index = 0;
mailbox_resp_ctr.flag = 0;
if (MBOX_RESP_ERR(mailbox_resp_ctr.payload->header) > 0U) {
INFO("Error in async response: %x\n",
mailbox_resp_ctr.payload->header);
return -MBOX_RESP_ERR(mailbox_resp_ctr.payload->header);
}
return MBOX_RET_OK;
}
*resp_len = 0;
return (mailbox_resp_ctr.flag & MBOX_PAYLOAD_FLAG_BUSY) ? MBOX_BUSY : MBOX_NO_RESPONSE;
#endif
}
int mailbox_poll_response(uint32_t job_id, uint32_t urgent, uint32_t *response,
unsigned int *resp_len)
{
#if SIP_SVC_V3
return mailbox_poll_response_v3(MBOX_ATF_CLIENT_ID, (uint8_t)job_id,
response, resp_len, urgent);
#else
unsigned int timeout = 40U;
unsigned int sdm_loop = 255U;
unsigned int ret_resp_len;
uint32_t rin;
uint32_t rout;
uint32_t resp_data;
while (sdm_loop != 0U) {
do {
if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM)
== 1U) {
break;
}
mdelay(10U);
} while (--timeout != 0U);
if (timeout == 0U) {
break;
}
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
if ((urgent & 1U) != 0U) {
mdelay(5U);
if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
MBOX_STATUS_UA_MASK) ^
(urgent & MBOX_STATUS_UA_MASK)) {
mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
return MBOX_RET_OK;
}
mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
ERROR("MBOX: Mailbox did not get UA");
return MBOX_RET_ERROR;
}
rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
while (rout != rin) {
resp_data = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP,
(rout)++));
rout %= MBOX_RESP_BUFFER_SIZE;
mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
if ((MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) ||
(MBOX_RESP_JOB_ID(resp_data) != job_id)) {
continue;
}
/* Get the return response len from the response header. */
ret_resp_len = MBOX_RESP_LEN(resp_data);
/* Print the response header. */
VERBOSE("MBOX: RespHdr: cid %d, jid %d, len %d, err_code 0x%x\n",
MBOX_RESP_CLIENT_ID(resp_data),
MBOX_RESP_JOB_ID(resp_data),
MBOX_RESP_LEN(resp_data),
MBOX_RESP_ERR(resp_data));
if (iterate_resp(ret_resp_len, response, resp_len)
!= MBOX_RET_OK) {
return MBOX_TIMEOUT;
}
if (MBOX_RESP_ERR(resp_data) > 0U) {
INFO("SDM response: Return Code: 0x%x\n", MBOX_RESP_ERR(resp_data));
return -MBOX_RESP_ERR(resp_data);
}
return MBOX_RET_OK;
}
sdm_loop--;
}
INFO("Timed out waiting for SDM\n");
return MBOX_TIMEOUT;
#endif
}
int iterate_resp(uint32_t mbox_resp_len, uint32_t *resp_buf,
unsigned int *resp_len)
{
unsigned int timeout, total_resp_len = 0U;
uint32_t resp_data;
uint32_t rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
uint32_t rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
while (mbox_resp_len > 0U) {
timeout = 100U;
mbox_resp_len--;
resp_data = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP, (rout)++));
if ((resp_buf != NULL) && (resp_len != NULL)
&& (*resp_len != 0U)) {
*(resp_buf + total_resp_len) = resp_data;
*resp_len = *resp_len - 1;
total_resp_len++;
}
rout %= MBOX_RESP_BUFFER_SIZE;
mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
do {
rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
if (rout == rin) {
mdelay(10U);
} else {
break;
}
timeout--;
} while ((mbox_resp_len > 0U) && (timeout != 0U));
if (timeout == 0U) {
INFO("Timed out waiting for SDM\n");
return MBOX_TIMEOUT;
}
}
if (resp_len)
*resp_len = total_resp_len;
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)
{
int status;
status = fill_mailbox_circular_buffer(
MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
MBOX_JOB_ID_CMD(*job_id) |
MBOX_CMD_LEN_CMD(len) |
MBOX_INDIRECT(indirect) |
cmd, args, len);
if (status < 0) {
return status;
}
#if SIP_SVC_V3
async_v1_job_id = (uint8_t)*job_id;
#endif
*job_id = (*job_id + 1U) % MBOX_MAX_IND_JOB_ID;
return MBOX_RET_OK;
}
int mailbox_send_cmd(uint32_t job_id, uint32_t cmd, uint32_t *args,
unsigned int len, uint32_t urgent, uint32_t *response,
unsigned int *resp_len)
{
int status = 0;
if (urgent != 0U) {
urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
MBOX_STATUS_UA_MASK;
mmio_write_32(MBOX_OFFSET + MBOX_URG, cmd);
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1U);
} else {
status = fill_mailbox_circular_buffer(
MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
MBOX_JOB_ID_CMD(job_id) |
MBOX_CMD_LEN_CMD(len) |
cmd, args, len);
}
if (status != 0) {
return status;
}
status = mailbox_poll_response(job_id, urgent, response, resp_len);
return status;
}
void mailbox_clear_response(void)
{
mmio_write_32(MBOX_OFFSET + MBOX_ROUT,
mmio_read_32(MBOX_OFFSET + MBOX_RIN));
}
void mailbox_set_int(uint32_t interrupt)
{
mmio_write_32(MBOX_OFFSET+MBOX_INT,
MBOX_COE_BIT(interrupt) |
MBOX_RIE_BIT(interrupt) |
MBOX_UAE_BIT(interrupt));
}
void mailbox_set_qspi_open(void)
{
mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_OPEN, NULL, 0U,
CMD_CASUAL, NULL, NULL);
}
void mailbox_set_qspi_direct(void)
{
uint32_t response[1], qspi_clk, reg;
unsigned int resp_len = ARRAY_SIZE(response);
mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, NULL, 0U,
CMD_CASUAL, response, &resp_len);
qspi_clk = response[0];
INFO("QSPI ref clock: %u\n", qspi_clk);
/*
* Store QSPI ref clock frequency in BOOT_SCRATCH_COLD_0 register for
* later boot loader (i.e. u-boot) use.
* The frequency is stored in kHz and occupies BOOT_SCRATCH_COLD_0
* register bits[27:0].
*/
qspi_clk /= 1000;
reg = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_0));
reg &= ~SYSMGR_QSPI_REFCLK_MASK;
reg |= qspi_clk & SYSMGR_QSPI_REFCLK_MASK;
mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_0), reg);
}
void mailbox_set_qspi_close(void)
{
mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_CLOSE, NULL, 0U,
CMD_CASUAL, NULL, NULL);
}
void mailbox_qspi_set_cs(uint32_t device_select)
{
uint32_t cs_setting;
/* QSPI device select settings at 31:28 */
cs_setting = (device_select << 28);
mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_SET_CS, &cs_setting,
1U, CMD_CASUAL, NULL, NULL);
}
void mailbox_hps_qspi_enable(void)
{
mailbox_set_qspi_open();
mailbox_set_qspi_direct();
}
void mailbox_reset_cold(void)
{
mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, 0U, 0U,
CMD_CASUAL, NULL, NULL);
}
void mailbox_reset_warm(uint32_t reset_type)
{
mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
reset_type = 0x01; // Warm reset header data must be 1
mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, &reset_type, 1U,
CMD_CASUAL, NULL, NULL);
}
int mailbox_rsu_get_spt_offset(uint32_t *resp_buf, unsigned int resp_buf_len)
{
return mailbox_send_cmd(MBOX_JOB_ID, MBOX_GET_SUBPARTITION_TABLE,
NULL, 0U, CMD_CASUAL, resp_buf,
&resp_buf_len);
}
struct rsu_status_info {
uint64_t current_image;
uint64_t fail_image;
uint32_t state;
uint32_t version;
uint32_t error_location;
uint32_t error_details;
uint32_t retry_counter;
};
int mailbox_rsu_status(uint32_t *resp_buf, unsigned int resp_buf_len)
{
int ret;
struct rsu_status_info *info = (struct rsu_status_info *)resp_buf;
info->retry_counter = ~0U;
ret = mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_STATUS, NULL, 0U,
CMD_CASUAL, resp_buf,
&resp_buf_len);
if (ret < 0) {
return ret;
}
if (info->retry_counter != ~0U) {
if ((info->version & RSU_VERSION_ACMF_MASK) == 0U) {
info->version |= RSU_VERSION_ACMF;
}
}
return ret;
}
int mailbox_rsu_get_device_info(uint32_t *resp_buf, unsigned int resp_buf_len)
{
return mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_GET_DEVICE_INFO, NULL, 0U,
CMD_CASUAL, resp_buf,
&resp_buf_len);
}
int mailbox_rsu_update(uint32_t *flash_offset)
{
return mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_UPDATE,
flash_offset, 2U,
CMD_CASUAL, NULL, NULL);
}
int mailbox_hps_stage_notify(uint32_t execution_stage)
{
return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HPS_STAGE_NOTIFY,
&execution_stage, 1U, CMD_CASUAL,
NULL, NULL);
}
int mailbox_init(void)
{
int status;
mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
MBOX_INT_FLAG_UAE);
mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
status = mailbox_send_cmd(0U, MBOX_CMD_RESTART, NULL, 0U,
CMD_URGENT, NULL, NULL);
if (status != 0) {
return status;
}
#if SIP_SVC_V3
/* Initialize the mailbox version3 implementation, and in V3 we
* are interested in only RIE interrupt
*/
mailbox_init_v3();
mailbox_set_int(MBOX_INT_FLAG_RIE);
#else
mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
MBOX_INT_FLAG_UAE);
#endif
return MBOX_RET_OK;
}
int mailbox_send_fpga_config_comp(void)
{
int ret;
ret = mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_FPGA_CONFIG_COMP, NULL, 0U,
CMD_CASUAL, NULL, NULL);
if (ret != 0) {
INFO("SOCFPGA: FPGA configuration complete response, Return Code: 0x%x\n",
MBOX_RESP_ERR(-ret));
return MBOX_RET_ERROR;
}
return MBOX_RET_OK;
}
int intel_mailbox_get_config_status(uint32_t cmd, bool init_done,
uint32_t *err_states)
{
int status;
uint32_t res, response[6];
unsigned int resp_len = ARRAY_SIZE(response);
status = mailbox_send_cmd(MBOX_JOB_ID, cmd, NULL, 0U, CMD_CASUAL,
response, &resp_len);
if (status < 0) {
return status;
}
res = response[RECONFIG_STATUS_STATE];
if (err_states != NULL)
*err_states = res;
if (res == MBOX_CFGSTAT_VAB_BS_PREAUTH) {
return MBOX_CFGSTAT_STATE_CONFIG;
}
if ((res != 0U) && (res != MBOX_CFGSTAT_STATE_CONFIG)) {
return res;
}
res = response[RECONFIG_STATUS_PIN_STATUS];
if ((res & PIN_STATUS_NSTATUS) == 0U) {
return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
}
res = response[RECONFIG_STATUS_SOFTFUNC_STATUS];
if ((res & SOFTFUNC_STATUS_SEU_ERROR) != 0U) {
return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
}
if ((res & SOFTFUNC_STATUS_CONF_DONE) == 0U) {
return MBOX_CFGSTAT_STATE_CONFIG;
}
if (init_done && (res & SOFTFUNC_STATUS_INIT_DONE) == 0U) {
return MBOX_CFGSTAT_STATE_CONFIG;
}
return MBOX_RET_OK;
}
int intel_mailbox_is_fpga_not_ready(void)
{
int ret = intel_mailbox_get_config_status(MBOX_RECONFIG_STATUS, true, NULL);
if ((ret != MBOX_RET_OK) && (ret != MBOX_CFGSTAT_STATE_CONFIG)) {
ret = intel_mailbox_get_config_status(MBOX_CONFIG_STATUS,
false, NULL);
}
return ret;
}
int mailbox_hwmon_readtemp(uint32_t chan, uint32_t *resp_buf)
{
unsigned int resp_len = sizeof(resp_buf);
return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HWMON_READTEMP, &chan, 1U,
CMD_CASUAL, resp_buf,
&resp_len);
}
int mailbox_hwmon_readvolt(uint32_t chan, uint32_t *resp_buf)
{
unsigned int resp_len = sizeof(resp_buf);
return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HWMON_READVOLT, &chan, 1U,
CMD_CASUAL, resp_buf,
&resp_len);
}
int mailbox_seu_err_status(uint32_t *resp_buf, unsigned int resp_buf_len)
{
return mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_SEU_ERR_READ, NULL, 0U,
CMD_CASUAL, resp_buf,
&resp_buf_len);
}
int mailbox_safe_inject_seu_err(uint32_t *arg, unsigned int len)
{
return mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_SAFE_INJECT_SEU_ERR, arg, len,
CMD_CASUAL, NULL, NULL);
}
#if SIP_SVC_V3
static int mailbox_fill_cmd_desc(uint8_t client_id, uint8_t job_id,
uint32_t *resp_buff)
{
sdm_command_t *cmd_desc = NULL;
/* Get a free command descriptor */
cmd_desc = mailbox_get_free_cmd_desc();
if (cmd_desc == NULL) {
return MBOX_BUFFER_FULL;
}
/* Record all the given values for the command. */
cmd_desc->client_id = client_id;
cmd_desc->job_id = job_id;
cmd_desc->cb = NULL;
cmd_desc->cb_args = resp_buff;
cmd_desc->cb_args_len = 0U;
return MBOX_RET_OK;
}
/* Returns the command descriptor based on the client and job ID. */
static sdm_command_t *mailbox_get_cmd_desc(uint8_t client_id, uint8_t job_id)
{
spin_lock(&mbox_db_lock);
for (uint32_t count = 0; count < MBOX_SVC_CMD_QUEUE_SIZE; count++) {
if ((mbox_svc.cmd_queue[count].client_id == client_id) &&
(mbox_svc.cmd_queue[count].job_id == job_id) &&
(mbox_svc.cmd_queue[count].flags & MBOX_SVC_CMD_IS_USED)) {
spin_unlock(&mbox_db_lock);
return &(mbox_svc.cmd_queue[count]);
}
}
spin_unlock(&mbox_db_lock);
VERBOSE("MBOX: Command descriptor not found for cid %d, jid %d\n",
client_id, job_id);
return NULL;
}
/* Returns the response descriptor based on only client ID. */
static sdm_response_t *mailbox_get_resp_desc_cid(uint8_t client_id, uint8_t *index)
{
spin_lock(&mbox_db_lock);
for (uint32_t count = 0; count < MBOX_SVC_RESP_QUEUE_SIZE; count++) {
if ((mbox_svc.resp_queue[count].client_id == client_id) &&
(mbox_svc.resp_queue[count].flags & FLAG_SDM_RESPONSE_IS_VALID)) {
*index = count;
/*
* Once we get the valid response descriptor, get the
* job ID and mark up the bitmaps.
*/
uint8_t job_id = mbox_svc.resp_queue[count].job_id;
uint8_t transaction_id = MBOX_GET_TRANS_ID(client_id, job_id);
mbox_svc.received_bitmap[transaction_id / MBOX_TID_BITMAP_SIZE] &=
~(1ULL << (transaction_id % MBOX_TID_BITMAP_SIZE));
mbox_svc.interrupt_bitmap[transaction_id / MBOX_TID_BITMAP_SIZE] &=
~(1ULL << (transaction_id % MBOX_TID_BITMAP_SIZE));
spin_unlock(&mbox_db_lock);
return &(mbox_svc.resp_queue[count]);
}
}
spin_unlock(&mbox_db_lock);
VERBOSE("MBOX: Response descriptor not found for cid %d\n", client_id);
return NULL;
}
/* Returns the response descriptor based on the client and job ID. */
static sdm_response_t *mailbox_get_resp_desc(uint8_t client_id, uint8_t job_id, uint8_t *index)
{
spin_lock(&mbox_db_lock);
/*
* Let's first check whether we have a response bitmap set for the given
* client ID and job ID.
*/
uint8_t transaction_id = MBOX_GET_TRANS_ID(client_id, job_id);
if ((mbox_svc.received_bitmap[transaction_id / MBOX_TID_BITMAP_SIZE] &
(1ULL << (transaction_id % MBOX_TID_BITMAP_SIZE))) == 0) {
spin_unlock(&mbox_db_lock);
VERBOSE("MBOX: Response bitmap not set for cid %d, jid %d, bitmap 0x%16lx\n",
client_id, job_id, mbox_svc.received_bitmap[transaction_id / 64]);
return NULL;
}
for (uint32_t count = 0; count < MBOX_SVC_RESP_QUEUE_SIZE; count++) {
if (mbox_svc.resp_queue[count].flags & FLAG_SDM_RESPONSE_IS_VALID) {
if ((mbox_svc.resp_queue[count].client_id == client_id) &&
(mbox_svc.resp_queue[count].job_id == job_id)) {
*index = count;
mbox_svc.received_bitmap[transaction_id / MBOX_TID_BITMAP_SIZE] &=
~(1ULL << (transaction_id % MBOX_TID_BITMAP_SIZE));
mbox_svc.interrupt_bitmap[transaction_id / MBOX_TID_BITMAP_SIZE] &=
~(1ULL << (transaction_id % MBOX_TID_BITMAP_SIZE));
spin_unlock(&mbox_db_lock);
return &(mbox_svc.resp_queue[count]);
}
}
}
spin_unlock(&mbox_db_lock);
VERBOSE("MBOX: Response descriptor not found for cid %d, jid %d\n",
client_id, job_id);
return NULL;
}
static int32_t mailbox_get_free_resp_desc(void)
{
spin_lock(&mbox_db_lock);
static uint32_t free_index = MBOX_SVC_RESP_QUEUE_SIZE - 1;
uint32_t count = 0U, try = 0U;
for (try = 0; try < MBOX_SVC_RESP_QUEUE_SIZE; try++) {
free_index = (free_index + 1) % MBOX_SVC_RESP_QUEUE_SIZE;
if ((mbox_svc.resp_queue[free_index].flags &
FLAG_SDM_RESPONSE_IS_USED) != 0U) {
count = free_index;
spin_unlock(&mbox_db_lock);
return count;
}
}
/* No free descriptors are available */
spin_unlock(&mbox_db_lock);
VERBOSE("MBOX: No free response descriptors are available\n");
return MBOX_BUFFER_FULL;
}
static sdm_command_t *mailbox_get_free_cmd_desc(void)
{
spin_lock(&mbox_db_lock);
static uint32_t free_index;
/* Rollover the command queue free index */
if (free_index == (MBOX_SVC_CMD_QUEUE_SIZE - 1)) {
free_index = 0U;
}
for (; free_index < MBOX_SVC_CMD_QUEUE_SIZE; free_index++) {
if ((mbox_svc.cmd_queue[free_index].flags &
MBOX_SVC_CMD_IS_USED) != 0U) {
mbox_svc.cmd_queue[free_index].flags |= MBOX_SVC_CMD_IS_USED;
spin_unlock(&mbox_db_lock);
return &(mbox_svc.cmd_queue[free_index]);
}
}
/* No free command descriptors are available */
spin_unlock(&mbox_db_lock);
VERBOSE("MBOX: No free command descriptors available\n");
return NULL;
}
static inline void mailbox_free_cmd_desc(sdm_command_t *cmd_desc)
{
if (cmd_desc == NULL) {
return;
}
spin_lock(&mbox_db_lock);
memset((void *)cmd_desc, 0, sizeof(sdm_command_t));
spin_unlock(&mbox_db_lock);
}
static inline void mailbox_free_resp_desc(uint8_t index)
{
if (index >= MBOX_SVC_RESP_QUEUE_SIZE) {
return;
}
spin_lock(&mbox_db_lock);
memset((void *)&mbox_svc.resp_queue[index], 0, sizeof(sdm_response_t));
spin_unlock(&mbox_db_lock);
}
/*
* This function serves the V1 _sync_read and _async_read functionality, and it
* is introduced as part of V3 framework to keep backward compatible with V1
* clients.
*/
static int mailbox_read_response_v3(uint8_t client_id, uint8_t *job_id,
uint32_t *header, uint32_t *resp,
uint32_t *resp_len,
uint8_t ignore_client_id)
{
uint8_t di = 0U;
int status = MBOX_RET_OK;
sdm_response_t *resp_desc = NULL;
sdm_command_t *cmd_desc = NULL;
/*
* In the V1, the client ID is always MBOX_ATF_CLIENT_ID and in this
* routine we will collect the response which only belongs to this
* client ID. So safe to ignore this input.
*/
(void)ignore_client_id;
/* Clear the SDM doorbell interrupt */
if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) == 1U)
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
/* Fill the command descriptor index and get the same */
status = mailbox_fill_cmd_desc(client_id, async_v1_job_id, resp);
if (status != MBOX_RET_OK) {
return status;
}
cmd_desc = mailbox_get_cmd_desc(client_id, async_v1_job_id);
/* Get the response from SDM, just go through one cycle */
status = mailbox_response_handler_fsm();
if (status != MBOX_RET_OK) {
mailbox_free_cmd_desc(cmd_desc);
*resp_len = 0U;
return status;
}
/* Check the local response queue with the given client ID */
resp_desc = mailbox_get_resp_desc_cid(client_id, &di);
if (resp_desc == NULL) {
mailbox_free_cmd_desc(cmd_desc);
*resp_len = 0U;
return MBOX_NO_RESPONSE;
}
/* Update the received mailbox response length, job ID and header */
*job_id = resp_desc->job_id;
*resp_len = resp_desc->rcvd_resp_len;
if (header != NULL) {
*header = resp_desc->header;
}
/* Check the mailbox response error code */
if (MBOX_RESP_ERR(resp_desc->header) > 0U) {
INFO("MBOX: Error in async response: %x\n", resp_desc->header);
status = -MBOX_RESP_ERR(resp_desc->header);
}
/* Free up the response and command descriptors */
mailbox_free_resp_desc(di);
mailbox_free_cmd_desc(cmd_desc);
return status;
}
int mailbox_send_cmd_async_v3(uint8_t client_id, uint8_t job_id, uint32_t cmd,
uint32_t *args, uint32_t args_len, uint8_t cmd_flag,
sdm_command_callback cb, uint32_t *cb_args,
uint32_t cb_args_len)
{
int status = 0;
sdm_command_t *cmd_desc = NULL;
VERBOSE("MBOX: cid: %d, jid: %d, cmd: %d, cmd_flag: %d\n",
client_id, job_id, cmd, cmd_flag);
if (IS_CMD_SET(cmd_flag, URGENT)) {
mmio_write_32(MBOX_OFFSET + MBOX_URG, cmd);
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1U);
} else {
/* Get a free command descriptor */
cmd_desc = mailbox_get_free_cmd_desc();
if (cmd_desc == NULL) {
return MBOX_BUFFER_FULL;
}
/* Record all the given values for the command. */
cmd_desc->client_id = client_id;
cmd_desc->job_id = job_id;
cmd_desc->cb = cb;
cmd_desc->cb_args = cb_args;
cmd_desc->cb_args_len = cb_args_len;
/* Push the command to mailbox FIFO */
status = fill_mailbox_circular_buffer(
MBOX_FRAME_CMD_HEADER(client_id, job_id,
args_len, IS_CMD_SET(cmd_flag, INDIRECT), cmd),
args,
args_len);
if (status != MBOX_RET_OK) {
INFO("MBOX: Failed to push the command to mailbox FIFO\n");
/* Free the command descriptor. */
mailbox_free_cmd_desc(cmd_desc);
}
}
INFO("MBOX: %s: status: %d\n", __func__, status);
return status;
}
static int mailbox_poll_response_v3(uint8_t client_id, uint8_t job_id,
uint32_t *resp, unsigned int *resp_len,
uint32_t urgent)
{
unsigned int timeout = 40U;
unsigned int sdm_loop = 255U;
bool is_cmd_desc_fill = false;
uint8_t di = 0U;
sdm_response_t *resp_desc = NULL;
sdm_command_t *cmd_desc = NULL;
while (sdm_loop != 0U) {
do {
if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM)
== 1U) {
break;
}
mdelay(10U);
} while (--timeout != 0U);
if (timeout == 0U) {
INFO("%s: Timed out waiting for SDM intr\n", __func__);
break;
}
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
if ((urgent & 1U) != 0U) {
mdelay(5U);
if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
MBOX_STATUS_UA_MASK) ^
(urgent & MBOX_STATUS_UA_MASK)) {
mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
return MBOX_RET_OK;
}
mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
ERROR("MBOX: Mailbox did not get UA");
return MBOX_RET_ERROR;
}
/* Fill the command descriptor index and get the same. */
if (!is_cmd_desc_fill) {
if (mailbox_fill_cmd_desc(client_id, job_id, resp) !=
MBOX_RET_OK) {
return MBOX_BUFFER_FULL;
}
cmd_desc = mailbox_get_cmd_desc(client_id, job_id);
is_cmd_desc_fill = true;
}
/* Since it is sync call, will try to read till it time out */
(void)mailbox_response_handler_fsm();
/* Check the response queue with the given client ID and job ID */
resp_desc = mailbox_get_resp_desc(client_id, job_id, &di);
if (resp_desc != NULL) {
VERBOSE("%s: Resp received for cid %d, jid %d\n",
__func__, resp_desc->client_id, resp_desc->job_id);
uint16_t header = resp_desc->header;
/* Update the return response length */
if (resp_len != NULL) {
*resp_len = resp_desc->rcvd_resp_len;
}
/* Free the response and command descriptor */
mailbox_free_resp_desc(di);
mailbox_free_cmd_desc(cmd_desc);
if (MBOX_RESP_ERR(header) > 0U) {
INFO("%s: SDM err code: 0x%x\n", __func__,
MBOX_RESP_ERR(header));
return -MBOX_RESP_ERR(header);
}
VERBOSE("%s: MBOX_RET_OK\n", __func__);
return MBOX_RET_OK;
}
sdm_loop--;
}
INFO("%s: Timed out waiting for SDM\n", __func__);
return MBOX_TIMEOUT;
}
/* SDM response parser handler state machine. */
static void mailbox_response_parser(void)
{
int di = -1; /* Descriptor index */
uint32_t rin;
uint32_t rout;
switch (mbox_svc.next_resp_state) {
case SRS_WAIT_FOR_RESP:
{
mbox_svc.resp_state = SRS_WAIT_FOR_RESP;
rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
if (rin != rout) {
mbox_svc.next_resp_state = SRS_WAIT_FOR_HEADER;
}
break;
}
case SRS_WAIT_FOR_HEADER:
{
mbox_svc.resp_state = SRS_WAIT_FOR_HEADER;
uint32_t resp_hdr;
uint8_t trans_id = 0U;
rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
if (rin != rout) {
/* Read the header and dequeue from the queue. */
resp_hdr = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP, (rout)++));
rout %= MBOX_RESP_BUFFER_SIZE;
mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
/* Allocate a new response descriptor */
di = mailbox_get_free_resp_desc();
if (di != -1) {
mbox_svc.curr_di = di;
mbox_svc.resp_queue[di].header = resp_hdr;
mbox_svc.resp_queue[di].client_id = MBOX_RESP_CLIENT_ID(resp_hdr);
mbox_svc.resp_queue[di].job_id = MBOX_RESP_JOB_ID(resp_hdr);
mbox_svc.resp_queue[di].resp_len = MBOX_RESP_LEN(resp_hdr);
mbox_svc.resp_queue[di].flags |= (FLAG_SDM_RESPONSE_IS_USED |
FLAG_SDM_RESPONSE_IS_IN_PROGRESS);
mbox_svc.resp_queue[di].err_code = MBOX_RESP_ERR(resp_hdr);
trans_id = MBOX_RESP_TRANSACTION_ID(resp_hdr);
VERBOSE("MBOX: Resp Hdr: cid %d, jid %d, len %d, err_code 0x%x\n",
mbox_svc.resp_queue[di].client_id,
mbox_svc.resp_queue[di].job_id,
mbox_svc.resp_queue[di].resp_len,
mbox_svc.resp_queue[di].err_code);
/* Check if the response is an argument response */
if (mbox_svc.resp_queue[di].resp_len > 0) {
mbox_svc.next_resp_state = SRS_WAIT_FOR_ARGUMENTS;
} else {
VERBOSE("MBOX: Received complete response with no args\n");
/* Non argument response, done */
mbox_svc.resp_queue[mbox_svc.curr_di].flags |=
FLAG_SDM_RESPONSE_IS_VALID;
/* Go back to waiting for new response */
mbox_svc.next_resp_state = SRS_WAIT_FOR_RESP;
mbox_svc.curr_di = -1;
/* Mark the transaction ID as received */
spin_lock(&mbox_db_lock);
mbox_svc.received_bitmap[trans_id / MBOX_TID_BITMAP_SIZE] |=
(1ULL << (trans_id % MBOX_TID_BITMAP_SIZE));
spin_unlock(&mbox_db_lock);
}
} else {
mbox_svc.next_resp_state = SRS_SYNC_ERROR;
}
}
break;
}
case SRS_WAIT_FOR_ARGUMENTS:
{
mbox_svc.resp_state = SRS_WAIT_FOR_ARGUMENTS;
uint16_t mbox_resp_len = mbox_svc.resp_queue[mbox_svc.curr_di].resp_len;
uint32_t *read_buff = NULL;
uint16_t read_len = 0U;
uint16_t read_max_len = 0U;
uint32_t timeout = 0U;
/* Determine where to copy the buffer. */
sdm_command_t *cmd_desc = mailbox_get_cmd_desc(
mbox_svc.resp_queue[mbox_svc.curr_di].client_id,
mbox_svc.resp_queue[mbox_svc.curr_di].job_id);
if (cmd_desc != NULL && cmd_desc->cb_args != NULL) {
read_buff = cmd_desc->cb_args;
read_max_len = mbox_resp_len;
} else {
read_buff = (uint32_t *)mbox_svc.resp_queue[mbox_svc.curr_di].resp_data;
read_max_len = MBOX_SVC_MAX_RESP_DATA_SIZE;
}
rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
while ((read_len < mbox_resp_len) && (rin != rout) && (read_len < read_max_len)) {
timeout = 10000U;
/* Copy the response data to the buffer */
read_buff[read_len++] = mmio_read_32(MBOX_ENTRY_TO_ADDR(RESP, (rout)++));
VERBOSE("MBOX: 0x%x\n", read_buff[read_len - 1]);
/* Update the read out buffer index */
rout %= MBOX_RESP_BUFFER_SIZE;
mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
/*
* The response buffer is of 16 words size, this loop checks
* if the response buffer is empty and if empty trigger an
* interrupt to SDM and wait for the response buffer to fill
*/
do {
if (read_len == mbox_resp_len)
break;
rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
if (rout == rin) {
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1U);
udelay(100);
} else {
break;
}
timeout--;
} while ((read_len < mbox_resp_len) && (timeout != 0U));
if (timeout == 0U) {
INFO("MBOX: Timeout waiting for response data\n");
mbox_svc.next_resp_state = SRS_SYNC_ERROR;
break;
}
}
/* Check if we have received all the arguments */
mbox_svc.resp_queue[mbox_svc.curr_di].rcvd_resp_len = read_len;
if (mbox_resp_len == read_len) {
uint8_t transaction_id =
((mbox_svc.resp_queue[mbox_svc.curr_di].client_id << 4) |
(mbox_svc.resp_queue[mbox_svc.curr_di].job_id));
VERBOSE("MBOX: Received all the response data len %d, transaction_id %d\n",
read_len, transaction_id);
spin_lock(&mbox_db_lock);
mbox_svc.received_bitmap[transaction_id / MBOX_TID_BITMAP_SIZE] |=
(1ULL << (transaction_id % MBOX_TID_BITMAP_SIZE));
spin_unlock(&mbox_db_lock);
mbox_svc.resp_queue[mbox_svc.curr_di].flags |= FLAG_SDM_RESPONSE_IS_VALID;
mbox_svc.next_resp_state = SRS_WAIT_FOR_RESP;
mbox_svc.curr_di = -1;
} else {
mbox_svc.next_resp_state = SRS_SYNC_ERROR;
VERBOSE("MBOX: Received partial response data len %d, max len %d\n",
read_len, read_max_len);
}
break;
}
case SRS_SYNC_ERROR:
{
mbox_svc.resp_state = SRS_SYNC_ERROR;
INFO("MBOX: Error in response handling\n");
break;
}
default:
break;
} /* switch */
}
static int mailbox_response_handler_fsm(void)
{
int status = MBOX_RET_OK;
spin_lock(&mbox_read_lock);
/* Mailbox peripheral response parser */
do {
/* Iterate till the state machine transition ends */
mailbox_response_parser();
/* Note down if there is any error in the response parsing */
if (mbox_svc.next_resp_state == SRS_SYNC_ERROR) {
status = MBOX_RET_ERROR;
}
} while (mbox_svc.resp_state != mbox_svc.next_resp_state);
spin_unlock(&mbox_read_lock);
return status;
}
int mailbox_response_poll_on_intr_v3(uint8_t *client_id, uint8_t *job_id,
uint64_t *bitmap)
{
uint32_t i = 0U;
int status = MBOX_RET_OK;
/* Clear the SDM doorbell interrupt immediately */
if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) == 1U) {
mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
}
/* Check mailbox FIFO for any pending responses available to read. */
status = mailbox_response_handler_fsm();
if (status != MBOX_RET_OK) {
return status;
}
/*
* Once we read the complete mailbox FIFO, let's mark up the bitmap for
* available responses with respect to each transcation IDs.
*/
status = MBOX_NO_RESPONSE;
spin_lock(&mbox_db_lock);
for (i = 0; i < MBOX_MAX_TIDS_BITMAP; i++) {
bitmap[i] = mbox_svc.interrupt_bitmap[i] ^ mbox_svc.received_bitmap[i];
if (bitmap[i] != 0 && status == MBOX_NO_RESPONSE) {
status = MBOX_RET_OK;
}
mbox_svc.interrupt_bitmap[i] = mbox_svc.received_bitmap[i];
}
spin_unlock(&mbox_db_lock);
return status;
}
int mailbox_response_poll_v3(uint8_t client_id, uint8_t job_id,
uint64_t *ret_args, uint32_t *ret_args_len)
{
sdm_command_t *cmd_desc = NULL;
sdm_response_t *resp_desc = NULL;
uint8_t di = 0U;
int status = MBOX_RET_OK;
/*
* Let's first check the local response queue with the given
* client ID and job ID
*/
resp_desc = mailbox_get_resp_desc(client_id, job_id, &di);
if (resp_desc == NULL) {
/* Not available in the local queue, let's read mailbox FIFO */
status = mailbox_response_handler_fsm();
if (status != MBOX_RET_OK) {
return status;
}
resp_desc = mailbox_get_resp_desc(client_id, job_id, &di);
}
cmd_desc = mailbox_get_cmd_desc(client_id, job_id);
if (cmd_desc != NULL && resp_desc != NULL) {
VERBOSE("MBOX: Resp found for cid %d, jid %d\n", client_id, job_id);
/* Command callback function */
*ret_args_len = cmd_desc->cb(resp_desc, cmd_desc, ret_args);
/* Free the command and response descriptors. */
mailbox_free_cmd_desc(cmd_desc);
mailbox_free_resp_desc(di);
return MBOX_RET_OK;
}
INFO("MBOX: No resp found for cid: %d, jid: %d\n", client_id, job_id);
return MBOX_NO_RESPONSE;
}
void mailbox_init_v3(void)
{
uint32_t count;
memset((void *)&mbox_svc, 0, sizeof(mbox_svc));
mbox_svc.next_resp_state = SRS_WAIT_FOR_RESP;
mbox_svc.resp_state = SRS_WAIT_FOR_RESP;
/* Free all entries from the response queue. */
for (count = 0; count < MBOX_SVC_RESP_QUEUE_SIZE; count++) {
mbox_svc.resp_queue[count].flags = 0;
}
/* Free all entries from the command queue. */
for (count = 0; count < MBOX_SVC_CMD_QUEUE_SIZE; count++) {
mbox_svc.cmd_queue[count].flags = 0;
}
mbox_svc.curr_di = -1;
}
#endif /* #if SIP_SVC_V3 */