19be88e75SGabriel Fernandez /* 2f2aebab8SGabriel Fernandez * Copyright (C) 2022-2024, 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 31*1be399b8SYann Gautier static void _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 39*1be399b8SYann Gautier static void _clk_unlock(struct spinlock *lock) 409be88e75SGabriel Fernandez { 419be88e75SGabriel Fernandez if (stm32mp_lock_available()) { 429be88e75SGabriel Fernandez spin_unlock(lock); 439be88e75SGabriel Fernandez } 449be88e75SGabriel Fernandez } 459be88e75SGabriel Fernandez 46*1be399b8SYann Gautier void clk_stm32_rcc_regs_lock(void) 479be88e75SGabriel Fernandez { 48*1be399b8SYann Gautier _clk_lock(®_lock); 499be88e75SGabriel Fernandez } 509be88e75SGabriel Fernandez 51*1be399b8SYann Gautier void clk_stm32_rcc_regs_unlock(void) 529be88e75SGabriel Fernandez { 53*1be399b8SYann Gautier _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 struct clk_stm32 *_clk_get(struct stm32_clk_priv *priv, int id) 2199be88e75SGabriel Fernandez { 2209be88e75SGabriel Fernandez if ((unsigned int)id < priv->num) { 2219be88e75SGabriel Fernandez return &priv->clks[id]; 2229be88e75SGabriel Fernandez } 2239be88e75SGabriel Fernandez 2249be88e75SGabriel Fernandez return NULL; 2259be88e75SGabriel Fernandez } 2269be88e75SGabriel Fernandez 227d9a7ddebSGabriel Fernandez static const struct stm32_clk_ops *_clk_get_ops(struct stm32_clk_priv *priv, int id) 228d9a7ddebSGabriel Fernandez { 229d9a7ddebSGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 230d9a7ddebSGabriel Fernandez 231d9a7ddebSGabriel Fernandez assert(clk->ops != NO_OPS); 232d9a7ddebSGabriel Fernandez 233d9a7ddebSGabriel Fernandez return priv->ops_array[clk->ops]; 234d9a7ddebSGabriel Fernandez } 235d9a7ddebSGabriel Fernandez 2369be88e75SGabriel Fernandez #define clk_div_mask(_width) GENMASK(((_width) - 1U), 0U) 2379be88e75SGabriel Fernandez 2389be88e75SGabriel Fernandez static unsigned int _get_table_div(const struct clk_div_table *table, 2399be88e75SGabriel Fernandez unsigned int val) 2409be88e75SGabriel Fernandez { 2419be88e75SGabriel Fernandez const struct clk_div_table *clkt; 2429be88e75SGabriel Fernandez 2439be88e75SGabriel Fernandez for (clkt = table; clkt->div; clkt++) { 2449be88e75SGabriel Fernandez if (clkt->val == val) { 2459be88e75SGabriel Fernandez return clkt->div; 2469be88e75SGabriel Fernandez } 2479be88e75SGabriel Fernandez } 2489be88e75SGabriel Fernandez 2499be88e75SGabriel Fernandez return 0; 2509be88e75SGabriel Fernandez } 2519be88e75SGabriel Fernandez 2529be88e75SGabriel Fernandez static unsigned int _get_div(const struct clk_div_table *table, 2539be88e75SGabriel Fernandez unsigned int val, unsigned long flags, 2549be88e75SGabriel Fernandez uint8_t width) 2559be88e75SGabriel Fernandez { 2569be88e75SGabriel Fernandez if ((flags & CLK_DIVIDER_ONE_BASED) != 0UL) { 2579be88e75SGabriel Fernandez return val; 2589be88e75SGabriel Fernandez } 2599be88e75SGabriel Fernandez 2609be88e75SGabriel Fernandez if ((flags & CLK_DIVIDER_POWER_OF_TWO) != 0UL) { 2619be88e75SGabriel Fernandez return BIT(val); 2629be88e75SGabriel Fernandez } 2639be88e75SGabriel Fernandez 2649be88e75SGabriel Fernandez if ((flags & CLK_DIVIDER_MAX_AT_ZERO) != 0UL) { 2659be88e75SGabriel Fernandez return (val != 0U) ? val : BIT(width); 2669be88e75SGabriel Fernandez } 2679be88e75SGabriel Fernandez 2689be88e75SGabriel Fernandez if (table != NULL) { 2699be88e75SGabriel Fernandez return _get_table_div(table, val); 2709be88e75SGabriel Fernandez } 2719be88e75SGabriel Fernandez 2729be88e75SGabriel Fernandez return val + 1U; 2739be88e75SGabriel Fernandez } 2749be88e75SGabriel Fernandez 2759be88e75SGabriel Fernandez #define TIMEOUT_US_200MS U(200000) 2769be88e75SGabriel Fernandez #define CLKSRC_TIMEOUT TIMEOUT_US_200MS 2779be88e75SGabriel Fernandez 2789be88e75SGabriel Fernandez int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel) 2799be88e75SGabriel Fernandez { 2809be88e75SGabriel Fernandez const struct parent_cfg *parents = &priv->parents[pid & MUX_PARENT_MASK]; 2819be88e75SGabriel Fernandez const struct mux_cfg *mux = parents->mux; 2829be88e75SGabriel Fernandez uintptr_t address = priv->base + mux->offset; 2839be88e75SGabriel Fernandez uint32_t mask; 2849be88e75SGabriel Fernandez uint64_t timeout; 2859be88e75SGabriel Fernandez 2869be88e75SGabriel Fernandez mask = MASK_WIDTH_SHIFT(mux->width, mux->shift); 2879be88e75SGabriel Fernandez 2889be88e75SGabriel Fernandez mmio_clrsetbits_32(address, mask, (sel << mux->shift) & mask); 2899be88e75SGabriel Fernandez 2909be88e75SGabriel Fernandez if (mux->bitrdy == MUX_NO_BIT_RDY) { 2919be88e75SGabriel Fernandez return 0; 2929be88e75SGabriel Fernandez } 2939be88e75SGabriel Fernandez 2949be88e75SGabriel Fernandez timeout = timeout_init_us(CLKSRC_TIMEOUT); 2959be88e75SGabriel Fernandez 2969be88e75SGabriel Fernandez mask = BIT(mux->bitrdy); 2979be88e75SGabriel Fernandez 2989be88e75SGabriel Fernandez while ((mmio_read_32(address) & mask) == 0U) { 2999be88e75SGabriel Fernandez if (timeout_elapsed(timeout)) { 3009be88e75SGabriel Fernandez return -ETIMEDOUT; 3019be88e75SGabriel Fernandez } 3029be88e75SGabriel Fernandez } 3039be88e75SGabriel Fernandez 3049be88e75SGabriel Fernandez return 0; 3059be88e75SGabriel Fernandez } 3069be88e75SGabriel Fernandez 3079be88e75SGabriel Fernandez int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int clk, int clkp) 3089be88e75SGabriel Fernandez { 3099be88e75SGabriel Fernandez const struct parent_cfg *parents; 3109be88e75SGabriel Fernandez uint16_t pid; 3119be88e75SGabriel Fernandez uint8_t sel; 3129be88e75SGabriel Fernandez int old_parent; 3139be88e75SGabriel Fernandez 3149be88e75SGabriel Fernandez pid = priv->clks[clk].parent; 3159be88e75SGabriel Fernandez 3169be88e75SGabriel Fernandez if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) { 3179be88e75SGabriel Fernandez return -EINVAL; 3189be88e75SGabriel Fernandez } 3199be88e75SGabriel Fernandez 3209be88e75SGabriel Fernandez old_parent = _clk_stm32_get_parent(priv, clk); 321b8eab512SYann Gautier if (old_parent < 0) { 322b8eab512SYann Gautier return old_parent; 323b8eab512SYann Gautier } 3249be88e75SGabriel Fernandez if (old_parent == clkp) { 3259be88e75SGabriel Fernandez return 0; 3269be88e75SGabriel Fernandez } 3279be88e75SGabriel Fernandez 3289be88e75SGabriel Fernandez parents = &priv->parents[pid & MUX_PARENT_MASK]; 3299be88e75SGabriel Fernandez 3309be88e75SGabriel Fernandez for (sel = 0; sel < parents->num_parents; sel++) { 3319be88e75SGabriel Fernandez if (parents->id_parents[sel] == (uint16_t)clkp) { 3329be88e75SGabriel Fernandez bool clk_was_enabled = _clk_stm32_is_enabled(priv, clk); 3339be88e75SGabriel Fernandez int err = 0; 3349be88e75SGabriel Fernandez 3359be88e75SGabriel Fernandez /* Enable the parents (for glitch free mux) */ 3369be88e75SGabriel Fernandez _clk_stm32_enable(priv, clkp); 3379be88e75SGabriel Fernandez _clk_stm32_enable(priv, old_parent); 3389be88e75SGabriel Fernandez 3399be88e75SGabriel Fernandez err = clk_mux_set_parent(priv, pid, sel); 3409be88e75SGabriel Fernandez 3419be88e75SGabriel Fernandez _clk_stm32_disable(priv, old_parent); 3429be88e75SGabriel Fernandez 3439be88e75SGabriel Fernandez if (clk_was_enabled) { 3449be88e75SGabriel Fernandez _clk_stm32_disable(priv, old_parent); 3459be88e75SGabriel Fernandez } else { 3469be88e75SGabriel Fernandez _clk_stm32_disable(priv, clkp); 3479be88e75SGabriel Fernandez } 3489be88e75SGabriel Fernandez 3499be88e75SGabriel Fernandez return err; 3509be88e75SGabriel Fernandez } 3519be88e75SGabriel Fernandez } 3529be88e75SGabriel Fernandez 3539be88e75SGabriel Fernandez return -EINVAL; 3549be88e75SGabriel Fernandez } 3559be88e75SGabriel Fernandez 3569be88e75SGabriel Fernandez int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id) 3579be88e75SGabriel Fernandez { 3589be88e75SGabriel Fernandez const struct parent_cfg *parent; 3599be88e75SGabriel Fernandez const struct mux_cfg *mux; 3609be88e75SGabriel Fernandez uint32_t mask; 3619be88e75SGabriel Fernandez 3629be88e75SGabriel Fernandez if (mux_id >= priv->nb_parents) { 3639be88e75SGabriel Fernandez panic(); 3649be88e75SGabriel Fernandez } 3659be88e75SGabriel Fernandez 3669be88e75SGabriel Fernandez parent = &priv->parents[mux_id]; 3679be88e75SGabriel Fernandez mux = parent->mux; 3689be88e75SGabriel Fernandez 3699be88e75SGabriel Fernandez mask = MASK_WIDTH_SHIFT(mux->width, mux->shift); 3709be88e75SGabriel Fernandez 3719be88e75SGabriel Fernandez return (mmio_read_32(priv->base + mux->offset) & mask) >> mux->shift; 3729be88e75SGabriel Fernandez } 3739be88e75SGabriel Fernandez 3749be88e75SGabriel Fernandez int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel) 3759be88e75SGabriel Fernandez { 3769be88e75SGabriel Fernandez uint16_t pid; 3779be88e75SGabriel Fernandez 3789be88e75SGabriel Fernandez pid = priv->clks[clk].parent; 3799be88e75SGabriel Fernandez 3809be88e75SGabriel Fernandez if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) { 3819be88e75SGabriel Fernandez return -EINVAL; 3829be88e75SGabriel Fernandez } 3839be88e75SGabriel Fernandez 3849be88e75SGabriel Fernandez return clk_mux_set_parent(priv, pid, sel); 3859be88e75SGabriel Fernandez } 3869be88e75SGabriel Fernandez 3879be88e75SGabriel Fernandez int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int clk_id) 3889be88e75SGabriel Fernandez { 389d9a7ddebSGabriel Fernandez const struct stm32_clk_ops *ops = _clk_get_ops(priv, clk_id); 3909be88e75SGabriel Fernandez const struct parent_cfg *parent; 3919be88e75SGabriel Fernandez uint16_t mux_id; 3929be88e75SGabriel Fernandez int sel; 3939be88e75SGabriel Fernandez 3949be88e75SGabriel Fernandez mux_id = priv->clks[clk_id].parent; 3959be88e75SGabriel Fernandez if (mux_id == CLK_IS_ROOT) { 3969be88e75SGabriel Fernandez return CLK_IS_ROOT; 3979be88e75SGabriel Fernandez } 3989be88e75SGabriel Fernandez 3999be88e75SGabriel Fernandez if (mux_id < MUX_MAX_PARENTS) { 4009be88e75SGabriel Fernandez return mux_id & MUX_PARENT_MASK; 4019be88e75SGabriel Fernandez } 4029be88e75SGabriel Fernandez 4039be88e75SGabriel Fernandez mux_id &= MUX_PARENT_MASK; 4049be88e75SGabriel Fernandez parent = &priv->parents[mux_id]; 4059be88e75SGabriel Fernandez 406d9a7ddebSGabriel Fernandez if (ops->get_parent != NULL) { 407d9a7ddebSGabriel Fernandez sel = ops->get_parent(priv, clk_id); 4089be88e75SGabriel Fernandez } else { 4099be88e75SGabriel Fernandez sel = clk_mux_get_parent(priv, mux_id); 4109be88e75SGabriel Fernandez } 4119be88e75SGabriel Fernandez 412b8eab512SYann Gautier if ((sel >= 0) && (sel < parent->num_parents)) { 4139be88e75SGabriel Fernandez return parent->id_parents[sel]; 4149be88e75SGabriel Fernandez } 4159be88e75SGabriel Fernandez 4169be88e75SGabriel Fernandez return -EINVAL; 4179be88e75SGabriel Fernandez } 4189be88e75SGabriel Fernandez 4199be88e75SGabriel Fernandez int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id) 4209be88e75SGabriel Fernandez { 4219be88e75SGabriel Fernandez uint16_t mux_id; 4229be88e75SGabriel Fernandez 4239be88e75SGabriel Fernandez mux_id = priv->clks[clk_id].parent; 4249be88e75SGabriel Fernandez if (mux_id == CLK_IS_ROOT) { 4259be88e75SGabriel Fernandez return CLK_IS_ROOT; 4269be88e75SGabriel Fernandez } 4279be88e75SGabriel Fernandez 4289be88e75SGabriel Fernandez if (mux_id < MUX_MAX_PARENTS) { 4299be88e75SGabriel Fernandez return mux_id & MUX_PARENT_MASK; 4309be88e75SGabriel Fernandez } 4319be88e75SGabriel Fernandez 4329be88e75SGabriel Fernandez mux_id &= MUX_PARENT_MASK; 4339be88e75SGabriel Fernandez 4349be88e75SGabriel Fernandez return clk_mux_get_parent(priv, mux_id); 4359be88e75SGabriel Fernandez } 4369be88e75SGabriel Fernandez 4379be88e75SGabriel Fernandez int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx) 4389be88e75SGabriel Fernandez { 4399be88e75SGabriel Fernandez const struct parent_cfg *parent; 4409be88e75SGabriel Fernandez uint16_t mux_id; 4419be88e75SGabriel Fernandez 4429be88e75SGabriel Fernandez mux_id = priv->clks[clk_id].parent; 4439be88e75SGabriel Fernandez if (mux_id == CLK_IS_ROOT) { 4449be88e75SGabriel Fernandez return CLK_IS_ROOT; 4459be88e75SGabriel Fernandez } 4469be88e75SGabriel Fernandez 4479be88e75SGabriel Fernandez if (mux_id < MUX_MAX_PARENTS) { 4489be88e75SGabriel Fernandez return mux_id & MUX_PARENT_MASK; 4499be88e75SGabriel Fernandez } 4509be88e75SGabriel Fernandez 4519be88e75SGabriel Fernandez mux_id &= MUX_PARENT_MASK; 4529be88e75SGabriel Fernandez parent = &priv->parents[mux_id]; 4539be88e75SGabriel Fernandez 4549be88e75SGabriel Fernandez if (idx < parent->num_parents) { 4559be88e75SGabriel Fernandez return parent->id_parents[idx]; 4569be88e75SGabriel Fernandez } 4579be88e75SGabriel Fernandez 4589be88e75SGabriel Fernandez return -EINVAL; 4599be88e75SGabriel Fernandez } 4609be88e75SGabriel Fernandez 4619be88e75SGabriel Fernandez int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id) 4629be88e75SGabriel Fernandez { 4639be88e75SGabriel Fernandez unsigned int i; 4649be88e75SGabriel Fernandez 4659be88e75SGabriel Fernandez for (i = 0U; i < priv->num; i++) { 4669be88e75SGabriel Fernandez if (binding_id == priv->clks[i].binding) { 4679be88e75SGabriel Fernandez return (int)i; 4689be88e75SGabriel Fernandez } 4699be88e75SGabriel Fernandez } 4709be88e75SGabriel Fernandez 4719be88e75SGabriel Fernandez return -EINVAL; 4729be88e75SGabriel Fernandez } 4739be88e75SGabriel Fernandez 4749be88e75SGabriel Fernandez unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id) 4759be88e75SGabriel Fernandez { 476d9a7ddebSGabriel Fernandez const struct stm32_clk_ops *ops = _clk_get_ops(priv, id); 4779be88e75SGabriel Fernandez int parent; 4789be88e75SGabriel Fernandez 4799be88e75SGabriel Fernandez if ((unsigned int)id >= priv->num) { 48069a2e320SYann Gautier return 0UL; 4819be88e75SGabriel Fernandez } 4829be88e75SGabriel Fernandez 4839be88e75SGabriel Fernandez parent = _clk_stm32_get_parent(priv, id); 484b8eab512SYann Gautier if (parent < 0) { 485b8eab512SYann Gautier return 0UL; 486b8eab512SYann Gautier } 4879be88e75SGabriel Fernandez 488d9a7ddebSGabriel Fernandez if (ops->recalc_rate != NULL) { 4899be88e75SGabriel Fernandez unsigned long prate = 0UL; 4909be88e75SGabriel Fernandez 4919be88e75SGabriel Fernandez if (parent != CLK_IS_ROOT) { 4929be88e75SGabriel Fernandez prate = _clk_stm32_get_rate(priv, parent); 4939be88e75SGabriel Fernandez } 4949be88e75SGabriel Fernandez 495d9a7ddebSGabriel Fernandez return ops->recalc_rate(priv, id, prate); 4969be88e75SGabriel Fernandez } 4979be88e75SGabriel Fernandez 49869a2e320SYann Gautier if (parent == CLK_IS_ROOT) { 4999be88e75SGabriel Fernandez panic(); 5009be88e75SGabriel Fernandez } 5019be88e75SGabriel Fernandez 50269a2e320SYann Gautier return _clk_stm32_get_rate(priv, parent); 5039be88e75SGabriel Fernandez } 5049be88e75SGabriel Fernandez 5059be88e75SGabriel Fernandez unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id) 5069be88e75SGabriel Fernandez { 5079be88e75SGabriel Fernandez int parent_id = _clk_stm32_get_parent(priv, id); 5089be88e75SGabriel Fernandez 509b8eab512SYann Gautier if (parent_id < 0) { 510b8eab512SYann Gautier return 0UL; 511b8eab512SYann Gautier } 512b8eab512SYann Gautier 5139be88e75SGabriel Fernandez return _clk_stm32_get_rate(priv, parent_id); 5149be88e75SGabriel Fernandez } 5159be88e75SGabriel Fernandez 5169be88e75SGabriel Fernandez static uint8_t _stm32_clk_get_flags(struct stm32_clk_priv *priv, int id) 5179be88e75SGabriel Fernandez { 5189be88e75SGabriel Fernandez return priv->clks[id].flags; 5199be88e75SGabriel Fernandez } 5209be88e75SGabriel Fernandez 5219be88e75SGabriel Fernandez bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag) 5229be88e75SGabriel Fernandez { 523c3ae7da0SYann Gautier if ((_stm32_clk_get_flags(priv, id) & flag) != 0U) { 5249be88e75SGabriel Fernandez return true; 5259be88e75SGabriel Fernandez } 5269be88e75SGabriel Fernandez 5279be88e75SGabriel Fernandez return false; 5289be88e75SGabriel Fernandez } 5299be88e75SGabriel Fernandez 5309be88e75SGabriel Fernandez int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id) 5319be88e75SGabriel Fernandez { 532d9a7ddebSGabriel Fernandez const struct stm32_clk_ops *ops = _clk_get_ops(priv, id); 5339be88e75SGabriel Fernandez 534d9a7ddebSGabriel Fernandez if (ops->enable != NULL) { 535d9a7ddebSGabriel Fernandez ops->enable(priv, id); 5369be88e75SGabriel Fernandez } 5379be88e75SGabriel Fernandez 5389be88e75SGabriel Fernandez return 0; 5399be88e75SGabriel Fernandez } 5409be88e75SGabriel Fernandez 5419be88e75SGabriel Fernandez static int _clk_stm32_enable_core(struct stm32_clk_priv *priv, int id) 5429be88e75SGabriel Fernandez { 5439be88e75SGabriel Fernandez int parent; 5449be88e75SGabriel Fernandez int ret = 0; 5459be88e75SGabriel Fernandez 5469be88e75SGabriel Fernandez if (priv->gate_refcounts[id] == 0U) { 5479be88e75SGabriel Fernandez parent = _clk_stm32_get_parent(priv, id); 548b8eab512SYann Gautier if (parent < 0) { 549b8eab512SYann Gautier return parent; 550b8eab512SYann Gautier } 5519be88e75SGabriel Fernandez if (parent != CLK_IS_ROOT) { 5529be88e75SGabriel Fernandez ret = _clk_stm32_enable_core(priv, parent); 553c3ae7da0SYann Gautier if (ret != 0) { 5549be88e75SGabriel Fernandez return ret; 5559be88e75SGabriel Fernandez } 5569be88e75SGabriel Fernandez } 5579be88e75SGabriel Fernandez clk_stm32_enable_call_ops(priv, id); 5589be88e75SGabriel Fernandez } 5599be88e75SGabriel Fernandez 5609be88e75SGabriel Fernandez priv->gate_refcounts[id]++; 5619be88e75SGabriel Fernandez 562d9a7ddebSGabriel Fernandez if (priv->gate_refcounts[id] == UINT8_MAX) { 5639be88e75SGabriel Fernandez ERROR("%s: %d max enable count !", __func__, id); 5649be88e75SGabriel Fernandez panic(); 5659be88e75SGabriel Fernandez } 5669be88e75SGabriel Fernandez 5679be88e75SGabriel Fernandez return 0; 5689be88e75SGabriel Fernandez } 5699be88e75SGabriel Fernandez 5709be88e75SGabriel Fernandez int _clk_stm32_enable(struct stm32_clk_priv *priv, int id) 5719be88e75SGabriel Fernandez { 5729be88e75SGabriel Fernandez int ret; 5739be88e75SGabriel Fernandez 574*1be399b8SYann Gautier _clk_lock(&refcount_lock); 5759be88e75SGabriel Fernandez ret = _clk_stm32_enable_core(priv, id); 576*1be399b8SYann Gautier _clk_unlock(&refcount_lock); 5779be88e75SGabriel Fernandez 5789be88e75SGabriel Fernandez return ret; 5799be88e75SGabriel Fernandez } 5809be88e75SGabriel Fernandez 5819be88e75SGabriel Fernandez void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id) 5829be88e75SGabriel Fernandez { 583d9a7ddebSGabriel Fernandez const struct stm32_clk_ops *ops = _clk_get_ops(priv, id); 5849be88e75SGabriel Fernandez 585d9a7ddebSGabriel Fernandez if (ops->disable != NULL) { 586d9a7ddebSGabriel Fernandez ops->disable(priv, id); 5879be88e75SGabriel Fernandez } 5889be88e75SGabriel Fernandez } 5899be88e75SGabriel Fernandez 5909be88e75SGabriel Fernandez static void _clk_stm32_disable_core(struct stm32_clk_priv *priv, int id) 5919be88e75SGabriel Fernandez { 5929be88e75SGabriel Fernandez int parent; 5939be88e75SGabriel Fernandez 5949be88e75SGabriel Fernandez if ((priv->gate_refcounts[id] == 1U) && _stm32_clk_is_flags(priv, id, CLK_IS_CRITICAL)) { 5959be88e75SGabriel Fernandez return; 5969be88e75SGabriel Fernandez } 5979be88e75SGabriel Fernandez 5989be88e75SGabriel Fernandez if (priv->gate_refcounts[id] == 0U) { 5999be88e75SGabriel Fernandez /* case of clock ignore unused */ 6009be88e75SGabriel Fernandez if (_clk_stm32_is_enabled(priv, id)) { 6019be88e75SGabriel Fernandez clk_stm32_disable_call_ops(priv, id); 6029be88e75SGabriel Fernandez return; 6039be88e75SGabriel Fernandez } 6049be88e75SGabriel Fernandez VERBOSE("%s: %d already disabled !\n\n", __func__, id); 6059be88e75SGabriel Fernandez return; 6069be88e75SGabriel Fernandez } 6079be88e75SGabriel Fernandez 6089be88e75SGabriel Fernandez if (--priv->gate_refcounts[id] > 0U) { 6099be88e75SGabriel Fernandez return; 6109be88e75SGabriel Fernandez } 6119be88e75SGabriel Fernandez 6129be88e75SGabriel Fernandez clk_stm32_disable_call_ops(priv, id); 6139be88e75SGabriel Fernandez 6149be88e75SGabriel Fernandez parent = _clk_stm32_get_parent(priv, id); 615b8eab512SYann Gautier if ((parent >= 0) && (parent != CLK_IS_ROOT)) { 6169be88e75SGabriel Fernandez _clk_stm32_disable_core(priv, parent); 6179be88e75SGabriel Fernandez } 6189be88e75SGabriel Fernandez } 6199be88e75SGabriel Fernandez 6209be88e75SGabriel Fernandez void _clk_stm32_disable(struct stm32_clk_priv *priv, int id) 6219be88e75SGabriel Fernandez { 622*1be399b8SYann Gautier _clk_lock(&refcount_lock); 6239be88e75SGabriel Fernandez 6249be88e75SGabriel Fernandez _clk_stm32_disable_core(priv, id); 6259be88e75SGabriel Fernandez 626*1be399b8SYann Gautier _clk_unlock(&refcount_lock); 6279be88e75SGabriel Fernandez } 6289be88e75SGabriel Fernandez 6299be88e75SGabriel Fernandez bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id) 6309be88e75SGabriel Fernandez { 631d9a7ddebSGabriel Fernandez const struct stm32_clk_ops *ops = _clk_get_ops(priv, id); 6329be88e75SGabriel Fernandez 633d9a7ddebSGabriel Fernandez if (ops->is_enabled != NULL) { 634d9a7ddebSGabriel Fernandez return ops->is_enabled(priv, id); 6359be88e75SGabriel Fernandez } 6369be88e75SGabriel Fernandez 6379be88e75SGabriel Fernandez return priv->gate_refcounts[id]; 6389be88e75SGabriel Fernandez } 6399be88e75SGabriel Fernandez 6409be88e75SGabriel Fernandez static int clk_stm32_enable(unsigned long binding_id) 6419be88e75SGabriel Fernandez { 6429be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6439be88e75SGabriel Fernandez int id; 6449be88e75SGabriel Fernandez 6459be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6469be88e75SGabriel Fernandez if (id == -EINVAL) { 6479be88e75SGabriel Fernandez return id; 6489be88e75SGabriel Fernandez } 6499be88e75SGabriel Fernandez 6509be88e75SGabriel Fernandez return _clk_stm32_enable(priv, id); 6519be88e75SGabriel Fernandez } 6529be88e75SGabriel Fernandez 6539be88e75SGabriel Fernandez static void clk_stm32_disable(unsigned long binding_id) 6549be88e75SGabriel Fernandez { 6559be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6569be88e75SGabriel Fernandez int id; 6579be88e75SGabriel Fernandez 6589be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6599be88e75SGabriel Fernandez if (id != -EINVAL) { 6609be88e75SGabriel Fernandez _clk_stm32_disable(priv, id); 6619be88e75SGabriel Fernandez } 6629be88e75SGabriel Fernandez } 6639be88e75SGabriel Fernandez 6649be88e75SGabriel Fernandez static bool clk_stm32_is_enabled(unsigned long binding_id) 6659be88e75SGabriel Fernandez { 6669be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6679be88e75SGabriel Fernandez int id; 6689be88e75SGabriel Fernandez 6699be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6709be88e75SGabriel Fernandez if (id == -EINVAL) { 6719be88e75SGabriel Fernandez return false; 6729be88e75SGabriel Fernandez } 6739be88e75SGabriel Fernandez 6749be88e75SGabriel Fernandez return _clk_stm32_is_enabled(priv, id); 6759be88e75SGabriel Fernandez } 6769be88e75SGabriel Fernandez 6779be88e75SGabriel Fernandez static unsigned long clk_stm32_get_rate(unsigned long binding_id) 6789be88e75SGabriel Fernandez { 6799be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6809be88e75SGabriel Fernandez int id; 6819be88e75SGabriel Fernandez 6829be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6839be88e75SGabriel Fernandez if (id == -EINVAL) { 6849be88e75SGabriel Fernandez return 0UL; 6859be88e75SGabriel Fernandez } 6869be88e75SGabriel Fernandez 6879be88e75SGabriel Fernandez return _clk_stm32_get_rate(priv, id); 6889be88e75SGabriel Fernandez } 6899be88e75SGabriel Fernandez 6909be88e75SGabriel Fernandez static int clk_stm32_get_parent(unsigned long binding_id) 6919be88e75SGabriel Fernandez { 6929be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6939be88e75SGabriel Fernandez int id; 6949be88e75SGabriel Fernandez 6959be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6969be88e75SGabriel Fernandez if (id == -EINVAL) { 6979be88e75SGabriel Fernandez return id; 6989be88e75SGabriel Fernandez } 6999be88e75SGabriel Fernandez 7009be88e75SGabriel Fernandez return _clk_stm32_get_parent(priv, id); 7019be88e75SGabriel Fernandez } 7029be88e75SGabriel Fernandez 7039be88e75SGabriel Fernandez static const struct clk_ops stm32mp_clk_ops = { 7049be88e75SGabriel Fernandez .enable = clk_stm32_enable, 7059be88e75SGabriel Fernandez .disable = clk_stm32_disable, 7069be88e75SGabriel Fernandez .is_enabled = clk_stm32_is_enabled, 7079be88e75SGabriel Fernandez .get_rate = clk_stm32_get_rate, 7089be88e75SGabriel Fernandez .get_parent = clk_stm32_get_parent, 7099be88e75SGabriel Fernandez }; 7109be88e75SGabriel Fernandez 7119be88e75SGabriel Fernandez void clk_stm32_enable_critical_clocks(void) 7129be88e75SGabriel Fernandez { 7139be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 7149be88e75SGabriel Fernandez unsigned int i; 7159be88e75SGabriel Fernandez 7169be88e75SGabriel Fernandez for (i = 0U; i < priv->num; i++) { 7179be88e75SGabriel Fernandez if (_stm32_clk_is_flags(priv, i, CLK_IS_CRITICAL)) { 7189be88e75SGabriel Fernandez _clk_stm32_enable(priv, i); 7199be88e75SGabriel Fernandez } 7209be88e75SGabriel Fernandez } 7219be88e75SGabriel Fernandez } 7229be88e75SGabriel Fernandez 7239be88e75SGabriel Fernandez static void stm32_clk_register(void) 7249be88e75SGabriel Fernandez { 7259be88e75SGabriel Fernandez clk_register(&stm32mp_clk_ops); 7269be88e75SGabriel Fernandez } 7279be88e75SGabriel Fernandez 7289be88e75SGabriel Fernandez uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id) 7299be88e75SGabriel Fernandez { 7309be88e75SGabriel Fernandez const struct div_cfg *divider = &priv->div[div_id]; 7319be88e75SGabriel Fernandez uint32_t val = 0; 7329be88e75SGabriel Fernandez 7339be88e75SGabriel Fernandez val = mmio_read_32(priv->base + divider->offset) >> divider->shift; 7349be88e75SGabriel Fernandez val &= clk_div_mask(divider->width); 7359be88e75SGabriel Fernandez 7369be88e75SGabriel Fernandez return val; 7379be88e75SGabriel Fernandez } 7389be88e75SGabriel Fernandez 7399be88e75SGabriel Fernandez unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv, 7409be88e75SGabriel Fernandez int div_id, 7419be88e75SGabriel Fernandez unsigned long prate) 7429be88e75SGabriel Fernandez { 7439be88e75SGabriel Fernandez const struct div_cfg *divider = &priv->div[div_id]; 7449be88e75SGabriel Fernandez uint32_t val = clk_stm32_div_get_value(priv, div_id); 7459be88e75SGabriel Fernandez unsigned int div = 0U; 7469be88e75SGabriel Fernandez 7479be88e75SGabriel Fernandez div = _get_div(divider->table, val, divider->flags, divider->width); 7489be88e75SGabriel Fernandez if (div == 0U) { 7499be88e75SGabriel Fernandez return prate; 7509be88e75SGabriel Fernandez } 7519be88e75SGabriel Fernandez 7529be88e75SGabriel Fernandez return div_round_up((uint64_t)prate, div); 7539be88e75SGabriel Fernandez } 7549be88e75SGabriel Fernandez 7559be88e75SGabriel Fernandez unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int id, 7569be88e75SGabriel Fernandez unsigned long prate) 7579be88e75SGabriel Fernandez { 7589be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 7599be88e75SGabriel Fernandez struct clk_stm32_div_cfg *div_cfg = clk->clock_cfg; 7609be88e75SGabriel Fernandez 7619be88e75SGabriel Fernandez return _clk_stm32_divider_recalc(priv, div_cfg->id, prate); 7629be88e75SGabriel Fernandez } 7639be88e75SGabriel Fernandez 7649be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_divider_ops = { 7659be88e75SGabriel Fernandez .recalc_rate = clk_stm32_divider_recalc, 7669be88e75SGabriel Fernandez }; 7679be88e75SGabriel Fernandez 7689be88e75SGabriel Fernandez int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value) 7699be88e75SGabriel Fernandez { 7709be88e75SGabriel Fernandez const struct div_cfg *divider; 7719be88e75SGabriel Fernandez uintptr_t address; 7729be88e75SGabriel Fernandez uint64_t timeout; 7739be88e75SGabriel Fernandez uint32_t mask; 7749be88e75SGabriel Fernandez 7759be88e75SGabriel Fernandez if (div_id >= priv->nb_div) { 7769be88e75SGabriel Fernandez panic(); 7779be88e75SGabriel Fernandez } 7789be88e75SGabriel Fernandez 7799be88e75SGabriel Fernandez divider = &priv->div[div_id]; 7809be88e75SGabriel Fernandez address = priv->base + divider->offset; 7819be88e75SGabriel Fernandez 7829be88e75SGabriel Fernandez mask = MASK_WIDTH_SHIFT(divider->width, divider->shift); 7839be88e75SGabriel Fernandez mmio_clrsetbits_32(address, mask, (value << divider->shift) & mask); 7849be88e75SGabriel Fernandez 7859be88e75SGabriel Fernandez if (divider->bitrdy == DIV_NO_BIT_RDY) { 7869be88e75SGabriel Fernandez return 0; 7879be88e75SGabriel Fernandez } 7889be88e75SGabriel Fernandez 7899be88e75SGabriel Fernandez timeout = timeout_init_us(CLKSRC_TIMEOUT); 7909be88e75SGabriel Fernandez mask = BIT(divider->bitrdy); 7919be88e75SGabriel Fernandez 7929be88e75SGabriel Fernandez while ((mmio_read_32(address) & mask) == 0U) { 7939be88e75SGabriel Fernandez if (timeout_elapsed(timeout)) { 7949be88e75SGabriel Fernandez return -ETIMEDOUT; 7959be88e75SGabriel Fernandez } 7969be88e75SGabriel Fernandez } 7979be88e75SGabriel Fernandez 7989be88e75SGabriel Fernandez return 0; 7999be88e75SGabriel Fernandez } 8009be88e75SGabriel Fernandez 8019be88e75SGabriel Fernandez int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id, 8029be88e75SGabriel Fernandez bool ready_on) 8039be88e75SGabriel Fernandez { 8049be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[gate_id]; 8059be88e75SGabriel Fernandez uintptr_t address = priv->base + gate->offset; 8069be88e75SGabriel Fernandez uint32_t mask_rdy = BIT(gate->bit_idx); 8079be88e75SGabriel Fernandez uint64_t timeout; 8089be88e75SGabriel Fernandez uint32_t mask_test; 8099be88e75SGabriel Fernandez 8109be88e75SGabriel Fernandez if (ready_on) { 8119be88e75SGabriel Fernandez mask_test = BIT(gate->bit_idx); 8129be88e75SGabriel Fernandez } else { 8139be88e75SGabriel Fernandez mask_test = 0U; 8149be88e75SGabriel Fernandez } 8159be88e75SGabriel Fernandez 8169be88e75SGabriel Fernandez timeout = timeout_init_us(OSCRDY_TIMEOUT); 8179be88e75SGabriel Fernandez 8189be88e75SGabriel Fernandez while ((mmio_read_32(address) & mask_rdy) != mask_test) { 8199be88e75SGabriel Fernandez if (timeout_elapsed(timeout)) { 8209be88e75SGabriel Fernandez break; 8219be88e75SGabriel Fernandez } 8229be88e75SGabriel Fernandez } 8239be88e75SGabriel Fernandez 82456f895edSYann Gautier if ((mmio_read_32(address) & mask_rdy) != mask_test) { 8259be88e75SGabriel Fernandez return -ETIMEDOUT; 82656f895edSYann Gautier } 8279be88e75SGabriel Fernandez 8289be88e75SGabriel Fernandez return 0; 8299be88e75SGabriel Fernandez } 8309be88e75SGabriel Fernandez 8319be88e75SGabriel Fernandez int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int id) 8329be88e75SGabriel Fernandez { 8339be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8349be88e75SGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->clock_cfg; 8359be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[cfg->id]; 8369be88e75SGabriel Fernandez uintptr_t addr = priv->base + gate->offset; 8379be88e75SGabriel Fernandez 8389be88e75SGabriel Fernandez if (gate->set_clr != 0U) { 8399be88e75SGabriel Fernandez mmio_write_32(addr, BIT(gate->bit_idx)); 8409be88e75SGabriel Fernandez 8419be88e75SGabriel Fernandez } else { 8429be88e75SGabriel Fernandez mmio_setbits_32(addr, BIT(gate->bit_idx)); 8439be88e75SGabriel Fernandez } 8449be88e75SGabriel Fernandez 8459be88e75SGabriel Fernandez return 0; 8469be88e75SGabriel Fernandez } 8479be88e75SGabriel Fernandez 8489be88e75SGabriel Fernandez void clk_stm32_gate_disable(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 + RCC_MP_ENCLRR_OFFSET, BIT(gate->bit_idx)); 8579be88e75SGabriel Fernandez } else { 8589be88e75SGabriel Fernandez mmio_clrbits_32(addr, BIT(gate->bit_idx)); 8599be88e75SGabriel Fernandez } 8609be88e75SGabriel Fernandez } 8619be88e75SGabriel Fernandez 8629be88e75SGabriel Fernandez bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id) 8639be88e75SGabriel Fernandez { 8649be88e75SGabriel Fernandez const struct gate_cfg *gate; 8659be88e75SGabriel Fernandez uint32_t addr; 8669be88e75SGabriel Fernandez 8679be88e75SGabriel Fernandez gate = &priv->gates[gate_id]; 8689be88e75SGabriel Fernandez addr = priv->base + gate->offset; 8699be88e75SGabriel Fernandez 8709be88e75SGabriel Fernandez return ((mmio_read_32(addr) & BIT(gate->bit_idx)) != 0U); 8719be88e75SGabriel Fernandez } 8729be88e75SGabriel Fernandez 8739be88e75SGabriel Fernandez bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int id) 8749be88e75SGabriel Fernandez { 8759be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8769be88e75SGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->clock_cfg; 8779be88e75SGabriel Fernandez 8789be88e75SGabriel Fernandez return _clk_stm32_gate_is_enabled(priv, cfg->id); 8799be88e75SGabriel Fernandez } 8809be88e75SGabriel Fernandez 8819be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_gate_ops = { 8829be88e75SGabriel Fernandez .enable = clk_stm32_gate_enable, 8839be88e75SGabriel Fernandez .disable = clk_stm32_gate_disable, 8849be88e75SGabriel Fernandez .is_enabled = clk_stm32_gate_is_enabled, 8859be88e75SGabriel Fernandez }; 8869be88e75SGabriel Fernandez 8879be88e75SGabriel Fernandez const struct stm32_clk_ops clk_fixed_factor_ops = { 8889be88e75SGabriel Fernandez .recalc_rate = fixed_factor_recalc_rate, 8899be88e75SGabriel Fernandez }; 8909be88e75SGabriel Fernandez 8919be88e75SGabriel Fernandez unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv, 8929be88e75SGabriel Fernandez int id, unsigned long prate) 8939be88e75SGabriel Fernandez { 8949be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8959be88e75SGabriel Fernandez const struct fixed_factor_cfg *cfg = clk->clock_cfg; 8969be88e75SGabriel Fernandez unsigned long long rate; 8979be88e75SGabriel Fernandez 8989be88e75SGabriel Fernandez rate = (unsigned long long)prate * cfg->mult; 8999be88e75SGabriel Fernandez 9009be88e75SGabriel Fernandez if (cfg->div == 0U) { 9019be88e75SGabriel Fernandez ERROR("division by zero\n"); 9029be88e75SGabriel Fernandez panic(); 9039be88e75SGabriel Fernandez } 9049be88e75SGabriel Fernandez 9059be88e75SGabriel Fernandez return (unsigned long)(rate / cfg->div); 9069be88e75SGabriel Fernandez }; 9079be88e75SGabriel Fernandez 9089be88e75SGabriel Fernandez #define APB_DIV_MASK GENMASK(2, 0) 9099be88e75SGabriel Fernandez #define TIM_PRE_MASK BIT(0) 9109be88e75SGabriel Fernandez 9119be88e75SGabriel Fernandez static unsigned long timer_recalc_rate(struct stm32_clk_priv *priv, 9129be88e75SGabriel Fernandez int id, unsigned long prate) 9139be88e75SGabriel Fernandez { 9149be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 9159be88e75SGabriel Fernandez const struct clk_timer_cfg *cfg = clk->clock_cfg; 9169be88e75SGabriel Fernandez uint32_t prescaler, timpre; 9179be88e75SGabriel Fernandez uintptr_t rcc_base = priv->base; 9189be88e75SGabriel Fernandez 9199be88e75SGabriel Fernandez prescaler = mmio_read_32(rcc_base + cfg->apbdiv) & 9209be88e75SGabriel Fernandez APB_DIV_MASK; 9219be88e75SGabriel Fernandez 9229be88e75SGabriel Fernandez timpre = mmio_read_32(rcc_base + cfg->timpre) & 9239be88e75SGabriel Fernandez TIM_PRE_MASK; 9249be88e75SGabriel Fernandez 9259be88e75SGabriel Fernandez if (prescaler == 0U) { 9269be88e75SGabriel Fernandez return prate; 9279be88e75SGabriel Fernandez } 9289be88e75SGabriel Fernandez 9299be88e75SGabriel Fernandez return prate * (timpre + 1U) * 2U; 9309be88e75SGabriel Fernandez }; 9319be88e75SGabriel Fernandez 9329be88e75SGabriel Fernandez const struct stm32_clk_ops clk_timer_ops = { 9339be88e75SGabriel Fernandez .recalc_rate = timer_recalc_rate, 9349be88e75SGabriel Fernandez }; 9359be88e75SGabriel Fernandez 9369be88e75SGabriel Fernandez static unsigned long clk_fixed_rate_recalc(struct stm32_clk_priv *priv, int id, 9379be88e75SGabriel Fernandez unsigned long prate) 9389be88e75SGabriel Fernandez { 9399be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 9409be88e75SGabriel Fernandez struct clk_stm32_fixed_rate_cfg *cfg = clk->clock_cfg; 9419be88e75SGabriel Fernandez 9429be88e75SGabriel Fernandez return cfg->rate; 9439be88e75SGabriel Fernandez } 9449be88e75SGabriel Fernandez 9459be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_fixed_rate_ops = { 9469be88e75SGabriel Fernandez .recalc_rate = clk_fixed_rate_recalc, 9479be88e75SGabriel Fernandez }; 9489be88e75SGabriel Fernandez 9499be88e75SGabriel Fernandez static unsigned long clk_stm32_osc_recalc_rate(struct stm32_clk_priv *priv, 9509be88e75SGabriel Fernandez int id, unsigned long prate) 9519be88e75SGabriel Fernandez { 9529be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9539be88e75SGabriel Fernandez 9549be88e75SGabriel Fernandez return osc_data->frequency; 9559be88e75SGabriel Fernandez }; 9569be88e75SGabriel Fernandez 9579be88e75SGabriel Fernandez bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id) 9589be88e75SGabriel Fernandez { 9599be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9609be88e75SGabriel Fernandez 9619be88e75SGabriel Fernandez return _clk_stm32_gate_is_enabled(priv, osc_data->gate_id); 9629be88e75SGabriel Fernandez 9639be88e75SGabriel Fernandez } 9649be88e75SGabriel Fernandez 9659be88e75SGabriel Fernandez int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id) 9669be88e75SGabriel Fernandez { 9679be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9689be88e75SGabriel Fernandez 969f2aebab8SGabriel Fernandez if (osc_data->frequency == 0UL) { 970f2aebab8SGabriel Fernandez return 0; 971f2aebab8SGabriel Fernandez } 972f2aebab8SGabriel Fernandez 9739be88e75SGabriel Fernandez _clk_stm32_gate_enable(priv, osc_data->gate_id); 9749be88e75SGabriel Fernandez 9759be88e75SGabriel Fernandez if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, true) != 0U) { 9769be88e75SGabriel Fernandez ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__); 9779be88e75SGabriel Fernandez panic(); 9789be88e75SGabriel Fernandez } 9799be88e75SGabriel Fernandez 9809be88e75SGabriel Fernandez return 0; 9819be88e75SGabriel Fernandez } 9829be88e75SGabriel Fernandez 9839be88e75SGabriel Fernandez void clk_stm32_osc_gate_disable(struct stm32_clk_priv *priv, int id) 9849be88e75SGabriel Fernandez { 9859be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9869be88e75SGabriel Fernandez 987f2aebab8SGabriel Fernandez if (osc_data->frequency == 0UL) { 988f2aebab8SGabriel Fernandez return; 989f2aebab8SGabriel Fernandez } 990f2aebab8SGabriel Fernandez 9919be88e75SGabriel Fernandez _clk_stm32_gate_disable(priv, osc_data->gate_id); 9929be88e75SGabriel Fernandez 9939be88e75SGabriel Fernandez if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, false) != 0U) { 9949be88e75SGabriel Fernandez ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__); 9959be88e75SGabriel Fernandez panic(); 9969be88e75SGabriel Fernandez } 9979be88e75SGabriel Fernandez } 9989be88e75SGabriel Fernandez 9999be88e75SGabriel Fernandez static unsigned long clk_stm32_get_dt_oscillator_frequency(const char *name) 10009be88e75SGabriel Fernandez { 10019be88e75SGabriel Fernandez void *fdt = NULL; 10029be88e75SGabriel Fernandez int node = 0; 10039be88e75SGabriel Fernandez int subnode = 0; 10049be88e75SGabriel Fernandez 10059be88e75SGabriel Fernandez if (fdt_get_address(&fdt) == 0) { 10069be88e75SGabriel Fernandez panic(); 10079be88e75SGabriel Fernandez } 10089be88e75SGabriel Fernandez 10099be88e75SGabriel Fernandez node = fdt_path_offset(fdt, "/clocks"); 10109be88e75SGabriel Fernandez if (node < 0) { 10119be88e75SGabriel Fernandez return 0UL; 10129be88e75SGabriel Fernandez } 10139be88e75SGabriel Fernandez 10149be88e75SGabriel Fernandez fdt_for_each_subnode(subnode, fdt, node) { 10159be88e75SGabriel Fernandez const char *cchar = NULL; 10169be88e75SGabriel Fernandez const fdt32_t *cuint = NULL; 10179be88e75SGabriel Fernandez int ret = 0; 10189be88e75SGabriel Fernandez 10199be88e75SGabriel Fernandez cchar = fdt_get_name(fdt, subnode, &ret); 10209be88e75SGabriel Fernandez if (cchar == NULL) { 10219be88e75SGabriel Fernandez continue; 10229be88e75SGabriel Fernandez } 10239be88e75SGabriel Fernandez 10249be88e75SGabriel Fernandez if (strncmp(cchar, name, (size_t)ret) || 10259be88e75SGabriel Fernandez fdt_get_status(subnode) == DT_DISABLED) { 10269be88e75SGabriel Fernandez continue; 10279be88e75SGabriel Fernandez } 10289be88e75SGabriel Fernandez 10299be88e75SGabriel Fernandez cuint = fdt_getprop(fdt, subnode, "clock-frequency", &ret); 10309be88e75SGabriel Fernandez if (cuint == NULL) { 10319be88e75SGabriel Fernandez return 0UL; 10329be88e75SGabriel Fernandez } 10339be88e75SGabriel Fernandez 10349be88e75SGabriel Fernandez return fdt32_to_cpu(*cuint); 10359be88e75SGabriel Fernandez } 10369be88e75SGabriel Fernandez 10379be88e75SGabriel Fernandez return 0UL; 10389be88e75SGabriel Fernandez } 10399be88e75SGabriel Fernandez 10409be88e75SGabriel Fernandez void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id) 10419be88e75SGabriel Fernandez { 10429be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 10439be88e75SGabriel Fernandez const char *name = osc_data->name; 10449be88e75SGabriel Fernandez 10459be88e75SGabriel Fernandez osc_data->frequency = clk_stm32_get_dt_oscillator_frequency(name); 10469be88e75SGabriel Fernandez } 10479be88e75SGabriel Fernandez 10489be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_osc_ops = { 10499be88e75SGabriel Fernandez .recalc_rate = clk_stm32_osc_recalc_rate, 10509be88e75SGabriel Fernandez .is_enabled = clk_stm32_osc_gate_is_enabled, 10519be88e75SGabriel Fernandez .enable = clk_stm32_osc_gate_enable, 10529be88e75SGabriel Fernandez .disable = clk_stm32_osc_gate_disable, 10539be88e75SGabriel Fernandez .init = clk_stm32_osc_init, 10549be88e75SGabriel Fernandez }; 10559be88e75SGabriel Fernandez 10569be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_osc_nogate_ops = { 10579be88e75SGabriel Fernandez .recalc_rate = clk_stm32_osc_recalc_rate, 10589be88e75SGabriel Fernandez .init = clk_stm32_osc_init, 10599be88e75SGabriel Fernandez }; 10609be88e75SGabriel Fernandez 10619be88e75SGabriel Fernandez int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb) 10629be88e75SGabriel Fernandez { 10639be88e75SGabriel Fernandez const fdt32_t *cell; 10649be88e75SGabriel Fernandez int len = 0; 10659be88e75SGabriel Fernandez uint32_t i; 10669be88e75SGabriel Fernandez 10679be88e75SGabriel Fernandez cell = fdt_getprop(fdt, node, name, &len); 10687417cda6SYann Gautier if (cell == NULL) { 10697417cda6SYann Gautier *nb = 0U; 10707417cda6SYann Gautier return 0; 10717417cda6SYann Gautier } 10727417cda6SYann Gautier 10739be88e75SGabriel Fernandez for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 10749be88e75SGabriel Fernandez uint32_t val = fdt32_to_cpu(cell[i]); 10759be88e75SGabriel Fernandez 10769be88e75SGabriel Fernandez tab[i] = val; 10779be88e75SGabriel Fernandez } 10789be88e75SGabriel Fernandez 10799be88e75SGabriel Fernandez *nb = (uint32_t)len / sizeof(uint32_t); 10809be88e75SGabriel Fernandez 10819be88e75SGabriel Fernandez return 0; 10829be88e75SGabriel Fernandez } 10839be88e75SGabriel Fernandez 10849be88e75SGabriel Fernandez int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base) 10859be88e75SGabriel Fernandez { 10869be88e75SGabriel Fernandez unsigned int i; 10879be88e75SGabriel Fernandez 10889be88e75SGabriel Fernandez stm32_clock_data = priv; 10899be88e75SGabriel Fernandez 10909be88e75SGabriel Fernandez priv->base = base; 10919be88e75SGabriel Fernandez 10929be88e75SGabriel Fernandez for (i = 0U; i < priv->num; i++) { 1093d9a7ddebSGabriel Fernandez const struct stm32_clk_ops *ops = _clk_get_ops(priv, i); 10949be88e75SGabriel Fernandez 1095d9a7ddebSGabriel Fernandez if (ops->init != NULL) { 1096d9a7ddebSGabriel Fernandez ops->init(priv, i); 10979be88e75SGabriel Fernandez } 10989be88e75SGabriel Fernandez } 10999be88e75SGabriel Fernandez 11009be88e75SGabriel Fernandez stm32_clk_register(); 11019be88e75SGabriel Fernandez 11029be88e75SGabriel Fernandez return 0; 11039be88e75SGabriel Fernandez } 1104