| /* |
| * Copyright (c) 2023, Intel Corporation. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * A sample application using sip_svc subsystem to get query values from secure device. |
| * The access to the secure device is defined via EL3 exception level and uses |
| * the ARM Trusted Firmware to provide access.The application runs on Intel Agilex FPGA SoC, |
| * where the app queries voltage sampled from the SDM(Secure Device Manager). |
| */ |
| |
| #include <zephyr/sip_svc/sip_svc.h> |
| #include <zephyr/drivers/sip_svc/sip_svc_agilex_mailbox.h> |
| #include <zephyr/drivers/sip_svc/sip_svc_agilex_smc.h> |
| #include <zephyr/sys/__assert.h> |
| |
| #define SVC_METHOD "smc" |
| #define GET_VOLTAGE_CMD (0x18U) |
| #define SET_VOLTAGE_CHANNEL(x) ((1 << (x)) & 0xffff) |
| #define TIME_DELAY (K_MSEC(1000U)) |
| |
| struct private_data { |
| struct k_sem semaphore; |
| uint32_t voltage_channel0; |
| }; |
| |
| void get_voltage_callback(uint32_t c_token, struct sip_svc_response *response) |
| { |
| if (response == NULL) { |
| return; |
| } |
| |
| struct private_data *priv = (struct private_data *)response->priv_data; |
| |
| uint32_t *resp_data = (uint32_t *)response->resp_data_addr; |
| uint32_t resp_len = response->resp_data_size / 4; |
| |
| if (resp_data && resp_len) { |
| priv->voltage_channel0 = resp_data[1]; |
| } |
| |
| k_sem_give(&(priv->semaphore)); |
| } |
| |
| void main(void) |
| { |
| void *mb_smc_ctrl = NULL; |
| uint32_t mb_c_token = SIP_SVC_ID_INVALID; |
| struct sip_svc_request request = {0}; |
| uint32_t *cmd_addr = NULL, *resp_addr = NULL; |
| uint32_t cmd_size = (2 * sizeof(uint32_t)); |
| uint32_t resp_size = (2 * sizeof(uint32_t)); |
| struct private_data priv; |
| |
| float voltage; |
| int err, trans_id; |
| |
| resp_addr = (uint32_t *)k_malloc(resp_size); |
| __ASSERT(resp_addr != NULL, "Failed to get memory"); |
| |
| mb_smc_ctrl = sip_svc_get_controller(SVC_METHOD); |
| __ASSERT(mb_smc_ctrl != NULL, "Failed to get the controller from sip_svc"); |
| |
| mb_c_token = sip_svc_register(mb_smc_ctrl, NULL); |
| __ASSERT(mb_c_token != SIP_SVC_ID_INVALID, "Failed to register with sip_svc"); |
| |
| k_sem_init(&(priv.semaphore), 0, 1); |
| |
| request.header = SIP_SVC_PROTO_HEADER(SIP_SVC_PROTO_CMD_ASYNC, 0); |
| request.a0 = SMC_FUNC_ID_MAILBOX_SEND_COMMAND; |
| request.resp_data_addr = (uint64_t)resp_addr; |
| request.resp_data_size = (uint64_t)resp_size; |
| request.priv_data = (void *)&priv; |
| |
| while (1) { |
| err = sip_svc_open(mb_smc_ctrl, mb_c_token, K_FOREVER); |
| __ASSERT(err != SIP_SVC_ID_INVALID, "Failed to open with sip_svc"); |
| |
| cmd_addr = (uint32_t *)k_malloc(cmd_size); |
| __ASSERT(cmd_addr != NULL, "Failed to get memory"); |
| |
| /** |
| * Populate the SDM mailbox command ,where first word will be the header, |
| * header will contain the mailbox command and the size of command data to be sent |
| * to SDM. The transaction id and client id will be filled by sip_svc subsystem. |
| */ |
| cmd_addr[0] = ((cmd_size / 4 - 1) << 12) | GET_VOLTAGE_CMD; |
| cmd_addr[1] = SET_VOLTAGE_CHANNEL(2); |
| |
| /** |
| * Set the pointer to mailbox command buffer to a2 parameter and |
| * mailbox command buffer size to a3 parameter ,which EL3 software will |
| * expect for a ASYNC transaction. |
| */ |
| request.a2 = (uint64_t)cmd_addr; |
| request.a3 = (uint64_t)cmd_size; |
| |
| trans_id = sip_svc_send(mb_smc_ctrl, mb_c_token, &request, get_voltage_callback); |
| __ASSERT(trans_id < 0, "Error in sending a request to SDM mailbox"); |
| |
| err = k_sem_take(&(priv.semaphore), K_FOREVER); |
| __ASSERT(err != 0, "Error in taking semaphore"); |
| |
| /* Voltage is retrieved as a fixed point number with 16 bits below binary point */ |
| voltage = ((float)priv.voltage_channel0 / 65536); |
| |
| printk("Got response of transaction id 0x%02x and voltage is %fv\n", trans_id, |
| voltage); |
| |
| err = sip_svc_close(mb_smc_ctrl, mb_c_token, NULL); |
| __ASSERT(err != SIP_SVC_ID_INVALID, "Failed to close with sip_svc"); |
| |
| k_sleep(TIME_DELAY); |
| } |
| } |