13a580e9eSGhennadi Procopciuc /* 23a580e9eSGhennadi Procopciuc * Copyright 2024 NXP 33a580e9eSGhennadi Procopciuc * 43a580e9eSGhennadi Procopciuc * SPDX-License-Identifier: BSD-3-Clause 53a580e9eSGhennadi Procopciuc */ 63a580e9eSGhennadi Procopciuc #include <errno.h> 73a580e9eSGhennadi Procopciuc 88ab34357SGhennadi Procopciuc #include <s32cc-clk-regs.h> 98ab34357SGhennadi Procopciuc 10d9373519SGhennadi Procopciuc #include <common/debug.h> 113a580e9eSGhennadi Procopciuc #include <drivers/clk.h> 128ab34357SGhennadi Procopciuc #include <lib/mmio.h> 13d9373519SGhennadi Procopciuc #include <s32cc-clk-modules.h> 14d9373519SGhennadi Procopciuc #include <s32cc-clk-utils.h> 15d9373519SGhennadi Procopciuc 16d9373519SGhennadi Procopciuc #define MAX_STACK_DEPTH (15U) 17d9373519SGhennadi Procopciuc 188ab34357SGhennadi Procopciuc struct s32cc_clk_drv { 198ab34357SGhennadi Procopciuc uintptr_t fxosc_base; 208ab34357SGhennadi Procopciuc }; 218ab34357SGhennadi Procopciuc 22d9373519SGhennadi Procopciuc static int update_stack_depth(unsigned int *depth) 23d9373519SGhennadi Procopciuc { 24d9373519SGhennadi Procopciuc if (*depth == 0U) { 25d9373519SGhennadi Procopciuc return -ENOMEM; 26d9373519SGhennadi Procopciuc } 27d9373519SGhennadi Procopciuc 28d9373519SGhennadi Procopciuc (*depth)--; 29d9373519SGhennadi Procopciuc return 0; 30d9373519SGhennadi Procopciuc } 313a580e9eSGhennadi Procopciuc 328ab34357SGhennadi Procopciuc static struct s32cc_clk_drv *get_drv(void) 338ab34357SGhennadi Procopciuc { 348ab34357SGhennadi Procopciuc static struct s32cc_clk_drv driver = { 358ab34357SGhennadi Procopciuc .fxosc_base = FXOSC_BASE_ADDR, 368ab34357SGhennadi Procopciuc }; 378ab34357SGhennadi Procopciuc 388ab34357SGhennadi Procopciuc return &driver; 398ab34357SGhennadi Procopciuc } 408ab34357SGhennadi Procopciuc 418ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth); 428ab34357SGhennadi Procopciuc 438ab34357SGhennadi Procopciuc static int enable_clk_module(const struct s32cc_clk_obj *module, 448ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 458ab34357SGhennadi Procopciuc unsigned int *depth) 468ab34357SGhennadi Procopciuc { 478ab34357SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 488ab34357SGhennadi Procopciuc int ret; 498ab34357SGhennadi Procopciuc 508ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 518ab34357SGhennadi Procopciuc if (ret != 0) { 528ab34357SGhennadi Procopciuc return ret; 538ab34357SGhennadi Procopciuc } 548ab34357SGhennadi Procopciuc 558ab34357SGhennadi Procopciuc if (clk == NULL) { 568ab34357SGhennadi Procopciuc return -EINVAL; 578ab34357SGhennadi Procopciuc } 588ab34357SGhennadi Procopciuc 598ab34357SGhennadi Procopciuc if (clk->module != NULL) { 608ab34357SGhennadi Procopciuc return enable_module(clk->module, depth); 618ab34357SGhennadi Procopciuc } 628ab34357SGhennadi Procopciuc 638ab34357SGhennadi Procopciuc if (clk->pclock != NULL) { 648ab34357SGhennadi Procopciuc return enable_clk_module(&clk->pclock->desc, drv, depth); 658ab34357SGhennadi Procopciuc } 668ab34357SGhennadi Procopciuc 678ab34357SGhennadi Procopciuc return -EINVAL; 688ab34357SGhennadi Procopciuc } 698ab34357SGhennadi Procopciuc 708ab34357SGhennadi Procopciuc static void enable_fxosc(const struct s32cc_clk_drv *drv) 718ab34357SGhennadi Procopciuc { 728ab34357SGhennadi Procopciuc uintptr_t fxosc_base = drv->fxosc_base; 738ab34357SGhennadi Procopciuc uint32_t ctrl; 748ab34357SGhennadi Procopciuc 758ab34357SGhennadi Procopciuc ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base)); 768ab34357SGhennadi Procopciuc if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) { 778ab34357SGhennadi Procopciuc return; 788ab34357SGhennadi Procopciuc } 798ab34357SGhennadi Procopciuc 808ab34357SGhennadi Procopciuc ctrl = FXOSC_CTRL_COMP_EN; 818ab34357SGhennadi Procopciuc ctrl &= ~FXOSC_CTRL_OSC_BYP; 828ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_EOCV(0x1); 838ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_GM_SEL(0x7); 848ab34357SGhennadi Procopciuc mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl); 858ab34357SGhennadi Procopciuc 868ab34357SGhennadi Procopciuc /* Switch ON the crystal oscillator. */ 878ab34357SGhennadi Procopciuc mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON); 888ab34357SGhennadi Procopciuc 898ab34357SGhennadi Procopciuc /* Wait until the clock is stable. */ 908ab34357SGhennadi Procopciuc while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) { 918ab34357SGhennadi Procopciuc } 928ab34357SGhennadi Procopciuc } 938ab34357SGhennadi Procopciuc 948ab34357SGhennadi Procopciuc static int enable_osc(const struct s32cc_clk_obj *module, 958ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 968ab34357SGhennadi Procopciuc unsigned int *depth) 978ab34357SGhennadi Procopciuc { 988ab34357SGhennadi Procopciuc const struct s32cc_osc *osc = s32cc_obj2osc(module); 998ab34357SGhennadi Procopciuc int ret = 0; 1008ab34357SGhennadi Procopciuc 1018ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 1028ab34357SGhennadi Procopciuc if (ret != 0) { 1038ab34357SGhennadi Procopciuc return ret; 1048ab34357SGhennadi Procopciuc } 1058ab34357SGhennadi Procopciuc 1068ab34357SGhennadi Procopciuc switch (osc->source) { 1078ab34357SGhennadi Procopciuc case S32CC_FXOSC: 1088ab34357SGhennadi Procopciuc enable_fxosc(drv); 1098ab34357SGhennadi Procopciuc break; 1108ab34357SGhennadi Procopciuc /* FIRC and SIRC oscillators are enabled by default */ 1118ab34357SGhennadi Procopciuc case S32CC_FIRC: 1128ab34357SGhennadi Procopciuc break; 1138ab34357SGhennadi Procopciuc case S32CC_SIRC: 1148ab34357SGhennadi Procopciuc break; 1158ab34357SGhennadi Procopciuc default: 1168ab34357SGhennadi Procopciuc ERROR("Invalid oscillator %d\n", osc->source); 1178ab34357SGhennadi Procopciuc ret = -EINVAL; 1188ab34357SGhennadi Procopciuc break; 1198ab34357SGhennadi Procopciuc }; 1208ab34357SGhennadi Procopciuc 1218ab34357SGhennadi Procopciuc return ret; 1228ab34357SGhennadi Procopciuc } 1238ab34357SGhennadi Procopciuc 1248ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth) 1258ab34357SGhennadi Procopciuc { 1268ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv = get_drv(); 1278ab34357SGhennadi Procopciuc int ret = 0; 1288ab34357SGhennadi Procopciuc 1298ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 1308ab34357SGhennadi Procopciuc if (ret != 0) { 1318ab34357SGhennadi Procopciuc return ret; 1328ab34357SGhennadi Procopciuc } 1338ab34357SGhennadi Procopciuc 1348ab34357SGhennadi Procopciuc if (drv == NULL) { 1358ab34357SGhennadi Procopciuc return -EINVAL; 1368ab34357SGhennadi Procopciuc } 1378ab34357SGhennadi Procopciuc 1388ab34357SGhennadi Procopciuc switch (module->type) { 1398ab34357SGhennadi Procopciuc case s32cc_osc_t: 1408ab34357SGhennadi Procopciuc ret = enable_osc(module, drv, depth); 1418ab34357SGhennadi Procopciuc break; 1428ab34357SGhennadi Procopciuc case s32cc_clk_t: 1438ab34357SGhennadi Procopciuc ret = enable_clk_module(module, drv, depth); 1448ab34357SGhennadi Procopciuc break; 145a8be748aSGhennadi Procopciuc case s32cc_clkmux_t: 146a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 147a8be748aSGhennadi Procopciuc break; 148a8be748aSGhennadi Procopciuc case s32cc_pll_t: 149a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 150a8be748aSGhennadi Procopciuc break; 151a8be748aSGhennadi Procopciuc case s32cc_pll_out_div_t: 152a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 153a8be748aSGhennadi Procopciuc break; 1548ab34357SGhennadi Procopciuc default: 1558ab34357SGhennadi Procopciuc ret = -EINVAL; 1568ab34357SGhennadi Procopciuc break; 1578ab34357SGhennadi Procopciuc } 1588ab34357SGhennadi Procopciuc 1598ab34357SGhennadi Procopciuc return ret; 1608ab34357SGhennadi Procopciuc } 1618ab34357SGhennadi Procopciuc 1623a580e9eSGhennadi Procopciuc static int s32cc_clk_enable(unsigned long id) 1633a580e9eSGhennadi Procopciuc { 1648ab34357SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 1658ab34357SGhennadi Procopciuc const struct s32cc_clk *clk; 1668ab34357SGhennadi Procopciuc 1678ab34357SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 1688ab34357SGhennadi Procopciuc if (clk == NULL) { 1698ab34357SGhennadi Procopciuc return -EINVAL; 1708ab34357SGhennadi Procopciuc } 1718ab34357SGhennadi Procopciuc 1728ab34357SGhennadi Procopciuc return enable_module(&clk->desc, &depth); 1733a580e9eSGhennadi Procopciuc } 1743a580e9eSGhennadi Procopciuc 1753a580e9eSGhennadi Procopciuc static void s32cc_clk_disable(unsigned long id) 1763a580e9eSGhennadi Procopciuc { 1773a580e9eSGhennadi Procopciuc } 1783a580e9eSGhennadi Procopciuc 1793a580e9eSGhennadi Procopciuc static bool s32cc_clk_is_enabled(unsigned long id) 1803a580e9eSGhennadi Procopciuc { 1813a580e9eSGhennadi Procopciuc return false; 1823a580e9eSGhennadi Procopciuc } 1833a580e9eSGhennadi Procopciuc 1843a580e9eSGhennadi Procopciuc static unsigned long s32cc_clk_get_rate(unsigned long id) 1853a580e9eSGhennadi Procopciuc { 1863a580e9eSGhennadi Procopciuc return 0; 1873a580e9eSGhennadi Procopciuc } 1883a580e9eSGhennadi Procopciuc 189d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 190d9373519SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 191d9373519SGhennadi Procopciuc unsigned int *depth); 192d9373519SGhennadi Procopciuc 193d9373519SGhennadi Procopciuc static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate, 194d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 195d9373519SGhennadi Procopciuc { 196d9373519SGhennadi Procopciuc struct s32cc_osc *osc = s32cc_obj2osc(module); 197d9373519SGhennadi Procopciuc int ret; 198d9373519SGhennadi Procopciuc 199d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 200d9373519SGhennadi Procopciuc if (ret != 0) { 201d9373519SGhennadi Procopciuc return ret; 202d9373519SGhennadi Procopciuc } 203d9373519SGhennadi Procopciuc 204d9373519SGhennadi Procopciuc if ((osc->freq != 0UL) && (rate != osc->freq)) { 205d9373519SGhennadi Procopciuc ERROR("Already initialized oscillator. freq = %lu\n", 206d9373519SGhennadi Procopciuc osc->freq); 207d9373519SGhennadi Procopciuc return -EINVAL; 208d9373519SGhennadi Procopciuc } 209d9373519SGhennadi Procopciuc 210d9373519SGhennadi Procopciuc osc->freq = rate; 211d9373519SGhennadi Procopciuc *orate = osc->freq; 212d9373519SGhennadi Procopciuc 213d9373519SGhennadi Procopciuc return 0; 214d9373519SGhennadi Procopciuc } 215d9373519SGhennadi Procopciuc 216d9373519SGhennadi Procopciuc static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate, 217d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 218d9373519SGhennadi Procopciuc { 219d9373519SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 220d9373519SGhennadi Procopciuc int ret; 221d9373519SGhennadi Procopciuc 222d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 223d9373519SGhennadi Procopciuc if (ret != 0) { 224d9373519SGhennadi Procopciuc return ret; 225d9373519SGhennadi Procopciuc } 226d9373519SGhennadi Procopciuc 227d9373519SGhennadi Procopciuc if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) && 228d9373519SGhennadi Procopciuc ((rate < clk->min_freq) || (rate > clk->max_freq))) { 229d9373519SGhennadi Procopciuc ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n", 230d9373519SGhennadi Procopciuc rate, clk->min_freq, clk->max_freq); 231d9373519SGhennadi Procopciuc return -EINVAL; 232d9373519SGhennadi Procopciuc } 233d9373519SGhennadi Procopciuc 234d9373519SGhennadi Procopciuc if (clk->module != NULL) { 235d9373519SGhennadi Procopciuc return set_module_rate(clk->module, rate, orate, depth); 236d9373519SGhennadi Procopciuc } 237d9373519SGhennadi Procopciuc 238d9373519SGhennadi Procopciuc if (clk->pclock != NULL) { 239d9373519SGhennadi Procopciuc return set_clk_freq(&clk->pclock->desc, rate, orate, depth); 240d9373519SGhennadi Procopciuc } 241d9373519SGhennadi Procopciuc 242d9373519SGhennadi Procopciuc return -EINVAL; 243d9373519SGhennadi Procopciuc } 244d9373519SGhennadi Procopciuc 245d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 246d9373519SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 247d9373519SGhennadi Procopciuc unsigned int *depth) 248d9373519SGhennadi Procopciuc { 249d9373519SGhennadi Procopciuc int ret = 0; 250d9373519SGhennadi Procopciuc 251d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 252d9373519SGhennadi Procopciuc if (ret != 0) { 253d9373519SGhennadi Procopciuc return ret; 254d9373519SGhennadi Procopciuc } 255d9373519SGhennadi Procopciuc 256d9373519SGhennadi Procopciuc switch (module->type) { 257d9373519SGhennadi Procopciuc case s32cc_clk_t: 258d9373519SGhennadi Procopciuc ret = set_clk_freq(module, rate, orate, depth); 259d9373519SGhennadi Procopciuc break; 260d9373519SGhennadi Procopciuc case s32cc_osc_t: 261d9373519SGhennadi Procopciuc ret = set_osc_freq(module, rate, orate, depth); 262d9373519SGhennadi Procopciuc break; 263a8be748aSGhennadi Procopciuc case s32cc_clkmux_t: 264a8be748aSGhennadi Procopciuc case s32cc_pll_t: 265a8be748aSGhennadi Procopciuc case s32cc_pll_out_div_t: 266a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 267a8be748aSGhennadi Procopciuc break; 268d9373519SGhennadi Procopciuc default: 269d9373519SGhennadi Procopciuc ret = -EINVAL; 270d9373519SGhennadi Procopciuc break; 271d9373519SGhennadi Procopciuc } 272d9373519SGhennadi Procopciuc 273d9373519SGhennadi Procopciuc return ret; 274d9373519SGhennadi Procopciuc } 275d9373519SGhennadi Procopciuc 2763a580e9eSGhennadi Procopciuc static int s32cc_clk_set_rate(unsigned long id, unsigned long rate, 2773a580e9eSGhennadi Procopciuc unsigned long *orate) 2783a580e9eSGhennadi Procopciuc { 279d9373519SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 280d9373519SGhennadi Procopciuc const struct s32cc_clk *clk; 281d9373519SGhennadi Procopciuc int ret; 282d9373519SGhennadi Procopciuc 283d9373519SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 284d9373519SGhennadi Procopciuc if (clk == NULL) { 285d9373519SGhennadi Procopciuc return -EINVAL; 286d9373519SGhennadi Procopciuc } 287d9373519SGhennadi Procopciuc 288d9373519SGhennadi Procopciuc ret = set_module_rate(&clk->desc, rate, orate, &depth); 289d9373519SGhennadi Procopciuc if (ret != 0) { 290d9373519SGhennadi Procopciuc ERROR("Failed to set frequency (%lu MHz) for clock %lu\n", 291d9373519SGhennadi Procopciuc rate, id); 292d9373519SGhennadi Procopciuc } 293d9373519SGhennadi Procopciuc 294d9373519SGhennadi Procopciuc return ret; 2953a580e9eSGhennadi Procopciuc } 2963a580e9eSGhennadi Procopciuc 2973a580e9eSGhennadi Procopciuc static int s32cc_clk_get_parent(unsigned long id) 2983a580e9eSGhennadi Procopciuc { 2993a580e9eSGhennadi Procopciuc return -ENOTSUP; 3003a580e9eSGhennadi Procopciuc } 3013a580e9eSGhennadi Procopciuc 3023a580e9eSGhennadi Procopciuc static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id) 3033a580e9eSGhennadi Procopciuc { 304*12e7a2cdSGhennadi Procopciuc const struct s32cc_clk *parent; 305*12e7a2cdSGhennadi Procopciuc const struct s32cc_clk *clk; 306*12e7a2cdSGhennadi Procopciuc bool valid_source = false; 307*12e7a2cdSGhennadi Procopciuc struct s32cc_clkmux *mux; 308*12e7a2cdSGhennadi Procopciuc uint8_t i; 309*12e7a2cdSGhennadi Procopciuc 310*12e7a2cdSGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 311*12e7a2cdSGhennadi Procopciuc if (clk == NULL) { 312*12e7a2cdSGhennadi Procopciuc return -EINVAL; 313*12e7a2cdSGhennadi Procopciuc } 314*12e7a2cdSGhennadi Procopciuc 315*12e7a2cdSGhennadi Procopciuc parent = s32cc_get_arch_clk(parent_id); 316*12e7a2cdSGhennadi Procopciuc if (parent == NULL) { 317*12e7a2cdSGhennadi Procopciuc return -EINVAL; 318*12e7a2cdSGhennadi Procopciuc } 319*12e7a2cdSGhennadi Procopciuc 320*12e7a2cdSGhennadi Procopciuc if (!is_s32cc_clk_mux(clk)) { 321*12e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a mux\n", id); 322*12e7a2cdSGhennadi Procopciuc return -EINVAL; 323*12e7a2cdSGhennadi Procopciuc } 324*12e7a2cdSGhennadi Procopciuc 325*12e7a2cdSGhennadi Procopciuc mux = s32cc_clk2mux(clk); 326*12e7a2cdSGhennadi Procopciuc if (mux == NULL) { 327*12e7a2cdSGhennadi Procopciuc ERROR("Failed to cast clock %lu to clock mux\n", id); 328*12e7a2cdSGhennadi Procopciuc return -EINVAL; 329*12e7a2cdSGhennadi Procopciuc } 330*12e7a2cdSGhennadi Procopciuc 331*12e7a2cdSGhennadi Procopciuc for (i = 0; i < mux->nclks; i++) { 332*12e7a2cdSGhennadi Procopciuc if (mux->clkids[i] == parent_id) { 333*12e7a2cdSGhennadi Procopciuc valid_source = true; 334*12e7a2cdSGhennadi Procopciuc break; 335*12e7a2cdSGhennadi Procopciuc } 336*12e7a2cdSGhennadi Procopciuc } 337*12e7a2cdSGhennadi Procopciuc 338*12e7a2cdSGhennadi Procopciuc if (!valid_source) { 339*12e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a valid clock for mux %lu\n", 340*12e7a2cdSGhennadi Procopciuc parent_id, id); 341*12e7a2cdSGhennadi Procopciuc return -EINVAL; 342*12e7a2cdSGhennadi Procopciuc } 343*12e7a2cdSGhennadi Procopciuc 344*12e7a2cdSGhennadi Procopciuc mux->source_id = parent_id; 345*12e7a2cdSGhennadi Procopciuc 346*12e7a2cdSGhennadi Procopciuc return 0; 3473a580e9eSGhennadi Procopciuc } 3483a580e9eSGhennadi Procopciuc 3493a580e9eSGhennadi Procopciuc void s32cc_clk_register_drv(void) 3503a580e9eSGhennadi Procopciuc { 3513a580e9eSGhennadi Procopciuc static const struct clk_ops s32cc_clk_ops = { 3523a580e9eSGhennadi Procopciuc .enable = s32cc_clk_enable, 3533a580e9eSGhennadi Procopciuc .disable = s32cc_clk_disable, 3543a580e9eSGhennadi Procopciuc .is_enabled = s32cc_clk_is_enabled, 3553a580e9eSGhennadi Procopciuc .get_rate = s32cc_clk_get_rate, 3563a580e9eSGhennadi Procopciuc .set_rate = s32cc_clk_set_rate, 3573a580e9eSGhennadi Procopciuc .get_parent = s32cc_clk_get_parent, 3583a580e9eSGhennadi Procopciuc .set_parent = s32cc_clk_set_parent, 3593a580e9eSGhennadi Procopciuc }; 3603a580e9eSGhennadi Procopciuc 3613a580e9eSGhennadi Procopciuc clk_register(&s32cc_clk_ops); 3623a580e9eSGhennadi Procopciuc } 3633a580e9eSGhennadi Procopciuc 364