13a580e9eSGhennadi Procopciuc /* 2bd691136SGhennadi Procopciuc * Copyright 2024-2025 NXP 33a580e9eSGhennadi Procopciuc * 43a580e9eSGhennadi Procopciuc * SPDX-License-Identifier: BSD-3-Clause 53a580e9eSGhennadi Procopciuc */ 63a580e9eSGhennadi Procopciuc #include <errno.h> 7d9373519SGhennadi Procopciuc #include <common/debug.h> 83a580e9eSGhennadi Procopciuc #include <drivers/clk.h> 98ab34357SGhennadi Procopciuc #include <lib/mmio.h> 10514c7380SGhennadi Procopciuc #include <lib/xlat_tables/xlat_tables_v2.h> 11b5101c45SGhennadi Procopciuc #include <s32cc-clk-ids.h> 12d9373519SGhennadi Procopciuc #include <s32cc-clk-modules.h> 138a4f840bSGhennadi Procopciuc #include <s32cc-clk-regs.h> 14d9373519SGhennadi Procopciuc #include <s32cc-clk-utils.h> 158a4f840bSGhennadi Procopciuc #include <s32cc-mc-me.h> 16d9373519SGhennadi Procopciuc 175300040bSGhennadi Procopciuc #define MAX_STACK_DEPTH (40U) 18d9373519SGhennadi Procopciuc 19b5101c45SGhennadi Procopciuc /* This is used for floating-point precision calculations. */ 20b5101c45SGhennadi Procopciuc #define FP_PRECISION (100000000UL) 21b5101c45SGhennadi Procopciuc 228ab34357SGhennadi Procopciuc struct s32cc_clk_drv { 238ab34357SGhennadi Procopciuc uintptr_t fxosc_base; 24b5101c45SGhennadi Procopciuc uintptr_t armpll_base; 258653352aSGhennadi Procopciuc uintptr_t periphpll_base; 264cd04c50SGhennadi Procopciuc uintptr_t armdfs_base; 279dbca85dSGhennadi Procopciuc uintptr_t cgm0_base; 287004f678SGhennadi Procopciuc uintptr_t cgm1_base; 298a4f840bSGhennadi Procopciuc uintptr_t cgm5_base; 3018c2b137SGhennadi Procopciuc uintptr_t ddrpll_base; 318a4f840bSGhennadi Procopciuc uintptr_t mc_me; 328a4f840bSGhennadi Procopciuc uintptr_t mc_rgm; 338a4f840bSGhennadi Procopciuc uintptr_t rdc; 348ab34357SGhennadi Procopciuc }; 358ab34357SGhennadi Procopciuc 362fb25509SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 372fb25509SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 382fb25509SGhennadi Procopciuc unsigned int *depth); 392fb25509SGhennadi Procopciuc static int get_module_rate(const struct s32cc_clk_obj *module, 402fb25509SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 412fb25509SGhennadi Procopciuc unsigned long *rate, 422fb25509SGhennadi Procopciuc unsigned int depth); 432fb25509SGhennadi Procopciuc 44d9373519SGhennadi Procopciuc static int update_stack_depth(unsigned int *depth) 45d9373519SGhennadi Procopciuc { 46d9373519SGhennadi Procopciuc if (*depth == 0U) { 47d9373519SGhennadi Procopciuc return -ENOMEM; 48d9373519SGhennadi Procopciuc } 49d9373519SGhennadi Procopciuc 50d9373519SGhennadi Procopciuc (*depth)--; 51d9373519SGhennadi Procopciuc return 0; 52d9373519SGhennadi Procopciuc } 533a580e9eSGhennadi Procopciuc 548ab34357SGhennadi Procopciuc static struct s32cc_clk_drv *get_drv(void) 558ab34357SGhennadi Procopciuc { 568ab34357SGhennadi Procopciuc static struct s32cc_clk_drv driver = { 578ab34357SGhennadi Procopciuc .fxosc_base = FXOSC_BASE_ADDR, 58b5101c45SGhennadi Procopciuc .armpll_base = ARMPLL_BASE_ADDR, 598653352aSGhennadi Procopciuc .periphpll_base = PERIPHPLL_BASE_ADDR, 604cd04c50SGhennadi Procopciuc .armdfs_base = ARM_DFS_BASE_ADDR, 619dbca85dSGhennadi Procopciuc .cgm0_base = CGM0_BASE_ADDR, 627004f678SGhennadi Procopciuc .cgm1_base = CGM1_BASE_ADDR, 638a4f840bSGhennadi Procopciuc .cgm5_base = MC_CGM5_BASE_ADDR, 6418c2b137SGhennadi Procopciuc .ddrpll_base = DDRPLL_BASE_ADDR, 658a4f840bSGhennadi Procopciuc .mc_me = MC_ME_BASE_ADDR, 668a4f840bSGhennadi Procopciuc .mc_rgm = MC_RGM_BASE_ADDR, 678a4f840bSGhennadi Procopciuc .rdc = RDC_BASE_ADDR, 688ab34357SGhennadi Procopciuc }; 698ab34357SGhennadi Procopciuc 708ab34357SGhennadi Procopciuc return &driver; 718ab34357SGhennadi Procopciuc } 728ab34357SGhennadi Procopciuc 735300040bSGhennadi Procopciuc static int enable_module(struct s32cc_clk_obj *module, 745300040bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 755300040bSGhennadi Procopciuc unsigned int depth); 768ab34357SGhennadi Procopciuc 7796e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_clk_parent(const struct s32cc_clk_obj *module) 7896e069cbSGhennadi Procopciuc { 7996e069cbSGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 8096e069cbSGhennadi Procopciuc 8196e069cbSGhennadi Procopciuc if (clk->module != NULL) { 8296e069cbSGhennadi Procopciuc return clk->module; 8396e069cbSGhennadi Procopciuc } 8496e069cbSGhennadi Procopciuc 8596e069cbSGhennadi Procopciuc if (clk->pclock != NULL) { 8696e069cbSGhennadi Procopciuc return &clk->pclock->desc; 8796e069cbSGhennadi Procopciuc } 8896e069cbSGhennadi Procopciuc 8996e069cbSGhennadi Procopciuc return NULL; 9096e069cbSGhennadi Procopciuc } 9196e069cbSGhennadi Procopciuc 92b5101c45SGhennadi Procopciuc static int get_base_addr(enum s32cc_clk_source id, const struct s32cc_clk_drv *drv, 93b5101c45SGhennadi Procopciuc uintptr_t *base) 94b5101c45SGhennadi Procopciuc { 95b5101c45SGhennadi Procopciuc int ret = 0; 96b5101c45SGhennadi Procopciuc 97b5101c45SGhennadi Procopciuc switch (id) { 98b5101c45SGhennadi Procopciuc case S32CC_FXOSC: 99b5101c45SGhennadi Procopciuc *base = drv->fxosc_base; 100b5101c45SGhennadi Procopciuc break; 101b5101c45SGhennadi Procopciuc case S32CC_ARM_PLL: 102b5101c45SGhennadi Procopciuc *base = drv->armpll_base; 103b5101c45SGhennadi Procopciuc break; 1048653352aSGhennadi Procopciuc case S32CC_PERIPH_PLL: 1058653352aSGhennadi Procopciuc *base = drv->periphpll_base; 1068653352aSGhennadi Procopciuc break; 10718c2b137SGhennadi Procopciuc case S32CC_DDR_PLL: 10818c2b137SGhennadi Procopciuc *base = drv->ddrpll_base; 10918c2b137SGhennadi Procopciuc break; 1104cd04c50SGhennadi Procopciuc case S32CC_ARM_DFS: 1114cd04c50SGhennadi Procopciuc *base = drv->armdfs_base; 1124cd04c50SGhennadi Procopciuc break; 1139dbca85dSGhennadi Procopciuc case S32CC_CGM0: 1149dbca85dSGhennadi Procopciuc *base = drv->cgm0_base; 1159dbca85dSGhennadi Procopciuc break; 116b5101c45SGhennadi Procopciuc case S32CC_CGM1: 1177004f678SGhennadi Procopciuc *base = drv->cgm1_base; 118b5101c45SGhennadi Procopciuc break; 1198a4f840bSGhennadi Procopciuc case S32CC_CGM5: 1208a4f840bSGhennadi Procopciuc *base = drv->cgm5_base; 1218a4f840bSGhennadi Procopciuc break; 122b5101c45SGhennadi Procopciuc case S32CC_FIRC: 123b5101c45SGhennadi Procopciuc break; 124b5101c45SGhennadi Procopciuc case S32CC_SIRC: 125b5101c45SGhennadi Procopciuc break; 126b5101c45SGhennadi Procopciuc default: 127b5101c45SGhennadi Procopciuc ret = -EINVAL; 128b5101c45SGhennadi Procopciuc break; 129b5101c45SGhennadi Procopciuc } 130b5101c45SGhennadi Procopciuc 131b5101c45SGhennadi Procopciuc if (ret != 0) { 132b5101c45SGhennadi Procopciuc ERROR("Unknown clock source id: %u\n", id); 133b5101c45SGhennadi Procopciuc } 134b5101c45SGhennadi Procopciuc 135b5101c45SGhennadi Procopciuc return ret; 136b5101c45SGhennadi Procopciuc } 137b5101c45SGhennadi Procopciuc 1388ab34357SGhennadi Procopciuc static void enable_fxosc(const struct s32cc_clk_drv *drv) 1398ab34357SGhennadi Procopciuc { 1408ab34357SGhennadi Procopciuc uintptr_t fxosc_base = drv->fxosc_base; 1418ab34357SGhennadi Procopciuc uint32_t ctrl; 1428ab34357SGhennadi Procopciuc 1438ab34357SGhennadi Procopciuc ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base)); 1448ab34357SGhennadi Procopciuc if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) { 1458ab34357SGhennadi Procopciuc return; 1468ab34357SGhennadi Procopciuc } 1478ab34357SGhennadi Procopciuc 1488ab34357SGhennadi Procopciuc ctrl = FXOSC_CTRL_COMP_EN; 1498ab34357SGhennadi Procopciuc ctrl &= ~FXOSC_CTRL_OSC_BYP; 1508ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_EOCV(0x1); 1518ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_GM_SEL(0x7); 1528ab34357SGhennadi Procopciuc mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl); 1538ab34357SGhennadi Procopciuc 1548ab34357SGhennadi Procopciuc /* Switch ON the crystal oscillator. */ 1558ab34357SGhennadi Procopciuc mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON); 1568ab34357SGhennadi Procopciuc 1578ab34357SGhennadi Procopciuc /* Wait until the clock is stable. */ 1588ab34357SGhennadi Procopciuc while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) { 1598ab34357SGhennadi Procopciuc } 1608ab34357SGhennadi Procopciuc } 1618ab34357SGhennadi Procopciuc 1625300040bSGhennadi Procopciuc static int enable_osc(struct s32cc_clk_obj *module, 1638ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 1645300040bSGhennadi Procopciuc unsigned int depth) 1658ab34357SGhennadi Procopciuc { 1668ab34357SGhennadi Procopciuc const struct s32cc_osc *osc = s32cc_obj2osc(module); 1678ee0fc31SGhennadi Procopciuc unsigned int ldepth = depth; 1688ab34357SGhennadi Procopciuc int ret = 0; 1698ab34357SGhennadi Procopciuc 1708ee0fc31SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 1718ab34357SGhennadi Procopciuc if (ret != 0) { 1728ab34357SGhennadi Procopciuc return ret; 1738ab34357SGhennadi Procopciuc } 1748ab34357SGhennadi Procopciuc 1758ab34357SGhennadi Procopciuc switch (osc->source) { 1768ab34357SGhennadi Procopciuc case S32CC_FXOSC: 1778ab34357SGhennadi Procopciuc enable_fxosc(drv); 1788ab34357SGhennadi Procopciuc break; 1798ab34357SGhennadi Procopciuc /* FIRC and SIRC oscillators are enabled by default */ 1808ab34357SGhennadi Procopciuc case S32CC_FIRC: 1818ab34357SGhennadi Procopciuc break; 1828ab34357SGhennadi Procopciuc case S32CC_SIRC: 1838ab34357SGhennadi Procopciuc break; 1848ab34357SGhennadi Procopciuc default: 1858ab34357SGhennadi Procopciuc ERROR("Invalid oscillator %d\n", osc->source); 1868ab34357SGhennadi Procopciuc ret = -EINVAL; 1878ab34357SGhennadi Procopciuc break; 1888ab34357SGhennadi Procopciuc }; 1898ab34357SGhennadi Procopciuc 1908ab34357SGhennadi Procopciuc return ret; 1918ab34357SGhennadi Procopciuc } 1928ab34357SGhennadi Procopciuc 19396e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_pll_parent(const struct s32cc_clk_obj *module) 19496e069cbSGhennadi Procopciuc { 19596e069cbSGhennadi Procopciuc const struct s32cc_pll *pll = s32cc_obj2pll(module); 19696e069cbSGhennadi Procopciuc 19796e069cbSGhennadi Procopciuc if (pll->source == NULL) { 19896e069cbSGhennadi Procopciuc ERROR("Failed to identify PLL's parent\n"); 19996e069cbSGhennadi Procopciuc } 20096e069cbSGhennadi Procopciuc 20196e069cbSGhennadi Procopciuc return pll->source; 20296e069cbSGhennadi Procopciuc } 20396e069cbSGhennadi Procopciuc 204b5101c45SGhennadi Procopciuc static int get_pll_mfi_mfn(unsigned long pll_vco, unsigned long ref_freq, 205b5101c45SGhennadi Procopciuc uint32_t *mfi, uint32_t *mfn) 206b5101c45SGhennadi Procopciuc 207b5101c45SGhennadi Procopciuc { 208b5101c45SGhennadi Procopciuc unsigned long vco; 209b5101c45SGhennadi Procopciuc unsigned long mfn64; 210b5101c45SGhennadi Procopciuc 211b5101c45SGhennadi Procopciuc /* FRAC-N mode */ 212b5101c45SGhennadi Procopciuc *mfi = (uint32_t)(pll_vco / ref_freq); 213b5101c45SGhennadi Procopciuc 214b5101c45SGhennadi Procopciuc /* MFN formula : (double)(pll_vco % ref_freq) / ref_freq * 18432.0 */ 215b5101c45SGhennadi Procopciuc mfn64 = pll_vco % ref_freq; 216b5101c45SGhennadi Procopciuc mfn64 *= FP_PRECISION; 217b5101c45SGhennadi Procopciuc mfn64 /= ref_freq; 218b5101c45SGhennadi Procopciuc mfn64 *= 18432UL; 219b5101c45SGhennadi Procopciuc mfn64 /= FP_PRECISION; 220b5101c45SGhennadi Procopciuc 221b5101c45SGhennadi Procopciuc if (mfn64 > UINT32_MAX) { 222b5101c45SGhennadi Procopciuc return -EINVAL; 223b5101c45SGhennadi Procopciuc } 224b5101c45SGhennadi Procopciuc 225b5101c45SGhennadi Procopciuc *mfn = (uint32_t)mfn64; 226b5101c45SGhennadi Procopciuc 227b5101c45SGhennadi Procopciuc vco = ((unsigned long)*mfn * FP_PRECISION) / 18432UL; 228b5101c45SGhennadi Procopciuc vco += (unsigned long)*mfi * FP_PRECISION; 229b5101c45SGhennadi Procopciuc vco *= ref_freq; 230b5101c45SGhennadi Procopciuc vco /= FP_PRECISION; 231b5101c45SGhennadi Procopciuc 232b5101c45SGhennadi Procopciuc if (vco != pll_vco) { 233b5101c45SGhennadi Procopciuc ERROR("Failed to find MFI and MFN settings for PLL freq %lu. Nearest freq = %lu\n", 234b5101c45SGhennadi Procopciuc pll_vco, vco); 235b5101c45SGhennadi Procopciuc return -EINVAL; 236b5101c45SGhennadi Procopciuc } 237b5101c45SGhennadi Procopciuc 238b5101c45SGhennadi Procopciuc return 0; 239b5101c45SGhennadi Procopciuc } 240b5101c45SGhennadi Procopciuc 241b5101c45SGhennadi Procopciuc static struct s32cc_clkmux *get_pll_mux(const struct s32cc_pll *pll) 242b5101c45SGhennadi Procopciuc { 243b5101c45SGhennadi Procopciuc const struct s32cc_clk_obj *source = pll->source; 244b5101c45SGhennadi Procopciuc const struct s32cc_clk *clk; 245b5101c45SGhennadi Procopciuc 246b5101c45SGhennadi Procopciuc if (source == NULL) { 247b5101c45SGhennadi Procopciuc ERROR("Failed to identify PLL's parent\n"); 248b5101c45SGhennadi Procopciuc return NULL; 249b5101c45SGhennadi Procopciuc } 250b5101c45SGhennadi Procopciuc 251b5101c45SGhennadi Procopciuc if (source->type != s32cc_clk_t) { 252b5101c45SGhennadi Procopciuc ERROR("The parent of the PLL isn't a clock\n"); 253b5101c45SGhennadi Procopciuc return NULL; 254b5101c45SGhennadi Procopciuc } 255b5101c45SGhennadi Procopciuc 256b5101c45SGhennadi Procopciuc clk = s32cc_obj2clk(source); 257b5101c45SGhennadi Procopciuc 258b5101c45SGhennadi Procopciuc if (clk->module == NULL) { 259b5101c45SGhennadi Procopciuc ERROR("The clock isn't connected to a module\n"); 260b5101c45SGhennadi Procopciuc return NULL; 261b5101c45SGhennadi Procopciuc } 262b5101c45SGhennadi Procopciuc 263b5101c45SGhennadi Procopciuc source = clk->module; 264b5101c45SGhennadi Procopciuc 265b5101c45SGhennadi Procopciuc if ((source->type != s32cc_clkmux_t) && 266b5101c45SGhennadi Procopciuc (source->type != s32cc_shared_clkmux_t)) { 267b5101c45SGhennadi Procopciuc ERROR("The parent of the PLL isn't a MUX\n"); 268b5101c45SGhennadi Procopciuc return NULL; 269b5101c45SGhennadi Procopciuc } 270b5101c45SGhennadi Procopciuc 271b5101c45SGhennadi Procopciuc return s32cc_obj2clkmux(source); 272b5101c45SGhennadi Procopciuc } 273b5101c45SGhennadi Procopciuc 274b5101c45SGhennadi Procopciuc static void disable_odiv(uintptr_t pll_addr, uint32_t div_index) 275b5101c45SGhennadi Procopciuc { 276b5101c45SGhennadi Procopciuc mmio_clrbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE); 277b5101c45SGhennadi Procopciuc } 278b5101c45SGhennadi Procopciuc 27984e82085SGhennadi Procopciuc static void enable_odiv(uintptr_t pll_addr, uint32_t div_index) 28084e82085SGhennadi Procopciuc { 28184e82085SGhennadi Procopciuc mmio_setbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE); 28284e82085SGhennadi Procopciuc } 28384e82085SGhennadi Procopciuc 284*c23dde6cSGhennadi Procopciuc static void enable_odivs(uintptr_t pll_addr, uint32_t ndivs, uint32_t mask) 285*c23dde6cSGhennadi Procopciuc { 286*c23dde6cSGhennadi Procopciuc uint32_t i; 287*c23dde6cSGhennadi Procopciuc 288*c23dde6cSGhennadi Procopciuc for (i = 0; i < ndivs; i++) { 289*c23dde6cSGhennadi Procopciuc if ((mask & BIT_32(i)) != 0U) { 290*c23dde6cSGhennadi Procopciuc enable_odiv(pll_addr, i); 291*c23dde6cSGhennadi Procopciuc } 292*c23dde6cSGhennadi Procopciuc } 293*c23dde6cSGhennadi Procopciuc } 294*c23dde6cSGhennadi Procopciuc 295*c23dde6cSGhennadi Procopciuc static int adjust_odiv_settings(const struct s32cc_pll *pll, uintptr_t pll_addr, 296*c23dde6cSGhennadi Procopciuc uint32_t odivs_mask, unsigned long old_vco) 297*c23dde6cSGhennadi Procopciuc { 298*c23dde6cSGhennadi Procopciuc uint64_t old_odiv_freq, odiv_freq; 299*c23dde6cSGhennadi Procopciuc uint32_t i, pllodiv, pdiv; 300*c23dde6cSGhennadi Procopciuc int ret = 0; 301*c23dde6cSGhennadi Procopciuc 302*c23dde6cSGhennadi Procopciuc if (old_vco == 0UL) { 303*c23dde6cSGhennadi Procopciuc return 0; 304*c23dde6cSGhennadi Procopciuc } 305*c23dde6cSGhennadi Procopciuc 306*c23dde6cSGhennadi Procopciuc for (i = 0; i < pll->ndividers; i++) { 307*c23dde6cSGhennadi Procopciuc if ((odivs_mask & BIT_32(i)) == 0U) { 308*c23dde6cSGhennadi Procopciuc continue; 309*c23dde6cSGhennadi Procopciuc } 310*c23dde6cSGhennadi Procopciuc 311*c23dde6cSGhennadi Procopciuc pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, i)); 312*c23dde6cSGhennadi Procopciuc 313*c23dde6cSGhennadi Procopciuc pdiv = PLLDIG_PLLODIV_DIV(pllodiv); 314*c23dde6cSGhennadi Procopciuc 315*c23dde6cSGhennadi Procopciuc old_odiv_freq = ((old_vco * FP_PRECISION) / (pdiv + 1U)) / FP_PRECISION; 316*c23dde6cSGhennadi Procopciuc pdiv = (uint32_t)(pll->vco_freq * FP_PRECISION / old_odiv_freq / FP_PRECISION); 317*c23dde6cSGhennadi Procopciuc 318*c23dde6cSGhennadi Procopciuc odiv_freq = pll->vco_freq * FP_PRECISION / pdiv / FP_PRECISION; 319*c23dde6cSGhennadi Procopciuc 320*c23dde6cSGhennadi Procopciuc if (old_odiv_freq != odiv_freq) { 321*c23dde6cSGhennadi Procopciuc ERROR("Failed to adjust ODIV %" PRIu32 " to match previous frequency\n", 322*c23dde6cSGhennadi Procopciuc i); 323*c23dde6cSGhennadi Procopciuc } 324*c23dde6cSGhennadi Procopciuc 325*c23dde6cSGhennadi Procopciuc pllodiv = PLLDIG_PLLODIV_DIV_SET(pdiv - 1U); 326*c23dde6cSGhennadi Procopciuc mmio_write_32(PLLDIG_PLLODIV(pll_addr, i), pllodiv); 327*c23dde6cSGhennadi Procopciuc } 328*c23dde6cSGhennadi Procopciuc 329*c23dde6cSGhennadi Procopciuc return ret; 330*c23dde6cSGhennadi Procopciuc } 331*c23dde6cSGhennadi Procopciuc 332*c23dde6cSGhennadi Procopciuc static uint32_t get_enabled_odivs(uintptr_t pll_addr, uint32_t ndivs) 333*c23dde6cSGhennadi Procopciuc { 334*c23dde6cSGhennadi Procopciuc uint32_t mask = 0; 335*c23dde6cSGhennadi Procopciuc uint32_t pllodiv; 336*c23dde6cSGhennadi Procopciuc uint32_t i; 337*c23dde6cSGhennadi Procopciuc 338*c23dde6cSGhennadi Procopciuc for (i = 0; i < ndivs; i++) { 339*c23dde6cSGhennadi Procopciuc pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, i)); 340*c23dde6cSGhennadi Procopciuc if ((pllodiv & PLLDIG_PLLODIV_DE) != 0U) { 341*c23dde6cSGhennadi Procopciuc mask |= BIT_32(i); 342*c23dde6cSGhennadi Procopciuc } 343*c23dde6cSGhennadi Procopciuc } 344*c23dde6cSGhennadi Procopciuc 345*c23dde6cSGhennadi Procopciuc return mask; 346*c23dde6cSGhennadi Procopciuc } 347*c23dde6cSGhennadi Procopciuc 348b5101c45SGhennadi Procopciuc static void disable_odivs(uintptr_t pll_addr, uint32_t ndivs) 349b5101c45SGhennadi Procopciuc { 350b5101c45SGhennadi Procopciuc uint32_t i; 351b5101c45SGhennadi Procopciuc 352b5101c45SGhennadi Procopciuc for (i = 0; i < ndivs; i++) { 353b5101c45SGhennadi Procopciuc disable_odiv(pll_addr, i); 354b5101c45SGhennadi Procopciuc } 355b5101c45SGhennadi Procopciuc } 356b5101c45SGhennadi Procopciuc 357b5101c45SGhennadi Procopciuc static void enable_pll_hw(uintptr_t pll_addr) 358b5101c45SGhennadi Procopciuc { 359b5101c45SGhennadi Procopciuc /* Enable the PLL. */ 360b5101c45SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLCR(pll_addr), 0x0); 361b5101c45SGhennadi Procopciuc 362b5101c45SGhennadi Procopciuc /* Poll until PLL acquires lock. */ 363b5101c45SGhennadi Procopciuc while ((mmio_read_32(PLLDIG_PLLSR(pll_addr)) & PLLDIG_PLLSR_LOCK) == 0U) { 364b5101c45SGhennadi Procopciuc } 365b5101c45SGhennadi Procopciuc } 366b5101c45SGhennadi Procopciuc 367b5101c45SGhennadi Procopciuc static void disable_pll_hw(uintptr_t pll_addr) 368b5101c45SGhennadi Procopciuc { 369b5101c45SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLCR(pll_addr), PLLDIG_PLLCR_PLLPD); 370b5101c45SGhennadi Procopciuc } 371b5101c45SGhennadi Procopciuc 372*c23dde6cSGhennadi Procopciuc static bool is_pll_enabled(uintptr_t pll_base) 373*c23dde6cSGhennadi Procopciuc { 374*c23dde6cSGhennadi Procopciuc uint32_t pllcr, pllsr; 375*c23dde6cSGhennadi Procopciuc 376*c23dde6cSGhennadi Procopciuc pllcr = mmio_read_32(PLLDIG_PLLCR(pll_base)); 377*c23dde6cSGhennadi Procopciuc pllsr = mmio_read_32(PLLDIG_PLLSR(pll_base)); 378*c23dde6cSGhennadi Procopciuc 379*c23dde6cSGhennadi Procopciuc /* Enabled and locked PLL */ 380*c23dde6cSGhennadi Procopciuc if ((pllcr & PLLDIG_PLLCR_PLLPD) != 0U) { 381*c23dde6cSGhennadi Procopciuc return false; 382*c23dde6cSGhennadi Procopciuc } 383*c23dde6cSGhennadi Procopciuc 384*c23dde6cSGhennadi Procopciuc if ((pllsr & PLLDIG_PLLSR_LOCK) == 0U) { 385*c23dde6cSGhennadi Procopciuc return false; 386*c23dde6cSGhennadi Procopciuc } 387*c23dde6cSGhennadi Procopciuc 388*c23dde6cSGhennadi Procopciuc return true; 389*c23dde6cSGhennadi Procopciuc } 390*c23dde6cSGhennadi Procopciuc 391b5101c45SGhennadi Procopciuc static int program_pll(const struct s32cc_pll *pll, uintptr_t pll_addr, 392b5101c45SGhennadi Procopciuc const struct s32cc_clk_drv *drv, uint32_t sclk_id, 393*c23dde6cSGhennadi Procopciuc unsigned long sclk_freq, unsigned int depth) 394b5101c45SGhennadi Procopciuc { 395b5101c45SGhennadi Procopciuc uint32_t rdiv = 1, mfi, mfn; 396*c23dde6cSGhennadi Procopciuc unsigned long old_vco = 0UL; 397*c23dde6cSGhennadi Procopciuc unsigned int ldepth = depth; 398*c23dde6cSGhennadi Procopciuc uint32_t odivs_mask; 399b5101c45SGhennadi Procopciuc int ret; 400b5101c45SGhennadi Procopciuc 401*c23dde6cSGhennadi Procopciuc ret = update_stack_depth(&ldepth); 402*c23dde6cSGhennadi Procopciuc if (ret != 0) { 403*c23dde6cSGhennadi Procopciuc return ret; 404*c23dde6cSGhennadi Procopciuc } 405*c23dde6cSGhennadi Procopciuc 406b5101c45SGhennadi Procopciuc ret = get_pll_mfi_mfn(pll->vco_freq, sclk_freq, &mfi, &mfn); 407b5101c45SGhennadi Procopciuc if (ret != 0) { 408b5101c45SGhennadi Procopciuc return -EINVAL; 409b5101c45SGhennadi Procopciuc } 410b5101c45SGhennadi Procopciuc 411*c23dde6cSGhennadi Procopciuc odivs_mask = get_enabled_odivs(pll_addr, pll->ndividers); 412*c23dde6cSGhennadi Procopciuc 413*c23dde6cSGhennadi Procopciuc if (is_pll_enabled(pll_addr)) { 414*c23dde6cSGhennadi Procopciuc ret = get_module_rate(&pll->desc, drv, &old_vco, ldepth); 415*c23dde6cSGhennadi Procopciuc if (ret != 0) { 416*c23dde6cSGhennadi Procopciuc return ret; 417*c23dde6cSGhennadi Procopciuc } 418*c23dde6cSGhennadi Procopciuc } 419*c23dde6cSGhennadi Procopciuc 420b5101c45SGhennadi Procopciuc /* Disable ODIVs*/ 421b5101c45SGhennadi Procopciuc disable_odivs(pll_addr, pll->ndividers); 422b5101c45SGhennadi Procopciuc 423b5101c45SGhennadi Procopciuc /* Disable PLL */ 424b5101c45SGhennadi Procopciuc disable_pll_hw(pll_addr); 425b5101c45SGhennadi Procopciuc 426b5101c45SGhennadi Procopciuc /* Program PLLCLKMUX */ 427b5101c45SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLCLKMUX(pll_addr), sclk_id); 428b5101c45SGhennadi Procopciuc 429b5101c45SGhennadi Procopciuc /* Program VCO */ 430b5101c45SGhennadi Procopciuc mmio_clrsetbits_32(PLLDIG_PLLDV(pll_addr), 431b5101c45SGhennadi Procopciuc PLLDIG_PLLDV_RDIV_MASK | PLLDIG_PLLDV_MFI_MASK, 432b5101c45SGhennadi Procopciuc PLLDIG_PLLDV_RDIV_SET(rdiv) | PLLDIG_PLLDV_MFI(mfi)); 433b5101c45SGhennadi Procopciuc 434b5101c45SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLFD(pll_addr), 435b5101c45SGhennadi Procopciuc PLLDIG_PLLFD_MFN_SET(mfn) | PLLDIG_PLLFD_SMDEN); 436b5101c45SGhennadi Procopciuc 437*c23dde6cSGhennadi Procopciuc ret = adjust_odiv_settings(pll, pll_addr, odivs_mask, old_vco); 438*c23dde6cSGhennadi Procopciuc if (ret != 0) { 439*c23dde6cSGhennadi Procopciuc return ret; 440*c23dde6cSGhennadi Procopciuc } 441*c23dde6cSGhennadi Procopciuc 442b5101c45SGhennadi Procopciuc enable_pll_hw(pll_addr); 443b5101c45SGhennadi Procopciuc 444*c23dde6cSGhennadi Procopciuc /* Enable out dividers */ 445*c23dde6cSGhennadi Procopciuc enable_odivs(pll_addr, pll->ndividers, odivs_mask); 446*c23dde6cSGhennadi Procopciuc 447b5101c45SGhennadi Procopciuc return ret; 448b5101c45SGhennadi Procopciuc } 449b5101c45SGhennadi Procopciuc 4505300040bSGhennadi Procopciuc static int enable_pll(struct s32cc_clk_obj *module, 451b5101c45SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 4525300040bSGhennadi Procopciuc unsigned int depth) 453b5101c45SGhennadi Procopciuc { 454b5101c45SGhennadi Procopciuc const struct s32cc_pll *pll = s32cc_obj2pll(module); 455*c23dde6cSGhennadi Procopciuc unsigned int clk_src, ldepth = depth; 456*c23dde6cSGhennadi Procopciuc unsigned long sclk_freq, pll_vco; 457b5101c45SGhennadi Procopciuc const struct s32cc_clkmux *mux; 458b5101c45SGhennadi Procopciuc uintptr_t pll_addr = UL(0x0); 459*c23dde6cSGhennadi Procopciuc bool pll_enabled; 460b5101c45SGhennadi Procopciuc uint32_t sclk_id; 461b5101c45SGhennadi Procopciuc int ret; 462b5101c45SGhennadi Procopciuc 4638ee0fc31SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 464b5101c45SGhennadi Procopciuc if (ret != 0) { 465b5101c45SGhennadi Procopciuc return ret; 466b5101c45SGhennadi Procopciuc } 467b5101c45SGhennadi Procopciuc 468b5101c45SGhennadi Procopciuc mux = get_pll_mux(pll); 469b5101c45SGhennadi Procopciuc if (mux == NULL) { 470b5101c45SGhennadi Procopciuc return -EINVAL; 471b5101c45SGhennadi Procopciuc } 472b5101c45SGhennadi Procopciuc 473b5101c45SGhennadi Procopciuc if (pll->instance != mux->module) { 474b5101c45SGhennadi Procopciuc ERROR("MUX type is not in sync with PLL ID\n"); 475b5101c45SGhennadi Procopciuc return -EINVAL; 476b5101c45SGhennadi Procopciuc } 477b5101c45SGhennadi Procopciuc 478b5101c45SGhennadi Procopciuc ret = get_base_addr(pll->instance, drv, &pll_addr); 479b5101c45SGhennadi Procopciuc if (ret != 0) { 480b5101c45SGhennadi Procopciuc ERROR("Failed to detect PLL instance\n"); 481b5101c45SGhennadi Procopciuc return ret; 482b5101c45SGhennadi Procopciuc } 483b5101c45SGhennadi Procopciuc 484b5101c45SGhennadi Procopciuc switch (mux->source_id) { 485b5101c45SGhennadi Procopciuc case S32CC_CLK_FIRC: 486b5101c45SGhennadi Procopciuc sclk_freq = 48U * MHZ; 487b5101c45SGhennadi Procopciuc sclk_id = 0; 488b5101c45SGhennadi Procopciuc break; 489b5101c45SGhennadi Procopciuc case S32CC_CLK_FXOSC: 490b5101c45SGhennadi Procopciuc sclk_freq = 40U * MHZ; 491b5101c45SGhennadi Procopciuc sclk_id = 1; 492b5101c45SGhennadi Procopciuc break; 493b5101c45SGhennadi Procopciuc default: 494b5101c45SGhennadi Procopciuc ERROR("Invalid source selection for PLL 0x%lx\n", 495b5101c45SGhennadi Procopciuc pll_addr); 496b5101c45SGhennadi Procopciuc return -EINVAL; 497b5101c45SGhennadi Procopciuc }; 498b5101c45SGhennadi Procopciuc 499*c23dde6cSGhennadi Procopciuc ret = get_module_rate(&pll->desc, drv, &pll_vco, depth); 500*c23dde6cSGhennadi Procopciuc if (ret != 0) { 501*c23dde6cSGhennadi Procopciuc return ret; 502*c23dde6cSGhennadi Procopciuc } 503*c23dde6cSGhennadi Procopciuc 504*c23dde6cSGhennadi Procopciuc pll_enabled = is_pll_enabled(pll_addr); 505*c23dde6cSGhennadi Procopciuc clk_src = mmio_read_32(PLLDIG_PLLCLKMUX(pll_addr)); 506*c23dde6cSGhennadi Procopciuc 507*c23dde6cSGhennadi Procopciuc if ((clk_src == sclk_id) && pll_enabled && 508*c23dde6cSGhennadi Procopciuc (pll_vco == pll->vco_freq)) { 509*c23dde6cSGhennadi Procopciuc return 0; 510*c23dde6cSGhennadi Procopciuc } 511*c23dde6cSGhennadi Procopciuc 512*c23dde6cSGhennadi Procopciuc return program_pll(pll, pll_addr, drv, sclk_id, sclk_freq, ldepth); 513b5101c45SGhennadi Procopciuc } 514b5101c45SGhennadi Procopciuc 51584e82085SGhennadi Procopciuc static inline struct s32cc_pll *get_div_pll(const struct s32cc_pll_out_div *pdiv) 51684e82085SGhennadi Procopciuc { 51784e82085SGhennadi Procopciuc const struct s32cc_clk_obj *parent; 51884e82085SGhennadi Procopciuc 51984e82085SGhennadi Procopciuc parent = pdiv->parent; 52084e82085SGhennadi Procopciuc if (parent == NULL) { 52184e82085SGhennadi Procopciuc ERROR("Failed to identify PLL divider's parent\n"); 52284e82085SGhennadi Procopciuc return NULL; 52384e82085SGhennadi Procopciuc } 52484e82085SGhennadi Procopciuc 52584e82085SGhennadi Procopciuc if (parent->type != s32cc_pll_t) { 52684e82085SGhennadi Procopciuc ERROR("The parent of the divider is not a PLL instance\n"); 52784e82085SGhennadi Procopciuc return NULL; 52884e82085SGhennadi Procopciuc } 52984e82085SGhennadi Procopciuc 53084e82085SGhennadi Procopciuc return s32cc_obj2pll(parent); 53184e82085SGhennadi Procopciuc } 53284e82085SGhennadi Procopciuc 53384e82085SGhennadi Procopciuc static void config_pll_out_div(uintptr_t pll_addr, uint32_t div_index, uint32_t dc) 53484e82085SGhennadi Procopciuc { 53584e82085SGhennadi Procopciuc uint32_t pllodiv; 53684e82085SGhennadi Procopciuc uint32_t pdiv; 53784e82085SGhennadi Procopciuc 53884e82085SGhennadi Procopciuc pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, div_index)); 53984e82085SGhennadi Procopciuc pdiv = PLLDIG_PLLODIV_DIV(pllodiv); 54084e82085SGhennadi Procopciuc 54184e82085SGhennadi Procopciuc if (((pdiv + 1U) == dc) && ((pllodiv & PLLDIG_PLLODIV_DE) != 0U)) { 54284e82085SGhennadi Procopciuc return; 54384e82085SGhennadi Procopciuc } 54484e82085SGhennadi Procopciuc 54584e82085SGhennadi Procopciuc if ((pllodiv & PLLDIG_PLLODIV_DE) != 0U) { 54684e82085SGhennadi Procopciuc disable_odiv(pll_addr, div_index); 54784e82085SGhennadi Procopciuc } 54884e82085SGhennadi Procopciuc 54984e82085SGhennadi Procopciuc pllodiv = PLLDIG_PLLODIV_DIV_SET(dc - 1U); 55084e82085SGhennadi Procopciuc mmio_write_32(PLLDIG_PLLODIV(pll_addr, div_index), pllodiv); 55184e82085SGhennadi Procopciuc 55284e82085SGhennadi Procopciuc enable_odiv(pll_addr, div_index); 55384e82085SGhennadi Procopciuc } 55484e82085SGhennadi Procopciuc 55596e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_pll_div_parent(const struct s32cc_clk_obj *module) 55696e069cbSGhennadi Procopciuc { 55796e069cbSGhennadi Procopciuc const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module); 55896e069cbSGhennadi Procopciuc 55996e069cbSGhennadi Procopciuc if (pdiv->parent == NULL) { 56096e069cbSGhennadi Procopciuc ERROR("Failed to identify PLL DIV's parent\n"); 56196e069cbSGhennadi Procopciuc } 56296e069cbSGhennadi Procopciuc 56396e069cbSGhennadi Procopciuc return pdiv->parent; 56496e069cbSGhennadi Procopciuc } 56596e069cbSGhennadi Procopciuc 5665300040bSGhennadi Procopciuc static int enable_pll_div(struct s32cc_clk_obj *module, 56784e82085SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 5685300040bSGhennadi Procopciuc unsigned int depth) 56984e82085SGhennadi Procopciuc { 57084e82085SGhennadi Procopciuc const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module); 57184e82085SGhennadi Procopciuc uintptr_t pll_addr = 0x0ULL; 5728ee0fc31SGhennadi Procopciuc unsigned int ldepth = depth; 57384e82085SGhennadi Procopciuc const struct s32cc_pll *pll; 574*c23dde6cSGhennadi Procopciuc unsigned long pll_vco; 57584e82085SGhennadi Procopciuc uint32_t dc; 57684e82085SGhennadi Procopciuc int ret; 57784e82085SGhennadi Procopciuc 5788ee0fc31SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 57984e82085SGhennadi Procopciuc if (ret != 0) { 58084e82085SGhennadi Procopciuc return ret; 58184e82085SGhennadi Procopciuc } 58284e82085SGhennadi Procopciuc 58384e82085SGhennadi Procopciuc pll = get_div_pll(pdiv); 58484e82085SGhennadi Procopciuc if (pll == NULL) { 58584e82085SGhennadi Procopciuc ERROR("The parent of the PLL DIV is invalid\n"); 58684e82085SGhennadi Procopciuc return 0; 58784e82085SGhennadi Procopciuc } 58884e82085SGhennadi Procopciuc 58984e82085SGhennadi Procopciuc ret = get_base_addr(pll->instance, drv, &pll_addr); 59084e82085SGhennadi Procopciuc if (ret != 0) { 59184e82085SGhennadi Procopciuc ERROR("Failed to detect PLL instance\n"); 59284e82085SGhennadi Procopciuc return -EINVAL; 59384e82085SGhennadi Procopciuc } 59484e82085SGhennadi Procopciuc 595*c23dde6cSGhennadi Procopciuc ret = get_module_rate(&pll->desc, drv, &pll_vco, ldepth); 596*c23dde6cSGhennadi Procopciuc if (ret != 0) { 597*c23dde6cSGhennadi Procopciuc ERROR("Failed to enable the PLL due to unknown rate for 0x%" PRIxPTR "\n", 598*c23dde6cSGhennadi Procopciuc pll_addr); 599*c23dde6cSGhennadi Procopciuc return ret; 600*c23dde6cSGhennadi Procopciuc } 601*c23dde6cSGhennadi Procopciuc 602*c23dde6cSGhennadi Procopciuc dc = (uint32_t)(pll_vco / pdiv->freq); 60384e82085SGhennadi Procopciuc 60484e82085SGhennadi Procopciuc config_pll_out_div(pll_addr, pdiv->index, dc); 60584e82085SGhennadi Procopciuc 60684e82085SGhennadi Procopciuc return 0; 60784e82085SGhennadi Procopciuc } 60884e82085SGhennadi Procopciuc 6097004f678SGhennadi Procopciuc static int cgm_mux_clk_config(uintptr_t cgm_addr, uint32_t mux, uint32_t source, 6107004f678SGhennadi Procopciuc bool safe_clk) 6117004f678SGhennadi Procopciuc { 6127004f678SGhennadi Procopciuc uint32_t css, csc; 6137004f678SGhennadi Procopciuc 6147004f678SGhennadi Procopciuc css = mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)); 6157004f678SGhennadi Procopciuc 6167004f678SGhennadi Procopciuc /* Already configured */ 6177004f678SGhennadi Procopciuc if ((MC_CGM_MUXn_CSS_SELSTAT(css) == source) && 6187004f678SGhennadi Procopciuc (MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SUCCESS) && 6197004f678SGhennadi Procopciuc ((css & MC_CGM_MUXn_CSS_SWIP) == 0U) && !safe_clk) { 6207004f678SGhennadi Procopciuc return 0; 6217004f678SGhennadi Procopciuc } 6227004f678SGhennadi Procopciuc 6237004f678SGhennadi Procopciuc /* Ongoing clock switch? */ 6247004f678SGhennadi Procopciuc while ((mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)) & 6257004f678SGhennadi Procopciuc MC_CGM_MUXn_CSS_SWIP) != 0U) { 6267004f678SGhennadi Procopciuc } 6277004f678SGhennadi Procopciuc 6287004f678SGhennadi Procopciuc csc = mmio_read_32(CGM_MUXn_CSC(cgm_addr, mux)); 6297004f678SGhennadi Procopciuc 6307004f678SGhennadi Procopciuc /* Clear previous source. */ 6317004f678SGhennadi Procopciuc csc &= ~(MC_CGM_MUXn_CSC_SELCTL_MASK); 6327004f678SGhennadi Procopciuc 6337004f678SGhennadi Procopciuc if (!safe_clk) { 6347004f678SGhennadi Procopciuc /* Select the clock source and trigger the clock switch. */ 6357004f678SGhennadi Procopciuc csc |= MC_CGM_MUXn_CSC_SELCTL(source) | MC_CGM_MUXn_CSC_CLK_SW; 6367004f678SGhennadi Procopciuc } else { 6377004f678SGhennadi Procopciuc /* Switch to safe clock */ 6387004f678SGhennadi Procopciuc csc |= MC_CGM_MUXn_CSC_SAFE_SW; 6397004f678SGhennadi Procopciuc } 6407004f678SGhennadi Procopciuc 6417004f678SGhennadi Procopciuc mmio_write_32(CGM_MUXn_CSC(cgm_addr, mux), csc); 6427004f678SGhennadi Procopciuc 6437004f678SGhennadi Procopciuc /* Wait for configuration bit to auto-clear. */ 6447004f678SGhennadi Procopciuc while ((mmio_read_32(CGM_MUXn_CSC(cgm_addr, mux)) & 6457004f678SGhennadi Procopciuc MC_CGM_MUXn_CSC_CLK_SW) != 0U) { 6467004f678SGhennadi Procopciuc } 6477004f678SGhennadi Procopciuc 6487004f678SGhennadi Procopciuc /* Is the clock switch completed? */ 6497004f678SGhennadi Procopciuc while ((mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)) & 6507004f678SGhennadi Procopciuc MC_CGM_MUXn_CSS_SWIP) != 0U) { 6517004f678SGhennadi Procopciuc } 6527004f678SGhennadi Procopciuc 6537004f678SGhennadi Procopciuc /* 6547004f678SGhennadi Procopciuc * Check if the switch succeeded. 6557004f678SGhennadi Procopciuc * Check switch trigger cause and the source. 6567004f678SGhennadi Procopciuc */ 6577004f678SGhennadi Procopciuc css = mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)); 6587004f678SGhennadi Procopciuc if (!safe_clk) { 6597004f678SGhennadi Procopciuc if ((MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SUCCESS) && 6607004f678SGhennadi Procopciuc (MC_CGM_MUXn_CSS_SELSTAT(css) == source)) { 6617004f678SGhennadi Procopciuc return 0; 6627004f678SGhennadi Procopciuc } 6637004f678SGhennadi Procopciuc 6647004f678SGhennadi Procopciuc ERROR("Failed to change the source of mux %" PRIu32 " to %" PRIu32 " (CGM=%lu)\n", 6657004f678SGhennadi Procopciuc mux, source, cgm_addr); 6667004f678SGhennadi Procopciuc } else { 6677004f678SGhennadi Procopciuc if (((MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK) || 6687004f678SGhennadi Procopciuc (MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK_INACTIVE)) && 6697004f678SGhennadi Procopciuc ((MC_CGM_MUXn_CSS_SAFE_SW & css) != 0U)) { 6707004f678SGhennadi Procopciuc return 0; 6717004f678SGhennadi Procopciuc } 6727004f678SGhennadi Procopciuc 6737004f678SGhennadi Procopciuc ERROR("The switch of mux %" PRIu32 " (CGM=%lu) to safe clock failed\n", 6747004f678SGhennadi Procopciuc mux, cgm_addr); 6757004f678SGhennadi Procopciuc } 6767004f678SGhennadi Procopciuc 6777004f678SGhennadi Procopciuc return -EINVAL; 6787004f678SGhennadi Procopciuc } 6797004f678SGhennadi Procopciuc 6807004f678SGhennadi Procopciuc static int enable_cgm_mux(const struct s32cc_clkmux *mux, 6817004f678SGhennadi Procopciuc const struct s32cc_clk_drv *drv) 6827004f678SGhennadi Procopciuc { 6837004f678SGhennadi Procopciuc uintptr_t cgm_addr = UL(0x0); 6847004f678SGhennadi Procopciuc uint32_t mux_hw_clk; 6857004f678SGhennadi Procopciuc int ret; 6867004f678SGhennadi Procopciuc 6877004f678SGhennadi Procopciuc ret = get_base_addr(mux->module, drv, &cgm_addr); 6887004f678SGhennadi Procopciuc if (ret != 0) { 6897004f678SGhennadi Procopciuc return ret; 6907004f678SGhennadi Procopciuc } 6917004f678SGhennadi Procopciuc 6927004f678SGhennadi Procopciuc mux_hw_clk = (uint32_t)S32CC_CLK_ID(mux->source_id); 6937004f678SGhennadi Procopciuc 6947004f678SGhennadi Procopciuc return cgm_mux_clk_config(cgm_addr, mux->index, 6957004f678SGhennadi Procopciuc mux_hw_clk, false); 6967004f678SGhennadi Procopciuc } 6977004f678SGhennadi Procopciuc 69896e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_mux_parent(const struct s32cc_clk_obj *module) 69996e069cbSGhennadi Procopciuc { 70096e069cbSGhennadi Procopciuc const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module); 70196e069cbSGhennadi Procopciuc struct s32cc_clk *clk; 70296e069cbSGhennadi Procopciuc 70396e069cbSGhennadi Procopciuc if (mux == NULL) { 70496e069cbSGhennadi Procopciuc return NULL; 70596e069cbSGhennadi Procopciuc } 70696e069cbSGhennadi Procopciuc 70796e069cbSGhennadi Procopciuc clk = s32cc_get_arch_clk(mux->source_id); 70896e069cbSGhennadi Procopciuc if (clk == NULL) { 70996e069cbSGhennadi Procopciuc ERROR("Invalid parent (%lu) for mux %" PRIu8 "\n", 71096e069cbSGhennadi Procopciuc mux->source_id, mux->index); 71196e069cbSGhennadi Procopciuc return NULL; 71296e069cbSGhennadi Procopciuc } 71396e069cbSGhennadi Procopciuc 71496e069cbSGhennadi Procopciuc return &clk->desc; 71596e069cbSGhennadi Procopciuc } 71696e069cbSGhennadi Procopciuc 7175300040bSGhennadi Procopciuc static int enable_mux(struct s32cc_clk_obj *module, 7187004f678SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 7195300040bSGhennadi Procopciuc unsigned int depth) 7207004f678SGhennadi Procopciuc { 7217004f678SGhennadi Procopciuc const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module); 7228ee0fc31SGhennadi Procopciuc unsigned int ldepth = depth; 7237004f678SGhennadi Procopciuc const struct s32cc_clk *clk; 7247004f678SGhennadi Procopciuc int ret = 0; 7257004f678SGhennadi Procopciuc 7268ee0fc31SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 7277004f678SGhennadi Procopciuc if (ret != 0) { 7287004f678SGhennadi Procopciuc return ret; 7297004f678SGhennadi Procopciuc } 7307004f678SGhennadi Procopciuc 7317004f678SGhennadi Procopciuc if (mux == NULL) { 7327004f678SGhennadi Procopciuc return -EINVAL; 7337004f678SGhennadi Procopciuc } 7347004f678SGhennadi Procopciuc 7357004f678SGhennadi Procopciuc clk = s32cc_get_arch_clk(mux->source_id); 7367004f678SGhennadi Procopciuc if (clk == NULL) { 7377004f678SGhennadi Procopciuc ERROR("Invalid parent (%lu) for mux %" PRIu8 "\n", 7387004f678SGhennadi Procopciuc mux->source_id, mux->index); 7397004f678SGhennadi Procopciuc return -EINVAL; 7407004f678SGhennadi Procopciuc } 7417004f678SGhennadi Procopciuc 7427004f678SGhennadi Procopciuc switch (mux->module) { 7437004f678SGhennadi Procopciuc /* PLL mux will be enabled by PLL setup */ 7447004f678SGhennadi Procopciuc case S32CC_ARM_PLL: 745f8490b85SGhennadi Procopciuc case S32CC_PERIPH_PLL: 74618c2b137SGhennadi Procopciuc case S32CC_DDR_PLL: 7477004f678SGhennadi Procopciuc break; 7487004f678SGhennadi Procopciuc case S32CC_CGM1: 7497004f678SGhennadi Procopciuc ret = enable_cgm_mux(mux, drv); 7507004f678SGhennadi Procopciuc break; 7519dbca85dSGhennadi Procopciuc case S32CC_CGM0: 7529dbca85dSGhennadi Procopciuc ret = enable_cgm_mux(mux, drv); 7539dbca85dSGhennadi Procopciuc break; 7548a4f840bSGhennadi Procopciuc case S32CC_CGM5: 7558a4f840bSGhennadi Procopciuc ret = enable_cgm_mux(mux, drv); 7568a4f840bSGhennadi Procopciuc break; 7577004f678SGhennadi Procopciuc default: 7587004f678SGhennadi Procopciuc ERROR("Unknown mux parent type: %d\n", mux->module); 7597004f678SGhennadi Procopciuc ret = -EINVAL; 7607004f678SGhennadi Procopciuc break; 7617004f678SGhennadi Procopciuc }; 7627004f678SGhennadi Procopciuc 7637004f678SGhennadi Procopciuc return ret; 7647004f678SGhennadi Procopciuc } 7657004f678SGhennadi Procopciuc 76696e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_dfs_parent(const struct s32cc_clk_obj *module) 76796e069cbSGhennadi Procopciuc { 76896e069cbSGhennadi Procopciuc const struct s32cc_dfs *dfs = s32cc_obj2dfs(module); 76996e069cbSGhennadi Procopciuc 77096e069cbSGhennadi Procopciuc if (dfs->parent == NULL) { 77196e069cbSGhennadi Procopciuc ERROR("Failed to identify DFS's parent\n"); 77296e069cbSGhennadi Procopciuc } 77396e069cbSGhennadi Procopciuc 77496e069cbSGhennadi Procopciuc return dfs->parent; 77596e069cbSGhennadi Procopciuc } 77696e069cbSGhennadi Procopciuc 7775300040bSGhennadi Procopciuc static int enable_dfs(struct s32cc_clk_obj *module, 7784cd04c50SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 7795300040bSGhennadi Procopciuc unsigned int depth) 7804cd04c50SGhennadi Procopciuc { 7818ee0fc31SGhennadi Procopciuc unsigned int ldepth = depth; 7824cd04c50SGhennadi Procopciuc int ret = 0; 7834cd04c50SGhennadi Procopciuc 7848ee0fc31SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 7854cd04c50SGhennadi Procopciuc if (ret != 0) { 7864cd04c50SGhennadi Procopciuc return ret; 7874cd04c50SGhennadi Procopciuc } 7884cd04c50SGhennadi Procopciuc 7894cd04c50SGhennadi Procopciuc return 0; 7904cd04c50SGhennadi Procopciuc } 7914cd04c50SGhennadi Procopciuc 7922fb25509SGhennadi Procopciuc static int get_dfs_freq(const struct s32cc_clk_obj *module, 7932fb25509SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 7942fb25509SGhennadi Procopciuc unsigned long *rate, unsigned int depth) 7952fb25509SGhennadi Procopciuc { 7962fb25509SGhennadi Procopciuc const struct s32cc_dfs *dfs = s32cc_obj2dfs(module); 7972fb25509SGhennadi Procopciuc unsigned int ldepth = depth; 7982fb25509SGhennadi Procopciuc uintptr_t dfs_addr; 7992fb25509SGhennadi Procopciuc int ret; 8002fb25509SGhennadi Procopciuc 8012fb25509SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 8022fb25509SGhennadi Procopciuc if (ret != 0) { 8032fb25509SGhennadi Procopciuc return ret; 8042fb25509SGhennadi Procopciuc } 8052fb25509SGhennadi Procopciuc 8062fb25509SGhennadi Procopciuc ret = get_base_addr(dfs->instance, drv, &dfs_addr); 8072fb25509SGhennadi Procopciuc if (ret != 0) { 8082fb25509SGhennadi Procopciuc ERROR("Failed to detect the DFS instance\n"); 8092fb25509SGhennadi Procopciuc return ret; 8102fb25509SGhennadi Procopciuc } 8112fb25509SGhennadi Procopciuc 8122fb25509SGhennadi Procopciuc return get_module_rate(dfs->parent, drv, rate, ldepth); 8132fb25509SGhennadi Procopciuc } 8142fb25509SGhennadi Procopciuc 8154cd04c50SGhennadi Procopciuc static struct s32cc_dfs *get_div_dfs(const struct s32cc_dfs_div *dfs_div) 8164cd04c50SGhennadi Procopciuc { 8174cd04c50SGhennadi Procopciuc const struct s32cc_clk_obj *parent = dfs_div->parent; 8184cd04c50SGhennadi Procopciuc 8194cd04c50SGhennadi Procopciuc if (parent->type != s32cc_dfs_t) { 8204cd04c50SGhennadi Procopciuc ERROR("DFS DIV doesn't have a DFS as parent\n"); 8214cd04c50SGhennadi Procopciuc return NULL; 8224cd04c50SGhennadi Procopciuc } 8234cd04c50SGhennadi Procopciuc 8244cd04c50SGhennadi Procopciuc return s32cc_obj2dfs(parent); 8254cd04c50SGhennadi Procopciuc } 8264cd04c50SGhennadi Procopciuc 8274cd04c50SGhennadi Procopciuc static int get_dfs_mfi_mfn(unsigned long dfs_freq, const struct s32cc_dfs_div *dfs_div, 8284cd04c50SGhennadi Procopciuc uint32_t *mfi, uint32_t *mfn) 8294cd04c50SGhennadi Procopciuc { 8304cd04c50SGhennadi Procopciuc uint64_t factor64, tmp64, ofreq; 8314cd04c50SGhennadi Procopciuc uint32_t factor32; 8324cd04c50SGhennadi Procopciuc 8334cd04c50SGhennadi Procopciuc unsigned long in = dfs_freq; 8344cd04c50SGhennadi Procopciuc unsigned long out = dfs_div->freq; 8354cd04c50SGhennadi Procopciuc 8364cd04c50SGhennadi Procopciuc /** 8374cd04c50SGhennadi Procopciuc * factor = (IN / OUT) / 2 8384cd04c50SGhennadi Procopciuc * MFI = integer(factor) 8394cd04c50SGhennadi Procopciuc * MFN = (factor - MFI) * 36 8404cd04c50SGhennadi Procopciuc */ 8414cd04c50SGhennadi Procopciuc factor64 = ((((uint64_t)in) * FP_PRECISION) / ((uint64_t)out)) / 2ULL; 8424cd04c50SGhennadi Procopciuc tmp64 = factor64 / FP_PRECISION; 8434cd04c50SGhennadi Procopciuc if (tmp64 > UINT32_MAX) { 8444cd04c50SGhennadi Procopciuc return -EINVAL; 8454cd04c50SGhennadi Procopciuc } 8464cd04c50SGhennadi Procopciuc 8474cd04c50SGhennadi Procopciuc factor32 = (uint32_t)tmp64; 8484cd04c50SGhennadi Procopciuc *mfi = factor32; 8494cd04c50SGhennadi Procopciuc 8504cd04c50SGhennadi Procopciuc tmp64 = ((factor64 - ((uint64_t)*mfi * FP_PRECISION)) * 36UL) / FP_PRECISION; 8514cd04c50SGhennadi Procopciuc if (tmp64 > UINT32_MAX) { 8524cd04c50SGhennadi Procopciuc return -EINVAL; 8534cd04c50SGhennadi Procopciuc } 8544cd04c50SGhennadi Procopciuc 8554cd04c50SGhennadi Procopciuc *mfn = (uint32_t)tmp64; 8564cd04c50SGhennadi Procopciuc 8574cd04c50SGhennadi Procopciuc /* div_freq = in / (2 * (*mfi + *mfn / 36.0)) */ 8584cd04c50SGhennadi Procopciuc factor64 = (((uint64_t)*mfn) * FP_PRECISION) / 36ULL; 8594cd04c50SGhennadi Procopciuc factor64 += ((uint64_t)*mfi) * FP_PRECISION; 8604cd04c50SGhennadi Procopciuc factor64 *= 2ULL; 8614cd04c50SGhennadi Procopciuc ofreq = (((uint64_t)in) * FP_PRECISION) / factor64; 8624cd04c50SGhennadi Procopciuc 8634cd04c50SGhennadi Procopciuc if (ofreq != dfs_div->freq) { 8644cd04c50SGhennadi Procopciuc ERROR("Failed to find MFI and MFN settings for DFS DIV freq %lu\n", 8654cd04c50SGhennadi Procopciuc dfs_div->freq); 8664cd04c50SGhennadi Procopciuc ERROR("Nearest freq = %" PRIx64 "\n", ofreq); 8674cd04c50SGhennadi Procopciuc return -EINVAL; 8684cd04c50SGhennadi Procopciuc } 8694cd04c50SGhennadi Procopciuc 8704cd04c50SGhennadi Procopciuc return 0; 8714cd04c50SGhennadi Procopciuc } 8724cd04c50SGhennadi Procopciuc 8734cd04c50SGhennadi Procopciuc static int init_dfs_port(uintptr_t dfs_addr, uint32_t port, 8744cd04c50SGhennadi Procopciuc uint32_t mfi, uint32_t mfn) 8754cd04c50SGhennadi Procopciuc { 8764cd04c50SGhennadi Procopciuc uint32_t portsr, portolsr; 8774cd04c50SGhennadi Procopciuc uint32_t mask, old_mfi, old_mfn; 8784cd04c50SGhennadi Procopciuc uint32_t dvport; 8794cd04c50SGhennadi Procopciuc bool init_dfs; 8804cd04c50SGhennadi Procopciuc 8814cd04c50SGhennadi Procopciuc dvport = mmio_read_32(DFS_DVPORTn(dfs_addr, port)); 8824cd04c50SGhennadi Procopciuc 8834cd04c50SGhennadi Procopciuc old_mfi = DFS_DVPORTn_MFI(dvport); 8844cd04c50SGhennadi Procopciuc old_mfn = DFS_DVPORTn_MFN(dvport); 8854cd04c50SGhennadi Procopciuc 8864cd04c50SGhennadi Procopciuc portsr = mmio_read_32(DFS_PORTSR(dfs_addr)); 8874cd04c50SGhennadi Procopciuc portolsr = mmio_read_32(DFS_PORTOLSR(dfs_addr)); 8884cd04c50SGhennadi Procopciuc 8894cd04c50SGhennadi Procopciuc /* Skip configuration if it's not needed */ 8904cd04c50SGhennadi Procopciuc if (((portsr & BIT_32(port)) != 0U) && 8914cd04c50SGhennadi Procopciuc ((portolsr & BIT_32(port)) == 0U) && 8924cd04c50SGhennadi Procopciuc (mfi == old_mfi) && (mfn == old_mfn)) { 8934cd04c50SGhennadi Procopciuc return 0; 8944cd04c50SGhennadi Procopciuc } 8954cd04c50SGhennadi Procopciuc 8964cd04c50SGhennadi Procopciuc init_dfs = (portsr == 0U); 8974cd04c50SGhennadi Procopciuc 8984cd04c50SGhennadi Procopciuc if (init_dfs) { 8994cd04c50SGhennadi Procopciuc mask = DFS_PORTRESET_MASK; 9004cd04c50SGhennadi Procopciuc } else { 9014cd04c50SGhennadi Procopciuc mask = DFS_PORTRESET_SET(BIT_32(port)); 9024cd04c50SGhennadi Procopciuc } 9034cd04c50SGhennadi Procopciuc 9044cd04c50SGhennadi Procopciuc mmio_write_32(DFS_PORTOLSR(dfs_addr), mask); 9054cd04c50SGhennadi Procopciuc mmio_write_32(DFS_PORTRESET(dfs_addr), mask); 9064cd04c50SGhennadi Procopciuc 9074cd04c50SGhennadi Procopciuc while ((mmio_read_32(DFS_PORTSR(dfs_addr)) & mask) != 0U) { 9084cd04c50SGhennadi Procopciuc } 9094cd04c50SGhennadi Procopciuc 9104cd04c50SGhennadi Procopciuc if (init_dfs) { 9114cd04c50SGhennadi Procopciuc mmio_write_32(DFS_CTL(dfs_addr), DFS_CTL_RESET); 9124cd04c50SGhennadi Procopciuc } 9134cd04c50SGhennadi Procopciuc 9144cd04c50SGhennadi Procopciuc mmio_write_32(DFS_DVPORTn(dfs_addr, port), 9154cd04c50SGhennadi Procopciuc DFS_DVPORTn_MFI_SET(mfi) | DFS_DVPORTn_MFN_SET(mfn)); 9164cd04c50SGhennadi Procopciuc 9174cd04c50SGhennadi Procopciuc if (init_dfs) { 9184cd04c50SGhennadi Procopciuc /* DFS clk enable programming */ 9194cd04c50SGhennadi Procopciuc mmio_clrbits_32(DFS_CTL(dfs_addr), DFS_CTL_RESET); 9204cd04c50SGhennadi Procopciuc } 9214cd04c50SGhennadi Procopciuc 9224cd04c50SGhennadi Procopciuc mmio_clrbits_32(DFS_PORTRESET(dfs_addr), BIT_32(port)); 9234cd04c50SGhennadi Procopciuc 9244cd04c50SGhennadi Procopciuc while ((mmio_read_32(DFS_PORTSR(dfs_addr)) & BIT_32(port)) != BIT_32(port)) { 9254cd04c50SGhennadi Procopciuc } 9264cd04c50SGhennadi Procopciuc 9274cd04c50SGhennadi Procopciuc portolsr = mmio_read_32(DFS_PORTOLSR(dfs_addr)); 9284cd04c50SGhennadi Procopciuc if ((portolsr & DFS_PORTOLSR_LOL(port)) != 0U) { 9294cd04c50SGhennadi Procopciuc ERROR("Failed to lock DFS divider\n"); 9304cd04c50SGhennadi Procopciuc return -EINVAL; 9314cd04c50SGhennadi Procopciuc } 9324cd04c50SGhennadi Procopciuc 9334cd04c50SGhennadi Procopciuc return 0; 9344cd04c50SGhennadi Procopciuc } 9354cd04c50SGhennadi Procopciuc 93696e069cbSGhennadi Procopciuc static struct s32cc_clk_obj * 93796e069cbSGhennadi Procopciuc get_dfs_div_parent(const struct s32cc_clk_obj *module) 93896e069cbSGhennadi Procopciuc { 93996e069cbSGhennadi Procopciuc const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module); 94096e069cbSGhennadi Procopciuc 94196e069cbSGhennadi Procopciuc if (dfs_div->parent == NULL) { 94296e069cbSGhennadi Procopciuc ERROR("Failed to identify DFS divider's parent\n"); 94396e069cbSGhennadi Procopciuc } 94496e069cbSGhennadi Procopciuc 94596e069cbSGhennadi Procopciuc return dfs_div->parent; 94696e069cbSGhennadi Procopciuc } 94796e069cbSGhennadi Procopciuc 9485300040bSGhennadi Procopciuc static int enable_dfs_div(struct s32cc_clk_obj *module, 9494cd04c50SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 9505300040bSGhennadi Procopciuc unsigned int depth) 9514cd04c50SGhennadi Procopciuc { 9524cd04c50SGhennadi Procopciuc const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module); 9538ee0fc31SGhennadi Procopciuc unsigned int ldepth = depth; 9544cd04c50SGhennadi Procopciuc const struct s32cc_dfs *dfs; 9554cd04c50SGhennadi Procopciuc uintptr_t dfs_addr = 0UL; 95643b4b29fSGhennadi Procopciuc unsigned long dfs_freq; 9574cd04c50SGhennadi Procopciuc uint32_t mfi, mfn; 9584cd04c50SGhennadi Procopciuc int ret = 0; 9594cd04c50SGhennadi Procopciuc 9608ee0fc31SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 9614cd04c50SGhennadi Procopciuc if (ret != 0) { 9624cd04c50SGhennadi Procopciuc return ret; 9634cd04c50SGhennadi Procopciuc } 9644cd04c50SGhennadi Procopciuc 9654cd04c50SGhennadi Procopciuc dfs = get_div_dfs(dfs_div); 9664cd04c50SGhennadi Procopciuc if (dfs == NULL) { 9674cd04c50SGhennadi Procopciuc return -EINVAL; 9684cd04c50SGhennadi Procopciuc } 9694cd04c50SGhennadi Procopciuc 9704cd04c50SGhennadi Procopciuc ret = get_base_addr(dfs->instance, drv, &dfs_addr); 9714cd04c50SGhennadi Procopciuc if ((ret != 0) || (dfs_addr == 0UL)) { 9724cd04c50SGhennadi Procopciuc return -EINVAL; 9734cd04c50SGhennadi Procopciuc } 9744cd04c50SGhennadi Procopciuc 97543b4b29fSGhennadi Procopciuc ret = get_module_rate(&dfs->desc, drv, &dfs_freq, depth); 97643b4b29fSGhennadi Procopciuc if (ret != 0) { 97743b4b29fSGhennadi Procopciuc return ret; 97843b4b29fSGhennadi Procopciuc } 97943b4b29fSGhennadi Procopciuc 98043b4b29fSGhennadi Procopciuc ret = get_dfs_mfi_mfn(dfs_freq, dfs_div, &mfi, &mfn); 9814cd04c50SGhennadi Procopciuc if (ret != 0) { 9824cd04c50SGhennadi Procopciuc return -EINVAL; 9834cd04c50SGhennadi Procopciuc } 9844cd04c50SGhennadi Procopciuc 9854cd04c50SGhennadi Procopciuc return init_dfs_port(dfs_addr, dfs_div->index, mfi, mfn); 9864cd04c50SGhennadi Procopciuc } 9874cd04c50SGhennadi Procopciuc 9885300040bSGhennadi Procopciuc typedef int (*enable_clk_t)(struct s32cc_clk_obj *module, 9895300040bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 9905300040bSGhennadi Procopciuc unsigned int depth); 9915300040bSGhennadi Procopciuc 9928a4f840bSGhennadi Procopciuc static int enable_part(struct s32cc_clk_obj *module, 9938a4f840bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 9948a4f840bSGhennadi Procopciuc unsigned int depth) 9958a4f840bSGhennadi Procopciuc { 9968a4f840bSGhennadi Procopciuc const struct s32cc_part *part = s32cc_obj2part(module); 9978a4f840bSGhennadi Procopciuc uint32_t part_no = part->partition_id; 9988a4f840bSGhennadi Procopciuc 9998a4f840bSGhennadi Procopciuc if ((drv->mc_me == 0UL) || (drv->mc_rgm == 0UL) || (drv->rdc == 0UL)) { 10008a4f840bSGhennadi Procopciuc return -EINVAL; 10018a4f840bSGhennadi Procopciuc } 10028a4f840bSGhennadi Procopciuc 10038a4f840bSGhennadi Procopciuc return mc_me_enable_partition(drv->mc_me, drv->mc_rgm, drv->rdc, part_no); 10048a4f840bSGhennadi Procopciuc } 10058a4f840bSGhennadi Procopciuc 10068a4f840bSGhennadi Procopciuc static int enable_part_block(struct s32cc_clk_obj *module, 10078a4f840bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 10088a4f840bSGhennadi Procopciuc unsigned int depth) 10098a4f840bSGhennadi Procopciuc { 10108a4f840bSGhennadi Procopciuc const struct s32cc_part_block *block = s32cc_obj2partblock(module); 10118a4f840bSGhennadi Procopciuc const struct s32cc_part *part = block->part; 10128a4f840bSGhennadi Procopciuc uint32_t part_no = part->partition_id; 10138a4f840bSGhennadi Procopciuc unsigned int ldepth = depth; 10148a4f840bSGhennadi Procopciuc uint32_t cofb; 10158a4f840bSGhennadi Procopciuc int ret; 10168a4f840bSGhennadi Procopciuc 10178a4f840bSGhennadi Procopciuc ret = update_stack_depth(&ldepth); 10188a4f840bSGhennadi Procopciuc if (ret != 0) { 10198a4f840bSGhennadi Procopciuc return ret; 10208a4f840bSGhennadi Procopciuc } 10218a4f840bSGhennadi Procopciuc 10228a4f840bSGhennadi Procopciuc if ((block->block >= s32cc_part_block0) && 10238a4f840bSGhennadi Procopciuc (block->block <= s32cc_part_block15)) { 10248a4f840bSGhennadi Procopciuc cofb = (uint32_t)block->block - (uint32_t)s32cc_part_block0; 10258a4f840bSGhennadi Procopciuc mc_me_enable_part_cofb(drv->mc_me, part_no, cofb, block->status); 10268a4f840bSGhennadi Procopciuc } else { 10278a4f840bSGhennadi Procopciuc ERROR("Unknown partition block type: %d\n", block->block); 10288a4f840bSGhennadi Procopciuc return -EINVAL; 10298a4f840bSGhennadi Procopciuc } 10308a4f840bSGhennadi Procopciuc 10318a4f840bSGhennadi Procopciuc return 0; 10328a4f840bSGhennadi Procopciuc } 10338a4f840bSGhennadi Procopciuc 10348a4f840bSGhennadi Procopciuc static struct s32cc_clk_obj * 10358a4f840bSGhennadi Procopciuc get_part_block_parent(const struct s32cc_clk_obj *module) 10368a4f840bSGhennadi Procopciuc { 10378a4f840bSGhennadi Procopciuc const struct s32cc_part_block *block = s32cc_obj2partblock(module); 10388a4f840bSGhennadi Procopciuc 10398a4f840bSGhennadi Procopciuc return &block->part->desc; 10408a4f840bSGhennadi Procopciuc } 10418a4f840bSGhennadi Procopciuc 10428a4f840bSGhennadi Procopciuc static int enable_module_with_refcount(struct s32cc_clk_obj *module, 10438a4f840bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 10448a4f840bSGhennadi Procopciuc unsigned int depth); 10458a4f840bSGhennadi Procopciuc 10468a4f840bSGhennadi Procopciuc static int enable_part_block_link(struct s32cc_clk_obj *module, 10478a4f840bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 10488a4f840bSGhennadi Procopciuc unsigned int depth) 10498a4f840bSGhennadi Procopciuc { 10508a4f840bSGhennadi Procopciuc const struct s32cc_part_block_link *link = s32cc_obj2partblocklink(module); 10518a4f840bSGhennadi Procopciuc struct s32cc_part_block *block = link->block; 10528a4f840bSGhennadi Procopciuc unsigned int ldepth = depth; 10538a4f840bSGhennadi Procopciuc int ret; 10548a4f840bSGhennadi Procopciuc 10558a4f840bSGhennadi Procopciuc ret = update_stack_depth(&ldepth); 10568a4f840bSGhennadi Procopciuc if (ret != 0) { 10578a4f840bSGhennadi Procopciuc return ret; 10588a4f840bSGhennadi Procopciuc } 10598a4f840bSGhennadi Procopciuc 10608a4f840bSGhennadi Procopciuc /* Move the enablement algorithm to partition tree */ 10618a4f840bSGhennadi Procopciuc return enable_module_with_refcount(&block->desc, drv, ldepth); 10628a4f840bSGhennadi Procopciuc } 10638a4f840bSGhennadi Procopciuc 10648a4f840bSGhennadi Procopciuc static struct s32cc_clk_obj * 10658a4f840bSGhennadi Procopciuc get_part_block_link_parent(const struct s32cc_clk_obj *module) 10668a4f840bSGhennadi Procopciuc { 10678a4f840bSGhennadi Procopciuc const struct s32cc_part_block_link *link = s32cc_obj2partblocklink(module); 10688a4f840bSGhennadi Procopciuc 10698a4f840bSGhennadi Procopciuc return link->parent; 10708a4f840bSGhennadi Procopciuc } 10718a4f840bSGhennadi Procopciuc 1072a74cf75fSGhennadi Procopciuc static int get_part_block_link_freq(const struct s32cc_clk_obj *module, 1073a74cf75fSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 1074a74cf75fSGhennadi Procopciuc unsigned long *rate, unsigned int depth) 1075a74cf75fSGhennadi Procopciuc { 1076a74cf75fSGhennadi Procopciuc const struct s32cc_part_block_link *block = s32cc_obj2partblocklink(module); 1077a74cf75fSGhennadi Procopciuc unsigned int ldepth = depth; 1078a74cf75fSGhennadi Procopciuc int ret; 1079a74cf75fSGhennadi Procopciuc 1080a74cf75fSGhennadi Procopciuc ret = update_stack_depth(&ldepth); 1081a74cf75fSGhennadi Procopciuc if (ret != 0) { 1082a74cf75fSGhennadi Procopciuc return ret; 1083a74cf75fSGhennadi Procopciuc } 1084a74cf75fSGhennadi Procopciuc 1085a74cf75fSGhennadi Procopciuc return get_module_rate(block->parent, drv, rate, ldepth); 1086a74cf75fSGhennadi Procopciuc } 1087a74cf75fSGhennadi Procopciuc 10885300040bSGhennadi Procopciuc static int no_enable(struct s32cc_clk_obj *module, 10895300040bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 10905300040bSGhennadi Procopciuc unsigned int depth) 10918ab34357SGhennadi Procopciuc { 10925300040bSGhennadi Procopciuc return 0; 10935300040bSGhennadi Procopciuc } 10945300040bSGhennadi Procopciuc 10955300040bSGhennadi Procopciuc static int exec_cb_with_refcount(enable_clk_t en_cb, struct s32cc_clk_obj *mod, 10965300040bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, bool leaf_node, 10975300040bSGhennadi Procopciuc unsigned int depth) 10985300040bSGhennadi Procopciuc { 10998ee0fc31SGhennadi Procopciuc unsigned int ldepth = depth; 11008ab34357SGhennadi Procopciuc int ret = 0; 11018ab34357SGhennadi Procopciuc 11025300040bSGhennadi Procopciuc if (mod == NULL) { 11035300040bSGhennadi Procopciuc return 0; 11045300040bSGhennadi Procopciuc } 11055300040bSGhennadi Procopciuc 11068ee0fc31SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 11075300040bSGhennadi Procopciuc if (ret != 0) { 11085300040bSGhennadi Procopciuc return ret; 11095300040bSGhennadi Procopciuc } 11105300040bSGhennadi Procopciuc 11115300040bSGhennadi Procopciuc /* Refcount will be updated as part of the recursivity */ 11125300040bSGhennadi Procopciuc if (leaf_node) { 11138ee0fc31SGhennadi Procopciuc return en_cb(mod, drv, ldepth); 11145300040bSGhennadi Procopciuc } 11155300040bSGhennadi Procopciuc 11165300040bSGhennadi Procopciuc if (mod->refcount == 0U) { 11178ee0fc31SGhennadi Procopciuc ret = en_cb(mod, drv, ldepth); 11185300040bSGhennadi Procopciuc } 11195300040bSGhennadi Procopciuc 11205300040bSGhennadi Procopciuc if (ret == 0) { 11215300040bSGhennadi Procopciuc mod->refcount++; 11225300040bSGhennadi Procopciuc } 11235300040bSGhennadi Procopciuc 11245300040bSGhennadi Procopciuc return ret; 11255300040bSGhennadi Procopciuc } 11265300040bSGhennadi Procopciuc 11275300040bSGhennadi Procopciuc static struct s32cc_clk_obj *get_module_parent(const struct s32cc_clk_obj *module); 11285300040bSGhennadi Procopciuc 11295300040bSGhennadi Procopciuc static int enable_module(struct s32cc_clk_obj *module, 11305300040bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 11315300040bSGhennadi Procopciuc unsigned int depth) 11325300040bSGhennadi Procopciuc { 11335300040bSGhennadi Procopciuc struct s32cc_clk_obj *parent = get_module_parent(module); 11348a4f840bSGhennadi Procopciuc static const enable_clk_t enable_clbs[12] = { 11355300040bSGhennadi Procopciuc [s32cc_clk_t] = no_enable, 11365300040bSGhennadi Procopciuc [s32cc_osc_t] = enable_osc, 11375300040bSGhennadi Procopciuc [s32cc_pll_t] = enable_pll, 11385300040bSGhennadi Procopciuc [s32cc_pll_out_div_t] = enable_pll_div, 11395300040bSGhennadi Procopciuc [s32cc_clkmux_t] = enable_mux, 11405300040bSGhennadi Procopciuc [s32cc_shared_clkmux_t] = enable_mux, 11415300040bSGhennadi Procopciuc [s32cc_dfs_t] = enable_dfs, 11425300040bSGhennadi Procopciuc [s32cc_dfs_div_t] = enable_dfs_div, 11438a4f840bSGhennadi Procopciuc [s32cc_part_t] = enable_part, 11448a4f840bSGhennadi Procopciuc [s32cc_part_block_t] = enable_part_block, 11458a4f840bSGhennadi Procopciuc [s32cc_part_block_link_t] = enable_part_block_link, 11465300040bSGhennadi Procopciuc }; 11478ee0fc31SGhennadi Procopciuc unsigned int ldepth = depth; 11485300040bSGhennadi Procopciuc uint32_t index; 11495300040bSGhennadi Procopciuc int ret = 0; 11505300040bSGhennadi Procopciuc 11518ee0fc31SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 11528ab34357SGhennadi Procopciuc if (ret != 0) { 11538ab34357SGhennadi Procopciuc return ret; 11548ab34357SGhennadi Procopciuc } 11558ab34357SGhennadi Procopciuc 11568ab34357SGhennadi Procopciuc if (drv == NULL) { 11578ab34357SGhennadi Procopciuc return -EINVAL; 11588ab34357SGhennadi Procopciuc } 11598ab34357SGhennadi Procopciuc 11605300040bSGhennadi Procopciuc index = (uint32_t)module->type; 11615300040bSGhennadi Procopciuc 11625300040bSGhennadi Procopciuc if (index >= ARRAY_SIZE(enable_clbs)) { 11635300040bSGhennadi Procopciuc ERROR("Undefined module type: %d\n", module->type); 11645300040bSGhennadi Procopciuc return -EINVAL; 11655300040bSGhennadi Procopciuc } 11665300040bSGhennadi Procopciuc 11675300040bSGhennadi Procopciuc if (enable_clbs[index] == NULL) { 11685300040bSGhennadi Procopciuc ERROR("Undefined callback for the clock type: %d\n", 11695300040bSGhennadi Procopciuc module->type); 11705300040bSGhennadi Procopciuc return -EINVAL; 11715300040bSGhennadi Procopciuc } 11725300040bSGhennadi Procopciuc 11735300040bSGhennadi Procopciuc parent = get_module_parent(module); 11745300040bSGhennadi Procopciuc 11755300040bSGhennadi Procopciuc ret = exec_cb_with_refcount(enable_module, parent, drv, 11768ee0fc31SGhennadi Procopciuc false, ldepth); 11775300040bSGhennadi Procopciuc if (ret != 0) { 11785300040bSGhennadi Procopciuc return ret; 11795300040bSGhennadi Procopciuc } 11805300040bSGhennadi Procopciuc 11815300040bSGhennadi Procopciuc ret = exec_cb_with_refcount(enable_clbs[index], module, drv, 11828ee0fc31SGhennadi Procopciuc true, ldepth); 11835300040bSGhennadi Procopciuc if (ret != 0) { 11845300040bSGhennadi Procopciuc return ret; 11858ab34357SGhennadi Procopciuc } 11868ab34357SGhennadi Procopciuc 11878ab34357SGhennadi Procopciuc return ret; 11888ab34357SGhennadi Procopciuc } 11898ab34357SGhennadi Procopciuc 11905300040bSGhennadi Procopciuc static int enable_module_with_refcount(struct s32cc_clk_obj *module, 11915300040bSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 11925300040bSGhennadi Procopciuc unsigned int depth) 11935300040bSGhennadi Procopciuc { 11945300040bSGhennadi Procopciuc return exec_cb_with_refcount(enable_module, module, drv, false, depth); 11955300040bSGhennadi Procopciuc } 11965300040bSGhennadi Procopciuc 11973a580e9eSGhennadi Procopciuc static int s32cc_clk_enable(unsigned long id) 11983a580e9eSGhennadi Procopciuc { 11995300040bSGhennadi Procopciuc const struct s32cc_clk_drv *drv = get_drv(); 12008ab34357SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 12015300040bSGhennadi Procopciuc struct s32cc_clk *clk; 12028ab34357SGhennadi Procopciuc 12038ab34357SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 12048ab34357SGhennadi Procopciuc if (clk == NULL) { 12058ab34357SGhennadi Procopciuc return -EINVAL; 12068ab34357SGhennadi Procopciuc } 12078ab34357SGhennadi Procopciuc 12085300040bSGhennadi Procopciuc return enable_module_with_refcount(&clk->desc, drv, depth); 12093a580e9eSGhennadi Procopciuc } 12103a580e9eSGhennadi Procopciuc 12113a580e9eSGhennadi Procopciuc static void s32cc_clk_disable(unsigned long id) 12123a580e9eSGhennadi Procopciuc { 12133a580e9eSGhennadi Procopciuc } 12143a580e9eSGhennadi Procopciuc 12153a580e9eSGhennadi Procopciuc static bool s32cc_clk_is_enabled(unsigned long id) 12163a580e9eSGhennadi Procopciuc { 12173a580e9eSGhennadi Procopciuc return false; 12183a580e9eSGhennadi Procopciuc } 12193a580e9eSGhennadi Procopciuc 1220d9373519SGhennadi Procopciuc static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate, 1221d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 1222d9373519SGhennadi Procopciuc { 1223d9373519SGhennadi Procopciuc struct s32cc_osc *osc = s32cc_obj2osc(module); 1224d9373519SGhennadi Procopciuc int ret; 1225d9373519SGhennadi Procopciuc 1226d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 1227d9373519SGhennadi Procopciuc if (ret != 0) { 1228d9373519SGhennadi Procopciuc return ret; 1229d9373519SGhennadi Procopciuc } 1230d9373519SGhennadi Procopciuc 1231d9373519SGhennadi Procopciuc if ((osc->freq != 0UL) && (rate != osc->freq)) { 1232d9373519SGhennadi Procopciuc ERROR("Already initialized oscillator. freq = %lu\n", 1233d9373519SGhennadi Procopciuc osc->freq); 1234d9373519SGhennadi Procopciuc return -EINVAL; 1235d9373519SGhennadi Procopciuc } 1236d9373519SGhennadi Procopciuc 1237d9373519SGhennadi Procopciuc osc->freq = rate; 1238d9373519SGhennadi Procopciuc *orate = osc->freq; 1239d9373519SGhennadi Procopciuc 1240d9373519SGhennadi Procopciuc return 0; 1241d9373519SGhennadi Procopciuc } 1242d9373519SGhennadi Procopciuc 1243bd691136SGhennadi Procopciuc static int get_osc_freq(const struct s32cc_clk_obj *module, 1244bd691136SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 1245bd691136SGhennadi Procopciuc unsigned long *rate, unsigned int depth) 1246bd691136SGhennadi Procopciuc { 1247bd691136SGhennadi Procopciuc const struct s32cc_osc *osc = s32cc_obj2osc(module); 1248bd691136SGhennadi Procopciuc unsigned int ldepth = depth; 1249bd691136SGhennadi Procopciuc int ret; 1250bd691136SGhennadi Procopciuc 1251bd691136SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 1252bd691136SGhennadi Procopciuc if (ret != 0) { 1253bd691136SGhennadi Procopciuc return ret; 1254bd691136SGhennadi Procopciuc } 1255bd691136SGhennadi Procopciuc 1256bd691136SGhennadi Procopciuc if (osc->freq == 0UL) { 1257bd691136SGhennadi Procopciuc ERROR("Uninitialized oscillator\n"); 1258bd691136SGhennadi Procopciuc return -EINVAL; 1259bd691136SGhennadi Procopciuc } 1260bd691136SGhennadi Procopciuc 1261bd691136SGhennadi Procopciuc *rate = osc->freq; 1262bd691136SGhennadi Procopciuc 1263bd691136SGhennadi Procopciuc return 0; 1264bd691136SGhennadi Procopciuc } 1265bd691136SGhennadi Procopciuc 1266d9373519SGhennadi Procopciuc static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate, 1267d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 1268d9373519SGhennadi Procopciuc { 1269d9373519SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 1270d9373519SGhennadi Procopciuc int ret; 1271d9373519SGhennadi Procopciuc 1272d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 1273d9373519SGhennadi Procopciuc if (ret != 0) { 1274d9373519SGhennadi Procopciuc return ret; 1275d9373519SGhennadi Procopciuc } 1276d9373519SGhennadi Procopciuc 1277d9373519SGhennadi Procopciuc if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) && 1278d9373519SGhennadi Procopciuc ((rate < clk->min_freq) || (rate > clk->max_freq))) { 1279d9373519SGhennadi Procopciuc ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n", 1280d9373519SGhennadi Procopciuc rate, clk->min_freq, clk->max_freq); 1281d9373519SGhennadi Procopciuc return -EINVAL; 1282d9373519SGhennadi Procopciuc } 1283d9373519SGhennadi Procopciuc 1284d9373519SGhennadi Procopciuc if (clk->module != NULL) { 1285d9373519SGhennadi Procopciuc return set_module_rate(clk->module, rate, orate, depth); 1286d9373519SGhennadi Procopciuc } 1287d9373519SGhennadi Procopciuc 1288d9373519SGhennadi Procopciuc if (clk->pclock != NULL) { 1289d9373519SGhennadi Procopciuc return set_clk_freq(&clk->pclock->desc, rate, orate, depth); 1290d9373519SGhennadi Procopciuc } 1291d9373519SGhennadi Procopciuc 1292d9373519SGhennadi Procopciuc return -EINVAL; 1293d9373519SGhennadi Procopciuc } 1294d9373519SGhennadi Procopciuc 129546de0b9cSGhennadi Procopciuc static int get_clk_freq(const struct s32cc_clk_obj *module, 129646de0b9cSGhennadi Procopciuc const struct s32cc_clk_drv *drv, unsigned long *rate, 129746de0b9cSGhennadi Procopciuc unsigned int depth) 129846de0b9cSGhennadi Procopciuc { 129946de0b9cSGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 130046de0b9cSGhennadi Procopciuc unsigned int ldepth = depth; 130146de0b9cSGhennadi Procopciuc int ret; 130246de0b9cSGhennadi Procopciuc 130346de0b9cSGhennadi Procopciuc ret = update_stack_depth(&ldepth); 130446de0b9cSGhennadi Procopciuc if (ret != 0) { 130546de0b9cSGhennadi Procopciuc return ret; 130646de0b9cSGhennadi Procopciuc } 130746de0b9cSGhennadi Procopciuc 130846de0b9cSGhennadi Procopciuc if (clk == NULL) { 130946de0b9cSGhennadi Procopciuc ERROR("Invalid clock\n"); 131046de0b9cSGhennadi Procopciuc return -EINVAL; 131146de0b9cSGhennadi Procopciuc } 131246de0b9cSGhennadi Procopciuc 131346de0b9cSGhennadi Procopciuc if (clk->module != NULL) { 131446de0b9cSGhennadi Procopciuc return get_module_rate(clk->module, drv, rate, ldepth); 131546de0b9cSGhennadi Procopciuc } 131646de0b9cSGhennadi Procopciuc 131746de0b9cSGhennadi Procopciuc if (clk->pclock == NULL) { 131846de0b9cSGhennadi Procopciuc ERROR("Invalid clock parent\n"); 131946de0b9cSGhennadi Procopciuc return -EINVAL; 132046de0b9cSGhennadi Procopciuc } 132146de0b9cSGhennadi Procopciuc 132246de0b9cSGhennadi Procopciuc return get_clk_freq(&clk->pclock->desc, drv, rate, ldepth); 132346de0b9cSGhennadi Procopciuc } 132446de0b9cSGhennadi Procopciuc 13257ad4e231SGhennadi Procopciuc static int set_pll_freq(const struct s32cc_clk_obj *module, unsigned long rate, 13267ad4e231SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 13277ad4e231SGhennadi Procopciuc { 13287ad4e231SGhennadi Procopciuc struct s32cc_pll *pll = s32cc_obj2pll(module); 13297ad4e231SGhennadi Procopciuc int ret; 13307ad4e231SGhennadi Procopciuc 13317ad4e231SGhennadi Procopciuc ret = update_stack_depth(depth); 13327ad4e231SGhennadi Procopciuc if (ret != 0) { 13337ad4e231SGhennadi Procopciuc return ret; 13347ad4e231SGhennadi Procopciuc } 13357ad4e231SGhennadi Procopciuc 13367ad4e231SGhennadi Procopciuc if ((pll->vco_freq != 0UL) && (pll->vco_freq != rate)) { 13377ad4e231SGhennadi Procopciuc ERROR("PLL frequency was already set\n"); 13387ad4e231SGhennadi Procopciuc return -EINVAL; 13397ad4e231SGhennadi Procopciuc } 13407ad4e231SGhennadi Procopciuc 13417ad4e231SGhennadi Procopciuc pll->vco_freq = rate; 13427ad4e231SGhennadi Procopciuc *orate = pll->vco_freq; 13437ad4e231SGhennadi Procopciuc 13447ad4e231SGhennadi Procopciuc return 0; 13457ad4e231SGhennadi Procopciuc } 13467ad4e231SGhennadi Procopciuc 1347fbebafa5SGhennadi Procopciuc static int get_pll_freq(const struct s32cc_clk_obj *module, 1348fbebafa5SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 1349fbebafa5SGhennadi Procopciuc unsigned long *rate, unsigned int depth) 1350fbebafa5SGhennadi Procopciuc { 1351fbebafa5SGhennadi Procopciuc const struct s32cc_pll *pll = s32cc_obj2pll(module); 1352fbebafa5SGhennadi Procopciuc const struct s32cc_clk *source; 1353fbebafa5SGhennadi Procopciuc uint32_t mfi, mfn, rdiv, plldv; 1354fbebafa5SGhennadi Procopciuc unsigned long prate, clk_src; 1355fbebafa5SGhennadi Procopciuc unsigned int ldepth = depth; 1356fbebafa5SGhennadi Procopciuc uintptr_t pll_addr = 0UL; 1357fbebafa5SGhennadi Procopciuc uint64_t t1, t2; 1358fbebafa5SGhennadi Procopciuc int ret; 1359fbebafa5SGhennadi Procopciuc 1360fbebafa5SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 1361fbebafa5SGhennadi Procopciuc if (ret != 0) { 1362fbebafa5SGhennadi Procopciuc return ret; 1363fbebafa5SGhennadi Procopciuc } 1364fbebafa5SGhennadi Procopciuc 1365fbebafa5SGhennadi Procopciuc ret = get_base_addr(pll->instance, drv, &pll_addr); 1366fbebafa5SGhennadi Procopciuc if (ret != 0) { 1367fbebafa5SGhennadi Procopciuc ERROR("Failed to detect PLL instance\n"); 1368fbebafa5SGhennadi Procopciuc return ret; 1369fbebafa5SGhennadi Procopciuc } 1370fbebafa5SGhennadi Procopciuc 1371fbebafa5SGhennadi Procopciuc /* Disabled PLL */ 1372*c23dde6cSGhennadi Procopciuc if (!is_pll_enabled(pll_addr)) { 1373fbebafa5SGhennadi Procopciuc *rate = pll->vco_freq; 1374fbebafa5SGhennadi Procopciuc return 0; 1375fbebafa5SGhennadi Procopciuc } 1376fbebafa5SGhennadi Procopciuc 1377fbebafa5SGhennadi Procopciuc clk_src = mmio_read_32(PLLDIG_PLLCLKMUX(pll_addr)); 1378fbebafa5SGhennadi Procopciuc switch (clk_src) { 1379fbebafa5SGhennadi Procopciuc case 0: 1380fbebafa5SGhennadi Procopciuc clk_src = S32CC_CLK_FIRC; 1381fbebafa5SGhennadi Procopciuc break; 1382fbebafa5SGhennadi Procopciuc case 1: 1383fbebafa5SGhennadi Procopciuc clk_src = S32CC_CLK_FXOSC; 1384fbebafa5SGhennadi Procopciuc break; 1385fbebafa5SGhennadi Procopciuc default: 1386fbebafa5SGhennadi Procopciuc ERROR("Failed to identify PLL source id %" PRIu64 "\n", clk_src); 1387fbebafa5SGhennadi Procopciuc return -EINVAL; 1388fbebafa5SGhennadi Procopciuc }; 1389fbebafa5SGhennadi Procopciuc 1390fbebafa5SGhennadi Procopciuc source = s32cc_get_arch_clk(clk_src); 1391fbebafa5SGhennadi Procopciuc if (source == NULL) { 1392fbebafa5SGhennadi Procopciuc ERROR("Failed to get PLL source clock\n"); 1393fbebafa5SGhennadi Procopciuc return -EINVAL; 1394fbebafa5SGhennadi Procopciuc } 1395fbebafa5SGhennadi Procopciuc 1396fbebafa5SGhennadi Procopciuc ret = get_module_rate(&source->desc, drv, &prate, ldepth); 1397fbebafa5SGhennadi Procopciuc if (ret != 0) { 1398fbebafa5SGhennadi Procopciuc ERROR("Failed to get PLL's parent frequency\n"); 1399fbebafa5SGhennadi Procopciuc return ret; 1400fbebafa5SGhennadi Procopciuc } 1401fbebafa5SGhennadi Procopciuc 1402fbebafa5SGhennadi Procopciuc plldv = mmio_read_32(PLLDIG_PLLDV(pll_addr)); 1403fbebafa5SGhennadi Procopciuc mfi = PLLDIG_PLLDV_MFI(plldv); 1404fbebafa5SGhennadi Procopciuc rdiv = PLLDIG_PLLDV_RDIV(plldv); 1405fbebafa5SGhennadi Procopciuc if (rdiv == 0U) { 1406fbebafa5SGhennadi Procopciuc rdiv = 1; 1407fbebafa5SGhennadi Procopciuc } 1408fbebafa5SGhennadi Procopciuc 1409fbebafa5SGhennadi Procopciuc /* Frac-N mode */ 1410fbebafa5SGhennadi Procopciuc mfn = PLLDIG_PLLFD_MFN_SET(mmio_read_32(PLLDIG_PLLFD(pll_addr))); 1411fbebafa5SGhennadi Procopciuc 1412fbebafa5SGhennadi Procopciuc /* PLL VCO frequency in Fractional mode when PLLDV[RDIV] is not 0 */ 1413fbebafa5SGhennadi Procopciuc t1 = prate / rdiv; 1414fbebafa5SGhennadi Procopciuc t2 = (mfi * FP_PRECISION) + (mfn * FP_PRECISION / 18432U); 1415fbebafa5SGhennadi Procopciuc 1416fbebafa5SGhennadi Procopciuc *rate = t1 * t2 / FP_PRECISION; 1417fbebafa5SGhennadi Procopciuc 1418fbebafa5SGhennadi Procopciuc return 0; 1419fbebafa5SGhennadi Procopciuc } 1420fbebafa5SGhennadi Procopciuc 1421de950ef0SGhennadi Procopciuc static int set_pll_div_freq(const struct s32cc_clk_obj *module, unsigned long rate, 1422de950ef0SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 1423de950ef0SGhennadi Procopciuc { 1424de950ef0SGhennadi Procopciuc struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module); 1425de950ef0SGhennadi Procopciuc const struct s32cc_pll *pll; 1426de950ef0SGhennadi Procopciuc unsigned long prate, dc; 1427de950ef0SGhennadi Procopciuc int ret; 1428de950ef0SGhennadi Procopciuc 1429de950ef0SGhennadi Procopciuc ret = update_stack_depth(depth); 1430de950ef0SGhennadi Procopciuc if (ret != 0) { 1431de950ef0SGhennadi Procopciuc return ret; 1432de950ef0SGhennadi Procopciuc } 1433de950ef0SGhennadi Procopciuc 1434de950ef0SGhennadi Procopciuc if (pdiv->parent == NULL) { 1435de950ef0SGhennadi Procopciuc ERROR("Failed to identify PLL divider's parent\n"); 1436de950ef0SGhennadi Procopciuc return -EINVAL; 1437de950ef0SGhennadi Procopciuc } 1438de950ef0SGhennadi Procopciuc 1439de950ef0SGhennadi Procopciuc pll = s32cc_obj2pll(pdiv->parent); 1440de950ef0SGhennadi Procopciuc if (pll == NULL) { 1441de950ef0SGhennadi Procopciuc ERROR("The parent of the PLL DIV is invalid\n"); 1442de950ef0SGhennadi Procopciuc return -EINVAL; 1443de950ef0SGhennadi Procopciuc } 1444de950ef0SGhennadi Procopciuc 1445de950ef0SGhennadi Procopciuc prate = pll->vco_freq; 1446de950ef0SGhennadi Procopciuc 1447de950ef0SGhennadi Procopciuc /** 1448de950ef0SGhennadi Procopciuc * The PLL is not initialized yet, so let's take a risk 1449de950ef0SGhennadi Procopciuc * and accept the proposed rate. 1450de950ef0SGhennadi Procopciuc */ 1451de950ef0SGhennadi Procopciuc if (prate == 0UL) { 1452de950ef0SGhennadi Procopciuc pdiv->freq = rate; 1453de950ef0SGhennadi Procopciuc *orate = rate; 1454de950ef0SGhennadi Procopciuc return 0; 1455de950ef0SGhennadi Procopciuc } 1456de950ef0SGhennadi Procopciuc 1457de950ef0SGhennadi Procopciuc /* Decline in case the rate cannot fit PLL's requirements. */ 1458de950ef0SGhennadi Procopciuc dc = prate / rate; 1459de950ef0SGhennadi Procopciuc if ((prate / dc) != rate) { 1460de950ef0SGhennadi Procopciuc return -EINVAL; 1461de950ef0SGhennadi Procopciuc } 1462de950ef0SGhennadi Procopciuc 1463de950ef0SGhennadi Procopciuc pdiv->freq = rate; 1464de950ef0SGhennadi Procopciuc *orate = pdiv->freq; 1465de950ef0SGhennadi Procopciuc 1466de950ef0SGhennadi Procopciuc return 0; 1467de950ef0SGhennadi Procopciuc } 1468de950ef0SGhennadi Procopciuc 1469a762c505SGhennadi Procopciuc static int get_pll_div_freq(const struct s32cc_clk_obj *module, 1470a762c505SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 1471a762c505SGhennadi Procopciuc unsigned long *rate, unsigned int depth) 1472a762c505SGhennadi Procopciuc { 1473a762c505SGhennadi Procopciuc const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module); 1474a762c505SGhennadi Procopciuc const struct s32cc_pll *pll; 1475a762c505SGhennadi Procopciuc unsigned int ldepth = depth; 1476a762c505SGhennadi Procopciuc uintptr_t pll_addr = 0UL; 1477a762c505SGhennadi Procopciuc unsigned long pfreq; 1478a762c505SGhennadi Procopciuc uint32_t pllodiv; 1479a762c505SGhennadi Procopciuc uint32_t dc; 1480a762c505SGhennadi Procopciuc int ret; 1481a762c505SGhennadi Procopciuc 1482a762c505SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 1483a762c505SGhennadi Procopciuc if (ret != 0) { 1484a762c505SGhennadi Procopciuc return ret; 1485a762c505SGhennadi Procopciuc } 1486a762c505SGhennadi Procopciuc 1487a762c505SGhennadi Procopciuc pll = get_div_pll(pdiv); 1488a762c505SGhennadi Procopciuc if (pll == NULL) { 1489a762c505SGhennadi Procopciuc ERROR("The parent of the PLL DIV is invalid\n"); 1490a762c505SGhennadi Procopciuc return -EINVAL; 1491a762c505SGhennadi Procopciuc } 1492a762c505SGhennadi Procopciuc 1493a762c505SGhennadi Procopciuc ret = get_base_addr(pll->instance, drv, &pll_addr); 1494a762c505SGhennadi Procopciuc if (ret != 0) { 1495a762c505SGhennadi Procopciuc ERROR("Failed to detect PLL instance\n"); 1496a762c505SGhennadi Procopciuc return -EINVAL; 1497a762c505SGhennadi Procopciuc } 1498a762c505SGhennadi Procopciuc 1499a762c505SGhennadi Procopciuc ret = get_module_rate(pdiv->parent, drv, &pfreq, ldepth); 1500a762c505SGhennadi Procopciuc if (ret != 0) { 1501a762c505SGhennadi Procopciuc ERROR("Failed to get the frequency of PLL %" PRIxPTR "\n", 1502a762c505SGhennadi Procopciuc pll_addr); 1503a762c505SGhennadi Procopciuc return ret; 1504a762c505SGhennadi Procopciuc } 1505a762c505SGhennadi Procopciuc 1506a762c505SGhennadi Procopciuc pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, pdiv->index)); 1507a762c505SGhennadi Procopciuc 1508a762c505SGhennadi Procopciuc /* Disabled module */ 1509a762c505SGhennadi Procopciuc if ((pllodiv & PLLDIG_PLLODIV_DE) == 0U) { 1510a762c505SGhennadi Procopciuc *rate = pdiv->freq; 1511a762c505SGhennadi Procopciuc return 0; 1512a762c505SGhennadi Procopciuc } 1513a762c505SGhennadi Procopciuc 1514a762c505SGhennadi Procopciuc dc = PLLDIG_PLLODIV_DIV(pllodiv); 1515a762c505SGhennadi Procopciuc *rate = (pfreq * FP_PRECISION) / (dc + 1U) / FP_PRECISION; 1516a762c505SGhennadi Procopciuc 1517a762c505SGhennadi Procopciuc return 0; 1518a762c505SGhennadi Procopciuc } 1519a762c505SGhennadi Procopciuc 152065739db2SGhennadi Procopciuc static int set_fixed_div_freq(const struct s32cc_clk_obj *module, unsigned long rate, 152165739db2SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 152265739db2SGhennadi Procopciuc { 152365739db2SGhennadi Procopciuc const struct s32cc_fixed_div *fdiv = s32cc_obj2fixeddiv(module); 152465739db2SGhennadi Procopciuc int ret; 152565739db2SGhennadi Procopciuc 152665739db2SGhennadi Procopciuc ret = update_stack_depth(depth); 152765739db2SGhennadi Procopciuc if (ret != 0) { 152865739db2SGhennadi Procopciuc return ret; 152965739db2SGhennadi Procopciuc } 153065739db2SGhennadi Procopciuc 153165739db2SGhennadi Procopciuc if (fdiv->parent == NULL) { 153265739db2SGhennadi Procopciuc ERROR("The divider doesn't have a valid parent\b"); 153365739db2SGhennadi Procopciuc return -EINVAL; 153465739db2SGhennadi Procopciuc } 153565739db2SGhennadi Procopciuc 153665739db2SGhennadi Procopciuc ret = set_module_rate(fdiv->parent, rate * fdiv->rate_div, orate, depth); 153765739db2SGhennadi Procopciuc 153865739db2SGhennadi Procopciuc /* Update the output rate based on the parent's rate */ 153965739db2SGhennadi Procopciuc *orate /= fdiv->rate_div; 154065739db2SGhennadi Procopciuc 154165739db2SGhennadi Procopciuc return ret; 154265739db2SGhennadi Procopciuc } 154365739db2SGhennadi Procopciuc 15447c298ebcSGhennadi Procopciuc static int get_fixed_div_freq(const struct s32cc_clk_obj *module, 15457c298ebcSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 15467c298ebcSGhennadi Procopciuc unsigned long *rate, unsigned int depth) 15477c298ebcSGhennadi Procopciuc { 15487c298ebcSGhennadi Procopciuc const struct s32cc_fixed_div *fdiv = s32cc_obj2fixeddiv(module); 15497c298ebcSGhennadi Procopciuc unsigned long pfreq; 15507c298ebcSGhennadi Procopciuc int ret; 15517c298ebcSGhennadi Procopciuc 15527c298ebcSGhennadi Procopciuc ret = get_module_rate(fdiv->parent, drv, &pfreq, depth); 15537c298ebcSGhennadi Procopciuc if (ret != 0) { 15547c298ebcSGhennadi Procopciuc return ret; 15557c298ebcSGhennadi Procopciuc } 15567c298ebcSGhennadi Procopciuc 15577c298ebcSGhennadi Procopciuc *rate = (pfreq * FP_PRECISION / fdiv->rate_div) / FP_PRECISION; 15587c298ebcSGhennadi Procopciuc return 0; 15597c298ebcSGhennadi Procopciuc } 15607c298ebcSGhennadi Procopciuc 156164e0c226SGhennadi Procopciuc static int set_mux_freq(const struct s32cc_clk_obj *module, unsigned long rate, 156264e0c226SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 156364e0c226SGhennadi Procopciuc { 156464e0c226SGhennadi Procopciuc const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module); 156564e0c226SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_get_arch_clk(mux->source_id); 156664e0c226SGhennadi Procopciuc int ret; 156764e0c226SGhennadi Procopciuc 156864e0c226SGhennadi Procopciuc ret = update_stack_depth(depth); 156964e0c226SGhennadi Procopciuc if (ret != 0) { 157064e0c226SGhennadi Procopciuc return ret; 157164e0c226SGhennadi Procopciuc } 157264e0c226SGhennadi Procopciuc 157364e0c226SGhennadi Procopciuc if (clk == NULL) { 157464e0c226SGhennadi Procopciuc ERROR("Mux (id:%" PRIu8 ") without a valid source (%lu)\n", 157564e0c226SGhennadi Procopciuc mux->index, mux->source_id); 157664e0c226SGhennadi Procopciuc return -EINVAL; 157764e0c226SGhennadi Procopciuc } 157864e0c226SGhennadi Procopciuc 157964e0c226SGhennadi Procopciuc return set_module_rate(&clk->desc, rate, orate, depth); 158064e0c226SGhennadi Procopciuc } 158164e0c226SGhennadi Procopciuc 1582d1567da6SGhennadi Procopciuc static int get_mux_freq(const struct s32cc_clk_obj *module, 1583d1567da6SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 1584d1567da6SGhennadi Procopciuc unsigned long *rate, unsigned int depth) 1585d1567da6SGhennadi Procopciuc { 1586d1567da6SGhennadi Procopciuc const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module); 1587d1567da6SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_get_arch_clk(mux->source_id); 1588d1567da6SGhennadi Procopciuc unsigned int ldepth = depth; 1589d1567da6SGhennadi Procopciuc int ret; 1590d1567da6SGhennadi Procopciuc 1591d1567da6SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 1592d1567da6SGhennadi Procopciuc if (ret != 0) { 1593d1567da6SGhennadi Procopciuc return ret; 1594d1567da6SGhennadi Procopciuc } 1595d1567da6SGhennadi Procopciuc 1596d1567da6SGhennadi Procopciuc if (clk == NULL) { 1597d1567da6SGhennadi Procopciuc ERROR("Mux (id:%" PRIu8 ") without a valid source (%lu)\n", 1598d1567da6SGhennadi Procopciuc mux->index, mux->source_id); 1599d1567da6SGhennadi Procopciuc return -EINVAL; 1600d1567da6SGhennadi Procopciuc } 1601d1567da6SGhennadi Procopciuc 1602d1567da6SGhennadi Procopciuc return get_clk_freq(&clk->desc, drv, rate, ldepth); 1603d1567da6SGhennadi Procopciuc } 1604d1567da6SGhennadi Procopciuc 16054cd04c50SGhennadi Procopciuc static int set_dfs_div_freq(const struct s32cc_clk_obj *module, unsigned long rate, 16064cd04c50SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 16074cd04c50SGhennadi Procopciuc { 16084cd04c50SGhennadi Procopciuc struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module); 16094cd04c50SGhennadi Procopciuc const struct s32cc_dfs *dfs; 16104cd04c50SGhennadi Procopciuc int ret; 16114cd04c50SGhennadi Procopciuc 16124cd04c50SGhennadi Procopciuc ret = update_stack_depth(depth); 16134cd04c50SGhennadi Procopciuc if (ret != 0) { 16144cd04c50SGhennadi Procopciuc return ret; 16154cd04c50SGhennadi Procopciuc } 16164cd04c50SGhennadi Procopciuc 16174cd04c50SGhennadi Procopciuc if (dfs_div->parent == NULL) { 16184cd04c50SGhennadi Procopciuc ERROR("Failed to identify DFS divider's parent\n"); 16194cd04c50SGhennadi Procopciuc return -EINVAL; 16204cd04c50SGhennadi Procopciuc } 16214cd04c50SGhennadi Procopciuc 16224cd04c50SGhennadi Procopciuc /* Sanity check */ 16234cd04c50SGhennadi Procopciuc dfs = s32cc_obj2dfs(dfs_div->parent); 16244cd04c50SGhennadi Procopciuc if (dfs->parent == NULL) { 16254cd04c50SGhennadi Procopciuc ERROR("Failed to identify DFS's parent\n"); 16264cd04c50SGhennadi Procopciuc return -EINVAL; 16274cd04c50SGhennadi Procopciuc } 16284cd04c50SGhennadi Procopciuc 16294cd04c50SGhennadi Procopciuc if ((dfs_div->freq != 0U) && (dfs_div->freq != rate)) { 16304cd04c50SGhennadi Procopciuc ERROR("DFS DIV frequency was already set to %lu\n", 16314cd04c50SGhennadi Procopciuc dfs_div->freq); 16324cd04c50SGhennadi Procopciuc return -EINVAL; 16334cd04c50SGhennadi Procopciuc } 16344cd04c50SGhennadi Procopciuc 16354cd04c50SGhennadi Procopciuc dfs_div->freq = rate; 16364cd04c50SGhennadi Procopciuc *orate = rate; 16374cd04c50SGhennadi Procopciuc 16384cd04c50SGhennadi Procopciuc return ret; 16394cd04c50SGhennadi Procopciuc } 16404cd04c50SGhennadi Procopciuc 16418f23e76fSGhennadi Procopciuc static unsigned long compute_dfs_div_freq(unsigned long pfreq, uint32_t mfi, uint32_t mfn) 16428f23e76fSGhennadi Procopciuc { 16438f23e76fSGhennadi Procopciuc unsigned long freq; 16448f23e76fSGhennadi Procopciuc 16458f23e76fSGhennadi Procopciuc /** 16468f23e76fSGhennadi Procopciuc * Formula for input and output clocks of each port divider. 16478f23e76fSGhennadi Procopciuc * See 'Digital Frequency Synthesizer' chapter from Reference Manual. 16488f23e76fSGhennadi Procopciuc * 16498f23e76fSGhennadi Procopciuc * freq = pfreq / (2 * (mfi + mfn / 36.0)); 16508f23e76fSGhennadi Procopciuc */ 16518f23e76fSGhennadi Procopciuc freq = (mfi * FP_PRECISION) + (mfn * FP_PRECISION / 36UL); 16528f23e76fSGhennadi Procopciuc freq *= 2UL; 16538f23e76fSGhennadi Procopciuc freq = pfreq * FP_PRECISION / freq; 16548f23e76fSGhennadi Procopciuc 16558f23e76fSGhennadi Procopciuc return freq; 16568f23e76fSGhennadi Procopciuc } 16578f23e76fSGhennadi Procopciuc 16588f23e76fSGhennadi Procopciuc static int get_dfs_div_freq(const struct s32cc_clk_obj *module, 16598f23e76fSGhennadi Procopciuc const struct s32cc_clk_drv *drv, 16608f23e76fSGhennadi Procopciuc unsigned long *rate, unsigned int depth) 16618f23e76fSGhennadi Procopciuc { 16628f23e76fSGhennadi Procopciuc const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module); 16638f23e76fSGhennadi Procopciuc unsigned int ldepth = depth; 16648f23e76fSGhennadi Procopciuc const struct s32cc_dfs *dfs; 16658f23e76fSGhennadi Procopciuc uint32_t dvport, mfi, mfn; 16668f23e76fSGhennadi Procopciuc uintptr_t dfs_addr = 0UL; 16678f23e76fSGhennadi Procopciuc unsigned long pfreq; 16688f23e76fSGhennadi Procopciuc int ret; 16698f23e76fSGhennadi Procopciuc 16708f23e76fSGhennadi Procopciuc ret = update_stack_depth(&ldepth); 16718f23e76fSGhennadi Procopciuc if (ret != 0) { 16728f23e76fSGhennadi Procopciuc return ret; 16738f23e76fSGhennadi Procopciuc } 16748f23e76fSGhennadi Procopciuc 16758f23e76fSGhennadi Procopciuc dfs = get_div_dfs(dfs_div); 16768f23e76fSGhennadi Procopciuc if (dfs == NULL) { 16778f23e76fSGhennadi Procopciuc return -EINVAL; 16788f23e76fSGhennadi Procopciuc } 16798f23e76fSGhennadi Procopciuc 16808f23e76fSGhennadi Procopciuc ret = get_module_rate(dfs_div->parent, drv, &pfreq, ldepth); 16818f23e76fSGhennadi Procopciuc if (ret != 0) { 16828f23e76fSGhennadi Procopciuc return ret; 16838f23e76fSGhennadi Procopciuc } 16848f23e76fSGhennadi Procopciuc 16858f23e76fSGhennadi Procopciuc ret = get_base_addr(dfs->instance, drv, &dfs_addr); 16868f23e76fSGhennadi Procopciuc if (ret != 0) { 16878f23e76fSGhennadi Procopciuc ERROR("Failed to detect the DFS instance\n"); 16888f23e76fSGhennadi Procopciuc return ret; 16898f23e76fSGhennadi Procopciuc } 16908f23e76fSGhennadi Procopciuc 16918f23e76fSGhennadi Procopciuc dvport = mmio_read_32(DFS_DVPORTn(dfs_addr, dfs_div->index)); 16928f23e76fSGhennadi Procopciuc 16938f23e76fSGhennadi Procopciuc mfi = DFS_DVPORTn_MFI(dvport); 16948f23e76fSGhennadi Procopciuc mfn = DFS_DVPORTn_MFN(dvport); 16958f23e76fSGhennadi Procopciuc 16968f23e76fSGhennadi Procopciuc /* Disabled port */ 16978f23e76fSGhennadi Procopciuc if ((mfi == 0U) && (mfn == 0U)) { 16988f23e76fSGhennadi Procopciuc *rate = dfs_div->freq; 16998f23e76fSGhennadi Procopciuc return 0; 17008f23e76fSGhennadi Procopciuc } 17018f23e76fSGhennadi Procopciuc 17028f23e76fSGhennadi Procopciuc *rate = compute_dfs_div_freq(pfreq, mfi, mfn); 17038f23e76fSGhennadi Procopciuc return 0; 17048f23e76fSGhennadi Procopciuc } 17058f23e76fSGhennadi Procopciuc 1706d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 1707d9373519SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 1708d9373519SGhennadi Procopciuc unsigned int *depth) 1709d9373519SGhennadi Procopciuc { 1710d9373519SGhennadi Procopciuc int ret = 0; 1711d9373519SGhennadi Procopciuc 1712d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 1713d9373519SGhennadi Procopciuc if (ret != 0) { 1714d9373519SGhennadi Procopciuc return ret; 1715d9373519SGhennadi Procopciuc } 1716d9373519SGhennadi Procopciuc 17174cd04c50SGhennadi Procopciuc ret = -EINVAL; 17184cd04c50SGhennadi Procopciuc 1719d9373519SGhennadi Procopciuc switch (module->type) { 1720d9373519SGhennadi Procopciuc case s32cc_clk_t: 1721d9373519SGhennadi Procopciuc ret = set_clk_freq(module, rate, orate, depth); 1722d9373519SGhennadi Procopciuc break; 1723d9373519SGhennadi Procopciuc case s32cc_osc_t: 1724d9373519SGhennadi Procopciuc ret = set_osc_freq(module, rate, orate, depth); 1725d9373519SGhennadi Procopciuc break; 17267ad4e231SGhennadi Procopciuc case s32cc_pll_t: 17277ad4e231SGhennadi Procopciuc ret = set_pll_freq(module, rate, orate, depth); 17287ad4e231SGhennadi Procopciuc break; 1729de950ef0SGhennadi Procopciuc case s32cc_pll_out_div_t: 1730de950ef0SGhennadi Procopciuc ret = set_pll_div_freq(module, rate, orate, depth); 1731de950ef0SGhennadi Procopciuc break; 173265739db2SGhennadi Procopciuc case s32cc_fixed_div_t: 173365739db2SGhennadi Procopciuc ret = set_fixed_div_freq(module, rate, orate, depth); 173465739db2SGhennadi Procopciuc break; 1735a8be748aSGhennadi Procopciuc case s32cc_clkmux_t: 173664e0c226SGhennadi Procopciuc ret = set_mux_freq(module, rate, orate, depth); 173764e0c226SGhennadi Procopciuc break; 17383fa91a94SGhennadi Procopciuc case s32cc_shared_clkmux_t: 173964e0c226SGhennadi Procopciuc ret = set_mux_freq(module, rate, orate, depth); 1740a8be748aSGhennadi Procopciuc break; 17414cd04c50SGhennadi Procopciuc case s32cc_dfs_t: 17424cd04c50SGhennadi Procopciuc ERROR("Setting the frequency of a DFS is not allowed!"); 17434cd04c50SGhennadi Procopciuc break; 17444cd04c50SGhennadi Procopciuc case s32cc_dfs_div_t: 17454cd04c50SGhennadi Procopciuc ret = set_dfs_div_freq(module, rate, orate, depth); 17464cd04c50SGhennadi Procopciuc break; 1747d9373519SGhennadi Procopciuc default: 1748d9373519SGhennadi Procopciuc break; 1749d9373519SGhennadi Procopciuc } 1750d9373519SGhennadi Procopciuc 1751d9373519SGhennadi Procopciuc return ret; 1752d9373519SGhennadi Procopciuc } 1753d9373519SGhennadi Procopciuc 1754bd691136SGhennadi Procopciuc static int get_module_rate(const struct s32cc_clk_obj *module, 1755bd691136SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 1756bd691136SGhennadi Procopciuc unsigned long *rate, 1757bd691136SGhennadi Procopciuc unsigned int depth) 1758bd691136SGhennadi Procopciuc { 1759bd691136SGhennadi Procopciuc unsigned int ldepth = depth; 1760bd691136SGhennadi Procopciuc int ret = 0; 1761bd691136SGhennadi Procopciuc 1762bd691136SGhennadi Procopciuc ret = update_stack_depth(&ldepth); 1763bd691136SGhennadi Procopciuc if (ret != 0) { 1764bd691136SGhennadi Procopciuc return ret; 1765bd691136SGhennadi Procopciuc } 1766bd691136SGhennadi Procopciuc 1767bd691136SGhennadi Procopciuc switch (module->type) { 1768bd691136SGhennadi Procopciuc case s32cc_osc_t: 1769bd691136SGhennadi Procopciuc ret = get_osc_freq(module, drv, rate, ldepth); 1770bd691136SGhennadi Procopciuc break; 177146de0b9cSGhennadi Procopciuc case s32cc_clk_t: 177246de0b9cSGhennadi Procopciuc ret = get_clk_freq(module, drv, rate, ldepth); 177346de0b9cSGhennadi Procopciuc break; 1774fbebafa5SGhennadi Procopciuc case s32cc_pll_t: 1775fbebafa5SGhennadi Procopciuc ret = get_pll_freq(module, drv, rate, ldepth); 1776fbebafa5SGhennadi Procopciuc break; 17772fb25509SGhennadi Procopciuc case s32cc_dfs_t: 17782fb25509SGhennadi Procopciuc ret = get_dfs_freq(module, drv, rate, ldepth); 17792fb25509SGhennadi Procopciuc break; 17808f23e76fSGhennadi Procopciuc case s32cc_dfs_div_t: 17818f23e76fSGhennadi Procopciuc ret = get_dfs_div_freq(module, drv, rate, ldepth); 17828f23e76fSGhennadi Procopciuc break; 17837c298ebcSGhennadi Procopciuc case s32cc_fixed_div_t: 17847c298ebcSGhennadi Procopciuc ret = get_fixed_div_freq(module, drv, rate, ldepth); 17857c298ebcSGhennadi Procopciuc break; 1786a762c505SGhennadi Procopciuc case s32cc_pll_out_div_t: 1787a762c505SGhennadi Procopciuc ret = get_pll_div_freq(module, drv, rate, ldepth); 1788a762c505SGhennadi Procopciuc break; 1789d1567da6SGhennadi Procopciuc case s32cc_clkmux_t: 1790d1567da6SGhennadi Procopciuc ret = get_mux_freq(module, drv, rate, ldepth); 1791d1567da6SGhennadi Procopciuc break; 1792d1567da6SGhennadi Procopciuc case s32cc_shared_clkmux_t: 1793d1567da6SGhennadi Procopciuc ret = get_mux_freq(module, drv, rate, ldepth); 1794d1567da6SGhennadi Procopciuc break; 1795a74cf75fSGhennadi Procopciuc case s32cc_part_t: 1796a74cf75fSGhennadi Procopciuc ERROR("s32cc_part_t cannot be used to get rate\n"); 1797a74cf75fSGhennadi Procopciuc break; 1798a74cf75fSGhennadi Procopciuc case s32cc_part_block_t: 1799a74cf75fSGhennadi Procopciuc ERROR("s32cc_part_block_t cannot be used to get rate\n"); 1800a74cf75fSGhennadi Procopciuc break; 1801a74cf75fSGhennadi Procopciuc case s32cc_part_block_link_t: 1802a74cf75fSGhennadi Procopciuc ret = get_part_block_link_freq(module, drv, rate, ldepth); 1803a74cf75fSGhennadi Procopciuc break; 1804bd691136SGhennadi Procopciuc default: 1805bd691136SGhennadi Procopciuc ret = -EINVAL; 1806bd691136SGhennadi Procopciuc break; 1807bd691136SGhennadi Procopciuc } 1808bd691136SGhennadi Procopciuc 1809bd691136SGhennadi Procopciuc return ret; 1810bd691136SGhennadi Procopciuc } 1811bd691136SGhennadi Procopciuc 18123a580e9eSGhennadi Procopciuc static int s32cc_clk_set_rate(unsigned long id, unsigned long rate, 18133a580e9eSGhennadi Procopciuc unsigned long *orate) 18143a580e9eSGhennadi Procopciuc { 1815d9373519SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 1816d9373519SGhennadi Procopciuc const struct s32cc_clk *clk; 1817d9373519SGhennadi Procopciuc int ret; 1818d9373519SGhennadi Procopciuc 1819d9373519SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 1820d9373519SGhennadi Procopciuc if (clk == NULL) { 1821d9373519SGhennadi Procopciuc return -EINVAL; 1822d9373519SGhennadi Procopciuc } 1823d9373519SGhennadi Procopciuc 1824d9373519SGhennadi Procopciuc ret = set_module_rate(&clk->desc, rate, orate, &depth); 1825d9373519SGhennadi Procopciuc if (ret != 0) { 1826d9373519SGhennadi Procopciuc ERROR("Failed to set frequency (%lu MHz) for clock %lu\n", 1827d9373519SGhennadi Procopciuc rate, id); 1828d9373519SGhennadi Procopciuc } 1829d9373519SGhennadi Procopciuc 1830d9373519SGhennadi Procopciuc return ret; 18313a580e9eSGhennadi Procopciuc } 18323a580e9eSGhennadi Procopciuc 1833bd691136SGhennadi Procopciuc static unsigned long s32cc_clk_get_rate(unsigned long id) 1834bd691136SGhennadi Procopciuc { 1835bd691136SGhennadi Procopciuc const struct s32cc_clk_drv *drv = get_drv(); 1836bd691136SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 1837bd691136SGhennadi Procopciuc const struct s32cc_clk *clk; 1838bd691136SGhennadi Procopciuc unsigned long rate = 0UL; 1839bd691136SGhennadi Procopciuc int ret; 1840bd691136SGhennadi Procopciuc 1841bd691136SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 1842bd691136SGhennadi Procopciuc if (clk == NULL) { 1843bd691136SGhennadi Procopciuc return 0; 1844bd691136SGhennadi Procopciuc } 1845bd691136SGhennadi Procopciuc 1846bd691136SGhennadi Procopciuc ret = get_module_rate(&clk->desc, drv, &rate, depth); 1847bd691136SGhennadi Procopciuc if (ret != 0) { 1848bd691136SGhennadi Procopciuc ERROR("Failed to get frequency (%lu MHz) for clock %lu\n", 1849bd691136SGhennadi Procopciuc rate, id); 1850bd691136SGhennadi Procopciuc return 0; 1851bd691136SGhennadi Procopciuc } 1852bd691136SGhennadi Procopciuc 1853bd691136SGhennadi Procopciuc return rate; 1854bd691136SGhennadi Procopciuc } 1855bd691136SGhennadi Procopciuc 185696e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_no_parent(const struct s32cc_clk_obj *module) 185796e069cbSGhennadi Procopciuc { 185896e069cbSGhennadi Procopciuc return NULL; 185996e069cbSGhennadi Procopciuc } 186096e069cbSGhennadi Procopciuc 186196e069cbSGhennadi Procopciuc typedef struct s32cc_clk_obj *(*get_parent_clb_t)(const struct s32cc_clk_obj *clk_obj); 186296e069cbSGhennadi Procopciuc 186396e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_module_parent(const struct s32cc_clk_obj *module) 186496e069cbSGhennadi Procopciuc { 18658a4f840bSGhennadi Procopciuc static const get_parent_clb_t parents_clbs[12] = { 186696e069cbSGhennadi Procopciuc [s32cc_clk_t] = get_clk_parent, 186796e069cbSGhennadi Procopciuc [s32cc_osc_t] = get_no_parent, 186896e069cbSGhennadi Procopciuc [s32cc_pll_t] = get_pll_parent, 186996e069cbSGhennadi Procopciuc [s32cc_pll_out_div_t] = get_pll_div_parent, 187096e069cbSGhennadi Procopciuc [s32cc_clkmux_t] = get_mux_parent, 187196e069cbSGhennadi Procopciuc [s32cc_shared_clkmux_t] = get_mux_parent, 187296e069cbSGhennadi Procopciuc [s32cc_dfs_t] = get_dfs_parent, 187396e069cbSGhennadi Procopciuc [s32cc_dfs_div_t] = get_dfs_div_parent, 18748a4f840bSGhennadi Procopciuc [s32cc_part_t] = get_no_parent, 18758a4f840bSGhennadi Procopciuc [s32cc_part_block_t] = get_part_block_parent, 18768a4f840bSGhennadi Procopciuc [s32cc_part_block_link_t] = get_part_block_link_parent, 187796e069cbSGhennadi Procopciuc }; 187896e069cbSGhennadi Procopciuc uint32_t index; 187996e069cbSGhennadi Procopciuc 188096e069cbSGhennadi Procopciuc if (module == NULL) { 188196e069cbSGhennadi Procopciuc return NULL; 188296e069cbSGhennadi Procopciuc } 188396e069cbSGhennadi Procopciuc 188496e069cbSGhennadi Procopciuc index = (uint32_t)module->type; 188596e069cbSGhennadi Procopciuc 188696e069cbSGhennadi Procopciuc if (index >= ARRAY_SIZE(parents_clbs)) { 188796e069cbSGhennadi Procopciuc ERROR("Undefined module type: %d\n", module->type); 188896e069cbSGhennadi Procopciuc return NULL; 188996e069cbSGhennadi Procopciuc } 189096e069cbSGhennadi Procopciuc 189196e069cbSGhennadi Procopciuc if (parents_clbs[index] == NULL) { 189296e069cbSGhennadi Procopciuc ERROR("Undefined parent getter for type: %d\n", module->type); 189396e069cbSGhennadi Procopciuc return NULL; 189496e069cbSGhennadi Procopciuc } 189596e069cbSGhennadi Procopciuc 189696e069cbSGhennadi Procopciuc return parents_clbs[index](module); 189796e069cbSGhennadi Procopciuc } 189896e069cbSGhennadi Procopciuc 18993a580e9eSGhennadi Procopciuc static int s32cc_clk_get_parent(unsigned long id) 19003a580e9eSGhennadi Procopciuc { 190196e069cbSGhennadi Procopciuc struct s32cc_clk *parent_clk; 190296e069cbSGhennadi Procopciuc const struct s32cc_clk_obj *parent; 190396e069cbSGhennadi Procopciuc const struct s32cc_clk *clk; 190496e069cbSGhennadi Procopciuc unsigned long parent_id; 190596e069cbSGhennadi Procopciuc int ret; 190696e069cbSGhennadi Procopciuc 190796e069cbSGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 190896e069cbSGhennadi Procopciuc if (clk == NULL) { 190996e069cbSGhennadi Procopciuc return -EINVAL; 191096e069cbSGhennadi Procopciuc } 191196e069cbSGhennadi Procopciuc 191296e069cbSGhennadi Procopciuc parent = get_module_parent(clk->module); 191396e069cbSGhennadi Procopciuc if (parent == NULL) { 191496e069cbSGhennadi Procopciuc return -EINVAL; 191596e069cbSGhennadi Procopciuc } 191696e069cbSGhennadi Procopciuc 191796e069cbSGhennadi Procopciuc parent_clk = s32cc_obj2clk(parent); 191896e069cbSGhennadi Procopciuc if (parent_clk == NULL) { 191996e069cbSGhennadi Procopciuc return -EINVAL; 192096e069cbSGhennadi Procopciuc } 192196e069cbSGhennadi Procopciuc 192296e069cbSGhennadi Procopciuc ret = s32cc_get_clk_id(parent_clk, &parent_id); 192396e069cbSGhennadi Procopciuc if (ret != 0) { 192496e069cbSGhennadi Procopciuc return ret; 192596e069cbSGhennadi Procopciuc } 192696e069cbSGhennadi Procopciuc 192796e069cbSGhennadi Procopciuc if (parent_id > (unsigned long)INT_MAX) { 192896e069cbSGhennadi Procopciuc return -E2BIG; 192996e069cbSGhennadi Procopciuc } 193096e069cbSGhennadi Procopciuc 193196e069cbSGhennadi Procopciuc return (int)parent_id; 19323a580e9eSGhennadi Procopciuc } 19333a580e9eSGhennadi Procopciuc 19343a580e9eSGhennadi Procopciuc static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id) 19353a580e9eSGhennadi Procopciuc { 193612e7a2cdSGhennadi Procopciuc const struct s32cc_clk *parent; 193712e7a2cdSGhennadi Procopciuc const struct s32cc_clk *clk; 193812e7a2cdSGhennadi Procopciuc bool valid_source = false; 193912e7a2cdSGhennadi Procopciuc struct s32cc_clkmux *mux; 194012e7a2cdSGhennadi Procopciuc uint8_t i; 194112e7a2cdSGhennadi Procopciuc 194212e7a2cdSGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 194312e7a2cdSGhennadi Procopciuc if (clk == NULL) { 194412e7a2cdSGhennadi Procopciuc return -EINVAL; 194512e7a2cdSGhennadi Procopciuc } 194612e7a2cdSGhennadi Procopciuc 194712e7a2cdSGhennadi Procopciuc parent = s32cc_get_arch_clk(parent_id); 194812e7a2cdSGhennadi Procopciuc if (parent == NULL) { 194912e7a2cdSGhennadi Procopciuc return -EINVAL; 195012e7a2cdSGhennadi Procopciuc } 195112e7a2cdSGhennadi Procopciuc 195212e7a2cdSGhennadi Procopciuc if (!is_s32cc_clk_mux(clk)) { 195312e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a mux\n", id); 195412e7a2cdSGhennadi Procopciuc return -EINVAL; 195512e7a2cdSGhennadi Procopciuc } 195612e7a2cdSGhennadi Procopciuc 195712e7a2cdSGhennadi Procopciuc mux = s32cc_clk2mux(clk); 195812e7a2cdSGhennadi Procopciuc if (mux == NULL) { 195912e7a2cdSGhennadi Procopciuc ERROR("Failed to cast clock %lu to clock mux\n", id); 196012e7a2cdSGhennadi Procopciuc return -EINVAL; 196112e7a2cdSGhennadi Procopciuc } 196212e7a2cdSGhennadi Procopciuc 196312e7a2cdSGhennadi Procopciuc for (i = 0; i < mux->nclks; i++) { 196412e7a2cdSGhennadi Procopciuc if (mux->clkids[i] == parent_id) { 196512e7a2cdSGhennadi Procopciuc valid_source = true; 196612e7a2cdSGhennadi Procopciuc break; 196712e7a2cdSGhennadi Procopciuc } 196812e7a2cdSGhennadi Procopciuc } 196912e7a2cdSGhennadi Procopciuc 197012e7a2cdSGhennadi Procopciuc if (!valid_source) { 197112e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a valid clock for mux %lu\n", 197212e7a2cdSGhennadi Procopciuc parent_id, id); 197312e7a2cdSGhennadi Procopciuc return -EINVAL; 197412e7a2cdSGhennadi Procopciuc } 197512e7a2cdSGhennadi Procopciuc 197612e7a2cdSGhennadi Procopciuc mux->source_id = parent_id; 197712e7a2cdSGhennadi Procopciuc 197812e7a2cdSGhennadi Procopciuc return 0; 19793a580e9eSGhennadi Procopciuc } 19803a580e9eSGhennadi Procopciuc 1981514c7380SGhennadi Procopciuc static int s32cc_clk_mmap_regs(const struct s32cc_clk_drv *drv) 1982514c7380SGhennadi Procopciuc { 1983514c7380SGhennadi Procopciuc const uintptr_t base_addrs[11] = { 1984514c7380SGhennadi Procopciuc drv->fxosc_base, 1985514c7380SGhennadi Procopciuc drv->armpll_base, 1986514c7380SGhennadi Procopciuc drv->periphpll_base, 1987514c7380SGhennadi Procopciuc drv->armdfs_base, 1988514c7380SGhennadi Procopciuc drv->cgm0_base, 1989514c7380SGhennadi Procopciuc drv->cgm1_base, 1990514c7380SGhennadi Procopciuc drv->cgm5_base, 1991514c7380SGhennadi Procopciuc drv->ddrpll_base, 1992514c7380SGhennadi Procopciuc drv->mc_me, 1993514c7380SGhennadi Procopciuc drv->mc_rgm, 1994514c7380SGhennadi Procopciuc drv->rdc, 1995514c7380SGhennadi Procopciuc }; 1996514c7380SGhennadi Procopciuc size_t i; 1997514c7380SGhennadi Procopciuc int ret; 1998514c7380SGhennadi Procopciuc 1999514c7380SGhennadi Procopciuc for (i = 0U; i < ARRAY_SIZE(base_addrs); i++) { 2000514c7380SGhennadi Procopciuc ret = mmap_add_dynamic_region(base_addrs[i], base_addrs[i], 2001514c7380SGhennadi Procopciuc PAGE_SIZE, 2002514c7380SGhennadi Procopciuc MT_DEVICE | MT_RW | MT_SECURE); 2003514c7380SGhennadi Procopciuc if (ret != 0) { 2004514c7380SGhennadi Procopciuc ERROR("Failed to map clock module 0x%" PRIuPTR "\n", 2005514c7380SGhennadi Procopciuc base_addrs[i]); 2006514c7380SGhennadi Procopciuc return ret; 2007514c7380SGhennadi Procopciuc } 2008514c7380SGhennadi Procopciuc } 2009514c7380SGhennadi Procopciuc 2010514c7380SGhennadi Procopciuc return 0; 2011514c7380SGhennadi Procopciuc } 2012514c7380SGhennadi Procopciuc 201361b5ef21SGhennadi Procopciuc int s32cc_clk_register_drv(bool mmap_regs) 20143a580e9eSGhennadi Procopciuc { 20153a580e9eSGhennadi Procopciuc static const struct clk_ops s32cc_clk_ops = { 20163a580e9eSGhennadi Procopciuc .enable = s32cc_clk_enable, 20173a580e9eSGhennadi Procopciuc .disable = s32cc_clk_disable, 20183a580e9eSGhennadi Procopciuc .is_enabled = s32cc_clk_is_enabled, 20193a580e9eSGhennadi Procopciuc .get_rate = s32cc_clk_get_rate, 20203a580e9eSGhennadi Procopciuc .set_rate = s32cc_clk_set_rate, 20213a580e9eSGhennadi Procopciuc .get_parent = s32cc_clk_get_parent, 20223a580e9eSGhennadi Procopciuc .set_parent = s32cc_clk_set_parent, 20233a580e9eSGhennadi Procopciuc }; 2024514c7380SGhennadi Procopciuc const struct s32cc_clk_drv *drv; 20253a580e9eSGhennadi Procopciuc 20263a580e9eSGhennadi Procopciuc clk_register(&s32cc_clk_ops); 2027514c7380SGhennadi Procopciuc 2028514c7380SGhennadi Procopciuc drv = get_drv(); 2029514c7380SGhennadi Procopciuc if (drv == NULL) { 2030514c7380SGhennadi Procopciuc return -EINVAL; 2031514c7380SGhennadi Procopciuc } 2032514c7380SGhennadi Procopciuc 203361b5ef21SGhennadi Procopciuc if (mmap_regs) { 2034514c7380SGhennadi Procopciuc return s32cc_clk_mmap_regs(drv); 20353a580e9eSGhennadi Procopciuc } 20363a580e9eSGhennadi Procopciuc 203761b5ef21SGhennadi Procopciuc return 0; 203861b5ef21SGhennadi Procopciuc } 203961b5ef21SGhennadi Procopciuc 2040