1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #ifndef MOD_CLOCK_H
9 #define MOD_CLOCK_H
10 
11 #include <fwk_element.h>
12 #include <fwk_id.h>
13 #include <fwk_module_idx.h>
14 
15 #include <stdint.h>
16 
17 /*!
18  * \addtogroup GroupModules Modules
19  * \{
20  */
21 
22 /*!
23  * \defgroup GroupClock Clock HAL
24  *
25  * \details A Hardware Abstraction Layer for configuring clock devices.
26  *
27  * \{
28  */
29 
30 /*!
31  * \brief Clock states.
32  */
33 enum mod_clock_state {
34     /*! The clock is stopped */
35     MOD_CLOCK_STATE_STOPPED = 0,
36 
37     /*! The clock is running */
38     MOD_CLOCK_STATE_RUNNING,
39 
40     /*! Number of defined clock states */
41     MOD_CLOCK_STATE_COUNT
42 };
43 
44 /*!
45  * \brief Clock notification indices.
46  */
47 enum mod_clock_notification_idx {
48      /*! The running state of a clock changed */
49     MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGED,
50 
51      /*! The running state of a clock is about to change */
52     MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING,
53 
54     /*! Number of defined notifications */
55     MOD_CLOCK_NOTIFICATION_IDX_COUNT
56 };
57 
58 #ifdef BUILD_HAS_MOD_CLOCK
59 /*!
60  * \brief Identifier for the ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGED
61  *     notification.
62  */
63 static const fwk_id_t mod_clock_notification_id_state_changed =
64     FWK_ID_NOTIFICATION_INIT(
65         FWK_MODULE_IDX_CLOCK,
66         MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGED);
67 
68 /*!
69  * \brief Identifier for the ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING
70  * notification
71  */
72 static const fwk_id_t mod_clock_notification_id_state_change_pending =
73     FWK_ID_NOTIFICATION_INIT(
74         FWK_MODULE_IDX_CLOCK,
75         MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING);
76 #endif
77 
78 /*!
79  * \brief Event parameters shared by the
80  *     ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGED and
81  *     ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING notifications.
82  */
83 struct clock_notification_params {
84     /*!
85      * The state that the clock has transitioned to, or is about
86      * to transition to.
87      */
88     enum mod_clock_state new_state;
89 };
90 
91 /*!
92  * \brief Response parameters for the
93  *     ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING notification.
94  */
95 struct clock_state_change_pending_resp_params {
96     /*!
97      * The status returned by the notified subscriber on processing the
98      * ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING notification.
99      */
100     int status;
101 };
102 
103 /*!
104  * \brief APIs that the module makes available to entities requesting binding.
105  */
106 enum mod_clock_api_type {
107     /*! Clock HAL */
108     MOD_CLOCK_API_TYPE_HAL,
109 
110     /*! Clock driver response */
111     MOD_CLOCK_API_TYPE_DRIVER_RESPONSE,
112 
113     /*! Number of defined APIs */
114     MOD_CLOCK_API_COUNT,
115 };
116 
117 /*!
118  * \brief Clock rate types.
119  */
120 enum mod_clock_rate_type {
121     /*! The clock has a discrete set of rates that it can attain */
122     MOD_CLOCK_RATE_TYPE_DISCRETE,
123 
124     /*! The clock has a continuous range of rates with a constant step */
125     MOD_CLOCK_RATE_TYPE_CONTINUOUS,
126 };
127 
128 /*!
129  * \brief Clock rounding modes.
130  */
131 enum mod_clock_round_mode {
132     /*!
133      * Do not perform any rounding. Any rate that is not precise and attainable
134      * will be rejected.
135      */
136     MOD_CLOCK_ROUND_MODE_NONE,
137 
138     /*! Round to the closest attainable rate, whether higher or lower */
139     MOD_CLOCK_ROUND_MODE_NEAREST,
140 
141     /*! Round to the closest attainable higher rate */
142     MOD_CLOCK_ROUND_MODE_UP,
143 
144     /*! Round to the closest attainable lower rate */
145     MOD_CLOCK_ROUND_MODE_DOWN,
146 };
147 
148 /*!
149  * \brief Clock module configuration data.
150  */
151 struct mod_clock_config {
152     /*!
153      * \brief Identifier of a notification to subscribe clock devices to in
154      *     order to receive notifications of power domain transitions that have
155      *     already occurred.
156      *
157      * \note May be ::FWK_ID_NONE to disable this functionality for all
158      *     elements.
159      */
160     const fwk_id_t pd_transition_notification_id;
161 
162     /*!
163      * \brief Identifier of a notification to subscribe clock devices to in
164      *     order to receive notifications of power domain transitions that are
165      *     about to occur.
166      *
167      * \note May be ::FWK_ID_NONE to disable this functionality for all
168      *     elements.
169      */
170     const fwk_id_t pd_pre_transition_notification_id;
171 };
172 
173 /*!
174  * \brief Clock element configuration data.
175  */
176 struct mod_clock_dev_config {
177     /*! Reference to the device element within the associated driver module */
178     const fwk_id_t driver_id;
179 
180     /*! Reference to the API provided by the device driver module */
181     const fwk_id_t api_id;
182 
183     /*!
184      * \brief Reference to the element or module that is the source of the
185      *     power domain notification.
186      *
187      * \details If the clock belongs to the always-on (AON) power domain (i.e.
188      *     it is always running), or if there are no actions to be performed
189      *     when the clock's power domain changes state, then this identifier
190      *     must be FWK_ID_NONE. In this case the clock will not be registered
191      *     to receive notifications from the power domain module.
192      */
193     fwk_id_t pd_source_id;
194 
195     /*!
196      * \brief Assigned clock parent optional identifier.
197      *
198      * \details If the clock parent is not defined, it will not be connected
199      *      to the tree of clocks and it will be left as a single node.
200      */
201     fwk_optional_id_t parent_id;
202 
203     /*!
204      * Flag to allow clock to be set to initial rate during initialization.
205      */
206     bool default_on;
207 };
208 
209 /*!
210  * \brief Range of supported rates for a clock.
211  */
212 struct mod_clock_range {
213     /*! The type of rates the clock provides (discrete or continuous) */
214     enum mod_clock_rate_type rate_type;
215 
216     /*! Minimum rate (in Hz) */
217     uint64_t min;
218 
219     /*! Maximum rate (in Hz) */
220     uint64_t max;
221 
222     /*!
223      * \brief Number of Hertz by which the rate can be incremented at each step
224      *      throughout the clock's range.
225      *
226      * \warning Valid only when rate_type is equal to
227      *      ::MOD_CLOCK_RATE_TYPE_CONTINUOUS, as clocks that use
228      *      ::MOD_CLOCK_RATE_TYPE_DISCRETE may not have a regular step between
229      *      their rates.
230      */
231     uint64_t step;
232 
233     /*! The number of unique rates that the clock can attain */
234     uint64_t rate_count;
235 };
236 
237 /*!
238  * \brief Clock properties exposed via the get_info() API function.
239  *
240  * \details This structure is intended to store clock information that is static
241  *     and which does not change during runtime. Dynamic information, such as
242  *     the current clock state, are exposed through functions in the clock and
243  *     clock driver APIs.
244  */
245 struct mod_clock_info {
246     /*! Human-friendly clock name */
247     const char *name;
248 
249     /*! Range of supported clock rates */
250     struct mod_clock_range range;
251 
252     /*! Number of discrete rates supported */
253     uint64_t rate_count;
254 };
255 
256 /*!
257  * \brief Clock driver interface.
258  */
259 struct mod_clock_drv_api {
260     /*! Name of the driver */
261     const char *name;
262 
263     /*!
264      * \brief Set a new clock rate by providing a frequency in Hertz (Hz).
265      *
266      * \param clock_id Clock device identifier.
267      *
268      * \param rate The desired frequency in Hertz.
269      *
270      * \param round_mode The type of rounding to perform, if required, to
271      *      achieve the given rate.
272      *
273      * \retval ::FWK_PENDING The request is pending. The driver will provide the
274      *      requested value later through the driver response API.
275      * \retval ::FWK_SUCCESS The operation succeeded.
276      * \return One of the standard framework error codes.
277      */
278     int (*set_rate)(fwk_id_t clock_id, uint64_t rate,
279                     enum mod_clock_round_mode round_mode);
280 
281     /*!
282      * \brief Get the current rate of a clock in Hertz (Hz).
283      *
284      * \param clock_id Clock device identifier.
285      *
286      * \param[out] rate The current clock rate in Hertz.
287      *
288      * \retval ::FWK_PENDING The request is pending. The driver will provide the
289      *      requested value later through the driver response API.
290      * \retval ::FWK_SUCCESS The operation succeeded.
291      * \return One of the standard framework error codes.
292      */
293     int (*get_rate)(fwk_id_t clock_id, uint64_t *rate);
294 
295     /*!
296      * \brief Get a clock rate in Hertz from an index into the clock's range.
297      *
298      * \param clock_id Clock device identifier.
299      *
300      * \param rate_index The index into the clock's range to get the rate of.
301      *
302      * \param[out] rate The rate, in Hertz, corresponding to the index.
303      *
304      * \retval ::FWK_SUCCESS The operation succeeded.
305      * \return One of the standard framework error codes.
306      */
307     int (*get_rate_from_index)(fwk_id_t clock_id, unsigned int rate_index,
308                                uint64_t *rate);
309 
310     /*!
311      * \brief Set the running state of a clock.
312      *
313      * \param clock_id Clock device identifier.
314      *
315      * \param state One of the valid clock states.
316      *
317      * \retval ::FWK_PENDING The request is pending. The driver will provide the
318      *      requested value later through the driver response API.
319      * \retval ::FWK_SUCCESS The operation succeeded.
320      * \return One of the standard framework error codes.
321      */
322     int (*set_state)(fwk_id_t clock_id, enum mod_clock_state state);
323 
324     /*!
325      * \brief Get the running state of a clock.
326      *
327      * \param clock_id Clock device identifier.
328      *
329      * \param[out] state The current clock state.
330      *
331      * \retval ::FWK_PENDING The request is pending. The driver will provide the
332      *      requested value later through the driver response API.
333      * \retval ::FWK_SUCCESS The operation succeeded.
334      * \return One of the standard framework error codes.
335      */
336     int (*get_state)(fwk_id_t clock_id, enum mod_clock_state *state);
337 
338     /*!
339      * \brief Get the range of rates that the clock supports.
340      *
341      * \param clock_id Clock device identifier.
342      *
343      * \param[out] range The clock range structure.
344      *
345      * \retval ::FWK_SUCCESS The operation succeeded.
346      * \return One of the standard framework error codes.
347      */
348     int (*get_range)(fwk_id_t clock_id, struct mod_clock_range *range);
349 
350     /*!
351      * \brief Handle the condition where the state of a clock's power domain is
352      *     about to change.
353      *
354      * \details This function will be called prior to the change in power
355      *     state occurring so that the clock driver implementing this API is
356      *     able to perform any required preparatory work beforehand.
357      *
358      * \note This function is optional. If the driver does not control any
359      *     clocks that require power state awareness then the pointer may be set
360      *     to NULL.
361      *
362      * \param clock_id Clock device identifier.
363      *
364      * \param current_state The current power state that the clock's power
365      *     domain will transition away from.
366      *
367      * \param new_state The power state that the clock's power domain will
368      *     transition to.
369      *
370      * \retval ::FWK_SUCCESS The operation succeeded.
371      * \return One of the standard framework error codes.
372      */
373     int (*process_pending_power_transition)(
374         fwk_id_t clock_id,
375         unsigned int current_state,
376         unsigned int new_state);
377 
378     /*!
379      * \brief Handle the condition where the state of a clock's power domain
380      *     has changed.
381      *
382      * \details This function will be called after the change in power state
383      *     has occurred. The driver can take any appropriate actions that are
384      *     required to accommodate the new state. The transition can be to a
385      *     deeper power state (e.g. ON->OFF) or to a shallower power state
386      *     (e.g. OFF->ON).
387      *
388      * \note This function is optional. If the driver does not control any
389      *     clocks that require power state awareness then the pointer may be set
390      *     to NULL.
391      *
392      * \param clock_id Clock device identifier.
393      *
394      * \param state The power state that the clock's power domain transitioned
395      *     to.
396      *
397      * \retval ::FWK_SUCCESS The operation succeeded.
398      * \return One of the standard framework error codes.
399      */
400     int (*process_power_transition)(fwk_id_t clock_id, unsigned int state);
401 
402     /*!
403      * \brief Update the output rate according to the specified input
404      *     value. It is just to keep track of the current input/output. It
405      *     should not be used to change any setting.
406      *
407      * \note This function is optional. If it is not needed, the pointer may be
408      *     set to NULL. This function must be synchronous and every status
409      *     return different from FWK_SUCCESS will be handle as an error.
410      *
411      *     Behaviour example:
412      *          In  -> 300MHz
413      *          Out <- 150MHz - /2 divider.
414      *
415      *          New input:
416      *          In  -> 600MHz
417      *          Out <- 300MHz (result) Preserve /2 divider.
418      *
419      * \param clock_id Clock device identifier.
420      *
421      * \param in_rate Desired input parent rate in Hertz.
422      *
423      * \param[out] out_rate The current clock rate in Hertz.
424      *
425      * \retval ::FWK_SUCCESS The operation succeeded.
426      * \return One of the standard framework error codes.
427      */
428     int (*update_input_rate)(
429         fwk_id_t clock_id,
430         uint64_t in_rate,
431         uint64_t *out_rate);
432 };
433 
434 /*!
435  * \brief Clock interface.
436  */
437 struct mod_clock_api {
438     /*!
439      * \brief Set a new clock rate by providing a frequency in Hertz (Hz).
440      *
441      * \param clock_id Clock device identifier.
442      *
443      * \param rate The desired frequency in Hertz.
444      *
445      * \param round_mode The type of rounding to perform, if required, to
446      *      achieve the given rate.
447      *
448      * \retval ::FWK_SUCCESS The operation succeeded.
449      * \retval ::FWK_PENDING The request is pending. The result for this
450      *      operation will be provided via a response event.
451      * \retval ::FWK_E_PARAM The clock identifier was invalid.
452      * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not
453      *      supported.
454      * \return One of the standard framework error codes.
455      */
456     int (*set_rate)(fwk_id_t clock_id, uint64_t rate,
457                     enum mod_clock_round_mode round_mode);
458 
459     /*!
460      * \brief Get the current rate of a clock in Hertz (Hz).
461      *
462      * \param clock_id Clock device identifier.
463      *
464      * \param[out] rate The current clock rate in Hertz.
465      *
466      * \retval ::FWK_SUCCESS The operation succeeded.
467      * \retval ::FWK_PENDING The request is pending. The requested rate will be
468      *      provided via a response event.
469      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
470      *      - The `clock_id` parameter was not a valid system entity identifier.
471      *      - The `rate` parameter was a null pointer value.
472      * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not
473      *      supported.
474      * \return One of the standard framework error codes.
475      */
476     int (*get_rate)(fwk_id_t clock_id, uint64_t *rate);
477 
478     /*!
479      * \brief Get a clock rate in Hertz from an index into the clock's range.
480      *
481      * \param clock_id Clock device identifier.
482      *
483      * \param rate_index The index into the clock's range to get the rate of.
484      *
485      * \param[out] rate The rate, in Hertz, corresponding to the index.
486      *
487      * \retval ::FWK_SUCCESS The operation succeeded.
488      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
489      *      - The `clock_id` parameter was not a valid system entity identifier.
490      *      - The `rate` parameter was a null pointer value.
491      * \return One of the standard framework error codes.
492      */
493     int (*get_rate_from_index)(fwk_id_t clock_id, unsigned int rate_index,
494                                uint64_t *rate);
495 
496     /*!
497      * \brief Set the running state of a clock.
498      *
499      * \param clock_id Clock device identifier.
500      *
501      * \param state One of the valid clock states.
502      *
503      * \retval ::FWK_SUCCESS The operation succeeded.
504      * \retval ::FWK_PENDING The request is pending. The result for this
505      *      operation will be provided via a response event.
506      * \retval ::FWK_E_PARAM The clock identifier was invalid.
507      * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not
508      *      supported.
509      * \return One of the standard framework error codes.
510      */
511     int (*set_state)(fwk_id_t clock_id, enum mod_clock_state state);
512 
513     /*!
514      * \brief Get the running state of a clock.
515      *
516      * \param clock_id Clock device identifier.
517      *
518      * \param[out] state The current clock state.
519      *
520      * \retval ::FWK_SUCCESS The operation succeeded.
521      * \retval ::FWK_PENDING The request is pending. The requested state will be
522      *      provided via a response event.
523      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
524      *      - The `clock_id` parameter was not a valid system entity identifier.
525      *      - The `state` parameter was a null pointer value.
526      * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not
527      *      supported.
528      * \return One of the standard framework error codes.
529      */
530     int (*get_state)(fwk_id_t clock_id, enum mod_clock_state *state);
531 
532     /*!
533      * \brief Get information about a clock's fixed properties.
534      *
535      * \param clock_id Clock device identifier.
536      *
537      * \param[out] info The clock device properties.
538      *
539      * \retval ::FWK_SUCCESS The operation succeeded.
540      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
541      *      - The `clock_id` parameter was not a valid system entity identifier.
542      *      - The `info` parameter was a null pointer value.
543      * \return One of the standard framework error codes.
544      */
545     int (*get_info)(fwk_id_t clock_id, struct mod_clock_info *info);
546 };
547 
548 /*!
549  * \brief Container for the values returned upon request completion.
550  */
551 union mod_clock_resp_values {
552     /*! The current clock rate in Hertz */
553     uint64_t rate;
554 
555     /*! The current clock state */
556     enum mod_clock_state state;
557 };
558 
559 /*!
560  * \brief Driver response parameters.
561  */
562 struct mod_clock_driver_resp_params {
563     /*! Status of driver operation */
564     int status;
565 
566     /*! Values returned */
567     union mod_clock_resp_values value;
568 };
569 
570 /*!
571  * \brief Clock driver response API.
572  *
573  * \details API used by the driver when an asynchronous request is completed.
574  *
575  */
576 struct mod_clock_driver_response_api {
577     /*!
578      * \brief Signal the completion of a driver request.
579      *
580      * \param dev_id Specific clock device identifier.
581      * \param resp_values Pointer to the values requested.
582      */
583     void (*request_complete)(fwk_id_t dev_id,
584                              struct mod_clock_driver_resp_params *resp_values);
585 };
586 
587 /*!
588  * \brief Event response parameters.
589  */
590 struct mod_clock_resp_params {
591     /*! Status of requested operation */
592     int status;
593 
594     /*! Values returned */
595     union mod_clock_resp_values value;
596 };
597 
598 /*!
599  * \brief Define the event identifiers for deferred responses.
600  */
601 enum mod_clock_event_idx {
602     MOD_CLOCK_EVENT_IDX_SET_RATE_REQUEST,
603     MOD_CLOCK_EVENT_IDX_GET_RATE_REQUEST,
604 
605     MOD_CLOCK_EVENT_IDX_SET_STATE_REQUEST,
606     MOD_CLOCK_EVENT_IDX_GET_STATE_REQUEST,
607 
608     MOD_CLOCK_EVENT_IDX_COUNT
609 };
610 
611 #ifdef BUILD_HAS_MOD_CLOCK
612 /*!
613  * \brief Request event identifiers.
614  *
615  * \details These identifiers are used by the clients that expect to receive a
616  *      response event from this module when a request is deferred.
617  */
618 static const fwk_id_t mod_clock_event_id_set_rate_request =
619     FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK,
620                       MOD_CLOCK_EVENT_IDX_SET_RATE_REQUEST);
621 
622 static const fwk_id_t mod_clock_event_id_get_rate_request =
623     FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK,
624                       MOD_CLOCK_EVENT_IDX_GET_RATE_REQUEST);
625 
626 static const fwk_id_t mod_clock_event_id_set_state_request =
627     FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK,
628                       MOD_CLOCK_EVENT_IDX_SET_STATE_REQUEST);
629 
630 static const fwk_id_t mod_clock_event_id_get_state_request =
631     FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK,
632                       MOD_CLOCK_EVENT_IDX_GET_STATE_REQUEST);
633 #endif
634 
635 /*!
636  * \}
637  */
638 
639 /*!
640  * \}
641  */
642 
643 #endif /* MOD_CLOCK_H */
644