19be88e75SGabriel Fernandez /* 2*f2aebab8SGabriel 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 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 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 2279be88e75SGabriel Fernandez #define clk_div_mask(_width) GENMASK(((_width) - 1U), 0U) 2289be88e75SGabriel Fernandez 2299be88e75SGabriel Fernandez static unsigned int _get_table_div(const struct clk_div_table *table, 2309be88e75SGabriel Fernandez unsigned int val) 2319be88e75SGabriel Fernandez { 2329be88e75SGabriel Fernandez const struct clk_div_table *clkt; 2339be88e75SGabriel Fernandez 2349be88e75SGabriel Fernandez for (clkt = table; clkt->div; clkt++) { 2359be88e75SGabriel Fernandez if (clkt->val == val) { 2369be88e75SGabriel Fernandez return clkt->div; 2379be88e75SGabriel Fernandez } 2389be88e75SGabriel Fernandez } 2399be88e75SGabriel Fernandez 2409be88e75SGabriel Fernandez return 0; 2419be88e75SGabriel Fernandez } 2429be88e75SGabriel Fernandez 2439be88e75SGabriel Fernandez static unsigned int _get_div(const struct clk_div_table *table, 2449be88e75SGabriel Fernandez unsigned int val, unsigned long flags, 2459be88e75SGabriel Fernandez uint8_t width) 2469be88e75SGabriel Fernandez { 2479be88e75SGabriel Fernandez if ((flags & CLK_DIVIDER_ONE_BASED) != 0UL) { 2489be88e75SGabriel Fernandez return val; 2499be88e75SGabriel Fernandez } 2509be88e75SGabriel Fernandez 2519be88e75SGabriel Fernandez if ((flags & CLK_DIVIDER_POWER_OF_TWO) != 0UL) { 2529be88e75SGabriel Fernandez return BIT(val); 2539be88e75SGabriel Fernandez } 2549be88e75SGabriel Fernandez 2559be88e75SGabriel Fernandez if ((flags & CLK_DIVIDER_MAX_AT_ZERO) != 0UL) { 2569be88e75SGabriel Fernandez return (val != 0U) ? val : BIT(width); 2579be88e75SGabriel Fernandez } 2589be88e75SGabriel Fernandez 2599be88e75SGabriel Fernandez if (table != NULL) { 2609be88e75SGabriel Fernandez return _get_table_div(table, val); 2619be88e75SGabriel Fernandez } 2629be88e75SGabriel Fernandez 2639be88e75SGabriel Fernandez return val + 1U; 2649be88e75SGabriel Fernandez } 2659be88e75SGabriel Fernandez 2669be88e75SGabriel Fernandez #define TIMEOUT_US_200MS U(200000) 2679be88e75SGabriel Fernandez #define CLKSRC_TIMEOUT TIMEOUT_US_200MS 2689be88e75SGabriel Fernandez 2699be88e75SGabriel Fernandez int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel) 2709be88e75SGabriel Fernandez { 2719be88e75SGabriel Fernandez const struct parent_cfg *parents = &priv->parents[pid & MUX_PARENT_MASK]; 2729be88e75SGabriel Fernandez const struct mux_cfg *mux = parents->mux; 2739be88e75SGabriel Fernandez uintptr_t address = priv->base + mux->offset; 2749be88e75SGabriel Fernandez uint32_t mask; 2759be88e75SGabriel Fernandez uint64_t timeout; 2769be88e75SGabriel Fernandez 2779be88e75SGabriel Fernandez mask = MASK_WIDTH_SHIFT(mux->width, mux->shift); 2789be88e75SGabriel Fernandez 2799be88e75SGabriel Fernandez mmio_clrsetbits_32(address, mask, (sel << mux->shift) & mask); 2809be88e75SGabriel Fernandez 2819be88e75SGabriel Fernandez if (mux->bitrdy == MUX_NO_BIT_RDY) { 2829be88e75SGabriel Fernandez return 0; 2839be88e75SGabriel Fernandez } 2849be88e75SGabriel Fernandez 2859be88e75SGabriel Fernandez timeout = timeout_init_us(CLKSRC_TIMEOUT); 2869be88e75SGabriel Fernandez 2879be88e75SGabriel Fernandez mask = BIT(mux->bitrdy); 2889be88e75SGabriel Fernandez 2899be88e75SGabriel Fernandez while ((mmio_read_32(address) & mask) == 0U) { 2909be88e75SGabriel Fernandez if (timeout_elapsed(timeout)) { 2919be88e75SGabriel Fernandez return -ETIMEDOUT; 2929be88e75SGabriel Fernandez } 2939be88e75SGabriel Fernandez } 2949be88e75SGabriel Fernandez 2959be88e75SGabriel Fernandez return 0; 2969be88e75SGabriel Fernandez } 2979be88e75SGabriel Fernandez 2989be88e75SGabriel Fernandez int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int clk, int clkp) 2999be88e75SGabriel Fernandez { 3009be88e75SGabriel Fernandez const struct parent_cfg *parents; 3019be88e75SGabriel Fernandez uint16_t pid; 3029be88e75SGabriel Fernandez uint8_t sel; 3039be88e75SGabriel Fernandez int old_parent; 3049be88e75SGabriel Fernandez 3059be88e75SGabriel Fernandez pid = priv->clks[clk].parent; 3069be88e75SGabriel Fernandez 3079be88e75SGabriel Fernandez if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) { 3089be88e75SGabriel Fernandez return -EINVAL; 3099be88e75SGabriel Fernandez } 3109be88e75SGabriel Fernandez 3119be88e75SGabriel Fernandez old_parent = _clk_stm32_get_parent(priv, clk); 312b8eab512SYann Gautier if (old_parent < 0) { 313b8eab512SYann Gautier return old_parent; 314b8eab512SYann Gautier } 3159be88e75SGabriel Fernandez if (old_parent == clkp) { 3169be88e75SGabriel Fernandez return 0; 3179be88e75SGabriel Fernandez } 3189be88e75SGabriel Fernandez 3199be88e75SGabriel Fernandez parents = &priv->parents[pid & MUX_PARENT_MASK]; 3209be88e75SGabriel Fernandez 3219be88e75SGabriel Fernandez for (sel = 0; sel < parents->num_parents; sel++) { 3229be88e75SGabriel Fernandez if (parents->id_parents[sel] == (uint16_t)clkp) { 3239be88e75SGabriel Fernandez bool clk_was_enabled = _clk_stm32_is_enabled(priv, clk); 3249be88e75SGabriel Fernandez int err = 0; 3259be88e75SGabriel Fernandez 3269be88e75SGabriel Fernandez /* Enable the parents (for glitch free mux) */ 3279be88e75SGabriel Fernandez _clk_stm32_enable(priv, clkp); 3289be88e75SGabriel Fernandez _clk_stm32_enable(priv, old_parent); 3299be88e75SGabriel Fernandez 3309be88e75SGabriel Fernandez err = clk_mux_set_parent(priv, pid, sel); 3319be88e75SGabriel Fernandez 3329be88e75SGabriel Fernandez _clk_stm32_disable(priv, old_parent); 3339be88e75SGabriel Fernandez 3349be88e75SGabriel Fernandez if (clk_was_enabled) { 3359be88e75SGabriel Fernandez _clk_stm32_disable(priv, old_parent); 3369be88e75SGabriel Fernandez } else { 3379be88e75SGabriel Fernandez _clk_stm32_disable(priv, clkp); 3389be88e75SGabriel Fernandez } 3399be88e75SGabriel Fernandez 3409be88e75SGabriel Fernandez return err; 3419be88e75SGabriel Fernandez } 3429be88e75SGabriel Fernandez } 3439be88e75SGabriel Fernandez 3449be88e75SGabriel Fernandez return -EINVAL; 3459be88e75SGabriel Fernandez } 3469be88e75SGabriel Fernandez 3479be88e75SGabriel Fernandez int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id) 3489be88e75SGabriel Fernandez { 3499be88e75SGabriel Fernandez const struct parent_cfg *parent; 3509be88e75SGabriel Fernandez const struct mux_cfg *mux; 3519be88e75SGabriel Fernandez uint32_t mask; 3529be88e75SGabriel Fernandez 3539be88e75SGabriel Fernandez if (mux_id >= priv->nb_parents) { 3549be88e75SGabriel Fernandez panic(); 3559be88e75SGabriel Fernandez } 3569be88e75SGabriel Fernandez 3579be88e75SGabriel Fernandez parent = &priv->parents[mux_id]; 3589be88e75SGabriel Fernandez mux = parent->mux; 3599be88e75SGabriel Fernandez 3609be88e75SGabriel Fernandez mask = MASK_WIDTH_SHIFT(mux->width, mux->shift); 3619be88e75SGabriel Fernandez 3629be88e75SGabriel Fernandez return (mmio_read_32(priv->base + mux->offset) & mask) >> mux->shift; 3639be88e75SGabriel Fernandez } 3649be88e75SGabriel Fernandez 3659be88e75SGabriel Fernandez int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel) 3669be88e75SGabriel Fernandez { 3679be88e75SGabriel Fernandez uint16_t pid; 3689be88e75SGabriel Fernandez 3699be88e75SGabriel Fernandez pid = priv->clks[clk].parent; 3709be88e75SGabriel Fernandez 3719be88e75SGabriel Fernandez if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) { 3729be88e75SGabriel Fernandez return -EINVAL; 3739be88e75SGabriel Fernandez } 3749be88e75SGabriel Fernandez 3759be88e75SGabriel Fernandez return clk_mux_set_parent(priv, pid, sel); 3769be88e75SGabriel Fernandez } 3779be88e75SGabriel Fernandez 3789be88e75SGabriel Fernandez int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int clk_id) 3799be88e75SGabriel Fernandez { 3809be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, clk_id); 3819be88e75SGabriel Fernandez const struct parent_cfg *parent; 3829be88e75SGabriel Fernandez uint16_t mux_id; 3839be88e75SGabriel Fernandez int sel; 3849be88e75SGabriel Fernandez 3859be88e75SGabriel Fernandez mux_id = priv->clks[clk_id].parent; 3869be88e75SGabriel Fernandez if (mux_id == CLK_IS_ROOT) { 3879be88e75SGabriel Fernandez return CLK_IS_ROOT; 3889be88e75SGabriel Fernandez } 3899be88e75SGabriel Fernandez 3909be88e75SGabriel Fernandez if (mux_id < MUX_MAX_PARENTS) { 3919be88e75SGabriel Fernandez return mux_id & MUX_PARENT_MASK; 3929be88e75SGabriel Fernandez } 3939be88e75SGabriel Fernandez 3949be88e75SGabriel Fernandez mux_id &= MUX_PARENT_MASK; 3959be88e75SGabriel Fernandez parent = &priv->parents[mux_id]; 3969be88e75SGabriel Fernandez 3979be88e75SGabriel Fernandez if (clk->ops->get_parent != NULL) { 3989be88e75SGabriel Fernandez sel = clk->ops->get_parent(priv, clk_id); 3999be88e75SGabriel Fernandez } else { 4009be88e75SGabriel Fernandez sel = clk_mux_get_parent(priv, mux_id); 4019be88e75SGabriel Fernandez } 4029be88e75SGabriel Fernandez 403b8eab512SYann Gautier if ((sel >= 0) && (sel < parent->num_parents)) { 4049be88e75SGabriel Fernandez return parent->id_parents[sel]; 4059be88e75SGabriel Fernandez } 4069be88e75SGabriel Fernandez 4079be88e75SGabriel Fernandez return -EINVAL; 4089be88e75SGabriel Fernandez } 4099be88e75SGabriel Fernandez 4109be88e75SGabriel Fernandez int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id) 4119be88e75SGabriel Fernandez { 4129be88e75SGabriel Fernandez uint16_t mux_id; 4139be88e75SGabriel Fernandez 4149be88e75SGabriel Fernandez mux_id = priv->clks[clk_id].parent; 4159be88e75SGabriel Fernandez if (mux_id == CLK_IS_ROOT) { 4169be88e75SGabriel Fernandez return CLK_IS_ROOT; 4179be88e75SGabriel Fernandez } 4189be88e75SGabriel Fernandez 4199be88e75SGabriel Fernandez if (mux_id < MUX_MAX_PARENTS) { 4209be88e75SGabriel Fernandez return mux_id & MUX_PARENT_MASK; 4219be88e75SGabriel Fernandez } 4229be88e75SGabriel Fernandez 4239be88e75SGabriel Fernandez mux_id &= MUX_PARENT_MASK; 4249be88e75SGabriel Fernandez 4259be88e75SGabriel Fernandez return clk_mux_get_parent(priv, mux_id); 4269be88e75SGabriel Fernandez } 4279be88e75SGabriel Fernandez 4289be88e75SGabriel Fernandez int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx) 4299be88e75SGabriel Fernandez { 4309be88e75SGabriel Fernandez const struct parent_cfg *parent; 4319be88e75SGabriel Fernandez uint16_t mux_id; 4329be88e75SGabriel Fernandez 4339be88e75SGabriel Fernandez mux_id = priv->clks[clk_id].parent; 4349be88e75SGabriel Fernandez if (mux_id == CLK_IS_ROOT) { 4359be88e75SGabriel Fernandez return CLK_IS_ROOT; 4369be88e75SGabriel Fernandez } 4379be88e75SGabriel Fernandez 4389be88e75SGabriel Fernandez if (mux_id < MUX_MAX_PARENTS) { 4399be88e75SGabriel Fernandez return mux_id & MUX_PARENT_MASK; 4409be88e75SGabriel Fernandez } 4419be88e75SGabriel Fernandez 4429be88e75SGabriel Fernandez mux_id &= MUX_PARENT_MASK; 4439be88e75SGabriel Fernandez parent = &priv->parents[mux_id]; 4449be88e75SGabriel Fernandez 4459be88e75SGabriel Fernandez if (idx < parent->num_parents) { 4469be88e75SGabriel Fernandez return parent->id_parents[idx]; 4479be88e75SGabriel Fernandez } 4489be88e75SGabriel Fernandez 4499be88e75SGabriel Fernandez return -EINVAL; 4509be88e75SGabriel Fernandez } 4519be88e75SGabriel Fernandez 4529be88e75SGabriel Fernandez int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id) 4539be88e75SGabriel Fernandez { 4549be88e75SGabriel Fernandez unsigned int i; 4559be88e75SGabriel Fernandez 4569be88e75SGabriel Fernandez for (i = 0U; i < priv->num; i++) { 4579be88e75SGabriel Fernandez if (binding_id == priv->clks[i].binding) { 4589be88e75SGabriel Fernandez return (int)i; 4599be88e75SGabriel Fernandez } 4609be88e75SGabriel Fernandez } 4619be88e75SGabriel Fernandez 4629be88e75SGabriel Fernandez return -EINVAL; 4639be88e75SGabriel Fernandez } 4649be88e75SGabriel Fernandez 4659be88e75SGabriel Fernandez unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id) 4669be88e75SGabriel Fernandez { 4679be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 4689be88e75SGabriel Fernandez int parent; 4699be88e75SGabriel Fernandez 4709be88e75SGabriel Fernandez if ((unsigned int)id >= priv->num) { 47169a2e320SYann Gautier return 0UL; 4729be88e75SGabriel Fernandez } 4739be88e75SGabriel Fernandez 4749be88e75SGabriel Fernandez parent = _clk_stm32_get_parent(priv, id); 475b8eab512SYann Gautier if (parent < 0) { 476b8eab512SYann Gautier return 0UL; 477b8eab512SYann Gautier } 4789be88e75SGabriel Fernandez 4799be88e75SGabriel Fernandez if (clk->ops->recalc_rate != NULL) { 4809be88e75SGabriel Fernandez unsigned long prate = 0UL; 4819be88e75SGabriel Fernandez 4829be88e75SGabriel Fernandez if (parent != CLK_IS_ROOT) { 4839be88e75SGabriel Fernandez prate = _clk_stm32_get_rate(priv, parent); 4849be88e75SGabriel Fernandez } 4859be88e75SGabriel Fernandez 48669a2e320SYann Gautier return clk->ops->recalc_rate(priv, id, prate); 4879be88e75SGabriel Fernandez } 4889be88e75SGabriel Fernandez 48969a2e320SYann Gautier if (parent == CLK_IS_ROOT) { 4909be88e75SGabriel Fernandez panic(); 4919be88e75SGabriel Fernandez } 4929be88e75SGabriel Fernandez 49369a2e320SYann Gautier return _clk_stm32_get_rate(priv, parent); 4949be88e75SGabriel Fernandez } 4959be88e75SGabriel Fernandez 4969be88e75SGabriel Fernandez unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id) 4979be88e75SGabriel Fernandez { 4989be88e75SGabriel Fernandez int parent_id = _clk_stm32_get_parent(priv, id); 4999be88e75SGabriel Fernandez 500b8eab512SYann Gautier if (parent_id < 0) { 501b8eab512SYann Gautier return 0UL; 502b8eab512SYann Gautier } 503b8eab512SYann Gautier 5049be88e75SGabriel Fernandez return _clk_stm32_get_rate(priv, parent_id); 5059be88e75SGabriel Fernandez } 5069be88e75SGabriel Fernandez 5079be88e75SGabriel Fernandez static uint8_t _stm32_clk_get_flags(struct stm32_clk_priv *priv, int id) 5089be88e75SGabriel Fernandez { 5099be88e75SGabriel Fernandez return priv->clks[id].flags; 5109be88e75SGabriel Fernandez } 5119be88e75SGabriel Fernandez 5129be88e75SGabriel Fernandez bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag) 5139be88e75SGabriel Fernandez { 514c3ae7da0SYann Gautier if ((_stm32_clk_get_flags(priv, id) & flag) != 0U) { 5159be88e75SGabriel Fernandez return true; 5169be88e75SGabriel Fernandez } 5179be88e75SGabriel Fernandez 5189be88e75SGabriel Fernandez return false; 5199be88e75SGabriel Fernandez } 5209be88e75SGabriel Fernandez 5219be88e75SGabriel Fernandez int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id) 5229be88e75SGabriel Fernandez { 5239be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 5249be88e75SGabriel Fernandez 5259be88e75SGabriel Fernandez if (clk->ops->enable != NULL) { 5269be88e75SGabriel Fernandez clk->ops->enable(priv, id); 5279be88e75SGabriel Fernandez } 5289be88e75SGabriel Fernandez 5299be88e75SGabriel Fernandez return 0; 5309be88e75SGabriel Fernandez } 5319be88e75SGabriel Fernandez 5329be88e75SGabriel Fernandez static int _clk_stm32_enable_core(struct stm32_clk_priv *priv, int id) 5339be88e75SGabriel Fernandez { 5349be88e75SGabriel Fernandez int parent; 5359be88e75SGabriel Fernandez int ret = 0; 5369be88e75SGabriel Fernandez 5379be88e75SGabriel Fernandez if (priv->gate_refcounts[id] == 0U) { 5389be88e75SGabriel Fernandez parent = _clk_stm32_get_parent(priv, id); 539b8eab512SYann Gautier if (parent < 0) { 540b8eab512SYann Gautier return parent; 541b8eab512SYann Gautier } 5429be88e75SGabriel Fernandez if (parent != CLK_IS_ROOT) { 5439be88e75SGabriel Fernandez ret = _clk_stm32_enable_core(priv, parent); 544c3ae7da0SYann Gautier if (ret != 0) { 5459be88e75SGabriel Fernandez return ret; 5469be88e75SGabriel Fernandez } 5479be88e75SGabriel Fernandez } 5489be88e75SGabriel Fernandez clk_stm32_enable_call_ops(priv, id); 5499be88e75SGabriel Fernandez } 5509be88e75SGabriel Fernandez 5519be88e75SGabriel Fernandez priv->gate_refcounts[id]++; 5529be88e75SGabriel Fernandez 5539be88e75SGabriel Fernandez if (priv->gate_refcounts[id] == UINT_MAX) { 5549be88e75SGabriel Fernandez ERROR("%s: %d max enable count !", __func__, id); 5559be88e75SGabriel Fernandez panic(); 5569be88e75SGabriel Fernandez } 5579be88e75SGabriel Fernandez 5589be88e75SGabriel Fernandez return 0; 5599be88e75SGabriel Fernandez } 5609be88e75SGabriel Fernandez 5619be88e75SGabriel Fernandez int _clk_stm32_enable(struct stm32_clk_priv *priv, int id) 5629be88e75SGabriel Fernandez { 5639be88e75SGabriel Fernandez int ret; 5649be88e75SGabriel Fernandez 5659be88e75SGabriel Fernandez stm32mp1_clk_lock(&refcount_lock); 5669be88e75SGabriel Fernandez ret = _clk_stm32_enable_core(priv, id); 5679be88e75SGabriel Fernandez stm32mp1_clk_unlock(&refcount_lock); 5689be88e75SGabriel Fernandez 5699be88e75SGabriel Fernandez return ret; 5709be88e75SGabriel Fernandez } 5719be88e75SGabriel Fernandez 5729be88e75SGabriel Fernandez void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id) 5739be88e75SGabriel Fernandez { 5749be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 5759be88e75SGabriel Fernandez 5769be88e75SGabriel Fernandez if (clk->ops->disable != NULL) { 5779be88e75SGabriel Fernandez clk->ops->disable(priv, id); 5789be88e75SGabriel Fernandez } 5799be88e75SGabriel Fernandez } 5809be88e75SGabriel Fernandez 5819be88e75SGabriel Fernandez static void _clk_stm32_disable_core(struct stm32_clk_priv *priv, int id) 5829be88e75SGabriel Fernandez { 5839be88e75SGabriel Fernandez int parent; 5849be88e75SGabriel Fernandez 5859be88e75SGabriel Fernandez if ((priv->gate_refcounts[id] == 1U) && _stm32_clk_is_flags(priv, id, CLK_IS_CRITICAL)) { 5869be88e75SGabriel Fernandez return; 5879be88e75SGabriel Fernandez } 5889be88e75SGabriel Fernandez 5899be88e75SGabriel Fernandez if (priv->gate_refcounts[id] == 0U) { 5909be88e75SGabriel Fernandez /* case of clock ignore unused */ 5919be88e75SGabriel Fernandez if (_clk_stm32_is_enabled(priv, id)) { 5929be88e75SGabriel Fernandez clk_stm32_disable_call_ops(priv, id); 5939be88e75SGabriel Fernandez return; 5949be88e75SGabriel Fernandez } 5959be88e75SGabriel Fernandez VERBOSE("%s: %d already disabled !\n\n", __func__, id); 5969be88e75SGabriel Fernandez return; 5979be88e75SGabriel Fernandez } 5989be88e75SGabriel Fernandez 5999be88e75SGabriel Fernandez if (--priv->gate_refcounts[id] > 0U) { 6009be88e75SGabriel Fernandez return; 6019be88e75SGabriel Fernandez } 6029be88e75SGabriel Fernandez 6039be88e75SGabriel Fernandez clk_stm32_disable_call_ops(priv, id); 6049be88e75SGabriel Fernandez 6059be88e75SGabriel Fernandez parent = _clk_stm32_get_parent(priv, id); 606b8eab512SYann Gautier if ((parent >= 0) && (parent != CLK_IS_ROOT)) { 6079be88e75SGabriel Fernandez _clk_stm32_disable_core(priv, parent); 6089be88e75SGabriel Fernandez } 6099be88e75SGabriel Fernandez } 6109be88e75SGabriel Fernandez 6119be88e75SGabriel Fernandez void _clk_stm32_disable(struct stm32_clk_priv *priv, int id) 6129be88e75SGabriel Fernandez { 6139be88e75SGabriel Fernandez stm32mp1_clk_lock(&refcount_lock); 6149be88e75SGabriel Fernandez 6159be88e75SGabriel Fernandez _clk_stm32_disable_core(priv, id); 6169be88e75SGabriel Fernandez 6179be88e75SGabriel Fernandez stm32mp1_clk_unlock(&refcount_lock); 6189be88e75SGabriel Fernandez } 6199be88e75SGabriel Fernandez 6209be88e75SGabriel Fernandez bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id) 6219be88e75SGabriel Fernandez { 6229be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 6239be88e75SGabriel Fernandez 6249be88e75SGabriel Fernandez if (clk->ops->is_enabled != NULL) { 6259be88e75SGabriel Fernandez return clk->ops->is_enabled(priv, id); 6269be88e75SGabriel Fernandez } 6279be88e75SGabriel Fernandez 6289be88e75SGabriel Fernandez return priv->gate_refcounts[id]; 6299be88e75SGabriel Fernandez } 6309be88e75SGabriel Fernandez 6319be88e75SGabriel Fernandez static int clk_stm32_enable(unsigned long binding_id) 6329be88e75SGabriel Fernandez { 6339be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6349be88e75SGabriel Fernandez int id; 6359be88e75SGabriel Fernandez 6369be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6379be88e75SGabriel Fernandez if (id == -EINVAL) { 6389be88e75SGabriel Fernandez return id; 6399be88e75SGabriel Fernandez } 6409be88e75SGabriel Fernandez 6419be88e75SGabriel Fernandez return _clk_stm32_enable(priv, id); 6429be88e75SGabriel Fernandez } 6439be88e75SGabriel Fernandez 6449be88e75SGabriel Fernandez static void clk_stm32_disable(unsigned long binding_id) 6459be88e75SGabriel Fernandez { 6469be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6479be88e75SGabriel Fernandez int id; 6489be88e75SGabriel Fernandez 6499be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6509be88e75SGabriel Fernandez if (id != -EINVAL) { 6519be88e75SGabriel Fernandez _clk_stm32_disable(priv, id); 6529be88e75SGabriel Fernandez } 6539be88e75SGabriel Fernandez } 6549be88e75SGabriel Fernandez 6559be88e75SGabriel Fernandez static bool clk_stm32_is_enabled(unsigned long binding_id) 6569be88e75SGabriel Fernandez { 6579be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6589be88e75SGabriel Fernandez int id; 6599be88e75SGabriel Fernandez 6609be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6619be88e75SGabriel Fernandez if (id == -EINVAL) { 6629be88e75SGabriel Fernandez return false; 6639be88e75SGabriel Fernandez } 6649be88e75SGabriel Fernandez 6659be88e75SGabriel Fernandez return _clk_stm32_is_enabled(priv, id); 6669be88e75SGabriel Fernandez } 6679be88e75SGabriel Fernandez 6689be88e75SGabriel Fernandez static unsigned long clk_stm32_get_rate(unsigned long binding_id) 6699be88e75SGabriel Fernandez { 6709be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 6719be88e75SGabriel Fernandez int id; 6729be88e75SGabriel Fernandez 6739be88e75SGabriel Fernandez id = clk_get_index(priv, binding_id); 6749be88e75SGabriel Fernandez if (id == -EINVAL) { 6759be88e75SGabriel Fernandez return 0UL; 6769be88e75SGabriel Fernandez } 6779be88e75SGabriel Fernandez 6789be88e75SGabriel Fernandez return _clk_stm32_get_rate(priv, id); 6799be88e75SGabriel Fernandez } 6809be88e75SGabriel Fernandez 6819be88e75SGabriel Fernandez static int clk_stm32_get_parent(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 id; 6899be88e75SGabriel Fernandez } 6909be88e75SGabriel Fernandez 6919be88e75SGabriel Fernandez return _clk_stm32_get_parent(priv, id); 6929be88e75SGabriel Fernandez } 6939be88e75SGabriel Fernandez 6949be88e75SGabriel Fernandez static const struct clk_ops stm32mp_clk_ops = { 6959be88e75SGabriel Fernandez .enable = clk_stm32_enable, 6969be88e75SGabriel Fernandez .disable = clk_stm32_disable, 6979be88e75SGabriel Fernandez .is_enabled = clk_stm32_is_enabled, 6989be88e75SGabriel Fernandez .get_rate = clk_stm32_get_rate, 6999be88e75SGabriel Fernandez .get_parent = clk_stm32_get_parent, 7009be88e75SGabriel Fernandez }; 7019be88e75SGabriel Fernandez 7029be88e75SGabriel Fernandez void clk_stm32_enable_critical_clocks(void) 7039be88e75SGabriel Fernandez { 7049be88e75SGabriel Fernandez struct stm32_clk_priv *priv = clk_stm32_get_priv(); 7059be88e75SGabriel Fernandez unsigned int i; 7069be88e75SGabriel Fernandez 7079be88e75SGabriel Fernandez for (i = 0U; i < priv->num; i++) { 7089be88e75SGabriel Fernandez if (_stm32_clk_is_flags(priv, i, CLK_IS_CRITICAL)) { 7099be88e75SGabriel Fernandez _clk_stm32_enable(priv, i); 7109be88e75SGabriel Fernandez } 7119be88e75SGabriel Fernandez } 7129be88e75SGabriel Fernandez } 7139be88e75SGabriel Fernandez 7149be88e75SGabriel Fernandez static void stm32_clk_register(void) 7159be88e75SGabriel Fernandez { 7169be88e75SGabriel Fernandez clk_register(&stm32mp_clk_ops); 7179be88e75SGabriel Fernandez } 7189be88e75SGabriel Fernandez 7199be88e75SGabriel Fernandez uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id) 7209be88e75SGabriel Fernandez { 7219be88e75SGabriel Fernandez const struct div_cfg *divider = &priv->div[div_id]; 7229be88e75SGabriel Fernandez uint32_t val = 0; 7239be88e75SGabriel Fernandez 7249be88e75SGabriel Fernandez val = mmio_read_32(priv->base + divider->offset) >> divider->shift; 7259be88e75SGabriel Fernandez val &= clk_div_mask(divider->width); 7269be88e75SGabriel Fernandez 7279be88e75SGabriel Fernandez return val; 7289be88e75SGabriel Fernandez } 7299be88e75SGabriel Fernandez 7309be88e75SGabriel Fernandez unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv, 7319be88e75SGabriel Fernandez int div_id, 7329be88e75SGabriel Fernandez unsigned long prate) 7339be88e75SGabriel Fernandez { 7349be88e75SGabriel Fernandez const struct div_cfg *divider = &priv->div[div_id]; 7359be88e75SGabriel Fernandez uint32_t val = clk_stm32_div_get_value(priv, div_id); 7369be88e75SGabriel Fernandez unsigned int div = 0U; 7379be88e75SGabriel Fernandez 7389be88e75SGabriel Fernandez div = _get_div(divider->table, val, divider->flags, divider->width); 7399be88e75SGabriel Fernandez if (div == 0U) { 7409be88e75SGabriel Fernandez return prate; 7419be88e75SGabriel Fernandez } 7429be88e75SGabriel Fernandez 7439be88e75SGabriel Fernandez return div_round_up((uint64_t)prate, div); 7449be88e75SGabriel Fernandez } 7459be88e75SGabriel Fernandez 7469be88e75SGabriel Fernandez unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int id, 7479be88e75SGabriel Fernandez unsigned long prate) 7489be88e75SGabriel Fernandez { 7499be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 7509be88e75SGabriel Fernandez struct clk_stm32_div_cfg *div_cfg = clk->clock_cfg; 7519be88e75SGabriel Fernandez 7529be88e75SGabriel Fernandez return _clk_stm32_divider_recalc(priv, div_cfg->id, prate); 7539be88e75SGabriel Fernandez } 7549be88e75SGabriel Fernandez 7559be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_divider_ops = { 7569be88e75SGabriel Fernandez .recalc_rate = clk_stm32_divider_recalc, 7579be88e75SGabriel Fernandez }; 7589be88e75SGabriel Fernandez 7599be88e75SGabriel Fernandez int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value) 7609be88e75SGabriel Fernandez { 7619be88e75SGabriel Fernandez const struct div_cfg *divider; 7629be88e75SGabriel Fernandez uintptr_t address; 7639be88e75SGabriel Fernandez uint64_t timeout; 7649be88e75SGabriel Fernandez uint32_t mask; 7659be88e75SGabriel Fernandez 7669be88e75SGabriel Fernandez if (div_id >= priv->nb_div) { 7679be88e75SGabriel Fernandez panic(); 7689be88e75SGabriel Fernandez } 7699be88e75SGabriel Fernandez 7709be88e75SGabriel Fernandez divider = &priv->div[div_id]; 7719be88e75SGabriel Fernandez address = priv->base + divider->offset; 7729be88e75SGabriel Fernandez 7739be88e75SGabriel Fernandez mask = MASK_WIDTH_SHIFT(divider->width, divider->shift); 7749be88e75SGabriel Fernandez mmio_clrsetbits_32(address, mask, (value << divider->shift) & mask); 7759be88e75SGabriel Fernandez 7769be88e75SGabriel Fernandez if (divider->bitrdy == DIV_NO_BIT_RDY) { 7779be88e75SGabriel Fernandez return 0; 7789be88e75SGabriel Fernandez } 7799be88e75SGabriel Fernandez 7809be88e75SGabriel Fernandez timeout = timeout_init_us(CLKSRC_TIMEOUT); 7819be88e75SGabriel Fernandez mask = BIT(divider->bitrdy); 7829be88e75SGabriel Fernandez 7839be88e75SGabriel Fernandez while ((mmio_read_32(address) & mask) == 0U) { 7849be88e75SGabriel Fernandez if (timeout_elapsed(timeout)) { 7859be88e75SGabriel Fernandez return -ETIMEDOUT; 7869be88e75SGabriel Fernandez } 7879be88e75SGabriel Fernandez } 7889be88e75SGabriel Fernandez 7899be88e75SGabriel Fernandez return 0; 7909be88e75SGabriel Fernandez } 7919be88e75SGabriel Fernandez 7929be88e75SGabriel Fernandez int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id, 7939be88e75SGabriel Fernandez bool ready_on) 7949be88e75SGabriel Fernandez { 7959be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[gate_id]; 7969be88e75SGabriel Fernandez uintptr_t address = priv->base + gate->offset; 7979be88e75SGabriel Fernandez uint32_t mask_rdy = BIT(gate->bit_idx); 7989be88e75SGabriel Fernandez uint64_t timeout; 7999be88e75SGabriel Fernandez uint32_t mask_test; 8009be88e75SGabriel Fernandez 8019be88e75SGabriel Fernandez if (ready_on) { 8029be88e75SGabriel Fernandez mask_test = BIT(gate->bit_idx); 8039be88e75SGabriel Fernandez } else { 8049be88e75SGabriel Fernandez mask_test = 0U; 8059be88e75SGabriel Fernandez } 8069be88e75SGabriel Fernandez 8079be88e75SGabriel Fernandez timeout = timeout_init_us(OSCRDY_TIMEOUT); 8089be88e75SGabriel Fernandez 8099be88e75SGabriel Fernandez while ((mmio_read_32(address) & mask_rdy) != mask_test) { 8109be88e75SGabriel Fernandez if (timeout_elapsed(timeout)) { 8119be88e75SGabriel Fernandez break; 8129be88e75SGabriel Fernandez } 8139be88e75SGabriel Fernandez } 8149be88e75SGabriel Fernandez 81556f895edSYann Gautier if ((mmio_read_32(address) & mask_rdy) != mask_test) { 8169be88e75SGabriel Fernandez return -ETIMEDOUT; 81756f895edSYann Gautier } 8189be88e75SGabriel Fernandez 8199be88e75SGabriel Fernandez return 0; 8209be88e75SGabriel Fernandez } 8219be88e75SGabriel Fernandez 8229be88e75SGabriel Fernandez int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int id) 8239be88e75SGabriel Fernandez { 8249be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8259be88e75SGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->clock_cfg; 8269be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[cfg->id]; 8279be88e75SGabriel Fernandez uintptr_t addr = priv->base + gate->offset; 8289be88e75SGabriel Fernandez 8299be88e75SGabriel Fernandez if (gate->set_clr != 0U) { 8309be88e75SGabriel Fernandez mmio_write_32(addr, BIT(gate->bit_idx)); 8319be88e75SGabriel Fernandez 8329be88e75SGabriel Fernandez } else { 8339be88e75SGabriel Fernandez mmio_setbits_32(addr, BIT(gate->bit_idx)); 8349be88e75SGabriel Fernandez } 8359be88e75SGabriel Fernandez 8369be88e75SGabriel Fernandez return 0; 8379be88e75SGabriel Fernandez } 8389be88e75SGabriel Fernandez 8399be88e75SGabriel Fernandez void clk_stm32_gate_disable(struct stm32_clk_priv *priv, int id) 8409be88e75SGabriel Fernandez { 8419be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8429be88e75SGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->clock_cfg; 8439be88e75SGabriel Fernandez const struct gate_cfg *gate = &priv->gates[cfg->id]; 8449be88e75SGabriel Fernandez uintptr_t addr = priv->base + gate->offset; 8459be88e75SGabriel Fernandez 8469be88e75SGabriel Fernandez if (gate->set_clr != 0U) { 8479be88e75SGabriel Fernandez mmio_write_32(addr + RCC_MP_ENCLRR_OFFSET, BIT(gate->bit_idx)); 8489be88e75SGabriel Fernandez } else { 8499be88e75SGabriel Fernandez mmio_clrbits_32(addr, BIT(gate->bit_idx)); 8509be88e75SGabriel Fernandez } 8519be88e75SGabriel Fernandez } 8529be88e75SGabriel Fernandez 8539be88e75SGabriel Fernandez bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id) 8549be88e75SGabriel Fernandez { 8559be88e75SGabriel Fernandez const struct gate_cfg *gate; 8569be88e75SGabriel Fernandez uint32_t addr; 8579be88e75SGabriel Fernandez 8589be88e75SGabriel Fernandez gate = &priv->gates[gate_id]; 8599be88e75SGabriel Fernandez addr = priv->base + gate->offset; 8609be88e75SGabriel Fernandez 8619be88e75SGabriel Fernandez return ((mmio_read_32(addr) & BIT(gate->bit_idx)) != 0U); 8629be88e75SGabriel Fernandez } 8639be88e75SGabriel Fernandez 8649be88e75SGabriel Fernandez bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int id) 8659be88e75SGabriel Fernandez { 8669be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8679be88e75SGabriel Fernandez struct clk_stm32_gate_cfg *cfg = clk->clock_cfg; 8689be88e75SGabriel Fernandez 8699be88e75SGabriel Fernandez return _clk_stm32_gate_is_enabled(priv, cfg->id); 8709be88e75SGabriel Fernandez } 8719be88e75SGabriel Fernandez 8729be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_gate_ops = { 8739be88e75SGabriel Fernandez .enable = clk_stm32_gate_enable, 8749be88e75SGabriel Fernandez .disable = clk_stm32_gate_disable, 8759be88e75SGabriel Fernandez .is_enabled = clk_stm32_gate_is_enabled, 8769be88e75SGabriel Fernandez }; 8779be88e75SGabriel Fernandez 8789be88e75SGabriel Fernandez const struct stm32_clk_ops clk_fixed_factor_ops = { 8799be88e75SGabriel Fernandez .recalc_rate = fixed_factor_recalc_rate, 8809be88e75SGabriel Fernandez }; 8819be88e75SGabriel Fernandez 8829be88e75SGabriel Fernandez unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv, 8839be88e75SGabriel Fernandez int id, unsigned long prate) 8849be88e75SGabriel Fernandez { 8859be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 8869be88e75SGabriel Fernandez const struct fixed_factor_cfg *cfg = clk->clock_cfg; 8879be88e75SGabriel Fernandez unsigned long long rate; 8889be88e75SGabriel Fernandez 8899be88e75SGabriel Fernandez rate = (unsigned long long)prate * cfg->mult; 8909be88e75SGabriel Fernandez 8919be88e75SGabriel Fernandez if (cfg->div == 0U) { 8929be88e75SGabriel Fernandez ERROR("division by zero\n"); 8939be88e75SGabriel Fernandez panic(); 8949be88e75SGabriel Fernandez } 8959be88e75SGabriel Fernandez 8969be88e75SGabriel Fernandez return (unsigned long)(rate / cfg->div); 8979be88e75SGabriel Fernandez }; 8989be88e75SGabriel Fernandez 8999be88e75SGabriel Fernandez #define APB_DIV_MASK GENMASK(2, 0) 9009be88e75SGabriel Fernandez #define TIM_PRE_MASK BIT(0) 9019be88e75SGabriel Fernandez 9029be88e75SGabriel Fernandez static unsigned long timer_recalc_rate(struct stm32_clk_priv *priv, 9039be88e75SGabriel Fernandez int id, unsigned long prate) 9049be88e75SGabriel Fernandez { 9059be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 9069be88e75SGabriel Fernandez const struct clk_timer_cfg *cfg = clk->clock_cfg; 9079be88e75SGabriel Fernandez uint32_t prescaler, timpre; 9089be88e75SGabriel Fernandez uintptr_t rcc_base = priv->base; 9099be88e75SGabriel Fernandez 9109be88e75SGabriel Fernandez prescaler = mmio_read_32(rcc_base + cfg->apbdiv) & 9119be88e75SGabriel Fernandez APB_DIV_MASK; 9129be88e75SGabriel Fernandez 9139be88e75SGabriel Fernandez timpre = mmio_read_32(rcc_base + cfg->timpre) & 9149be88e75SGabriel Fernandez TIM_PRE_MASK; 9159be88e75SGabriel Fernandez 9169be88e75SGabriel Fernandez if (prescaler == 0U) { 9179be88e75SGabriel Fernandez return prate; 9189be88e75SGabriel Fernandez } 9199be88e75SGabriel Fernandez 9209be88e75SGabriel Fernandez return prate * (timpre + 1U) * 2U; 9219be88e75SGabriel Fernandez }; 9229be88e75SGabriel Fernandez 9239be88e75SGabriel Fernandez const struct stm32_clk_ops clk_timer_ops = { 9249be88e75SGabriel Fernandez .recalc_rate = timer_recalc_rate, 9259be88e75SGabriel Fernandez }; 9269be88e75SGabriel Fernandez 9279be88e75SGabriel Fernandez static unsigned long clk_fixed_rate_recalc(struct stm32_clk_priv *priv, int id, 9289be88e75SGabriel Fernandez unsigned long prate) 9299be88e75SGabriel Fernandez { 9309be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, id); 9319be88e75SGabriel Fernandez struct clk_stm32_fixed_rate_cfg *cfg = clk->clock_cfg; 9329be88e75SGabriel Fernandez 9339be88e75SGabriel Fernandez return cfg->rate; 9349be88e75SGabriel Fernandez } 9359be88e75SGabriel Fernandez 9369be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_fixed_rate_ops = { 9379be88e75SGabriel Fernandez .recalc_rate = clk_fixed_rate_recalc, 9389be88e75SGabriel Fernandez }; 9399be88e75SGabriel Fernandez 9409be88e75SGabriel Fernandez static unsigned long clk_stm32_osc_recalc_rate(struct stm32_clk_priv *priv, 9419be88e75SGabriel Fernandez int id, unsigned long prate) 9429be88e75SGabriel Fernandez { 9439be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9449be88e75SGabriel Fernandez 9459be88e75SGabriel Fernandez return osc_data->frequency; 9469be88e75SGabriel Fernandez }; 9479be88e75SGabriel Fernandez 9489be88e75SGabriel Fernandez bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id) 9499be88e75SGabriel Fernandez { 9509be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9519be88e75SGabriel Fernandez 9529be88e75SGabriel Fernandez return _clk_stm32_gate_is_enabled(priv, osc_data->gate_id); 9539be88e75SGabriel Fernandez 9549be88e75SGabriel Fernandez } 9559be88e75SGabriel Fernandez 9569be88e75SGabriel Fernandez int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id) 9579be88e75SGabriel Fernandez { 9589be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 9599be88e75SGabriel Fernandez 960*f2aebab8SGabriel Fernandez if (osc_data->frequency == 0UL) { 961*f2aebab8SGabriel Fernandez return 0; 962*f2aebab8SGabriel Fernandez } 963*f2aebab8SGabriel Fernandez 9649be88e75SGabriel Fernandez _clk_stm32_gate_enable(priv, osc_data->gate_id); 9659be88e75SGabriel Fernandez 9669be88e75SGabriel Fernandez if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, true) != 0U) { 9679be88e75SGabriel Fernandez ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__); 9689be88e75SGabriel Fernandez panic(); 9699be88e75SGabriel Fernandez } 9709be88e75SGabriel Fernandez 9719be88e75SGabriel Fernandez return 0; 9729be88e75SGabriel Fernandez } 9739be88e75SGabriel Fernandez 9749be88e75SGabriel Fernandez void clk_stm32_osc_gate_disable(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 978*f2aebab8SGabriel Fernandez if (osc_data->frequency == 0UL) { 979*f2aebab8SGabriel Fernandez return; 980*f2aebab8SGabriel Fernandez } 981*f2aebab8SGabriel Fernandez 9829be88e75SGabriel Fernandez _clk_stm32_gate_disable(priv, osc_data->gate_id); 9839be88e75SGabriel Fernandez 9849be88e75SGabriel Fernandez if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, false) != 0U) { 9859be88e75SGabriel Fernandez ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__); 9869be88e75SGabriel Fernandez panic(); 9879be88e75SGabriel Fernandez } 9889be88e75SGabriel Fernandez } 9899be88e75SGabriel Fernandez 9909be88e75SGabriel Fernandez static unsigned long clk_stm32_get_dt_oscillator_frequency(const char *name) 9919be88e75SGabriel Fernandez { 9929be88e75SGabriel Fernandez void *fdt = NULL; 9939be88e75SGabriel Fernandez int node = 0; 9949be88e75SGabriel Fernandez int subnode = 0; 9959be88e75SGabriel Fernandez 9969be88e75SGabriel Fernandez if (fdt_get_address(&fdt) == 0) { 9979be88e75SGabriel Fernandez panic(); 9989be88e75SGabriel Fernandez } 9999be88e75SGabriel Fernandez 10009be88e75SGabriel Fernandez node = fdt_path_offset(fdt, "/clocks"); 10019be88e75SGabriel Fernandez if (node < 0) { 10029be88e75SGabriel Fernandez return 0UL; 10039be88e75SGabriel Fernandez } 10049be88e75SGabriel Fernandez 10059be88e75SGabriel Fernandez fdt_for_each_subnode(subnode, fdt, node) { 10069be88e75SGabriel Fernandez const char *cchar = NULL; 10079be88e75SGabriel Fernandez const fdt32_t *cuint = NULL; 10089be88e75SGabriel Fernandez int ret = 0; 10099be88e75SGabriel Fernandez 10109be88e75SGabriel Fernandez cchar = fdt_get_name(fdt, subnode, &ret); 10119be88e75SGabriel Fernandez if (cchar == NULL) { 10129be88e75SGabriel Fernandez continue; 10139be88e75SGabriel Fernandez } 10149be88e75SGabriel Fernandez 10159be88e75SGabriel Fernandez if (strncmp(cchar, name, (size_t)ret) || 10169be88e75SGabriel Fernandez fdt_get_status(subnode) == DT_DISABLED) { 10179be88e75SGabriel Fernandez continue; 10189be88e75SGabriel Fernandez } 10199be88e75SGabriel Fernandez 10209be88e75SGabriel Fernandez cuint = fdt_getprop(fdt, subnode, "clock-frequency", &ret); 10219be88e75SGabriel Fernandez if (cuint == NULL) { 10229be88e75SGabriel Fernandez return 0UL; 10239be88e75SGabriel Fernandez } 10249be88e75SGabriel Fernandez 10259be88e75SGabriel Fernandez return fdt32_to_cpu(*cuint); 10269be88e75SGabriel Fernandez } 10279be88e75SGabriel Fernandez 10289be88e75SGabriel Fernandez return 0UL; 10299be88e75SGabriel Fernandez } 10309be88e75SGabriel Fernandez 10319be88e75SGabriel Fernandez void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id) 10329be88e75SGabriel Fernandez { 10339be88e75SGabriel Fernandez struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id); 10349be88e75SGabriel Fernandez const char *name = osc_data->name; 10359be88e75SGabriel Fernandez 10369be88e75SGabriel Fernandez osc_data->frequency = clk_stm32_get_dt_oscillator_frequency(name); 10379be88e75SGabriel Fernandez } 10389be88e75SGabriel Fernandez 10399be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_osc_ops = { 10409be88e75SGabriel Fernandez .recalc_rate = clk_stm32_osc_recalc_rate, 10419be88e75SGabriel Fernandez .is_enabled = clk_stm32_osc_gate_is_enabled, 10429be88e75SGabriel Fernandez .enable = clk_stm32_osc_gate_enable, 10439be88e75SGabriel Fernandez .disable = clk_stm32_osc_gate_disable, 10449be88e75SGabriel Fernandez .init = clk_stm32_osc_init, 10459be88e75SGabriel Fernandez }; 10469be88e75SGabriel Fernandez 10479be88e75SGabriel Fernandez const struct stm32_clk_ops clk_stm32_osc_nogate_ops = { 10489be88e75SGabriel Fernandez .recalc_rate = clk_stm32_osc_recalc_rate, 10499be88e75SGabriel Fernandez .init = clk_stm32_osc_init, 10509be88e75SGabriel Fernandez }; 10519be88e75SGabriel Fernandez 10529be88e75SGabriel Fernandez int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb) 10539be88e75SGabriel Fernandez { 10549be88e75SGabriel Fernandez const fdt32_t *cell; 10559be88e75SGabriel Fernandez int len = 0; 10569be88e75SGabriel Fernandez uint32_t i; 10579be88e75SGabriel Fernandez 10589be88e75SGabriel Fernandez cell = fdt_getprop(fdt, node, name, &len); 10597417cda6SYann Gautier if (cell == NULL) { 10607417cda6SYann Gautier *nb = 0U; 10617417cda6SYann Gautier return 0; 10627417cda6SYann Gautier } 10637417cda6SYann Gautier 10649be88e75SGabriel Fernandez for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { 10659be88e75SGabriel Fernandez uint32_t val = fdt32_to_cpu(cell[i]); 10669be88e75SGabriel Fernandez 10679be88e75SGabriel Fernandez tab[i] = val; 10689be88e75SGabriel Fernandez } 10699be88e75SGabriel Fernandez 10709be88e75SGabriel Fernandez *nb = (uint32_t)len / sizeof(uint32_t); 10719be88e75SGabriel Fernandez 10729be88e75SGabriel Fernandez return 0; 10739be88e75SGabriel Fernandez } 10749be88e75SGabriel Fernandez 10759be88e75SGabriel Fernandez int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base) 10769be88e75SGabriel Fernandez { 10779be88e75SGabriel Fernandez unsigned int i; 10789be88e75SGabriel Fernandez 10799be88e75SGabriel Fernandez stm32_clock_data = priv; 10809be88e75SGabriel Fernandez 10819be88e75SGabriel Fernandez priv->base = base; 10829be88e75SGabriel Fernandez 10839be88e75SGabriel Fernandez for (i = 0U; i < priv->num; i++) { 10849be88e75SGabriel Fernandez const struct clk_stm32 *clk = _clk_get(priv, i); 10859be88e75SGabriel Fernandez 10869be88e75SGabriel Fernandez assert(clk->ops != NULL); 10879be88e75SGabriel Fernandez 10889be88e75SGabriel Fernandez if (clk->ops->init != NULL) { 10899be88e75SGabriel Fernandez clk->ops->init(priv, i); 10909be88e75SGabriel Fernandez } 10919be88e75SGabriel Fernandez } 10929be88e75SGabriel Fernandez 10939be88e75SGabriel Fernandez stm32_clk_register(); 10949be88e75SGabriel Fernandez 10959be88e75SGabriel Fernandez return 0; 10969be88e75SGabriel Fernandez } 1097