xref: /optee_os/core/drivers/clk/clk.c (revision 2305544b3b9bce764141c863985a7ab44c98657c)
1*2305544bSClément Léger // SPDX-License-Identifier: BSD-2-Clause
2*2305544bSClément Léger /*
3*2305544bSClément Léger  * Copyright (c) 2021, Bootlin
4*2305544bSClément Léger  */
5*2305544bSClément Léger 
6*2305544bSClément Léger #include <drivers/clk.h>
7*2305544bSClément Léger #include <kernel/boot.h>
8*2305544bSClément Léger #include <kernel/panic.h>
9*2305544bSClément Léger #include <kernel/spinlock.h>
10*2305544bSClément Léger #include <libfdt.h>
11*2305544bSClément Léger #include <malloc.h>
12*2305544bSClément Léger #include <stddef.h>
13*2305544bSClément Léger 
14*2305544bSClément Léger /* Global clock tree lock */
15*2305544bSClément Léger static unsigned int clk_lock = SPINLOCK_UNLOCK;
16*2305544bSClément Léger 
17*2305544bSClément Léger struct clk *clk_alloc(const char *name, const struct clk_ops *ops,
18*2305544bSClément Léger 		      struct clk **parent_clks, size_t parent_count)
19*2305544bSClément Léger {
20*2305544bSClément Léger 	struct clk *clk = NULL;
21*2305544bSClément Léger 	size_t parent = 0;
22*2305544bSClément Léger 
23*2305544bSClément Léger 	clk = calloc(1, sizeof(*clk) + parent_count * sizeof(clk));
24*2305544bSClément Léger 	if (!clk)
25*2305544bSClément Léger 		return NULL;
26*2305544bSClément Léger 
27*2305544bSClément Léger 	clk->num_parents = parent_count;
28*2305544bSClément Léger 	for (parent = 0; parent < parent_count; parent++)
29*2305544bSClément Léger 		clk->parents[parent] = parent_clks[parent];
30*2305544bSClément Léger 
31*2305544bSClément Léger 	clk->name = name;
32*2305544bSClément Léger 	clk->ops = ops;
33*2305544bSClément Léger 	refcount_set(&clk->enabled_count, 0);
34*2305544bSClément Léger 
35*2305544bSClément Léger 	return clk;
36*2305544bSClément Léger }
37*2305544bSClément Léger 
38*2305544bSClément Léger void clk_free(struct clk *clk)
39*2305544bSClément Léger {
40*2305544bSClément Léger 	free(clk);
41*2305544bSClément Léger }
42*2305544bSClément Léger 
43*2305544bSClément Léger static bool __maybe_unused clk_check(struct clk *clk)
44*2305544bSClément Léger {
45*2305544bSClément Léger 	if (!clk->ops)
46*2305544bSClément Léger 		return false;
47*2305544bSClément Léger 
48*2305544bSClément Léger 	if (clk->ops->set_parent && !clk->ops->get_parent)
49*2305544bSClément Léger 		return false;
50*2305544bSClément Léger 
51*2305544bSClément Léger 	if (clk->num_parents > 1 && !clk->ops->get_parent)
52*2305544bSClément Léger 		return false;
53*2305544bSClément Léger 
54*2305544bSClément Léger 	return true;
55*2305544bSClément Léger }
56*2305544bSClément Léger 
57*2305544bSClément Léger static void clk_compute_rate_no_lock(struct clk *clk)
58*2305544bSClément Léger {
59*2305544bSClément Léger 	unsigned long parent_rate = 0;
60*2305544bSClément Léger 
61*2305544bSClément Léger 	if (clk->parent)
62*2305544bSClément Léger 		parent_rate = clk->parent->rate;
63*2305544bSClément Léger 
64*2305544bSClément Léger 	if (clk->ops->get_rate)
65*2305544bSClément Léger 		clk->rate = clk->ops->get_rate(clk, parent_rate);
66*2305544bSClément Léger 	else
67*2305544bSClément Léger 		clk->rate = parent_rate;
68*2305544bSClément Léger }
69*2305544bSClément Léger 
70*2305544bSClément Léger struct clk *clk_get_parent_by_index(struct clk *clk, size_t pidx)
71*2305544bSClément Léger {
72*2305544bSClément Léger 	if (pidx >= clk->num_parents)
73*2305544bSClément Léger 		return NULL;
74*2305544bSClément Léger 
75*2305544bSClément Léger 	return clk->parents[pidx];
76*2305544bSClément Léger }
77*2305544bSClément Léger 
78*2305544bSClément Léger static void clk_init_parent(struct clk *clk)
79*2305544bSClément Léger {
80*2305544bSClément Léger 	size_t pidx = 0;
81*2305544bSClément Léger 
82*2305544bSClément Léger 	switch (clk->num_parents) {
83*2305544bSClément Léger 	case 0:
84*2305544bSClément Léger 		break;
85*2305544bSClément Léger 	case 1:
86*2305544bSClément Léger 		clk->parent = clk->parents[0];
87*2305544bSClément Léger 		break;
88*2305544bSClément Léger 	default:
89*2305544bSClément Léger 		pidx = clk->ops->get_parent(clk);
90*2305544bSClément Léger 		assert(pidx < clk->num_parents);
91*2305544bSClément Léger 
92*2305544bSClément Léger 		clk->parent = clk->parents[pidx];
93*2305544bSClément Léger 		break;
94*2305544bSClément Léger 	}
95*2305544bSClément Léger }
96*2305544bSClément Léger 
97*2305544bSClément Léger TEE_Result clk_register(struct clk *clk)
98*2305544bSClément Léger {
99*2305544bSClément Léger 	assert(clk_check(clk));
100*2305544bSClément Léger 
101*2305544bSClément Léger 	clk_init_parent(clk);
102*2305544bSClément Léger 	clk_compute_rate_no_lock(clk);
103*2305544bSClément Léger 
104*2305544bSClément Léger 	DMSG("Registered clock %s, freq %lu", clk->name, clk_get_rate(clk));
105*2305544bSClément Léger 
106*2305544bSClément Léger 	return TEE_SUCCESS;
107*2305544bSClément Léger }
108*2305544bSClément Léger 
109*2305544bSClément Léger static bool clk_is_enabled_no_lock(struct clk *clk)
110*2305544bSClément Léger {
111*2305544bSClément Léger 	return refcount_val(&clk->enabled_count) != 0;
112*2305544bSClément Léger }
113*2305544bSClément Léger 
114*2305544bSClément Léger static void clk_disable_no_lock(struct clk *clk)
115*2305544bSClément Léger {
116*2305544bSClément Léger 	struct clk *parent = NULL;
117*2305544bSClément Léger 
118*2305544bSClément Léger 	if (!refcount_dec(&clk->enabled_count))
119*2305544bSClément Léger 		return;
120*2305544bSClément Léger 
121*2305544bSClément Léger 	if (clk->ops->disable)
122*2305544bSClément Léger 		clk->ops->disable(clk);
123*2305544bSClément Léger 
124*2305544bSClément Léger 	parent = clk_get_parent(clk);
125*2305544bSClément Léger 	if (parent)
126*2305544bSClément Léger 		clk_disable_no_lock(parent);
127*2305544bSClément Léger }
128*2305544bSClément Léger 
129*2305544bSClément Léger static TEE_Result clk_enable_no_lock(struct clk *clk)
130*2305544bSClément Léger {
131*2305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
132*2305544bSClément Léger 	struct clk *parent = NULL;
133*2305544bSClément Léger 
134*2305544bSClément Léger 	if (refcount_inc(&clk->enabled_count))
135*2305544bSClément Léger 		return TEE_SUCCESS;
136*2305544bSClément Léger 
137*2305544bSClément Léger 	parent = clk_get_parent(clk);
138*2305544bSClément Léger 	if (parent) {
139*2305544bSClément Léger 		res = clk_enable_no_lock(parent);
140*2305544bSClément Léger 		if (res)
141*2305544bSClément Léger 			return res;
142*2305544bSClément Léger 	}
143*2305544bSClément Léger 
144*2305544bSClément Léger 	if (clk->ops->enable) {
145*2305544bSClément Léger 		res = clk->ops->enable(clk);
146*2305544bSClément Léger 		if (res) {
147*2305544bSClément Léger 			if (parent)
148*2305544bSClément Léger 				clk_disable_no_lock(parent);
149*2305544bSClément Léger 
150*2305544bSClément Léger 			return res;
151*2305544bSClément Léger 		}
152*2305544bSClément Léger 	}
153*2305544bSClément Léger 
154*2305544bSClément Léger 	refcount_set(&clk->enabled_count, 1);
155*2305544bSClément Léger 
156*2305544bSClément Léger 	return TEE_SUCCESS;
157*2305544bSClément Léger }
158*2305544bSClément Léger 
159*2305544bSClément Léger TEE_Result clk_enable(struct clk *clk)
160*2305544bSClément Léger {
161*2305544bSClément Léger 	uint32_t exceptions = 0;
162*2305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
163*2305544bSClément Léger 
164*2305544bSClément Léger 	exceptions = cpu_spin_lock_xsave(&clk_lock);
165*2305544bSClément Léger 	res = clk_enable_no_lock(clk);
166*2305544bSClément Léger 	cpu_spin_unlock_xrestore(&clk_lock, exceptions);
167*2305544bSClément Léger 
168*2305544bSClément Léger 	return res;
169*2305544bSClément Léger }
170*2305544bSClément Léger 
171*2305544bSClément Léger void clk_disable(struct clk *clk)
172*2305544bSClément Léger {
173*2305544bSClément Léger 	uint32_t exceptions = 0;
174*2305544bSClément Léger 
175*2305544bSClément Léger 	exceptions = cpu_spin_lock_xsave(&clk_lock);
176*2305544bSClément Léger 	clk_disable_no_lock(clk);
177*2305544bSClément Léger 	cpu_spin_unlock_xrestore(&clk_lock, exceptions);
178*2305544bSClément Léger }
179*2305544bSClément Léger 
180*2305544bSClément Léger unsigned long clk_get_rate(struct clk *clk)
181*2305544bSClément Léger {
182*2305544bSClément Léger 	return clk->rate;
183*2305544bSClément Léger }
184*2305544bSClément Léger 
185*2305544bSClément Léger static TEE_Result clk_set_rate_no_lock(struct clk *clk, unsigned long rate)
186*2305544bSClément Léger {
187*2305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
188*2305544bSClément Léger 	unsigned long parent_rate = 0;
189*2305544bSClément Léger 
190*2305544bSClément Léger 	if (clk->parent)
191*2305544bSClément Léger 		parent_rate = clk_get_rate(clk->parent);
192*2305544bSClément Léger 
193*2305544bSClément Léger 	res = clk->ops->set_rate(clk, rate, parent_rate);
194*2305544bSClément Léger 	if (res)
195*2305544bSClément Léger 		return res;
196*2305544bSClément Léger 
197*2305544bSClément Léger 	clk_compute_rate_no_lock(clk);
198*2305544bSClément Léger 
199*2305544bSClément Léger 	return TEE_SUCCESS;
200*2305544bSClément Léger }
201*2305544bSClément Léger 
202*2305544bSClément Léger TEE_Result clk_set_rate(struct clk *clk, unsigned long rate)
203*2305544bSClément Léger {
204*2305544bSClément Léger 	uint32_t exceptions = 0;
205*2305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
206*2305544bSClément Léger 
207*2305544bSClément Léger 	if (!clk->ops->set_rate)
208*2305544bSClément Léger 		return TEE_ERROR_NOT_SUPPORTED;
209*2305544bSClément Léger 
210*2305544bSClément Léger 	exceptions =  cpu_spin_lock_xsave(&clk_lock);
211*2305544bSClément Léger 
212*2305544bSClément Léger 	if (clk->flags & CLK_SET_RATE_GATE && clk_is_enabled_no_lock(clk))
213*2305544bSClément Léger 		res = TEE_ERROR_BAD_STATE;
214*2305544bSClément Léger 	else
215*2305544bSClément Léger 		res = clk_set_rate_no_lock(clk, rate);
216*2305544bSClément Léger 
217*2305544bSClément Léger 	cpu_spin_unlock_xrestore(&clk_lock, exceptions);
218*2305544bSClément Léger 
219*2305544bSClément Léger 	return res;
220*2305544bSClément Léger }
221*2305544bSClément Léger 
222*2305544bSClément Léger struct clk *clk_get_parent(struct clk *clk)
223*2305544bSClément Léger {
224*2305544bSClément Léger 	return clk->parent;
225*2305544bSClément Léger }
226*2305544bSClément Léger 
227*2305544bSClément Léger static TEE_Result clk_get_parent_idx(struct clk *clk, struct clk *parent,
228*2305544bSClément Léger 				     size_t *pidx)
229*2305544bSClément Léger {
230*2305544bSClément Léger 	size_t i = 0;
231*2305544bSClément Léger 
232*2305544bSClément Léger 	for (i = 0; i < clk_get_num_parents(clk); i++) {
233*2305544bSClément Léger 		if (clk_get_parent_by_index(clk, i) == parent) {
234*2305544bSClément Léger 			*pidx = i;
235*2305544bSClément Léger 			return TEE_SUCCESS;
236*2305544bSClément Léger 		}
237*2305544bSClément Léger 	}
238*2305544bSClément Léger 	EMSG("Clock %s is not a parent of clock %s", parent->name, clk->name);
239*2305544bSClément Léger 
240*2305544bSClément Léger 	return TEE_ERROR_BAD_PARAMETERS;
241*2305544bSClément Léger }
242*2305544bSClément Léger 
243*2305544bSClément Léger static TEE_Result clk_set_parent_no_lock(struct clk *clk, struct clk *parent,
244*2305544bSClément Léger 					 size_t pidx)
245*2305544bSClément Léger {
246*2305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
247*2305544bSClément Léger 	bool was_enabled = false;
248*2305544bSClément Léger 
249*2305544bSClément Léger 	/* Requested parent is already the one set */
250*2305544bSClément Léger 	if (clk->parent == parent)
251*2305544bSClément Léger 		return TEE_SUCCESS;
252*2305544bSClément Léger 
253*2305544bSClément Léger 	was_enabled = clk_is_enabled_no_lock(clk);
254*2305544bSClément Léger 	/* Call is needed to decrement refcount on current parent tree */
255*2305544bSClément Léger 	if (was_enabled)
256*2305544bSClément Léger 		clk_disable_no_lock(clk);
257*2305544bSClément Léger 
258*2305544bSClément Léger 	res = clk->ops->set_parent(clk, pidx);
259*2305544bSClément Léger 	if (res)
260*2305544bSClément Léger 		goto out;
261*2305544bSClément Léger 
262*2305544bSClément Léger 	clk->parent = parent;
263*2305544bSClément Léger 
264*2305544bSClément Léger 	/* The parent changed and the rate might also have changed */
265*2305544bSClément Léger 	clk_compute_rate_no_lock(clk);
266*2305544bSClément Léger 
267*2305544bSClément Léger out:
268*2305544bSClément Léger 	/* Call is needed to increment refcount on the new parent tree */
269*2305544bSClément Léger 	if (was_enabled) {
270*2305544bSClément Léger 		res = clk_enable_no_lock(clk);
271*2305544bSClément Léger 		if (res)
272*2305544bSClément Léger 			panic("Failed to re-enable clock after setting parent");
273*2305544bSClément Léger 	}
274*2305544bSClément Léger 
275*2305544bSClément Léger 	return res;
276*2305544bSClément Léger }
277*2305544bSClément Léger 
278*2305544bSClément Léger TEE_Result clk_set_parent(struct clk *clk, struct clk *parent)
279*2305544bSClément Léger {
280*2305544bSClément Léger 	size_t pidx = 0;
281*2305544bSClément Léger 	uint32_t exceptions = 0;
282*2305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
283*2305544bSClément Léger 
284*2305544bSClément Léger 	if (clk_get_parent_idx(clk, parent, &pidx) || !clk->ops->set_parent)
285*2305544bSClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
286*2305544bSClément Léger 
287*2305544bSClément Léger 	exceptions = cpu_spin_lock_xsave(&clk_lock);
288*2305544bSClément Léger 	if (clk->flags & CLK_SET_PARENT_GATE && clk_is_enabled_no_lock(clk)) {
289*2305544bSClément Léger 		res = TEE_ERROR_BAD_STATE;
290*2305544bSClément Léger 		goto out;
291*2305544bSClément Léger 	}
292*2305544bSClément Léger 
293*2305544bSClément Léger 	res = clk_set_parent_no_lock(clk, parent, pidx);
294*2305544bSClément Léger out:
295*2305544bSClément Léger 	cpu_spin_unlock_xrestore(&clk_lock, exceptions);
296*2305544bSClément Léger 
297*2305544bSClément Léger 	return res;
298*2305544bSClément Léger }
299