1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     SCMI Agent Support.
9  */
10 
11 #include <mod_scmi_agent.h>
12 #include <mod_smt.h>
13 
14 #include <fwk_core.h>
15 #include <fwk_event.h>
16 #include <fwk_id.h>
17 #include <fwk_log.h>
18 #include <fwk_mm.h>
19 #include <fwk_module.h>
20 #include <fwk_module_idx.h>
21 #include <fwk_status.h>
22 
23 #include <inttypes.h>
24 #include <stddef.h>
25 #include <stdint.h>
26 
27 /* SCMI agent context */
28 struct scmi_agent_ctx {
29     /* Pointer to agent configuration data */
30     struct mod_scmi_agent_config *config;
31 
32     /* Pointer to received payload data */
33     const void *payload;
34 
35     /* Size of received payload */
36     size_t size;
37 };
38 
39 /* Module context */
40 struct mod_scmi_agent_module_ctx {
41     /* Pointer to agent configuration table */
42     struct scmi_agent_ctx *agent_ctx_table;
43 
44     /* SMT API pointer */
45     const struct mod_scmi_agent_to_transport_api *smt_api;
46 };
47 
48 enum scmi_agent_event {
49     MOD_SCMI_AGENT_EVENT_RUN,
50     MOD_SCMI_AGENT_EVENT_COUNT,
51 };
52 
53 static struct mod_scmi_agent_module_ctx ctx;
54 
_scmi_agent_transact(fwk_id_t agent_id,struct mod_smt_command_config * cmd)55 static int _scmi_agent_transact(fwk_id_t agent_id,
56                                struct mod_smt_command_config *cmd)
57 {
58     struct scmi_agent_ctx *agent_ctx;
59     int status;
60 
61     agent_ctx = &ctx.agent_ctx_table[fwk_id_get_element_idx(agent_id)];
62 
63     /* Check if channel is free */
64     if (!ctx.smt_api->is_channel_free(agent_ctx->config->transport_id)) {
65         FWK_LOG_ERR("[SCMI AGENT] Channel Busy!");
66         return FWK_E_BUSY;
67     }
68 
69     /* Send SCMI command to platform */
70     status = ctx.smt_api->send(agent_ctx->config->transport_id, cmd);
71     if (status != FWK_SUCCESS) {
72         ctx.smt_api->put_channel(agent_ctx->config->transport_id);
73         return status;
74     }
75 
76     /* Wait until platform responds */
77     while (!ctx.smt_api->is_channel_free(agent_ctx->config->transport_id))
78         ;
79 
80     /* Get response payload */
81     status = ctx.smt_api->get_payload(agent_ctx->config->transport_id,
82                                       &agent_ctx->payload, &agent_ctx->size);
83     if (status != FWK_SUCCESS)
84         return status;
85 
86     /* Release channel */
87     status = ctx.smt_api->put_channel(agent_ctx->config->transport_id);
88     if (status != FWK_SUCCESS)
89         return status;
90 
91     return FWK_SUCCESS;
92 }
93 
94 /*
95  * SCMI Management Agent API interface
96  */
agent_get_protocol_version(fwk_id_t agent_id,uint32_t * version)97 static int agent_get_protocol_version(fwk_id_t agent_id, uint32_t *version)
98 {
99     int status;
100     struct scmi_agent_ctx *agent_ctx;
101     struct mod_smt_command_config cmd = {
102         .protocol_id = SCMI_PROTOCOL_ID_MANAGEMENT,
103         .message_id = SCMI_MANAGEMENT_PROTOCOL_VERSION_GET,
104         .payload = NULL,
105         .size = 0,
106     };
107 
108     if (version == NULL)
109         return FWK_E_PARAM;
110 
111     status = _scmi_agent_transact(agent_id, &cmd);
112     if (status != FWK_SUCCESS)
113         return status;
114 
115     agent_ctx = &ctx.agent_ctx_table[fwk_id_get_element_idx(agent_id)];
116     *version = *(((uint32_t *)agent_ctx->payload) + 1);
117 
118     return FWK_SUCCESS;
119 }
120 
agent_get_clock_status(fwk_id_t agent_id,uint32_t * clock_status)121 static int agent_get_clock_status(fwk_id_t agent_id, uint32_t *clock_status)
122 {
123     int status;
124     struct scmi_agent_ctx *agent_ctx;
125     struct mod_smt_command_config cmd = {
126         .protocol_id = SCMI_PROTOCOL_ID_MANAGEMENT,
127         .message_id = SCMI_MANAGEMENT_CLOCK_STATUS_GET,
128         .payload = NULL,
129         .size = 0,
130     };
131 
132     if (clock_status == NULL)
133         return FWK_E_PARAM;
134 
135     status = _scmi_agent_transact(agent_id, &cmd);
136     if (status != FWK_SUCCESS)
137         return status;
138 
139     agent_ctx = &ctx.agent_ctx_table[fwk_id_get_element_idx(agent_id)];
140     *clock_status = *(((uint32_t *)agent_ctx->payload) + 1);
141 
142     return FWK_SUCCESS;
143 }
144 
agent_get_chipid_info(fwk_id_t agent_id,uint8_t * multichip_mode,uint8_t * chipid)145 static int agent_get_chipid_info(fwk_id_t agent_id,
146                                  uint8_t *multichip_mode,
147                                  uint8_t *chipid)
148 {
149     int status;
150     struct scmi_agent_ctx *agent_ctx;
151     struct mod_smt_command_config cmd = {
152         .protocol_id = SCMI_PROTOCOL_ID_MANAGEMENT,
153         .message_id = SCMI_MANAGEMENT_CHIPID_INFO_GET,
154         .payload = NULL,
155         .size = 0,
156     };
157 
158     if ((multichip_mode == NULL) || (chipid == NULL))
159         return FWK_E_PARAM;
160 
161     status = _scmi_agent_transact(agent_id, &cmd);
162     if (status != FWK_SUCCESS)
163         return status;
164 
165     agent_ctx = &ctx.agent_ctx_table[fwk_id_get_element_idx(agent_id)];
166     *multichip_mode = (uint8_t)(*(((uint32_t *)agent_ctx->payload) + 1));
167     *chipid = (uint8_t)(*(((uint32_t *)agent_ctx->payload) + 2));
168 
169     return FWK_SUCCESS;
170 }
171 
172 struct mod_scmi_agent_api scmi_agent_api = {
173     .get_protocol_version = agent_get_protocol_version,
174     .get_clock_status = agent_get_clock_status,
175     .get_chipid_info = agent_get_chipid_info,
176 };
177 
178 /*
179  * Functions fulfilling the framework's module interface
180  */
181 
scmi_agent_init(fwk_id_t module_id,unsigned int agent_count,const void * unused2)182 static int scmi_agent_init(fwk_id_t module_id, unsigned int agent_count,
183     const void *unused2)
184 {
185     ctx.agent_ctx_table = fwk_mm_calloc(agent_count,
186                                         sizeof(ctx.agent_ctx_table[0]));
187 
188     return FWK_SUCCESS;
189 }
190 
scmi_agent_element_init(fwk_id_t agent_id,unsigned int unused,const void * data)191 static int scmi_agent_element_init(fwk_id_t agent_id, unsigned int unused,
192                              const void *data)
193 {
194     struct scmi_agent_ctx *agent_ctx;
195     struct mod_scmi_agent_config *config =
196         (struct mod_scmi_agent_config *)data;
197 
198     if (config == NULL)
199         return FWK_E_PARAM;
200 
201     agent_ctx = &ctx.agent_ctx_table[fwk_id_get_element_idx(agent_id)];
202     agent_ctx->config = config;
203 
204     return FWK_SUCCESS;
205 }
206 
scmi_agent_bind(fwk_id_t id,unsigned int round)207 static int scmi_agent_bind(fwk_id_t id, unsigned int round)
208 {
209     struct scmi_agent_ctx *agent_ctx;
210 
211     if (round == 0) {
212         if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE))
213             return FWK_SUCCESS;
214 
215         agent_ctx = &ctx.agent_ctx_table[fwk_id_get_element_idx(id)];
216         return fwk_module_bind(agent_ctx->config->transport_id,
217                                agent_ctx->config->transport_api_id,
218                                &ctx.smt_api);
219     }
220     return FWK_SUCCESS;
221 }
222 
scmi_agent_start(fwk_id_t id)223 static int scmi_agent_start(fwk_id_t id)
224 {
225     /* Process only in the element start stage */
226     if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE))
227         return FWK_SUCCESS;
228 
229     struct fwk_event event = {
230         .source_id = id,
231         .target_id = id,
232         .id = FWK_ID_EVENT(FWK_MODULE_IDX_SCMI_AGENT,
233                            MOD_SCMI_AGENT_EVENT_RUN),
234     };
235 
236     return fwk_put_event(&event);
237 }
238 
scmi_agent_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)239 static int scmi_agent_process_bind_request(fwk_id_t source_id,
240                                            fwk_id_t target_id,
241                                            fwk_id_t api_id,
242                                            const void **api)
243 {
244     *api = &scmi_agent_api;
245     return FWK_SUCCESS;
246 }
247 
scmi_agent_process_event(const struct fwk_event * event,struct fwk_event * resp)248 static int scmi_agent_process_event(const struct fwk_event *event,
249                                     struct fwk_event *resp)
250 {
251     int status;
252     uint32_t temp = 0;
253 
254     status = agent_get_protocol_version(event->target_id, &temp);
255     if (status != FWK_SUCCESS)
256         return status;
257 
258     FWK_LOG_INFO(
259         "[SCMI AGENT] Found management protocol version: 0x%" PRIu32, temp);
260 
261     return status;
262 }
263 
264 const struct fwk_module module_scmi_agent = {
265     .type = FWK_MODULE_TYPE_SERVICE,
266     .api_count = MOD_SCMI_AGENT_API_IDX_COUNT,
267     .event_count = MOD_SCMI_AGENT_EVENT_COUNT,
268     .init = scmi_agent_init,
269     .element_init = scmi_agent_element_init,
270     .bind = scmi_agent_bind,
271     .start = scmi_agent_start,
272     .process_bind_request = scmi_agent_process_bind_request,
273     .process_event = scmi_agent_process_event,
274 };
275