1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2019-2023, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * SCMI Reset Domain management protocol support.
9 */
10
11 #include <internal/scmi_reset_domain.h>
12
13 #include <mod_reset_domain.h>
14 #include <mod_scmi.h>
15 #include <mod_scmi_reset_domain.h>
16
17 #include <fwk_assert.h>
18 #include <fwk_attributes.h>
19 #include <fwk_log.h>
20 #include <fwk_macros.h>
21 #include <fwk_mm.h>
22 #include <fwk_module.h>
23 #include <fwk_module_idx.h>
24 #include <fwk_notification.h>
25 #include <fwk_status.h>
26
27 #include <string.h>
28
29 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
30 # include <mod_resource_perms.h>
31 #endif
32
33 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
34 # define MOD_SCMI_RESET_DOMAIN_NOTIFICATION_COUNT 1
35 #endif
36
37 struct scmi_rd_ctx {
38 /*! SCMI Reset Module Configuration */
39 const struct mod_scmi_reset_domain_config *config;
40
41 /* Bound module APIs */
42 const struct mod_scmi_from_protocol_api *scmi_api;
43 const struct mod_reset_domain_api *reset_api;
44
45 /*! Number of reset domains available on platform */
46 uint8_t plat_reset_domain_count;
47
48 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
49 /*! SCMI notification_id */
50 fwk_id_t notification_id;
51
52 /* SCMI notification API */
53 const struct mod_scmi_notification_api *scmi_notification_api;
54 #endif
55
56 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
57 /* SCMI Resource Permissions API */
58 const struct mod_res_permissions_api *res_perms_api;
59 #endif
60 };
61
62 static int protocol_version_handler(fwk_id_t service_id,
63 const uint32_t *payload);
64
65 static int protocol_attributes_handler(fwk_id_t service_id,
66 const uint32_t *payload);
67 static int protocol_message_attributes_handler(fwk_id_t service_id,
68 const uint32_t *payload);
69 static int reset_attributes_handler(fwk_id_t service_id,
70 const uint32_t *payload);
71 static int reset_request_handler(fwk_id_t service_id,
72 const uint32_t *payload);
73 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
74 static int reset_notify_handler(fwk_id_t service_id,
75 const uint32_t *payload);
76 #endif
77
78 /*
79 * Internal variables
80 */
81
82 static struct scmi_rd_ctx scmi_rd_ctx;
83
84 static int (*msg_handler_table[])(fwk_id_t, const uint32_t *) = {
85 [MOD_SCMI_PROTOCOL_VERSION] = protocol_version_handler,
86 [MOD_SCMI_PROTOCOL_ATTRIBUTES] = protocol_attributes_handler,
87 [MOD_SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] =
88 protocol_message_attributes_handler,
89 [MOD_SCMI_RESET_DOMAIN_ATTRIBUTES] = reset_attributes_handler,
90 [MOD_SCMI_RESET_REQUEST] = reset_request_handler,
91 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
92 [MOD_SCMI_RESET_NOTIFY] = reset_notify_handler,
93 #endif
94 };
95
96 static unsigned int payload_size_table[] = {
97 [MOD_SCMI_PROTOCOL_VERSION] = 0,
98 [MOD_SCMI_PROTOCOL_ATTRIBUTES] = 0,
99 [MOD_SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] =
100 (unsigned int)sizeof(struct scmi_protocol_message_attributes_a2p),
101 [MOD_SCMI_RESET_DOMAIN_ATTRIBUTES] =
102 (unsigned int)sizeof(struct scmi_reset_domain_attributes_a2p),
103 [MOD_SCMI_RESET_REQUEST] =
104 (unsigned int)sizeof(struct scmi_reset_domain_request_a2p),
105 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
106 [MOD_SCMI_RESET_NOTIFY] = sizeof(struct scmi_reset_domain_notify_a2p),
107 #endif
108 };
109
110 /*
111 * Reset domain management protocol implementation
112 */
113
protocol_version_handler(fwk_id_t service_id,const uint32_t * payload)114 static int protocol_version_handler(fwk_id_t service_id,
115 const uint32_t *payload)
116 {
117 struct scmi_protocol_version_p2a outmsg = {
118 .status = (int32_t)SCMI_SUCCESS,
119 .version = SCMI_PROTOCOL_VERSION_RESET_DOMAIN,
120 };
121
122 return scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, sizeof(outmsg));
123 }
124
protocol_attributes_handler(fwk_id_t service_id,const uint32_t * payload)125 static int protocol_attributes_handler(fwk_id_t service_id,
126 const uint32_t *payload)
127 {
128 struct scmi_reset_domain_protocol_attributes_p2a outmsg = {
129 .status = (int32_t)SCMI_SUCCESS,
130 };
131 int status = 0;
132 unsigned int agent_id = 0;
133
134 status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, &agent_id);
135 if (status != FWK_SUCCESS)
136 return status;
137
138 if (agent_id >= scmi_rd_ctx.config->agent_count)
139 return FWK_E_PARAM;
140
141 outmsg.attributes = scmi_rd_ctx.config->
142 agent_table[agent_id].agent_domain_count;
143
144 return scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, sizeof(outmsg));
145 }
146
protocol_message_attributes_handler(fwk_id_t service_id,const uint32_t * payload)147 static int protocol_message_attributes_handler(fwk_id_t service_id,
148 const uint32_t *payload)
149 {
150 struct scmi_protocol_message_attributes_p2a outmsg = {
151 .status = (int32_t)SCMI_NOT_FOUND,
152 };
153 size_t outmsg_size = sizeof(outmsg.status);
154 struct scmi_protocol_message_attributes_a2p params = { 0 };
155
156 params = *(const struct scmi_protocol_message_attributes_a2p *)payload;
157
158 if ((params.message_id < FWK_ARRAY_SIZE(msg_handler_table)) &&
159 (msg_handler_table[params.message_id] != NULL)) {
160 outmsg.status = (int32_t)SCMI_SUCCESS;
161 outmsg_size = sizeof(outmsg);
162 }
163
164 return scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size);
165 }
166
167 /*
168 * Given a service identifier, retrieve a agent identifier
169 */
get_agent_id(fwk_id_t service_id,unsigned int * agent_id)170 static int get_agent_id(fwk_id_t service_id, unsigned int* agent_id)
171 {
172 int status;
173
174 status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, agent_id);
175 if (status != FWK_SUCCESS)
176 return status;
177
178 if (*agent_id >= scmi_rd_ctx.config->agent_count)
179 return FWK_E_PARAM;
180
181 return FWK_SUCCESS;
182 }
183
184 /*
185 * Given a service identifier, retrieve a pointer to its agent's
186 * \c mod_scmi_reset_domain_agent structure within the agent table.
187 */
get_agent_entry(fwk_id_t service_id,const struct mod_scmi_reset_domain_agent ** agent)188 static int get_agent_entry(fwk_id_t service_id,
189 const struct mod_scmi_reset_domain_agent **agent)
190 {
191 int status = 0;
192 unsigned int agent_id = 0;
193
194 status = get_agent_id(service_id, &agent_id);
195 if (status != FWK_SUCCESS)
196 return status;
197
198 *agent = &scmi_rd_ctx.config->agent_table[agent_id];
199
200 return FWK_SUCCESS;
201 }
202
get_reset_device(fwk_id_t service_id,unsigned int domain_id,const struct mod_scmi_reset_domain_device ** device)203 static int get_reset_device(fwk_id_t service_id,
204 unsigned int domain_id,
205 const struct mod_scmi_reset_domain_device **device)
206 {
207 int status;
208 const struct mod_scmi_reset_domain_agent *agent_entry = NULL;
209
210 status = get_agent_entry(service_id, &agent_entry);
211 if (status != FWK_SUCCESS)
212 return status;
213
214 if (domain_id >= agent_entry->agent_domain_count)
215 return FWK_E_RANGE;
216
217 *device = &agent_entry->device_table[domain_id];
218
219 fwk_assert(fwk_module_is_valid_element_id((*device)->element_id));
220
221 if (!fwk_module_is_valid_element_id((*device)->element_id))
222 return FWK_E_PANIC;
223
224 return FWK_SUCCESS;
225 }
226
227 /*
228 * Reset Request Policy Handler
229 */
scmi_reset_domain_reset_request_policy(enum mod_scmi_reset_domain_policy_status * policy_status,enum mod_reset_domain_mode * mode,uint32_t * reset_state,uint32_t agent_id,uint32_t domain_id)230 FWK_WEAK int scmi_reset_domain_reset_request_policy(
231 enum mod_scmi_reset_domain_policy_status *policy_status,
232 enum mod_reset_domain_mode *mode,
233 uint32_t *reset_state,
234 uint32_t agent_id,
235 uint32_t domain_id)
236 {
237 *policy_status = MOD_SCMI_RESET_DOMAIN_EXECUTE_MESSAGE_HANDLER;
238
239 return FWK_SUCCESS;
240 }
241
242
reset_attributes_handler(fwk_id_t service_id,const uint32_t * payload)243 static int reset_attributes_handler(fwk_id_t service_id,
244 const uint32_t *payload)
245 {
246 const struct mod_scmi_reset_domain_device *reset_device = NULL;
247 struct mod_reset_domain_dev_config *reset_dev_config = NULL;
248 struct scmi_reset_domain_attributes_a2p params = { 0 };
249 struct scmi_reset_domain_attributes_p2a outmsg = {
250 .status = (int32_t)SCMI_GENERIC_ERROR,
251 };
252 size_t outmsg_size = sizeof(outmsg.status);
253 int status = FWK_SUCCESS;
254 int respond_status;
255
256 params = *(const struct scmi_reset_domain_attributes_a2p *)payload;
257
258 status = get_reset_device(service_id, params.domain_id, &reset_device);
259 if (status != FWK_SUCCESS) {
260 outmsg.status = (int32_t)SCMI_NOT_FOUND;
261 goto exit;
262 }
263
264 reset_dev_config = (struct mod_reset_domain_dev_config *)
265 fwk_module_get_data(reset_device->element_id);
266 /*
267 * Currently: no support for async reset.
268 */
269 outmsg.flags &= (uint32_t)~SCMI_RESET_DOMAIN_ATTR_ASYNC;
270
271 if (reset_dev_config->capabilities & MOD_RESET_DOMAIN_CAP_NOTIFICATION)
272 outmsg.flags |= (uint32_t)SCMI_RESET_DOMAIN_ATTR_NOTIF;
273
274 outmsg.latency = reset_dev_config->latency;
275
276 strncpy(
277 (char *)outmsg.name,
278 fwk_module_get_element_name(reset_device->element_id),
279 sizeof(outmsg.name) - 1);
280
281 outmsg.status = (int32_t)SCMI_SUCCESS;
282 outmsg_size = sizeof(outmsg);
283
284 exit:
285 respond_status =
286 scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size);
287
288 if (respond_status != FWK_SUCCESS) {
289 FWK_LOG_DEBUG("[SCMI-RESET] %s @%d", __func__, __LINE__);
290 }
291
292 return status;
293 }
294
reset_request_handler(fwk_id_t service_id,const uint32_t * payload)295 static int reset_request_handler(fwk_id_t service_id,
296 const uint32_t *payload)
297 {
298 int status, respond_status;
299 unsigned int agent_id;
300 struct mod_reset_domain_dev_config *reset_dev_config;
301 struct scmi_reset_domain_request_a2p params = { 0 };
302 struct scmi_reset_domain_request_p2a outmsg = {
303 .status = (int32_t)SCMI_NOT_FOUND
304 };
305 enum mod_reset_domain_mode mode = MOD_RESET_DOMAIN_MODE_EXPLICIT_DEASSERT;
306
307 size_t outmsg_size = sizeof(outmsg.status);
308 const struct mod_reset_domain_api *reset_api = scmi_rd_ctx.reset_api;
309 const struct mod_scmi_reset_domain_device *reset_device = NULL;
310 enum mod_scmi_reset_domain_policy_status policy_status;
311 uint32_t reset_state;
312
313 params = *(const struct scmi_reset_domain_request_a2p *)payload;
314
315 if ((params.flags & ~SCMI_RESET_DOMAIN_FLAGS_MASK) != 0) {
316 status = FWK_SUCCESS;
317 outmsg.status = (int32_t)SCMI_INVALID_PARAMETERS;
318 goto exit;
319 }
320
321 /**
322 * Verify that the reset state ID is 0 when the reset
323 * state type is Architectural.
324 */
325 if (((params.reset_state & SCMI_RESET_DOMAIN_RESET_STATE_TYPE_MASK) == 0) &&
326 ((params.reset_state & SCMI_RESET_DOMAIN_RESET_STATE_ID_MASK) != 0)) {
327 status = FWK_SUCCESS;
328 outmsg.status = (int32_t)SCMI_INVALID_PARAMETERS;
329 goto exit;
330 }
331
332 status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, &agent_id);
333 if (status != FWK_SUCCESS)
334 goto exit;
335
336 if (params.domain_id >= scmi_rd_ctx.plat_reset_domain_count) {
337 status = FWK_E_PARAM;
338 goto exit;
339 }
340
341 status = get_reset_device(service_id, params.domain_id, &reset_device);
342 if (status != FWK_SUCCESS)
343 goto exit;
344
345 reset_dev_config = (struct mod_reset_domain_dev_config *)
346 fwk_module_get_data(reset_device->element_id);
347
348 /* Check if explicit assert is requested.
349 * Note, valid request in flags
350 * b000 Explicit de-assert request.
351 * b001 Auto Reset request.
352 * b010 Explicit reset request.
353 * b101 Auto Reset Async.
354 */
355 if (!(params.flags & SCMI_RESET_DOMAIN_AUTO)) {
356 /* If auto reset is not requested then check if device supports explicit
357 * assert/de-assert reset.
358 */
359 if (!(reset_dev_config->modes &
360 (MOD_RESET_DOMAIN_MODE_EXPLICIT_ASSERT |
361 MOD_RESET_DOMAIN_MODE_EXPLICIT_DEASSERT))) {
362 outmsg.status = (int32_t)SCMI_NOT_SUPPORTED;
363 goto exit;
364 } else {
365 if (params.flags & SCMI_RESET_DOMAIN_EXPLICIT)
366 mode = MOD_RESET_DOMAIN_MODE_EXPLICIT_ASSERT;
367 }
368 } else {
369 mode = (enum mod_reset_domain_mode)SCMI_RESET_DOMAIN_AUTO;
370 }
371
372 /* Handle async reset request. */
373 if (params.flags & SCMI_RESET_DOMAIN_ASYNC) {
374 /* Async reset request is valid only in auto reset mode
375 */
376 if (!(params.flags & SCMI_RESET_DOMAIN_AUTO)) {
377 outmsg.status = (int32_t)SCMI_INVALID_PARAMETERS;
378 goto exit;
379 }
380
381 /* Return not supported as associated device does not support
382 * Async reset.
383 */
384 if (!(reset_dev_config->modes &
385 MOD_RESET_DOMAIN_MODE_AUTO_RESET_ASYNC)) {
386 outmsg.status = (int32_t)SCMI_NOT_SUPPORTED;
387 goto exit;
388 } else {
389 mode |= MOD_RESET_DOMAIN_MODE_AUTO_RESET_ASYNC;
390 }
391 }
392
393 reset_state = params.reset_state;
394 status = scmi_reset_domain_reset_request_policy(&policy_status,
395 &mode, &reset_state, agent_id, params.domain_id);
396
397 if (status != FWK_SUCCESS) {
398 outmsg.status = (int32_t)SCMI_GENERIC_ERROR;
399 goto exit;
400 }
401 if (policy_status == MOD_SCMI_RESET_DOMAIN_SKIP_MESSAGE_HANDLER) {
402 outmsg.status = (int32_t)SCMI_SUCCESS;
403 goto exit;
404 }
405
406 outmsg.status = (int32_t)SCMI_NOT_SUPPORTED;
407 status = reset_api->set_reset_state(reset_device->element_id,
408 mode,
409 reset_state,
410 (uintptr_t)agent_id);
411 if (status != FWK_SUCCESS) {
412 if (status == FWK_E_STATE)
413 outmsg.status = (int32_t)SCMI_HARDWARE_ERROR;
414 goto exit;
415 }
416
417 outmsg.status = (int32_t)SCMI_SUCCESS;
418 outmsg_size = sizeof(outmsg);
419
420 exit:
421 respond_status =
422 scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size);
423
424 if (respond_status != FWK_SUCCESS) {
425 FWK_LOG_DEBUG("[SCMI-RESET] %s @%d", __func__, __LINE__);
426 }
427
428 return status;
429 }
430
431 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
reset_notify_handler(fwk_id_t service_id,const uint32_t * payload)432 static int reset_notify_handler(fwk_id_t service_id,
433 const uint32_t *payload)
434 {
435 unsigned int agent_id;
436 int status, respond_status;
437 unsigned int domain_id;
438 const struct scmi_reset_domain_notify_a2p *parameters;
439 struct scmi_reset_domain_notify_p2a outmsg = {
440 .status = SCMI_GENERIC_ERROR,
441 };
442
443 status = get_agent_id(service_id, &agent_id);
444 if (status != FWK_SUCCESS)
445 goto exit;
446
447 parameters = (const struct scmi_reset_domain_notify_a2p *)payload;
448
449 domain_id = parameters->domain_id;
450 if (domain_id >= scmi_rd_ctx.config->
451 agent_table[agent_id].agent_domain_count) {
452 status = FWK_SUCCESS;
453 outmsg.status = SCMI_NOT_FOUND;
454 goto exit;
455 }
456
457 if ((parameters->notify_enable & ~SCMI_RESET_DOMAIN_DO_NOTIFY) != 0) {
458 status = FWK_SUCCESS;
459 outmsg.status = SCMI_INVALID_PARAMETERS;
460 goto exit;
461 }
462
463 if (parameters->notify_enable)
464 scmi_rd_ctx.scmi_notification_api->scmi_notification_add_subscriber(
465 MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN,
466 domain_id,
467 MOD_SCMI_RESET_NOTIFY,
468 service_id);
469 else
470 scmi_rd_ctx.scmi_notification_api->scmi_notification_remove_subscriber(
471 MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN,
472 agent_id,
473 domain_id,
474 MOD_SCMI_RESET_NOTIFY);
475
476 outmsg.status = SCMI_SUCCESS;
477
478 exit:
479 respond_status = scmi_rd_ctx.scmi_api->respond(
480 service_id,
481 &outmsg,
482 (outmsg.status == SCMI_SUCCESS) ? sizeof(outmsg) :
483 sizeof(outmsg.status));
484
485 if (respond_status != FWK_SUCCESS) {
486 FWK_LOG_DEBUG("[SCMI-RESET] %s @%d", __func__, __LINE__);
487 }
488
489 return status;
490 }
491
scmi_reset_issued_notify(uint32_t domain_id,uint32_t reset_state,uintptr_t cookie)492 static void scmi_reset_issued_notify(uint32_t domain_id,
493 uint32_t reset_state,
494 uintptr_t cookie)
495 {
496 struct scmi_reset_domain_issued_p2a reset_issued = {
497 .agent_id = (uint32_t)cookie
498 };
499
500 reset_issued.domain_id = domain_id;
501 reset_issued.reset_state = reset_state;
502
503 scmi_rd_ctx.scmi_notification_api->scmi_notification_notify(
504 MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN,
505 MOD_SCMI_RESET_NOTIFY,
506 MOD_SCMI_RESET_ISSUED,
507 &reset_issued,
508 sizeof(reset_issued));
509 }
510 #endif
511
512 /*
513 * SCMI Resource Permissions handler
514 */
515 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
get_reset_domain_id(const uint32_t * payload)516 static unsigned int get_reset_domain_id(const uint32_t *payload)
517 {
518 struct scmi_reset_domain_request_a2p *params;
519
520 params = (struct scmi_reset_domain_request_a2p *)payload;
521 return params->domain_id;
522 }
523
scmi_reset_domain_permissions_handler(fwk_id_t service_id,const uint32_t * payload,size_t payload_size,unsigned int message_id)524 static int scmi_reset_domain_permissions_handler(
525 fwk_id_t service_id,
526 const uint32_t *payload,
527 size_t payload_size,
528 unsigned int message_id)
529 {
530 enum mod_res_perms_permissions perms;
531 unsigned int agent_id, domain_id;
532 int status;
533
534 status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, &agent_id);
535 if (status != FWK_SUCCESS)
536 return FWK_E_ACCESS;
537
538 if (message_id < 3) {
539 perms = scmi_rd_ctx.res_perms_api->agent_has_protocol_permission(
540 agent_id, MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN);
541 if (perms == MOD_RES_PERMS_ACCESS_ALLOWED)
542 return FWK_SUCCESS;
543 return FWK_E_ACCESS;
544 }
545
546 domain_id = get_reset_domain_id(payload);
547
548 perms = scmi_rd_ctx.res_perms_api->agent_has_resource_permission(
549 agent_id, MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN, message_id, domain_id);
550
551 if (perms == MOD_RES_PERMS_ACCESS_ALLOWED)
552 return FWK_SUCCESS;
553 else
554 return FWK_E_ACCESS;
555 }
556 #endif
557
558 /*
559 * SCMI module -> SCMI reset module interface
560 */
scmi_reset_get_scmi_protocol_id(fwk_id_t protocol_id,uint8_t * scmi_protocol_id)561 static int scmi_reset_get_scmi_protocol_id(fwk_id_t protocol_id,
562 uint8_t *scmi_protocol_id)
563 {
564 *scmi_protocol_id = MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN;
565
566 return FWK_SUCCESS;
567 }
568
scmi_reset_message_handler(fwk_id_t protocol_id,fwk_id_t service_id,const uint32_t * payload,size_t payload_size,unsigned int message_id)569 static int scmi_reset_message_handler(fwk_id_t protocol_id,
570 fwk_id_t service_id,
571 const uint32_t *payload,
572 size_t payload_size,
573 unsigned int message_id)
574 {
575 int32_t return_value;
576
577 static_assert(FWK_ARRAY_SIZE(msg_handler_table) ==
578 FWK_ARRAY_SIZE(payload_size_table),
579 "[SCMI] reset domain protocol table sizes not consistent");
580
581 fwk_assert(payload != NULL);
582
583 if (message_id >= FWK_ARRAY_SIZE(msg_handler_table)) {
584 return_value = (int32_t)SCMI_NOT_FOUND;
585 goto error;
586 }
587
588 if (payload_size != payload_size_table[message_id]) {
589 return_value = (int32_t)SCMI_PROTOCOL_ERROR;
590 goto error;
591 }
592
593 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
594 if (scmi_reset_domain_permissions_handler(
595 service_id, payload, payload_size, message_id) != FWK_SUCCESS) {
596 return_value = SCMI_DENIED;
597 goto error;
598 }
599 #endif
600
601 return msg_handler_table[message_id](service_id, payload);
602
603 error:
604 return scmi_rd_ctx.scmi_api->respond(
605 service_id, &return_value, sizeof(return_value));
606 }
607
608 static struct mod_scmi_to_protocol_api scmi_reset_mod_scmi_to_protocol_api = {
609 .get_scmi_protocol_id = scmi_reset_get_scmi_protocol_id,
610 .message_handler = scmi_reset_message_handler
611 };
612
613 /*
614 * Framework handlers
615 */
616
scmi_reset_init(fwk_id_t module_id,unsigned int element_count,const void * data)617 static int scmi_reset_init(fwk_id_t module_id,
618 unsigned int element_count,
619 const void *data)
620 {
621 const struct mod_scmi_reset_domain_config *config;
622
623 config = (const struct mod_scmi_reset_domain_config *)data;
624
625 if ((config == NULL) || (config->agent_table == NULL))
626 return FWK_E_PARAM;
627
628 scmi_rd_ctx.config = config;
629
630 return FWK_SUCCESS;
631 }
632
633 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
scmi_reset_init_notifications(void)634 static int scmi_reset_init_notifications(void)
635 {
636 fwk_assert(scmi_rd_ctx.config->agent_count != 0u);
637
638 return scmi_rd_ctx.scmi_notification_api->scmi_notification_init(
639 MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN,
640 scmi_rd_ctx.config->agent_count,
641 scmi_rd_ctx.plat_reset_domain_count,
642 MOD_SCMI_RESET_DOMAIN_NOTIFICATION_COUNT);
643 }
644 #endif
645
scmi_reset_bind(fwk_id_t id,unsigned int round)646 static int scmi_reset_bind(fwk_id_t id, unsigned int round)
647 {
648 int status;
649 int rst_dom_count;
650
651 if (round == 1)
652 return FWK_SUCCESS;
653
654 status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_SCMI),
655 FWK_ID_API(FWK_MODULE_IDX_SCMI,
656 MOD_SCMI_API_IDX_PROTOCOL),
657 &scmi_rd_ctx.scmi_api);
658 if (status != FWK_SUCCESS)
659 return status;
660
661 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
662 status = fwk_module_bind(
663 FWK_ID_MODULE(FWK_MODULE_IDX_SCMI),
664 FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_NOTIFICATION),
665 &scmi_rd_ctx.scmi_notification_api);
666 if (status != FWK_SUCCESS)
667 return status;
668 #endif
669
670 rst_dom_count = fwk_module_get_element_count(
671 FWK_ID_MODULE(FWK_MODULE_IDX_RESET_DOMAIN));
672
673 if (rst_dom_count <= 0) {
674 return FWK_E_SUPPORT;
675 } else {
676 scmi_rd_ctx.plat_reset_domain_count = (uint8_t)rst_dom_count;
677 }
678
679 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
680 status = fwk_module_bind(
681 FWK_ID_MODULE(FWK_MODULE_IDX_RESOURCE_PERMS),
682 FWK_ID_API(FWK_MODULE_IDX_RESOURCE_PERMS, MOD_RES_PERM_RESOURCE_PERMS),
683 &scmi_rd_ctx.res_perms_api);
684 if (status != FWK_SUCCESS)
685 return status;
686 #endif
687
688 return fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_RESET_DOMAIN),
689 FWK_ID_API(FWK_MODULE_IDX_RESET_DOMAIN, 0),
690 &scmi_rd_ctx.reset_api);
691 }
692
scmi_reset_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)693 static int scmi_reset_process_bind_request(fwk_id_t source_id,
694 fwk_id_t target_id,
695 fwk_id_t api_id, const void **api)
696 {
697 switch ((enum scmi_reset_domain_api_idx)fwk_id_get_api_idx(api_id)) {
698 case MOD_SCMI_RESET_DOMAIN_PROTOCOL_API:
699 *api = &scmi_reset_mod_scmi_to_protocol_api;
700 break;
701
702 default:
703 return FWK_E_ACCESS;
704 }
705
706 return FWK_SUCCESS;
707 }
708
709 #if defined(BUILD_HAS_SCMI_NOTIFICATIONS) && defined(BUILD_HAS_NOTIFICATION)
scmi_reset_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)710 static int scmi_reset_process_notification(const struct fwk_event *event,
711 struct fwk_event *resp_event)
712 {
713 struct mod_reset_domain_notification_event_params* params =
714 (struct mod_reset_domain_notification_event_params*)event->params;
715
716 if (!fwk_id_is_equal(scmi_rd_ctx.notification_id,
717 event->id))
718 return FWK_E_SUPPORT;
719
720 scmi_reset_issued_notify(params->domain_id, params->reset_state,
721 params->cookie);
722
723 return FWK_SUCCESS;
724 }
725
scmi_reset_start(fwk_id_t id)726 static int scmi_reset_start(fwk_id_t id)
727 {
728 int status;
729 struct mod_reset_domain_config *config;
730 config = (struct mod_reset_domain_config*)fwk_module_get_data(
731 FWK_ID_MODULE(FWK_MODULE_IDX_RESET_DOMAIN)
732 );
733
734 scmi_rd_ctx.notification_id = config->notification_id;
735
736 status = scmi_reset_init_notifications();
737 if (status != FWK_SUCCESS)
738 return status;
739
740 return fwk_notification_subscribe(
741 scmi_rd_ctx.notification_id,
742 FWK_ID_MODULE(FWK_MODULE_IDX_RESET_DOMAIN),
743 id);
744 }
745 #endif
746
747 /* SCMI Reset Domain Management Protocol Definition */
748 const struct fwk_module module_scmi_reset_domain = {
749 .api_count = (unsigned int)MOD_SCMI_RESET_DOMAIN_API_COUNT,
750 .type = FWK_MODULE_TYPE_PROTOCOL,
751 .init = scmi_reset_init,
752 .bind = scmi_reset_bind,
753 .process_bind_request = scmi_reset_process_bind_request,
754 #if defined(BUILD_HAS_SCMI_NOTIFICATIONS) && defined(BUILD_HAS_NOTIFICATION)
755 .start = scmi_reset_start,
756 .process_notification = scmi_reset_process_notification,
757 #endif
758 };
759