xref: /optee_os/core/drivers/clk/clk.c (revision 5df61a5dd7d4b519bef61e57ed2d89970e6bac52)
12305544bSClément Léger // SPDX-License-Identifier: BSD-2-Clause
22305544bSClément Léger /*
32305544bSClément Léger  * Copyright (c) 2021, Bootlin
42305544bSClément Léger  */
52305544bSClément Léger 
62305544bSClément Léger #include <drivers/clk.h>
72305544bSClément Léger #include <kernel/boot.h>
82305544bSClément Léger #include <kernel/panic.h>
92305544bSClément Léger #include <kernel/spinlock.h>
102305544bSClément Léger #include <libfdt.h>
112305544bSClément Léger #include <malloc.h>
122305544bSClément Léger #include <stddef.h>
132305544bSClément Léger 
142305544bSClément Léger /* Global clock tree lock */
152305544bSClément Léger static unsigned int clk_lock = SPINLOCK_UNLOCK;
162305544bSClément Léger 
172305544bSClément Léger struct clk *clk_alloc(const char *name, const struct clk_ops *ops,
182305544bSClément Léger 		      struct clk **parent_clks, size_t parent_count)
192305544bSClément Léger {
202305544bSClément Léger 	struct clk *clk = NULL;
212305544bSClément Léger 	size_t parent = 0;
222305544bSClément Léger 
232305544bSClément Léger 	clk = calloc(1, sizeof(*clk) + parent_count * sizeof(clk));
242305544bSClément Léger 	if (!clk)
252305544bSClément Léger 		return NULL;
262305544bSClément Léger 
272305544bSClément Léger 	clk->num_parents = parent_count;
282305544bSClément Léger 	for (parent = 0; parent < parent_count; parent++)
292305544bSClément Léger 		clk->parents[parent] = parent_clks[parent];
302305544bSClément Léger 
312305544bSClément Léger 	clk->name = name;
322305544bSClément Léger 	clk->ops = ops;
332305544bSClément Léger 	refcount_set(&clk->enabled_count, 0);
342305544bSClément Léger 
352305544bSClément Léger 	return clk;
362305544bSClément Léger }
372305544bSClément Léger 
382305544bSClément Léger void clk_free(struct clk *clk)
392305544bSClément Léger {
402305544bSClément Léger 	free(clk);
412305544bSClément Léger }
422305544bSClément Léger 
432305544bSClément Léger static bool __maybe_unused clk_check(struct clk *clk)
442305544bSClément Léger {
452305544bSClément Léger 	if (!clk->ops)
462305544bSClément Léger 		return false;
472305544bSClément Léger 
482305544bSClément Léger 	if (clk->ops->set_parent && !clk->ops->get_parent)
492305544bSClément Léger 		return false;
502305544bSClément Léger 
512305544bSClément Léger 	if (clk->num_parents > 1 && !clk->ops->get_parent)
522305544bSClément Léger 		return false;
532305544bSClément Léger 
542305544bSClément Léger 	return true;
552305544bSClément Léger }
562305544bSClément Léger 
572305544bSClément Léger static void clk_compute_rate_no_lock(struct clk *clk)
582305544bSClément Léger {
592305544bSClément Léger 	unsigned long parent_rate = 0;
602305544bSClément Léger 
612305544bSClément Léger 	if (clk->parent)
622305544bSClément Léger 		parent_rate = clk->parent->rate;
632305544bSClément Léger 
642305544bSClément Léger 	if (clk->ops->get_rate)
652305544bSClément Léger 		clk->rate = clk->ops->get_rate(clk, parent_rate);
662305544bSClément Léger 	else
672305544bSClément Léger 		clk->rate = parent_rate;
682305544bSClément Léger }
692305544bSClément Léger 
702305544bSClément Léger struct clk *clk_get_parent_by_index(struct clk *clk, size_t pidx)
712305544bSClément Léger {
722305544bSClément Léger 	if (pidx >= clk->num_parents)
732305544bSClément Léger 		return NULL;
742305544bSClément Léger 
752305544bSClément Léger 	return clk->parents[pidx];
762305544bSClément Léger }
772305544bSClément Léger 
782305544bSClément Léger static void clk_init_parent(struct clk *clk)
792305544bSClément Léger {
802305544bSClément Léger 	size_t pidx = 0;
812305544bSClément Léger 
822305544bSClément Léger 	switch (clk->num_parents) {
832305544bSClément Léger 	case 0:
842305544bSClément Léger 		break;
852305544bSClément Léger 	case 1:
862305544bSClément Léger 		clk->parent = clk->parents[0];
872305544bSClément Léger 		break;
882305544bSClément Léger 	default:
892305544bSClément Léger 		pidx = clk->ops->get_parent(clk);
902305544bSClément Léger 		assert(pidx < clk->num_parents);
912305544bSClément Léger 
922305544bSClément Léger 		clk->parent = clk->parents[pidx];
932305544bSClément Léger 		break;
942305544bSClément Léger 	}
952305544bSClément Léger }
962305544bSClément Léger 
972305544bSClément Léger TEE_Result clk_register(struct clk *clk)
982305544bSClément Léger {
992305544bSClément Léger 	assert(clk_check(clk));
1002305544bSClément Léger 
1012305544bSClément Léger 	clk_init_parent(clk);
1022305544bSClément Léger 	clk_compute_rate_no_lock(clk);
1032305544bSClément Léger 
1042305544bSClément Léger 	DMSG("Registered clock %s, freq %lu", clk->name, clk_get_rate(clk));
1052305544bSClément Léger 
1062305544bSClément Léger 	return TEE_SUCCESS;
1072305544bSClément Léger }
1082305544bSClément Léger 
1092305544bSClément Léger static bool clk_is_enabled_no_lock(struct clk *clk)
1102305544bSClément Léger {
1112305544bSClément Léger 	return refcount_val(&clk->enabled_count) != 0;
1122305544bSClément Léger }
1132305544bSClément Léger 
1146c9ed842SEtienne Carriere bool clk_is_enabled(struct clk *clk)
1156c9ed842SEtienne Carriere {
1166c9ed842SEtienne Carriere 	return clk_is_enabled_no_lock(clk);
1176c9ed842SEtienne Carriere }
1186c9ed842SEtienne Carriere 
1192305544bSClément Léger static void clk_disable_no_lock(struct clk *clk)
1202305544bSClément Léger {
1212305544bSClément Léger 	struct clk *parent = NULL;
1222305544bSClément Léger 
1232305544bSClément Léger 	if (!refcount_dec(&clk->enabled_count))
1242305544bSClément Léger 		return;
1252305544bSClément Léger 
1262305544bSClément Léger 	if (clk->ops->disable)
1272305544bSClément Léger 		clk->ops->disable(clk);
1282305544bSClément Léger 
1292305544bSClément Léger 	parent = clk_get_parent(clk);
1302305544bSClément Léger 	if (parent)
1312305544bSClément Léger 		clk_disable_no_lock(parent);
1322305544bSClément Léger }
1332305544bSClément Léger 
1342305544bSClément Léger static TEE_Result clk_enable_no_lock(struct clk *clk)
1352305544bSClément Léger {
1362305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
1372305544bSClément Léger 	struct clk *parent = NULL;
1382305544bSClément Léger 
1392305544bSClément Léger 	if (refcount_inc(&clk->enabled_count))
1402305544bSClément Léger 		return TEE_SUCCESS;
1412305544bSClément Léger 
1422305544bSClément Léger 	parent = clk_get_parent(clk);
1432305544bSClément Léger 	if (parent) {
1442305544bSClément Léger 		res = clk_enable_no_lock(parent);
1452305544bSClément Léger 		if (res)
1462305544bSClément Léger 			return res;
1472305544bSClément Léger 	}
1482305544bSClément Léger 
1492305544bSClément Léger 	if (clk->ops->enable) {
1502305544bSClément Léger 		res = clk->ops->enable(clk);
1512305544bSClément Léger 		if (res) {
1522305544bSClément Léger 			if (parent)
1532305544bSClément Léger 				clk_disable_no_lock(parent);
1542305544bSClément Léger 
1552305544bSClément Léger 			return res;
1562305544bSClément Léger 		}
1572305544bSClément Léger 	}
1582305544bSClément Léger 
1592305544bSClément Léger 	refcount_set(&clk->enabled_count, 1);
1602305544bSClément Léger 
1612305544bSClément Léger 	return TEE_SUCCESS;
1622305544bSClément Léger }
1632305544bSClément Léger 
1642305544bSClément Léger TEE_Result clk_enable(struct clk *clk)
1652305544bSClément Léger {
1662305544bSClément Léger 	uint32_t exceptions = 0;
1672305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
1682305544bSClément Léger 
1692305544bSClément Léger 	exceptions = cpu_spin_lock_xsave(&clk_lock);
1702305544bSClément Léger 	res = clk_enable_no_lock(clk);
1712305544bSClément Léger 	cpu_spin_unlock_xrestore(&clk_lock, exceptions);
1722305544bSClément Léger 
1732305544bSClément Léger 	return res;
1742305544bSClément Léger }
1752305544bSClément Léger 
1762305544bSClément Léger void clk_disable(struct clk *clk)
1772305544bSClément Léger {
1782305544bSClément Léger 	uint32_t exceptions = 0;
1792305544bSClément Léger 
1802305544bSClément Léger 	exceptions = cpu_spin_lock_xsave(&clk_lock);
1812305544bSClément Léger 	clk_disable_no_lock(clk);
1822305544bSClément Léger 	cpu_spin_unlock_xrestore(&clk_lock, exceptions);
1832305544bSClément Léger }
1842305544bSClément Léger 
1852305544bSClément Léger unsigned long clk_get_rate(struct clk *clk)
1862305544bSClément Léger {
1872305544bSClément Léger 	return clk->rate;
1882305544bSClément Léger }
1892305544bSClément Léger 
1902305544bSClément Léger static TEE_Result clk_set_rate_no_lock(struct clk *clk, unsigned long rate)
1912305544bSClément Léger {
1922305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
1932305544bSClément Léger 	unsigned long parent_rate = 0;
1942305544bSClément Léger 
1952305544bSClément Léger 	if (clk->parent)
1962305544bSClément Léger 		parent_rate = clk_get_rate(clk->parent);
1972305544bSClément Léger 
1982305544bSClément Léger 	res = clk->ops->set_rate(clk, rate, parent_rate);
1992305544bSClément Léger 	if (res)
2002305544bSClément Léger 		return res;
2012305544bSClément Léger 
2022305544bSClément Léger 	clk_compute_rate_no_lock(clk);
2032305544bSClément Léger 
2042305544bSClément Léger 	return TEE_SUCCESS;
2052305544bSClément Léger }
2062305544bSClément Léger 
2072305544bSClément Léger TEE_Result clk_set_rate(struct clk *clk, unsigned long rate)
2082305544bSClément Léger {
2092305544bSClément Léger 	uint32_t exceptions = 0;
2102305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
2112305544bSClément Léger 
2122305544bSClément Léger 	if (!clk->ops->set_rate)
2132305544bSClément Léger 		return TEE_ERROR_NOT_SUPPORTED;
2142305544bSClément Léger 
2152305544bSClément Léger 	exceptions =  cpu_spin_lock_xsave(&clk_lock);
2162305544bSClément Léger 
2172305544bSClément Léger 	if (clk->flags & CLK_SET_RATE_GATE && clk_is_enabled_no_lock(clk))
2182305544bSClément Léger 		res = TEE_ERROR_BAD_STATE;
2192305544bSClément Léger 	else
2202305544bSClément Léger 		res = clk_set_rate_no_lock(clk, rate);
2212305544bSClément Léger 
2222305544bSClément Léger 	cpu_spin_unlock_xrestore(&clk_lock, exceptions);
2232305544bSClément Léger 
2242305544bSClément Léger 	return res;
2252305544bSClément Léger }
2262305544bSClément Léger 
2272305544bSClément Léger struct clk *clk_get_parent(struct clk *clk)
2282305544bSClément Léger {
2292305544bSClément Léger 	return clk->parent;
2302305544bSClément Léger }
2312305544bSClément Léger 
2322305544bSClément Léger static TEE_Result clk_get_parent_idx(struct clk *clk, struct clk *parent,
2332305544bSClément Léger 				     size_t *pidx)
2342305544bSClément Léger {
2352305544bSClément Léger 	size_t i = 0;
2362305544bSClément Léger 
2372305544bSClément Léger 	for (i = 0; i < clk_get_num_parents(clk); i++) {
2382305544bSClément Léger 		if (clk_get_parent_by_index(clk, i) == parent) {
2392305544bSClément Léger 			*pidx = i;
2402305544bSClément Léger 			return TEE_SUCCESS;
2412305544bSClément Léger 		}
2422305544bSClément Léger 	}
2432305544bSClément Léger 	EMSG("Clock %s is not a parent of clock %s", parent->name, clk->name);
2442305544bSClément Léger 
2452305544bSClément Léger 	return TEE_ERROR_BAD_PARAMETERS;
2462305544bSClément Léger }
2472305544bSClément Léger 
2482305544bSClément Léger static TEE_Result clk_set_parent_no_lock(struct clk *clk, struct clk *parent,
2492305544bSClément Léger 					 size_t pidx)
2502305544bSClément Léger {
2512305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
2522305544bSClément Léger 	bool was_enabled = false;
2532305544bSClément Léger 
2542305544bSClément Léger 	/* Requested parent is already the one set */
2552305544bSClément Léger 	if (clk->parent == parent)
2562305544bSClément Léger 		return TEE_SUCCESS;
2572305544bSClément Léger 
2582305544bSClément Léger 	was_enabled = clk_is_enabled_no_lock(clk);
2592305544bSClément Léger 	/* Call is needed to decrement refcount on current parent tree */
2602305544bSClément Léger 	if (was_enabled)
2612305544bSClément Léger 		clk_disable_no_lock(clk);
2622305544bSClément Léger 
2632305544bSClément Léger 	res = clk->ops->set_parent(clk, pidx);
2642305544bSClément Léger 	if (res)
2652305544bSClément Léger 		goto out;
2662305544bSClément Léger 
2672305544bSClément Léger 	clk->parent = parent;
2682305544bSClément Léger 
2692305544bSClément Léger 	/* The parent changed and the rate might also have changed */
2702305544bSClément Léger 	clk_compute_rate_no_lock(clk);
2712305544bSClément Léger 
2722305544bSClément Léger out:
2732305544bSClément Léger 	/* Call is needed to increment refcount on the new parent tree */
2742305544bSClément Léger 	if (was_enabled) {
2752305544bSClément Léger 		res = clk_enable_no_lock(clk);
2762305544bSClément Léger 		if (res)
2772305544bSClément Léger 			panic("Failed to re-enable clock after setting parent");
2782305544bSClément Léger 	}
2792305544bSClément Léger 
2802305544bSClément Léger 	return res;
2812305544bSClément Léger }
2822305544bSClément Léger 
2832305544bSClément Léger TEE_Result clk_set_parent(struct clk *clk, struct clk *parent)
2842305544bSClément Léger {
2852305544bSClément Léger 	size_t pidx = 0;
2862305544bSClément Léger 	uint32_t exceptions = 0;
2872305544bSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
2882305544bSClément Léger 
2892305544bSClément Léger 	if (clk_get_parent_idx(clk, parent, &pidx) || !clk->ops->set_parent)
2902305544bSClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
2912305544bSClément Léger 
2922305544bSClément Léger 	exceptions = cpu_spin_lock_xsave(&clk_lock);
2932305544bSClément Léger 	if (clk->flags & CLK_SET_PARENT_GATE && clk_is_enabled_no_lock(clk)) {
2942305544bSClément Léger 		res = TEE_ERROR_BAD_STATE;
2952305544bSClément Léger 		goto out;
2962305544bSClément Léger 	}
2972305544bSClément Léger 
2982305544bSClément Léger 	res = clk_set_parent_no_lock(clk, parent, pidx);
2992305544bSClément Léger out:
3002305544bSClément Léger 	cpu_spin_unlock_xrestore(&clk_lock, exceptions);
3012305544bSClément Léger 
3022305544bSClément Léger 	return res;
3032305544bSClément Léger }
304*5df61a5dSClément Léger 
305*5df61a5dSClément Léger TEE_Result clk_get_rates_array(struct clk *clk, size_t start_index,
306*5df61a5dSClément Léger 			       unsigned long *rates, size_t *nb_elts)
307*5df61a5dSClément Léger {
308*5df61a5dSClément Léger 	if (!clk->ops->get_rates_array)
309*5df61a5dSClément Léger 		return TEE_ERROR_NOT_SUPPORTED;
310*5df61a5dSClément Léger 
311*5df61a5dSClément Léger 	return clk->ops->get_rates_array(clk, start_index, rates, nb_elts);
312*5df61a5dSClément Léger }
313