1 /*
2 * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 /*
8 * TI Clock Framework API Header
9 *
10 * This header defines the core clock framework data structures and API
11 * functions. It provides clock data types, clock driver interfaces, parent-
12 * child relationships, frequency ranges, and the main API for clock
13 * operations including get/put, frequency control, and state management.
14 */
15
16 #ifndef TI_CLK_H
17 #define TI_CLK_H
18
19 #include <assert.h>
20 #include <stddef.h>
21
22 #include <common/debug.h>
23 #include <lib/utils_def.h>
24
25 #include <ti_pm_types.h>
26
27 /*
28 * Generates a 32-bit mask that covers all set bits in a number.
29 * number must be non-zero; __builtin_clz(0) is undefined behavior.
30 */
ti_mask_cover_for_number(uint32_t number)31 static inline uint32_t ti_mask_cover_for_number(uint32_t number)
32 {
33 assert(number != 0U);
34 return (uint32_t)((1UL << (32U - (uint32_t)__builtin_clz(number))) - 1UL);
35 }
36
37 #define TI_MASK_COVER_FOR_NUMBER(number) ti_mask_cover_for_number(number)
38
39 /*
40 * Initializes a clock range entry with min and max frequencies
41 */
42 #define TI_CLK_RANGE(id, min, max)[(id)] = \
43 { .min_hz = (uint32_t) (min), \
44 .max_hz = (uint32_t) (max) }
45
46 /*
47 * Initializes a clock default frequency entry with min, target, and max
48 */
49 #define TI_CLK_DEFAULT(id, min, target, max)[(id)] = \
50 { .min_hz = (uint32_t) (min), \
51 .target_hz = (uint32_t) (target), \
52 .max_hz = (uint32_t) (max) }
53
54 /* Clock type identifier for divider clocks */
55 #define TI_CLK_TYPE_DIV 1U
56
57 /* Clock type identifier for multiplexer clocks */
58 #define TI_CLK_TYPE_MUX 2U
59
60 /* Allows clock to modify its parent's frequency */
61 #define TI_CLK_DATA_FLAG_MODIFY_PARENT_FREQ BIT(0)
62
63 /* Skips hardware reinitialization during clock setup */
64 #define TI_CLK_DATA_FLAG_NO_HW_REINIT BIT(2)
65
66 /* Clock should be enabled during power-up */
67 #define TI_CLK_FLAG_PWR_UP_EN ((uint8_t) BIT(0))
68
69 /* Clock has been initialized */
70 #define TI_CLK_FLAG_INITIALIZED ((uint8_t) BIT(2))
71
72 /*
73 * Clock has a cached frequency value stored in soc_clock_values[] array.
74 * Used for clocks like PLLs where the frequency is programmed and stored
75 * rather than derived from parent clocks or hardware registers.
76 */
77 #define TI_CLK_FLAG_CACHED ((uint8_t) BIT(3))
78
79 /* Clock hardware is disabled */
80 #define TI_CLK_HW_STATE_DISABLED 0U
81
82 /* Clock hardware is enabled */
83 #define TI_CLK_HW_STATE_ENABLED 1U
84
85 /* Clock hardware is in transition state */
86 #define TI_CLK_HW_STATE_TRANSITION 2U
87
88 /*
89 * Defines a frequency range with minimum and maximum values
90 */
91 struct ti_clk_range {
92 /* Minimum frequency in Hz */
93 uint32_t min_hz;
94 /* Maximum frequency in Hz */
95 uint32_t max_hz;
96 };
97
98 /*
99 * Defines a default frequency configuration with min, target, and max
100 */
101 struct ti_clk_default {
102 /* Minimum acceptable frequency in Hz */
103 uint32_t min_hz;
104 /* Target frequency in Hz */
105 uint32_t target_hz;
106 /* Maximum acceptable frequency in Hz */
107 uint32_t max_hz;
108 };
109
110 /*
111 * Represents a clock's parent and associated divider
112 */
113 struct ti_clk_parent {
114 /* Parent clock ID */
115 uint16_t clk;
116 /* Divider value applied to parent frequency */
117 uint8_t div;
118 };
119
120 /*
121 * Clock driver-specific data (placeholder for extensibility)
122 */
123 struct ti_clk_drv_data {
124 };
125
126 /*
127 * Clock structure combining runtime state and configuration
128 *
129 * This structure merges what was previously ti_clk (runtime) and ti_clk_data
130 * (configuration). Since everything runs from RAM on this platform, there's no
131 * benefit to separating them into parallel arrays.
132 */
133 struct ti_clk {
134 /* Runtime state - modified during operation */
135 /* Reference count for clock usage */
136 uint8_t ref_count;
137 /* Runtime flags (TI_CLK_FLAG_*) */
138 uint8_t flags;
139
140 /* Configuration - set at initialization, read-only afterwards */
141 /* Clock driver operations */
142 const struct ti_clk_drv *drv;
143 /* Driver-specific data */
144 const struct ti_clk_drv_data *data;
145 /* Parent clock and divider */
146 const struct ti_clk_parent parent;
147 /* soc_clock_values[] index for cached clocks */
148 const uint16_t freq_idx;
149 /* Index into shared range table */
150 const uint8_t range_idx;
151 /* Clock type (TI_CLK_TYPE_*) */
152 const uint8_t type;
153 /* Configuration flags (TI_CLK_DATA_FLAG_*) */
154 const uint8_t data_flags;
155 };
156
157 struct ti_clk_drv {
158 /* Perform any necessary initialization */
159 int32_t (*init)(struct ti_clk *clkp);
160
161 /*
162 * Set the current state of a clock.
163 */
164 bool (*set_state)(struct ti_clk *clkp, bool enabled);
165
166 /*
167 * Get the current state of a clock.
168 */
169 uint32_t (*get_state)(struct ti_clk *clkp);
170
171 /*
172 * Program a clock to run at a given frequency. The minimum
173 * and maximum frequency parameters allow the best nearest
174 * match to be chosen. The clock tree is walked to accomplish
175 * this.
176 */
177 uint32_t (*set_freq)(struct ti_clk *clkp, uint32_t target_hz,
178 uint32_t min_hz, uint32_t max_hz,
179 bool *changed);
180
181 /*
182 * Return the frequency this clock runs at.
183 */
184 uint32_t (*get_freq)(struct ti_clk *clkp);
185
186 };
187
188 /* The table of clock structures */
189 extern struct ti_clk soc_clocks[];
190 extern const size_t soc_clock_count;
191
192 /* The table of shared const clock ranges */
193 extern const struct ti_clk_range soc_clock_ranges[];
194 extern const size_t soc_clock_range_count;
195
196 /* The table of default frequencies */
197 extern const struct ti_clk_default soc_clock_freq_defaults[];
198 extern const size_t soc_clock_freq_defaults_count;
199
200 /*
201 * The table of cached clock frequency values.
202 * Some clocks (e.g., PLLs) store their programmed frequency in this array
203 * indexed by clk->freq_idx, rather than deriving it from parent clocks or
204 * hardware registers. Clocks using this mechanism have TI_CLK_FLAG_CACHED set.
205 */
206 extern uint32_t soc_clock_values[];
207 extern const size_t soc_clock_value_count;
208
209 /**
210 * ti_clk_value_set_freq() - Sets frequency for clocks with cached frequency values
211 * @clkp: The clock to modify (must have valid freq_idx)
212 * @target_hz: Target frequency in Hz
213 * @min_hz: Minimum acceptable frequency
214 * @max_hz: Maximum acceptable frequency
215 * @changed: Output parameter indicating if frequency changed
216 *
217 * Used by clocks that store their frequency in soc_clock_values[] array
218 * (e.g., PLLs). The frequency is validated against min/max range and stored
219 * at the index specified by clk->freq_idx.
220 *
221 * Return: Target frequency in Hz on success, 0 on failure
222 */
223 uint32_t ti_clk_value_set_freq(struct ti_clk *clkp, uint32_t target_hz,
224 uint32_t min_hz, uint32_t max_hz,
225 bool *changed);
226
227 /**
228 * ti_clk_value_get_freq() - Gets the cached frequency value for a clock
229 * @clkp: The clock to query (must have valid freq_idx)
230 *
231 * Retrieves the frequency stored in soc_clock_values[] array for clocks
232 * that cache their frequency (e.g., PLLs). The value is read from the index
233 * specified by clk->freq_idx.
234 *
235 * Return: The cached frequency in Hz, or 0 if freq_idx is out of bounds
236 */
237 uint32_t ti_clk_value_get_freq(struct ti_clk *clkp);
238
239 /**
240 * ti_clk_get_parent_freq() - Gets the parent clock's current frequency
241 * @clkp: The clock whose parent frequency to retrieve
242 *
243 * Return: Parent frequency in Hz
244 */
245 uint32_t ti_clk_get_parent_freq(struct ti_clk *clkp);
246
247 /**
248 * ti_clk_generic_set_freq_parent() - Generic frequency setter that adjusts parent frequency
249 * @clkp: The clock to modify
250 * @parent: The parent clock
251 * @target_hz: Target frequency in Hz
252 * @min_hz: Minimum acceptable frequency
253 * @max_hz: Maximum acceptable frequency
254 * @changed: Output parameter indicating if frequency changed
255 * @div: Divider from parent to child (child = parent/div).
256 * Used to translate child frequency to parent frequency.
257 *
258 * Return: Best frequency found in Hz, 0 on failure
259 */
260 uint32_t ti_clk_generic_set_freq_parent(struct ti_clk *clkp, struct ti_clk *parent,
261 uint32_t target_hz, uint32_t min_hz,
262 uint32_t max_hz,
263 bool *changed, uint32_t div);
264
265 /**
266 * ti_clk_set_freq() - Sets a clock's frequency
267 * @clkp: The clock to modify
268 * @target_hz: Target frequency in Hz
269 * @min_hz: Minimum acceptable frequency
270 * @max_hz: Maximum acceptable frequency
271 * @changed: Output parameter indicating if frequency changed
272 *
273 * Return: Best frequency found in Hz, 0 on failure
274 */
275 uint32_t ti_clk_set_freq(struct ti_clk *clkp, uint32_t target_hz, uint32_t min_hz,
276 uint32_t max_hz, bool *changed);
277
278 /**
279 * ti_clk_get_freq() - Gets a clock's current frequency
280 * @clkp: The clock to query
281 *
282 * Return: Current frequency in Hz
283 */
284 uint32_t ti_clk_get_freq(struct ti_clk *clkp);
285
286 /**
287 * ti_clk_get_state() - Gets a clock's hardware state
288 * @clkp: The clock to query
289 *
290 * Return: Clock state (TI_CLK_HW_STATE_*)
291 */
292 uint32_t ti_clk_get_state(struct ti_clk *clkp);
293
294 /**
295 * ti_clk_set_state() - Sets a clock's hardware state (enable/disable)
296 * @clkp: The clock to modify
297 * @enable: True to enable, false to disable
298 *
299 * Return: True if successful
300 */
301 bool ti_clk_set_state(struct ti_clk *clkp, bool enable);
302
303 /**
304 * ti_clk_get() - Increments a clock's reference count and enables it
305 * @clkp: The clock to get
306 *
307 * Return: True if successful
308 */
309 bool ti_clk_get(struct ti_clk *clkp);
310
311 /**
312 * ti_clk_put() - Decrements a clock's reference count and disables if zero
313 * @clkp: The clock to put
314 */
315 void ti_clk_put(struct ti_clk *clkp);
316
317 /**
318 * ti_clk_init() - Initializes the TI clock framework
319 *
320 * Performs one pass of clock initialization. Clocks are processed in array
321 * order. Each clock is skipped if its parent clock is not yet initialized,
322 * allowing the function to handle parent-child dependencies.
323 *
324 * Design for arbitrary clock ordering:
325 * - The function can be called multiple times to initialize clocks with
326 * multi-level dependencies
327 * - Each call initializes clocks whose parent dependencies are now met
328 * - Returns 0 if progress was made, -EAGAIN if no progress possible
329 *
330 * Current implementation:
331 * - The clock table is topologically sorted (parents before children)
332 * - A single call initializes all clocks
333 * - Multiple calls are not necessary but are safe (subsequent calls
334 * detect all clocks initialized and return 0 quickly)
335 *
336 * Return: 0 on success (clocks initialized or no clocks need init),
337 * -EAGAIN if no progress made (circular dependency - fatal),
338 * -ENODEV if a power-up clock failed to enable,
339 * or other negative error code on failure
340 */
341 int32_t ti_clk_init(void);
342
343 /**
344 * ti_clk_drop_pwr_up_en() - Clears power-up enable flag on all clocks
345 */
346 void ti_clk_drop_pwr_up_en(void);
347
348 /**
349 * ti_clk_id_valid() - Determine if a clock ID is valid.
350 * @id: The internal clock API ID.
351 *
352 * Return: True if the clock ID refers to a valid SoC clock, false otherwise
353 */
ti_clk_id_valid(ti_clk_idx_t id)354 static inline bool ti_clk_id_valid(ti_clk_idx_t id)
355 {
356 return (id < soc_clock_count) && (soc_clocks[id].drv != NULL);
357 }
358
359 /*
360 * Lookup an internal clock based on a clock ID
361 *
362 * This does a lookup of a clock based on the clock ID.
363 */
ti_clk_lookup(ti_clk_idx_t id)364 static inline struct ti_clk *ti_clk_lookup(ti_clk_idx_t id)
365 {
366 return ti_clk_id_valid(id) ? (soc_clocks + id) : NULL;
367 }
368
369 /*
370 * Return the clock ID based on a clock pointer.
371 *
372 * The clock pointer is just an index into the array of clocks. This is
373 * used to return a clock ID. This function has no error checking for NULL
374 * pointers.
375 */
ti_clk_id(struct ti_clk * clkp)376 static inline ti_clk_idx_t ti_clk_id(struct ti_clk *clkp)
377 {
378 return (ti_clk_idx_t) (clkp - soc_clocks);
379 }
380
381 /*
382 * Return a shared clock range with bounds checking.
383 *
384 * The clock infrastructure contains a set of shared clock ranges. Many
385 * clocks and PLLs have min/max ranges. However, these min/max ranges can
386 * take up a significant amount of storage. As many clocks share the same
387 * ranges, we use a shared table of ranges. The clocks can then index that
388 * table with a small uint8_t.
389 */
ti_clk_get_range(ti_clk_idx_t idx)390 static inline const struct ti_clk_range *ti_clk_get_range(ti_clk_idx_t idx)
391 {
392 if (idx >= soc_clock_range_count) {
393 return NULL;
394 }
395 return soc_clock_ranges + idx;
396 }
397
398 /**
399 * ti_clk_set_value() - Set a cached clock frequency value with bounds checking.
400 * @idx: The index into soc_clock_values[] array (from clk->freq_idx).
401 * @value_hz: The frequency value in Hz to cache.
402 *
403 * Stores a frequency value in the soc_clock_values[] array for clocks that
404 * cache their frequency (e.g., PLLs with TI_CLK_FLAG_CACHED set). Validates
405 * the index is within array bounds before writing.
406 *
407 * Return: True if the value was cached successfully, false if index is out of bounds.
408 */
ti_clk_set_value(uint16_t idx,uint32_t value_hz)409 static inline bool ti_clk_set_value(uint16_t idx, uint32_t value_hz)
410 {
411 if (idx >= soc_clock_value_count) {
412 return false;
413 }
414 soc_clock_values[idx] = value_hz;
415 return true;
416 }
417
418 /**
419 * ti_clk_get_value() - Get a cached clock frequency value with bounds checking.
420 * @idx: The index into soc_clock_values[] array (from clk->freq_idx).
421 *
422 * Retrieves a frequency value from the soc_clock_values[] array for clocks
423 * that cache their frequency (e.g., PLLs with TI_CLK_FLAG_CACHED set).
424 * Validates the index is within array bounds before reading.
425 *
426 * Return: The cached frequency value in Hz, or 0 if index is out of bounds.
427 */
ti_clk_get_value(uint16_t idx)428 static inline uint32_t ti_clk_get_value(uint16_t idx)
429 {
430 if (idx >= soc_clock_value_count) {
431 return 0;
432 }
433 return soc_clock_values[idx];
434 }
435
436 #endif /* TI_CLK_H */
437