12305544bSClément Léger // SPDX-License-Identifier: BSD-2-Clause 22305544bSClément Léger /* 32305544bSClément Léger * Copyright (c) 2021, Bootlin 4*cd04d138SEtienne Carriere * Copyright (c) 2023, STMicroelectronics 52305544bSClément Léger */ 62305544bSClément Léger 7*cd04d138SEtienne Carriere #include <config.h> 82305544bSClément Léger #include <drivers/clk.h> 92305544bSClément Léger #include <kernel/boot.h> 102305544bSClément Léger #include <kernel/panic.h> 112305544bSClément Léger #include <kernel/spinlock.h> 122305544bSClément Léger #include <libfdt.h> 132305544bSClément Léger #include <malloc.h> 142305544bSClément Léger #include <stddef.h> 15*cd04d138SEtienne Carriere #include <stdio.h> 162305544bSClément Léger 172305544bSClément Léger /* Global clock tree lock */ 182305544bSClément Léger static unsigned int clk_lock = SPINLOCK_UNLOCK; 192305544bSClément Léger 20*cd04d138SEtienne Carriere #ifdef CFG_DRIVERS_CLK_PRINT_TREE 21*cd04d138SEtienne Carriere static STAILQ_HEAD(, clk) clock_list = STAILQ_HEAD_INITIALIZER(clock_list); 22*cd04d138SEtienne Carriere #endif 23*cd04d138SEtienne Carriere 242305544bSClément Léger struct clk *clk_alloc(const char *name, const struct clk_ops *ops, 252305544bSClément Léger struct clk **parent_clks, size_t parent_count) 262305544bSClément Léger { 272305544bSClément Léger struct clk *clk = NULL; 282305544bSClément Léger size_t parent = 0; 292305544bSClément Léger 302305544bSClément Léger clk = calloc(1, sizeof(*clk) + parent_count * sizeof(clk)); 312305544bSClément Léger if (!clk) 322305544bSClément Léger return NULL; 332305544bSClément Léger 342305544bSClément Léger clk->num_parents = parent_count; 352305544bSClément Léger for (parent = 0; parent < parent_count; parent++) 362305544bSClément Léger clk->parents[parent] = parent_clks[parent]; 372305544bSClément Léger 382305544bSClément Léger clk->name = name; 392305544bSClément Léger clk->ops = ops; 402305544bSClément Léger refcount_set(&clk->enabled_count, 0); 412305544bSClément Léger 422305544bSClément Léger return clk; 432305544bSClément Léger } 442305544bSClément Léger 452305544bSClément Léger void clk_free(struct clk *clk) 462305544bSClément Léger { 472305544bSClément Léger free(clk); 482305544bSClément Léger } 492305544bSClément Léger 502305544bSClément Léger static bool __maybe_unused clk_check(struct clk *clk) 512305544bSClément Léger { 522305544bSClément Léger if (!clk->ops) 532305544bSClément Léger return false; 542305544bSClément Léger 552305544bSClément Léger if (clk->ops->set_parent && !clk->ops->get_parent) 562305544bSClément Léger return false; 572305544bSClément Léger 582305544bSClément Léger if (clk->num_parents > 1 && !clk->ops->get_parent) 592305544bSClément Léger return false; 602305544bSClément Léger 612305544bSClément Léger return true; 622305544bSClément Léger } 632305544bSClément Léger 642305544bSClément Léger static void clk_compute_rate_no_lock(struct clk *clk) 652305544bSClément Léger { 662305544bSClément Léger unsigned long parent_rate = 0; 672305544bSClément Léger 682305544bSClément Léger if (clk->parent) 692305544bSClément Léger parent_rate = clk->parent->rate; 702305544bSClément Léger 712305544bSClément Léger if (clk->ops->get_rate) 722305544bSClément Léger clk->rate = clk->ops->get_rate(clk, parent_rate); 732305544bSClément Léger else 742305544bSClément Léger clk->rate = parent_rate; 752305544bSClément Léger } 762305544bSClément Léger 772305544bSClément Léger struct clk *clk_get_parent_by_index(struct clk *clk, size_t pidx) 782305544bSClément Léger { 792305544bSClément Léger if (pidx >= clk->num_parents) 802305544bSClément Léger return NULL; 812305544bSClément Léger 822305544bSClément Léger return clk->parents[pidx]; 832305544bSClément Léger } 842305544bSClément Léger 852305544bSClément Léger static void clk_init_parent(struct clk *clk) 862305544bSClément Léger { 872305544bSClément Léger size_t pidx = 0; 882305544bSClément Léger 892305544bSClément Léger switch (clk->num_parents) { 902305544bSClément Léger case 0: 912305544bSClément Léger break; 922305544bSClément Léger case 1: 932305544bSClément Léger clk->parent = clk->parents[0]; 942305544bSClément Léger break; 952305544bSClément Léger default: 962305544bSClément Léger pidx = clk->ops->get_parent(clk); 972305544bSClément Léger assert(pidx < clk->num_parents); 982305544bSClément Léger 992305544bSClément Léger clk->parent = clk->parents[pidx]; 1002305544bSClément Léger break; 1012305544bSClément Léger } 1022305544bSClément Léger } 1032305544bSClément Léger 1042305544bSClément Léger TEE_Result clk_register(struct clk *clk) 1052305544bSClément Léger { 1062305544bSClément Léger assert(clk_check(clk)); 1072305544bSClément Léger 1082305544bSClément Léger clk_init_parent(clk); 1092305544bSClément Léger clk_compute_rate_no_lock(clk); 1102305544bSClément Léger 111*cd04d138SEtienne Carriere #ifdef CFG_DRIVERS_CLK_PRINT_TREE 112*cd04d138SEtienne Carriere STAILQ_INSERT_TAIL(&clock_list, clk, link); 113*cd04d138SEtienne Carriere #endif 114*cd04d138SEtienne Carriere 1152305544bSClément Léger DMSG("Registered clock %s, freq %lu", clk->name, clk_get_rate(clk)); 1162305544bSClément Léger 1172305544bSClément Léger return TEE_SUCCESS; 1182305544bSClément Léger } 1192305544bSClément Léger 1202305544bSClément Léger static bool clk_is_enabled_no_lock(struct clk *clk) 1212305544bSClément Léger { 1222305544bSClément Léger return refcount_val(&clk->enabled_count) != 0; 1232305544bSClément Léger } 1242305544bSClément Léger 1256c9ed842SEtienne Carriere bool clk_is_enabled(struct clk *clk) 1266c9ed842SEtienne Carriere { 1276c9ed842SEtienne Carriere return clk_is_enabled_no_lock(clk); 1286c9ed842SEtienne Carriere } 1296c9ed842SEtienne Carriere 1302305544bSClément Léger static void clk_disable_no_lock(struct clk *clk) 1312305544bSClément Léger { 1322305544bSClément Léger struct clk *parent = NULL; 1332305544bSClément Léger 1342305544bSClément Léger if (!refcount_dec(&clk->enabled_count)) 1352305544bSClément Léger return; 1362305544bSClément Léger 1372305544bSClément Léger if (clk->ops->disable) 1382305544bSClément Léger clk->ops->disable(clk); 1392305544bSClément Léger 1402305544bSClément Léger parent = clk_get_parent(clk); 1412305544bSClément Léger if (parent) 1422305544bSClément Léger clk_disable_no_lock(parent); 1432305544bSClément Léger } 1442305544bSClément Léger 1452305544bSClément Léger static TEE_Result clk_enable_no_lock(struct clk *clk) 1462305544bSClément Léger { 1472305544bSClément Léger TEE_Result res = TEE_ERROR_GENERIC; 1482305544bSClément Léger struct clk *parent = NULL; 1492305544bSClément Léger 1502305544bSClément Léger if (refcount_inc(&clk->enabled_count)) 1512305544bSClément Léger return TEE_SUCCESS; 1522305544bSClément Léger 1532305544bSClément Léger parent = clk_get_parent(clk); 1542305544bSClément Léger if (parent) { 1552305544bSClément Léger res = clk_enable_no_lock(parent); 1562305544bSClément Léger if (res) 1572305544bSClément Léger return res; 1582305544bSClément Léger } 1592305544bSClément Léger 1602305544bSClément Léger if (clk->ops->enable) { 1612305544bSClément Léger res = clk->ops->enable(clk); 1622305544bSClément Léger if (res) { 1632305544bSClément Léger if (parent) 1642305544bSClément Léger clk_disable_no_lock(parent); 1652305544bSClément Léger 1662305544bSClément Léger return res; 1672305544bSClément Léger } 1682305544bSClément Léger } 1692305544bSClément Léger 1702305544bSClément Léger refcount_set(&clk->enabled_count, 1); 1712305544bSClément Léger 1722305544bSClément Léger return TEE_SUCCESS; 1732305544bSClément Léger } 1742305544bSClément Léger 1752305544bSClément Léger TEE_Result clk_enable(struct clk *clk) 1762305544bSClément Léger { 1772305544bSClément Léger uint32_t exceptions = 0; 1782305544bSClément Léger TEE_Result res = TEE_ERROR_GENERIC; 1792305544bSClément Léger 1802305544bSClément Léger exceptions = cpu_spin_lock_xsave(&clk_lock); 1812305544bSClément Léger res = clk_enable_no_lock(clk); 1822305544bSClément Léger cpu_spin_unlock_xrestore(&clk_lock, exceptions); 1832305544bSClément Léger 1842305544bSClément Léger return res; 1852305544bSClément Léger } 1862305544bSClément Léger 1872305544bSClément Léger void clk_disable(struct clk *clk) 1882305544bSClément Léger { 1892305544bSClément Léger uint32_t exceptions = 0; 1902305544bSClément Léger 1912305544bSClément Léger exceptions = cpu_spin_lock_xsave(&clk_lock); 1922305544bSClément Léger clk_disable_no_lock(clk); 1932305544bSClément Léger cpu_spin_unlock_xrestore(&clk_lock, exceptions); 1942305544bSClément Léger } 1952305544bSClément Léger 1962305544bSClément Léger unsigned long clk_get_rate(struct clk *clk) 1972305544bSClément Léger { 1982305544bSClément Léger return clk->rate; 1992305544bSClément Léger } 2002305544bSClément Léger 2012305544bSClément Léger static TEE_Result clk_set_rate_no_lock(struct clk *clk, unsigned long rate) 2022305544bSClément Léger { 2032305544bSClément Léger TEE_Result res = TEE_ERROR_GENERIC; 2042305544bSClément Léger unsigned long parent_rate = 0; 2052305544bSClément Léger 2062305544bSClément Léger if (clk->parent) 2072305544bSClément Léger parent_rate = clk_get_rate(clk->parent); 2082305544bSClément Léger 2092305544bSClément Léger res = clk->ops->set_rate(clk, rate, parent_rate); 2102305544bSClément Léger if (res) 2112305544bSClément Léger return res; 2122305544bSClément Léger 2132305544bSClément Léger clk_compute_rate_no_lock(clk); 2142305544bSClément Léger 2152305544bSClément Léger return TEE_SUCCESS; 2162305544bSClément Léger } 2172305544bSClément Léger 2182305544bSClément Léger TEE_Result clk_set_rate(struct clk *clk, unsigned long rate) 2192305544bSClément Léger { 2202305544bSClément Léger uint32_t exceptions = 0; 2212305544bSClément Léger TEE_Result res = TEE_ERROR_GENERIC; 2222305544bSClément Léger 2232305544bSClément Léger if (!clk->ops->set_rate) 2242305544bSClément Léger return TEE_ERROR_NOT_SUPPORTED; 2252305544bSClément Léger 2262305544bSClément Léger exceptions = cpu_spin_lock_xsave(&clk_lock); 2272305544bSClément Léger 2282305544bSClément Léger if (clk->flags & CLK_SET_RATE_GATE && clk_is_enabled_no_lock(clk)) 2292305544bSClément Léger res = TEE_ERROR_BAD_STATE; 2302305544bSClément Léger else 2312305544bSClément Léger res = clk_set_rate_no_lock(clk, rate); 2322305544bSClément Léger 2332305544bSClément Léger cpu_spin_unlock_xrestore(&clk_lock, exceptions); 2342305544bSClément Léger 2352305544bSClément Léger return res; 2362305544bSClément Léger } 2372305544bSClément Léger 2382305544bSClément Léger struct clk *clk_get_parent(struct clk *clk) 2392305544bSClément Léger { 2402305544bSClément Léger return clk->parent; 2412305544bSClément Léger } 2422305544bSClément Léger 2432305544bSClément Léger static TEE_Result clk_get_parent_idx(struct clk *clk, struct clk *parent, 2442305544bSClément Léger size_t *pidx) 2452305544bSClément Léger { 2462305544bSClément Léger size_t i = 0; 2472305544bSClément Léger 2482305544bSClément Léger for (i = 0; i < clk_get_num_parents(clk); i++) { 2492305544bSClément Léger if (clk_get_parent_by_index(clk, i) == parent) { 2502305544bSClément Léger *pidx = i; 2512305544bSClément Léger return TEE_SUCCESS; 2522305544bSClément Léger } 2532305544bSClément Léger } 2542305544bSClément Léger EMSG("Clock %s is not a parent of clock %s", parent->name, clk->name); 2552305544bSClément Léger 2562305544bSClément Léger return TEE_ERROR_BAD_PARAMETERS; 2572305544bSClément Léger } 2582305544bSClément Léger 2592305544bSClément Léger static TEE_Result clk_set_parent_no_lock(struct clk *clk, struct clk *parent, 2602305544bSClément Léger size_t pidx) 2612305544bSClément Léger { 2622305544bSClément Léger TEE_Result res = TEE_ERROR_GENERIC; 2632305544bSClément Léger bool was_enabled = false; 2642305544bSClément Léger 2652305544bSClément Léger /* Requested parent is already the one set */ 2662305544bSClément Léger if (clk->parent == parent) 2672305544bSClément Léger return TEE_SUCCESS; 2682305544bSClément Léger 2692305544bSClément Léger was_enabled = clk_is_enabled_no_lock(clk); 2702305544bSClément Léger /* Call is needed to decrement refcount on current parent tree */ 2712305544bSClément Léger if (was_enabled) 2722305544bSClément Léger clk_disable_no_lock(clk); 2732305544bSClément Léger 2742305544bSClément Léger res = clk->ops->set_parent(clk, pidx); 2752305544bSClément Léger if (res) 2762305544bSClément Léger goto out; 2772305544bSClément Léger 2782305544bSClément Léger clk->parent = parent; 2792305544bSClément Léger 2802305544bSClément Léger /* The parent changed and the rate might also have changed */ 2812305544bSClément Léger clk_compute_rate_no_lock(clk); 2822305544bSClément Léger 2832305544bSClément Léger out: 2842305544bSClément Léger /* Call is needed to increment refcount on the new parent tree */ 2852305544bSClément Léger if (was_enabled) { 2862305544bSClément Léger res = clk_enable_no_lock(clk); 2872305544bSClément Léger if (res) 2882305544bSClément Léger panic("Failed to re-enable clock after setting parent"); 2892305544bSClément Léger } 2902305544bSClément Léger 2912305544bSClément Léger return res; 2922305544bSClément Léger } 2932305544bSClément Léger 2942305544bSClément Léger TEE_Result clk_set_parent(struct clk *clk, struct clk *parent) 2952305544bSClément Léger { 2962305544bSClément Léger size_t pidx = 0; 2972305544bSClément Léger uint32_t exceptions = 0; 2982305544bSClément Léger TEE_Result res = TEE_ERROR_GENERIC; 2992305544bSClément Léger 3002305544bSClément Léger if (clk_get_parent_idx(clk, parent, &pidx) || !clk->ops->set_parent) 3012305544bSClément Léger return TEE_ERROR_BAD_PARAMETERS; 3022305544bSClément Léger 3032305544bSClément Léger exceptions = cpu_spin_lock_xsave(&clk_lock); 3042305544bSClément Léger if (clk->flags & CLK_SET_PARENT_GATE && clk_is_enabled_no_lock(clk)) { 3052305544bSClément Léger res = TEE_ERROR_BAD_STATE; 3062305544bSClément Léger goto out; 3072305544bSClément Léger } 3082305544bSClément Léger 3092305544bSClément Léger res = clk_set_parent_no_lock(clk, parent, pidx); 3102305544bSClément Léger out: 3112305544bSClément Léger cpu_spin_unlock_xrestore(&clk_lock, exceptions); 3122305544bSClément Léger 3132305544bSClément Léger return res; 3142305544bSClément Léger } 3155df61a5dSClément Léger 3165df61a5dSClément Léger TEE_Result clk_get_rates_array(struct clk *clk, size_t start_index, 3175df61a5dSClément Léger unsigned long *rates, size_t *nb_elts) 3185df61a5dSClément Léger { 3195df61a5dSClément Léger if (!clk->ops->get_rates_array) 3205df61a5dSClément Léger return TEE_ERROR_NOT_SUPPORTED; 3215df61a5dSClément Léger 3225df61a5dSClément Léger return clk->ops->get_rates_array(clk, start_index, rates, nb_elts); 3235df61a5dSClément Léger } 324*cd04d138SEtienne Carriere 325*cd04d138SEtienne Carriere /* Return updated message buffer position of NULL on failure */ 326*cd04d138SEtienne Carriere static __printf(3, 4) char *add_msg(char *cur, char *end, const char *fmt, ...) 327*cd04d138SEtienne Carriere { 328*cd04d138SEtienne Carriere va_list ap = { }; 329*cd04d138SEtienne Carriere int max_len = end - cur; 330*cd04d138SEtienne Carriere int ret = 0; 331*cd04d138SEtienne Carriere 332*cd04d138SEtienne Carriere va_start(ap, fmt); 333*cd04d138SEtienne Carriere ret = vsnprintf(cur, max_len, fmt, ap); 334*cd04d138SEtienne Carriere va_end(ap); 335*cd04d138SEtienne Carriere 336*cd04d138SEtienne Carriere if (ret < 0 || ret >= max_len) 337*cd04d138SEtienne Carriere return NULL; 338*cd04d138SEtienne Carriere 339*cd04d138SEtienne Carriere return cur + ret; 340*cd04d138SEtienne Carriere } 341*cd04d138SEtienne Carriere 342*cd04d138SEtienne Carriere static void __maybe_unused print_clock(struct clk *clk, int indent) 343*cd04d138SEtienne Carriere { 344*cd04d138SEtienne Carriere static const char * const rate_unit[] = { "Hz", "kHz", "MHz", "GHz" }; 345*cd04d138SEtienne Carriere int max_unit = ARRAY_SIZE(rate_unit); 346*cd04d138SEtienne Carriere unsigned long rate = 0; 347*cd04d138SEtienne Carriere char msg_buf[128] = { }; 348*cd04d138SEtienne Carriere char *msg_end = msg_buf + sizeof(msg_buf); 349*cd04d138SEtienne Carriere char *msg = msg_buf; 350*cd04d138SEtienne Carriere int n = 0; 351*cd04d138SEtienne Carriere 352*cd04d138SEtienne Carriere /* 353*cd04d138SEtienne Carriere * Currently prints the clock state based on the clock refcount. 354*cd04d138SEtienne Carriere * A future change could print the hardware clock state when 355*cd04d138SEtienne Carriere * related clock driver provides a struct clk_ops::is_enabled handler 356*cd04d138SEtienne Carriere */ 357*cd04d138SEtienne Carriere 358*cd04d138SEtienne Carriere if (indent) { 359*cd04d138SEtienne Carriere for (n = 0; n < indent - 1; n++) { 360*cd04d138SEtienne Carriere msg = add_msg(msg, msg_end, "| "); 361*cd04d138SEtienne Carriere if (!msg) 362*cd04d138SEtienne Carriere goto out; 363*cd04d138SEtienne Carriere } 364*cd04d138SEtienne Carriere 365*cd04d138SEtienne Carriere msg = add_msg(msg, msg_end, "+-- "); 366*cd04d138SEtienne Carriere if (!msg) 367*cd04d138SEtienne Carriere goto out; 368*cd04d138SEtienne Carriere } 369*cd04d138SEtienne Carriere 370*cd04d138SEtienne Carriere rate = clk_get_rate(clk); 371*cd04d138SEtienne Carriere for (n = 1; rate && !(rate % 1000) && n < max_unit; n++) 372*cd04d138SEtienne Carriere rate /= 1000; 373*cd04d138SEtienne Carriere 374*cd04d138SEtienne Carriere msg = add_msg(msg, msg_end, "%s \t(%3s / refcnt %u / %ld %s)", 375*cd04d138SEtienne Carriere clk_get_name(clk), 376*cd04d138SEtienne Carriere refcount_val(&clk->enabled_count) ? "on " : "off", 377*cd04d138SEtienne Carriere refcount_val(&clk->enabled_count), 378*cd04d138SEtienne Carriere rate, rate_unit[n - 1]); 379*cd04d138SEtienne Carriere if (!msg) 380*cd04d138SEtienne Carriere goto out; 381*cd04d138SEtienne Carriere 382*cd04d138SEtienne Carriere out: 383*cd04d138SEtienne Carriere if (!msg) 384*cd04d138SEtienne Carriere snprintf(msg_end - 4, 4, "..."); 385*cd04d138SEtienne Carriere 386*cd04d138SEtienne Carriere IMSG("%s", msg_buf); 387*cd04d138SEtienne Carriere } 388*cd04d138SEtienne Carriere 389*cd04d138SEtienne Carriere static void print_clock_subtree(struct clk *clk_root __maybe_unused, 390*cd04d138SEtienne Carriere int indent __maybe_unused) 391*cd04d138SEtienne Carriere { 392*cd04d138SEtienne Carriere #ifdef CFG_DRIVERS_CLK_PRINT_TREE 393*cd04d138SEtienne Carriere struct clk *clk = NULL; 394*cd04d138SEtienne Carriere 395*cd04d138SEtienne Carriere STAILQ_FOREACH(clk, &clock_list, link) { 396*cd04d138SEtienne Carriere if (clk_get_parent(clk) == clk_root) { 397*cd04d138SEtienne Carriere print_clock(clk, indent + 1); 398*cd04d138SEtienne Carriere print_clock_subtree(clk, indent + 1); 399*cd04d138SEtienne Carriere if (indent == -1) 400*cd04d138SEtienne Carriere IMSG("%s", ""); 401*cd04d138SEtienne Carriere } 402*cd04d138SEtienne Carriere } 403*cd04d138SEtienne Carriere #endif 404*cd04d138SEtienne Carriere } 405*cd04d138SEtienne Carriere 406*cd04d138SEtienne Carriere void clk_print_tree(void) 407*cd04d138SEtienne Carriere { 408*cd04d138SEtienne Carriere if (IS_ENABLED(CFG_DRIVERS_CLK_PRINT_TREE)) { 409*cd04d138SEtienne Carriere uint32_t exceptions = 0; 410*cd04d138SEtienne Carriere 411*cd04d138SEtienne Carriere exceptions = cpu_spin_lock_xsave(&clk_lock); 412*cd04d138SEtienne Carriere IMSG("Clock tree summary"); 413*cd04d138SEtienne Carriere IMSG("%s", ""); 414*cd04d138SEtienne Carriere print_clock_subtree(NULL, -1); 415*cd04d138SEtienne Carriere cpu_spin_unlock_xrestore(&clk_lock, exceptions); 416*cd04d138SEtienne Carriere } 417*cd04d138SEtienne Carriere } 418