1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *      System Control and Management Interface (SCMI) support.
9  */
10 
11 #ifndef MOD_SCMI_H
12 #define MOD_SCMI_H
13 
14 #include <internal/scmi.h>
15 #include <mod_scmi_std.h>
16 
17 #include <fwk_id.h>
18 #include <fwk_module_idx.h>
19 
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 
24 /*!
25  * \addtogroup GroupModules Modules
26  * \{
27  */
28 
29 /*!
30  * \defgroup GroupSCMI System Control & Management Interface (SCMI)
31  * \{
32  */
33 
34 /*!
35  * \brief Index of the interfaces exposed by the SCMI module.
36  */
37 enum mod_scmi_api_idx {
38     MOD_SCMI_API_IDX_PROTOCOL,
39     MOD_SCMI_API_IDX_PROTOCOL_REQ,
40     MOD_SCMI_API_IDX_TRANSPORT,
41 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
42     MOD_SCMI_API_IDX_NOTIFICATION,
43 #endif
44     MOD_SCMI_API_IDX_COUNT,
45 };
46 
47 /*!
48  * \brief Entity role.
49  */
50 enum mod_scmi_entity_role { MOD_SCMI_ROLE_PLATFORM, MOD_SCMI_ROLE_AGENT };
51 
52 /*!
53  * \brief Agent descriptor
54  */
55 struct mod_scmi_agent {
56     /*! \brief Type of the agent. */
57     enum scmi_agent_type type;
58 
59     /*!
60      *  \brief Pointer to the agent's name. This pointer may be equal to NULL.
61      *       In that case, the agent will be assigned a default name based on
62      *       its type: "PSCI", "MANAGEMENT", "OSPM", or "OTHER".
63      *
64      *  \details The agent name of the BASE_DISCOVER_AGENT command can be at
65      *       most 16 bytes in length (null terminator included). If the value
66      *       assigned to this variable is longer than the limit then the agents
67      *       in the system will be provided with a truncated version of it.
68      */
69     const char *name;
70 };
71 
72 /*!
73  * \brief SCMI module configuration data.
74  */
75 struct mod_scmi_config {
76     /*!
77      *  \brief Maximum number of SCMI protocol modules that can bind to the
78      *       SCMI module.
79      */
80     unsigned int protocol_count_max;
81 
82     /*!
83      *  \brief Maximum number of SCMI protocol requester modules that can
84      *       bind to the SCMI module.
85      */
86     unsigned int protocol_requester_count_max;
87 
88 #ifndef BUILD_HAS_MOD_RESOURCE_PERMS
89     /*!
90      *  \brief Number of the disabled SCMI protocols for the PSCI agent.
91      *         If set to zero then all protocols are allowed for a PSCI agent.
92      */
93     unsigned int dis_protocol_count_psci;
94 
95     /*!
96      *  \brief list protocols disabled for the PSCI agent , limited
97      *       by protocol_count_psci
98      */
99     const uint32_t *dis_protocol_list_psci;
100 #endif
101 
102     /*!
103      *  \brief Number of agents in the system. Must be smaller than or equal to
104      *       SCMI_AGENT_ID_MAX.
105      */
106     unsigned int agent_count;
107 
108     /*!
109      *  \brief Table of descriptors of the agents in the system.
110      *
111      *  \details Entry 'i' in the table contains the descriptor of the agent
112      *       with identifier 'i'. The agent identifiers are sequential and start
113      *       from one, with the identifier 0 being reserved to identify the
114      *       platform. The table must therefore have space for 'agent_count + 1'
115      *       entries. The first entry is ignored.
116      */
117     const struct mod_scmi_agent *agent_table;
118 
119     /*!
120      *  \brief Pointer to the vendor identifier.
121      *
122      *  \note The vendor identifier in the BASE_DISCOVER_VENDOR command is
123      *       up to 16 bytes in length (null terminator included). The vendor
124      *       identifier provided to agents will be truncated if it exceeds
125      *       this limit.
126      */
127     const char *vendor_identifier;
128 
129     /*!
130      *  \brief Pointer to the sub-vendor identifier.
131      *
132      *  \note The sub-vendor identifier in the BASE_DISCOVER_SUB_VENDOR
133      *       command is up to 16 bytes in length (null terminator included).
134      *       The sub-vendor identifier provided to agents will be truncated
135      *       if it exceeds this limit.
136      */
137     const char *sub_vendor_identifier;
138 };
139 
140 /*!
141  * \brief Service configuration data.
142  */
143 struct mod_scmi_service_config {
144     /*!
145      * \brief Identifier of the transport entity.
146      */
147     fwk_id_t transport_id;
148 
149     /*!
150      * \brief Identifier of the API of the transport entity.
151      */
152     fwk_id_t transport_api_id;
153 
154     /*!
155      * \brief Identifier of the notification indicating the transport has been
156      *      initialized.
157      */
158     fwk_id_t transport_notification_init_id;
159 
160     /*!
161      *  \brief Identifier of the agent.
162      *
163      *  \details An SCMI channel is the communication channel between an agent
164      *        and the platform. This is the identifier assigned in the system
165      *        to the agent using the transport channel identified by
166      *        'scmi_channel_id'. The agent identifier must be greater than or
167      *        equal to one (the identifier 0 is assigned to the platform) and
168      *        lower than or equal to the number of agents declared in SCMI
169      *        module configuration data.
170      */
171     unsigned int scmi_agent_id;
172 
173     /*!
174      *  \brief Identifier of SCMI P2A service asssociated with this A2P service.
175      *
176      *  \details If a request for notifications is received on this service
177      *        channel the notifications will be sent on the channel identified
178      *        here.
179      */
180     fwk_id_t scmi_p2a_id;
181 
182     /*!
183      * \brief Entity role.
184      *
185      * \details Determine if this entity is an agent or a platform.
186      */
187     enum mod_scmi_entity_role scmi_entity_role;
188 };
189 
190 /*!
191  * \brief SCMI module to transport entity API.
192  */
193 struct mod_scmi_to_transport_api {
194     /*!
195      * \brief Check whether a channel is secure or non-secure.
196      *
197      * \param channel_id Channel identifier.
198      * \param[out] secure Channel security state. True if the channel
199      *      is secure, or false if it is non-secure.
200      *
201      * \retval ::FWK_SUCCESS The operation succeeded.
202      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
203      *      - The `channel_id` parameter was not a valid system entity
204      *        identifier.
205      *      - The `secure` parameter was a null pointer value.
206      * \return One of the standard error codes for implementation-defined
207      *      errors.
208      */
209     int (*get_secure)(fwk_id_t channel_id, bool *secure);
210 
211     /*!
212      * \brief Get the maximum permitted payload size of a channel.
213      *
214      * \param channel_id Channel identifier.
215      * \param[out] size Maximum payload size in bytes.
216      *
217      * \retval ::FWK_SUCCESS The operation succeeded.
218      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
219      *      - The `channel_id` parameter was not a valid system entity
220      *        identifier.
221      *      - The `size` parameter was a null pointer value.
222      * \return One of the standard error codes for implementation-defined
223      *      errors.
224      */
225     int (*get_max_payload_size)(fwk_id_t channel_id, size_t *size);
226 
227     /*!
228      * \brief Get the SCMI message header from a channel.
229      *
230      * \param channel_id Channel identifier.
231      * \param[out] message_header SCMI message header.
232      *
233      * \retval ::FWK_SUCCESS The operation succeeded.
234      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
235      *      - The `channel_id` parameter was not a valid system entity
236      *        identifier.
237      *      - The `message_header` parameter was a null pointer value.
238      * \retval ::FWK_E_ACCESS No message is available to read.
239      * \return One of the standard error codes for implementation-defined
240      *      errors.
241      */
242     int (*get_message_header)(fwk_id_t channel_id, uint32_t *message_header);
243 
244     /*!
245      * \brief Get the SCMI payload from a channel.
246      *
247      * \param channel_id Channel identifier.
248      * \param[out] payload Pointer to the payload.
249      * \param[out] size Payload size. May be NULL, in which case the
250      *      parameter should be ignored.
251      *
252      * \retval ::FWK_SUCCESS The operation succeeded.
253      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
254      *      - The `channel_id` parameter was not a valid system entity
255      *        identifier.
256      *      - The `payload` parameter was a null pointer value.
257      *      - The `size` parameter was a null pointer value.
258      * \retval ::FWK_E_ACCESS No message is available to read.
259      * \return One of the standard error codes for implementation-defined
260      *      errors.
261      */
262     int (*get_payload)(fwk_id_t channel_id, const void **payload,
263                        size_t *size);
264 
265     /*!
266      * \brief Write part of a payload to a channel.
267      *
268      * \param channel_id Channel identifier.
269      * \param offset Offset to begin writing at.
270      * \param payload Payload data to write.
271      * \param size Size of the payload data.
272      *
273      * \retval ::FWK_SUCCESS The operation succeeded.
274      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
275      *      - The `channel_id` parameter was not a valid system entity
276      *        identifier.
277      *      - The `payload` parameter was a null pointer value.
278      *      - The offset and size provided are not within the bounds of the
279      *        payload area.
280      * \return One of the standard error codes for implementation-defined
281      *      errors.
282      */
283     int (*write_payload)(fwk_id_t channel_id, size_t offset,
284                          const void *payload, size_t size);
285 
286     /*!
287      * \brief Respond to an SCMI message on a channel.
288      *
289      * \param channel_id Channel identifier.
290      * \param payload Payload data to write, or NULL if a payload has already
291      *      been written.
292      * \param size Size of the payload source.
293      *
294      * \retval ::FWK_SUCCESS The operation succeeded.
295      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
296      *      - The `channel_id` parameter was not a valid system entity
297      *        identifier.
298      *      - The size given is less than the size of one paylout entry.
299      * \retval ::FWK_E_ACCESS No message is available to respond to.
300      * \return One of the standard error codes for implementation-defined
301      *      errors.
302      */
303     int (*respond)(fwk_id_t channel_id, const void *payload, size_t size);
304 
305     /*!
306      * \brief Send a message on a channel.
307      *
308      * \param channel_id Channel identifier.
309      * \param message_header Message ID.
310      * \param payload Payload data to write.
311      * \param size Size of the payload source.
312      * \param request_ack_by_interrupt flag to select whether acknowledgement
313      * interrupt is required for this message.
314      *
315      * \retval ::FWK_SUCCESS The operation succeeded.
316      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
317      *      - The `channel_id` parameter was not a valid system entity
318      *        identifier.
319      *      - The size given is less than the size of one paylout entry.
320      * \return One of the standard error codes for implementation-defined
321      *      errors.
322      */
323     int (*transmit)(
324         fwk_id_t channel_id,
325         uint32_t message_header,
326         const void *payload,
327         size_t size,
328         bool request_ack_by_interrupt);
329 
330     /*!
331      * \brief Release the transport channel context lock.
332      *
333      * \param channel_id Transport channel identifier.
334      *
335      * \retval ::FWK_SUCCESS The operation succeeded.
336      */
337     int (*release_transport_channel_lock)(fwk_id_t channel_id);
338 };
339 
340 /*!
341  * \brief Transport entity API to SCMI module API.
342  */
343 struct mod_scmi_from_transport_api {
344     /*!
345      * \brief Signal to a SCMI service that a incoming message for it has
346      *      incorrect length and payload size and so the incoming message has
347      *      been dropped.
348      *
349      * \note Subscribed SCMI service should call the respond API to free the
350      *       channel.
351      *
352      * \param service_id service identifier.
353      *
354      * \retval ::FWK_SUCCESS The operation succeeded.
355      * \retval ::FWK_E_PARAM The service_id parameter is invalid.
356      * \return One of the standard error codes for implementation-defined
357      *      errors.
358      */
359     int (*signal_error)(fwk_id_t service_id);
360 
361     /*!
362      * \brief Signal to a service that a message is incoming.
363      *
364      * \param service_id SCMI service identifier.
365      *
366      * \retval ::FWK_SUCCESS The operation succeeded.
367      * \retval ::FWK_E_PARAM The `service_id` parameter was not a valid system
368      *      entity identifier.
369      * \return One of the standard error codes for implementation-defined
370      *      errors.
371      */
372     int (*signal_message)(fwk_id_t service_id);
373 };
374 
375 /*!
376  * \brief SCMI protocol message handler prototype.
377  *
378  * \details Prototype of a message handler called by the SCMI module when it
379  *      receives a message for a SCMI protocol module.
380  *
381  * \note A return value of FWK_SUCCESS indicates only that no internal error
382  *      was encountered, not that the SCMI command has returned a successful
383  *      result to the SCMI agent. In the case where the return value indicates
384  *      an internal failure, the SCMI command is expected to return the status
385  *      code SCMI_GENERIC_ERROR per the specification.
386  *
387  * \param protocol_id Identifier of the protocol module.
388  * \param service_id Identifer of the SCMI service which received the message.
389  * \param payload Pointer to the message payload.
390  * \param payload_size Size in number of bytes of the message payload.
391  * \param message_id Identifier of the message to be handled by the protocol
392  *      handler.
393  *
394  * \retval ::FWK_SUCCESS The operation succeeded.
395  * \return One of the standard error codes for implementation-defined errors.
396  *
397  */
398 typedef int mod_scmi_message_handler_t(fwk_id_t protocol_id,
399     fwk_id_t service_id, const uint32_t *payload, size_t payload_size,
400     unsigned int message_id);
401 
402 /*!
403  * \brief SCMI module to SCMI protocol module API.
404  */
405 struct mod_scmi_to_protocol_api {
406     /*!
407      * \brief Get the SCMI protocol identifier of the SCMI protocol implemented
408      *      by the SCMI protocol module implementing this API.
409      *
410      * \param protocol_id Identifier of the protocol module.
411      * \param scmi_protocol_id SCMI protocol identifier.
412      *
413      * \retval ::FWK_SUCCESS The operation succeeded.
414      * \return One of the standard error codes for implementation-defined
415      *      errors.
416      *
417      */
418     int (*get_scmi_protocol_id)(fwk_id_t protocol_id,
419                                 uint8_t *scmi_protocol_id);
420 
421     /*! Protocol message handler. */
422     mod_scmi_message_handler_t *message_handler;
423 };
424 
425 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
426 /*!
427  * \brief SCMI protocol SCMI module SCMI notification API.
428  */
429 struct mod_scmi_notification_api {
430     /*!
431      * \brief Initialize notification context for a protocol.
432      *
433      * \param protocol_id Identifier of the protocol.
434      * \param agent_count Number of agents supported by the protocol.
435      * \param element_count Number of elements that support notification.
436      * \param operation_count Number of notification SCMI messages supported.
437      *
438      * \retval ::FWK_SUCCESS Initialization successful.
439      * \retval One of the standard error codes for implementation-defined
440      *      errors.
441      */
442     int (*scmi_notification_init)(
443         unsigned int protocol_id,
444         unsigned int agent_count,
445         unsigned int element_count,
446         unsigned int operation_count);
447 
448     /*!
449      * \brief Add an agent to subscriber list that requested a notification.
450      *
451      * \param protocol_id Identifier of the protocol.
452      * \param element_idx Index of the element within specified protocol
453      *     context.
454      * \param operation_id Identifier of the operation.
455      * \param service_id  Identifier of the agent's SCMI service context.
456      *
457      * \retval ::FWK_SUCCESS Adding of subscriber agent to the list is
458      *      successful.
459      * \retval One of the standard error codes for implementation-defined
460      *      errors.
461      */
462     int (*scmi_notification_add_subscriber)(
463         unsigned int protocol_id,
464         unsigned int element_idx,
465         unsigned int operation_id,
466         fwk_id_t service_id);
467 
468     /*!
469      * \brief Remove an agent from subscriber list.
470      *
471      * \param protocol_id Identifier of the protocol.
472      * \param agent_idx Index of the agent within specified protocol context.
473      * \param element_idx Index of the element within specified protocol
474      *     context.
475      * \param operation_id Identifier of the operation.
476      *
477      * \retval ::FWK_SUCCESS Removing of subscriber agent from the list is
478      *     successful.
479      * \retval One of the standard error codes for implementation-defined
480      *      errors.
481      */
482     int (*scmi_notification_remove_subscriber)(
483         unsigned int protocol_id,
484         unsigned int agent_idx,
485         unsigned int element_idx,
486         unsigned int operation_id);
487 
488     /*!
489      * \brief Notifiy all agents which requested a specific notification.
490      *
491      * \param protocol_id Identifier of the protocol.
492      * \param operation_id Identifier of the operation.
493      * \param scmi_response_message_id SCMI message identifier that is sent as
494      *     as a part of the notification.
495      * \param payload_p2a Notification message payload from platform to
496      *     agent.
497      * \param payload_size Size of the message.
498      *
499      * \retval ::FWK_SUCCESS Notification to agents is successful.
500      * \retval One of the standard error codes for implementation-defined
501      *      errors.
502      */
503     int (*scmi_notification_notify)(
504         unsigned int protocol_id,
505         unsigned int operation_id,
506         unsigned int scmi_response_message_id,
507         void *payload_p2a,
508         size_t payload_size);
509 };
510 #endif
511 
512 /*!
513  * \brief SCMI protocol module to SCMI module API.
514  */
515 struct mod_scmi_from_protocol_api {
516     /*!
517      * \brief Get the number of active agents.
518      *
519      * \param[out] agent_count Number of active agents.
520      *
521      * \retval ::FWK_SUCCESS The agent count was returned.
522      * \retval ::FWK_E_PARAM The parameter `agent_count` is equal to `NULL`.
523      */
524     int (*get_agent_count)(unsigned int *agent_count);
525 
526     /*!
527      * \brief Get the identifier of the agent associated with a service
528      *
529      * \param service_id Identifier of the service.
530      * \param[out] agent_id Agent identifier.
531      *
532      * \retval ::FWK_SUCCESS The agent identifier was returned.
533      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
534      *      - The `service_id` parameter was not a valid system entity
535      *        identifier.
536      *      - The `agent_id` parameter was a null pointer value.
537      * \retval ::FWK_E_INIT The service is not initialized.
538      * \retval ::FWK_E_STATE The service is in an invalid state.
539      */
540     int (*get_agent_id)(fwk_id_t service_id, unsigned int *agent_id);
541 
542     /*!
543      * \brief Get the type of the agent given its identifier.
544      *
545      * \details This API can be used by SCMI protocols to check the validity
546      *          of an agent identifier.
547      *
548      * \param agent_id Identifier of the agent.
549      * \param[out] agent_type Agent type.
550      *
551      * \retval ::FWK_SUCCESS The agent identifier was returned.
552      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
553      *      - The `agent_id` parameter was not a valid system entity
554      *        identifier.
555      *      - The `agent_type` parameter was a null pointer value.
556      */
557     int (*get_agent_type)(uint32_t agent_id, enum scmi_agent_type *agent_type);
558 
559     /*!
560      * \brief Get the maximum permitted payload size of a channel associated
561      *        with a service.
562      *
563      * \param service_id Service identifier.
564      * \param[out] size Maximum payload size in bytes.
565      *
566      * \retval ::FWK_SUCCESS The operation succeeded.
567      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
568      *      - The `service_id` parameter was not a valid system entity
569      *        identifier.
570      *      - The `size` parameter was a null pointer value.
571      * \retval ::FWK_E_INIT The service is not initialized.
572      * \retval ::FWK_E_STATE The service is in an invalid sate.
573      * \return One of the standard error codes for implementation-defined
574      *      errors.
575      */
576     int (*get_max_payload_size)(fwk_id_t service_id, size_t *size);
577 
578     /*!
579      * \brief Write part of a payload through a service.
580      *
581      * \param service_id Service identifier.
582      * \param offset Offset to begin writing at.
583      * \param payload Payload data to write.
584      * \param size Size of the payload data.
585      *
586      * \retval ::FWK_SUCCESS The operation succeeded.
587      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
588      *      - The `service_id` parameter was not a valid system entity
589      *        identifier.
590      *      - The offset and size given were not within the bounds of the
591      *        payload area.
592      * \return One of the standard error codes for implementation-defined
593      *      errors.
594      */
595     int (*write_payload)(fwk_id_t service_id, size_t offset,
596                          const void *payload, size_t size);
597 
598     /*!
599      * \brief Respond to an SCMI message on a service.
600      *
601      * \param service_id Service identifier.
602      * \param payload Payload data to write, or NULL if a payload has already
603      *      been written.
604      * \param size Size of the payload.
605      *
606      * \retval ::FWK_SUCCESS The operation succeeded.
607      * \retval ::FWK_E_SUPPORT Transport-specific message not supported.
608      * \return One of the standard error codes for implementation-defined
609      *      errors.
610      */
611     int (*respond)(fwk_id_t service_id, const void *payload, size_t size);
612 
613     /*!
614      * \brief Send a notification to the agent on behalf on an SCMI service.
615      *
616      * \param service_id Service identifier.
617      * \param protocol_id Protocol identifier.
618      * \param message_id Message identifier.
619      * \param payload Payload data to write, or NULL if a payload has already
620      *         been written.
621      * \param size Size of the payload in bytes.
622      */
623     void (*notify)(fwk_id_t service_id, int protocol_id, int message_id,
624         const void *payload, size_t size);
625 };
626 
627 /*!
628  * \brief SCMI protocol requester module to SCMI module API.
629  */
630 struct mod_scmi_from_protocol_req_api {
631     /*!
632      * \brief Send an SCMI message
633      *
634      * \param scmi_message_id SCMI message identifier.
635      * \param scmi_protocol_id SCMI message protocol identifier.
636      * \param token SCMI message token.
637      * \param service_id SCMI service identifier.
638      * \param payload Payload data to write
639      * \param payload_size size of the payload in bytes.
640      * \param request_ack_by_interrupt flag to select whether acknowledgement
641      * interrupt is required for this message.
642      */
643     int (*scmi_send_message)(
644         uint8_t scmi_message_id,
645         uint8_t scmi_protocol_id,
646         uint8_t token,
647         fwk_id_t service_id,
648         const void *payload,
649         size_t payload_size,
650         bool request_ack_by_interrupt);
651 
652     /*!
653      * \brief Handle response SCMI message
654      *
655      * \param service_id Service identifier.
656      *
657      * \retval ::FWK_SUCCESS The operation succeeded.
658      */
659     int (*response_message_handler)(fwk_id_t service_id);
660 };
661 
662 /*!
663  * \brief SCMI notification indices.
664  */
665 enum mod_scmi_notification_idx {
666     /*! The SCMI service has been initialized */
667     MOD_SCMI_NOTIFICATION_IDX_INITIALIZED,
668 
669     /*! Number of defined notifications */
670     MOD_SCMI_NOTIFICATION_IDX_COUNT
671 };
672 
673 /*!
674  * \brief Identifier for the MOD_SCMI_NOTIFICATION_IDX_INITIALIZED
675  *     notification.
676  */
677 static const fwk_id_t mod_scmi_notification_id_initialized =
678     FWK_ID_NOTIFICATION_INIT(
679         FWK_MODULE_IDX_SCMI,
680         MOD_SCMI_NOTIFICATION_IDX_INITIALIZED);
681 
682 /*!
683  * \}
684  */
685 
686 /*!
687  * \}
688  */
689 
690 #endif /* MOD_SCMI_H */
691