arm-trusted-firmware/plat/intel/soc/common/soc/socfpga_mailbox.c
Jit Loon Lim 8e59b9f423 feat(intel): mailbox and SMC support for Agilex5 SoC FPGA
This patch is used to enable mailbox and SMC support
for Agilex5 SoC FPGA.
	1. Enabled mailbox and SMC support.
	2. Updated product name -> Agilex5
	3. Updated register address based on y22ww52.2 RTL
	4. Updated TSN register base address

Signed-off-by: Jit Loon Lim <jit.loon.lim@intel.com>
Change-Id: I152bee5668b96ef599ded09945167f27a71f23fe
2023-07-05 09:08:29 +08:00

698 lines
16 KiB
C

/*
* Copyright (c) 2020-2022, Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/mmio.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"
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 = 200U;
do {
if (is_mailbox_cmdbuf_empty(cin)) {
break;
}
mdelay(10U);
} 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 = 100U;
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;
}
mdelay(10U);
} 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;
}
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;
cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN);
sdm_read_offset = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
ret = write_mailbox_cmd_buffer(&cmd_free_offset, sdm_read_offset,
header_cmd, &is_doorbell_triggered);
if (ret != 0) {
goto restart_mailbox;
}
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);
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");
}
}
return MBOX_TIMEOUT;
}
int mailbox_read_response(unsigned int *job_id, uint32_t *response,
unsigned int *resp_len)
{
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("Error in response: %x\n", resp_data);
return -MBOX_RESP_ERR(resp_data);
}
return MBOX_RET_OK;
}
return MBOX_NO_RESPONSE;
}
int mailbox_read_response_async(unsigned int *job_id, uint32_t *header,
uint32_t *response, unsigned int *resp_len,
uint8_t ignore_client_id)
{
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((uint8_t *) response,
(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;
}
int mailbox_poll_response(uint32_t job_id, uint32_t urgent, uint32_t *response,
unsigned int *resp_len)
{
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);
INFO("Error: 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;
}
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("Error in response: %x\n", resp_data);
return -MBOX_RESP_ERR(resp_data);
}
return MBOX_RET_OK;
}
sdm_loop--;
}
INFO("Timed out waiting for SDM\n");
return MBOX_TIMEOUT;
}
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;
}
*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_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_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;
}
mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
MBOX_INT_FLAG_UAE);
return MBOX_RET_OK;
}
int intel_mailbox_get_config_status(uint32_t cmd, bool init_done)
{
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 (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) {
ERROR("SoftFunction Status SEU ERROR\n");
}
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);
if ((ret != MBOX_RET_OK) && (ret != MBOX_CFGSTAT_STATE_CONFIG)) {
ret = intel_mailbox_get_config_status(MBOX_CONFIG_STATUS,
false);
}
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);
}