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_CSS_CLOCK_H
9 #define MOD_CSS_CLOCK_H
10 
11 #include <fwk_element.h>
12 #include <fwk_id.h>
13 
14 #include <stdbool.h>
15 #include <stdint.h>
16 
17 /*!
18  * \addtogroup GroupModules Modules
19  * \{
20  */
21 
22 /*!
23  * \defgroup GroupCSSClock CSS Clock Driver
24  *
25  * \details A driver for Arm Compute Sub-System clock devices.
26  *
27  * \{
28  */
29 
30 /*!
31  * \brief Type of the clock (indexed vs non-indexed).
32  */
33 enum mod_css_clock_type {
34     /*! A lookup table is used to find the settings for a given rate. */
35     MOD_CSS_CLOCK_TYPE_INDEXED,
36     /*! The clock rate is set without looking up settings in a table. */
37     MOD_CSS_CLOCK_TYPE_NON_INDEXED,
38 };
39 
40 /*!
41  * \brief APIs that the module makes available to entities requesting binding.
42  */
43 enum mod_css_clock_api_types {
44     /*! Clock HAL */
45     MOD_CSS_CLOCK_API_TYPE_CLOCK,
46     MOD_CSS_CLOCK_API_COUNT,
47 };
48 
49 /*!
50  * \brief Rate lookup table entry.
51  */
52 struct mod_css_clock_rate {
53     /*! Rate of the clock in Hertz. */
54     uint64_t rate;
55 
56     /*! Rate of the source PLL in Hertz. */
57     uint64_t pll_rate;
58 
59     /*! The clock source used to attain the rate. */
60     uint8_t clock_source;
61 
62     /*! The clock divider to program. */
63     uint8_t clock_div_type;
64 
65     /*! The clock divider used to attain the rate. */
66     uint32_t clock_div;
67 
68     /*! The clock modulator numerator setting, if implemented. */
69     uint32_t clock_mod_numerator;
70 
71     /*! The clock modulator denominator setting, if implemented. */
72     uint32_t clock_mod_denominator;
73 };
74 
75 /*!
76  * \brief Subsystem clock device configuration.
77  */
78 struct mod_css_clock_dev_config {
79     /*! The type of the clock (indexed vs non-indexed). */
80     enum mod_css_clock_type clock_type;
81 
82     /*! Clock source used for non-indexed clocks. */
83     uint8_t clock_default_source;
84 
85     /*! Clock source used when changing the PLL rate. */
86     uint8_t clock_switching_source;
87 
88     /*! Element identifier for the associated PLL. */
89     fwk_id_t pll_id;
90 
91     /*! Reference to the API provided by the PLL driver. */
92     fwk_id_t pll_api_id;
93 
94     /*! Pointer to the table of clocks that are members of the group. */
95     fwk_id_t const *member_table;
96 
97     /*! The number of clocks in the member table. */
98     uint32_t member_count;
99 
100     /*! Reference to the API for the clocks that are members of the group. */
101     fwk_id_t member_api_id;
102 
103     /*!
104      * The rate, in Hz, that the member clocks run at before any configuration.
105      */
106     uint64_t initial_rate;
107 
108     /*! The clock's support for modulation. */
109     bool modulation_supported;
110 
111     /*! Pointer to the clock's rate lookup table. */
112     struct mod_css_clock_rate const *rate_table;
113 
114     /*! The number of rates in the rate lookup table. */
115     uint32_t rate_count;
116 };
117 
118 /*!
119  * \brief CSS clock control interface.
120  */
121 struct mod_css_clock_direct_api {
122     /*! Set the clock device's divider */
123     int (*set_div)(fwk_id_t device_id, uint32_t divider_type,
124                    uint32_t divider);
125 
126     /*! Set the clock device's source (multi-source clocks only) */
127     int (*set_source)(fwk_id_t device_id, uint8_t source);
128 
129     /*! Set the clock device's modulator (multi-source clocks only) */
130     int (*set_mod)(fwk_id_t device_id, uint32_t numerator,
131                    uint32_t denominator);
132 
133     /*!
134      * \brief Handle the condition where the state of a clock's power domain is
135      *     about to change.
136      *
137      * \details This function will be called prior to the change in power
138      *     state occurring so that the clock driver implementing this API is
139      *     able to perform any required preparatory work beforehand.
140      *
141      * \note This function is optional. If the driver does not control any
142      *     clocks that require power state awareness then the pointer may be set
143      *     to NULL.
144      *
145      * \param clock_id Clock device identifier.
146      *
147      * \param current_state The current power state that the clock's power
148      *     domain will transition away from.
149      *
150      * \param new_state The power state that the clock's power domain will
151      *     transition to.
152      *
153      * \retval ::FWK_SUCCESS The operation succeeded.
154      * \return One of the standard framework error codes.
155      */
156     int (*process_pending_power_transition)(
157         fwk_id_t clock_id,
158         unsigned int current_state,
159         unsigned int new_state);
160 
161     /*!
162      * \brief Handle the condition where the state of a clock's power domain
163      *     has changed.
164      *
165      * \details This function will be called after the change in power state
166      *     has occurred. The driver can take any appropriate actions that are
167      *     required to accommodate the new state. The transition can be to a
168      *     deeper power state (e.g. ON->OFF) or to a shallower power state
169      *     (e.g. OFF->ON).
170      *
171      * \note This function is optional. If the driver does not control any
172      *     clocks that require power state awareness then the pointer may be set
173      *     to NULL.
174      *
175      * \param clock_id Clock device identifier.
176      *
177      * \param state The power state that the clock's power domain transitioned
178      *     to.
179      *
180      * \retval ::FWK_SUCCESS The operation succeeded.
181      * \return One of the standard framework error codes.
182      */
183     int (*process_power_transition)(fwk_id_t clock_id, unsigned int state);
184 };
185 
186 /*!
187  * \}
188  */
189 
190 /*!
191  * \}
192  */
193 
194 #endif /* MOD_CSS_CLOCK_H */
195