xref: /rk3399_ARM-atf/drivers/ti/pd/include/ti_device_clk.h (revision a28114d66a6d43db4accef5fd5d6dab6c059e584)
1*6f2a8791SKamlesh Gurudasani /*
2*6f2a8791SKamlesh Gurudasani  * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com
3*6f2a8791SKamlesh Gurudasani  *
4*6f2a8791SKamlesh Gurudasani  * SPDX-License-Identifier: BSD-3-Clause
5*6f2a8791SKamlesh Gurudasani  */
6*6f2a8791SKamlesh Gurudasani 
7*6f2a8791SKamlesh Gurudasani /*
8*6f2a8791SKamlesh Gurudasani  * Device Clock Management API
9*6f2a8791SKamlesh Gurudasani  *
10*6f2a8791SKamlesh Gurudasani  * This header defines the device clock API for managing clocks attached to
11*6f2a8791SKamlesh Gurudasani  * devices. It provides clock type definitions, device clock data structures,
12*6f2a8791SKamlesh Gurudasani  * and functions for clock control including enable/disable, parent selection,
13*6f2a8791SKamlesh Gurudasani  * frequency configuration, and state management.
14*6f2a8791SKamlesh Gurudasani  */
15*6f2a8791SKamlesh Gurudasani 
16*6f2a8791SKamlesh Gurudasani #ifndef TI_DEVICE_CLK_H
17*6f2a8791SKamlesh Gurudasani #define TI_DEVICE_CLK_H
18*6f2a8791SKamlesh Gurudasani 
19*6f2a8791SKamlesh Gurudasani #include <ti_build_assert.h>
20*6f2a8791SKamlesh Gurudasani #include <ti_pm_types.h>
21*6f2a8791SKamlesh Gurudasani 
22*6f2a8791SKamlesh Gurudasani /*
23*6f2a8791SKamlesh Gurudasani  * Sentinel value for invalid or non-existent device clock ID
24*6f2a8791SKamlesh Gurudasani  *
25*6f2a8791SKamlesh Gurudasani  * Used to indicate that a device clock index is invalid, uninitialized, or
26*6f2a8791SKamlesh Gurudasani  * that no clock exists at the requested position. Functions returning
27*6f2a8791SKamlesh Gurudasani  * ti_dev_clk_idx_t use this value to signal errors or missing clocks.
28*6f2a8791SKamlesh Gurudasani  */
29*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_ID_NONE ((ti_dev_clk_idx_t) (~0U))
30*6f2a8791SKamlesh Gurudasani 
31*6f2a8791SKamlesh Gurudasani /*
32*6f2a8791SKamlesh Gurudasani  * Input clock type.
33*6f2a8791SKamlesh Gurudasani  *
34*6f2a8791SKamlesh Gurudasani  * This is a normal clock, it's an input to the IP from elsewhere.
35*6f2a8791SKamlesh Gurudasani  */
36*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_TABLE_TYPE_INPUT	0U
37*6f2a8791SKamlesh Gurudasani 
38*6f2a8791SKamlesh Gurudasani /*
39*6f2a8791SKamlesh Gurudasani  * Mux clock type.
40*6f2a8791SKamlesh Gurudasani  *
41*6f2a8791SKamlesh Gurudasani  * This is a clock mux that is meant to be controlled directly. The potential
42*6f2a8791SKamlesh Gurudasani  * parents of the mux are listed after the mux as TYPE_PARENT. Set frequency
43*6f2a8791SKamlesh Gurudasani  * calls to a mux are passed to the current parent.
44*6f2a8791SKamlesh Gurudasani  */
45*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_TABLE_TYPE_MUX		1U
46*6f2a8791SKamlesh Gurudasani 
47*6f2a8791SKamlesh Gurudasani /*
48*6f2a8791SKamlesh Gurudasani  * Mux parent clock type.
49*6f2a8791SKamlesh Gurudasani  *
50*6f2a8791SKamlesh Gurudasani  * This is a potential parent for a mux. Normal clocks are set to follow the
51*6f2a8791SKamlesh Gurudasani  * device state (requested when device is enabled, unrequested otherwise) but
52*6f2a8791SKamlesh Gurudasani  * mux parents are set to always unrequested by default. If they are selected
53*6f2a8791SKamlesh Gurudasani  * they will get a ref count from the mux clock.
54*6f2a8791SKamlesh Gurudasani  *
55*6f2a8791SKamlesh Gurudasani  * Mux parents are present so they can be enabled and configured before being
56*6f2a8791SKamlesh Gurudasani  * selected via the mux.
57*6f2a8791SKamlesh Gurudasani  */
58*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_TABLE_TYPE_PARENT	2U
59*6f2a8791SKamlesh Gurudasani 
60*6f2a8791SKamlesh Gurudasani /*
61*6f2a8791SKamlesh Gurudasani  * Output clock type.
62*6f2a8791SKamlesh Gurudasani  *
63*6f2a8791SKamlesh Gurudasani  * This is an output clock from the device. Setting the frequency informs
64*6f2a8791SKamlesh Gurudasani  * potential consumers of the frequency but otherwise has no effect.
65*6f2a8791SKamlesh Gurudasani  */
66*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_TABLE_TYPE_OUTPUT	3U
67*6f2a8791SKamlesh Gurudasani 
68*6f2a8791SKamlesh Gurudasani struct ti_device;
69*6f2a8791SKamlesh Gurudasani 
70*6f2a8791SKamlesh Gurudasani /*
71*6f2a8791SKamlesh Gurudasani  * Const clock device data
72*6f2a8791SKamlesh Gurudasani  *
73*6f2a8791SKamlesh Gurudasani  * This is the fixed data for tracking clocks attached to devices.
74*6f2a8791SKamlesh Gurudasani  */
75*6f2a8791SKamlesh Gurudasani struct ti_dev_clk_data {
76*6f2a8791SKamlesh Gurudasani 	/* Type of table entry */
77*6f2a8791SKamlesh Gurudasani 	uint8_t type;
78*6f2a8791SKamlesh Gurudasani 
79*6f2a8791SKamlesh Gurudasani 	/*
80*6f2a8791SKamlesh Gurudasani 	 * Modifying the frequency of this clock will attempt to modify
81*6f2a8791SKamlesh Gurudasani 	 * the parent freq.
82*6f2a8791SKamlesh Gurudasani 	 */
83*6f2a8791SKamlesh Gurudasani 	uint8_t modify_parent_freq;
84*6f2a8791SKamlesh Gurudasani 
85*6f2a8791SKamlesh Gurudasani 	/*
86*6f2a8791SKamlesh Gurudasani 	 * Clock divider, not valid for output, max 255 for parent otherwise
87*6f2a8791SKamlesh Gurudasani 	 * up to USHORT_MAX/8.
88*6f2a8791SKamlesh Gurudasani 	 */
89*6f2a8791SKamlesh Gurudasani 	uint16_t div;
90*6f2a8791SKamlesh Gurudasani 
91*6f2a8791SKamlesh Gurudasani 	/* For mux, the number of parents, for parents the index for the mux */
92*6f2a8791SKamlesh Gurudasani 	uint8_t idx;
93*6f2a8791SKamlesh Gurudasani 
94*6f2a8791SKamlesh Gurudasani 	/* For mux, the number of reserved parent slots */
95*6f2a8791SKamlesh Gurudasani 	uint8_t n_reserved_parents;
96*6f2a8791SKamlesh Gurudasani 
97*6f2a8791SKamlesh Gurudasani 	/* Which SoC clock this plugs into */
98*6f2a8791SKamlesh Gurudasani 	uint16_t clk;
99*6f2a8791SKamlesh Gurudasani };
100*6f2a8791SKamlesh Gurudasani 
101*6f2a8791SKamlesh Gurudasani /*
102*6f2a8791SKamlesh Gurudasani  * Dynamic clock device data
103*6f2a8791SKamlesh Gurudasani  *
104*6f2a8791SKamlesh Gurudasani  * This tracks the current state of a device attached clock via flags.
105*6f2a8791SKamlesh Gurudasani  * This is just how the upstream clock is configured for the current
106*6f2a8791SKamlesh Gurudasani  * device. The upstream clock still has its own data and state.
107*6f2a8791SKamlesh Gurudasani  *
108*6f2a8791SKamlesh Gurudasani  * A pointer to a bss that has been reserved for this data is pointed
109*6f2a8791SKamlesh Gurudasani  * to by the device. If there is only one clock on the device, the field
110*6f2a8791SKamlesh Gurudasani  * is shared with the device flags and a forced cast is made to return
111*6f2a8791SKamlesh Gurudasani  * the field.
112*6f2a8791SKamlesh Gurudasani  */
113*6f2a8791SKamlesh Gurudasani struct ti_dev_clk {
114*6f2a8791SKamlesh Gurudasani 	uint8_t flags;
115*6f2a8791SKamlesh Gurudasani };
116*6f2a8791SKamlesh Gurudasani 
117*6f2a8791SKamlesh Gurudasani /* Declare a device clock of type input */
118*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK(base, id, parent, _div)[(base) + (id)] =	\
119*6f2a8791SKamlesh Gurudasani 		{ .clk = (parent), .div = (_div),		\
120*6f2a8791SKamlesh Gurudasani 		  .type = TI_DEV_CLK_TABLE_TYPE_INPUT,		\
121*6f2a8791SKamlesh Gurudasani 		  .modify_parent_freq	= 1U }
122*6f2a8791SKamlesh Gurudasani 
123*6f2a8791SKamlesh Gurudasani /* Declare a device clock of type mux */
124*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_MUX(base, id, parent, _div, n_parents, n_reserved)[(base) + (id)] = \
125*6f2a8791SKamlesh Gurudasani 		{ .clk = (parent), .div = (_div),			\
126*6f2a8791SKamlesh Gurudasani 		  .type = TI_DEV_CLK_TABLE_TYPE_MUX,			\
127*6f2a8791SKamlesh Gurudasani 		  .idx = (n_parents),					\
128*6f2a8791SKamlesh Gurudasani 		  .n_reserved_parents = (n_reserved),			\
129*6f2a8791SKamlesh Gurudasani 		  .modify_parent_freq = 1U }
130*6f2a8791SKamlesh Gurudasani 
131*6f2a8791SKamlesh Gurudasani /*
132*6f2a8791SKamlesh Gurudasani  * Declare a device clock of type mux parent. To match clk_mux_parent,
133*6f2a8791SKamlesh Gurudasani  * divider here can only be 8 bit
134*6f2a8791SKamlesh Gurudasani  */
135*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_PARENT(base, id, parent, _div, _idx)[(base) + (id)] =	\
136*6f2a8791SKamlesh Gurudasani 		{ .clk = (parent),					\
137*6f2a8791SKamlesh Gurudasani 		  .type = TI_DEV_CLK_TABLE_TYPE_PARENT,			\
138*6f2a8791SKamlesh Gurudasani 		  .div = (_div) + (int) TI_BUILD_ASSERT_OR_ZERO(_div < 256), \
139*6f2a8791SKamlesh Gurudasani 		  .idx = (_idx),					\
140*6f2a8791SKamlesh Gurudasani 		  .modify_parent_freq	= 1U }
141*6f2a8791SKamlesh Gurudasani 
142*6f2a8791SKamlesh Gurudasani /* Declare a device clock of type output. */
143*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_OUTPUT(base, id, child)[(base) + (id)] =		\
144*6f2a8791SKamlesh Gurudasani 		{ .clk = (child),					\
145*6f2a8791SKamlesh Gurudasani 		  .type = TI_DEV_CLK_TABLE_TYPE_OUTPUT,			\
146*6f2a8791SKamlesh Gurudasani 		  .modify_parent_freq = 1U }
147*6f2a8791SKamlesh Gurudasani 
148*6f2a8791SKamlesh Gurudasani /*
149*6f2a8791SKamlesh Gurudasani  * Get the dynamic data associated with a device clock.
150*6f2a8791SKamlesh Gurudasani  */
151*6f2a8791SKamlesh Gurudasani struct ti_dev_clk *ti_get_dev_clk(struct ti_device *dev, ti_dev_clk_idx_t clk_idx);
152*6f2a8791SKamlesh Gurudasani 
153*6f2a8791SKamlesh Gurudasani /*
154*6f2a8791SKamlesh Gurudasani  * Get the const data associated with a device clock.
155*6f2a8791SKamlesh Gurudasani  */
156*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *ti_get_dev_clk_data(struct ti_device *dev, ti_dev_clk_idx_t clk_idx);
157*6f2a8791SKamlesh Gurudasani 
158*6f2a8791SKamlesh Gurudasani /*
159*6f2a8791SKamlesh Gurudasani  * Lookup the clock API clock associated with a device clock index.
160*6f2a8791SKamlesh Gurudasani  */
161*6f2a8791SKamlesh Gurudasani struct ti_clk *ti_dev_get_clk(struct ti_device *dev, ti_dev_clk_idx_t clk_idx);
162*6f2a8791SKamlesh Gurudasani 
163*6f2a8791SKamlesh Gurudasani /**
164*6f2a8791SKamlesh Gurudasani  * ti_device_clk_set_gated() - Set the gate/ungate property for a device clock
165*6f2a8791SKamlesh Gurudasani  * @dev: The device ID that the clock is connected to.
166*6f2a8791SKamlesh Gurudasani  * @clk_idx: The index of the clock on this device.
167*6f2a8791SKamlesh Gurudasani  * @gated: True to gate the clock, false to ungate.
168*6f2a8791SKamlesh Gurudasani  *
169*6f2a8791SKamlesh Gurudasani  * This sets/clears the gate/ungate property for a device clock. If a clock
170*6f2a8791SKamlesh Gurudasani  * is gated, the internal clock API clock that it references is not ref
171*6f2a8791SKamlesh Gurudasani  * counted. If it is ungated, then the refcount is incremented when the device
172*6f2a8791SKamlesh Gurudasani  * is enabled and decremented when the device is disabled.
173*6f2a8791SKamlesh Gurudasani  *
174*6f2a8791SKamlesh Gurudasani  * Return: True if operation succeeded, false if it failed or clk_idx was invalid.
175*6f2a8791SKamlesh Gurudasani  */
176*6f2a8791SKamlesh Gurudasani bool ti_device_clk_set_gated(struct ti_device *dev, ti_dev_clk_idx_t clk_idx, bool gated);
177*6f2a8791SKamlesh Gurudasani 
178*6f2a8791SKamlesh Gurudasani /**
179*6f2a8791SKamlesh Gurudasani  * ti_device_clk_get_sw_gated() - Get the current state of the gated flag.
180*6f2a8791SKamlesh Gurudasani  * @dev: The device ID that the clock is connected to.
181*6f2a8791SKamlesh Gurudasani  * @clk_idx: The index of the clock on this device.
182*6f2a8791SKamlesh Gurudasani  *
183*6f2a8791SKamlesh Gurudasani  * Return: The current state of the gated flag as set by ti_device_clk_set_gated.
184*6f2a8791SKamlesh Gurudasani  */
185*6f2a8791SKamlesh Gurudasani bool ti_device_clk_get_sw_gated(struct ti_device *dev, ti_dev_clk_idx_t clk_idx);
186*6f2a8791SKamlesh Gurudasani 
187*6f2a8791SKamlesh Gurudasani /**
188*6f2a8791SKamlesh Gurudasani  * ti_device_clk_set_parent() - Change a device mux clocks's parent.
189*6f2a8791SKamlesh Gurudasani  * @dev: The device ID that the clock mux and new parent is connected to.
190*6f2a8791SKamlesh Gurudasani  * @clk_idx: The index of the clock mux on this device.
191*6f2a8791SKamlesh Gurudasani  * @parent_idx: The index of the new clock parent on this device.
192*6f2a8791SKamlesh Gurudasani  *
193*6f2a8791SKamlesh Gurudasani  * Return: True if parent change was successful, false if it
194*6f2a8791SKamlesh Gurudasani  *         failed or one of the clock indexes was invalid.
195*6f2a8791SKamlesh Gurudasani  */
196*6f2a8791SKamlesh Gurudasani bool ti_device_clk_set_parent(struct ti_device *dev, ti_dev_clk_idx_t clk_idx,
197*6f2a8791SKamlesh Gurudasani 			      ti_dev_clk_idx_t parent_idx);
198*6f2a8791SKamlesh Gurudasani 
199*6f2a8791SKamlesh Gurudasani /*
200*6f2a8791SKamlesh Gurudasani  * Get the current parent of a device mux clock.
201*6f2a8791SKamlesh Gurudasani  */
202*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t ti_device_clk_get_parent(struct ti_device *dev, ti_dev_clk_idx_t clk_idx);
203*6f2a8791SKamlesh Gurudasani 
204*6f2a8791SKamlesh Gurudasani /*
205*6f2a8791SKamlesh Gurudasani  * Get the number of parents of a given device mux clock.
206*6f2a8791SKamlesh Gurudasani  */
207*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t ti_device_clk_get_num_parents(struct ti_device *dev,
208*6f2a8791SKamlesh Gurudasani 					       ti_dev_clk_idx_t clk_idx);
209*6f2a8791SKamlesh Gurudasani 
210*6f2a8791SKamlesh Gurudasani /**
211*6f2a8791SKamlesh Gurudasani  * ti_device_clk_set_freq() - Set the frequency of a device's clock
212*6f2a8791SKamlesh Gurudasani  * @dev: The device ID that the clock is connected to.
213*6f2a8791SKamlesh Gurudasani  * @clk_idx: The index of the clock on this device.
214*6f2a8791SKamlesh Gurudasani  * @min_freq_hz: The minimum acceptable frequency (Hz).
215*6f2a8791SKamlesh Gurudasani  * @target_freq_hz: The target frequency in Hz. The clock API will
216*6f2a8791SKamlesh Gurudasani  *                  attempt to set a frequency as close as possible.
217*6f2a8791SKamlesh Gurudasani  * @max_freq_hz: The maximum acceptable frequency (Hz).
218*6f2a8791SKamlesh Gurudasani  *
219*6f2a8791SKamlesh Gurudasani  * This locates the correct clock and calls the internal clock API
220*6f2a8791SKamlesh Gurudasani  * set function. If the clock is a mux type, we instead send the request to
221*6f2a8791SKamlesh Gurudasani  * the parent. This is because calling set freq on the mux may switch the mux
222*6f2a8791SKamlesh Gurudasani  * which is not what we want on muxes that are exposed on devices.
223*6f2a8791SKamlesh Gurudasani  *
224*6f2a8791SKamlesh Gurudasani  * Return: True if the new frequency was accepted, false otherwise.
225*6f2a8791SKamlesh Gurudasani  */
226*6f2a8791SKamlesh Gurudasani bool ti_device_clk_set_freq(struct ti_device *dev, ti_dev_clk_idx_t clk_idx,
227*6f2a8791SKamlesh Gurudasani 			    uint32_t min_freq_hz, uint32_t target_freq_hz,
228*6f2a8791SKamlesh Gurudasani 			    uint32_t max_freq_hz);
229*6f2a8791SKamlesh Gurudasani 
230*6f2a8791SKamlesh Gurudasani /**
231*6f2a8791SKamlesh Gurudasani  * ti_device_clk_get_freq() - Get the current frequency of a device clock.
232*6f2a8791SKamlesh Gurudasani  * @dev: The device ID that the clock is connected to.
233*6f2a8791SKamlesh Gurudasani  * @clk_idx: The index of the clock on this device.
234*6f2a8791SKamlesh Gurudasani  *
235*6f2a8791SKamlesh Gurudasani  * Return: Current clock frequency in Hz if enabled, or the
236*6f2a8791SKamlesh Gurudasani  *         frequency it would run at if enabled. Returns 0 if
237*6f2a8791SKamlesh Gurudasani  *         clk_idx is invalid or the clock cannot run.
238*6f2a8791SKamlesh Gurudasani  */
239*6f2a8791SKamlesh Gurudasani uint32_t ti_device_clk_get_freq(struct ti_device *dev, ti_dev_clk_idx_t clk_idx);
240*6f2a8791SKamlesh Gurudasani 
241*6f2a8791SKamlesh Gurudasani /**
242*6f2a8791SKamlesh Gurudasani  * ti_device_clk_enable() - Enable a device clock
243*6f2a8791SKamlesh Gurudasani  * @dev: The device ID that the clock is connected to.
244*6f2a8791SKamlesh Gurudasani  * @clk_idx: The index of the clock on this device.
245*6f2a8791SKamlesh Gurudasani  *
246*6f2a8791SKamlesh Gurudasani  * This is called by the device pm code for each clock when the device is
247*6f2a8791SKamlesh Gurudasani  * enabled. This allows the device clk code to take appropriate action.
248*6f2a8791SKamlesh Gurudasani  */
249*6f2a8791SKamlesh Gurudasani void ti_device_clk_enable(struct ti_device *dev, ti_dev_clk_idx_t clk_idx);
250*6f2a8791SKamlesh Gurudasani 
251*6f2a8791SKamlesh Gurudasani /**
252*6f2a8791SKamlesh Gurudasani  * ti_device_clk_disable() - Disable a device clock
253*6f2a8791SKamlesh Gurudasani  * @dev: The device ID that the clock is connected to.
254*6f2a8791SKamlesh Gurudasani  * @clk_idx: The index of the clock on this device.
255*6f2a8791SKamlesh Gurudasani  *
256*6f2a8791SKamlesh Gurudasani  * This is called by the device pm code for each clock when the device is
257*6f2a8791SKamlesh Gurudasani  * disabled. This allows the device clk code to take appropriate action.
258*6f2a8791SKamlesh Gurudasani  */
259*6f2a8791SKamlesh Gurudasani void ti_device_clk_disable(struct ti_device *dev, ti_dev_clk_idx_t clk_idx);
260*6f2a8791SKamlesh Gurudasani 
261*6f2a8791SKamlesh Gurudasani /**
262*6f2a8791SKamlesh Gurudasani  * ti_device_clk_init() - Initialize a device clock
263*6f2a8791SKamlesh Gurudasani  * @dev: The device ID that the clock is connected to.
264*6f2a8791SKamlesh Gurudasani  * @clk_idx: The index of the clock on this device.
265*6f2a8791SKamlesh Gurudasani  *
266*6f2a8791SKamlesh Gurudasani  * This is called by the device pm code for each clock when the device is
267*6f2a8791SKamlesh Gurudasani  * disabled. This allows the device clk code to take appropriate action such
268*6f2a8791SKamlesh Gurudasani  * setting default state.
269*6f2a8791SKamlesh Gurudasani  */
270*6f2a8791SKamlesh Gurudasani void ti_device_clk_init(struct ti_device *dev, ti_dev_clk_idx_t clk_idx);
271*6f2a8791SKamlesh Gurudasani 
272*6f2a8791SKamlesh Gurudasani #endif /* TI_DEVICE_CLK_H */
273