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