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