1 /*
2  * Copyright (c) 2023, Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * A sample application using sip_svc subsystem to get query values from secure device.
7  * The access to the secure device is defined via EL3 exception level and uses
8  * the ARM Trusted Firmware to provide access.The application runs on Intel Agilex FPGA SoC,
9  * where the app queries voltage sampled from the SDM(Secure Device Manager).
10  */
11 
12 #include <zephyr/sip_svc/sip_svc.h>
13 #include <zephyr/drivers/sip_svc/sip_svc_agilex_mailbox.h>
14 #include <zephyr/drivers/sip_svc/sip_svc_agilex_smc.h>
15 #include <zephyr/sys/__assert.h>
16 
17 #define SVC_METHOD	       "smc"
18 #define GET_VOLTAGE_CMD	       (0x18U)
19 #define SET_VOLTAGE_CHANNEL(x) ((1 << (x)) & 0xffff)
20 #define TIME_DELAY	       (K_MSEC(1000U))
21 
22 struct private_data {
23 	struct k_sem semaphore;
24 	uint32_t voltage_channel0;
25 };
26 
get_voltage_callback(uint32_t c_token,struct sip_svc_response * response)27 void get_voltage_callback(uint32_t c_token, struct sip_svc_response *response)
28 {
29 	if (response == NULL) {
30 		return;
31 	}
32 
33 	struct private_data *priv = (struct private_data *)response->priv_data;
34 
35 	uint32_t *resp_data = (uint32_t *)response->resp_data_addr;
36 	uint32_t resp_len = response->resp_data_size / 4;
37 
38 	if (resp_data && resp_len) {
39 		priv->voltage_channel0 = resp_data[1];
40 	}
41 
42 	k_sem_give(&(priv->semaphore));
43 }
44 
main(void)45 int main(void)
46 {
47 	void *mb_smc_ctrl = NULL;
48 	uint32_t mb_c_token = SIP_SVC_ID_INVALID;
49 	struct sip_svc_request request = {0};
50 	uint32_t *cmd_addr = NULL, *resp_addr = NULL;
51 	uint32_t cmd_size = (2 * sizeof(uint32_t));
52 	uint32_t resp_size = (2 * sizeof(uint32_t));
53 	struct private_data priv;
54 
55 	float voltage;
56 	int err, trans_id;
57 
58 	resp_addr = (uint32_t *)k_malloc(resp_size);
59 	__ASSERT(resp_addr != NULL, "Failed to get memory");
60 
61 	mb_smc_ctrl = sip_svc_get_controller(SVC_METHOD);
62 	__ASSERT(mb_smc_ctrl != NULL, "Failed to get the controller from sip_svc");
63 
64 	mb_c_token = sip_svc_register(mb_smc_ctrl, NULL);
65 	__ASSERT(mb_c_token != SIP_SVC_ID_INVALID, "Failed to register with sip_svc");
66 
67 	k_sem_init(&(priv.semaphore), 0, 1);
68 
69 	request.header = SIP_SVC_PROTO_HEADER(SIP_SVC_PROTO_CMD_ASYNC, 0);
70 	request.a0 = SMC_FUNC_ID_MAILBOX_SEND_COMMAND;
71 	request.resp_data_addr = (uint64_t)resp_addr;
72 	request.resp_data_size = (uint64_t)resp_size;
73 	request.priv_data = (void *)&priv;
74 
75 	while (1) {
76 		err = sip_svc_open(mb_smc_ctrl, mb_c_token, K_FOREVER);
77 		__ASSERT(err != SIP_SVC_ID_INVALID, "Failed to open with sip_svc");
78 
79 		cmd_addr = (uint32_t *)k_malloc(cmd_size);
80 		__ASSERT(cmd_addr != NULL, "Failed to get memory");
81 
82 		/**
83 		 * Populate the SDM mailbox command ,where first word will be the header,
84 		 * header will contain the mailbox command and the size of command data to be sent
85 		 * to SDM. The transaction id and client id will be filled by sip_svc subsystem.
86 		 */
87 		cmd_addr[0] = ((cmd_size / 4 - 1) << 12) | GET_VOLTAGE_CMD;
88 		cmd_addr[1] = SET_VOLTAGE_CHANNEL(2);
89 
90 		/**
91 		 * Set the pointer to mailbox command buffer to a2 parameter and
92 		 * mailbox command buffer size to a3 parameter ,which EL3 software will
93 		 * expect for a ASYNC transaction.
94 		 */
95 		request.a2 = (uint64_t)cmd_addr;
96 		request.a3 = (uint64_t)cmd_size;
97 
98 		trans_id = sip_svc_send(mb_smc_ctrl, mb_c_token, &request, get_voltage_callback);
99 		__ASSERT(trans_id < 0, "Error in sending a request to SDM mailbox");
100 
101 		err = k_sem_take(&(priv.semaphore), K_FOREVER);
102 		__ASSERT(err != 0, "Error in taking semaphore");
103 
104 		/* Voltage is retrieved as a fixed point number with 16 bits below binary point */
105 		voltage = ((float)priv.voltage_channel0 / 65536);
106 
107 		printk("Got response of transaction id 0x%02x and voltage is %fv\n", trans_id,
108 		       voltage);
109 
110 		err = sip_svc_close(mb_smc_ctrl, mb_c_token, NULL);
111 		__ASSERT(err != SIP_SVC_ID_INVALID, "Failed to close with sip_svc");
112 
113 		k_sleep(TIME_DELAY);
114 	}
115 }
116