19be88e75SGabriel Fernandez /* 29be88e75SGabriel Fernandez * Copyright (C) 2022, STMicroelectronics - All Rights Reserved 39be88e75SGabriel Fernandez * 49be88e75SGabriel Fernandez * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause 59be88e75SGabriel Fernandez */ 69be88e75SGabriel Fernandez 79be88e75SGabriel Fernandez #include <assert.h> 89be88e75SGabriel Fernandez #include <errno.h> 99be88e75SGabriel Fernandez 109be88e75SGabriel Fernandez #include "clk-stm32-core.h" 119be88e75SGabriel Fernandez #include <common/debug.h> 129be88e75SGabriel Fernandez #include <common/fdt_wrappers.h> 139be88e75SGabriel Fernandez #include <drivers/clk.h> 149be88e75SGabriel Fernandez #include <drivers/delay_timer.h> 159be88e75SGabriel Fernandez #include <drivers/st/stm32mp_clkfunc.h> 169be88e75SGabriel Fernandez #include <lib/mmio.h> 179be88e75SGabriel Fernandez #include <lib/spinlock.h> 189be88e75SGabriel Fernandez 199be88e75SGabriel Fernandez static struct spinlock reg_lock; 209be88e75SGabriel Fernandez static struct spinlock refcount_lock; 219be88e75SGabriel Fernandez 229be88e75SGabriel Fernandez static struct stm32_clk_priv *stm32_clock_data; 239be88e75SGabriel Fernandez 249be88e75SGabriel Fernandez const struct stm32_clk_ops clk_mux_ops; 259be88e75SGabriel Fernandez 269be88e75SGabriel Fernandez struct stm32_clk_priv *clk_stm32_get_priv(void) 279be88e75SGabriel Fernandez { 289be88e75SGabriel Fernandez return stm32_clock_data; 299be88e75SGabriel Fernandez } 309be88e75SGabriel Fernandez 319be88e75SGabriel Fernandez static void stm32mp1_clk_lock(struct spinlock *lock) 329be88e75SGabriel Fernandez { 339be88e75SGabriel Fernandez if (stm32mp_lock_available()) { 349be88e75SGabriel Fernandez /* Assume interrupts are masked */ 359be88e75SGabriel Fernandez spin_lock(lock); 369be88e75SGabriel Fernandez } 379be88e75SGabriel Fernandez } 389be88e75SGabriel Fernandez 399be88e75SGabriel Fernandez static void stm32mp1_clk_unlock(struct spinlock *lock) 409be88e75SGabriel Fernandez { 419be88e75SGabriel Fernandez if (stm32mp_lock_available()) { 429be88e75SGabriel Fernandez spin_unlock(lock); 439be88e75SGabriel Fernandez } 449be88e75SGabriel Fernandez } 459be88e75SGabriel Fernandez 469be88e75SGabriel Fernandez void stm32mp1_clk_rcc_regs_lock(void) 479be88e75SGabriel Fernandez { 489be88e75SGabriel Fernandez stm32mp1_clk_lock(®_lock); 499be88e75SGabriel Fernandez } 509be88e75SGabriel Fernandez 519be88e75SGabriel Fernandez void stm32mp1_clk_rcc_regs_unlock(void) 529be88e75SGabriel Fernandez { 539be88e75SGabriel Fernandez stm32mp1_clk_unlock(®_lock); 549be88e75SGabriel Fernandez } 559be88e75SGabriel Fernandez 569be88e75SGabriel Fernandez #define TIMEOUT_US_1S U(1000000) 579be88e75SGabriel Fernandez #define OSCRDY_TIMEOUT TIMEOUT_US_1S 589be88e75SGabriel Fernandez 599be88e75SGabriel Fernandez struct clk_oscillator_data *clk_oscillator_get_data(struct stm32_clk_priv *priv, int id) 609be88e75SGabriel Fernandez { 619be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 629be88e75SGabriel Fernandez struct stm32_osc_cfg *osc_cfg = clk->clock_cfg; 639be88e75SGabriel Fernandez int osc_id = osc_cfg->osc_id; 649be88e75SGabriel Fernandez 659be88e75SGabriel Fernandez return &priv->osci_data[osc_id]; 669be88e75SGabriel Fernandez } 679be88e75SGabriel Fernandez 689be88e75SGabriel Fernandez void clk_oscillator_set_bypass(struct stm32_clk_priv *priv, int id, bool digbyp, bool bypass) 699be88e75SGabriel Fernandez { 709be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 719be88e75SGabriel Fernandez 729be88e75SGabriel Fernandez struct stm32_clk_bypass *bypass_data = osc_data->bypass; 739be88e75SGabriel Fernandez uintptr_t address; 749be88e75SGabriel Fernandez 759be88e75SGabriel Fernandez if (bypass_data == NULL) { 769be88e75SGabriel Fernandez return; 779be88e75SGabriel Fernandez } 789be88e75SGabriel Fernandez 799be88e75SGabriel Fernandez address = priv->base + bypass_data->offset; 809be88e75SGabriel Fernandez 819be88e75SGabriel Fernandez if (digbyp) { 829be88e75SGabriel Fernandez mmio_setbits_32(address, BIT(bypass_data->bit_digbyp)); 839be88e75SGabriel Fernandez } 849be88e75SGabriel Fernandez 859be88e75SGabriel Fernandez if (bypass || digbyp) { 869be88e75SGabriel Fernandez mmio_setbits_32(address, BIT(bypass_data->bit_byp)); 879be88e75SGabriel Fernandez } 889be88e75SGabriel Fernandez } 899be88e75SGabriel Fernandez 909be88e75SGabriel Fernandez void clk_oscillator_set_css(struct stm32_clk_priv *priv, int id, bool css) 919be88e75SGabriel Fernandez { 929be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 939be88e75SGabriel Fernandez 949be88e75SGabriel Fernandez struct stm32_clk_css *css_data = osc_data->css; 959be88e75SGabriel Fernandez uintptr_t address; 969be88e75SGabriel Fernandez 979be88e75SGabriel Fernandez if (css_data == NULL) { 989be88e75SGabriel Fernandez return; 999be88e75SGabriel Fernandez } 1009be88e75SGabriel Fernandez 1019be88e75SGabriel Fernandez address = priv->base + css_data->offset; 1029be88e75SGabriel Fernandez 1039be88e75SGabriel Fernandez if (css) { 1049be88e75SGabriel Fernandez mmio_setbits_32(address, BIT(css_data->bit_css)); 1059be88e75SGabriel Fernandez } 1069be88e75SGabriel Fernandez } 1079be88e75SGabriel Fernandez 1089be88e75SGabriel Fernandez void clk_oscillator_set_drive(struct stm32_clk_priv *priv, int id, uint8_t lsedrv) 1099be88e75SGabriel Fernandez { 1109be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 1119be88e75SGabriel Fernandez 1129be88e75SGabriel Fernandez struct stm32_clk_drive *drive_data = osc_data->drive; 1139be88e75SGabriel Fernandez uintptr_t address; 1149be88e75SGabriel Fernandez uint32_t mask; 1159be88e75SGabriel Fernandez uint32_t value; 1169be88e75SGabriel Fernandez 1179be88e75SGabriel Fernandez if (drive_data == NULL) { 1189be88e75SGabriel Fernandez return; 1199be88e75SGabriel Fernandez } 1209be88e75SGabriel Fernandez 1219be88e75SGabriel Fernandez address = priv->base + drive_data->offset; 1229be88e75SGabriel Fernandez 1239be88e75SGabriel Fernandez mask = (BIT(drive_data->drv_width) - 1U) << drive_data->drv_shift; 1249be88e75SGabriel Fernandez 1259be88e75SGabriel Fernandez /* 1269be88e75SGabriel Fernandez * Warning: not recommended to switch directly from "high drive" 1279be88e75SGabriel Fernandez * to "medium low drive", and vice-versa. 1289be88e75SGabriel Fernandez */ 1299be88e75SGabriel Fernandez value = (mmio_read_32(address) & mask) >> drive_data->drv_shift; 1309be88e75SGabriel Fernandez 1319be88e75SGabriel Fernandez while (value != lsedrv) { 1329be88e75SGabriel Fernandez if (value > lsedrv) { 1339be88e75SGabriel Fernandez value--; 1349be88e75SGabriel Fernandez } else { 1359be88e75SGabriel Fernandez value++; 1369be88e75SGabriel Fernandez } 1379be88e75SGabriel Fernandez 1389be88e75SGabriel Fernandez mmio_clrsetbits_32(address, mask, value << drive_data->drv_shift); 1399be88e75SGabriel Fernandez } 1409be88e75SGabriel Fernandez } 1419be88e75SGabriel Fernandez 1429be88e75SGabriel Fernandez int clk_oscillator_wait_ready(struct stm32_clk_priv *priv, int id, bool ready_on) 1439be88e75SGabriel Fernandez { 1449be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 1459be88e75SGabriel Fernandez 1463b06a530SYann Gautier return _clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, ready_on); 1479be88e75SGabriel Fernandez } 1489be88e75SGabriel Fernandez 1499be88e75SGabriel Fernandez int clk_oscillator_wait_ready_on(struct stm32_clk_priv *priv, int id) 1509be88e75SGabriel Fernandez { 1519be88e75SGabriel Fernandez return clk_oscillator_wait_ready(priv, id, true); 1529be88e75SGabriel Fernandez } 1539be88e75SGabriel Fernandez 1549be88e75SGabriel Fernandez int clk_oscillator_wait_ready_off(struct stm32_clk_priv *priv, int id) 1559be88e75SGabriel Fernandez { 1569be88e75SGabriel Fernandez return clk_oscillator_wait_ready(priv, id, false); 1579be88e75SGabriel Fernandez } 1589be88e75SGabriel Fernandez 1599be88e75SGabriel Fernandez static int clk_gate_enable(struct stm32_clk_priv *priv, int id) 1609be88e75SGabriel Fernandez { 1619be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 1629be88e75SGabriel Fernandez struct clk_gate_cfg *cfg = clk->clock_cfg; 1639be88e75SGabriel Fernandez 1649be88e75SGabriel Fernandez mmio_setbits_32(priv->base + cfg->offset, BIT(cfg->bit_idx)); 1659be88e75SGabriel Fernandez 1669be88e75SGabriel Fernandez return 0; 1679be88e75SGabriel Fernandez } 1689be88e75SGabriel Fernandez 1699be88e75SGabriel Fernandez static void clk_gate_disable(struct stm32_clk_priv *priv, int id) 1709be88e75SGabriel Fernandez { 1719be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 1729be88e75SGabriel Fernandez struct clk_gate_cfg *cfg = clk->clock_cfg; 1739be88e75SGabriel Fernandez 1749be88e75SGabriel Fernandez mmio_clrbits_32(priv->base + cfg->offset, BIT(cfg->bit_idx)); 1759be88e75SGabriel Fernandez } 1769be88e75SGabriel Fernandez 1779be88e75SGabriel Fernandez static bool clk_gate_is_enabled(struct stm32_clk_priv *priv, int id) 1789be88e75SGabriel Fernandez { 1799be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 1809be88e75SGabriel Fernandez struct clk_gate_cfg *cfg = clk->clock_cfg; 1819be88e75SGabriel Fernandez 1829be88e75SGabriel Fernandez return ((mmio_read_32(priv->base + cfg->offset) & BIT(cfg->bit_idx)) != 0U); 1839be88e75SGabriel Fernandez } 1849be88e75SGabriel Fernandez 1859be88e75SGabriel Fernandez const struct stm32_clk_ops clk_gate_ops = { 1869be88e75SGabriel Fernandez .enable = clk_gate_enable, 1879be88e75SGabriel Fernandez .disable = clk_gate_disable, 1889be88e75SGabriel Fernandez .is_enabled = clk_gate_is_enabled, 1899be88e75SGabriel Fernandez }; 1909be88e75SGabriel Fernandez 1919be88e75SGabriel Fernandez void _clk_stm32_gate_disable(struct stm32_clk_priv *priv, uint16_t gate_id) 1929be88e75SGabriel Fernandez { 1939be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[gate_id]; 1949be88e75SGabriel Fernandez uintptr_t addr = priv->base + gate->offset; 1959be88e75SGabriel Fernandez 1969be88e75SGabriel Fernandez if (gate->set_clr != 0U) { 1979be88e75SGabriel Fernandez mmio_write_32(addr + RCC_MP_ENCLRR_OFFSET, BIT(gate->bit_idx)); 1989be88e75SGabriel Fernandez } else { 1999be88e75SGabriel Fernandez mmio_clrbits_32(addr, BIT(gate->bit_idx)); 2009be88e75SGabriel Fernandez } 2019be88e75SGabriel Fernandez } 2029be88e75SGabriel Fernandez 2039be88e75SGabriel Fernandez int _clk_stm32_gate_enable(struct stm32_clk_priv *priv, uint16_t gate_id) 2049be88e75SGabriel Fernandez { 2059be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[gate_id]; 2069be88e75SGabriel Fernandez uintptr_t addr = priv->base + gate->offset; 2079be88e75SGabriel Fernandez 2089be88e75SGabriel Fernandez if (gate->set_clr != 0U) { 2099be88e75SGabriel Fernandez mmio_write_32(addr, BIT(gate->bit_idx)); 2109be88e75SGabriel Fernandez 2119be88e75SGabriel Fernandez } else { 2129be88e75SGabriel Fernandez mmio_setbits_32(addr, BIT(gate->bit_idx)); 2139be88e75SGabriel Fernandez } 2149be88e75SGabriel Fernandez 2159be88e75SGabriel Fernandez return 0; 2169be88e75SGabriel Fernandez } 2179be88e75SGabriel Fernandez 2189be88e75SGabriel Fernandez const char *_clk_stm32_get_name(struct stm32_clk_priv *priv, int id) 2199be88e75SGabriel Fernandez { 2209be88e75SGabriel Fernandez return priv->clks[id].name; 2219be88e75SGabriel Fernandez } 2229be88e75SGabriel Fernandez 2239be88e75SGabriel Fernandez const char *clk_stm32_get_name(struct stm32_clk_priv *priv, 2249be88e75SGabriel Fernandez unsigned long binding_id) 2259be88e75SGabriel Fernandez { 2269be88e75SGabriel Fernandez int id; 2279be88e75SGabriel Fernandez 2289be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 2299be88e75SGabriel Fernandez if (id == -EINVAL) { 2309be88e75SGabriel Fernandez return NULL; 2319be88e75SGabriel Fernandez } 2329be88e75SGabriel Fernandez 2339be88e75SGabriel Fernandez return _clk_stm32_get_name(priv, id); 2349be88e75SGabriel Fernandez } 2359be88e75SGabriel Fernandez 2369be88e75SGabriel Fernandez const struct clk_stm32 *_clk_get(struct stm32_clk_priv *priv, int id) 2379be88e75SGabriel Fernandez { 2389be88e75SGabriel Fernandez if ((unsigned int)id < priv->num) { 2399be88e75SGabriel Fernandez return &priv->clks[id]; 2409be88e75SGabriel Fernandez } 2419be88e75SGabriel Fernandez 2429be88e75SGabriel Fernandez return NULL; 2439be88e75SGabriel Fernandez } 2449be88e75SGabriel Fernandez 2459be88e75SGabriel Fernandez #define clk_div_mask(_width) GENMASK(((_width) - 1U), 0U) 2469be88e75SGabriel Fernandez 2479be88e75SGabriel Fernandez static unsigned int _get_table_div(const struct clk_div_table *table, 2489be88e75SGabriel Fernandez unsigned int val) 2499be88e75SGabriel Fernandez { 2509be88e75SGabriel Fernandez const struct clk_div_table *clkt; 2519be88e75SGabriel Fernandez 2529be88e75SGabriel Fernandez for (clkt = table; clkt->div; clkt++) { 2539be88e75SGabriel Fernandez if (clkt->val == val) { 2549be88e75SGabriel Fernandez return clkt->div; 2559be88e75SGabriel Fernandez } 2569be88e75SGabriel Fernandez } 2579be88e75SGabriel Fernandez 2589be88e75SGabriel Fernandez return 0; 2599be88e75SGabriel Fernandez } 2609be88e75SGabriel Fernandez 2619be88e75SGabriel Fernandez static unsigned int _get_div(const struct clk_div_table *table, 2629be88e75SGabriel Fernandez unsigned int val, unsigned long flags, 2639be88e75SGabriel Fernandez uint8_t width) 2649be88e75SGabriel Fernandez { 2659be88e75SGabriel Fernandez if ((flags & CLK_DIVIDER_ONE_BASED) != 0UL) { 2669be88e75SGabriel Fernandez return val; 2679be88e75SGabriel Fernandez } 2689be88e75SGabriel Fernandez 2699be88e75SGabriel Fernandez if ((flags & CLK_DIVIDER_POWER_OF_TWO) != 0UL) { 2709be88e75SGabriel Fernandez return BIT(val); 2719be88e75SGabriel Fernandez } 2729be88e75SGabriel Fernandez 2739be88e75SGabriel Fernandez if ((flags & CLK_DIVIDER_MAX_AT_ZERO) != 0UL) { 2749be88e75SGabriel Fernandez return (val != 0U) ? val : BIT(width); 2759be88e75SGabriel Fernandez } 2769be88e75SGabriel Fernandez 2779be88e75SGabriel Fernandez if (table != NULL) { 2789be88e75SGabriel Fernandez return _get_table_div(table, val); 2799be88e75SGabriel Fernandez } 2809be88e75SGabriel Fernandez 2819be88e75SGabriel Fernandez return val + 1U; 2829be88e75SGabriel Fernandez } 2839be88e75SGabriel Fernandez 2849be88e75SGabriel Fernandez #define TIMEOUT_US_200MS U(200000) 2859be88e75SGabriel Fernandez #define CLKSRC_TIMEOUT TIMEOUT_US_200MS 2869be88e75SGabriel Fernandez 2879be88e75SGabriel Fernandez int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel) 2889be88e75SGabriel Fernandez { 2899be88e75SGabriel Fernandez const struct parent_cfg *parents = &priv->parents[pid & MUX_PARENT_MASK]; 2909be88e75SGabriel Fernandez const struct mux_cfg *mux = parents->mux; 2919be88e75SGabriel Fernandez uintptr_t address = priv->base + mux->offset; 2929be88e75SGabriel Fernandez uint32_t mask; 2939be88e75SGabriel Fernandez uint64_t timeout; 2949be88e75SGabriel Fernandez 2959be88e75SGabriel Fernandez mask = MASK_WIDTH_SHIFT(mux->width, mux->shift); 2969be88e75SGabriel Fernandez 2979be88e75SGabriel Fernandez mmio_clrsetbits_32(address, mask, (sel << mux->shift) & mask); 2989be88e75SGabriel Fernandez 2999be88e75SGabriel Fernandez if (mux->bitrdy == MUX_NO_BIT_RDY) { 3009be88e75SGabriel Fernandez return 0; 3019be88e75SGabriel Fernandez } 3029be88e75SGabriel Fernandez 3039be88e75SGabriel Fernandez timeout = timeout_init_us(CLKSRC_TIMEOUT); 3049be88e75SGabriel Fernandez 3059be88e75SGabriel Fernandez mask = BIT(mux->bitrdy); 3069be88e75SGabriel Fernandez 3079be88e75SGabriel Fernandez while ((mmio_read_32(address) & mask) == 0U) { 3089be88e75SGabriel Fernandez if (timeout_elapsed(timeout)) { 3099be88e75SGabriel Fernandez return -ETIMEDOUT; 3109be88e75SGabriel Fernandez } 3119be88e75SGabriel Fernandez } 3129be88e75SGabriel Fernandez 3139be88e75SGabriel Fernandez return 0; 3149be88e75SGabriel Fernandez } 3159be88e75SGabriel Fernandez 3169be88e75SGabriel Fernandez int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int clk, int clkp) 3179be88e75SGabriel Fernandez { 3189be88e75SGabriel Fernandez const struct parent_cfg *parents; 3199be88e75SGabriel Fernandez uint16_t pid; 3209be88e75SGabriel Fernandez uint8_t sel; 3219be88e75SGabriel Fernandez int old_parent; 3229be88e75SGabriel Fernandez 3239be88e75SGabriel Fernandez pid = priv->clks[clk].parent; 3249be88e75SGabriel Fernandez 3259be88e75SGabriel Fernandez if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) { 3269be88e75SGabriel Fernandez return -EINVAL; 3279be88e75SGabriel Fernandez } 3289be88e75SGabriel Fernandez 3299be88e75SGabriel Fernandez old_parent = _clk_stm32_get_parent(priv, clk); 330b8eab512SYann Gautier if (old_parent < 0) { 331b8eab512SYann Gautier return old_parent; 332b8eab512SYann Gautier } 3339be88e75SGabriel Fernandez if (old_parent == clkp) { 3349be88e75SGabriel Fernandez return 0; 3359be88e75SGabriel Fernandez } 3369be88e75SGabriel Fernandez 3379be88e75SGabriel Fernandez parents = &priv->parents[pid & MUX_PARENT_MASK]; 3389be88e75SGabriel Fernandez 3399be88e75SGabriel Fernandez for (sel = 0; sel < parents->num_parents; sel++) { 3409be88e75SGabriel Fernandez if (parents->id_parents[sel] == (uint16_t)clkp) { 3419be88e75SGabriel Fernandez bool clk_was_enabled = _clk_stm32_is_enabled(priv, clk); 3429be88e75SGabriel Fernandez int err = 0; 3439be88e75SGabriel Fernandez 3449be88e75SGabriel Fernandez /* Enable the parents (for glitch free mux) */ 3459be88e75SGabriel Fernandez _clk_stm32_enable(priv, clkp); 3469be88e75SGabriel Fernandez _clk_stm32_enable(priv, old_parent); 3479be88e75SGabriel Fernandez 3489be88e75SGabriel Fernandez err = clk_mux_set_parent(priv, pid, sel); 3499be88e75SGabriel Fernandez 3509be88e75SGabriel Fernandez _clk_stm32_disable(priv, old_parent); 3519be88e75SGabriel Fernandez 3529be88e75SGabriel Fernandez if (clk_was_enabled) { 3539be88e75SGabriel Fernandez _clk_stm32_disable(priv, old_parent); 3549be88e75SGabriel Fernandez } else { 3559be88e75SGabriel Fernandez _clk_stm32_disable(priv, clkp); 3569be88e75SGabriel Fernandez } 3579be88e75SGabriel Fernandez 3589be88e75SGabriel Fernandez return err; 3599be88e75SGabriel Fernandez } 3609be88e75SGabriel Fernandez } 3619be88e75SGabriel Fernandez 3629be88e75SGabriel Fernandez return -EINVAL; 3639be88e75SGabriel Fernandez } 3649be88e75SGabriel Fernandez 3659be88e75SGabriel Fernandez int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id) 3669be88e75SGabriel Fernandez { 3679be88e75SGabriel Fernandez const struct parent_cfg *parent; 3689be88e75SGabriel Fernandez const struct mux_cfg *mux; 3699be88e75SGabriel Fernandez uint32_t mask; 3709be88e75SGabriel Fernandez 3719be88e75SGabriel Fernandez if (mux_id >= priv->nb_parents) { 3729be88e75SGabriel Fernandez panic(); 3739be88e75SGabriel Fernandez } 3749be88e75SGabriel Fernandez 3759be88e75SGabriel Fernandez parent = &priv->parents[mux_id]; 3769be88e75SGabriel Fernandez mux = parent->mux; 3779be88e75SGabriel Fernandez 3789be88e75SGabriel Fernandez mask = MASK_WIDTH_SHIFT(mux->width, mux->shift); 3799be88e75SGabriel Fernandez 3809be88e75SGabriel Fernandez return (mmio_read_32(priv->base + mux->offset) & mask) >> mux->shift; 3819be88e75SGabriel Fernandez } 3829be88e75SGabriel Fernandez 3839be88e75SGabriel Fernandez int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel) 3849be88e75SGabriel Fernandez { 3859be88e75SGabriel Fernandez uint16_t pid; 3869be88e75SGabriel Fernandez 3879be88e75SGabriel Fernandez pid = priv->clks[clk].parent; 3889be88e75SGabriel Fernandez 3899be88e75SGabriel Fernandez if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) { 3909be88e75SGabriel Fernandez return -EINVAL; 3919be88e75SGabriel Fernandez } 3929be88e75SGabriel Fernandez 3939be88e75SGabriel Fernandez return clk_mux_set_parent(priv, pid, sel); 3949be88e75SGabriel Fernandez } 3959be88e75SGabriel Fernandez 3969be88e75SGabriel Fernandez int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int clk_id) 3979be88e75SGabriel Fernandez { 3989be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, clk_id); 3999be88e75SGabriel Fernandez const struct parent_cfg *parent; 4009be88e75SGabriel Fernandez uint16_t mux_id; 4019be88e75SGabriel Fernandez int sel; 4029be88e75SGabriel Fernandez 4039be88e75SGabriel Fernandez mux_id = priv->clks[clk_id].parent; 4049be88e75SGabriel Fernandez if (mux_id == CLK_IS_ROOT) { 4059be88e75SGabriel Fernandez return CLK_IS_ROOT; 4069be88e75SGabriel Fernandez } 4079be88e75SGabriel Fernandez 4089be88e75SGabriel Fernandez if (mux_id < MUX_MAX_PARENTS) { 4099be88e75SGabriel Fernandez return mux_id & MUX_PARENT_MASK; 4109be88e75SGabriel Fernandez } 4119be88e75SGabriel Fernandez 4129be88e75SGabriel Fernandez mux_id &= MUX_PARENT_MASK; 4139be88e75SGabriel Fernandez parent = &priv->parents[mux_id]; 4149be88e75SGabriel Fernandez 4159be88e75SGabriel Fernandez if (clk->ops->get_parent != NULL) { 4169be88e75SGabriel Fernandez sel = clk->ops->get_parent(priv, clk_id); 4179be88e75SGabriel Fernandez } else { 4189be88e75SGabriel Fernandez sel = clk_mux_get_parent(priv, mux_id); 4199be88e75SGabriel Fernandez } 4209be88e75SGabriel Fernandez 421b8eab512SYann Gautier if ((sel >= 0) && (sel < parent->num_parents)) { 4229be88e75SGabriel Fernandez return parent->id_parents[sel]; 4239be88e75SGabriel Fernandez } 4249be88e75SGabriel Fernandez 4259be88e75SGabriel Fernandez return -EINVAL; 4269be88e75SGabriel Fernandez } 4279be88e75SGabriel Fernandez 4289be88e75SGabriel Fernandez int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id) 4299be88e75SGabriel Fernandez { 4309be88e75SGabriel Fernandez uint16_t mux_id; 4319be88e75SGabriel Fernandez 4329be88e75SGabriel Fernandez mux_id = priv->clks[clk_id].parent; 4339be88e75SGabriel Fernandez if (mux_id == CLK_IS_ROOT) { 4349be88e75SGabriel Fernandez return CLK_IS_ROOT; 4359be88e75SGabriel Fernandez } 4369be88e75SGabriel Fernandez 4379be88e75SGabriel Fernandez if (mux_id < MUX_MAX_PARENTS) { 4389be88e75SGabriel Fernandez return mux_id & MUX_PARENT_MASK; 4399be88e75SGabriel Fernandez } 4409be88e75SGabriel Fernandez 4419be88e75SGabriel Fernandez mux_id &= MUX_PARENT_MASK; 4429be88e75SGabriel Fernandez 4439be88e75SGabriel Fernandez return clk_mux_get_parent(priv, mux_id); 4449be88e75SGabriel Fernandez } 4459be88e75SGabriel Fernandez 4469be88e75SGabriel Fernandez int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx) 4479be88e75SGabriel Fernandez { 4489be88e75SGabriel Fernandez const struct parent_cfg *parent; 4499be88e75SGabriel Fernandez uint16_t mux_id; 4509be88e75SGabriel Fernandez 4519be88e75SGabriel Fernandez mux_id = priv->clks[clk_id].parent; 4529be88e75SGabriel Fernandez if (mux_id == CLK_IS_ROOT) { 4539be88e75SGabriel Fernandez return CLK_IS_ROOT; 4549be88e75SGabriel Fernandez } 4559be88e75SGabriel Fernandez 4569be88e75SGabriel Fernandez if (mux_id < MUX_MAX_PARENTS) { 4579be88e75SGabriel Fernandez return mux_id & MUX_PARENT_MASK; 4589be88e75SGabriel Fernandez } 4599be88e75SGabriel Fernandez 4609be88e75SGabriel Fernandez mux_id &= MUX_PARENT_MASK; 4619be88e75SGabriel Fernandez parent = &priv->parents[mux_id]; 4629be88e75SGabriel Fernandez 4639be88e75SGabriel Fernandez if (idx < parent->num_parents) { 4649be88e75SGabriel Fernandez return parent->id_parents[idx]; 4659be88e75SGabriel Fernandez } 4669be88e75SGabriel Fernandez 4679be88e75SGabriel Fernandez return -EINVAL; 4689be88e75SGabriel Fernandez } 4699be88e75SGabriel Fernandez 4709be88e75SGabriel Fernandez int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id) 4719be88e75SGabriel Fernandez { 4729be88e75SGabriel Fernandez unsigned int i; 4739be88e75SGabriel Fernandez 4749be88e75SGabriel Fernandez for (i = 0U; i < priv->num; i++) { 4759be88e75SGabriel Fernandez if (binding_id == priv->clks[i].binding) { 4769be88e75SGabriel Fernandez return (int)i; 4779be88e75SGabriel Fernandez } 4789be88e75SGabriel Fernandez } 4799be88e75SGabriel Fernandez 4809be88e75SGabriel Fernandez return -EINVAL; 4819be88e75SGabriel Fernandez } 4829be88e75SGabriel Fernandez 4839be88e75SGabriel Fernandez unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id) 4849be88e75SGabriel Fernandez { 4859be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 4869be88e75SGabriel Fernandez int parent; 4879be88e75SGabriel Fernandez unsigned long rate = 0UL; 4889be88e75SGabriel Fernandez 4899be88e75SGabriel Fernandez if ((unsigned int)id >= priv->num) { 4909be88e75SGabriel Fernandez return rate; 4919be88e75SGabriel Fernandez } 4929be88e75SGabriel Fernandez 4939be88e75SGabriel Fernandez parent = _clk_stm32_get_parent(priv, id); 494b8eab512SYann Gautier if (parent < 0) { 495b8eab512SYann Gautier return 0UL; 496b8eab512SYann Gautier } 4979be88e75SGabriel Fernandez 4989be88e75SGabriel Fernandez if (clk->ops->recalc_rate != NULL) { 4999be88e75SGabriel Fernandez unsigned long prate = 0UL; 5009be88e75SGabriel Fernandez 5019be88e75SGabriel Fernandez if (parent != CLK_IS_ROOT) { 5029be88e75SGabriel Fernandez prate = _clk_stm32_get_rate(priv, parent); 5039be88e75SGabriel Fernandez } 5049be88e75SGabriel Fernandez 5059be88e75SGabriel Fernandez rate = clk->ops->recalc_rate(priv, id, prate); 5069be88e75SGabriel Fernandez 5079be88e75SGabriel Fernandez return rate; 5089be88e75SGabriel Fernandez } 5099be88e75SGabriel Fernandez 5109be88e75SGabriel Fernandez switch (parent) { 5119be88e75SGabriel Fernandez case CLK_IS_ROOT: 5129be88e75SGabriel Fernandez panic(); 5139be88e75SGabriel Fernandez 5149be88e75SGabriel Fernandez default: 5159be88e75SGabriel Fernandez rate = _clk_stm32_get_rate(priv, parent); 5169be88e75SGabriel Fernandez break; 5179be88e75SGabriel Fernandez } 5189be88e75SGabriel Fernandez return rate; 5199be88e75SGabriel Fernandez 5209be88e75SGabriel Fernandez } 5219be88e75SGabriel Fernandez 5229be88e75SGabriel Fernandez unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id) 5239be88e75SGabriel Fernandez { 5249be88e75SGabriel Fernandez int parent_id = _clk_stm32_get_parent(priv, id); 5259be88e75SGabriel Fernandez 526b8eab512SYann Gautier if (parent_id < 0) { 527b8eab512SYann Gautier return 0UL; 528b8eab512SYann Gautier } 529b8eab512SYann Gautier 5309be88e75SGabriel Fernandez return _clk_stm32_get_rate(priv, parent_id); 5319be88e75SGabriel Fernandez } 5329be88e75SGabriel Fernandez 5339be88e75SGabriel Fernandez static uint8_t _stm32_clk_get_flags(struct stm32_clk_priv *priv, int id) 5349be88e75SGabriel Fernandez { 5359be88e75SGabriel Fernandez return priv->clks[id].flags; 5369be88e75SGabriel Fernandez } 5379be88e75SGabriel Fernandez 5389be88e75SGabriel Fernandez bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag) 5399be88e75SGabriel Fernandez { 5409be88e75SGabriel Fernandez if (_stm32_clk_get_flags(priv, id) & flag) { 5419be88e75SGabriel Fernandez return true; 5429be88e75SGabriel Fernandez } 5439be88e75SGabriel Fernandez 5449be88e75SGabriel Fernandez return false; 5459be88e75SGabriel Fernandez } 5469be88e75SGabriel Fernandez 5479be88e75SGabriel Fernandez int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id) 5489be88e75SGabriel Fernandez { 5499be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 5509be88e75SGabriel Fernandez 5519be88e75SGabriel Fernandez if (clk->ops->enable != NULL) { 5529be88e75SGabriel Fernandez clk->ops->enable(priv, id); 5539be88e75SGabriel Fernandez } 5549be88e75SGabriel Fernandez 5559be88e75SGabriel Fernandez return 0; 5569be88e75SGabriel Fernandez } 5579be88e75SGabriel Fernandez 5589be88e75SGabriel Fernandez static int _clk_stm32_enable_core(struct stm32_clk_priv *priv, int id) 5599be88e75SGabriel Fernandez { 5609be88e75SGabriel Fernandez int parent; 5619be88e75SGabriel Fernandez int ret = 0; 5629be88e75SGabriel Fernandez 5639be88e75SGabriel Fernandez if (priv->gate_refcounts[id] == 0U) { 5649be88e75SGabriel Fernandez parent = _clk_stm32_get_parent(priv, id); 565b8eab512SYann Gautier if (parent < 0) { 566b8eab512SYann Gautier return parent; 567b8eab512SYann Gautier } 5689be88e75SGabriel Fernandez if (parent != CLK_IS_ROOT) { 5699be88e75SGabriel Fernandez ret = _clk_stm32_enable_core(priv, parent); 5709be88e75SGabriel Fernandez if (ret) { 5719be88e75SGabriel Fernandez return ret; 5729be88e75SGabriel Fernandez } 5739be88e75SGabriel Fernandez } 5749be88e75SGabriel Fernandez clk_stm32_enable_call_ops(priv, id); 5759be88e75SGabriel Fernandez } 5769be88e75SGabriel Fernandez 5779be88e75SGabriel Fernandez priv->gate_refcounts[id]++; 5789be88e75SGabriel Fernandez 5799be88e75SGabriel Fernandez if (priv->gate_refcounts[id] == UINT_MAX) { 5809be88e75SGabriel Fernandez ERROR("%s: %d max enable count !", __func__, id); 5819be88e75SGabriel Fernandez panic(); 5829be88e75SGabriel Fernandez } 5839be88e75SGabriel Fernandez 5849be88e75SGabriel Fernandez return 0; 5859be88e75SGabriel Fernandez } 5869be88e75SGabriel Fernandez 5879be88e75SGabriel Fernandez int _clk_stm32_enable(struct stm32_clk_priv *priv, int id) 5889be88e75SGabriel Fernandez { 5899be88e75SGabriel Fernandez int ret; 5909be88e75SGabriel Fernandez 5919be88e75SGabriel Fernandez stm32mp1_clk_lock(&refcount_lock); 5929be88e75SGabriel Fernandez ret = _clk_stm32_enable_core(priv, id); 5939be88e75SGabriel Fernandez stm32mp1_clk_unlock(&refcount_lock); 5949be88e75SGabriel Fernandez 5959be88e75SGabriel Fernandez return ret; 5969be88e75SGabriel Fernandez } 5979be88e75SGabriel Fernandez 5989be88e75SGabriel Fernandez void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id) 5999be88e75SGabriel Fernandez { 6009be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 6019be88e75SGabriel Fernandez 6029be88e75SGabriel Fernandez if (clk->ops->disable != NULL) { 6039be88e75SGabriel Fernandez clk->ops->disable(priv, id); 6049be88e75SGabriel Fernandez } 6059be88e75SGabriel Fernandez } 6069be88e75SGabriel Fernandez 6079be88e75SGabriel Fernandez static void _clk_stm32_disable_core(struct stm32_clk_priv *priv, int id) 6089be88e75SGabriel Fernandez { 6099be88e75SGabriel Fernandez int parent; 6109be88e75SGabriel Fernandez 6119be88e75SGabriel Fernandez if ((priv->gate_refcounts[id] == 1U) && _stm32_clk_is_flags(priv, id, CLK_IS_CRITICAL)) { 6129be88e75SGabriel Fernandez return; 6139be88e75SGabriel Fernandez } 6149be88e75SGabriel Fernandez 6159be88e75SGabriel Fernandez if (priv->gate_refcounts[id] == 0U) { 6169be88e75SGabriel Fernandez /* case of clock ignore unused */ 6179be88e75SGabriel Fernandez if (_clk_stm32_is_enabled(priv, id)) { 6189be88e75SGabriel Fernandez clk_stm32_disable_call_ops(priv, id); 6199be88e75SGabriel Fernandez return; 6209be88e75SGabriel Fernandez } 6219be88e75SGabriel Fernandez VERBOSE("%s: %d already disabled !\n\n", __func__, id); 6229be88e75SGabriel Fernandez return; 6239be88e75SGabriel Fernandez } 6249be88e75SGabriel Fernandez 6259be88e75SGabriel Fernandez if (--priv->gate_refcounts[id] > 0U) { 6269be88e75SGabriel Fernandez return; 6279be88e75SGabriel Fernandez } 6289be88e75SGabriel Fernandez 6299be88e75SGabriel Fernandez clk_stm32_disable_call_ops(priv, id); 6309be88e75SGabriel Fernandez 6319be88e75SGabriel Fernandez parent = _clk_stm32_get_parent(priv, id); 632b8eab512SYann Gautier if ((parent >= 0) && (parent != CLK_IS_ROOT)) { 6339be88e75SGabriel Fernandez _clk_stm32_disable_core(priv, parent); 6349be88e75SGabriel Fernandez } 6359be88e75SGabriel Fernandez } 6369be88e75SGabriel Fernandez 6379be88e75SGabriel Fernandez void _clk_stm32_disable(struct stm32_clk_priv *priv, int id) 6389be88e75SGabriel Fernandez { 6399be88e75SGabriel Fernandez stm32mp1_clk_lock(&refcount_lock); 6409be88e75SGabriel Fernandez 6419be88e75SGabriel Fernandez _clk_stm32_disable_core(priv, id); 6429be88e75SGabriel Fernandez 6439be88e75SGabriel Fernandez stm32mp1_clk_unlock(&refcount_lock); 6449be88e75SGabriel Fernandez } 6459be88e75SGabriel Fernandez 6469be88e75SGabriel Fernandez bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id) 6479be88e75SGabriel Fernandez { 6489be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 6499be88e75SGabriel Fernandez 6509be88e75SGabriel Fernandez if (clk->ops->is_enabled != NULL) { 6519be88e75SGabriel Fernandez return clk->ops->is_enabled(priv, id); 6529be88e75SGabriel Fernandez } 6539be88e75SGabriel Fernandez 6549be88e75SGabriel Fernandez return priv->gate_refcounts[id]; 6559be88e75SGabriel Fernandez } 6569be88e75SGabriel Fernandez 6579be88e75SGabriel Fernandez static int clk_stm32_enable(unsigned long binding_id) 6589be88e75SGabriel Fernandez { 6599be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6609be88e75SGabriel Fernandez int id; 6619be88e75SGabriel Fernandez 6629be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6639be88e75SGabriel Fernandez if (id == -EINVAL) { 6649be88e75SGabriel Fernandez return id; 6659be88e75SGabriel Fernandez } 6669be88e75SGabriel Fernandez 6679be88e75SGabriel Fernandez return _clk_stm32_enable(priv, id); 6689be88e75SGabriel Fernandez } 6699be88e75SGabriel Fernandez 6709be88e75SGabriel Fernandez static void clk_stm32_disable(unsigned long binding_id) 6719be88e75SGabriel Fernandez { 6729be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6739be88e75SGabriel Fernandez int id; 6749be88e75SGabriel Fernandez 6759be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6769be88e75SGabriel Fernandez if (id != -EINVAL) { 6779be88e75SGabriel Fernandez _clk_stm32_disable(priv, id); 6789be88e75SGabriel Fernandez } 6799be88e75SGabriel Fernandez } 6809be88e75SGabriel Fernandez 6819be88e75SGabriel Fernandez static bool clk_stm32_is_enabled(unsigned long binding_id) 6829be88e75SGabriel Fernandez { 6839be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6849be88e75SGabriel Fernandez int id; 6859be88e75SGabriel Fernandez 6869be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6879be88e75SGabriel Fernandez if (id == -EINVAL) { 6889be88e75SGabriel Fernandez return false; 6899be88e75SGabriel Fernandez } 6909be88e75SGabriel Fernandez 6919be88e75SGabriel Fernandez return _clk_stm32_is_enabled(priv, id); 6929be88e75SGabriel Fernandez } 6939be88e75SGabriel Fernandez 6949be88e75SGabriel Fernandez static unsigned long clk_stm32_get_rate(unsigned long binding_id) 6959be88e75SGabriel Fernandez { 6969be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6979be88e75SGabriel Fernandez int id; 6989be88e75SGabriel Fernandez 6999be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 7009be88e75SGabriel Fernandez if (id == -EINVAL) { 7019be88e75SGabriel Fernandez return 0UL; 7029be88e75SGabriel Fernandez } 7039be88e75SGabriel Fernandez 7049be88e75SGabriel Fernandez return _clk_stm32_get_rate(priv, id); 7059be88e75SGabriel Fernandez } 7069be88e75SGabriel Fernandez 7079be88e75SGabriel Fernandez static int clk_stm32_get_parent(unsigned long binding_id) 7089be88e75SGabriel Fernandez { 7099be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 7109be88e75SGabriel Fernandez int id; 7119be88e75SGabriel Fernandez 7129be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 7139be88e75SGabriel Fernandez if (id == -EINVAL) { 7149be88e75SGabriel Fernandez return id; 7159be88e75SGabriel Fernandez } 7169be88e75SGabriel Fernandez 7179be88e75SGabriel Fernandez return _clk_stm32_get_parent(priv, id); 7189be88e75SGabriel Fernandez } 7199be88e75SGabriel Fernandez 7209be88e75SGabriel Fernandez static const struct clk_ops stm32mp_clk_ops = { 7219be88e75SGabriel Fernandez .enable = clk_stm32_enable, 7229be88e75SGabriel Fernandez .disable = clk_stm32_disable, 7239be88e75SGabriel Fernandez .is_enabled = clk_stm32_is_enabled, 7249be88e75SGabriel Fernandez .get_rate = clk_stm32_get_rate, 7259be88e75SGabriel Fernandez .get_parent = clk_stm32_get_parent, 7269be88e75SGabriel Fernandez }; 7279be88e75SGabriel Fernandez 7289be88e75SGabriel Fernandez void clk_stm32_enable_critical_clocks(void) 7299be88e75SGabriel Fernandez { 7309be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 7319be88e75SGabriel Fernandez unsigned int i; 7329be88e75SGabriel Fernandez 7339be88e75SGabriel Fernandez for (i = 0U; i < priv->num; i++) { 7349be88e75SGabriel Fernandez if (_stm32_clk_is_flags(priv, i, CLK_IS_CRITICAL)) { 7359be88e75SGabriel Fernandez _clk_stm32_enable(priv, i); 7369be88e75SGabriel Fernandez } 7379be88e75SGabriel Fernandez } 7389be88e75SGabriel Fernandez } 7399be88e75SGabriel Fernandez 7409be88e75SGabriel Fernandez static void stm32_clk_register(void) 7419be88e75SGabriel Fernandez { 7429be88e75SGabriel Fernandez clk_register(&stm32mp_clk_ops); 7439be88e75SGabriel Fernandez } 7449be88e75SGabriel Fernandez 7459be88e75SGabriel Fernandez uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id) 7469be88e75SGabriel Fernandez { 7479be88e75SGabriel Fernandez const struct div_cfg *divider = &priv->div[div_id]; 7489be88e75SGabriel Fernandez uint32_t val = 0; 7499be88e75SGabriel Fernandez 7509be88e75SGabriel Fernandez val = mmio_read_32(priv->base + divider->offset) >> divider->shift; 7519be88e75SGabriel Fernandez val &= clk_div_mask(divider->width); 7529be88e75SGabriel Fernandez 7539be88e75SGabriel Fernandez return val; 7549be88e75SGabriel Fernandez } 7559be88e75SGabriel Fernandez 7569be88e75SGabriel Fernandez unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv, 7579be88e75SGabriel Fernandez int div_id, 7589be88e75SGabriel Fernandez unsigned long prate) 7599be88e75SGabriel Fernandez { 7609be88e75SGabriel Fernandez const struct div_cfg *divider = &priv->div[div_id]; 7619be88e75SGabriel Fernandez uint32_t val = clk_stm32_div_get_value(priv, div_id); 7629be88e75SGabriel Fernandez unsigned int div = 0U; 7639be88e75SGabriel Fernandez 7649be88e75SGabriel Fernandez div = _get_div(divider->table, val, divider->flags, divider->width); 7659be88e75SGabriel Fernandez if (div == 0U) { 7669be88e75SGabriel Fernandez return prate; 7679be88e75SGabriel Fernandez } 7689be88e75SGabriel Fernandez 7699be88e75SGabriel Fernandez return div_round_up((uint64_t)prate, div); 7709be88e75SGabriel Fernandez } 7719be88e75SGabriel Fernandez 7729be88e75SGabriel Fernandez unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int id, 7739be88e75SGabriel Fernandez unsigned long prate) 7749be88e75SGabriel Fernandez { 7759be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 7769be88e75SGabriel Fernandez struct clk_stm32_div_cfg *div_cfg = clk->clock_cfg; 7779be88e75SGabriel Fernandez 7789be88e75SGabriel Fernandez return _clk_stm32_divider_recalc(priv, div_cfg->id, prate); 7799be88e75SGabriel Fernandez } 7809be88e75SGabriel Fernandez 7819be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_divider_ops = { 7829be88e75SGabriel Fernandez .recalc_rate = clk_stm32_divider_recalc, 7839be88e75SGabriel Fernandez }; 7849be88e75SGabriel Fernandez 7859be88e75SGabriel Fernandez int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value) 7869be88e75SGabriel Fernandez { 7879be88e75SGabriel Fernandez const struct div_cfg *divider; 7889be88e75SGabriel Fernandez uintptr_t address; 7899be88e75SGabriel Fernandez uint64_t timeout; 7909be88e75SGabriel Fernandez uint32_t mask; 7919be88e75SGabriel Fernandez 7929be88e75SGabriel Fernandez if (div_id >= priv->nb_div) { 7939be88e75SGabriel Fernandez panic(); 7949be88e75SGabriel Fernandez } 7959be88e75SGabriel Fernandez 7969be88e75SGabriel Fernandez divider = &priv->div[div_id]; 7979be88e75SGabriel Fernandez address = priv->base + divider->offset; 7989be88e75SGabriel Fernandez 7999be88e75SGabriel Fernandez mask = MASK_WIDTH_SHIFT(divider->width, divider->shift); 8009be88e75SGabriel Fernandez mmio_clrsetbits_32(address, mask, (value << divider->shift) & mask); 8019be88e75SGabriel Fernandez 8029be88e75SGabriel Fernandez if (divider->bitrdy == DIV_NO_BIT_RDY) { 8039be88e75SGabriel Fernandez return 0; 8049be88e75SGabriel Fernandez } 8059be88e75SGabriel Fernandez 8069be88e75SGabriel Fernandez timeout = timeout_init_us(CLKSRC_TIMEOUT); 8079be88e75SGabriel Fernandez mask = BIT(divider->bitrdy); 8089be88e75SGabriel Fernandez 8099be88e75SGabriel Fernandez while ((mmio_read_32(address) & mask) == 0U) { 8109be88e75SGabriel Fernandez if (timeout_elapsed(timeout)) { 8119be88e75SGabriel Fernandez return -ETIMEDOUT; 8129be88e75SGabriel Fernandez } 8139be88e75SGabriel Fernandez } 8149be88e75SGabriel Fernandez 8159be88e75SGabriel Fernandez return 0; 8169be88e75SGabriel Fernandez } 8179be88e75SGabriel Fernandez 8189be88e75SGabriel Fernandez int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id, 8199be88e75SGabriel Fernandez bool ready_on) 8209be88e75SGabriel Fernandez { 8219be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[gate_id]; 8229be88e75SGabriel Fernandez uintptr_t address = priv->base + gate->offset; 8239be88e75SGabriel Fernandez uint32_t mask_rdy = BIT(gate->bit_idx); 8249be88e75SGabriel Fernandez uint64_t timeout; 8259be88e75SGabriel Fernandez uint32_t mask_test; 8269be88e75SGabriel Fernandez 8279be88e75SGabriel Fernandez if (ready_on) { 8289be88e75SGabriel Fernandez mask_test = BIT(gate->bit_idx); 8299be88e75SGabriel Fernandez } else { 8309be88e75SGabriel Fernandez mask_test = 0U; 8319be88e75SGabriel Fernandez } 8329be88e75SGabriel Fernandez 8339be88e75SGabriel Fernandez timeout = timeout_init_us(OSCRDY_TIMEOUT); 8349be88e75SGabriel Fernandez 8359be88e75SGabriel Fernandez while ((mmio_read_32(address) & mask_rdy) != mask_test) { 8369be88e75SGabriel Fernandez if (timeout_elapsed(timeout)) { 8379be88e75SGabriel Fernandez break; 8389be88e75SGabriel Fernandez } 8399be88e75SGabriel Fernandez } 8409be88e75SGabriel Fernandez 841*56f895edSYann Gautier if ((mmio_read_32(address) & mask_rdy) != mask_test) { 8429be88e75SGabriel Fernandez return -ETIMEDOUT; 843*56f895edSYann Gautier } 8449be88e75SGabriel Fernandez 8459be88e75SGabriel Fernandez return 0; 8469be88e75SGabriel Fernandez } 8479be88e75SGabriel Fernandez 8489be88e75SGabriel Fernandez int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int id) 8499be88e75SGabriel Fernandez { 8509be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8519be88e75SGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->clock_cfg; 8529be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[cfg->id]; 8539be88e75SGabriel Fernandez uintptr_t addr = priv->base + gate->offset; 8549be88e75SGabriel Fernandez 8559be88e75SGabriel Fernandez if (gate->set_clr != 0U) { 8569be88e75SGabriel Fernandez mmio_write_32(addr, BIT(gate->bit_idx)); 8579be88e75SGabriel Fernandez 8589be88e75SGabriel Fernandez } else { 8599be88e75SGabriel Fernandez mmio_setbits_32(addr, BIT(gate->bit_idx)); 8609be88e75SGabriel Fernandez } 8619be88e75SGabriel Fernandez 8629be88e75SGabriel Fernandez return 0; 8639be88e75SGabriel Fernandez } 8649be88e75SGabriel Fernandez 8659be88e75SGabriel Fernandez void clk_stm32_gate_disable(struct stm32_clk_priv *priv, int id) 8669be88e75SGabriel Fernandez { 8679be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8689be88e75SGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->clock_cfg; 8699be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[cfg->id]; 8709be88e75SGabriel Fernandez uintptr_t addr = priv->base + gate->offset; 8719be88e75SGabriel Fernandez 8729be88e75SGabriel Fernandez if (gate->set_clr != 0U) { 8739be88e75SGabriel Fernandez mmio_write_32(addr + RCC_MP_ENCLRR_OFFSET, BIT(gate->bit_idx)); 8749be88e75SGabriel Fernandez } else { 8759be88e75SGabriel Fernandez mmio_clrbits_32(addr, BIT(gate->bit_idx)); 8769be88e75SGabriel Fernandez } 8779be88e75SGabriel Fernandez } 8789be88e75SGabriel Fernandez 8799be88e75SGabriel Fernandez bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id) 8809be88e75SGabriel Fernandez { 8819be88e75SGabriel Fernandez const struct gate_cfg *gate; 8829be88e75SGabriel Fernandez uint32_t addr; 8839be88e75SGabriel Fernandez 8849be88e75SGabriel Fernandez gate = &priv->gates[gate_id]; 8859be88e75SGabriel Fernandez addr = priv->base + gate->offset; 8869be88e75SGabriel Fernandez 8879be88e75SGabriel Fernandez return ((mmio_read_32(addr) & BIT(gate->bit_idx)) != 0U); 8889be88e75SGabriel Fernandez } 8899be88e75SGabriel Fernandez 8909be88e75SGabriel Fernandez bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int id) 8919be88e75SGabriel Fernandez { 8929be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8939be88e75SGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->clock_cfg; 8949be88e75SGabriel Fernandez 8959be88e75SGabriel Fernandez return _clk_stm32_gate_is_enabled(priv, cfg->id); 8969be88e75SGabriel Fernandez } 8979be88e75SGabriel Fernandez 8989be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_gate_ops = { 8999be88e75SGabriel Fernandez .enable = clk_stm32_gate_enable, 9009be88e75SGabriel Fernandez .disable = clk_stm32_gate_disable, 9019be88e75SGabriel Fernandez .is_enabled = clk_stm32_gate_is_enabled, 9029be88e75SGabriel Fernandez }; 9039be88e75SGabriel Fernandez 9049be88e75SGabriel Fernandez const struct stm32_clk_ops clk_fixed_factor_ops = { 9059be88e75SGabriel Fernandez .recalc_rate = fixed_factor_recalc_rate, 9069be88e75SGabriel Fernandez }; 9079be88e75SGabriel Fernandez 9089be88e75SGabriel Fernandez unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv, 9099be88e75SGabriel Fernandez int id, unsigned long prate) 9109be88e75SGabriel Fernandez { 9119be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 9129be88e75SGabriel Fernandez const struct fixed_factor_cfg *cfg = clk->clock_cfg; 9139be88e75SGabriel Fernandez unsigned long long rate; 9149be88e75SGabriel Fernandez 9159be88e75SGabriel Fernandez rate = (unsigned long long)prate * cfg->mult; 9169be88e75SGabriel Fernandez 9179be88e75SGabriel Fernandez if (cfg->div == 0U) { 9189be88e75SGabriel Fernandez ERROR("division by zero\n"); 9199be88e75SGabriel Fernandez panic(); 9209be88e75SGabriel Fernandez } 9219be88e75SGabriel Fernandez 9229be88e75SGabriel Fernandez return (unsigned long)(rate / cfg->div); 9239be88e75SGabriel Fernandez }; 9249be88e75SGabriel Fernandez 9259be88e75SGabriel Fernandez #define APB_DIV_MASK GENMASK(2, 0) 9269be88e75SGabriel Fernandez #define TIM_PRE_MASK BIT(0) 9279be88e75SGabriel Fernandez 9289be88e75SGabriel Fernandez static unsigned long timer_recalc_rate(struct stm32_clk_priv *priv, 9299be88e75SGabriel Fernandez int id, unsigned long prate) 9309be88e75SGabriel Fernandez { 9319be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 9329be88e75SGabriel Fernandez const struct clk_timer_cfg *cfg = clk->clock_cfg; 9339be88e75SGabriel Fernandez uint32_t prescaler, timpre; 9349be88e75SGabriel Fernandez uintptr_t rcc_base = priv->base; 9359be88e75SGabriel Fernandez 9369be88e75SGabriel Fernandez prescaler = mmio_read_32(rcc_base + cfg->apbdiv) & 9379be88e75SGabriel Fernandez APB_DIV_MASK; 9389be88e75SGabriel Fernandez 9399be88e75SGabriel Fernandez timpre = mmio_read_32(rcc_base + cfg->timpre) & 9409be88e75SGabriel Fernandez TIM_PRE_MASK; 9419be88e75SGabriel Fernandez 9429be88e75SGabriel Fernandez if (prescaler == 0U) { 9439be88e75SGabriel Fernandez return prate; 9449be88e75SGabriel Fernandez } 9459be88e75SGabriel Fernandez 9469be88e75SGabriel Fernandez return prate * (timpre + 1U) * 2U; 9479be88e75SGabriel Fernandez }; 9489be88e75SGabriel Fernandez 9499be88e75SGabriel Fernandez const struct stm32_clk_ops clk_timer_ops = { 9509be88e75SGabriel Fernandez .recalc_rate = timer_recalc_rate, 9519be88e75SGabriel Fernandez }; 9529be88e75SGabriel Fernandez 9539be88e75SGabriel Fernandez static unsigned long clk_fixed_rate_recalc(struct stm32_clk_priv *priv, int id, 9549be88e75SGabriel Fernandez unsigned long prate) 9559be88e75SGabriel Fernandez { 9569be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 9579be88e75SGabriel Fernandez struct clk_stm32_fixed_rate_cfg *cfg = clk->clock_cfg; 9589be88e75SGabriel Fernandez 9599be88e75SGabriel Fernandez return cfg->rate; 9609be88e75SGabriel Fernandez } 9619be88e75SGabriel Fernandez 9629be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_fixed_rate_ops = { 9639be88e75SGabriel Fernandez .recalc_rate = clk_fixed_rate_recalc, 9649be88e75SGabriel Fernandez }; 9659be88e75SGabriel Fernandez 9669be88e75SGabriel Fernandez static unsigned long clk_stm32_osc_recalc_rate(struct stm32_clk_priv *priv, 9679be88e75SGabriel Fernandez int id, unsigned long prate) 9689be88e75SGabriel Fernandez { 9699be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9709be88e75SGabriel Fernandez 9719be88e75SGabriel Fernandez return osc_data->frequency; 9729be88e75SGabriel Fernandez }; 9739be88e75SGabriel Fernandez 9749be88e75SGabriel Fernandez bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id) 9759be88e75SGabriel Fernandez { 9769be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9779be88e75SGabriel Fernandez 9789be88e75SGabriel Fernandez return _clk_stm32_gate_is_enabled(priv, osc_data->gate_id); 9799be88e75SGabriel Fernandez 9809be88e75SGabriel Fernandez } 9819be88e75SGabriel Fernandez 9829be88e75SGabriel Fernandez int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id) 9839be88e75SGabriel Fernandez { 9849be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9859be88e75SGabriel Fernandez 9869be88e75SGabriel Fernandez _clk_stm32_gate_enable(priv, osc_data->gate_id); 9879be88e75SGabriel Fernandez 9889be88e75SGabriel Fernandez if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, true) != 0U) { 9899be88e75SGabriel Fernandez ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__); 9909be88e75SGabriel Fernandez panic(); 9919be88e75SGabriel Fernandez } 9929be88e75SGabriel Fernandez 9939be88e75SGabriel Fernandez return 0; 9949be88e75SGabriel Fernandez } 9959be88e75SGabriel Fernandez 9969be88e75SGabriel Fernandez void clk_stm32_osc_gate_disable(struct stm32_clk_priv *priv, int id) 9979be88e75SGabriel Fernandez { 9989be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9999be88e75SGabriel Fernandez 10009be88e75SGabriel Fernandez _clk_stm32_gate_disable(priv, osc_data->gate_id); 10019be88e75SGabriel Fernandez 10029be88e75SGabriel Fernandez if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, false) != 0U) { 10039be88e75SGabriel Fernandez ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__); 10049be88e75SGabriel Fernandez panic(); 10059be88e75SGabriel Fernandez } 10069be88e75SGabriel Fernandez } 10079be88e75SGabriel Fernandez 10089be88e75SGabriel Fernandez static unsigned long clk_stm32_get_dt_oscillator_frequency(const char *name) 10099be88e75SGabriel Fernandez { 10109be88e75SGabriel Fernandez void *fdt = NULL; 10119be88e75SGabriel Fernandez int node = 0; 10129be88e75SGabriel Fernandez int subnode = 0; 10139be88e75SGabriel Fernandez 10149be88e75SGabriel Fernandez if (fdt_get_address(&fdt) == 0) { 10159be88e75SGabriel Fernandez panic(); 10169be88e75SGabriel Fernandez } 10179be88e75SGabriel Fernandez 10189be88e75SGabriel Fernandez node = fdt_path_offset(fdt, "/clocks"); 10199be88e75SGabriel Fernandez if (node < 0) { 10209be88e75SGabriel Fernandez return 0UL; 10219be88e75SGabriel Fernandez } 10229be88e75SGabriel Fernandez 10239be88e75SGabriel Fernandez fdt_for_each_subnode(subnode, fdt, node) { 10249be88e75SGabriel Fernandez const char *cchar = NULL; 10259be88e75SGabriel Fernandez const fdt32_t *cuint = NULL; 10269be88e75SGabriel Fernandez int ret = 0; 10279be88e75SGabriel Fernandez 10289be88e75SGabriel Fernandez cchar = fdt_get_name(fdt, subnode, &ret); 10299be88e75SGabriel Fernandez if (cchar == NULL) { 10309be88e75SGabriel Fernandez continue; 10319be88e75SGabriel Fernandez } 10329be88e75SGabriel Fernandez 10339be88e75SGabriel Fernandez if (strncmp(cchar, name, (size_t)ret) || 10349be88e75SGabriel Fernandez fdt_get_status(subnode) == DT_DISABLED) { 10359be88e75SGabriel Fernandez continue; 10369be88e75SGabriel Fernandez } 10379be88e75SGabriel Fernandez 10389be88e75SGabriel Fernandez cuint = fdt_getprop(fdt, subnode, "clock-frequency", &ret); 10399be88e75SGabriel Fernandez if (cuint == NULL) { 10409be88e75SGabriel Fernandez return 0UL; 10419be88e75SGabriel Fernandez } 10429be88e75SGabriel Fernandez 10439be88e75SGabriel Fernandez return fdt32_to_cpu(*cuint); 10449be88e75SGabriel Fernandez } 10459be88e75SGabriel Fernandez 10469be88e75SGabriel Fernandez return 0UL; 10479be88e75SGabriel Fernandez } 10489be88e75SGabriel Fernandez 10499be88e75SGabriel Fernandez void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id) 10509be88e75SGabriel Fernandez { 10519be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 10529be88e75SGabriel Fernandez const char *name = osc_data->name; 10539be88e75SGabriel Fernandez 10549be88e75SGabriel Fernandez osc_data->frequency = clk_stm32_get_dt_oscillator_frequency(name); 10559be88e75SGabriel Fernandez } 10569be88e75SGabriel Fernandez 10579be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_osc_ops = { 10589be88e75SGabriel Fernandez .recalc_rate = clk_stm32_osc_recalc_rate, 10599be88e75SGabriel Fernandez .is_enabled = clk_stm32_osc_gate_is_enabled, 10609be88e75SGabriel Fernandez .enable = clk_stm32_osc_gate_enable, 10619be88e75SGabriel Fernandez .disable = clk_stm32_osc_gate_disable, 10629be88e75SGabriel Fernandez .init = clk_stm32_osc_init, 10639be88e75SGabriel Fernandez }; 10649be88e75SGabriel Fernandez 10659be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_osc_nogate_ops = { 10669be88e75SGabriel Fernandez .recalc_rate = clk_stm32_osc_recalc_rate, 10679be88e75SGabriel Fernandez .init = clk_stm32_osc_init, 10689be88e75SGabriel Fernandez }; 10699be88e75SGabriel Fernandez 10709be88e75SGabriel Fernandez int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb) 10719be88e75SGabriel Fernandez { 10729be88e75SGabriel Fernandez const fdt32_t *cell; 10739be88e75SGabriel Fernandez int len = 0; 10749be88e75SGabriel Fernandez uint32_t i; 10759be88e75SGabriel Fernandez 10769be88e75SGabriel Fernandez cell = fdt_getprop(fdt, node, name, &len); 10777417cda6SYann Gautier if (cell == NULL) { 10787417cda6SYann Gautier *nb = 0U; 10797417cda6SYann Gautier return 0; 10807417cda6SYann Gautier } 10817417cda6SYann Gautier 10829be88e75SGabriel Fernandez for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 10839be88e75SGabriel Fernandez uint32_t val = fdt32_to_cpu(cell[i]); 10849be88e75SGabriel Fernandez 10859be88e75SGabriel Fernandez tab[i] = val; 10869be88e75SGabriel Fernandez } 10879be88e75SGabriel Fernandez 10889be88e75SGabriel Fernandez *nb = (uint32_t)len / sizeof(uint32_t); 10899be88e75SGabriel Fernandez 10909be88e75SGabriel Fernandez return 0; 10919be88e75SGabriel Fernandez } 10929be88e75SGabriel Fernandez 10939be88e75SGabriel Fernandez int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base) 10949be88e75SGabriel Fernandez { 10959be88e75SGabriel Fernandez unsigned int i; 10969be88e75SGabriel Fernandez 10979be88e75SGabriel Fernandez stm32_clock_data = priv; 10989be88e75SGabriel Fernandez 10999be88e75SGabriel Fernandez priv->base = base; 11009be88e75SGabriel Fernandez 11019be88e75SGabriel Fernandez for (i = 0U; i < priv->num; i++) { 11029be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, i); 11039be88e75SGabriel Fernandez 11049be88e75SGabriel Fernandez assert(clk->ops != NULL); 11059be88e75SGabriel Fernandez 11069be88e75SGabriel Fernandez if (clk->ops->init != NULL) { 11079be88e75SGabriel Fernandez clk->ops->init(priv, i); 11089be88e75SGabriel Fernandez } 11099be88e75SGabriel Fernandez } 11109be88e75SGabriel Fernandez 11119be88e75SGabriel Fernandez stm32_clk_register(); 11129be88e75SGabriel Fernandez 11139be88e75SGabriel Fernandez return 0; 11149be88e75SGabriel Fernandez } 1115