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