1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-2021, 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 /*!
205  * \brief Range of supported rates for a clock.
206  */
207 struct mod_clock_range {
208     /*! The type of rates the clock provides (discrete or continuous) */
209     enum mod_clock_rate_type rate_type;
210 
211     /*! Minimum rate (in Hz) */
212     uint64_t min;
213 
214     /*! Maximum rate (in Hz) */
215     uint64_t max;
216 
217     /*!
218      * \brief Number of Hertz by which the rate can be incremented at each step
219      *      throughout the clock's range.
220      *
221      * \warning Valid only when rate_type is equal to
222      *      ::MOD_CLOCK_RATE_TYPE_CONTINUOUS, as clocks that use
223      *      ::MOD_CLOCK_RATE_TYPE_DISCRETE may not have a regular step between
224      *      their rates.
225      */
226     uint64_t step;
227 
228     /*! The number of unique rates that the clock can attain */
229     uint64_t rate_count;
230 };
231 
232 /*!
233  * \brief Clock properties exposed via the get_info() API function.
234  *
235  * \details This structure is intended to store clock information that is static
236  *     and which does not change during runtime. Dynamic information, such as
237  *     the current clock state, are exposed through functions in the clock and
238  *     clock driver APIs.
239  */
240 struct mod_clock_info {
241     /*! Human-friendly clock name */
242     const char *name;
243 
244     /*! Range of supported clock rates */
245     struct mod_clock_range range;
246 
247     /*! Number of discrete rates supported */
248     uint64_t rate_count;
249 };
250 
251 /*!
252  * \brief Clock driver interface.
253  */
254 struct mod_clock_drv_api {
255     /*! Name of the driver */
256     const char *name;
257 
258     /*!
259      * \brief Set a new clock rate by providing a frequency in Hertz (Hz).
260      *
261      * \param clock_id Clock device identifier.
262      *
263      * \param rate The desired frequency in Hertz.
264      *
265      * \param round_mode The type of rounding to perform, if required, to
266      *      achieve the given rate.
267      *
268      * \retval ::FWK_PENDING The request is pending. The driver will provide the
269      *      requested value later through the driver response API.
270      * \retval ::FWK_SUCCESS The operation succeeded.
271      * \return One of the standard framework error codes.
272      */
273     int (*set_rate)(fwk_id_t clock_id, uint64_t rate,
274                     enum mod_clock_round_mode round_mode);
275 
276     /*!
277      * \brief Get the current rate of a clock in Hertz (Hz).
278      *
279      * \param clock_id Clock device identifier.
280      *
281      * \param[out] rate The current clock rate in Hertz.
282      *
283      * \retval ::FWK_PENDING The request is pending. The driver will provide the
284      *      requested value later through the driver response API.
285      * \retval ::FWK_SUCCESS The operation succeeded.
286      * \return One of the standard framework error codes.
287      */
288     int (*get_rate)(fwk_id_t clock_id, uint64_t *rate);
289 
290     /*!
291      * \brief Get a clock rate in Hertz from an index into the clock's range.
292      *
293      * \param clock_id Clock device identifier.
294      *
295      * \param rate_index The index into the clock's range to get the rate of.
296      *
297      * \param[out] rate The rate, in Hertz, corresponding to the index.
298      *
299      * \retval ::FWK_SUCCESS The operation succeeded.
300      * \return One of the standard framework error codes.
301      */
302     int (*get_rate_from_index)(fwk_id_t clock_id, unsigned int rate_index,
303                                uint64_t *rate);
304 
305     /*!
306      * \brief Set the running state of a clock.
307      *
308      * \param clock_id Clock device identifier.
309      *
310      * \param state One of the valid clock states.
311      *
312      * \retval ::FWK_PENDING The request is pending. The driver will provide the
313      *      requested value later through the driver response API.
314      * \retval ::FWK_SUCCESS The operation succeeded.
315      * \return One of the standard framework error codes.
316      */
317     int (*set_state)(fwk_id_t clock_id, enum mod_clock_state state);
318 
319     /*!
320      * \brief Get the running state of a clock.
321      *
322      * \param clock_id Clock device identifier.
323      *
324      * \param[out] state The current clock state.
325      *
326      * \retval ::FWK_PENDING The request is pending. The driver will provide the
327      *      requested value later through the driver response API.
328      * \retval ::FWK_SUCCESS The operation succeeded.
329      * \return One of the standard framework error codes.
330      */
331     int (*get_state)(fwk_id_t clock_id, enum mod_clock_state *state);
332 
333     /*!
334      * \brief Get the range of rates that the clock supports.
335      *
336      * \param clock_id Clock device identifier.
337      *
338      * \param[out] range The clock range structure.
339      *
340      * \retval ::FWK_SUCCESS The operation succeeded.
341      * \return One of the standard framework error codes.
342      */
343     int (*get_range)(fwk_id_t clock_id, struct mod_clock_range *range);
344 
345     /*!
346      * \brief Handle the condition where the state of a clock's power domain is
347      *     about to change.
348      *
349      * \details This function will be called prior to the change in power
350      *     state occurring so that the clock driver implementing this API is
351      *     able to perform any required preparatory work beforehand.
352      *
353      * \note This function is optional. If the driver does not control any
354      *     clocks that require power state awareness then the pointer may be set
355      *     to NULL.
356      *
357      * \param clock_id Clock device identifier.
358      *
359      * \param current_state The current power state that the clock's power
360      *     domain will transition away from.
361      *
362      * \param new_state The power state that the clock's power domain will
363      *     transition to.
364      *
365      * \retval ::FWK_SUCCESS The operation succeeded.
366      * \return One of the standard framework error codes.
367      */
368     int (*process_pending_power_transition)(
369         fwk_id_t clock_id,
370         unsigned int current_state,
371         unsigned int new_state);
372 
373     /*!
374      * \brief Handle the condition where the state of a clock's power domain
375      *     has changed.
376      *
377      * \details This function will be called after the change in power state
378      *     has occurred. The driver can take any appropriate actions that are
379      *     required to accommodate the new state. The transition can be to a
380      *     deeper power state (e.g. ON->OFF) or to a shallower power state
381      *     (e.g. OFF->ON).
382      *
383      * \note This function is optional. If the driver does not control any
384      *     clocks that require power state awareness then the pointer may be set
385      *     to NULL.
386      *
387      * \param clock_id Clock device identifier.
388      *
389      * \param state The power state that the clock's power domain transitioned
390      *     to.
391      *
392      * \retval ::FWK_SUCCESS The operation succeeded.
393      * \return One of the standard framework error codes.
394      */
395     int (*process_power_transition)(fwk_id_t clock_id, unsigned int state);
396 
397     /*!
398      * \brief Update the output rate according to the specified input
399      *     value. It is just to keep track of the current input/output. It
400      *     should not be used to change any setting.
401      *
402      * \note This function is optional. If it is not needed, the pointer may be
403      *     set to NULL. This function must be synchronous and every status
404      *     return different from FWK_SUCCESS will be handle as an error.
405      *
406      *     Behaviour example:
407      *          In  -> 300MHz
408      *          Out <- 150MHz - /2 divider.
409      *
410      *          New input:
411      *          In  -> 600MHz
412      *          Out <- 300MHz (result) Preserve /2 divider.
413      *
414      * \param clock_id Clock device identifier.
415      *
416      * \param in_rate Desired input parent rate in Hertz.
417      *
418      * \param[out] out_rate The current clock rate in Hertz.
419      *
420      * \retval ::FWK_SUCCESS The operation succeeded.
421      * \return One of the standard framework error codes.
422      */
423     int (*update_input_rate)(
424         fwk_id_t clock_id,
425         uint64_t in_rate,
426         uint64_t *out_rate);
427 };
428 
429 /*!
430  * \brief Clock interface.
431  */
432 struct mod_clock_api {
433     /*!
434      * \brief Set a new clock rate by providing a frequency in Hertz (Hz).
435      *
436      * \param clock_id Clock device identifier.
437      *
438      * \param rate The desired frequency in Hertz.
439      *
440      * \param round_mode The type of rounding to perform, if required, to
441      *      achieve the given rate.
442      *
443      * \retval ::FWK_SUCCESS The operation succeeded.
444      * \retval ::FWK_PENDING The request is pending. The result for this
445      *      operation will be provided via a response event.
446      * \retval ::FWK_E_PARAM The clock identifier was invalid.
447      * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not
448      *      supported.
449      * \return One of the standard framework error codes.
450      */
451     int (*set_rate)(fwk_id_t clock_id, uint64_t rate,
452                     enum mod_clock_round_mode round_mode);
453 
454     /*!
455      * \brief Get the current rate of a clock in Hertz (Hz).
456      *
457      * \param clock_id Clock device identifier.
458      *
459      * \param[out] rate The current clock rate in Hertz.
460      *
461      * \retval ::FWK_SUCCESS The operation succeeded.
462      * \retval ::FWK_PENDING The request is pending. The requested rate will be
463      *      provided via a response event.
464      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
465      *      - The `clock_id` parameter was not a valid system entity identifier.
466      *      - The `rate` parameter was a null pointer value.
467      * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not
468      *      supported.
469      * \return One of the standard framework error codes.
470      */
471     int (*get_rate)(fwk_id_t clock_id, uint64_t *rate);
472 
473     /*!
474      * \brief Get a clock rate in Hertz from an index into the clock's range.
475      *
476      * \param clock_id Clock device identifier.
477      *
478      * \param rate_index The index into the clock's range to get the rate of.
479      *
480      * \param[out] rate The rate, in Hertz, corresponding to the index.
481      *
482      * \retval ::FWK_SUCCESS The operation succeeded.
483      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
484      *      - The `clock_id` parameter was not a valid system entity identifier.
485      *      - The `rate` parameter was a null pointer value.
486      * \return One of the standard framework error codes.
487      */
488     int (*get_rate_from_index)(fwk_id_t clock_id, unsigned int rate_index,
489                                uint64_t *rate);
490 
491     /*!
492      * \brief Set the running state of a clock.
493      *
494      * \param clock_id Clock device identifier.
495      *
496      * \param state One of the valid clock states.
497      *
498      * \retval ::FWK_SUCCESS The operation succeeded.
499      * \retval ::FWK_PENDING The request is pending. The result for this
500      *      operation will be provided via a response event.
501      * \retval ::FWK_E_PARAM The clock identifier was invalid.
502      * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not
503      *      supported.
504      * \return One of the standard framework error codes.
505      */
506     int (*set_state)(fwk_id_t clock_id, enum mod_clock_state state);
507 
508     /*!
509      * \brief Get the running state of a clock.
510      *
511      * \param clock_id Clock device identifier.
512      *
513      * \param[out] state The current clock state.
514      *
515      * \retval ::FWK_SUCCESS The operation succeeded.
516      * \retval ::FWK_PENDING The request is pending. The requested state will be
517      *      provided via a response event.
518      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
519      *      - The `clock_id` parameter was not a valid system entity identifier.
520      *      - The `state` parameter was a null pointer value.
521      * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not
522      *      supported.
523      * \return One of the standard framework error codes.
524      */
525     int (*get_state)(fwk_id_t clock_id, enum mod_clock_state *state);
526 
527     /*!
528      * \brief Get information about a clock's fixed properties.
529      *
530      * \param clock_id Clock device identifier.
531      *
532      * \param[out] info The clock device properties.
533      *
534      * \retval ::FWK_SUCCESS The operation succeeded.
535      * \retval ::FWK_E_PARAM An invalid parameter was encountered:
536      *      - The `clock_id` parameter was not a valid system entity identifier.
537      *      - The `info` parameter was a null pointer value.
538      * \return One of the standard framework error codes.
539      */
540     int (*get_info)(fwk_id_t clock_id, struct mod_clock_info *info);
541 };
542 
543 /*!
544  * \brief Container for the values returned upon request completion.
545  */
546 union mod_clock_resp_values {
547     /*! The current clock rate in Hertz */
548     uint64_t rate;
549 
550     /*! The current clock state */
551     enum mod_clock_state state;
552 };
553 
554 /*!
555  * \brief Driver response parameters.
556  */
557 struct mod_clock_driver_resp_params {
558     /*! Status of driver operation */
559     int status;
560 
561     /*! Values returned */
562     union mod_clock_resp_values value;
563 };
564 
565 /*!
566  * \brief Clock driver response API.
567  *
568  * \details API used by the driver when an asynchronous request is completed.
569  *
570  */
571 struct mod_clock_driver_response_api {
572     /*!
573      * \brief Signal the completion of a driver request.
574      *
575      * \param dev_id Specific clock device identifier.
576      * \param resp_values Pointer to the values requested.
577      */
578     void (*request_complete)(fwk_id_t dev_id,
579                              struct mod_clock_driver_resp_params *resp_values);
580 };
581 
582 /*!
583  * \brief Event response parameters.
584  */
585 struct mod_clock_resp_params {
586     /*! Status of requested operation */
587     int status;
588 
589     /*! Values returned */
590     union mod_clock_resp_values value;
591 };
592 
593 /*!
594  * \brief Define the event identifiers for deferred responses.
595  */
596 enum mod_clock_event_idx {
597     MOD_CLOCK_EVENT_IDX_SET_RATE_REQUEST,
598     MOD_CLOCK_EVENT_IDX_GET_RATE_REQUEST,
599 
600     MOD_CLOCK_EVENT_IDX_SET_STATE_REQUEST,
601     MOD_CLOCK_EVENT_IDX_GET_STATE_REQUEST,
602 
603     MOD_CLOCK_EVENT_IDX_COUNT
604 };
605 
606 /*!
607  * \brief Request event identifiers.
608  *
609  * \details These identifiers are used by the clients that expect to receive a
610  *      response event from this module when a request is deferred.
611  */
612 static const fwk_id_t mod_clock_event_id_set_rate_request =
613     FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK,
614                       MOD_CLOCK_EVENT_IDX_SET_RATE_REQUEST);
615 
616 static const fwk_id_t mod_clock_event_id_get_rate_request =
617     FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK,
618                       MOD_CLOCK_EVENT_IDX_GET_RATE_REQUEST);
619 
620 static const fwk_id_t mod_clock_event_id_set_state_request =
621     FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK,
622                       MOD_CLOCK_EVENT_IDX_SET_STATE_REQUEST);
623 
624 static const fwk_id_t mod_clock_event_id_get_state_request =
625     FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK,
626                       MOD_CLOCK_EVENT_IDX_GET_STATE_REQUEST);
627 
628 /*!
629  * \}
630  */
631 
632 /*!
633  * \}
634  */
635 
636 #endif /* MOD_CLOCK_H */
637