1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <mod_power_domain.h>
9 #include <mod_scmi.h>
10 #include <mod_scmi_system_power_req.h>
11
12 #include <fwk_assert.h>
13 #include <fwk_core.h>
14 #include <fwk_event.h>
15 #include <fwk_id.h>
16 #include <fwk_interrupt.h>
17 #include <fwk_log.h>
18 #include <fwk_macros.h>
19 #include <fwk_mm.h>
20 #include <fwk_module.h>
21 #include <fwk_module_idx.h>
22 #include <fwk_status.h>
23 #include <fwk_string.h>
24
25 #include <stdbool.h>
26 #include <stdint.h>
27
28 /* Element context */
29 struct scmi_system_power_req_dev_ctx {
30 /* Element configuration data pointer */
31 const struct mod_scmi_system_power_req_dev_config *config;
32 };
33
34 /* Module context */
35 struct mod_scmi_system_power_req_ctx {
36 /* token to track the sent messages */
37 uint8_t token;
38
39 /* SCMI System power requester element context table */
40 struct scmi_system_power_req_dev_ctx *dev_ctx_table;
41
42 /* Number of elements */
43 unsigned int dev_count;
44
45 /* SCMI send message API */
46 const struct mod_scmi_from_protocol_req_api *scmi_api;
47
48 /* System State - collated after Set State command responses */
49 uint32_t state;
50
51 /* System State Requested - the state that has been sent in the SCMI
52 * command. */
53 uint32_t state_requested;
54
55 /* For the delayed response */
56 uint32_t cookie;
57
58 /* Whether or not the client requested a response */
59 bool response_requested;
60
61 /* Module state after a set state command */
62 int32_t state_change_status;
63 };
64
65 static int scmi_system_power_req_state_set_handler(
66 fwk_id_t service_id,
67 const void *payload,
68 size_t payload_size);
69
70 static int scmi_system_power_req_message_handler(
71 fwk_id_t protocol_id,
72 fwk_id_t service_id,
73 const uint32_t *payload,
74 size_t payload_size,
75 unsigned int message_id);
76
77 /*
78 * Internal variables.
79 */
80 static struct mod_scmi_system_power_req_ctx mod_ctx;
81
82 /*!
83 * \brief SCMI System Power Protocol Message IDs
84 */
85
86 enum scmi_sys_power_req_command_id {
87 /*
88 * SCMI Command ID of the System Power command
89 * implemented in this module.
90 */
91 MOD_SCMI_SYS_POWER_REQ_STATE_SET = 0x003,
92 MOD_SCMI_SYS_POWER_REQ_COMMAND_COUNT,
93 };
94
95 enum scmi_system_power_req_event_idx {
96 /* Event to handle sync set state */
97 SCMI_SPR_EVENT_IDX_SET_STATE = MOD_SCMI_SPR_EVENT_IDX_SET_STATE,
98 SCMI_SPR_EVENT_IDX_SET_COMPLETE,
99 SCMI_SPR_EVENT_IDX_COUNT,
100 };
101
102 /*
103 * Parameters of the set state request event
104 */
105 struct spr_set_state_request {
106 /*
107 * The composite state that defines the power state that the power domain,
108 * target of the request, has to be put into and possibly the power states
109 * the ancestors of the power domain have to be put into.
110 */
111 uint32_t state;
112
113 /* The flags passed from the original SCMI System Power command.*/
114 uint32_t flags;
115 };
116
117 static int (*handler_table[MOD_SCMI_SYS_POWER_REQ_COMMAND_COUNT])(
118 fwk_id_t,
119 const void *,
120 size_t) = {
121 [MOD_SCMI_SYS_POWER_REQ_STATE_SET] =
122 scmi_system_power_req_state_set_handler,
123 };
124
125 static const unsigned int
126 payload_size_table[MOD_SCMI_SYS_POWER_REQ_COMMAND_COUNT] = {
127 [MOD_SCMI_SYS_POWER_REQ_STATE_SET] =
128 (unsigned int)sizeof(struct scmi_sys_power_req_state_set_a2p),
129 };
130
131 static_assert(
132 FWK_ARRAY_SIZE(handler_table) == FWK_ARRAY_SIZE(payload_size_table),
133 "[SCMI] System Power Req protocol table sizes not "
134 "consistent");
135
136 /*
137 * SCMI module -> SCMI system power requester module interface
138 */
scmi_system_power_req_get_scmi_protocol_id(fwk_id_t protocol_id,uint8_t * scmi_protocol_id)139 static int scmi_system_power_req_get_scmi_protocol_id(
140 fwk_id_t protocol_id,
141 uint8_t *scmi_protocol_id)
142 {
143 *scmi_protocol_id = (uint8_t)MOD_SCMI_PROTOCOL_ID_SYS_POWER;
144
145 return FWK_SUCCESS;
146 }
147
148 /*
149 * System Power Requester Response handlers
150 */
scmi_system_power_req_message_handler(fwk_id_t protocol_id,fwk_id_t service_id,const uint32_t * payload,size_t payload_size,unsigned int message_id)151 static int scmi_system_power_req_message_handler(
152 fwk_id_t protocol_id,
153 fwk_id_t service_id,
154 const uint32_t *payload,
155 size_t payload_size,
156 unsigned int message_id)
157 {
158 int ret_status, alt_status;
159
160 fwk_assert(payload != NULL);
161
162 if (message_id >= FWK_ARRAY_SIZE(handler_table)) {
163 return FWK_E_RANGE;
164 }
165
166 if (payload_size != payload_size_table[message_id]) {
167 return FWK_E_PARAM;
168 }
169
170 if (handler_table[message_id] == NULL) {
171 return FWK_E_PARAM;
172 }
173 ret_status = handler_table[message_id](service_id, payload, payload_size);
174
175 alt_status = mod_ctx.scmi_api->response_message_handler(service_id);
176
177 return (ret_status != FWK_SUCCESS) ? ret_status : alt_status;
178 }
179
180 static struct mod_scmi_to_protocol_api
181 scmi_system_power_req_scmi_to_protocol_api = {
182 .get_scmi_protocol_id = scmi_system_power_req_get_scmi_protocol_id,
183 .message_handler = scmi_system_power_req_message_handler,
184 };
185
186 /*
187 * Return System Power Requester reading handler. This is the Set State response
188 * handler.
189 */
scmi_system_power_req_state_set_handler(fwk_id_t service_id,const void * payload,size_t payload_size)190 static int scmi_system_power_req_state_set_handler(
191 fwk_id_t service_id,
192 const void *payload,
193 size_t payload_size)
194 {
195 int ret_status;
196 int status;
197
198 ret_status = *((const int *)payload);
199
200 if (ret_status == SCMI_SUCCESS) {
201 mod_ctx.state = mod_ctx.state_requested;
202 }
203
204 mod_ctx.state_change_status = ret_status;
205
206 if (mod_ctx.response_requested) {
207 struct fwk_event_light req = (struct fwk_event_light){
208 .id = FWK_ID_EVENT(
209 FWK_MODULE_IDX_SCMI_SYSTEM_POWER_REQ,
210 SCMI_SPR_EVENT_IDX_SET_COMPLETE),
211 .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_SCMI_SYSTEM_POWER_REQ),
212 };
213
214 status = fwk_put_event(&req);
215 if (status != FWK_SUCCESS) {
216 return status;
217 }
218 }
219
220 return ret_status;
221 }
222
scmi_system_power_req_set_state(bool response_requested,uint32_t state,uint32_t flags)223 static int scmi_system_power_req_set_state(
224 bool response_requested,
225 uint32_t state,
226 uint32_t flags)
227 {
228 int status;
229
230 struct fwk_event req;
231 struct spr_set_state_request *req_params =
232 (struct spr_set_state_request *)(&req.params);
233
234 mod_ctx.state_requested = state;
235 mod_ctx.response_requested = response_requested;
236
237 req = (struct fwk_event){
238 .id = system_power_requester_set_state_request,
239 .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_SCMI_SYSTEM_POWER_REQ),
240 .response_requested = response_requested,
241 };
242
243 req_params->state = state;
244 req_params->flags = flags;
245 status = fwk_put_event(&req);
246
247 if (status == FWK_SUCCESS) {
248 return FWK_PENDING;
249 } else {
250 return status;
251 }
252 }
253
process_set_state(fwk_id_t id,uint32_t state,uint32_t flags)254 static int process_set_state(fwk_id_t id, uint32_t state, uint32_t flags)
255 {
256 uint8_t scmi_protocol_id = (uint8_t)MOD_SCMI_PROTOCOL_ID_SYS_POWER;
257 uint8_t scmi_message_id = (uint8_t)MOD_SCMI_SYS_POWER_REQ_STATE_SET;
258
259 struct scmi_system_power_req_dev_ctx *ctx = &(mod_ctx.dev_ctx_table[0]);
260
261 const struct scmi_sys_power_req_state_set_a2p payload = {
262 .flags = flags,
263 .system_state = state,
264 };
265
266 return mod_ctx.scmi_api->scmi_send_message(
267 scmi_message_id,
268 scmi_protocol_id,
269 mod_ctx.token++,
270 ctx->config->service_id,
271 (const void *)&payload,
272 sizeof(payload),
273 true);
274 }
275
scmi_system_power_req_get_state(uint32_t * state)276 static int scmi_system_power_req_get_state(uint32_t *state)
277 {
278 if (state != NULL) {
279 /* Set State command will cache the response */
280 *state = mod_ctx.state;
281
282 return FWK_SUCCESS;
283 }
284 return FWK_E_PARAM;
285 }
286
287 static const struct mod_system_power_requester_api
288 scmi_system_power_req_driver_api = {
289 .set_req_state = scmi_system_power_req_set_state,
290 .get_req_state = scmi_system_power_req_get_state,
291 };
292
293 /*
294 * Framework handlers
295 */
scmi_system_power_req_init(fwk_id_t module_id,unsigned int element_count,const void * data)296 static int scmi_system_power_req_init(
297 fwk_id_t module_id,
298 unsigned int element_count,
299 const void *data)
300 {
301 mod_ctx.state = MOD_PD_STATE_ON;
302
303 /* We definitely need elements in this module. */
304 if (element_count != 1) {
305 return FWK_E_SUPPORT;
306 }
307
308 mod_ctx.dev_count = element_count;
309 mod_ctx.dev_ctx_table =
310 fwk_mm_calloc(element_count, sizeof(mod_ctx.dev_ctx_table[0]));
311
312 return FWK_SUCCESS;
313 }
314
scmi_system_power_req_elem_init(fwk_id_t element_id,unsigned int unused,const void * data)315 static int scmi_system_power_req_elem_init(
316 fwk_id_t element_id,
317 unsigned int unused,
318 const void *data)
319 {
320 struct scmi_system_power_req_dev_ctx *dev_ctx;
321
322 if (fwk_id_get_element_idx(element_id) >= mod_ctx.dev_count) {
323 return FWK_E_PARAM;
324 }
325
326 dev_ctx = &mod_ctx.dev_ctx_table[fwk_id_get_element_idx(element_id)];
327
328 if (data == NULL) {
329 return FWK_E_PANIC;
330 }
331
332 const struct mod_scmi_system_power_req_dev_config *mod_sys_pow_req_config =
333 (const struct mod_scmi_system_power_req_dev_config *)data;
334
335 dev_ctx->config = mod_sys_pow_req_config;
336
337 return FWK_SUCCESS;
338 }
339
scmi_system_power_req_bind(fwk_id_t id,unsigned int round)340 static int scmi_system_power_req_bind(fwk_id_t id, unsigned int round)
341 {
342 int status = FWK_SUCCESS;
343
344 if (round == 0) {
345 if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
346 status = fwk_module_bind(
347 FWK_ID_MODULE(FWK_MODULE_IDX_SCMI),
348 FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_PROTOCOL_REQ),
349 &mod_ctx.scmi_api);
350 }
351 }
352 return status;
353 }
354
scmi_system_power_req_bind_request(fwk_id_t requester_id,fwk_id_t unused,fwk_id_t api_id,const void ** api)355 static int scmi_system_power_req_bind_request(
356 fwk_id_t requester_id,
357 fwk_id_t unused,
358 fwk_id_t api_id,
359 const void **api)
360 {
361 if (fwk_id_is_equal(api_id, mod_sys_power_req_scmi_api_id)) {
362 if (!fwk_id_is_equal(
363 fwk_id_build_module_id(requester_id), fwk_module_id_scmi)) {
364 return FWK_E_ACCESS;
365 }
366 *api = &scmi_system_power_req_scmi_to_protocol_api;
367 } else if (fwk_id_is_equal(api_id, mod_sys_power_req_api_id)) {
368 *api = &scmi_system_power_req_driver_api;
369 } else {
370 return FWK_E_SUPPORT;
371 }
372
373 return FWK_SUCCESS;
374 }
375
scmi_system_power_req_process_event(const struct fwk_event * event,struct fwk_event * resp)376 static int scmi_system_power_req_process_event(
377 const struct fwk_event *event,
378 struct fwk_event *resp)
379 {
380 struct fwk_event set_req_event;
381 int status;
382 struct spr_set_state_request *event_params =
383 (struct spr_set_state_request *)(event->params);
384
385 enum scmi_system_power_req_event_idx event_id_type =
386 (enum scmi_system_power_req_event_idx)fwk_id_get_event_idx(event->id);
387
388 switch (event_id_type) {
389 case SCMI_SPR_EVENT_IDX_SET_STATE:
390 if (event->response_requested) {
391 /*
392 * We keep the cookie event of the request that triggers the
393 * state change.
394 */
395 mod_ctx.cookie = event->cookie;
396 resp->is_delayed_response = true;
397 }
398 process_set_state(event->id, event_params->state, event_params->flags);
399 return FWK_SUCCESS;
400
401 case SCMI_SPR_EVENT_IDX_SET_COMPLETE:
402 status = fwk_get_delayed_response(
403 event->target_id, mod_ctx.cookie, &set_req_event);
404 if (status != FWK_SUCCESS) {
405 return status;
406 }
407
408 event_params->state = mod_ctx.state_change_status;
409 return fwk_put_event(&set_req_event);
410
411 default:
412 return FWK_E_PARAM;
413 }
414 }
415
416 const struct fwk_module module_scmi_system_power_req = {
417 .type = FWK_MODULE_TYPE_PROTOCOL,
418 .api_count = (unsigned int)MOD_SYS_POW_REQ_API_IDX_COUNT,
419 .event_count = (unsigned int)SCMI_SPR_EVENT_IDX_COUNT,
420 .init = scmi_system_power_req_init,
421 .element_init = scmi_system_power_req_elem_init,
422 .bind = scmi_system_power_req_bind,
423 .process_bind_request = scmi_system_power_req_bind_request,
424 .process_event = scmi_system_power_req_process_event,
425 };
426